feat(colors): DLT-3360 retune blue gold purple red black magenta palettes - #1242
feat(colors): DLT-3360 retune blue gold purple red black magenta palettes#1242Joshua Hynes (hynes-dialpad) wants to merge 25 commits into
Conversation
…lters, reviewer routing, and convention references (#1223)
## [8.79.2](dialtone-css/v8.79.1...dialtone-css/v8.79.2) (2026-05-01) ### Bug Fixes * **Rich Text Editor:** NO-JIRA fix multiple rich text issues ([#1240](#1240)) ([f285a3e](f285a3e))
## [1.2.5](dialtone-emojis/v1.2.4...dialtone-emojis/v1.2.5) (2026-05-01)
## [4.51.1](dialtone-icons/v4.51.0...dialtone-icons/v4.51.1) (2026-05-01) ### Bug Fixes * **Rich Text Editor:** NO-JIRA fix multiple rich text issues ([#1240](#1240)) ([f285a3e](f285a3e))
# [9.182.0](dialtone/v9.181.0...dialtone/v9.182.0) (2026-05-01) ### Bug Fixes * **Popover, Collapsible:** DP-185811 cancel transitions on unmount ([#1241](#1241)) ([6883a0e](6883a0e)) * **Rich Text Editor:** NO-JIRA fix multiple rich text issues ([#1240](#1240)) ([f285a3e](f285a3e)) ### Features * DLT-3352 refresh GEO standard, publish llms.txt, add freshness check ([#1235](#1235)) ([e43643d](e43643d))
…tokens Add link.mention-background, link.mention-background-hover, link.mention-inverted-background, and link.mention-inverted-background-hover tokens using Tokens Studio alpha modifiers on brand-opaque surface values. Update mention and inverted-mention variants in link.less to reference semantic tokens instead of inline oklch() expressions. Swap default/hover text-decoration so underline appears on hover (consistent with base link). Remove :active override from mention variant.
notice.less: replace surface-strong with surface-primary-inverted for important/banner/toast variant background. dialtone-syntax.less: replace surface-info with surface-info-subtle for inline code background.
Extract inline v-for array literals to named consts (buttonVariants, badgeKinds, badgeTypes, noticeKinds, progressKinds) matching the file's existing convention. Replace two inline capitalize expressions with the already-defined capitalize(). Remove .foo placeholder class and empty style block.
link.less: rename --link-color -> --link-color-default and --link-color -> --link-color-default-hover in &--mention so the mention token actually applies (base .d-link reads --link-color-default, not --link-color). Remove redundant :hover color redeclaration since the base hover rule already swaps to --link-color-default-hover. Remove stale 'reversed underline' comment and dead commented-out property. dark.json: swap mention-background alpha values (.25/.15 -> .15/.25) so hover is more visible than the default state, matching the light-mode pattern (.1 -> .15). scratch-color.md: trim data table comment to the non-obvious WHY.
WalkthroughThis PR integrates a VuePress LLMs plugin for documentation generation, introduces a content freshness-checking system for standards with CI workflow automation, enhances rich-text-editor component functionality and Storybook integration, refactors component documentation examples, rebrand success tokens to positive, and updates CodeRabbit configuration with enhanced path-based reviewer mappings and knowledge-base linkages. Changes
Possibly related PRs
Suggested labels
Suggested reviewers
✨ Finishing Touches🧪 Generate unit tests (beta)
Review rate limit: 8/10 reviews remaining, refill in 7 minutes and 18 seconds. Comment |
Wiz Scan Summary
To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dc41701ed5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "Codex (@codex) review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".
|
|
||
| spaceTokenMatch.forEach((match) => { | ||
| const spaceToken = match.replace('var(', '').replace(')', ''); | ||
| const sizeToken = spaceToken.replace('--dt-space-', '--dt-size-'); |
There was a problem hiding this comment.
Suggest spacing tokens instead of deprecated size tokens
This rule currently rewrites --dt-space-* to --dt-size-*, but the same plugin set now treats --dt-size-* as deprecated (see no-deprecated-size-tokens in the plugin index), so users who follow this warning are pushed into another deprecation warning instead of a stable target. In practice this creates contradictory lint guidance and non-converging migrations; the replacement here should point to --dt-spacing-* (or context-aware spacing/layout guidance) rather than --dt-size-*.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 19
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
packages/dialtone-vue/.storybook/preview.js (1)
251-257:⚠️ Potential issue | 🟠 MajorMove dark mode listener into useEffect to prevent accumulation.
Line 255 adds a
channel.onlistener on every render without cleanup, causing listeners to accumulate and fire duplicately. This logic already exists in theuseEffect(lines 259–264); consolidate both subscriptions into the effect.Suggested fix
docs: { page: DialtoneDocsPage, container: ({ children, ...props }) => { const [isDark, setDark] = useState(false); const channel = addons.getChannel(); - - channel.on(DARK_MODE_EVENT_NAME, (isDark) => { - setMode(isDark ? 'dark' : 'light', document.documentElement); - }); useEffect(() => { - channel.on(DARK_MODE_EVENT_NAME, setDark); + const handleDarkMode = (nextIsDark) => { + setDark(nextIsDark); + setMode(nextIsDark ? 'dark' : 'light', document.documentElement); + }; + channel.on(DARK_MODE_EVENT_NAME, handleDarkMode); return () => { - channel.off(DARK_MODE_EVENT_NAME, setDark); + channel.off(DARK_MODE_EVENT_NAME, handleDarkMode); }; - }, [channel, setDark]); + }, [channel]; return React.createElement( DocsContainer, { theme: isDark ? dialtoneDarkTheme : dialtoneLightTheme, context: props.context }, children,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/dialtone-vue/.storybook/preview.js` around lines 251 - 257, The container render currently calls channel.on(DARK_MODE_EVENT_NAME, ...) on every render which accumulates listeners; move that subscription into the existing useEffect in the container component, register a named handler that calls setMode(...) and setDark(...), and return a cleanup that removes the handler (e.g., channel.removeListener or channel.off with the same handler) to avoid duplicate firings; remove the direct channel.on call from the render body so the only subscription is inside useEffect.apps/dialtone-documentation/docs/guides/mcp-server/index.md (1)
124-132:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse
positivehere instead of deprecatedsuccess.The token-search guidance still tells users to query
success, which is stale relative to this PR’ssuccess→positivemigration and will bias MCP results toward deprecated aliases.Based on learnings, "the broad rename from
error/success/dangertocritical/positiveacross component prop values, CSS class names, and constants is an intentional breaking change with no legacy fallback aliases desired."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/dialtone-documentation/docs/guides/mcp-server/index.md` around lines 124 - 132, Update the token-search guidance to use the new "positive" terminology instead of the deprecated "success": change any occurrences of "success" in the search_tokens tool description and example queries (e.g., the example `"color foreground primary" → --dt-color-foreground-primary` and the `"space 400" → --dt-space-400, --dt-space-400-negative"` section that currently mentions `success`) so examples and copy reference `positive` (and remove references to legacy aliases); ensure the text reflects the breaking rename from `success`→`positive` so MCP results won't favor deprecated tokens..coderabbit.yaml (1)
135-149: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winRelax the token-review rules to match current repo conventions.
This block still tells reviewers to flag missing dark overrides and direct base-palette references unconditionally. That will create recurring false positives for intentional token inheritance and valid base-palette mappings.
Suggested change
- path: 'packages/dialtone-tokens/**' instructions: > - Token naming: camelCase with category prefix (dtColor*, dtSpace*, dtFontSize*, dtFontWeight*, dtShadow*, dtRadius*, dtSize*). - - New tokens must have dark mode overrides in dark.json. + - New tokens may inherit from default.json when the same value is + correct in dark mode. Add a dark.json override only when the dark + theme value must differ. - - Component tokens must reference semantic tokens, not base palette. + - Prefer semantic tokens when a suitable mapping exists, but direct + base-palette references are valid when they are the correct source. - Flag any circular references or references to non-existent tokens. - New design tokens must be defined across all 8 themes (Dialpad Light/Dark, T-Mobile Light/Dark, Expressive Light/Dark, Expressive Small Light/Dark).Based on learnings: not every new token requires a
dark.jsonoverride when inheritance is intentional, and direct base-palette references in token JSON are acceptable when no suitable semantic token exists.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.coderabbit.yaml around lines 135 - 149, Update the token-review instruction block that currently enforces "New tokens must have dark mode overrides in dark.json" and "Component tokens must reference semantic tokens, not base palette" so it allows intentional inheritance and acceptable base-palette mappings: replace the unconditional checks with guidance that dark.json overrides are required only when a token is not intentionally inheriting (explicitly require a comment/metadata when inheritance is intended) and that direct base-palette references are permitted when no appropriate semantic token exists (flag only references to non-existent tokens or unexpected palette usage). Also update the referenced guidance paragraph (the design-tokens rule) to document these exceptions and add a short heuristic to avoid false positives.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.coderabbit.yaml:
- Around line 59-70: Add an exclusion for the demo-only scratchpad by updating
the path_filters in .coderabbit.yaml: modify the path_filters array (symbol:
path_filters) to include a negative pattern for the specific file
"apps/dialtone-documentation/docs/scratch-color.md" (e.g., add
"!apps/dialtone-documentation/docs/scratch-color.md") so the reviewer bot skips
that file during inline review.
In @.github/workflows/dialtone-documentation-tests.yml:
- Around line 11-19: The workflow's path filters only watch
apps/dialtone-documentation/** and pnpm-lock.yaml, so changes in dependent
workspace packages won't trigger the job; update the paths list used under both
pull_request and push to also include the package inputs such as
'packages/dialtone-css/**', 'packages/dialtone-icons/**',
'packages/dialtone-tokens/**', and 'packages/dialtone-vue/**' (and optionally
root files like 'package.json' or 'packages/**' if you prefer a broader
catch-all) so changes to those packages will run the documentation tests.
In `@apps/dialtone-documentation/docs/components/avatar.md`:
- Around line 524-526: The sentence "When it comes to voiceover, avatars
accompanying a label should generally be considered decorative, is not
focusable, nor is it read out" is grammatically broken and ambiguous; replace it
with a clear, explicit guidance such as: "When displayed alongside a text label,
avatars should be treated as decorative: they must not receive keyboard focus
and should be hidden from assistive technologies (for example, use
aria-hidden='true'). For example, a user's avatar next to their name should not
be read aloud." This fixes grammar, clarifies behavior, and gives an
implementation hint.
- Around line 244-269: The HTML example for the avatar group is out of sync with
the Vue examples (dt-avatar :group="100", :group="11", :group="3"); update the
three static HTML blocks so their badge numbers and digit modifier classes match
those Vue values—i.e., ensure the first block shows count 100 and uses the
appropriate d-avatar--group-digits-3 modifier, the second shows 11 with
d-avatar--group-digits-2, and the third shows 3 (or 3 -> single-digit class if
applicable) so d-avatar__count and d-avatar__count-number reflect the same
values as the dt-avatar examples.
In `@apps/dialtone-documentation/docs/components/skeleton.md`:
- Around line 11-15: The DtSkeleton demo instances in the docs (the <dt-skeleton
:animate="false" /> examples) are missing accessible names and thus create noisy
role="status" output for screen-readers; update each decorative/demo DtSkeleton
instance (all occurrences shown in the file) to either include an appropriate
aria-label (e.g., aria-label="loading placeholder") if it conveys meaning or
mark purely decorative ones aria-hidden="true" to remove them from assistive
tech, ensuring the change is applied to every DtSkeleton used in the examples
(including the instances within code-well-header and other demo blocks).
In `@apps/dialtone-documentation/docs/components/tabs.md`:
- Line 54: The docs callout references internal classes `d-tablist--no-border`
and `d-tablist--inverted` but should document the public props used in the Vue
examples; update the prose to mention the `borderless` and `inverted` props (and
their effect) instead of the internal class names so readers see the component
API (`borderless`, `inverted`) that they should use.
In `@apps/dialtone-documentation/docs/utilities/typography/line-clamp.md`:
- Around line 67-70: Replace the placeholder "..." inside the example div with a
short, real text sample so the snippet is copy-paste runnable; locate the
example using the div element with class "d-lc-custom" and the inline style
"--lc-lines: 11" and substitute the placeholder content with a brief sentence or
two of real text (e.g., lorem or a meaningful example sentence) that
demonstrates line-clamping behavior.
In `@CHANGELOG.md`:
- Line 11: The release changelog has a heading-level jump: the release heading
"# 9.182.0" is followed by "### Bug Fixes" which triggers MD001; update the
subsection heading to use "## Bug Fixes" (or alternatively change the release
heading to "## 9.182.0") so heading levels increment correctly and the hierarchy
is valid; locate the string "### Bug Fixes" in CHANGELOG.md and adjust the
hashes accordingly, and apply the same fix to the other occurrence referenced
(line 17).
In `@packages/dialtone-css/CHANGELOG.md`:
- Around line 1-7: The changelog entry under "## [8.79.2]" currently references
the Rich Text Editor fix (`#1240`) and commit f285a3e, which is unrelated to this
DLT-3360 color/token PR (`#1242`); update the block so 8.79.2 documents the
DLT-3360 color/token changes and references the correct issue/PR number (`#1242`)
and commit(s) from this branch (replace or regenerate the list item that
mentions "Rich Text Editor" and f285a3e with the appropriate summary and commit
hash(es) for the color/token work).
In `@packages/dialtone-docs/src/content/standards/standard-geo-optimization.md`:
- Line 20: The paragraph starting with "**Platforms differ.**" hard-codes
volatile benchmark percentages and a year; remove the numeric figures (~11%,
~48%, 90%+) and the "(2026)" year from that paragraph and replace them with a
concise qualitative statement (e.g., "they cite different sources and use
different signals; ChatGPT favors established brand/Wikipedia while Perplexity
favors community and easily-extractable pages") and add a short pointer to "See
the linked Averi report for current per-platform data" so the detailed numbers
remain only in the referenced report.
In `@packages/dialtone-docs/tests/tests/schema.test.js`:
- Around line 182-198: Update the standards discovery to match recursive paths
and validate real calendar dates: change the findFiles invocation that sets
standardFiles (used in the test named 'all standards have last_verified in
YYYY-MM-DD format') to use the recursive glob for standards (e.g.,
'src/content/standards/**\/*.md' or the project-equivalent pattern) so it
discovers all nested files, and replace the current regex-only validation
(datePattern) with logic that, after a regex match or if value is a string,
parses the string via Date (using parseFrontmatter/readFile to get
data.last_verified) and verifies the resulting Date is valid (not NaN) and that
the year/month/day components round-trip to the original YYYY-MM-DD string to
ensure real calendar dates.
In `@packages/dialtone-emojis/CHANGELOG.json`:
- Line 1: The versions array contains duplicate entries for "1.2.5" (and
"1.0.0"); remove the redundant objects so each semantic version appears exactly
once in the versions array (keep the intended/latest entry for each duplicate),
ensuring the "version" string is unique and the array order remains
chronological; update the parsed/title fields if needed so the remaining entry
fully represents the release.
In `@packages/dialtone-icons/gulpfile.cjs`:
- Around line 66-81: The three clean tasks (cleanDist, cleanIcons,
cleanIllustrations) currently call execSync('rm -rf ...') which is Unix-only;
replace those execSync calls with fs.rmSync(path, { recursive: true, force: true
}) (or fs.rmSync(path, { maxRetries: 0, recursive: true, force: true }) if
desired) using the same path checks (fs.existsSync('./dist'), './src/icons',
'./src/illustrations') and wrap in try/catch to surface errors via the task
runner; update each function (cleanDist, cleanIcons, cleanIllustrations) to use
fs.rmSync and remove the execSync usage so cleaning is cross-platform and safe.
In `@packages/dialtone-icons/package.json`:
- Around line 9-28: The package.json exports removed the legacy "./vue" entry
causing many broken imports; restore backward compatibility by adding "./vue"
and "./vue/*" export entries that alias to the existing "./vue3" targets (mirror
the same "types", "import", and "require" arrays/paths used under "./vue3" and
"./vue3/*"), update README.md to mention both "./vue" and "./vue3" or note the
alias, and include a BREAKING CHANGE footer in the commit message explaining the
revert and recommended migration (or, if you prefer to enforce the rename,
update all internal imports in dialpad/ios and dialpad/firespotter and document
the migration steps instead). Ensure you reference the exports keys in
package.json when making the change.
In `@packages/dialtone-tokens/tokens/theme/dp/default.json`:
- Around line 991-1004: The deprecated aliases "success-opaque-inverted" and
"success-subtle-opaque-inverted" currently add an extra
$extensions.studio.tokens.modify alpha block which makes them diverge from their
targets; remove the $extensions...modify alpha entries from both
"success-opaque-inverted" and "success-subtle-opaque-inverted" so their "value"
remains a pure alias to "positive-opaque-inverted" and
"positive-subtle-opaque-inverted" respectively, leaving only the "value",
"type", "description", and "$deprecated" fields.
- Around line 175-184: The new semantic tokens (e.g., warning-strong,
warning-strong-inverted, all mention* variants, all positive* variants,
inputs.color.border.positive and the full set of color.link.positive* /
color.link.mention* / color.surface.positive* / color.border.positive* keys)
were only added to the dp theme; add equivalent entries to each of the other 8
theme default.json files (themes 101–137, aegean, botany, etc.) with the same
structure and palette references used in dp (use the same "{color.*}"
references), and add dark.json overrides only where the palette requires
different dark-mode values rather than inheriting the default. Ensure you use
the exact token names listed in the comment (e.g.,
"color.foreground.warning-strong", "color.foreground.warning-strong-inverted",
"color.link.positive", "color.link.positive-hover", "color.link.mention",
"color.surface.positive-strong", "color.border.positive-inverted",
"inputs.color.border.positive", etc.) so exports for CSS/iOS/Android include
them.
In `@packages/dialtone-vue/.storybook/DialtoneDocsPage.js`:
- Around line 13-16: preparedMeta.title may be undefined or non-string so
calling split on it can throw; update the logic around preparedMeta,
preparedMeta.title, segments, componentName and slug to guard and provide a safe
fallback (e.g., check typeof preparedMeta?.title === 'string' and use that, or
coerce with String(preparedMeta?.title || '') before calling split) so segments/
componentName/ slug are derived from a stable default value when title is
missing or not a string.
In `@packages/dialtone-vue/CHANGELOG.md`:
- Around line 1-8: The Dialtone Vue changelog currently contains an unrelated
release note block (the version header and two bullet entries about
Popover/Collapsible and Rich Text Editor) that must be removed or replaced; edit
packages/dialtone-vue/CHANGELOG.md to delete or replace the entire 3.219.2
section (the header and its Bug Fixes bullets) and either add the correct token
palette/semantic color release notes for this PR or leave the section out,
ensuring any moved notes are placed in the correct package changelog and the
commit/PR description reflects the changelog change.
In `@packages/dialtone-vue/components/popover/popover.test.js`:
- Around line 341-389: Tests currently combine uncontrolled and controlled
assertions in the single tests for onLeaveTransitionComplete and
onEnterTransitionComplete while also toggling wrapper.vm._isUnmounting; split
each of the two multi-assertion tests ("emits \"opened\" and respects open prop
when leave transition completes and not unmounting" and "emits \"opened\" and
respects open prop when enter transition completes and not unmounting") into two
separate tests each: one for the uncontrolled scenario (open === null) that only
sets _isUnmounting = false, calls
onLeaveTransitionComplete/onEnterTransitionComplete, and asserts
wrapper.emitted('opened') and that update:open is undefined, and another for the
controlled scenario that sets props (await wrapper.setProps({ open: false }))
then calls the same method and asserts update:open is emitted with the expected
value; keep the _isUnmounting manipulation and use the existing symbols
(wrapper.vm._isUnmounting, wrapper.vm.onLeaveTransitionComplete,
wrapper.vm.onEnterTransitionComplete, wrapper.setProps, wrapper.emitted) to
locate and split the logic.
---
Outside diff comments:
In @.coderabbit.yaml:
- Around line 135-149: Update the token-review instruction block that currently
enforces "New tokens must have dark mode overrides in dark.json" and "Component
tokens must reference semantic tokens, not base palette" so it allows
intentional inheritance and acceptable base-palette mappings: replace the
unconditional checks with guidance that dark.json overrides are required only
when a token is not intentionally inheriting (explicitly require a
comment/metadata when inheritance is intended) and that direct base-palette
references are permitted when no appropriate semantic token exists (flag only
references to non-existent tokens or unexpected palette usage). Also update the
referenced guidance paragraph (the design-tokens rule) to document these
exceptions and add a short heuristic to avoid false positives.
In `@apps/dialtone-documentation/docs/guides/mcp-server/index.md`:
- Around line 124-132: Update the token-search guidance to use the new
"positive" terminology instead of the deprecated "success": change any
occurrences of "success" in the search_tokens tool description and example
queries (e.g., the example `"color foreground primary" →
--dt-color-foreground-primary` and the `"space 400" → --dt-space-400,
--dt-space-400-negative"` section that currently mentions `success`) so examples
and copy reference `positive` (and remove references to legacy aliases); ensure
the text reflects the breaking rename from `success`→`positive` so MCP results
won't favor deprecated tokens.
In `@packages/dialtone-vue/.storybook/preview.js`:
- Around line 251-257: The container render currently calls
channel.on(DARK_MODE_EVENT_NAME, ...) on every render which accumulates
listeners; move that subscription into the existing useEffect in the container
component, register a named handler that calls setMode(...) and setDark(...),
and return a cleanup that removes the handler (e.g., channel.removeListener or
channel.off with the same handler) to avoid duplicate firings; remove the direct
channel.on call from the render body so the only subscription is inside
useEffect.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 753fada9-9de1-4550-848f-3f201b4959b3
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamland included by**
📒 Files selected for processing (63)
.coderabbit.yaml.github/CODEOWNERS.github/workflows/dialtone-documentation-tests.yml.github/workflows/standards-freshness.ymlCHANGELOG.jsonCHANGELOG.mdCLAUDE.mdapps/dialtone-documentation/docs/.vuepress/config.jsapps/dialtone-documentation/docs/.vuepress/exampleComponents/ExampleTabs.vueapps/dialtone-documentation/docs/.vuepress/theme/assets/less/dialtone-syntax.lessapps/dialtone-documentation/docs/components/avatar.mdapps/dialtone-documentation/docs/components/emoji.mdapps/dialtone-documentation/docs/components/rich-text-editor.mdapps/dialtone-documentation/docs/components/skeleton.mdapps/dialtone-documentation/docs/components/tabs.mdapps/dialtone-documentation/docs/guides/mcp-server/index.mdapps/dialtone-documentation/docs/scratch-color.mdapps/dialtone-documentation/docs/utilities/typography/line-clamp.mdapps/dialtone-documentation/package.jsonpackage.jsonpackages/dialtone-css/CHANGELOG.jsonpackages/dialtone-css/CHANGELOG.mdpackages/dialtone-css/lib/build/less/components/link.lesspackages/dialtone-css/lib/build/less/components/notice.lesspackages/dialtone-css/lib/build/less/components/rich-text-editor.lesspackages/dialtone-css/package.jsonpackages/dialtone-docs/package.jsonpackages/dialtone-docs/project.jsonpackages/dialtone-docs/src/content/standards/INDEX.mdpackages/dialtone-docs/src/content/standards/standard-ai-documentation.mdpackages/dialtone-docs/src/content/standards/standard-geo-optimization.mdpackages/dialtone-docs/src/generators/check-freshness.mjspackages/dialtone-docs/tests/tests/check-freshness.test.jspackages/dialtone-docs/tests/tests/schema.test.jspackages/dialtone-emojis/CHANGELOG.jsonpackages/dialtone-emojis/CHANGELOG.mdpackages/dialtone-emojis/package.jsonpackages/dialtone-icons/CHANGELOG.jsonpackages/dialtone-icons/CHANGELOG.mdpackages/dialtone-icons/android/gradle.propertiespackages/dialtone-icons/gulpfile.cjspackages/dialtone-icons/package.jsonpackages/dialtone-tokens/package.jsonpackages/dialtone-tokens/tokens/base/dark.jsonpackages/dialtone-tokens/tokens/base/default.jsonpackages/dialtone-tokens/tokens/components/badge/default.jsonpackages/dialtone-tokens/tokens/theme/dp/dark.jsonpackages/dialtone-tokens/tokens/theme/dp/default.jsonpackages/dialtone-tokens/tokens/theme/prota-deuter/default.jsonpackages/dialtone-vue/.storybook/DialtoneDocsPage.jspackages/dialtone-vue/.storybook/DialtoneDocsPage.jsxpackages/dialtone-vue/.storybook/preview.jspackages/dialtone-vue/CHANGELOG.jsonpackages/dialtone-vue/CHANGELOG.mdpackages/dialtone-vue/components/collapsible/collapsible.test.jspackages/dialtone-vue/components/collapsible/collapsible.vuepackages/dialtone-vue/components/popover/popover.test.jspackages/dialtone-vue/components/popover/popover.vuepackages/dialtone-vue/components/rich_text_editor/rich_text_editor.vuepackages/dialtone-vue/package.jsonpackages/eslint-plugin-dialtone/package.jsonpackages/postcss-responsive-variations/package.jsonpackages/stylelint-plugin-dialtone/package.json
💤 Files with no reviewable changes (1)
- packages/dialtone-vue/.storybook/DialtoneDocsPage.jsx
| <code-example-tabs | ||
| htmlCode=' | ||
| <div class="d-avatar d-avatar--group d-avatar--group-digits-3"> | ||
| <div class="d-avatar__canvas"> | ||
| <img class="d-avatar__image" src="/assets/images/person.png" alt="Person Avatar"/> | ||
| </div> | ||
| <span class="d-avatar__count"><span class="d-avatar__count-number">12</span></span> | ||
| </div> | ||
| <div class="d-avatar d-avatar--group d-avatar--group-digits-2"> | ||
| <div class="d-avatar__canvas"> | ||
| <img class="d-avatar__image" src="/assets/images/person.png" alt="Person Avatar"/> | ||
| </div> | ||
| <span class="d-avatar__count"><span class="d-avatar__count-number">12</span></span> | ||
| </div> | ||
| <div class="d-avatar d-avatar--group"> | ||
| <div class="d-avatar__canvas"> | ||
| <img class="d-avatar__image" src="/assets/images/person.png" alt="Person Avatar"/> | ||
| </div> | ||
| <span class="d-avatar__count"><span class="d-avatar__count-number">1</span></span> | ||
| </div> | ||
| ' | ||
| vueCode=' | ||
| <dt-avatar :group="100" image-src="/assets/images/person.png" image-alt="Person Avatar" /> | ||
| <dt-avatar :group="11" image-src="/assets/images/person.png" image-alt="Person Avatar" /> | ||
| <dt-avatar :group="3" image-src="/assets/images/person.png" image-alt="Person Avatar" /> | ||
| ' |
There was a problem hiding this comment.
Sync the hand-written HTML sample with the Vue demo values.
The raw HTML block does not match the adjacent Vue example (:group="100", 11, 3), so the badge counts and digit classes shown to readers are inconsistent.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/dialtone-documentation/docs/components/avatar.md` around lines 244 -
269, The HTML example for the avatar group is out of sync with the Vue examples
(dt-avatar :group="100", :group="11", :group="3"); update the three static HTML
blocks so their badge numbers and digit modifier classes match those Vue
values—i.e., ensure the first block shows count 100 and uses the appropriate
d-avatar--group-digits-3 modifier, the second shows 11 with
d-avatar--group-digits-2, and the third shows 3 (or 3 -> single-digit class if
applicable) so d-avatar__count and d-avatar__count-number reflect the same
values as the dt-avatar examples.
| When it comes to voiceover, avatars accompanying a label should generally be considered decorative, | ||
| is not focusable, nor is it read out. An example is a user's avatar next to their name. | ||
|
|
There was a problem hiding this comment.
Tighten the accessibility copy here.
This sentence is grammatically broken (avatars ... is not focusable) and reads ambiguously. Reword it so the decorative-avatar guidance is explicit.
Suggested change
-When it comes to voiceover, avatars accompanying a label should generally be considered decorative,
-is not focusable, nor is it read out. An example is a user's avatar next to their name.
+When it comes to VoiceOver, avatars accompanying a label should generally be considered decorative,
+are not focusable, and should not be read out. An example is a user's avatar next to their name.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| When it comes to voiceover, avatars accompanying a label should generally be considered decorative, | |
| is not focusable, nor is it read out. An example is a user's avatar next to their name. | |
| When it comes to VoiceOver, avatars accompanying a label should generally be considered decorative, | |
| are not focusable, and should not be read out. An example is a user's avatar next to their name. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/dialtone-documentation/docs/components/avatar.md` around lines 524 -
526, The sentence "When it comes to voiceover, avatars accompanying a label
should generally be considered decorative, is not focusable, nor is it read out"
is grammatically broken and ambiguous; replace it with a clear, explicit
guidance such as: "When displayed alongside a text label, avatars should be
treated as decorative: they must not receive keyboard focus and should be hidden
from assistive technologies (for example, use aria-hidden='true'). For example,
a user's avatar next to their name should not be read aloud." This fixes
grammar, clarifies behavior, and gives an implementation hint.
| <code-well-header> | ||
| <div class="d-w50p"> | ||
| <dt-skeleton :animate="false" /> | ||
| </div> | ||
| </code-well-header> |
There was a problem hiding this comment.
Hide decorative skeleton demos from assistive tech or label them.
These examples render multiple DtSkeleton instances without an accessible name. On the docs page that creates ambiguous/noisy role="status" content for screen-reader users. Add aria-label consistently, or mark purely visual demo instances aria-hidden="true".
Also applies to: 151-160, 173-182, 195-204, 219-223, 239-245, 262-274, 292-306
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/dialtone-documentation/docs/components/skeleton.md` around lines 11 -
15, The DtSkeleton demo instances in the docs (the <dt-skeleton :animate="false"
/> examples) are missing accessible names and thus create noisy role="status"
output for screen-readers; update each decorative/demo DtSkeleton instance (all
occurrences shown in the file) to either include an appropriate aria-label
(e.g., aria-label="loading placeholder") if it conveys meaning or mark purely
decorative ones aria-hidden="true" to remove them from assistive tech, ensuring
the change is applied to every DtSkeleton used in the examples (including the
instances within code-well-header and other demo blocks).
| "warning-strong": { | ||
| "value": "{color.gold.950}", | ||
| "type": "color", | ||
| "description": "Indicates a strong warning that requires user\u2019s attention and further action may be necessary." | ||
| }, | ||
| "warning-strong-inverted": { | ||
| "value": "{color.gold.500}", | ||
| "type": "color", | ||
| "description": "Warning inverted strong text that sits on high-contrast surfaces or backgrounds." | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
python <<'PY'
import json
import pathlib
import sys
root = pathlib.Path("packages/dialtone-tokens/tokens/theme")
expected = [
"color.foreground.warning-strong",
"color.foreground.warning-strong-inverted",
"color.link.positive",
"color.link.positive-hover",
"color.link.positive-inverted",
"color.link.positive-inverted-hover",
"color.link.mention",
"color.link.mention-hover",
"color.link.mention-background",
"color.link.mention-background-hover",
"color.link.mention-inverted-background",
"color.link.mention-inverted-background-hover",
"color.surface.positive",
"color.surface.positive-subtle",
"color.surface.positive-strong",
"color.surface.positive-opaque",
"color.surface.positive-subtle-opaque",
"color.surface.positive-inverted",
"color.surface.positive-subtle-inverted",
"color.surface.positive-strong-inverted",
"color.surface.positive-opaque-inverted",
"color.surface.positive-subtle-opaque-inverted",
"color.border.positive",
"color.border.positive-subtle",
"color.border.positive-strong",
"color.border.positive-inverted",
"color.border.positive-subtle-inverted",
"color.border.positive-strong-inverted",
"inputs.color.border.positive",
]
def has_path(obj, dotted):
cur = obj
for part in dotted.split("."):
if not isinstance(cur, dict) or part not in cur:
return False
cur = cur[part]
return True
failures = {}
for path in sorted(root.glob("*/default.json")):
data = json.loads(path.read_text())
missing = [key for key in expected if not has_path(data, key)]
if missing:
failures[str(path)] = missing
if failures:
for file, missing in failures.items():
print(f"\n{file}")
for key in missing:
print(f" MISSING {key}")
sys.exit(1)
print("All expected keys exist in every theme default.json.")
PYRepository: dialpad/dialtone
Length of output: 50372
Add new semantic tokens to all 8 theme default.json files, not just dp.
Per coding guidelines, new design tokens must be defined across all 8 themes. The new warning-strong, mention*, positive*, and inputs.color.border.positive keys appear only in packages/dialtone-tokens/tokens/theme/dp/default.json. They are missing from themes 101–137, aegean, botany, and others, which will result in missing CSS/iOS/Android exports.
Required tokens across all themes:
color.foreground.warning-strong,color.foreground.warning-strong-invertedcolor.link.positive*(6 variants: positive, positive-hover, positive-inverted, positive-inverted-hover, plus mention variants)color.link.mention*(6 variants: mention, mention-hover, mention-background, mention-background-hover, mention-inverted-background, mention-inverted-background-hover)color.surface.positive*(12 variants: positive, positive-subtle, positive-strong, positive-opaque, positive-subtle-opaque, positive-inverted, and -inverted variants)color.border.positive*(6 variants: positive, positive-subtle, positive-strong, positive-inverted, positive-subtle-inverted, positive-strong-inverted)inputs.color.border.positive
Dark mode overrides in dark.json can inherit when the default value is already correct; only override when the palette value needs to differ.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/dialtone-tokens/tokens/theme/dp/default.json` around lines 175 -
184, The new semantic tokens (e.g., warning-strong, warning-strong-inverted, all
mention* variants, all positive* variants, inputs.color.border.positive and the
full set of color.link.positive* / color.link.mention* / color.surface.positive*
/ color.border.positive* keys) were only added to the dp theme; add equivalent
entries to each of the other 8 theme default.json files (themes 101–137, aegean,
botany, etc.) with the same structure and palette references used in dp (use the
same "{color.*}" references), and add dark.json overrides only where the palette
requires different dark-mode values rather than inheriting the default. Ensure
you use the exact token names listed in the comment (e.g.,
"color.foreground.warning-strong", "color.foreground.warning-strong-inverted",
"color.link.positive", "color.link.positive-hover", "color.link.mention",
"color.surface.positive-strong", "color.border.positive-inverted",
"inputs.color.border.positive", etc.) so exports for CSS/iOS/Android include
them.
| const { preparedMeta } = useOf('meta', ['meta']); | ||
| const segments = preparedMeta.title.split('/'); | ||
| const componentName = segments[segments.length - 1]; | ||
| const slug = componentName.replace(/\s+/g, '-').toLowerCase(); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Storybook @storybook/addon-docs/blocks, for useOf('meta', ['meta']), is preparedMeta.title always guaranteed to be a string? If not, what is the recommended defensive pattern?
💡 Result:
No, preparedMeta.title is not always guaranteed to be a string. The meta.title field in CSF stories is optional (defaults to auto-generated title from file path if omitted), so preparedMeta.title can be undefined if no title is explicitly set in the meta object. Recommended defensive pattern: Check if title exists before using it, and provide a fallback (e.g., component name or auto-title). Example from official StoryName block (which handles both story.name and meta.title): const resolvedOf = useOf('meta', ['meta']); if (resolvedOf.type === 'meta') { return
{resolvedOf.preparedMeta.title ?? 'Fallback Title'}
; } Use optional chaining preparedMeta.title ?? 'Default' or if (preparedMeta.title) { ... } for safety.Citations:
- 1: https://github.com/storybookjs/storybook/blob/next/docs/api/doc-blocks/doc-block-useof.mdx
- 2: https://storybook.js.org/docs/api/doc-blocks/doc-block-useof
- 3: prepareMeta function similar to prepareStory storybookjs/storybook#20592
- 4: React: Fix manifest stories empty when meta has no explicit title storybookjs/storybook#33878
🏁 Script executed:
#!/bin/bash
# Locate DialtoneDocsPage.js and examine the full function
find . -name "DialtoneDocsPage.js" -type fRepository: dialpad/dialtone
Length of output: 115
🏁 Script executed:
#!/bin/bash
# Read the file content around the flagged lines
cat -n packages/dialtone-vue/.storybook/DialtoneDocsPage.js | head -50Repository: dialpad/dialtone
Length of output: 1374
🏁 Script executed:
#!/bin/bash
# Check if there are any usages or tests of DialtoneDocsPage to understand expected behavior
find . -name "*.js" -o -name "*.ts" -o -name "*.tsx" | xargs grep -l "DialtoneDocsPage\|DialtoneDocumentationLink" 2>/dev/null | head -10Repository: dialpad/dialtone
Length of output: 161
🏁 Script executed:
#!/bin/bash
# Check if there are any storybook configuration files that show how meta is set up
find . -path "*.storybook*" -name "*.js" -o -name "*.ts" | xargs grep -l "title" 2>/dev/null | head -10Repository: dialpad/dialtone
Length of output: 207
🏁 Script executed:
#!/bin/bash
# Check preview.js to see how stories are configured
cat -n packages/dialtone-vue/.storybook/preview.js | head -100Repository: dialpad/dialtone
Length of output: 5225
🏁 Script executed:
#!/bin/bash
# Search for example stories to see if meta.title is always provided
find packages/dialtone-vue -name "*.stories.js" -o -name "*.stories.ts" | head -5 | xargs cat | head -100Repository: dialpad/dialtone
Length of output: 2282
🏁 Script executed:
#!/bin/bash
# Get a complete story file to see how meta.title is typically configured
find packages/dialtone-vue -name "*.stories.js" | head -1 | xargs wc -lRepository: dialpad/dialtone
Length of output: 122
🏁 Script executed:
#!/bin/bash
# Read a complete story file
find packages/dialtone-vue -name "*.stories.js" | head -1 | xargs cat | tail -100Repository: dialpad/dialtone
Length of output: 1960
🏁 Script executed:
#!/bin/bash
# Check if there are any tests for DialtoneDocumentationLink or error handling
find . -path "*.test.*" -o -path "*.spec.*" | xargs grep -l "DialtoneDocumentation\|DialtoneDocsPage" 2>/dev/nullRepository: dialpad/dialtone
Length of output: 44
🏁 Script executed:
#!/bin/bash
# Check if there are stories that might not have a title defined
find packages/dialtone-vue -name "*.stories.js" -o -name "*.stories.ts" | xargs grep -L "title:" 2>/dev/null | head -5Repository: dialpad/dialtone
Length of output: 42
🏁 Script executed:
#!/bin/bash
# Check if there's any Storybook config that might enforce title on all stories
find packages/dialtone-vue/.storybook -type f \( -name "*.js" -o -name "*.ts" \) -exec cat {} \; | grep -A5 -B5 "title" | head -50Repository: dialpad/dialtone
Length of output: 1345
Guard against missing or non-string preparedMeta.title before calling split.
Line 14 can throw if preparedMeta.title is absent or non-string, which breaks docs page rendering. Storybook's useOf('meta', ['meta']) does not guarantee title is a string—it's optional and can be undefined.
Suggested fix
function DialtoneDocumentationLink() {
const { preparedMeta } = useOf('meta', ['meta']);
- const segments = preparedMeta.title.split('/');
+ const title = preparedMeta?.title;
+ if (typeof title !== 'string' || title.length === 0) return null;
+ const segments = title.split('/');
const componentName = segments[segments.length - 1];
const slug = componentName.replace(/\s+/g, '-').toLowerCase();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/dialtone-vue/.storybook/DialtoneDocsPage.js` around lines 13 - 16,
preparedMeta.title may be undefined or non-string so calling split on it can
throw; update the logic around preparedMeta, preparedMeta.title, segments,
componentName and slug to guard and provide a safe fallback (e.g., check typeof
preparedMeta?.title === 'string' and use that, or coerce with
String(preparedMeta?.title || '') before calling split) so segments/
componentName/ slug are derived from a stable default value when title is
missing or not a string.
| describe('When component is unmounting', () => { | ||
| beforeEach(() => { | ||
| wrapper.vm._isUnmounting = true; | ||
| }); | ||
|
|
||
| it('sets transition: none on content element to cancel in-flight transitions', () => { | ||
| const contentEl = wrapper.vm.popoverContentEl; | ||
| wrapper.unmount(); | ||
| expect(contentEl.style.transition).toBe('none'); | ||
| }); | ||
|
|
||
| it('does not emit "opened" when leave transition completes', async () => { | ||
| await wrapper.vm.onLeaveTransitionComplete(); | ||
| expect(wrapper.emitted('opened')).toBeUndefined(); | ||
| }); | ||
|
|
||
| it('emits "opened" and respects open prop when leave transition completes and not unmounting', async () => { | ||
| wrapper.vm._isUnmounting = false; | ||
| await wrapper.vm.onLeaveTransitionComplete(); | ||
| expect(wrapper.emitted('opened')).toBeDefined(); | ||
| expect(wrapper.emitted('opened')[0]).toEqual([false]); | ||
| // uncontrolled (open === null): update:open is not emitted | ||
| expect(wrapper.emitted('update:open')).toBeUndefined(); | ||
| // controlled (open !== null): update:open is emitted | ||
| await wrapper.setProps({ open: false }); | ||
| await wrapper.vm.onLeaveTransitionComplete(); | ||
| expect(wrapper.emitted('update:open')).toBeDefined(); | ||
| expect(wrapper.emitted('update:open')[0]).toEqual([false]); | ||
| }); | ||
|
|
||
| it('does not emit "opened" when enter transition completes', async () => { | ||
| await wrapper.vm.onEnterTransitionComplete(); | ||
| expect(wrapper.emitted('opened')).toBeUndefined(); | ||
| }); | ||
|
|
||
| it('emits "opened" and respects open prop when enter transition completes and not unmounting', async () => { | ||
| wrapper.vm._isUnmounting = false; | ||
| await wrapper.vm.onEnterTransitionComplete(); | ||
| expect(wrapper.emitted('opened')).toBeDefined(); | ||
| expect(wrapper.emitted('opened')[0][0]).toBe(true); | ||
| // uncontrolled (open === null): update:open is not emitted | ||
| expect(wrapper.emitted('update:open')).toBeUndefined(); | ||
| // controlled (open !== null): update:open is emitted | ||
| await wrapper.setProps({ open: false }); | ||
| await wrapper.vm.onEnterTransitionComplete(); | ||
| expect(wrapper.emitted('update:open')).toBeDefined(); | ||
| expect(wrapper.emitted('update:open')[0]).toEqual([true]); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Tests access internal implementation details but outcomes are observable.
The tests manipulate _isUnmounting and call internal methods (onLeaveTransitionComplete, onEnterTransitionComplete) directly. Per coding guidelines, tests should assert observable behavior rather than implementation details.
However, this tests a lifecycle race condition fix where the internal guard is the mechanism. The assertions on wrapper.emitted() are legitimate behavioral outcomes.
Consider splitting lines 357-369 and 376-388 — each test contains multiple uncontrolled/controlled scenarios with separate assertions, violating one-assertion-per-test guidance.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/dialtone-vue/components/popover/popover.test.js` around lines 341 -
389, Tests currently combine uncontrolled and controlled assertions in the
single tests for onLeaveTransitionComplete and onEnterTransitionComplete while
also toggling wrapper.vm._isUnmounting; split each of the two multi-assertion
tests ("emits \"opened\" and respects open prop when leave transition completes
and not unmounting" and "emits \"opened\" and respects open prop when enter
transition completes and not unmounting") into two separate tests each: one for
the uncontrolled scenario (open === null) that only sets _isUnmounting = false,
calls onLeaveTransitionComplete/onEnterTransitionComplete, and asserts
wrapper.emitted('opened') and that update:open is undefined, and another for the
controlled scenario that sets props (await wrapper.setProps({ open: false }))
then calls the same method and asserts update:open is emitted with the expected
value; keep the _isUnmounting manipulation and use the existing symbols
(wrapper.vm._isUnmounting, wrapper.vm.onLeaveTransitionComplete,
wrapper.vm.onEnterTransitionComplete, wrapper.setProps, wrapper.emitted) to
locate and split the logic.
|
Please add either the |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
.coderabbit.yaml (2)
255-263:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winNarrow the
site-nav.jsonrule to sidebar pages only.The current wording is too broad for
noSidebaror navbar-only docs pages, which intentionally do not live in_data/site-nav.json. Tightening this avoids recurring false positives.Suggested change
- path: 'apps/dialtone-documentation/**' instructions: > - Component doc pages require: overview, usage example, variants, props table, events table, slots table, accessibility notes. - - Sidebar navigation is in _data/site-nav.json — new pages must be added there. + - Sidebar navigation is in _data/site-nav.json — add new pages there + only when they participate in sidebar navigation. noSidebar or + navbar-only pages are exceptions. Follow the conventions in .claude/rules/documentation-site.md.Based on learnings: pages that set
noSidebar: trueand are linked via hard-coded navbar items should not be added toapps/dialtone-documentation/docs/_data/site-nav.json.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.coderabbit.yaml around lines 255 - 263, The rule text under the apps/dialtone-documentation/** block is too broad — it currently requires all pages to be added to _data/site-nav.json; update the instructions to only mandate adding pages that should appear in the sidebar (i.e., exclude pages that set noSidebar: true or are navbar-only). Specifically, change the guidance so it references _data/site-nav.json for sidebar pages only and calls out the noSidebar frontmatter flag (noSidebar: true) and navbar-linked pages as exceptions, while keeping the rest of the documentation conventions referenced in .claude/rules/documentation-site.md.
121-134:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winCarve out the migration-fixture exception in the CSS guidance.
This block currently tells reviewers to flag any raw value anywhere under
packages/dialtone-css/**, but the migration helper fixtures intentionally contain raw literals to verify no-op cases. Without an exception here, the config will keep generating false positives on those test files.Suggested change
- path: 'packages/dialtone-css/**' instructions: > - All values must use var(--dt-*) custom properties. Flag any hardcoded raw values (px, hex, rgb). + + - Exception: files under + packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/ + are migration fixtures; intentional raw CSS literals there should not + be flagged. - Utility naming: d-<property-shorthand><value> (e.g., d-p8, d-d-flex).Based on learnings: files under
packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/are migration test fixtures and raw CSS values there are intentional skip-case sentinels.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.coderabbit.yaml around lines 121 - 134, Update the .coderabbit.yaml rule that targets 'packages/dialtone-css/**' to exclude the migration fixture directory so raw literals there are ignored: adjust the rule for the path 'packages/dialtone-css/**' (or add an explicit new rule) to skip files under lib/build/js/dialtone_migration_helper/tests/ so reviewers won't flag intentional raw CSS values in those migration test fixtures.packages/dialtone-tokens/tokens/theme/prota-deuter/default.json (1)
30-38:⚠️ Potential issue | 🔴 CriticalRemove the duplicate
positivetoken declaration.The
positivekey is declared twice in the same object, with the second declaration shadowing the first. This causes the$deprecatedmetadata in the first declaration to be lost, breaking the deprecation signal.Proposed fix
- "positive": { - "value": "{shell.base.color.accent}", - "type": "color", - "$deprecated": "Use positive instead." - }, "positive": { "value": "{shell.base.color.accent}", "type": "color" },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/dialtone-tokens/tokens/theme/prota-deuter/default.json` around lines 30 - 38, The object contains two identical "positive" token entries; remove the duplicate and ensure the remaining "positive" token includes the "$deprecated" metadata from the original so the deprecation signal is preserved—update the single "positive" entry (token name "positive") to keep "value": "{shell.base.color.accent}", "type": "color" and add "$deprecated": "Use positive instead." if it isn't present.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.coderabbit.yaml:
- Around line 59-70: Add the scratch.md file to the path_filters exclusions so
it won't be included in inline reviews; update the path_filters array in
.coderabbit.yaml by adding the entry
"!apps/dialtone-documentation/docs/scratch.md" alongside the existing
"!apps/dialtone-documentation/docs/scratch-color.md" exclusion to prevent review
noise from the internal scratchpad.
In @.github/workflows/dialtone-documentation-tests.yml:
- Around line 10-27: The workflow's trigger paths omit the workflow file itself
and its local action, so edits to
.github/workflows/dialtone-documentation-tests.yml and the action at
.github/actions/setup-environment/** won't run validation; update both
pull_request.paths and push.paths in the workflow
(dialtone-documentation-tests.yml) to include
'.github/workflows/dialtone-documentation-tests.yml' and
'.github/actions/setup-environment/**' so changes to the workflow or its local
action trigger the job.
In
`@apps/dialtone-documentation/docs/.vuepress/theme/assets/less/dialtone-syntax.less`:
- Around line 43-49: The broad selector code:not(.d-code--md, .d-code--sm,
.d-prose *) is unintentionally overriding Prism inline-code styles; update that
selector to explicitly exclude Prism-marked code by adding
:not([class*="language-"]) (e.g. code:not(.d-code--md, .d-code--sm, .d-prose *,
[class*="language-"])) so Prism rules like code[class*="language-"] keep their
own user-select and padding, and verify the rules in the same block (user-select
and padding) no longer affect code[class*="language-"] elements.
In `@packages/dialtone-css/lib/build/less/components/link.less`:
- Line 20: The base .d-link rule wrongly sets --link-text-decoration: none which
removes underlines globally and makes .d-link--no-underline redundant; revert
that change by removing the --link-text-decoration declaration from the .d-link
selector and instead add the variable assignment only to the mention-specific
selectors (.d-link--mention and .d-link--inverted-mention) so that default links
remain underlined and the no-underline modifier still works.
---
Outside diff comments:
In @.coderabbit.yaml:
- Around line 255-263: The rule text under the apps/dialtone-documentation/**
block is too broad — it currently requires all pages to be added to
_data/site-nav.json; update the instructions to only mandate adding pages that
should appear in the sidebar (i.e., exclude pages that set noSidebar: true or
are navbar-only). Specifically, change the guidance so it references
_data/site-nav.json for sidebar pages only and calls out the noSidebar
frontmatter flag (noSidebar: true) and navbar-linked pages as exceptions, while
keeping the rest of the documentation conventions referenced in
.claude/rules/documentation-site.md.
- Around line 121-134: Update the .coderabbit.yaml rule that targets
'packages/dialtone-css/**' to exclude the migration fixture directory so raw
literals there are ignored: adjust the rule for the path
'packages/dialtone-css/**' (or add an explicit new rule) to skip files under
lib/build/js/dialtone_migration_helper/tests/ so reviewers won't flag
intentional raw CSS values in those migration test fixtures.
In `@packages/dialtone-tokens/tokens/theme/prota-deuter/default.json`:
- Around line 30-38: The object contains two identical "positive" token entries;
remove the duplicate and ensure the remaining "positive" token includes the
"$deprecated" metadata from the original so the deprecation signal is
preserved—update the single "positive" entry (token name "positive") to keep
"value": "{shell.base.color.accent}", "type": "color" and add "$deprecated":
"Use positive instead." if it isn't present.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: fe45f5a6-8e57-405c-a46e-cb05aa621605
📒 Files selected for processing (11)
.coderabbit.yaml.github/workflows/dialtone-documentation-tests.ymlapps/dialtone-documentation/docs/.vuepress/theme/assets/less/dialtone-syntax.lessapps/dialtone-documentation/docs/guides/mcp-server/index.mdpackages/dialtone-css/lib/build/less/components/link.lesspackages/dialtone-css/lib/build/less/components/notice.lesspackages/dialtone-tokens/package.jsonpackages/dialtone-tokens/tokens/theme/dp/dark.jsonpackages/dialtone-tokens/tokens/theme/dp/default.jsonpackages/dialtone-tokens/tokens/theme/prota-deuter/default.jsonpackages/eslint-plugin-dialtone/package.json
| path_filters: | ||
| - "**" | ||
| - "!**/dist/**" | ||
| - "!coverage/**" | ||
| - "!.nx/**" | ||
| - "!node_modules/**" | ||
| - "!packages/dialtone-icons/src/icons/**" # generated Vue components from SVG source | ||
| - "!packages/dialtone-icons/src/illustrations/**" # generated | ||
| - "!packages/dialtone-icons/android/src/**" # generated Android resources | ||
| - "!packages/dialtone-vue/storybook-static/**" # Storybook build output | ||
| - "!packages/dialtone-vue/functions/generated/**" | ||
| - "!apps/dialtone-documentation/docs/scratch-color.md" # dev scratchpad, not doc content |
There was a problem hiding this comment.
Exclude scratch.md from inline review too.
apps/dialtone-documentation/docs/scratch.md is another internal-only scratchpad, so it will still generate review noise unless it is filtered out alongside scratch-color.md.
Suggested change
path_filters:
- "**"
- "!**/dist/**"
- "!coverage/**"
- "!.nx/**"
- "!node_modules/**"
- "!packages/dialtone-icons/src/icons/**" # generated Vue components from SVG source
- "!packages/dialtone-icons/src/illustrations/**" # generated
- "!packages/dialtone-icons/android/src/**" # generated Android resources
- "!packages/dialtone-vue/storybook-static/**" # Storybook build output
- "!packages/dialtone-vue/functions/generated/**"
+ - "!apps/dialtone-documentation/docs/scratch.md" # internal scratchpad
- "!apps/dialtone-documentation/docs/scratch-color.md" # dev scratchpad, not doc contentBased on learnings: apps/dialtone-documentation/docs/scratch.md is an internal-only scratchpad page and should not be reviewed or commented on in PRs.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| path_filters: | |
| - "**" | |
| - "!**/dist/**" | |
| - "!coverage/**" | |
| - "!.nx/**" | |
| - "!node_modules/**" | |
| - "!packages/dialtone-icons/src/icons/**" # generated Vue components from SVG source | |
| - "!packages/dialtone-icons/src/illustrations/**" # generated | |
| - "!packages/dialtone-icons/android/src/**" # generated Android resources | |
| - "!packages/dialtone-vue/storybook-static/**" # Storybook build output | |
| - "!packages/dialtone-vue/functions/generated/**" | |
| - "!apps/dialtone-documentation/docs/scratch-color.md" # dev scratchpad, not doc content | |
| path_filters: | |
| - "**" | |
| - "!**/dist/**" | |
| - "!coverage/**" | |
| - "!.nx/**" | |
| - "!node_modules/**" | |
| - "!packages/dialtone-icons/src/icons/**" # generated Vue components from SVG source | |
| - "!packages/dialtone-icons/src/illustrations/**" # generated | |
| - "!packages/dialtone-icons/android/src/**" # generated Android resources | |
| - "!packages/dialtone-vue/storybook-static/**" # Storybook build output | |
| - "!packages/dialtone-vue/functions/generated/**" | |
| - "!apps/dialtone-documentation/docs/scratch.md" # internal scratchpad | |
| - "!apps/dialtone-documentation/docs/scratch-color.md" # dev scratchpad, not doc content |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.coderabbit.yaml around lines 59 - 70, Add the scratch.md file to the
path_filters exclusions so it won't be included in inline reviews; update the
path_filters array in .coderabbit.yaml by adding the entry
"!apps/dialtone-documentation/docs/scratch.md" alongside the existing
"!apps/dialtone-documentation/docs/scratch-color.md" exclusion to prevent review
noise from the internal scratchpad.
| pull_request: | ||
| paths: | ||
| - 'apps/dialtone-documentation/**' | ||
| - 'packages/dialtone-css/**' | ||
| - 'packages/dialtone-icons/**' | ||
| - 'packages/dialtone-tokens/**' | ||
| - 'packages/dialtone-vue/**' | ||
| - 'pnpm-lock.yaml' | ||
| push: | ||
| branches: | ||
| - staging | ||
| paths: | ||
| - 'apps/dialtone-documentation/**' | ||
| - 'packages/dialtone-css/**' | ||
| - 'packages/dialtone-icons/**' | ||
| - 'packages/dialtone-tokens/**' | ||
| - 'packages/dialtone-vue/**' | ||
| - 'pnpm-lock.yaml' |
There was a problem hiding this comment.
Include the workflow and its local action in the trigger paths.
As written, this job will not run when .github/workflows/dialtone-documentation-tests.yml or ./.github/actions/setup-environment/** changes, even though both are direct inputs to the job. That leaves workflow edits unvalidated.
Suggested change
pull_request:
paths:
+ - '.github/workflows/dialtone-documentation-tests.yml'
+ - '.github/actions/setup-environment/**'
- 'apps/dialtone-documentation/**'
- 'packages/dialtone-css/**'
- 'packages/dialtone-icons/**'
- 'packages/dialtone-tokens/**'
- 'packages/dialtone-vue/**'
- 'pnpm-lock.yaml'
push:
branches:
- staging
paths:
+ - '.github/workflows/dialtone-documentation-tests.yml'
+ - '.github/actions/setup-environment/**'
- 'apps/dialtone-documentation/**'
- 'packages/dialtone-css/**'
- 'packages/dialtone-icons/**'
- 'packages/dialtone-tokens/**'
- 'packages/dialtone-vue/**'
- 'pnpm-lock.yaml'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/dialtone-documentation-tests.yml around lines 10 - 27, The
workflow's trigger paths omit the workflow file itself and its local action, so
edits to .github/workflows/dialtone-documentation-tests.yml and the action at
.github/actions/setup-environment/** won't run validation; update both
pull_request.paths and push.paths in the workflow
(dialtone-documentation-tests.yml) to include
'.github/workflows/dialtone-documentation-tests.yml' and
'.github/actions/setup-environment/**' so changes to the workflow or its local
action trigger the job.
| code:not(.d-code--md, .d-code--sm, .d-prose *) { | ||
| padding: var(--dt-size-200) var(--dt-size-300); | ||
| color: var(--dt-color-foreground-info); | ||
| background-color: var(--dt-color-surface-info-subtle); | ||
| border-radius: var(--dt-size-radius-200); | ||
| user-select: all; | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consider narrowing the selector to avoid overriding Prism inline code styles.
Right now the rule targets basically “all code except .d-code--md/.d-code--sm and (maybe) descendants of .d-prose”. If .d-prose * exclusion doesn’t fully cover your Prism-marked inline code, you could override:
code[class*="language-"]styling atLine 52-68(notablyuser-select: initial)- inline language code padding at
Line 88-92
If the intent is only plain inline code, consider explicitly excluding code[class*="language-"] (or otherwise targeting only the markup pattern for plain inline code in your docs).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@apps/dialtone-documentation/docs/.vuepress/theme/assets/less/dialtone-syntax.less`
around lines 43 - 49, The broad selector code:not(.d-code--md, .d-code--sm,
.d-prose *) is unintentionally overriding Prism inline-code styles; update that
selector to explicitly exclude Prism-marked code by adding
:not([class*="language-"]) (e.g. code:not(.d-code--md, .d-code--sm, .d-prose *,
[class*="language-"])) so Prism rules like code[class*="language-"] keep their
own user-select and padding, and verify the rules in the same block (user-select
and padding) no longer affect code[class*="language-"] elements.
| --link-color-default: var(--dt-color-link-primary); | ||
| --link-color-default-hover: var(--dt-color-link-primary-hover); | ||
| --link-text-decoration: underline; | ||
| --link-text-decoration: none; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
python <<'PY'
from pathlib import Path
s = Path("packages/dialtone-css/lib/build/less/components/link.less").read_text()
print("Base declaration uses no underline:",
"--link-text-decoration: none;" in s)
print("Base hover enforces underline:",
"&:hover {\n --link-text-decoration: underline;" in s)
print("no-underline modifier still sets none+hover-underline:",
"&--no-underline" in s and " --link-text-decoration: underline;" in s)
PYRepository: dialpad/dialtone
Length of output: 197
🏁 Script executed:
#!/bin/bash
# Get full link.less file to understand complete structure
cat -n packages/dialtone-css/lib/build/less/components/link.lessRepository: dialpad/dialtone
Length of output: 146
🏁 Script executed:
#!/bin/bash
# Check file size first
wc -l packages/dialtone-css/lib/build/less/components/link.less
# Read specific sections around the flagged lines
echo "=== Lines 15-35 (around line 20) ==="
sed -n '15,35p' packages/dialtone-css/lib/build/less/components/link.less
echo "=== Lines 43-53 (around line 48) ==="
sed -n '43,53p' packages/dialtone-css/lib/build/less/components/link.less
echo "=== Lines 65-80 (around lines 70-75) ==="
sed -n '65,80p' packages/dialtone-css/lib/build/less/components/link.lessRepository: dialpad/dialtone
Length of output: 1735
🏁 Script executed:
#!/bin/bash
# Read the rest of the file to see mention-specific modifiers
echo "=== Lines 80-222 (remaining content) ==="
sed -n '80,222p' packages/dialtone-css/lib/build/less/components/link.lessRepository: dialpad/dialtone
Length of output: 5735
🏁 Script executed:
#!/bin/bash
# Check git diff for link.less to see what changed
git diff HEAD~1 packages/dialtone-css/lib/build/less/components/link.less || echo "=== Trying git show ===" && git show HEAD:packages/dialtone-css/lib/build/less/components/link.less 2>/dev/null | head -40Repository: dialpad/dialtone
Length of output: 1607
🏁 Script executed:
#!/bin/bash
# Check recent commits and PR context
git log --oneline -20 -- packages/dialtone-css/lib/build/less/components/link.less
# Look for any related test or documentation files
fd -e test.js -e spec.js -e mock.js link && echo "=== Test files ===" || true
find . -path "*/link*" -name "*.md" 2>/dev/null | head -10Repository: dialpad/dialtone
Length of output: 498
🏁 Script executed:
#!/bin/bash
# Check documentation about link behavior
echo "=== Link component documentation ==="
head -100 ./apps/dialtone-documentation/docs/components/link.md
echo ""
echo "=== Link test file to understand intended behavior ==="
grep -A 10 -B 2 "text-decoration\|underline\|no-underline" packages/dialtone-vue/components/link/link.test.js | head -50Repository: dialpad/dialtone
Length of output: 4482
Revert base link underline change; scope to mention variants only.
The CSS change sets --link-text-decoration: none; on .d-link base, making default links underline-free. This conflicts with documented behavior (docs state underline="false" removes underline from the default underlined state) and makes .d-link--no-underline functionally redundant.
If this PR targets mention styles specifically, change only .d-link--mention and .d-link--inverted-mention:
Scoped fix
.d-link {
--link-color-default: var(--dt-color-link-primary);
--link-color-default-hover: var(--dt-color-link-primary-hover);
- --link-text-decoration: none;
+ --link-text-decoration: underline;
--link-padding: 0;
--link-background-color: transparent; &--mention {
--link-color-default: var(--dt-color-link-mention);
--link-color-default-hover: var(--dt-color-link-mention-hover);
+ --link-text-decoration: none;
--link-padding: var(--dt-spacing-1) var(--dt-spacing-25);
--link-background-color: var(--dt-color-link-mention-background); &--inverted-mention {
--link-color-default: var(--dt-color-link-primary-inverted);
--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: var(--dt-color-link-mention-inverted-background);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/dialtone-css/lib/build/less/components/link.less` at line 20, The
base .d-link rule wrongly sets --link-text-decoration: none which removes
underlines globally and makes .d-link--no-underline redundant; revert that
change by removing the --link-text-decoration declaration from the .d-link
selector and instead add the variable assignment only to the mention-specific
selectors (.d-link--mention and .d-link--inverted-mention) so that default links
remain underlined and the no-underline modifier still works.
|
Closing in favor of a clean rebase. New PR incoming from |
feat(colors): DLT-3360 retune palettes for blue color update
Obligatory GIF (super important!)
🛠️ Type Of Change
📖 Jira Ticket
DLT-3360
📖 Description
Retunes the blue, gray, and purple base palette stops using OKLCH values calibrated for the updated blue color direction. Includes several related semantic token and component style changes bundled with the palette work:
tokens/base/default.jsonandtokens/base/dark.jsonsuccess→positivemigration — Addedpositive,positive-subtle,positive-strong, andpositive-opaquecompanions to all semantic surface/foreground/border token families in the DP and prota-deuter themes. Existingsuccess*tokens aliased to theirpositive*equivalents and marked$deprecated. Badge component tokens updated similarly.oklch(from ...)alpha math inlink.lesswith semantic tokens (link.mention-background,link.mention-inverted-background, and hover variants). Fixed dead--link-colorvariable (should be--link-color-default) in the mention modifier. Corrected swapped alpha values in dark-mode mention background tokens.surface-primary-inverted(wassurface-strong). Inline code background in doc site now usessurface-info-subtle(wassurface-info).scratch-color.mdas a developer-only visual test page for comprehensive token verification across modes, contrast, and themes.📦 Cross-Package Impact
dialtone-tokenspositivetoken additions, mention link tokensdialtone-cssd-link--mention,d-notice--important, or inline code stylesDependency flow: tokens → CSS → Vue → docs/MCP/language-server
💡 Context
The blue palette retune is part of a broader brand color system refresh (DLT-3360). The
success→positivemigration aligns Dialtone's semantic naming with the broader design language ("positive" is the canonical term for success-state feedback). The link mention and notice fixes correct token usage that was using hardcoded OKLCH math or less-specific surface tokens.📝 Checklist
For all PRs:
For all CSS changes:
🔮 Next Steps
success*deprecated tokens in a future major release once consumers have migrated topositive*subtle/default/boldvssubtle/default/strong) was identified during this work but deferred — follow-up ticket needed📷 Screenshots / GIFs
Visual verification done via the
scratch-color.mdpage added in this PR. Runpnpm nx run dialtone-documentation:startand navigate to/scratch-colorto see all token families across light/dark/high-contrast modes and inverted contexts.🔗 Sources