Skip to content

feat(colors): DLT-3360 retune blue gold purple red black magenta palettes - #1242

Closed
Joshua Hynes (hynes-dialpad) wants to merge 25 commits into
nextfrom
feat/DLT-3360-blue-color-palette-updates
Closed

feat(colors): DLT-3360 retune blue gold purple red black magenta palettes#1242
Joshua Hynes (hynes-dialpad) wants to merge 25 commits into
nextfrom
feat/DLT-3360-blue-color-palette-updates

Conversation

@hynes-dialpad

@hynes-dialpad Joshua Hynes (hynes-dialpad) commented May 1, 2026

Copy link
Copy Markdown
Member

feat(colors): DLT-3360 retune palettes for blue color update

Obligatory GIF (super important!)

Working hard

🛠️ Type Of Change

  • Feature
  • Refactor

📖 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:

  • Palette retune — Updated OKLCH values for blue, black/gray, purple, and magenta scales in tokens/base/default.json and tokens/base/dark.json
  • successpositive migration — Added positive, positive-subtle, positive-strong, and positive-opaque companions to all semantic surface/foreground/border token families in the DP and prota-deuter themes. Existing success* tokens aliased to their positive* equivalents and marked $deprecated. Badge component tokens updated similarly.
  • Link mention variant — Replaced inline oklch(from ...) alpha math in link.less with semantic tokens (link.mention-background, link.mention-inverted-background, and hover variants). Fixed dead --link-color variable (should be --link-color-default) in the mention modifier. Corrected swapped alpha values in dark-mode mention background tokens.
  • Surface token fixes — Important notice/banner/toast variant now uses surface-primary-inverted (was surface-strong). Inline code background in doc site now uses surface-info-subtle (was surface-info).
  • Scratch color page — Added scratch-color.md as a developer-only visual test page for comprehensive token verification across modes, contrast, and themes.

📦 Cross-Package Impact

Package Changes Downstream Impact
dialtone-tokens Palette retune, positive token additions, mention link tokens All token consumers pick up new palette values on next build
dialtone-css Link mention variant, notice important variant, doc site inline code Any product using d-link--mention, d-notice--important, or inline code styles

Dependency flow: tokensCSS → Vue → docs/MCP/language-server

💡 Context

The blue palette retune is part of a broader brand color system refresh (DLT-3360). The successpositive migration 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:

  • I have ensured no private Dialpad links or info are in the code or pull request description (Dialtone is a public repo!).
  • I have reviewed my changes.
  • I have added all relevant documentation.
  • I have considered the performance impact of my change.

For all CSS changes:

  • I have used design tokens whenever possible.
  • I have considered how this change will behave on different screen sizes.
  • I have visually validated my change in light and dark mode.
  • I have used gap or flexbox properties for layout instead of margin whenever possible.

🔮 Next Steps

  • Remove success* deprecated tokens in a future major release once consumers have migrated to positive*
  • The border naming inconsistency (subtle/default/bold vs subtle/default/strong) was identified during this work but deferred — follow-up ticket needed

📷 Screenshots / GIFs

Visual verification done via the scratch-color.md page added in this PR. Run pnpm nx run dialtone-documentation:start and navigate to /scratch-color to see all token families across light/dark/high-contrast modes and inverted contexts.

🔗 Sources

Brad Paugh (braddialpad) and others added 19 commits April 28, 2026 11:19
…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))
## [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))
## [3.219.2](dialtone-vue/v3.219.1...dialtone-vue/v3.219.2) (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))
# [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.
@coderabbitai

coderabbitai Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This 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

Cohort / File(s) Summary
LLMs & Documentation Build
apps/dialtone-documentation/docs/.vuepress/config.js, apps/dialtone-documentation/package.json
Adds VuePress @vuepress/plugin-llms plugin with route filtering, enables llmsTxt and llmsFullTxt generation, excludes whats-new/brand/illustrations routes, includes design/components/guides sections. Replaces colorjs.io with tinycolor2 and updates dependencies.
Standards Freshness System
packages/dialtone-docs/src/generators/check-freshness.mjs, packages/dialtone-docs/src/content/standards/..., packages/dialtone-docs/tests/tests/check-freshness.test.js, packages/dialtone-docs/tests/tests/schema.test.js, packages/dialtone-docs/package.json, packages/dialtone-docs/project.json
Introduces 90-day content verification scanning with last_verified frontmatter field, exports parseLastVerified and isStale helpers, adds nx check-freshness target, creates comprehensive test coverage for date parsing and staleness logic.
Standards Freshness CI Workflow
.github/workflows/standards-freshness.yml, .github/workflows/dialtone-documentation-tests.yml, CLAUDE.md
Adds dedicated workflows: standards-freshness scans for stale content and posts paginated PR comments with findings, documentation-tests validates LLMs artifact generation. Updates contributor guide with CodeRabbit maintenance instructions.
Component Lifecycle Fixes
packages/dialtone-vue/components/collapsible/collapsible.vue, packages/dialtone-vue/components/collapsible/collapsible.test.js, packages/dialtone-vue/components/popover/popover.vue, packages/dialtone-vue/components/popover/popover.test.js
Adds _isUnmounting guard during beforeUnmount to prevent transition callbacks from emitting events after component teardown; includes comprehensive test coverage for both controlled and uncontrolled modes.
Rich Text Editor Enhancements
packages/dialtone-vue/components/rich_text_editor/rich_text_editor.vue
Introduces allowTextAlign prop, improves code-block rendering to respect selection ranges, merges multiple textblocks into single code block, converts pastes of <hr> elements to line separators.
Design Token Updates
packages/dialtone-tokens/tokens/base/default.json, packages/dialtone-tokens/tokens/base/dark.json, packages/dialtone-tokens/tokens/components/badge/default.json, packages/dialtone-tokens/tokens/theme/dp/default.json, packages/dialtone-tokens/tokens/theme/dp/dark.json, packages/dialtone-tokens/tokens/theme/prota-deuter/default.json
Rebrand success-related tokens to positive with deprecated aliases, introduce new link-mention color tokens with background variants and opacity modifiers, update link.info to reference blue palette, modernize oklch color values across base palettes.
Component Documentation Refactoring
apps/dialtone-documentation/docs/components/avatar.md, apps/dialtone-documentation/docs/components/emoji.md, apps/dialtone-documentation/docs/components/skeleton.md, apps/dialtone-documentation/docs/components/tabs.md, apps/dialtone-documentation/docs/components/rich-text-editor.md
Converts inline vue demo blocks to <code-well-header> and <code-example-tabs> components with html/vue code variants, removes deprecated/redundant examples, updates attribute names and demo structure for consistency.
Storybook Integration
packages/dialtone-vue/.storybook/DialtoneDocsPage.js, packages/dialtone-vue/.storybook/DialtoneDocsPage.jsx, packages/dialtone-vue/.storybook/preview.js
Adds new DialtoneDocsPage component that derives component documentation link from Storybook meta.title, removes JSX variant, switches DocsContainer to createElement API, updates import path.
Documentation Additions
apps/dialtone-documentation/docs/scratch-color.md, apps/dialtone-documentation/docs/guides/mcp-server/index.md, apps/dialtone-documentation/docs/.vuepress/exampleComponents/ExampleTabs.vue
Adds interactive color/theme token playground with surface/foreground/link previews, updates MCP search_tokens documentation to use positive instead of success, refines ExampleTabs label prop usage.
CSS & Style Updates
packages/dialtone-css/lib/build/less/components/link.less, packages/dialtone-css/lib/build/less/components/notice.less, packages/dialtone-css/lib/build/less/components/rich-text-editor.less, apps/dialtone-documentation/docs/.vuepress/theme/assets/less/dialtone-syntax.less
Changes link defaults to non-underlined with hover underline, updates mention-link styling to pill-based with tokenized backgrounds, changes important notice background token, adds nested list marker variation (disc/circle/square and decimal/lower-alpha/lower-roman), adds inline code element styling.
Package Metadata & Configuration
.coderabbit.yaml, .github/CODEOWNERS, packages/dialtone-emojis/package.json, packages/dialtone-emojis/CHANGELOG.json, packages/dialtone-emojis/CHANGELOG.md, packages/dialtone-icons/package.json, packages/dialtone-icons/CHANGELOG.md, packages/dialtone-icons/android/gradle.properties, packages/dialtone-icons/gulpfile.cjs, packages/dialtone-tokens/package.json, packages/eslint-plugin-dialtone/package.json, packages/postcss-responsive-variations/package.json, packages/stylelint-plugin-dialtone/package.json
Extends CodeRabbit configuration with knowledge-base links, path-based reviewer mappings, and targeted path-instructions; adds Belu Montoya to CODEOWNERS catch-all and multiple package contributor lists; publishes dialtone-icons vue3 build (v4.51.1), bumps dialtone-emojis to v1.2.5, refactors icon build cleanup tasks from del.sync to execSync('rm -rf').

Possibly related PRs

Suggested labels

visual-test-ready

Suggested reviewers

  • francisrupert
  • iropolo
  • braddialpad
  • ninarepetto
  • belumontoya
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/DLT-3360-blue-color-palette-updates

Review rate limit: 8/10 reviews remaining, refill in 7 minutes and 18 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@wiz-inc-55b470eb7e

wiz-inc-55b470eb7e Bot commented May 1, 2026

Copy link
Copy Markdown

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities -
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings -
Software Management Finding Software Management Findings -
Total -

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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-');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@hynes-dialpad
Joshua Hynes (hynes-dialpad) changed the base branch from staging to next May 1, 2026 04:40
@hynes-dialpad Joshua Hynes (hynes-dialpad) changed the title feat(colors): DLT-3360 retune palettes for blue color update feat(colors): DLT-3360 retune blue gold purple red black palettes May 1, 2026
@hynes-dialpad Joshua Hynes (hynes-dialpad) changed the title feat(colors): DLT-3360 retune blue gold purple red black palettes feat(colors): DLT-3360 retune blue gold purple red black magenta palettes May 1, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 | 🟠 Major

Move dark mode listener into useEffect to prevent accumulation.

Line 255 adds a channel.on listener on every render without cleanup, causing listeners to accumulate and fire duplicately. This logic already exists in the useEffect (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 win

Use positive here instead of deprecated success.

The token-search guidance still tells users to query success, which is stale relative to this PR’s successpositive migration and will bias MCP results toward deprecated aliases.

Based on learnings, "the broad rename from error/success/danger to critical/positive across 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 win

Relax 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.json override 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

📥 Commits

Reviewing files that changed from the base of the PR and between e6e75ef and edf2c9f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml and included by **
📒 Files selected for processing (63)
  • .coderabbit.yaml
  • .github/CODEOWNERS
  • .github/workflows/dialtone-documentation-tests.yml
  • .github/workflows/standards-freshness.yml
  • CHANGELOG.json
  • CHANGELOG.md
  • CLAUDE.md
  • apps/dialtone-documentation/docs/.vuepress/config.js
  • apps/dialtone-documentation/docs/.vuepress/exampleComponents/ExampleTabs.vue
  • apps/dialtone-documentation/docs/.vuepress/theme/assets/less/dialtone-syntax.less
  • apps/dialtone-documentation/docs/components/avatar.md
  • apps/dialtone-documentation/docs/components/emoji.md
  • apps/dialtone-documentation/docs/components/rich-text-editor.md
  • apps/dialtone-documentation/docs/components/skeleton.md
  • apps/dialtone-documentation/docs/components/tabs.md
  • apps/dialtone-documentation/docs/guides/mcp-server/index.md
  • apps/dialtone-documentation/docs/scratch-color.md
  • apps/dialtone-documentation/docs/utilities/typography/line-clamp.md
  • apps/dialtone-documentation/package.json
  • package.json
  • packages/dialtone-css/CHANGELOG.json
  • packages/dialtone-css/CHANGELOG.md
  • packages/dialtone-css/lib/build/less/components/link.less
  • packages/dialtone-css/lib/build/less/components/notice.less
  • packages/dialtone-css/lib/build/less/components/rich-text-editor.less
  • packages/dialtone-css/package.json
  • packages/dialtone-docs/package.json
  • packages/dialtone-docs/project.json
  • packages/dialtone-docs/src/content/standards/INDEX.md
  • packages/dialtone-docs/src/content/standards/standard-ai-documentation.md
  • packages/dialtone-docs/src/content/standards/standard-geo-optimization.md
  • packages/dialtone-docs/src/generators/check-freshness.mjs
  • packages/dialtone-docs/tests/tests/check-freshness.test.js
  • packages/dialtone-docs/tests/tests/schema.test.js
  • packages/dialtone-emojis/CHANGELOG.json
  • packages/dialtone-emojis/CHANGELOG.md
  • packages/dialtone-emojis/package.json
  • packages/dialtone-icons/CHANGELOG.json
  • packages/dialtone-icons/CHANGELOG.md
  • packages/dialtone-icons/android/gradle.properties
  • packages/dialtone-icons/gulpfile.cjs
  • packages/dialtone-icons/package.json
  • packages/dialtone-tokens/package.json
  • packages/dialtone-tokens/tokens/base/dark.json
  • packages/dialtone-tokens/tokens/base/default.json
  • packages/dialtone-tokens/tokens/components/badge/default.json
  • packages/dialtone-tokens/tokens/theme/dp/dark.json
  • packages/dialtone-tokens/tokens/theme/dp/default.json
  • packages/dialtone-tokens/tokens/theme/prota-deuter/default.json
  • packages/dialtone-vue/.storybook/DialtoneDocsPage.js
  • packages/dialtone-vue/.storybook/DialtoneDocsPage.jsx
  • packages/dialtone-vue/.storybook/preview.js
  • packages/dialtone-vue/CHANGELOG.json
  • packages/dialtone-vue/CHANGELOG.md
  • packages/dialtone-vue/components/collapsible/collapsible.test.js
  • packages/dialtone-vue/components/collapsible/collapsible.vue
  • packages/dialtone-vue/components/popover/popover.test.js
  • packages/dialtone-vue/components/popover/popover.vue
  • packages/dialtone-vue/components/rich_text_editor/rich_text_editor.vue
  • packages/dialtone-vue/package.json
  • packages/eslint-plugin-dialtone/package.json
  • packages/postcss-responsive-variations/package.json
  • packages/stylelint-plugin-dialtone/package.json
💤 Files with no reviewable changes (1)
  • packages/dialtone-vue/.storybook/DialtoneDocsPage.jsx

Comment thread .coderabbit.yaml
Comment thread .github/workflows/dialtone-documentation-tests.yml
Comment on lines +244 to +269
<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" />
'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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.

Comment on lines +524 to 526
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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.

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.
🤖 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.

Comment on lines +11 to +15
<code-well-header>
<div class="d-w50p">
<dt-skeleton :animate="false" />
</div>
</code-well-header>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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).

Comment on lines 175 to 184
"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."
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 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.")
PY

Repository: 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-inverted
  • color.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.

Comment thread packages/dialtone-tokens/tokens/theme/dp/default.json Outdated
Comment on lines +13 to +16
const { preparedMeta } = useOf('meta', ['meta']);
const segments = preparedMeta.title.split('/');
const componentName = segments[segments.length - 1];
const slug = componentName.replace(/\s+/g, '-').toLowerCase();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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:


🏁 Script executed:

#!/bin/bash
# Locate DialtoneDocsPage.js and examine the full function
find . -name "DialtoneDocsPage.js" -type f

Repository: 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 -50

Repository: 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 -10

Repository: 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 -10

Repository: 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 -100

Repository: 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 -100

Repository: 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 -l

Repository: 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 -100

Repository: 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/null

Repository: 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 -5

Repository: 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 -50

Repository: 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.

Comment thread packages/dialtone-vue/CHANGELOG.md Outdated
Comment on lines +341 to +389
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]);
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

@github-actions

github-actions Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

Please add either the visual-test-ready or no-visual-test label to this PR depending on whether you want to run visual tests or not.
It is recommended to run visual tests if your PR changes any UI. ‼️

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Narrow the site-nav.json rule to sidebar pages only.

The current wording is too broad for noSidebar or 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: true and are linked via hard-coded navbar items should not be added to apps/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 win

Carve 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 | 🔴 Critical

Remove the duplicate positive token declaration.

The positive key is declared twice in the same object, with the second declaration shadowing the first. This causes the $deprecated metadata 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

📥 Commits

Reviewing files that changed from the base of the PR and between edf2c9f and 6b8b466.

📒 Files selected for processing (11)
  • .coderabbit.yaml
  • .github/workflows/dialtone-documentation-tests.yml
  • apps/dialtone-documentation/docs/.vuepress/theme/assets/less/dialtone-syntax.less
  • apps/dialtone-documentation/docs/guides/mcp-server/index.md
  • packages/dialtone-css/lib/build/less/components/link.less
  • packages/dialtone-css/lib/build/less/components/notice.less
  • packages/dialtone-tokens/package.json
  • packages/dialtone-tokens/tokens/theme/dp/dark.json
  • packages/dialtone-tokens/tokens/theme/dp/default.json
  • packages/dialtone-tokens/tokens/theme/prota-deuter/default.json
  • packages/eslint-plugin-dialtone/package.json

Comment thread .coderabbit.yaml
Comment on lines +59 to +70
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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 content

Based 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.

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-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.

Comment on lines +10 to +27
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'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Comment on lines +43 to +49
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;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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 at Line 52-68 (notably user-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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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)
PY

Repository: 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.less

Repository: 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.less

Repository: 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.less

Repository: 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 -40

Repository: 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 -10

Repository: 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 -50

Repository: 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.

@hynes-dialpad

Copy link
Copy Markdown
Member Author

Closing in favor of a clean rebase. New PR incoming from rebase-work branch — the old branch had accumulated staging merge commits and noise.

@hynes-dialpad
Joshua Hynes (hynes-dialpad) deleted the feat/DLT-3360-blue-color-palette-updates branch May 1, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants