@dialpad/dialtone-css
Advanced tools
| #!/usr/bin/env node | ||
| /** | ||
| * @fileoverview Migration script for DtChip `interactive` prop default change. | ||
| * | ||
| * DLT-3195 DtChip `interactive` prop default changed from `true` → `false`. | ||
| * Chips that need click/keyboard behavior must now explicitly set | ||
| * `:interactive="true"`. | ||
| * | ||
| * This script: | ||
| * - Adds `:interactive="true"` to <dt-chip> tags that have a click event | ||
| * listener (@click, v-on:click) or an object v-on binding (v-on="…"), | ||
| * since those clearly need interactive behavior. | ||
| * - Skips chips that already set the `interactive` prop (any form). | ||
| * - Warns about remaining chips with no `interactive` prop and no detected | ||
| * click handler — these may be display-only (no change needed) or may | ||
| * need `:interactive="true"` added manually. | ||
| * | ||
| * Usage: | ||
| * npx dialtone-migrate-chip-interactive [options] | ||
| * | ||
| * Options: | ||
| * --cwd <path> Working directory (default: cwd) | ||
| * --dry-run Show changes without applying them | ||
| * --yes Apply all changes without prompting | ||
| * --help Show help | ||
| */ | ||
| import fs from 'fs/promises'; | ||
| import { realpathSync } from 'node:fs'; | ||
| import path from 'path'; | ||
| import readline from 'readline'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| // --------------------------------------------------------------------------- | ||
| // Constants | ||
| // --------------------------------------------------------------------------- | ||
| // Quote-aware attribute body. Matches sequences of non-quote/non-gt chars | ||
| // optionally followed by a fully-quoted attribute value, so `>` inside a | ||
| // quoted value like `:class="a > b"` does not prematurely terminate the tag. | ||
| const QUOTE_AWARE_ATTRS = '(?:[^>"\']|"[^"]*"|\'[^\']*\')*'; | ||
| // Matches `<dt-chip` or `<DtChip` opening tags (including self-closing). | ||
| // Group 1: tag name; group 2: attributes (quote-aware); group 3: closer (`>` or `/>`). | ||
| const CHIP_TAG_RE = new RegExp( | ||
| `(<(?:dt-chip|DtChip)\\b)(${QUOTE_AWARE_ATTRS})(\\s*\\/?>)`, | ||
| 'g', | ||
| ); | ||
| // Detects that the `interactive` prop is already present in any form: | ||
| // interactive, :interactive, v-bind:interactive | ||
| const HAS_INTERACTIVE_RE = /(?:^|\s)(?::|v-bind:)?interactive(?:\s*=|\s|\/|>)/; | ||
| // Detects a click event listener: | ||
| // @click, v-on:click, @click.stop, @click.prevent, etc. | ||
| const HAS_CLICK_RE = /(?:^|\s)(?:@click|v-on:click)(?:\s*=|\s*\.|\/|>|\s)/; | ||
| // Detects an object-form v-on binding (v-on="…") which may contain click. | ||
| // We treat this conservatively as "may be interactive" and add the prop. | ||
| const HAS_VON_OBJECT_RE = /(?:^|\s)v-on\s*=\s*(?:"[^"]*"|'[^']*')/; | ||
| // --------------------------------------------------------------------------- | ||
| // Transform | ||
| // --------------------------------------------------------------------------- | ||
| /** | ||
| * Strip quoted attribute values from an attrs string before regex testing. | ||
| * Replaces "…" and '…' with empty equivalents so keywords that happen to | ||
| * appear inside a quoted value (e.g. :title=" @click is cool") don't | ||
| * false-positive against HAS_CLICK_RE / HAS_INTERACTIVE_RE / HAS_VON_OBJECT_RE. | ||
| * Real attribute tokens like @click="handler" survive as @click="" and still match. | ||
| */ | ||
| function stripQuotedValues (attrs) { | ||
| return attrs.replace(/"[^"]*"|'[^']*'/g, match => (match[0] === '"' ? '""' : '\'\'')); | ||
| } | ||
| /** | ||
| * Find the position to insert `:interactive="true"` — immediately after the | ||
| * tag name so it appears first in the attribute list (consistent with existing | ||
| * Dialtone convention where `:interactive` is an early structural prop). | ||
| * | ||
| * Returns the index within `attrs` where the insertion should happen. | ||
| * We insert after any leading whitespace on the attribute string. | ||
| */ | ||
| function insertInteractiveProp (attrs) { | ||
| const leadingSpace = attrs.match(/^\s*/)[0]; | ||
| const rest = attrs.slice(leadingSpace.length); | ||
| // Preserve the original leading whitespace, then prepend the prop | ||
| return `${leadingSpace}:interactive="true" ${rest}`; | ||
| } | ||
| /** | ||
| * Transform a single file's content. | ||
| * Returns { transformed, warnings } where warnings are strings. | ||
| */ | ||
| export function transformContent (content, opts = {}) { | ||
| const filePath = opts.filePath || '<input>'; | ||
| const warnings = []; | ||
| // Fast path: skip files with no dt-chip / DtChip reference at all. | ||
| if (!/(?:dt-chip|DtChip)/i.test(content)) { | ||
| return { transformed: content, warnings }; | ||
| } | ||
| // Mask inert content (HTML comments, <script>, <style>) so we don't | ||
| // accidentally match tag-like text inside them. | ||
| const { masked, segments, token } = maskInertContent(content); | ||
| let out = masked; | ||
| const replacements = []; | ||
| // Reset lastIndex before iterating | ||
| CHIP_TAG_RE.lastIndex = 0; | ||
| let m; | ||
| while ((m = CHIP_TAG_RE.exec(out)) !== null) { | ||
| const [fullMatch, openTag, attrs, closer] = m; | ||
| const matchStart = m.index; | ||
| const matchEnd = matchStart + fullMatch.length; | ||
| // Strip quoted values before regex testing so keywords inside quoted | ||
| // attribute values don't produce false positives. | ||
| const attrsForTest = stripQuotedValues(attrs); | ||
| // Already has the interactive prop — nothing to do. | ||
| if (HAS_INTERACTIVE_RE.test(attrsForTest)) continue; | ||
| const hasClick = HAS_CLICK_RE.test(attrsForTest); | ||
| const hasVOnObject = HAS_VON_OBJECT_RE.test(attrsForTest); | ||
| if (hasClick || hasVOnObject) { | ||
| // Auto-add :interactive="true" | ||
| const newAttrs = insertInteractiveProp(attrs); | ||
| replacements.push({ | ||
| start: matchStart, | ||
| end: matchEnd, | ||
| text: `${openTag}${newAttrs}${closer}`, | ||
| }); | ||
| } else { | ||
| // No click handler and no interactive prop. | ||
| // Warn: this chip will now render as a <span>. May be intentional | ||
| // (display-only) or may need :interactive="true" manually. | ||
| warnings.push( | ||
| `${filePath}: <dt-chip> has no interactive prop and no @click handler — ` + | ||
| `will now render as a non-interactive <span>. ` + | ||
| `Add :interactive="true" if this chip should be clickable.`, | ||
| ); | ||
| } | ||
| } | ||
| // Apply replacements in reverse order to preserve indices | ||
| replacements.sort((a, b) => b.start - a.start); | ||
| for (const r of replacements) { | ||
| out = out.slice(0, r.start) + r.text + out.slice(r.end); | ||
| } | ||
| return { transformed: unmaskInertContent(out, segments, token), warnings }; | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // Inert-content masking (same pattern as dialtone_migrate_link_rendering) | ||
| // --------------------------------------------------------------------------- | ||
| function maskInertContent (content) { | ||
| const token = Math.random().toString(36).slice(2, 10); | ||
| const innerRe = /<!--[\s\S]*?-->|<script\b[^>]*>[\s\S]*?<\/script>|<style\b[^>]*>[\s\S]*?<\/style>/g; | ||
| const segments = []; | ||
| const masked = content.replace(innerRe, (match) => { | ||
| const placeholder = ` DT_MIGRATE_INERT_${token}_${segments.length} `; | ||
| segments.push(match); | ||
| return placeholder; | ||
| }); | ||
| return { masked, segments, token }; | ||
| } | ||
| function unmaskInertContent (masked, segments, token) { | ||
| return masked.replace(new RegExp(` DT_MIGRATE_INERT_${token}_(\\d+) `, 'g'), (_, idx) => segments[Number(idx)]); | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // File walker | ||
| // --------------------------------------------------------------------------- | ||
| function isIgnoredPath (fullPath, ignore) { | ||
| const segments = fullPath.split(path.sep); | ||
| return ignore.some(ig => { | ||
| if (ig.includes('/')) { | ||
| const parts = ig.split('/'); | ||
| for (let i = 0; i + parts.length <= segments.length; i++) { | ||
| if (parts.every((p, j) => segments[i + j] === p)) return true; | ||
| } | ||
| return false; | ||
| } | ||
| return segments.includes(ig); | ||
| }); | ||
| } | ||
| async function findFiles (dir, extensions, ignore = []) { | ||
| const results = []; | ||
| async function walk (currentDir) { | ||
| let entries; | ||
| try { | ||
| entries = await fs.readdir(currentDir, { withFileTypes: true }); | ||
| } catch { | ||
| return; | ||
| } | ||
| for (const entry of entries) { | ||
| const fullPath = path.join(currentDir, entry.name); | ||
| if (isIgnoredPath(fullPath, ignore)) continue; | ||
| if (entry.isDirectory()) { | ||
| await walk(fullPath); | ||
| } else if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) { | ||
| results.push(fullPath); | ||
| } | ||
| } | ||
| } | ||
| await walk(dir); | ||
| return results; | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // CLI plumbing | ||
| // --------------------------------------------------------------------------- | ||
| function printHelp () { | ||
| console.log(` | ||
| Usage: npx dialtone-migrate-chip-interactive [options] | ||
| Migrates DtChip usage after the \`interactive\` prop default changed from | ||
| \`true\` to \`false\` (DLT-3195). | ||
| Chips with a @click handler or v-on object binding automatically receive | ||
| :interactive="true". All other chips without an existing interactive prop | ||
| are listed as warnings for manual review. | ||
| Options: | ||
| --cwd <path> Working directory (default: cwd) | ||
| --dry-run Show changes without applying them | ||
| --yes Apply all changes without prompting | ||
| --help Show help | ||
| Examples: | ||
| npx dialtone-migrate-chip-interactive | ||
| npx dialtone-migrate-chip-interactive --dry-run | ||
| npx dialtone-migrate-chip-interactive --cwd ./src | ||
| npx dialtone-migrate-chip-interactive --yes | ||
| `); | ||
| } | ||
| function parseArgs (args) { | ||
| const cwdIndex = args.indexOf('--cwd'); | ||
| return { | ||
| help: args.includes('--help'), | ||
| dryRun: args.includes('--dry-run'), | ||
| autoYes: args.includes('--yes'), | ||
| cwd: cwdIndex !== -1 && args[cwdIndex + 1] | ||
| ? path.resolve(args[cwdIndex + 1]) | ||
| : process.cwd(), | ||
| }; | ||
| } | ||
| async function prompt (question) { | ||
| const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); | ||
| return new Promise(resolve => { | ||
| rl.question(question, answer => { | ||
| rl.close(); | ||
| resolve(answer.trim().toLowerCase()); | ||
| }); | ||
| }); | ||
| } | ||
| async function scanFiles (cwd) { | ||
| const extensions = ['.vue']; | ||
| const ignore = ['node_modules', 'dist', '.git', '.vuepress/public', '.vuepress/.temp', '.vuepress/.cache']; | ||
| const files = await findFiles(cwd, extensions, ignore); | ||
| const changes = []; | ||
| const allWarnings = []; | ||
| for (const file of files) { | ||
| const content = await fs.readFile(file, 'utf8'); | ||
| const { transformed, warnings } = transformContent(content, { | ||
| filePath: path.relative(cwd, file), | ||
| }); | ||
| if (transformed !== content) { | ||
| changes.push({ file, content, transformed }); | ||
| } | ||
| if (warnings.length) allWarnings.push(...warnings); | ||
| } | ||
| return { changes, allWarnings }; | ||
| } | ||
| async function applyChanges (changes, autoYes) { | ||
| if (!autoYes) { | ||
| const answer = await prompt('\nApply changes? (y/N) '); | ||
| if (answer !== 'y' && answer !== 'yes') { | ||
| console.log('Cancelled.'); | ||
| return false; | ||
| } | ||
| } | ||
| for (const { file, transformed } of changes) { | ||
| await fs.writeFile(file, transformed, 'utf8'); | ||
| } | ||
| return true; | ||
| } | ||
| function printWarnings (warnings) { | ||
| if (!warnings.length) return; | ||
| console.log('\nWarnings — manual review required:\n'); | ||
| for (const w of warnings) console.log(` ${w}`); | ||
| console.log(); | ||
| } | ||
| function printChangeSummary (changes, cwd) { | ||
| console.log(`\nFound changes in ${changes.length} file(s):\n`); | ||
| for (const { file } of changes) { | ||
| console.log(` ${path.relative(cwd, file)}`); | ||
| } | ||
| } | ||
| async function main () { | ||
| const opts = parseArgs(process.argv.slice(2)); | ||
| if (opts.help) { | ||
| printHelp(); | ||
| process.exit(0); | ||
| } | ||
| console.log(`\nScanning ${opts.cwd} for DtChip usages...`); | ||
| const { changes, allWarnings } = await scanFiles(opts.cwd); | ||
| printWarnings(allWarnings); | ||
| if (changes.length === 0) { | ||
| console.log(allWarnings.length | ||
| ? 'No automated code changes needed. See manual review items above.' | ||
| : 'No DtChip usages found. Nothing to migrate.'); | ||
| process.exit(0); | ||
| } | ||
| printChangeSummary(changes, opts.cwd); | ||
| if (opts.dryRun) { | ||
| console.log('\n--dry-run: No files were modified.'); | ||
| process.exit(0); | ||
| } | ||
| const applied = await applyChanges(changes, opts.autoYes); | ||
| if (applied) console.log(`\nMigrated ${changes.length} file(s).\n`); | ||
| } | ||
| const isDirectRun = (() => { | ||
| try { | ||
| return realpathSync(process.argv[1]) === fileURLToPath(import.meta.url); | ||
| } catch { | ||
| return false; | ||
| } | ||
| })(); | ||
| if (isDirectRun) { | ||
| main().catch(err => { | ||
| console.error(err); | ||
| process.exit(1); | ||
| }); | ||
| } |
| /** | ||
| * DLT-3195 — dialtone-migrate-chip-interactive tests. | ||
| * | ||
| * One assertion per test; data-driven via for..of where multiple cases share a concept. | ||
| */ | ||
| import { describe, it } from 'node:test'; | ||
| import assert from 'node:assert/strict'; | ||
| import { transformContent } from './index.mjs'; | ||
| function run (input) { | ||
| const { transformed } = transformContent(input, { filePath: 'test.vue' }); | ||
| return transformed; | ||
| } | ||
| function warnings (input) { | ||
| return transformContent(input, { filePath: 'test.vue' }).warnings; | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // Auto-add :interactive="true" for chips with click handlers | ||
| // --------------------------------------------------------------------------- | ||
| describe('quoted value false-positive prevention', () => { | ||
| it('does not false-positive on @click inside a quoted attribute value', () => { | ||
| const input = '<dt-chip :title=" @click is cool">Label</dt-chip>'; | ||
| assert.equal(run(input), input); | ||
| assert.equal(warnings(input).length, 1); | ||
| }); | ||
| it('does not false-positive on interactive inside a quoted attribute value', () => { | ||
| // HAS_INTERACTIVE_RE must not fire on this — chip still needs fixing | ||
| const input = '<dt-chip :aria-label="set interactive prop" @click="go">Label</dt-chip>'; | ||
| const expected = '<dt-chip :interactive="true" :aria-label="set interactive prop" @click="go">Label</dt-chip>'; | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| it('real :interactive prop still prevents insertion', () => { | ||
| const input = '<dt-chip :interactive="false" @click="go">Label</dt-chip>'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| }); | ||
| describe('quote-aware attribute parsing — > inside quoted value', () => { | ||
| it('handles > inside a quoted attribute value before @click', () => { | ||
| const input = '<dt-chip :class="a > b" @click="onClick">Label</dt-chip>'; | ||
| const expected = '<dt-chip :interactive="true" :class="a > b" @click="onClick">Label</dt-chip>'; | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| it('does not warn when @click is present but attrs contain quoted >', () => { | ||
| const input = '<dt-chip :class="a > b" @click="onClick">Label</dt-chip>'; | ||
| assert.equal(warnings(input).length, 0); | ||
| }); | ||
| it('handles > inside a single-quoted attribute value', () => { | ||
| const input = '<dt-chip :title="x > y" @click="onClick">Label</dt-chip>'; | ||
| const expected = '<dt-chip :interactive="true" :title="x > y" @click="onClick">Label</dt-chip>'; | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| }); | ||
| describe('chips with @click — auto-add :interactive="true"', () => { | ||
| const cases = [ | ||
| [ | ||
| 'single-line chip with @click', | ||
| '<dt-chip @click="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" @click="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with @click.stop modifier', | ||
| '<dt-chip @click.stop="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" @click.stop="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with @click.prevent modifier', | ||
| '<dt-chip @click.prevent="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" @click.prevent="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with v-on:click', | ||
| '<dt-chip v-on:click="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" v-on:click="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with other props and @click', | ||
| '<dt-chip :size="200" :disabled="isDisabled" @click="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" :size="200" :disabled="isDisabled" @click="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'self-closing chip with @click', | ||
| '<dt-chip @click="handleClick" />', | ||
| '<dt-chip :interactive="true" @click="handleClick" />', | ||
| ], | ||
| [ | ||
| 'PascalCase DtChip with @click', | ||
| '<DtChip @click="handleClick">Label</DtChip>', | ||
| '<DtChip :interactive="true" @click="handleClick">Label</DtChip>', | ||
| ], | ||
| ]; | ||
| for (const [label, input, expected] of cases) { | ||
| it(label, () => { | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| } | ||
| }); | ||
| describe('chips with v-on object binding — auto-add :interactive="true"', () => { | ||
| const cases = [ | ||
| [ | ||
| 'chip with v-on object binding (double quotes)', | ||
| '<dt-chip v-on="chipListeners">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" v-on="chipListeners">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with v-on object binding (single quotes)', | ||
| '<dt-chip v-on=\'chipListeners\'>Label</dt-chip>', | ||
| '<dt-chip :interactive="true" v-on=\'chipListeners\'>Label</dt-chip>', | ||
| ], | ||
| ]; | ||
| for (const [label, input, expected] of cases) { | ||
| it(label, () => { | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| } | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Skip chips that already have the interactive prop | ||
| // --------------------------------------------------------------------------- | ||
| describe('chips that already have interactive prop — no change', () => { | ||
| const cases = [ | ||
| [ | ||
| 'already has :interactive="true"', | ||
| '<dt-chip :interactive="true" @click="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'already has :interactive="false"', | ||
| '<dt-chip :interactive="false">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'already has plain interactive', | ||
| '<dt-chip interactive>Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'already has v-bind:interactive', | ||
| '<dt-chip v-bind:interactive="isInteractive">Label</dt-chip>', | ||
| ], | ||
| ]; | ||
| for (const [label, input] of cases) { | ||
| it(label, () => { | ||
| assert.equal(run(input), input); | ||
| }); | ||
| } | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Chips with no click handler — warn, no change | ||
| // --------------------------------------------------------------------------- | ||
| describe('chips with no click handler — no change, emit warning', () => { | ||
| it('display-only chip produces no output change', () => { | ||
| const input = '<dt-chip>Label</dt-chip>'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| it('display-only chip emits a warning', () => { | ||
| const input = '<dt-chip>Label</dt-chip>'; | ||
| assert.equal(warnings(input).length, 1); | ||
| }); | ||
| it('warning message mentions the file path', () => { | ||
| const { warnings: w } = transformContent('<dt-chip>Label</dt-chip>', { filePath: 'src/MyComponent.vue' }); | ||
| assert.ok(w[0].includes('src/MyComponent.vue')); | ||
| }); | ||
| it('chip with @close only (no @click) emits warning, no auto-change', () => { | ||
| const input = '<dt-chip @close="onRemove">Label</dt-chip>'; | ||
| assert.equal(run(input), input); | ||
| assert.equal(warnings(input).length, 1); | ||
| }); | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Multiple chips in one file | ||
| // --------------------------------------------------------------------------- | ||
| describe('multiple chips in one file', () => { | ||
| it('adds :interactive to the clickable chip only', () => { | ||
| const input = [ | ||
| '<dt-chip @click="onClick">Clickable</dt-chip>', | ||
| '<dt-chip>Display</dt-chip>', | ||
| ].join('\n'); | ||
| const expected = [ | ||
| '<dt-chip :interactive="true" @click="onClick">Clickable</dt-chip>', | ||
| '<dt-chip>Display</dt-chip>', | ||
| ].join('\n'); | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| it('warns once per display-only chip', () => { | ||
| const input = [ | ||
| '<dt-chip>Label A</dt-chip>', | ||
| '<dt-chip>Label B</dt-chip>', | ||
| ].join('\n'); | ||
| assert.equal(warnings(input).length, 2); | ||
| }); | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Inert content masking — should not match chips in comments or script | ||
| // --------------------------------------------------------------------------- | ||
| describe('inert content masking', () => { | ||
| it('does not transform chip inside HTML comment', () => { | ||
| const input = '<!-- <dt-chip @click="x">hidden</dt-chip> -->'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| it('does not transform chip inside <script>', () => { | ||
| const input = '<script>\nconst example = `<dt-chip @click="x">Label</dt-chip>`;\n</script>'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Fast path — no-op on files with no dt-chip reference | ||
| // --------------------------------------------------------------------------- | ||
| describe('fast path', () => { | ||
| it('returns unchanged content when no dt-chip present', () => { | ||
| const input = '<dt-button @click="x">Click</dt-button>'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| it('emits no warnings when no dt-chip present', () => { | ||
| const input = '<dt-button @click="x">Click</dt-button>'; | ||
| assert.equal(warnings(input).length, 0); | ||
| }); | ||
| }); |
| #!/usr/bin/env node | ||
| /** | ||
| * @fileoverview Migration script for v-dt-scrollbar :never → :always rename. | ||
| * | ||
| * DLT-3158 The `:never` directive argument was renamed to `:always` to reflect | ||
| * its actual meaning (always show the scrollbar, never auto-hide it). | ||
| * The `DtBox` `scrollbar="never"` prop value is similarly renamed to | ||
| * `scrollbar="always"`. | ||
| * | ||
| * This script: | ||
| * - Replaces `v-dt-scrollbar:never` with `v-dt-scrollbar:always` in .vue and .html files. | ||
| * - Replaces `scrollbar="never"` with `scrollbar="always"` (DtBox prop) in .vue files. | ||
| * - Replaces `:scrollbar="'never'"` and `scrollbar='never'` variants in .vue files. | ||
| * | ||
| * Usage: | ||
| * npx dialtone-migrate-scrollbar-always [options] | ||
| * | ||
| * Options: | ||
| * --cwd <path> Working directory (default: cwd) | ||
| * --dry-run Show changes without applying them | ||
| * --yes Apply all changes without prompting | ||
| * --help Show help | ||
| */ | ||
| import fs from 'fs/promises'; | ||
| import { realpathSync } from 'node:fs'; | ||
| import path from 'path'; | ||
| import readline from 'readline'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| // --------------------------------------------------------------------------- | ||
| // Transform | ||
| // --------------------------------------------------------------------------- | ||
| /** | ||
| * Apply all renames to a single file's content. | ||
| * Returns the transformed string (may be identical to input if no matches). | ||
| */ | ||
| export function transformContent (content) { | ||
| return content | ||
| // v-dt-scrollbar:never → v-dt-scrollbar:always | ||
| .replace(/v-dt-scrollbar:never\b/g, 'v-dt-scrollbar:always') | ||
| // DtBox scrollbar prop: match the entire opening <dt-box>/<DtBox> tag, rewrite only within it | ||
| .replace(/<(dt-box|DtBox)\b[\s\S]*?>/g, tag => | ||
| tag | ||
| // scrollbar="never" → scrollbar="always" (unbound prop only; negative lookbehind excludes :scrollbar="never") | ||
| .replace(/(?<!:)\bscrollbar="never"/g, 'scrollbar="always"') | ||
| // scrollbar='never' → scrollbar='always' (unbound prop only) | ||
| .replace(/(?<!:)\bscrollbar='never'/g, 'scrollbar=\'always\'') | ||
| // :scrollbar="'never'" → :scrollbar="'always'" | ||
| .replace(/:scrollbar="'never'"/g, ':scrollbar="\'always\'"') | ||
| // :scrollbar="\"never\"" → :scrollbar="\"always\"" | ||
| .replace(/:scrollbar='"never"'/g, ':scrollbar=\'"always"\''), | ||
| ); | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // File walker | ||
| // --------------------------------------------------------------------------- | ||
| function isIgnoredPath (fullPath, ignore) { | ||
| const segments = fullPath.split(path.sep); | ||
| return ignore.some(ig => { | ||
| if (ig.includes('/')) { | ||
| const parts = ig.split('/'); | ||
| for (let i = 0; i + parts.length <= segments.length; i++) { | ||
| if (parts.every((p, j) => segments[i + j] === p)) return true; | ||
| } | ||
| return false; | ||
| } | ||
| return segments.includes(ig); | ||
| }); | ||
| } | ||
| async function findFiles (dir, extensions, ignore = []) { | ||
| const results = []; | ||
| async function walk (currentDir) { | ||
| let entries; | ||
| try { | ||
| entries = await fs.readdir(currentDir, { withFileTypes: true }); | ||
| } catch { | ||
| return; | ||
| } | ||
| for (const entry of entries) { | ||
| const fullPath = path.join(currentDir, entry.name); | ||
| if (isIgnoredPath(fullPath, ignore)) continue; | ||
| if (entry.isDirectory()) { | ||
| await walk(fullPath); | ||
| } else if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) { | ||
| results.push(fullPath); | ||
| } | ||
| } | ||
| } | ||
| await walk(dir); | ||
| return results; | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // CLI plumbing | ||
| // --------------------------------------------------------------------------- | ||
| function printHelp () { | ||
| console.log(` | ||
| Usage: npx dialtone-migrate-scrollbar-always [options] | ||
| Renames the v-dt-scrollbar ":never" directive argument to ":always" (DLT-3158). | ||
| Also renames the DtBox scrollbar="never" prop value to scrollbar="always". | ||
| Options: | ||
| --cwd <path> Working directory (default: cwd) | ||
| --dry-run Show changes without applying them | ||
| --yes Apply all changes without prompting | ||
| --help Show help | ||
| Examples: | ||
| npx dialtone-migrate-scrollbar-always | ||
| npx dialtone-migrate-scrollbar-always --dry-run | ||
| npx dialtone-migrate-scrollbar-always --cwd ./src | ||
| npx dialtone-migrate-scrollbar-always --yes | ||
| `); | ||
| } | ||
| function parseArgs (args) { | ||
| const cwdIndex = args.indexOf('--cwd'); | ||
| return { | ||
| help: args.includes('--help'), | ||
| dryRun: args.includes('--dry-run'), | ||
| autoYes: args.includes('--yes'), | ||
| cwd: cwdIndex !== -1 && args[cwdIndex + 1] | ||
| ? path.resolve(args[cwdIndex + 1]) | ||
| : process.cwd(), | ||
| }; | ||
| } | ||
| async function prompt (question) { | ||
| const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); | ||
| return new Promise(resolve => { | ||
| rl.question(question, answer => { | ||
| rl.close(); | ||
| resolve(answer.trim().toLowerCase()); | ||
| }); | ||
| }); | ||
| } | ||
| async function scanFiles (cwd) { | ||
| const extensions = ['.vue', '.html']; | ||
| const ignore = ['node_modules', 'dist', '.git', '.vuepress/public', '.vuepress/.temp', '.vuepress/.cache', 'storybook-static']; | ||
| const files = await findFiles(cwd, extensions, ignore); | ||
| const changes = []; | ||
| for (const file of files) { | ||
| const content = await fs.readFile(file, 'utf8'); | ||
| const transformed = transformContent(content); | ||
| if (transformed !== content) { | ||
| changes.push({ file, content, transformed }); | ||
| } | ||
| } | ||
| return changes; | ||
| } | ||
| async function applyChanges (changes, autoYes) { | ||
| if (!autoYes) { | ||
| const answer = await prompt('\nApply changes? (y/N) '); | ||
| if (answer !== 'y' && answer !== 'yes') { | ||
| console.log('Cancelled.'); | ||
| return false; | ||
| } | ||
| } | ||
| for (const { file, transformed } of changes) { | ||
| await fs.writeFile(file, transformed, 'utf8'); | ||
| } | ||
| return true; | ||
| } | ||
| function printChangeSummary (changes, cwd) { | ||
| console.log(`\nFound changes in ${changes.length} file(s):\n`); | ||
| for (const { file } of changes) { | ||
| console.log(` ${path.relative(cwd, file)}`); | ||
| } | ||
| } | ||
| async function main () { | ||
| const opts = parseArgs(process.argv.slice(2)); | ||
| if (opts.help) { | ||
| printHelp(); | ||
| process.exit(0); | ||
| } | ||
| console.log(`\nScanning ${opts.cwd} for v-dt-scrollbar:never and scrollbar="never" usages...`); | ||
| const changes = await scanFiles(opts.cwd); | ||
| if (changes.length === 0) { | ||
| console.log('No usages found. Nothing to migrate.'); | ||
| process.exit(0); | ||
| } | ||
| printChangeSummary(changes, opts.cwd); | ||
| if (opts.dryRun) { | ||
| console.log('\n--dry-run: No files were modified.'); | ||
| process.exit(0); | ||
| } | ||
| const applied = await applyChanges(changes, opts.autoYes); | ||
| if (applied) console.log(`\nMigrated ${changes.length} file(s).\n`); | ||
| } | ||
| const isDirectRun = (() => { | ||
| try { | ||
| return realpathSync(process.argv[1]) === fileURLToPath(import.meta.url); | ||
| } catch { | ||
| return false; | ||
| } | ||
| })(); | ||
| if (isDirectRun) { | ||
| main().catch(err => { | ||
| console.error(err); | ||
| process.exit(1); | ||
| }); | ||
| } |
| #!/usr/bin/env node | ||
| /** | ||
| * @fileoverview Migration script for DtChip `interactive` prop default change. | ||
| * | ||
| * DLT-3195 DtChip `interactive` prop default changed from `true` → `false`. | ||
| * Chips that need click/keyboard behavior must now explicitly set | ||
| * `:interactive="true"`. | ||
| * | ||
| * This script: | ||
| * - Adds `:interactive="true"` to <dt-chip> tags that have a click event | ||
| * listener (@click, v-on:click) or an object v-on binding (v-on="…"), | ||
| * since those clearly need interactive behavior. | ||
| * - Skips chips that already set the `interactive` prop (any form). | ||
| * - Warns about remaining chips with no `interactive` prop and no detected | ||
| * click handler — these may be display-only (no change needed) or may | ||
| * need `:interactive="true"` added manually. | ||
| * | ||
| * Usage: | ||
| * npx dialtone-migrate-chip-interactive [options] | ||
| * | ||
| * Options: | ||
| * --cwd <path> Working directory (default: cwd) | ||
| * --dry-run Show changes without applying them | ||
| * --yes Apply all changes without prompting | ||
| * --help Show help | ||
| */ | ||
| import fs from 'fs/promises'; | ||
| import { realpathSync } from 'node:fs'; | ||
| import path from 'path'; | ||
| import readline from 'readline'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| // --------------------------------------------------------------------------- | ||
| // Constants | ||
| // --------------------------------------------------------------------------- | ||
| // Quote-aware attribute body. Matches sequences of non-quote/non-gt chars | ||
| // optionally followed by a fully-quoted attribute value, so `>` inside a | ||
| // quoted value like `:class="a > b"` does not prematurely terminate the tag. | ||
| const QUOTE_AWARE_ATTRS = '(?:[^>"\']|"[^"]*"|\'[^\']*\')*'; | ||
| // Matches `<dt-chip` or `<DtChip` opening tags (including self-closing). | ||
| // Group 1: tag name; group 2: attributes (quote-aware); group 3: closer (`>` or `/>`). | ||
| const CHIP_TAG_RE = new RegExp( | ||
| `(<(?:dt-chip|DtChip)\\b)(${QUOTE_AWARE_ATTRS})(\\s*\\/?>)`, | ||
| 'g', | ||
| ); | ||
| // Detects that the `interactive` prop is already present in any form: | ||
| // interactive, :interactive, v-bind:interactive | ||
| const HAS_INTERACTIVE_RE = /(?:^|\s)(?::|v-bind:)?interactive(?:\s*=|\s|\/|>)/; | ||
| // Detects a click event listener: | ||
| // @click, v-on:click, @click.stop, @click.prevent, etc. | ||
| const HAS_CLICK_RE = /(?:^|\s)(?:@click|v-on:click)(?:\s*=|\s*\.|\/|>|\s)/; | ||
| // Detects an object-form v-on binding (v-on="…") which may contain click. | ||
| // We treat this conservatively as "may be interactive" and add the prop. | ||
| const HAS_VON_OBJECT_RE = /(?:^|\s)v-on\s*=\s*(?:"[^"]*"|'[^']*')/; | ||
| // --------------------------------------------------------------------------- | ||
| // Transform | ||
| // --------------------------------------------------------------------------- | ||
| /** | ||
| * Strip quoted attribute values from an attrs string before regex testing. | ||
| * Replaces "…" and '…' with empty equivalents so keywords that happen to | ||
| * appear inside a quoted value (e.g. :title=" @click is cool") don't | ||
| * false-positive against HAS_CLICK_RE / HAS_INTERACTIVE_RE / HAS_VON_OBJECT_RE. | ||
| * Real attribute tokens like @click="handler" survive as @click="" and still match. | ||
| */ | ||
| function stripQuotedValues (attrs) { | ||
| return attrs.replace(/"[^"]*"|'[^']*'/g, match => (match[0] === '"' ? '""' : '\'\'')); | ||
| } | ||
| /** | ||
| * Find the position to insert `:interactive="true"` — immediately after the | ||
| * tag name so it appears first in the attribute list (consistent with existing | ||
| * Dialtone convention where `:interactive` is an early structural prop). | ||
| * | ||
| * Returns the index within `attrs` where the insertion should happen. | ||
| * We insert after any leading whitespace on the attribute string. | ||
| */ | ||
| function insertInteractiveProp (attrs) { | ||
| const leadingSpace = attrs.match(/^\s*/)[0]; | ||
| const rest = attrs.slice(leadingSpace.length); | ||
| // Preserve the original leading whitespace, then prepend the prop | ||
| return `${leadingSpace}:interactive="true" ${rest}`; | ||
| } | ||
| /** | ||
| * Transform a single file's content. | ||
| * Returns { transformed, warnings } where warnings are strings. | ||
| */ | ||
| export function transformContent (content, opts = {}) { | ||
| const filePath = opts.filePath || '<input>'; | ||
| const warnings = []; | ||
| // Fast path: skip files with no dt-chip / DtChip reference at all. | ||
| if (!/(?:dt-chip|DtChip)/i.test(content)) { | ||
| return { transformed: content, warnings }; | ||
| } | ||
| // Mask inert content (HTML comments, <script>, <style>) so we don't | ||
| // accidentally match tag-like text inside them. | ||
| const { masked, segments, token } = maskInertContent(content); | ||
| let out = masked; | ||
| const replacements = []; | ||
| // Reset lastIndex before iterating | ||
| CHIP_TAG_RE.lastIndex = 0; | ||
| let m; | ||
| while ((m = CHIP_TAG_RE.exec(out)) !== null) { | ||
| const [fullMatch, openTag, attrs, closer] = m; | ||
| const matchStart = m.index; | ||
| const matchEnd = matchStart + fullMatch.length; | ||
| // Strip quoted values before regex testing so keywords inside quoted | ||
| // attribute values don't produce false positives. | ||
| const attrsForTest = stripQuotedValues(attrs); | ||
| // Already has the interactive prop — nothing to do. | ||
| if (HAS_INTERACTIVE_RE.test(attrsForTest)) continue; | ||
| const hasClick = HAS_CLICK_RE.test(attrsForTest); | ||
| const hasVOnObject = HAS_VON_OBJECT_RE.test(attrsForTest); | ||
| if (hasClick || hasVOnObject) { | ||
| // Auto-add :interactive="true" | ||
| const newAttrs = insertInteractiveProp(attrs); | ||
| replacements.push({ | ||
| start: matchStart, | ||
| end: matchEnd, | ||
| text: `${openTag}${newAttrs}${closer}`, | ||
| }); | ||
| } else { | ||
| // No click handler and no interactive prop. | ||
| // Warn: this chip will now render as a <span>. May be intentional | ||
| // (display-only) or may need :interactive="true" manually. | ||
| warnings.push( | ||
| `${filePath}: <dt-chip> has no interactive prop and no @click handler — ` + | ||
| `will now render as a non-interactive <span>. ` + | ||
| `Add :interactive="true" if this chip should be clickable.`, | ||
| ); | ||
| } | ||
| } | ||
| // Apply replacements in reverse order to preserve indices | ||
| replacements.sort((a, b) => b.start - a.start); | ||
| for (const r of replacements) { | ||
| out = out.slice(0, r.start) + r.text + out.slice(r.end); | ||
| } | ||
| return { transformed: unmaskInertContent(out, segments, token), warnings }; | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // Inert-content masking (same pattern as dialtone_migrate_link_rendering) | ||
| // --------------------------------------------------------------------------- | ||
| function maskInertContent (content) { | ||
| const token = Math.random().toString(36).slice(2, 10); | ||
| const innerRe = /<!--[\s\S]*?-->|<script\b[^>]*>[\s\S]*?<\/script>|<style\b[^>]*>[\s\S]*?<\/style>/g; | ||
| const segments = []; | ||
| const masked = content.replace(innerRe, (match) => { | ||
| const placeholder = ` DT_MIGRATE_INERT_${token}_${segments.length} `; | ||
| segments.push(match); | ||
| return placeholder; | ||
| }); | ||
| return { masked, segments, token }; | ||
| } | ||
| function unmaskInertContent (masked, segments, token) { | ||
| return masked.replace(new RegExp(` DT_MIGRATE_INERT_${token}_(\\d+) `, 'g'), (_, idx) => segments[Number(idx)]); | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // File walker | ||
| // --------------------------------------------------------------------------- | ||
| function isIgnoredPath (fullPath, ignore) { | ||
| const segments = fullPath.split(path.sep); | ||
| return ignore.some(ig => { | ||
| if (ig.includes('/')) { | ||
| const parts = ig.split('/'); | ||
| for (let i = 0; i + parts.length <= segments.length; i++) { | ||
| if (parts.every((p, j) => segments[i + j] === p)) return true; | ||
| } | ||
| return false; | ||
| } | ||
| return segments.includes(ig); | ||
| }); | ||
| } | ||
| async function findFiles (dir, extensions, ignore = []) { | ||
| const results = []; | ||
| async function walk (currentDir) { | ||
| let entries; | ||
| try { | ||
| entries = await fs.readdir(currentDir, { withFileTypes: true }); | ||
| } catch { | ||
| return; | ||
| } | ||
| for (const entry of entries) { | ||
| const fullPath = path.join(currentDir, entry.name); | ||
| if (isIgnoredPath(fullPath, ignore)) continue; | ||
| if (entry.isDirectory()) { | ||
| await walk(fullPath); | ||
| } else if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) { | ||
| results.push(fullPath); | ||
| } | ||
| } | ||
| } | ||
| await walk(dir); | ||
| return results; | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // CLI plumbing | ||
| // --------------------------------------------------------------------------- | ||
| function printHelp () { | ||
| console.log(` | ||
| Usage: npx dialtone-migrate-chip-interactive [options] | ||
| Migrates DtChip usage after the \`interactive\` prop default changed from | ||
| \`true\` to \`false\` (DLT-3195). | ||
| Chips with a @click handler or v-on object binding automatically receive | ||
| :interactive="true". All other chips without an existing interactive prop | ||
| are listed as warnings for manual review. | ||
| Options: | ||
| --cwd <path> Working directory (default: cwd) | ||
| --dry-run Show changes without applying them | ||
| --yes Apply all changes without prompting | ||
| --help Show help | ||
| Examples: | ||
| npx dialtone-migrate-chip-interactive | ||
| npx dialtone-migrate-chip-interactive --dry-run | ||
| npx dialtone-migrate-chip-interactive --cwd ./src | ||
| npx dialtone-migrate-chip-interactive --yes | ||
| `); | ||
| } | ||
| function parseArgs (args) { | ||
| const cwdIndex = args.indexOf('--cwd'); | ||
| return { | ||
| help: args.includes('--help'), | ||
| dryRun: args.includes('--dry-run'), | ||
| autoYes: args.includes('--yes'), | ||
| cwd: cwdIndex !== -1 && args[cwdIndex + 1] | ||
| ? path.resolve(args[cwdIndex + 1]) | ||
| : process.cwd(), | ||
| }; | ||
| } | ||
| async function prompt (question) { | ||
| const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); | ||
| return new Promise(resolve => { | ||
| rl.question(question, answer => { | ||
| rl.close(); | ||
| resolve(answer.trim().toLowerCase()); | ||
| }); | ||
| }); | ||
| } | ||
| async function scanFiles (cwd) { | ||
| const extensions = ['.vue']; | ||
| const ignore = ['node_modules', 'dist', '.git', '.vuepress/public', '.vuepress/.temp', '.vuepress/.cache']; | ||
| const files = await findFiles(cwd, extensions, ignore); | ||
| const changes = []; | ||
| const allWarnings = []; | ||
| for (const file of files) { | ||
| const content = await fs.readFile(file, 'utf8'); | ||
| const { transformed, warnings } = transformContent(content, { | ||
| filePath: path.relative(cwd, file), | ||
| }); | ||
| if (transformed !== content) { | ||
| changes.push({ file, content, transformed }); | ||
| } | ||
| if (warnings.length) allWarnings.push(...warnings); | ||
| } | ||
| return { changes, allWarnings }; | ||
| } | ||
| async function applyChanges (changes, autoYes) { | ||
| if (!autoYes) { | ||
| const answer = await prompt('\nApply changes? (y/N) '); | ||
| if (answer !== 'y' && answer !== 'yes') { | ||
| console.log('Cancelled.'); | ||
| return false; | ||
| } | ||
| } | ||
| for (const { file, transformed } of changes) { | ||
| await fs.writeFile(file, transformed, 'utf8'); | ||
| } | ||
| return true; | ||
| } | ||
| function printWarnings (warnings) { | ||
| if (!warnings.length) return; | ||
| console.log('\nWarnings — manual review required:\n'); | ||
| for (const w of warnings) console.log(` ${w}`); | ||
| console.log(); | ||
| } | ||
| function printChangeSummary (changes, cwd) { | ||
| console.log(`\nFound changes in ${changes.length} file(s):\n`); | ||
| for (const { file } of changes) { | ||
| console.log(` ${path.relative(cwd, file)}`); | ||
| } | ||
| } | ||
| async function main () { | ||
| const opts = parseArgs(process.argv.slice(2)); | ||
| if (opts.help) { | ||
| printHelp(); | ||
| process.exit(0); | ||
| } | ||
| console.log(`\nScanning ${opts.cwd} for DtChip usages...`); | ||
| const { changes, allWarnings } = await scanFiles(opts.cwd); | ||
| printWarnings(allWarnings); | ||
| if (changes.length === 0) { | ||
| console.log(allWarnings.length | ||
| ? 'No automated code changes needed. See manual review items above.' | ||
| : 'No DtChip usages found. Nothing to migrate.'); | ||
| process.exit(0); | ||
| } | ||
| printChangeSummary(changes, opts.cwd); | ||
| if (opts.dryRun) { | ||
| console.log('\n--dry-run: No files were modified.'); | ||
| process.exit(0); | ||
| } | ||
| const applied = await applyChanges(changes, opts.autoYes); | ||
| if (applied) console.log(`\nMigrated ${changes.length} file(s).\n`); | ||
| } | ||
| const isDirectRun = (() => { | ||
| try { | ||
| return realpathSync(process.argv[1]) === fileURLToPath(import.meta.url); | ||
| } catch { | ||
| return false; | ||
| } | ||
| })(); | ||
| if (isDirectRun) { | ||
| main().catch(err => { | ||
| console.error(err); | ||
| process.exit(1); | ||
| }); | ||
| } |
| /** | ||
| * DLT-3195 — dialtone-migrate-chip-interactive tests. | ||
| * | ||
| * One assertion per test; data-driven via for..of where multiple cases share a concept. | ||
| */ | ||
| import { describe, it } from 'node:test'; | ||
| import assert from 'node:assert/strict'; | ||
| import { transformContent } from './index.mjs'; | ||
| function run (input) { | ||
| const { transformed } = transformContent(input, { filePath: 'test.vue' }); | ||
| return transformed; | ||
| } | ||
| function warnings (input) { | ||
| return transformContent(input, { filePath: 'test.vue' }).warnings; | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // Auto-add :interactive="true" for chips with click handlers | ||
| // --------------------------------------------------------------------------- | ||
| describe('quoted value false-positive prevention', () => { | ||
| it('does not false-positive on @click inside a quoted attribute value', () => { | ||
| const input = '<dt-chip :title=" @click is cool">Label</dt-chip>'; | ||
| assert.equal(run(input), input); | ||
| assert.equal(warnings(input).length, 1); | ||
| }); | ||
| it('does not false-positive on interactive inside a quoted attribute value', () => { | ||
| // HAS_INTERACTIVE_RE must not fire on this — chip still needs fixing | ||
| const input = '<dt-chip :aria-label="set interactive prop" @click="go">Label</dt-chip>'; | ||
| const expected = '<dt-chip :interactive="true" :aria-label="set interactive prop" @click="go">Label</dt-chip>'; | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| it('real :interactive prop still prevents insertion', () => { | ||
| const input = '<dt-chip :interactive="false" @click="go">Label</dt-chip>'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| }); | ||
| describe('quote-aware attribute parsing — > inside quoted value', () => { | ||
| it('handles > inside a quoted attribute value before @click', () => { | ||
| const input = '<dt-chip :class="a > b" @click="onClick">Label</dt-chip>'; | ||
| const expected = '<dt-chip :interactive="true" :class="a > b" @click="onClick">Label</dt-chip>'; | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| it('does not warn when @click is present but attrs contain quoted >', () => { | ||
| const input = '<dt-chip :class="a > b" @click="onClick">Label</dt-chip>'; | ||
| assert.equal(warnings(input).length, 0); | ||
| }); | ||
| it('handles > inside a single-quoted attribute value', () => { | ||
| const input = '<dt-chip :title="x > y" @click="onClick">Label</dt-chip>'; | ||
| const expected = '<dt-chip :interactive="true" :title="x > y" @click="onClick">Label</dt-chip>'; | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| }); | ||
| describe('chips with @click — auto-add :interactive="true"', () => { | ||
| const cases = [ | ||
| [ | ||
| 'single-line chip with @click', | ||
| '<dt-chip @click="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" @click="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with @click.stop modifier', | ||
| '<dt-chip @click.stop="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" @click.stop="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with @click.prevent modifier', | ||
| '<dt-chip @click.prevent="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" @click.prevent="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with v-on:click', | ||
| '<dt-chip v-on:click="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" v-on:click="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with other props and @click', | ||
| '<dt-chip :size="200" :disabled="isDisabled" @click="handleClick">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" :size="200" :disabled="isDisabled" @click="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'self-closing chip with @click', | ||
| '<dt-chip @click="handleClick" />', | ||
| '<dt-chip :interactive="true" @click="handleClick" />', | ||
| ], | ||
| [ | ||
| 'PascalCase DtChip with @click', | ||
| '<DtChip @click="handleClick">Label</DtChip>', | ||
| '<DtChip :interactive="true" @click="handleClick">Label</DtChip>', | ||
| ], | ||
| ]; | ||
| for (const [label, input, expected] of cases) { | ||
| it(label, () => { | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| } | ||
| }); | ||
| describe('chips with v-on object binding — auto-add :interactive="true"', () => { | ||
| const cases = [ | ||
| [ | ||
| 'chip with v-on object binding (double quotes)', | ||
| '<dt-chip v-on="chipListeners">Label</dt-chip>', | ||
| '<dt-chip :interactive="true" v-on="chipListeners">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'chip with v-on object binding (single quotes)', | ||
| '<dt-chip v-on=\'chipListeners\'>Label</dt-chip>', | ||
| '<dt-chip :interactive="true" v-on=\'chipListeners\'>Label</dt-chip>', | ||
| ], | ||
| ]; | ||
| for (const [label, input, expected] of cases) { | ||
| it(label, () => { | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| } | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Skip chips that already have the interactive prop | ||
| // --------------------------------------------------------------------------- | ||
| describe('chips that already have interactive prop — no change', () => { | ||
| const cases = [ | ||
| [ | ||
| 'already has :interactive="true"', | ||
| '<dt-chip :interactive="true" @click="handleClick">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'already has :interactive="false"', | ||
| '<dt-chip :interactive="false">Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'already has plain interactive', | ||
| '<dt-chip interactive>Label</dt-chip>', | ||
| ], | ||
| [ | ||
| 'already has v-bind:interactive', | ||
| '<dt-chip v-bind:interactive="isInteractive">Label</dt-chip>', | ||
| ], | ||
| ]; | ||
| for (const [label, input] of cases) { | ||
| it(label, () => { | ||
| assert.equal(run(input), input); | ||
| }); | ||
| } | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Chips with no click handler — warn, no change | ||
| // --------------------------------------------------------------------------- | ||
| describe('chips with no click handler — no change, emit warning', () => { | ||
| it('display-only chip produces no output change', () => { | ||
| const input = '<dt-chip>Label</dt-chip>'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| it('display-only chip emits a warning', () => { | ||
| const input = '<dt-chip>Label</dt-chip>'; | ||
| assert.equal(warnings(input).length, 1); | ||
| }); | ||
| it('warning message mentions the file path', () => { | ||
| const { warnings: w } = transformContent('<dt-chip>Label</dt-chip>', { filePath: 'src/MyComponent.vue' }); | ||
| assert.ok(w[0].includes('src/MyComponent.vue')); | ||
| }); | ||
| it('chip with @close only (no @click) emits warning, no auto-change', () => { | ||
| const input = '<dt-chip @close="onRemove">Label</dt-chip>'; | ||
| assert.equal(run(input), input); | ||
| assert.equal(warnings(input).length, 1); | ||
| }); | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Multiple chips in one file | ||
| // --------------------------------------------------------------------------- | ||
| describe('multiple chips in one file', () => { | ||
| it('adds :interactive to the clickable chip only', () => { | ||
| const input = [ | ||
| '<dt-chip @click="onClick">Clickable</dt-chip>', | ||
| '<dt-chip>Display</dt-chip>', | ||
| ].join('\n'); | ||
| const expected = [ | ||
| '<dt-chip :interactive="true" @click="onClick">Clickable</dt-chip>', | ||
| '<dt-chip>Display</dt-chip>', | ||
| ].join('\n'); | ||
| assert.equal(run(input), expected); | ||
| }); | ||
| it('warns once per display-only chip', () => { | ||
| const input = [ | ||
| '<dt-chip>Label A</dt-chip>', | ||
| '<dt-chip>Label B</dt-chip>', | ||
| ].join('\n'); | ||
| assert.equal(warnings(input).length, 2); | ||
| }); | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Inert content masking — should not match chips in comments or script | ||
| // --------------------------------------------------------------------------- | ||
| describe('inert content masking', () => { | ||
| it('does not transform chip inside HTML comment', () => { | ||
| const input = '<!-- <dt-chip @click="x">hidden</dt-chip> -->'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| it('does not transform chip inside <script>', () => { | ||
| const input = '<script>\nconst example = `<dt-chip @click="x">Label</dt-chip>`;\n</script>'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| }); | ||
| // --------------------------------------------------------------------------- | ||
| // Fast path — no-op on files with no dt-chip reference | ||
| // --------------------------------------------------------------------------- | ||
| describe('fast path', () => { | ||
| it('returns unchanged content when no dt-chip present', () => { | ||
| const input = '<dt-button @click="x">Click</dt-button>'; | ||
| assert.equal(run(input), input); | ||
| }); | ||
| it('emits no warnings when no dt-chip present', () => { | ||
| const input = '<dt-button @click="x">Click</dt-button>'; | ||
| assert.equal(warnings(input).length, 0); | ||
| }); | ||
| }); |
| #!/usr/bin/env node | ||
| /** | ||
| * @fileoverview Migration script for v-dt-scrollbar :never → :always rename. | ||
| * | ||
| * DLT-3158 The `:never` directive argument was renamed to `:always` to reflect | ||
| * its actual meaning (always show the scrollbar, never auto-hide it). | ||
| * The `DtBox` `scrollbar="never"` prop value is similarly renamed to | ||
| * `scrollbar="always"`. | ||
| * | ||
| * This script: | ||
| * - Replaces `v-dt-scrollbar:never` with `v-dt-scrollbar:always` in .vue and .html files. | ||
| * - Replaces `scrollbar="never"` with `scrollbar="always"` (DtBox prop) in .vue files. | ||
| * - Replaces `:scrollbar="'never'"` and `scrollbar='never'` variants in .vue files. | ||
| * | ||
| * Usage: | ||
| * npx dialtone-migrate-scrollbar-always [options] | ||
| * | ||
| * Options: | ||
| * --cwd <path> Working directory (default: cwd) | ||
| * --dry-run Show changes without applying them | ||
| * --yes Apply all changes without prompting | ||
| * --help Show help | ||
| */ | ||
| import fs from 'fs/promises'; | ||
| import { realpathSync } from 'node:fs'; | ||
| import path from 'path'; | ||
| import readline from 'readline'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| // --------------------------------------------------------------------------- | ||
| // Transform | ||
| // --------------------------------------------------------------------------- | ||
| /** | ||
| * Apply all renames to a single file's content. | ||
| * Returns the transformed string (may be identical to input if no matches). | ||
| */ | ||
| export function transformContent (content) { | ||
| return content | ||
| // v-dt-scrollbar:never → v-dt-scrollbar:always | ||
| .replace(/v-dt-scrollbar:never\b/g, 'v-dt-scrollbar:always') | ||
| // DtBox scrollbar prop: match the entire opening <dt-box>/<DtBox> tag, rewrite only within it | ||
| .replace(/<(dt-box|DtBox)\b[\s\S]*?>/g, tag => | ||
| tag | ||
| // scrollbar="never" → scrollbar="always" (unbound prop only; negative lookbehind excludes :scrollbar="never") | ||
| .replace(/(?<!:)\bscrollbar="never"/g, 'scrollbar="always"') | ||
| // scrollbar='never' → scrollbar='always' (unbound prop only) | ||
| .replace(/(?<!:)\bscrollbar='never'/g, 'scrollbar=\'always\'') | ||
| // :scrollbar="'never'" → :scrollbar="'always'" | ||
| .replace(/:scrollbar="'never'"/g, ':scrollbar="\'always\'"') | ||
| // :scrollbar="\"never\"" → :scrollbar="\"always\"" | ||
| .replace(/:scrollbar='"never"'/g, ':scrollbar=\'"always"\''), | ||
| ); | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // File walker | ||
| // --------------------------------------------------------------------------- | ||
| function isIgnoredPath (fullPath, ignore) { | ||
| const segments = fullPath.split(path.sep); | ||
| return ignore.some(ig => { | ||
| if (ig.includes('/')) { | ||
| const parts = ig.split('/'); | ||
| for (let i = 0; i + parts.length <= segments.length; i++) { | ||
| if (parts.every((p, j) => segments[i + j] === p)) return true; | ||
| } | ||
| return false; | ||
| } | ||
| return segments.includes(ig); | ||
| }); | ||
| } | ||
| async function findFiles (dir, extensions, ignore = []) { | ||
| const results = []; | ||
| async function walk (currentDir) { | ||
| let entries; | ||
| try { | ||
| entries = await fs.readdir(currentDir, { withFileTypes: true }); | ||
| } catch { | ||
| return; | ||
| } | ||
| for (const entry of entries) { | ||
| const fullPath = path.join(currentDir, entry.name); | ||
| if (isIgnoredPath(fullPath, ignore)) continue; | ||
| if (entry.isDirectory()) { | ||
| await walk(fullPath); | ||
| } else if (entry.isFile() && extensions.some(ext => entry.name.endsWith(ext))) { | ||
| results.push(fullPath); | ||
| } | ||
| } | ||
| } | ||
| await walk(dir); | ||
| return results; | ||
| } | ||
| // --------------------------------------------------------------------------- | ||
| // CLI plumbing | ||
| // --------------------------------------------------------------------------- | ||
| function printHelp () { | ||
| console.log(` | ||
| Usage: npx dialtone-migrate-scrollbar-always [options] | ||
| Renames the v-dt-scrollbar ":never" directive argument to ":always" (DLT-3158). | ||
| Also renames the DtBox scrollbar="never" prop value to scrollbar="always". | ||
| Options: | ||
| --cwd <path> Working directory (default: cwd) | ||
| --dry-run Show changes without applying them | ||
| --yes Apply all changes without prompting | ||
| --help Show help | ||
| Examples: | ||
| npx dialtone-migrate-scrollbar-always | ||
| npx dialtone-migrate-scrollbar-always --dry-run | ||
| npx dialtone-migrate-scrollbar-always --cwd ./src | ||
| npx dialtone-migrate-scrollbar-always --yes | ||
| `); | ||
| } | ||
| function parseArgs (args) { | ||
| const cwdIndex = args.indexOf('--cwd'); | ||
| return { | ||
| help: args.includes('--help'), | ||
| dryRun: args.includes('--dry-run'), | ||
| autoYes: args.includes('--yes'), | ||
| cwd: cwdIndex !== -1 && args[cwdIndex + 1] | ||
| ? path.resolve(args[cwdIndex + 1]) | ||
| : process.cwd(), | ||
| }; | ||
| } | ||
| async function prompt (question) { | ||
| const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); | ||
| return new Promise(resolve => { | ||
| rl.question(question, answer => { | ||
| rl.close(); | ||
| resolve(answer.trim().toLowerCase()); | ||
| }); | ||
| }); | ||
| } | ||
| async function scanFiles (cwd) { | ||
| const extensions = ['.vue', '.html']; | ||
| const ignore = ['node_modules', 'dist', '.git', '.vuepress/public', '.vuepress/.temp', '.vuepress/.cache', 'storybook-static']; | ||
| const files = await findFiles(cwd, extensions, ignore); | ||
| const changes = []; | ||
| for (const file of files) { | ||
| const content = await fs.readFile(file, 'utf8'); | ||
| const transformed = transformContent(content); | ||
| if (transformed !== content) { | ||
| changes.push({ file, content, transformed }); | ||
| } | ||
| } | ||
| return changes; | ||
| } | ||
| async function applyChanges (changes, autoYes) { | ||
| if (!autoYes) { | ||
| const answer = await prompt('\nApply changes? (y/N) '); | ||
| if (answer !== 'y' && answer !== 'yes') { | ||
| console.log('Cancelled.'); | ||
| return false; | ||
| } | ||
| } | ||
| for (const { file, transformed } of changes) { | ||
| await fs.writeFile(file, transformed, 'utf8'); | ||
| } | ||
| return true; | ||
| } | ||
| function printChangeSummary (changes, cwd) { | ||
| console.log(`\nFound changes in ${changes.length} file(s):\n`); | ||
| for (const { file } of changes) { | ||
| console.log(` ${path.relative(cwd, file)}`); | ||
| } | ||
| } | ||
| async function main () { | ||
| const opts = parseArgs(process.argv.slice(2)); | ||
| if (opts.help) { | ||
| printHelp(); | ||
| process.exit(0); | ||
| } | ||
| console.log(`\nScanning ${opts.cwd} for v-dt-scrollbar:never and scrollbar="never" usages...`); | ||
| const changes = await scanFiles(opts.cwd); | ||
| if (changes.length === 0) { | ||
| console.log('No usages found. Nothing to migrate.'); | ||
| process.exit(0); | ||
| } | ||
| printChangeSummary(changes, opts.cwd); | ||
| if (opts.dryRun) { | ||
| console.log('\n--dry-run: No files were modified.'); | ||
| process.exit(0); | ||
| } | ||
| const applied = await applyChanges(changes, opts.autoYes); | ||
| if (applied) console.log(`\nMigrated ${changes.length} file(s).\n`); | ||
| } | ||
| const isDirectRun = (() => { | ||
| try { | ||
| return realpathSync(process.argv[1]) === fileURLToPath(import.meta.url); | ||
| } catch { | ||
| return false; | ||
| } | ||
| })(); | ||
| if (isDirectRun) { | ||
| main().catch(err => { | ||
| console.error(err); | ||
| process.exit(1); | ||
| }); | ||
| } |
@@ -102,2 +102,3 @@ // | ||
| // ============================================================================ | ||
@@ -144,2 +145,3 @@ // $ VALUE LISTS | ||
| padding-inline: var(--box-pis, var(--box-pi, var(--box-p, 0))) var(--box-pie, var(--box-pi, var(--box-p, 0))); | ||
| } | ||
@@ -146,0 +148,0 @@ |
@@ -55,3 +55,2 @@ // | ||
| &:active { | ||
| // --link-text-decoration: underline; | ||
| color: var(--link-color-default); | ||
@@ -195,8 +194,11 @@ } | ||
| --link-color-default-hover: var(--dt-color-link-primary-inverted-hover); | ||
| --link-text-decoration: none; | ||
| --link-padding: 0 var(--dt-spacing-25); | ||
| --link-background-color: oklch(from var(--dt-color-surface-brand-strong) l c h /0.3); | ||
| --link-background-color: var(--dt-color-link-mention-inverted-background); | ||
| line-height: var(--dt-font-line-height-200); | ||
| border-radius: var(--dt-size-radius-200); | ||
| border-radius: var(--dt-size-radius-300); | ||
| &:hover { | ||
| --link-background-color: var(--dt-color-link-mention-inverted-background-hover); | ||
| } | ||
| } | ||
@@ -206,25 +208,18 @@ | ||
| // ---------------------------------------------------------------------------- | ||
| // Styling specific to mentions such as @brad.paugh. The underline highlighting | ||
| // is reversed compared to a regular link, and it has a light background. | ||
| // Styling for @mention links (e.g. @brad.paugh). Displays as a pill-shaped | ||
| // background using brand surface tokens. Background changes on hover. | ||
| &--mention { | ||
| --link-text-decoration: none; | ||
| --link-padding: 0 var(--dt-spacing-25); | ||
| --link-background-color: oklch(from var(--dt-color-surface-brand-strong) l c h /0.1); | ||
| --link-color-default: var(--dt-color-link-mention); | ||
| --link-color-default-hover: var(--dt-color-link-mention-hover); | ||
| --link-padding: var(--dt-spacing-1) var(--dt-spacing-25); | ||
| --link-background-color: var(--dt-color-link-mention-background); | ||
| line-height: var(--dt-font-line-height-200); | ||
| border-radius: var(--dt-size-radius-200); | ||
| border-radius: var(--dt-size-radius-300); | ||
| &:hover { | ||
| --link-text-decoration: underline; | ||
| --link-background-color: oklch(from var(--dt-color-surface-brand-strong) l c h /0.25); | ||
| text-underline-offset: var(--dt-spacing-25); | ||
| text-decoration-thickness: var(--dt-size-border-100); | ||
| --link-background-color: var(--dt-color-link-mention-background-hover); | ||
| } | ||
| &:active { | ||
| --link-background-color: oklch(from var(--dt-color-surface-brand-strong) l c h /0.1); | ||
| } | ||
| } | ||
| } | ||
| } |
@@ -117,3 +117,3 @@ // | ||
| .d-toast.d-toast--important { | ||
| --notice-color-background: var(--dt-color-surface-strong); | ||
| --notice-color-background: var(--dt-color-surface-primary-inverted); | ||
| --notice-color-text: var(--dt-color-foreground-primary-inverted); | ||
@@ -120,0 +120,0 @@ --notice-color-icon: var(--notice-color-text); |
@@ -33,2 +33,24 @@ /* validate-layers: off */ | ||
| } | ||
| // Track offsets via CSS custom properties set by v-dt-scrollbar directive. | ||
| // The base rules (0,3,0) beat OS's non-cornerless rules (0,1,0). | ||
| // The cornerless overrides (0,4,0) beat OS's cornerless rules (0,3,0) which reset | ||
| // top/bottom on vertical and left/right on horizontal — regardless of import order. | ||
| &.os-scrollbar-vertical { | ||
| inset-block-start: var(--dt-scrollbar-offset-block-start, 0); | ||
| inset-inline-end: var(--dt-scrollbar-offset-inline-end, 0); | ||
| } | ||
| &.os-scrollbar-vertical.os-scrollbar-cornerless { | ||
| inset-block: var(--dt-scrollbar-offset-block-start, 0) var(--dt-scrollbar-offset-block-end, 0); | ||
| } | ||
| &.os-scrollbar-horizontal { | ||
| inset-block-end: var(--dt-scrollbar-offset-block-end, 0); | ||
| inset-inline-start: var(--dt-scrollbar-offset-inline-start, 0); | ||
| } | ||
| &.os-scrollbar-horizontal.os-scrollbar-cornerless { | ||
| inset-inline: var(--dt-scrollbar-offset-inline-start, 0) var(--dt-scrollbar-offset-inline-end, 0); | ||
| } | ||
| } | ||
@@ -35,0 +57,0 @@ } |
@@ -136,1 +136,8 @@ // | ||
| } | ||
| @layer dialtone.utilities { | ||
| /* | ||
| [data-dt-brand="prota-deuter"] { --dt-color-surface-info-opaque: oklch(from var(--dt-color-blue-300) l c h / 0.5) !important; } | ||
| [data-dt-brand="prota-deuter"][data-dt-mode="dark"] { --dt-color-surface-info-opaque: oklch(from var(--dt-color-blue-300) l c h / 0.6) !important; } | ||
| */ | ||
| } |
@@ -103,14 +103,14 @@ @layer dialtone.base {/** | ||
| --dt-color-indigo-50: oklch(0.1938 0.0398 236.11); | ||
| --dt-color-teal-1000: oklch(0.9841 0.0096 189.07); | ||
| --dt-color-teal-950: oklch(0.9727 0.0302 191.61); | ||
| --dt-color-teal-900: oklch(0.9444 0.05 191.72); | ||
| --dt-color-teal-800: oklch(0.9223 0.0705 191.59); | ||
| --dt-color-teal-700: oklch(0.8709 0.0908 191.27); | ||
| --dt-color-teal-600: oklch(0.8114 0.1149 190.22); | ||
| --dt-color-teal-500: oklch(0.7098 0.1095 190.41); | ||
| --dt-color-teal-400: oklch(0.6099 0.1 189.66); | ||
| --dt-color-teal-300: oklch(0.501 0.0805 189.24); | ||
| --dt-color-teal-200: oklch(0.3749 0.0599 190.01); | ||
| --dt-color-teal-100: oklch(0.2671 0.0407 189.77); | ||
| --dt-color-teal-50: oklch(0.1839 0.0252 190.56); | ||
| --dt-color-teal-1000: oklch(0.9802 0.0070 200); | ||
| --dt-color-teal-950: oklch(0.9574 0.0140 200); | ||
| --dt-color-teal-900: oklch(0.9088 0.0460 200); | ||
| --dt-color-teal-800: oklch(0.8614 0.0860 200); | ||
| --dt-color-teal-700: oklch(0.7803 0.1080 200); | ||
| --dt-color-teal-600: oklch(0.7060 0.1200 200); | ||
| --dt-color-teal-500: oklch(0.6526 0.1240 200); | ||
| --dt-color-teal-400: oklch(0.5743 0.1260 201); | ||
| --dt-color-teal-300: oklch(0.4546 0.1140 202); | ||
| --dt-color-teal-200: oklch(0.3449 0.0840 203); | ||
| --dt-color-teal-100: oklch(0.2161 0.0480 204); | ||
| --dt-color-teal-50: oklch(0.1442 0.0300 205); | ||
| --dt-color-olive-1000: oklch(0.9815 0.027 93.1); | ||
@@ -128,14 +128,14 @@ --dt-color-olive-950: oklch(0.9563 0.0607 95.13); | ||
| --dt-color-olive-50: oklch(0.2228 0.047 103.99); | ||
| --dt-color-coral-1000: oklch(0.9741 0.0115 37.42); | ||
| --dt-color-coral-950: oklch(0.9145 0.0398 43.39); | ||
| --dt-color-coral-900: oklch(0.8254 0.0954 39.92); | ||
| --dt-color-coral-800: oklch(0.7329 0.1552 38.73); | ||
| --dt-color-coral-700: oklch(0.6828 0.2004 37.3); | ||
| --dt-color-coral-600: oklch(0.6305 0.2167 35.54); | ||
| --dt-color-coral-500: oklch(0.5698 0.1932 35.27); | ||
| --dt-color-coral-400: oklch(0.4911 0.1632 35.8); | ||
| --dt-color-coral-300: oklch(0.4167 0.1356 35.76); | ||
| --dt-color-coral-200: oklch(0.3452 0.1072 37.37); | ||
| --dt-color-coral-100: oklch(0.265 0.0723 40.9); | ||
| --dt-color-coral-50: oklch(0.2001 0.0507 45.42); | ||
| --dt-color-coral-1000: oklch(0.9834 0.0115 42); | ||
| --dt-color-coral-950: oklch(0.9658 0.0398 43); | ||
| --dt-color-coral-900: oklch(0.9328 0.0750 41); | ||
| --dt-color-coral-800: oklch(0.9030 0.1100 40); | ||
| --dt-color-coral-700: oklch(0.8394 0.1500 38); | ||
| --dt-color-coral-600: oklch(0.7806 0.1850 37); | ||
| --dt-color-coral-500: oklch(0.7111 0.2050 36); | ||
| --dt-color-coral-400: oklch(0.6203 0.2100 35); | ||
| --dt-color-coral-300: oklch(0.4762 0.1700 35); | ||
| --dt-color-coral-200: oklch(0.3497 0.1280 36); | ||
| --dt-color-coral-100: oklch(0.2386 0.0750 38); | ||
| --dt-color-coral-50: oklch(0.1994 0.0507 42); | ||
| --dt-color-berry-1000: oklch(0.9709 0.0244 327.79); | ||
@@ -165,14 +165,14 @@ --dt-color-berry-950: oklch(0.9518 0.0405 328.39); | ||
| --dt-color-tan-50: oklch(0.1456 0.0028 68.55); | ||
| --dt-color-red-1000: oklch(0.9716 0.0141 12.01); | ||
| --dt-color-red-950: oklch(0.926 0.0299 15.15); | ||
| --dt-color-red-900: oklch(0.8206 0.0707 24.14); | ||
| --dt-color-red-800: oklch(0.7202 0.1741 23.26); | ||
| --dt-color-red-700: oklch(0.6649 0.2 23.09); | ||
| --dt-color-red-600: oklch(0.6147 0.2301 18.88); | ||
| --dt-color-red-500: oklch(0.5638 0.2148 16.42); | ||
| --dt-color-red-400: oklch(0.4788 0.1855 16.67); | ||
| --dt-color-red-300: oklch(0.4046 0.1551 11.36); | ||
| --dt-color-red-200: oklch(0.3207 0.125 12.36); | ||
| --dt-color-red-100: oklch(0.2395 0.0904 17.78); | ||
| --dt-color-red-50: oklch(0.173 0.0657 16.5); | ||
| --dt-color-red-1000: oklch(0.936 0.0322 22.46); | ||
| --dt-color-red-950: oklch(0.8774 0.0653 17.3); | ||
| --dt-color-red-900: oklch(0.8211 0.1019 12.69); | ||
| --dt-color-red-800: oklch(0.7713 0.1367 14.03); | ||
| --dt-color-red-700: oklch(0.6886 0.204 14.67); | ||
| --dt-color-red-600: oklch(0.6392 0.25 15.77); | ||
| --dt-color-red-500: oklch(0.5724 0.229466 18.56); | ||
| --dt-color-red-400: oklch(0.4703 0.1879 17.53); | ||
| --dt-color-red-300: oklch(0.385 0.15406 16.4808); | ||
| --dt-color-red-200: oklch(0.3132 0.1252 14.67); | ||
| --dt-color-red-100: oklch(0.2429 0.0952 12.48); | ||
| --dt-color-red-50: oklch(0.1721 0.0689 8); | ||
| --dt-color-green-1000: oklch(0.9852 0.0069 124.45); | ||
@@ -190,62 +190,62 @@ --dt-color-green-950: oklch(0.9708 0.0324 127.99); | ||
| --dt-color-green-50: oklch(0.2214 0.0599 130.32); | ||
| --dt-color-gold-1000: oklch(0.9834 0.028 95.89); | ||
| --dt-color-gold-950: oklch(0.9658 0.0531 94.43); | ||
| --dt-color-gold-900: oklch(0.9328 0.0981 93.22); | ||
| --dt-color-gold-800: oklch(0.903 0.1174 88.43); | ||
| --dt-color-gold-700: oklch(0.8394 0.149 78.12); | ||
| --dt-color-gold-600: oklch(0.7806 0.1652 70.4); | ||
| --dt-color-gold-500: oklch(0.7111 0.1585 65.89); | ||
| --dt-color-gold-400: oklch(0.6203 0.1351 64.5); | ||
| --dt-color-gold-300: oklch(0.4762 0.101 68.29); | ||
| --dt-color-gold-200: oklch(0.3497 0.0735 68.31); | ||
| --dt-color-gold-100: oklch(0.2386 0.0474 74.23); | ||
| --dt-color-gold-50: oklch(0.1994 0.0396 76.09); | ||
| --dt-color-magenta-1000: oklch(0.9654 0.0225 341.31); | ||
| --dt-color-magenta-950: oklch(0.9373 0.0412 342.14); | ||
| --dt-color-magenta-900: oklch(0.8428 0.0978 354.64); | ||
| --dt-color-magenta-800: oklch(0.7677 0.1528 355.76); | ||
| --dt-color-magenta-700: oklch(0.7048 0.2009 357.71); | ||
| --dt-color-magenta-600: oklch(0.6629 0.2447 351.8); | ||
| --dt-color-magenta-500: oklch(0.5868 0.238 350.69); | ||
| --dt-color-magenta-400: oklch(0.5339 0.2193 349.23); | ||
| --dt-color-magenta-300: oklch(0.4542 0.175 347.48); | ||
| --dt-color-magenta-200: oklch(0.3726 0.1454 342.26); | ||
| --dt-color-magenta-100: oklch(0.2373 0.0953 343.1); | ||
| --dt-color-magenta-50: oklch(0.1639 0.062 340.52); | ||
| --dt-color-blue-1000: oklch(0.9802 0.0068 247.89); | ||
| --dt-color-blue-950: oklch(0.9574 0.0137 247.97); | ||
| --dt-color-blue-900: oklch(0.9088 0.045 231.65); | ||
| --dt-color-blue-800: oklch(0.8614 0.0838 231.39); | ||
| --dt-color-blue-700: oklch(0.7803 0.1096 234.16); | ||
| --dt-color-blue-600: oklch(0.706 0.1304 241.91); | ||
| --dt-color-blue-500: oklch(0.6526 0.1385 246.51); | ||
| --dt-color-blue-400: oklch(0.5743 0.1498 251.06); | ||
| --dt-color-blue-300: oklch(0.4546 0.136 256.17); | ||
| --dt-color-blue-200: oklch(0.3449 0.0951 254.97); | ||
| --dt-color-blue-100: oklch(0.2161 0.0514 247.62); | ||
| --dt-color-blue-50: oklch(0.1442 0.0315 244.16); | ||
| --dt-color-purple-1000: oklch(0.978 0.0123 301.29); | ||
| --dt-color-purple-950: oklch(0.9347 0.0306 302.3); | ||
| --dt-color-purple-900: oklch(0.8371 0.0754 300.31); | ||
| --dt-color-purple-800: oklch(0.7755 0.1222 294.6); | ||
| --dt-color-purple-700: oklch(0.7113 0.1613 290.66); | ||
| --dt-color-purple-600: oklch(0.6464 0.1985 289.97); | ||
| --dt-color-purple-500: oklch(0.5851 0.2414 287.62); | ||
| --dt-color-purple-400: oklch(0.5217 0.2647 284.59); | ||
| --dt-color-purple-300: oklch(0.4638 0.2502 281.37); | ||
| --dt-color-purple-200: oklch(0.361 0.1955 283.93); | ||
| --dt-color-purple-100: oklch(0.2281 0.1309 285.47); | ||
| --dt-color-purple-50: oklch(0.1599 0.0811 291.62); | ||
| --dt-color-gold-1000: oklch(0.9818 0.0152 77.07); | ||
| --dt-color-gold-950: oklch(0.9436 0.0483 77.26); | ||
| --dt-color-gold-900: oklch(0.9018 0.0868 77.62); | ||
| --dt-color-gold-800: oklch(0.8585 0.122968 75.6919); | ||
| --dt-color-gold-700: oklch(0.8105 0.1572 71.72); | ||
| --dt-color-gold-600: oklch(0.7807 0.1708 66.55); | ||
| --dt-color-gold-500: oklch(0.7336 0.174556 58.5601); | ||
| --dt-color-gold-400: oklch(0.5888 0.138492 59.7021); | ||
| --dt-color-gold-300: oklch(0.418 0.096552 61.5939); | ||
| --dt-color-gold-200: oklch(0.3218 0.0723 64.75); | ||
| --dt-color-gold-100: oklch(0.2269 0.049661 68.4257); | ||
| --dt-color-gold-50: oklch(0.1849 0.0386 77.52); | ||
| --dt-color-magenta-1000: oklch(0.9317 0.0463 340.48); | ||
| --dt-color-magenta-950: oklch(0.8813 0.0822 342.24); | ||
| --dt-color-magenta-900: oklch(0.8232 0.1275 343.61); | ||
| --dt-color-magenta-800: oklch(0.7802 0.164 344.57); | ||
| --dt-color-magenta-700: oklch(0.7038 0.232 347.8); | ||
| --dt-color-magenta-600: oklch(0.663 0.2652 351.9); | ||
| --dt-color-magenta-500: oklch(0.5768 0.237302 354.3202); | ||
| --dt-color-magenta-400: oklch(0.4724 0.194579 353.8977); | ||
| --dt-color-magenta-300: oklch(0.3868 0.1589 353.23); | ||
| --dt-color-magenta-200: oklch(0.2808 0.1164 351.92); | ||
| --dt-color-magenta-100: oklch(0.227 0.0946 350.32); | ||
| --dt-color-magenta-50: oklch(0.1422 0.0604 345.16); | ||
| --dt-color-blue-1000: oklch(0.9486 0.0246 257.65); | ||
| --dt-color-blue-950: oklch(0.9037 0.047 257.26); | ||
| --dt-color-blue-900: oklch(0.8437 0.0781 257.48); | ||
| --dt-color-blue-800: oklch(0.7558 0.1259 258.28); | ||
| --dt-color-blue-700: oklch(0.6566 0.1838 258.62); | ||
| --dt-color-blue-600: oklch(0.6089 0.2128 259.28); | ||
| --dt-color-blue-500: oklch(0.5552 0.223 260.26); | ||
| --dt-color-blue-400: oklch(0.4857 0.205 260.61); | ||
| --dt-color-blue-300: oklch(0.4126 0.1703 260.22); | ||
| --dt-color-blue-200: oklch(0.3269 0.1294 259.43); | ||
| --dt-color-blue-100: oklch(0.2552 0.0945 258.02); | ||
| --dt-color-blue-50: oklch(0.163 0.0489 252.1); | ||
| --dt-color-purple-1000: oklch(0.9514 0.0276 301.76); | ||
| --dt-color-purple-950: oklch(0.9029 0.056 301.24); | ||
| --dt-color-purple-900: oklch(0.8546 0.085 300.63); | ||
| --dt-color-purple-800: oklch(0.7697 0.130656 294.1037); | ||
| --dt-color-purple-700: oklch(0.6717 0.189855 291.5342); | ||
| --dt-color-purple-600: oklch(0.5829 0.2426 287.41); | ||
| --dt-color-purple-500: oklch(0.4831 0.2316 284.82); | ||
| --dt-color-purple-400: oklch(0.4108 0.2066 284.07); | ||
| --dt-color-purple-300: oklch(0.3629 0.1821 284.23); | ||
| --dt-color-purple-200: oklch(0.2984 0.1549 283.05); | ||
| --dt-color-purple-100: oklch(0.2244 0.131 285.15); | ||
| --dt-color-purple-50: oklch(0.1531 0.0859 291.49); | ||
| --dt-color-black-1000: oklch(1 0 0); | ||
| --dt-color-black-950: oklch(0.9821 0 0); | ||
| --dt-color-black-900: oklch(0.9249 0 0); | ||
| --dt-color-black-800: oklch(0.8699 0 0); | ||
| --dt-color-black-700: oklch(0.8297 0 0); | ||
| --dt-color-black-600: oklch(0.7572 0 0); | ||
| --dt-color-black-500: oklch(0.5999 0 0); | ||
| --dt-color-black-400: oklch(0.4495 0 0); | ||
| --dt-color-black-300: oklch(0.36 0 0); | ||
| --dt-color-black-200: oklch(0.2393 0 0); | ||
| --dt-color-black-100: oklch(0.2046 0 0); | ||
| --dt-color-black-50: oklch(0 0 0); | ||
| --dt-color-black-950: oklch(0.9774 0.0025 48.72); | ||
| --dt-color-black-900: oklch(0.9312 0.0029 84.56); | ||
| --dt-color-black-800: oklch(0.858 0.0059 84.57); | ||
| --dt-color-black-700: oklch(0.7321 0.0061 84.57); | ||
| --dt-color-black-600: oklch(0.6001 0.0032 84.56); | ||
| --dt-color-black-500: oklch(0.5134 0.0063 95.18); | ||
| --dt-color-black-400: oklch(0.4468 0.0055 78.27); | ||
| --dt-color-black-300: oklch(0.3352 0.0055 56.21); | ||
| --dt-color-black-200: oklch(0.2572 0.0063 78.21); | ||
| --dt-color-black-100: oklch(0.2134 0.006 91.63); | ||
| --dt-color-black-50: oklch(0.1595 0.0045 84.59); | ||
| --dt-color-neutral-transparent: transparent; /* Transparent color independent of any theme. */ | ||
@@ -401,3 +401,3 @@ --dt-color-neutral-black: oklch(0 0 0); /* Black color independent of any theme. */ | ||
| --dt-shadow-focus-inset-offset-x: var(--dt-size-0); | ||
| --dt-shadow-focus-inset-color: oklch(0.6526 0.1385 246.51); | ||
| --dt-shadow-focus-inset-color: oklch(0.5552 0.223 260.26); | ||
| --dt-shadow-focus-inset-spread: var(--dt-size-200); | ||
@@ -407,3 +407,3 @@ --dt-shadow-focus-inset-blur: var(--dt-size-0); | ||
| --dt-shadow-focus-2-offset-x: var(--dt-size-0); | ||
| --dt-shadow-focus-2-color: oklch(0.6526 0.1385 246.51); | ||
| --dt-shadow-focus-2-color: oklch(0.5552 0.223 260.26); | ||
| --dt-shadow-focus-2-spread: calc(var(--dt-size-200) + var(--dt-size-100)); | ||
@@ -413,3 +413,3 @@ --dt-shadow-focus-2-blur: var(--dt-size-0); | ||
| --dt-shadow-focus-1-offset-x: var(--dt-size-0); | ||
| --dt-shadow-focus-1-color: oklch(0.2046 0 0); | ||
| --dt-shadow-focus-1-color: oklch(0.2134 0.006 91.63); | ||
| --dt-shadow-focus-1-spread: var(--dt-size-100); | ||
@@ -416,0 +416,0 @@ --dt-shadow-focus-1-blur: var(--dt-size-0); |
@@ -53,14 +53,14 @@ @layer dialtone.base {/** | ||
| --dt-color-indigo-50: oklch(0.9723 0.0074 260.73); | ||
| --dt-color-teal-1000: oklch(0.1839 0.0252 190.56); | ||
| --dt-color-teal-950: oklch(0.2671 0.0407 189.77); | ||
| --dt-color-teal-900: oklch(0.3749 0.0599 190.01); | ||
| --dt-color-teal-800: oklch(0.501 0.0805 189.24); | ||
| --dt-color-teal-700: oklch(0.6099 0.1 189.66); | ||
| --dt-color-teal-600: oklch(0.7098 0.1095 190.41); | ||
| --dt-color-teal-500: oklch(0.8114 0.1149 190.22); | ||
| --dt-color-teal-400: oklch(0.8709 0.0908 191.27); | ||
| --dt-color-teal-300: oklch(0.9223 0.0705 191.59); | ||
| --dt-color-teal-200: oklch(0.9444 0.05 191.72); | ||
| --dt-color-teal-100: oklch(0.9727 0.0302 191.61); | ||
| --dt-color-teal-50: oklch(0.9841 0.0096 189.07); | ||
| --dt-color-teal-1000: oklch(0.1442 0.0300 205); | ||
| --dt-color-teal-950: oklch(0.2161 0.0480 204); | ||
| --dt-color-teal-900: oklch(0.3449 0.0840 203); | ||
| --dt-color-teal-800: oklch(0.4546 0.1140 202); | ||
| --dt-color-teal-700: oklch(0.5743 0.1260 201); | ||
| --dt-color-teal-600: oklch(0.6526 0.1240 200); | ||
| --dt-color-teal-500: oklch(0.7060 0.1200 200); | ||
| --dt-color-teal-400: oklch(0.7803 0.1080 200); | ||
| --dt-color-teal-300: oklch(0.8614 0.0860 200); | ||
| --dt-color-teal-200: oklch(0.9088 0.0460 200); | ||
| --dt-color-teal-100: oklch(0.9574 0.0140 200); | ||
| --dt-color-teal-50: oklch(0.9802 0.0070 200); | ||
| --dt-color-olive-1000: oklch(0.2228 0.047 103.99); | ||
@@ -78,14 +78,14 @@ --dt-color-olive-950: oklch(0.256 0.0488 104.11); | ||
| --dt-color-olive-50: oklch(0.9815 0.027 93.1); | ||
| --dt-color-coral-1000: oklch(0.2001 0.0507 45.42); | ||
| --dt-color-coral-950: oklch(0.265 0.0723 40.9); | ||
| --dt-color-coral-900: oklch(0.3452 0.1072 37.37); | ||
| --dt-color-coral-800: oklch(0.4167 0.1356 35.76); | ||
| --dt-color-coral-700: oklch(0.4911 0.1632 35.8); | ||
| --dt-color-coral-600: oklch(0.5698 0.1932 35.27); | ||
| --dt-color-coral-500: oklch(0.6305 0.2167 35.54); | ||
| --dt-color-coral-400: oklch(0.6828 0.2004 37.3); | ||
| --dt-color-coral-300: oklch(0.7329 0.1552 38.73); | ||
| --dt-color-coral-200: oklch(0.8254 0.0954 39.92); | ||
| --dt-color-coral-100: oklch(0.9145 0.0398 43.39); | ||
| --dt-color-coral-50: oklch(0.9741 0.0115 37.42); | ||
| --dt-color-coral-1000: oklch(0.1994 0.0507 42); | ||
| --dt-color-coral-950: oklch(0.2386 0.0750 38); | ||
| --dt-color-coral-900: oklch(0.3497 0.1280 36); | ||
| --dt-color-coral-800: oklch(0.4762 0.1700 35); | ||
| --dt-color-coral-700: oklch(0.6203 0.2100 35); | ||
| --dt-color-coral-600: oklch(0.7111 0.2050 36); | ||
| --dt-color-coral-500: oklch(0.7806 0.1850 37); | ||
| --dt-color-coral-400: oklch(0.8394 0.1500 38); | ||
| --dt-color-coral-300: oklch(0.9030 0.1100 40); | ||
| --dt-color-coral-200: oklch(0.9328 0.0750 41); | ||
| --dt-color-coral-100: oklch(0.9658 0.0398 43); | ||
| --dt-color-coral-50: oklch(0.9834 0.0115 42); | ||
| --dt-color-berry-1000: oklch(0.1805 0.061 307.56); | ||
@@ -115,14 +115,14 @@ --dt-color-berry-950: oklch(0.2636 0.0991 307.61); | ||
| --dt-color-tan-50: oklch(0.9766 0.0017 67.8); | ||
| --dt-color-red-1000: oklch(0.173 0.0657 16.5); | ||
| --dt-color-red-950: oklch(0.2395 0.0904 17.78); | ||
| --dt-color-red-900: oklch(0.3207 0.125 12.36); | ||
| --dt-color-red-800: oklch(0.4046 0.1551 11.36); | ||
| --dt-color-red-700: oklch(0.4788 0.1855 16.67); | ||
| --dt-color-red-600: oklch(0.5638 0.2148 16.42); | ||
| --dt-color-red-500: oklch(0.6147 0.2301 18.88); | ||
| --dt-color-red-400: oklch(0.6649 0.2 23.09); | ||
| --dt-color-red-300: oklch(0.7303 0.1397 25.27); | ||
| --dt-color-red-200: oklch(0.8206 0.0707 24.14); | ||
| --dt-color-red-100: oklch(0.926 0.0299 15.15); | ||
| --dt-color-red-50: oklch(0.9716 0.0141 12.01); | ||
| --dt-color-red-1000: oklch(0.1721 0.0689 8); | ||
| --dt-color-red-950: oklch(0.2429 0.0952 12.48); | ||
| --dt-color-red-900: oklch(0.3132 0.1252 14.67); | ||
| --dt-color-red-800: oklch(0.385 0.15406 16.4808); | ||
| --dt-color-red-700: oklch(0.4703 0.1879 17.53); | ||
| --dt-color-red-600: oklch(0.5724 0.229466 18.56); | ||
| --dt-color-red-500: oklch(0.6392 0.25 15.77); | ||
| --dt-color-red-400: oklch(0.6886 0.204 14.67); | ||
| --dt-color-red-300: oklch(0.7713 0.1367 14.03); | ||
| --dt-color-red-200: oklch(0.8211 0.1019 12.69); | ||
| --dt-color-red-100: oklch(0.8774 0.0653 17.3); | ||
| --dt-color-red-50: oklch(0.936 0.0322 22.46); | ||
| --dt-color-green-1000: oklch(0.2077 0.0458 161.69); | ||
@@ -140,61 +140,61 @@ --dt-color-green-950: oklch(0.2725 0.0631 158.54); | ||
| --dt-color-green-50: oklch(0.9766 0.0201 169.36); | ||
| --dt-color-gold-1000: oklch(0.1994 0.0396 76.09); | ||
| --dt-color-gold-950: oklch(0.2386 0.0474 74.23); | ||
| --dt-color-gold-900: oklch(0.3497 0.0735 68.31); | ||
| --dt-color-gold-800: oklch(0.4762 0.101 68.29); | ||
| --dt-color-gold-700: oklch(0.6203 0.1351 64.5); | ||
| --dt-color-gold-600: oklch(0.7111 0.1585 65.89); | ||
| --dt-color-gold-500: oklch(0.7806 0.1652 70.4); | ||
| --dt-color-gold-400: oklch(0.8394 0.149 78.12); | ||
| --dt-color-gold-300: oklch(0.903 0.1174 88.43); | ||
| --dt-color-gold-200: oklch(0.9328 0.0981 93.22); | ||
| --dt-color-gold-100: oklch(0.9658 0.0531 94.43); | ||
| --dt-color-gold-50: oklch(0.9834 0.028 95.89); | ||
| --dt-color-magenta-1000: oklch(0.1639 0.062 340.52); | ||
| --dt-color-magenta-950: oklch(0.2373 0.0953 343.1); | ||
| --dt-color-magenta-900: oklch(0.3726 0.1454 342.26); | ||
| --dt-color-magenta-800: oklch(0.4542 0.175 347.48); | ||
| --dt-color-magenta-700: oklch(0.5339 0.2193 349.23); | ||
| --dt-color-magenta-600: oklch(0.5868 0.238 350.69); | ||
| --dt-color-magenta-500: oklch(0.6629 0.2447 351.8); | ||
| --dt-color-magenta-400: oklch(0.7048 0.2009 357.71); | ||
| --dt-color-magenta-300: oklch(0.7677 0.1528 355.76); | ||
| --dt-color-magenta-200: oklch(0.8428 0.0978 354.64); | ||
| --dt-color-magenta-100: oklch(0.9373 0.0412 342.14); | ||
| --dt-color-magenta-50: oklch(0.9654 0.0225 341.31); | ||
| --dt-color-blue-1000: oklch(0.1442 0.0315 244.16); | ||
| --dt-color-blue-950: oklch(0.2161 0.0514 247.62); | ||
| --dt-color-blue-900: oklch(0.3449 0.0951 254.97); | ||
| --dt-color-blue-800: oklch(0.4546 0.136 256.17); | ||
| --dt-color-blue-700: oklch(0.5743 0.1498 251.06); | ||
| --dt-color-blue-600: oklch(0.6526 0.1385 246.51); | ||
| --dt-color-blue-500: oklch(0.706 0.1304 241.91); | ||
| --dt-color-blue-400: oklch(0.7803 0.1096 234.16); | ||
| --dt-color-blue-300: oklch(0.8614 0.0838 231.39); | ||
| --dt-color-blue-200: oklch(0.9088 0.045 231.65); | ||
| --dt-color-blue-100: oklch(0.9574 0.0137 247.97); | ||
| --dt-color-blue-50: oklch(0.9802 0.0068 247.89); | ||
| --dt-color-purple-1000: oklch(0.1599 0.0811 291.62); | ||
| --dt-color-purple-950: oklch(0.2281 0.1309 285.47); | ||
| --dt-color-purple-900: oklch(0.361 0.1955 283.93); | ||
| --dt-color-purple-800: oklch(0.4638 0.2502 281.37); | ||
| --dt-color-purple-700: oklch(0.5217 0.2647 284.59); | ||
| --dt-color-purple-600: oklch(0.5851 0.2414 287.62); | ||
| --dt-color-purple-500: oklch(0.6464 0.1985 289.97); | ||
| --dt-color-purple-400: oklch(0.7113 0.1613 290.66); | ||
| --dt-color-purple-300: oklch(0.7755 0.1222 294.6); | ||
| --dt-color-purple-200: oklch(0.8371 0.0754 300.31); | ||
| --dt-color-purple-100: oklch(0.9347 0.0306 302.3); | ||
| --dt-color-purple-50: oklch(0.978 0.0123 301.29); | ||
| --dt-color-black-1000: oklch(0 0 0); | ||
| --dt-color-black-950: oklch(0.2046 0 0); | ||
| --dt-color-black-900: oklch(0.2264 0 0); | ||
| --dt-color-black-800: oklch(0.2645 0 0); | ||
| --dt-color-black-700: oklch(0.3485 0 0); | ||
| --dt-color-black-600: oklch(0.4423 0 0); | ||
| --dt-color-black-500: oklch(0.5999 0 0); | ||
| --dt-color-black-400: oklch(0.738 0 0); | ||
| --dt-color-black-300: oklch(0.8638 0 0); | ||
| --dt-color-black-200: oklch(0.934 0 0); | ||
| --dt-color-black-100: oklch(0.9821 0 0); | ||
| --dt-color-gold-1000: oklch(0.1849 0.0386 77.52); | ||
| --dt-color-gold-950: oklch(0.2269 0.049661 68.4257); | ||
| --dt-color-gold-900: oklch(0.3218 0.0723 64.75); | ||
| --dt-color-gold-800: oklch(0.418 0.096552 61.5939); | ||
| --dt-color-gold-700: oklch(0.5888 0.138492 59.7021); | ||
| --dt-color-gold-600: oklch(0.7336 0.174556 58.5601); | ||
| --dt-color-gold-500: oklch(0.7807 0.1708 66.55); | ||
| --dt-color-gold-400: oklch(0.8105 0.1572 71.72); | ||
| --dt-color-gold-300: oklch(0.8585 0.122968 75.6919); | ||
| --dt-color-gold-200: oklch(0.9018 0.0868 77.62); | ||
| --dt-color-gold-100: oklch(0.9436 0.0483 77.26); | ||
| --dt-color-gold-50: oklch(0.9818 0.0152 77.07); | ||
| --dt-color-magenta-1000: oklch(0.1422 0.0604 345.16); | ||
| --dt-color-magenta-950: oklch(0.227 0.0946 350.32); | ||
| --dt-color-magenta-900: oklch(0.2808 0.1164 351.92); | ||
| --dt-color-magenta-800: oklch(0.3868 0.1589 353.23); | ||
| --dt-color-magenta-700: oklch(0.4724 0.194579 353.8977); | ||
| --dt-color-magenta-600: oklch(0.5768 0.237302 354.3202); | ||
| --dt-color-magenta-500: oklch(0.663 0.2652 351.9); | ||
| --dt-color-magenta-400: oklch(0.7038 0.232 347.8); | ||
| --dt-color-magenta-300: oklch(0.7802 0.164 344.57); | ||
| --dt-color-magenta-200: oklch(0.8232 0.1275 343.61); | ||
| --dt-color-magenta-100: oklch(0.8813 0.0822 342.24); | ||
| --dt-color-magenta-50: oklch(0.9317 0.0463 340.48); | ||
| --dt-color-blue-1000: oklch(0.163 0.0489 252.1); | ||
| --dt-color-blue-950: oklch(0.2552 0.0945 258.02); | ||
| --dt-color-blue-900: oklch(0.3269 0.1294 259.43); | ||
| --dt-color-blue-800: oklch(0.4126 0.1703 260.22); | ||
| --dt-color-blue-700: oklch(0.4857 0.205 260.61); | ||
| --dt-color-blue-600: oklch(0.5552 0.223 260.26); | ||
| --dt-color-blue-500: oklch(0.6089 0.2128 259.28); | ||
| --dt-color-blue-400: oklch(0.6566 0.1838 258.62); | ||
| --dt-color-blue-300: oklch(0.7558 0.1259 258.28); | ||
| --dt-color-blue-200: oklch(0.8437 0.0781 257.48); | ||
| --dt-color-blue-100: oklch(0.9037 0.047 257.26); | ||
| --dt-color-blue-50: oklch(0.9486 0.0246 257.65); | ||
| --dt-color-purple-1000: oklch(0.1531 0.0859 291.49); | ||
| --dt-color-purple-950: oklch(0.2244 0.131 285.15); | ||
| --dt-color-purple-900: oklch(0.2984 0.1549 283.05); | ||
| --dt-color-purple-800: oklch(0.3629 0.1821 284.23); | ||
| --dt-color-purple-700: oklch(0.4108 0.2066 284.07); | ||
| --dt-color-purple-600: oklch(0.4831 0.2316 284.82); | ||
| --dt-color-purple-500: oklch(0.5829 0.2426 287.41); | ||
| --dt-color-purple-400: oklch(0.6717 0.189855 291.5342); | ||
| --dt-color-purple-300: oklch(0.7697 0.130656 294.1037); | ||
| --dt-color-purple-200: oklch(0.8546 0.085 300.63); | ||
| --dt-color-purple-100: oklch(0.9029 0.056 301.24); | ||
| --dt-color-purple-50: oklch(0.9514 0.0276 301.76); | ||
| --dt-color-black-1000: oklch(0.1595 0.0045 84.59); | ||
| --dt-color-black-950: oklch(0.2134 0.006 91.63); | ||
| --dt-color-black-900: oklch(0.2572 0.0063 78.21); | ||
| --dt-color-black-800: oklch(0.3352 0.0055 56.21); | ||
| --dt-color-black-700: oklch(0.4468 0.0055 78.27); | ||
| --dt-color-black-600: oklch(0.5134 0.0063 95.18); | ||
| --dt-color-black-500: oklch(0.6001 0.0032 84.56); | ||
| --dt-color-black-400: oklch(0.7321 0.0061 84.57); | ||
| --dt-color-black-300: oklch(0.858 0.0059 84.57); | ||
| --dt-color-black-200: oklch(0.9312 0.0029 84.56); | ||
| --dt-color-black-100: oklch(0.9774 0.0025 48.72); | ||
| --dt-color-black-50: oklch(1 0 0); | ||
@@ -351,3 +351,3 @@ --dt-color-neutral-transparent: transparent; /* Transparent color independent of any theme. */ | ||
| --dt-shadow-focus-inset-offset-x: var(--dt-size-0); | ||
| --dt-shadow-focus-inset-color: oklch(0.706 0.1304 241.91); | ||
| --dt-shadow-focus-inset-color: oklch(0.6089 0.2128 259.28); | ||
| --dt-shadow-focus-inset-spread: var(--dt-size-200); | ||
@@ -357,3 +357,3 @@ --dt-shadow-focus-inset-blur: var(--dt-size-0); | ||
| --dt-shadow-focus-2-offset-x: var(--dt-size-0); | ||
| --dt-shadow-focus-2-color: oklch(0.706 0.1304 241.91); | ||
| --dt-shadow-focus-2-color: oklch(0.6089 0.2128 259.28); | ||
| --dt-shadow-focus-2-spread: calc(var(--dt-size-200) + var(--dt-size-100)); | ||
@@ -363,3 +363,3 @@ --dt-shadow-focus-2-blur: var(--dt-size-0); | ||
| --dt-shadow-focus-1-offset-x: var(--dt-size-0); | ||
| --dt-shadow-focus-1-color: oklch(0.9821 0 0); | ||
| --dt-shadow-focus-1-color: oklch(0.9774 0.0025 48.72); | ||
| --dt-shadow-focus-1-spread: var(--dt-size-100); | ||
@@ -366,0 +366,0 @@ --dt-shadow-focus-1-blur: var(--dt-size-0); |
@@ -17,5 +17,5 @@ @layer dialtone.base {/** | ||
| --dt-shell-color-border-subtle: oklch(1 0 0 / 0.15); | ||
| --dt-shell-color-foreground-muted: oklch(0.92 0 0 / 0.6); | ||
| --dt-shell-color-foreground-tertiary: oklch(0.92 0 0 / 0.72); | ||
| --dt-shell-color-foreground-secondary: oklch(0.92 0 0 / 0.86); | ||
| --dt-shell-color-foreground-muted: oklch(0.93 0 84.6 / 0.6); | ||
| --dt-shell-color-foreground-tertiary: oklch(0.93 0 84.6 / 0.72); | ||
| --dt-shell-color-foreground-secondary: oklch(0.93 0 84.6 / 0.86); | ||
| --dt-shell-color-foreground-primary: var(--dt-shell-base-color-foreground); | ||
@@ -22,0 +22,0 @@ --dt-action-color-border-positive-default: var(--dt-color-border-subtle); |
@@ -5,17 +5,17 @@ @layer dialtone.base {/** | ||
| color-scheme: light; | ||
| --dt-color-border-bold: oklch(0 0 0 / 0.5); | ||
| --dt-color-border-moderate: oklch(0 0 0 / 0.85); | ||
| --dt-color-border-default: oklch(0 0 0 / 0.66); | ||
| --dt-color-border-subtle: oklch(0 0 0 / 0.5); | ||
| --dt-color-border-bold: oklch(0.16 0 84.6 / 0.5); | ||
| --dt-color-border-moderate: oklch(0.16 0 84.6 / 0.85); | ||
| --dt-color-border-default: oklch(0.16 0 84.6 / 0.66); | ||
| --dt-color-border-subtle: oklch(0.16 0 84.6 / 0.5); | ||
| --dt-color-foreground-disabled: var(--dt-color-black-700); /* Used for text paired with disabled content or components, like the form elements. */ | ||
| --dt-color-foreground-placeholder: var(--dt-color-black-700); /* Text color for placeholder text within form elements. */ | ||
| --dt-color-foreground-muted: oklch(0 0 0 / 0.5); | ||
| --dt-color-foreground-muted: oklch(0.16 0 84.6 / 0.5); | ||
| --dt-color-foreground-tertiary: var(--dt-color-black-800); /* Used to imply visual hierarchy relative to primary and secondary text colors, e.g. headlines and labels. */ | ||
| --dt-color-foreground-secondary: var(--dt-color-black-900); /* Example uses include introduction paragraphs, labels, and descriptions paired with form elements. */ | ||
| --dt-color-foreground-primary: var(--dt-color-black-1000); /* Default text color throughout the UI. */ | ||
| --dt-shell-color-border-default: oklch(0 0 0 / 0.17); | ||
| --dt-shell-color-border-subtle: oklch(0 0 0 / 0.1); | ||
| --dt-shell-color-foreground-muted: oklch(0.23 0 0 / 0.6); | ||
| --dt-shell-color-foreground-tertiary: oklch(0.23 0 0 / 0.72); | ||
| --dt-shell-color-foreground-secondary: oklch(0.23 0 0 / 0.86); | ||
| --dt-shell-color-border-default: oklch(0.16 0 84.6 / 0.17); | ||
| --dt-shell-color-border-subtle: oklch(0.16 0 84.6 / 0.1); | ||
| --dt-shell-color-foreground-muted: oklch(0.26 0.01 78.2 / 0.6); | ||
| --dt-shell-color-foreground-tertiary: oklch(0.26 0.01 78.2 / 0.72); | ||
| --dt-shell-color-foreground-secondary: oklch(0.26 0.01 78.2 / 0.86); | ||
| --dt-shell-color-foreground-primary: var(--dt-shell-base-color-foreground); | ||
@@ -22,0 +22,0 @@ --dt-action-color-border-positive-default: var(--dt-color-border-subtle); |
+4
-2
| { | ||
| "name": "@dialpad/dialtone-css", | ||
| "version": "8.80.0-next.4", | ||
| "version": "8.80.0-next.5", | ||
| "description": "Dialpad's design system", | ||
@@ -55,3 +55,5 @@ "keywords": [ | ||
| "dialtone-migrate-flex-to-stack": "./lib/dist/js/dialtone_migrate_flex_to_stack/index.mjs", | ||
| "dialtone-migrate-link-rendering": "./lib/dist/js/dialtone_migrate_link_rendering/index.mjs" | ||
| "dialtone-migrate-link-rendering": "./lib/dist/js/dialtone_migrate_link_rendering/index.mjs", | ||
| "dialtone-migrate-chip-interactive": "./lib/dist/js/dialtone_migrate_chip_interactive/index.mjs", | ||
| "dialtone-migrate-scrollbar-always": "./lib/dist/js/dialtone_migrate_scrollbar_always/index.mjs" | ||
| }, | ||
@@ -58,0 +60,0 @@ "type": "module", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
30340270
1.9%365
1.67%186306
1.21%29
16%