Skip to content

feat(css-utilities, design-tokens): DLT-3330 DLT-3332 add off-scale pixel-indexed layout tokens and sizing utilities#1206

Merged
Francis Rupert (francisrupert) merged 9 commits intonextfrom
off-scale-layout-tokens
Apr 17, 2026
Merged

feat(css-utilities, design-tokens): DLT-3330 DLT-3332 add off-scale pixel-indexed layout tokens and sizing utilities#1206
Francis Rupert (francisrupert) merged 9 commits intonextfrom
off-scale-layout-tokens

Conversation

@francisrupert
Copy link
Copy Markdown
Contributor

@francisrupert Francis Rupert (francisrupert) commented Apr 16, 2026

Merry go round dog

🛠️ Type Of Change

  • Feature

📖 Jira Ticket

  • DLT-3330 — Add off-scale pixel-indexed layout tokens and sizing utilities
  • DLT-3332 — Migrate legacy small-size utility classes and --dt-size-* references to off-scale layout tokens (bundled in this PR)

📖 Description

Add off-scale pixel-indexed layout tokens (--dt-layout-1px, --dt-layout-2px, --dt-layout-8px, --dt-layout-20px, --dt-layout-24px) alongside the scale-indexed dt-layout-25/50/… scale.

Emit 35 new hyphenated sizing utility selectors — .d-w-1px, .d-h-2px, .d-size-8px, .d-wmn-20px, .d-hmx-24px, etc. — across all 7 sizing properties: height, max-height, min-height, size, width, max-width, min-width.

Docs: add a disambiguation notice to the 7 sizing utility pages. Token/utility tables interleave exceptions with scale tokens in ascending resolved-pixel-value order.

Naming rule: px suffix in a stop = literal pixel value; bare integer = scale unit on the 64px base.

Migration & lint updates (DLT-3332)

Extend existing migration helper configs and ESLint rule to cover the five off-scale values so consumers can migrate legacy callsites automatically:

  • utility-class-to-token-stops migration — extended SIZING_MAP so .d-w1.d-w-1px, .d-h24.d-h-24px, etc. across all 6 sizing prefixes.
  • size-to-layout migration — extended LAYOUT_MAP so width: var(--dt-size-N) at the 5 small stops (100/200/400/525/550) routes to var(--dt-layout-Npx) in layout-property context. Property-aware routing already existed; only the mapping data was missing. Spacing-context routing unchanged (regression guard in tests).
  • deprecated-pixel-utility-classes ESLint rule — extended SIZING_PIXELS (in descending-length order) so .d-w1, .d-h24, .d-hmn8, etc. are flagged as deprecated in editors.
  • Automated tests added for both migrations and the new ESLint cases.

What this does NOT do:

  • Add other off-scale values (e.g. 4, 6, 12, 42)
  • Change any existing scale-indexed tokens or utilities
  • Touch the deprecated .d-w1/.d-h1/… calc-based path generation (stays on its existing deprecation timeline)
  • Cover padding, margin, gap, inset, or percent-based layout
  • Update Figma variables (design-team side task)

💡 Context

The dt-layout-* scale is indexed on a 64px base — 100 = 64px, each step of 25 = 16px. Works cleanly for 16px-and-up multiples, but sub-16px (1, 2, 8px) and off-grid-between-steps (20, 24px) values produce hostile token names (dt-layout-1.5625, dt-layout-37.5, …). Product teams need these values. This change provides them as first-class tokens with a predictable naming rule that humans and AI can pick from a spec without math.

📦 Cross-Package Impact

Package Changes Downstream
dialtone-tokens 5 new layout tokens Consumed by dialtone-css and all downstream Vue/docs/MCP builds
dialtone-css LAYOUT_STOPS extended; 35 new hyphenated utility selectors; migration helper configs extended Consumed by dialtone-documentation and the MCP data blobs
dialtone-documentation Notice added to 7 sizing pages; _data/width-height.json extended
eslint-plugin-dialtone SIZING_PIXELS in deprecated-pixel-utility-classes rule extended Consumer editors flag legacy .d-w1-style classes

Dependency flow: tokenscssvue / docs / MCP / eslint

📄 Documentation Artifacts

Artifact Status Notes
VuePress docs ✅ Updated Notice + interleaved data on 7 sizing pages
MCP server data ✅ Updated (via build) Flows through dialtone-css build outputs automatically
Migration helper docs ✅ Updated /dt-migrate skill doc: size-to-layout + utility-class-to-token-stops entries note off-scale coverage
Vue source / tests / stories / component-docs.json n/a No Vue changes

📝 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

  • Follow-up (separate ticket) to retire the legacy .d-w1/.d-h1/… Tier 1 calc-based path once consumers migrate.
  • Design-team task to expose the new tokens as Figma variables.

@github-actions
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
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 16, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 5ab26ea4-0854-4c05-8bcb-cbbfa17a8c43

📥 Commits

Reviewing files that changed from the base of the PR and between 24bb71c and deff971.

📒 Files selected for processing (3)
  • packages/dialtone-css/lib/build/less/components/box.less
  • packages/dialtone-vue/components/box/box.vue
  • packages/dialtone-vue/components/box/box_constants.js

Cache: Disabled due to Reviews > Disable Cache setting

Disabled knowledge base sources:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.


Adds five off-scale pixel-indexed layout tokens (1px, 2px, 8px, 20px, 24px), 35 hyphenated sizing utilities across seven sizing properties, docs updates, migration/lint rule extensions, and comprehensive tests; includes an unrelated dropdown checkmark removal.

Overall Judgement: ⚠️ Needs minor changes

Rationale: Feature is well implemented and tested, but the unrelated UI change (control_selection.vue) should be split into a separate PR to keep scope focused.

Walkthrough

Adds five pixel-suffixed off-scale layout stops (1px, 2px, 8px, 20px, 24px) across tokens, constants, Less/CSS generators, Vue props/validators, migration helpers, lint rules, tests, and docs; clarifies that bare integers remain scale-indexed on a 64px base while px stops are literal pixels.

Changes

Cohort / File(s) Summary
Layout data & docs
apps/dialtone-documentation/docs/_data/width-height.json, apps/dialtone-documentation/docs/utilities/sizing/width.md, .../height.md, .../size.md, .../min-width.md, .../min-height.md, .../max-width.md, .../max-height.md
Inserted 1px,2px,8px,20px,24px stops into width/height data and added notes explaining bare-integer (64px-base scale) vs px-suffixed literal behavior.
Tokens & postcss constants
packages/dialtone-tokens/tokens/base/default.json, packages/dialtone-css/postcss/constants.cjs
Added layout token entries for new *px keys and updated LAYOUT_STOPS to include string *px exceptions mixed with integer stops; comment updated to document scale vs px exceptions.
Less/CSS generation
packages/dialtone-css/lib/build/less/components/box.less
Extended ._box-layout(Roman (@prop)) mixin to generate modifier branches for -1px, -2px, -8px, -20px, -24px mapping to corresponding var(--dt-layout-*).
Vue props, constants, validators
packages/dialtone-vue/components/box/box.vue, packages/dialtone-vue/components/box/box_constants.js, packages/dialtone-vue/components/box/validators.js
Inserted px tokens into documented @values and DT_BOX_LAYOUT_VALUES; refactored validators to a shared listValidator and included new px tokens in validation lists (with dev-mode warnings).
Migration helpers & tests/examples
packages/dialtone-css/lib/build/js/dialtone_migration_helper/configs/size-to-layout.mjs, .../utility-class-to-token-stops.mjs, .../tests/size-to-layout.test.mjs, .../tests/utility-class-to-token-stops.test.mjs, .../tests/size-to-layout-test-examples.vue
Extended mappings to route selected --dt-size-* stops to --dt-layout-* px exceptions; switched mapping source to LAYOUT_STOPS; added tests/examples covering off-scale mappings and preserving spacing routing for spacing contexts.
ESLint rule & tests
packages/eslint-plugin-dialtone/lib/rules/deprecated-pixel-utility-classes.js, packages/eslint-plugin-dialtone/tests/lib/rules/deprecated-pixel-utility-classes.js
Expanded detected pixel sizing set to include 1,2,8,20,24, adjusted regex ordering/message examples, and added tests for new off-scale utility forms.
Combinator UI
packages/combinator/src/components/controls/control_selection.vue
Removed per-option trailing checkmark markup and deleted the DtIconCheck import.
Migration docs
.claude/skills/dt-migrate.md
Added size-to-layout and utility-class-to-token-stops migration entries documenting off-scale pixel-indexed mappings and examples.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • dialpad/dialtone PR 1206 — Adds the same five off-scale pixel-indexed layout tokens/utilities across tokens, CSS/LESS, Vue, migration helpers, ESLint, docs, and tests.
  • dialpad/dialtone PR 1203 — Modifies Box sizing tokens/values and related validators/stop mappings; closely related to DT_BOX_LAYOUT_VALUES and validator changes.
  • dialpad/dialtone PR 1208 — Touches the same box/layout sizing codepaths and documentation changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch off-scale-layout-tokens

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

@francisrupert Francis Rupert (francisrupert) changed the title feat(css-utilities, design-tokens): DLT-3330 add off-scale pixel-indexed layout tokens and sizing utilities feat(css-utilities, design-tokens): DLT-3330 DLT-3332 add off-scale pixel-indexed layout tokens and sizing utilities Apr 17, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/size-to-layout-test-examples.vue (1)

126-129: Avoid duplicate block-size in the off-scale CSS sample.

Line 129 overrides Line 126, so one sample is effectively shadowed. Consider using a distinct layout property for the 24px case to keep each mapping independently visible.

Proposed tweak
-  block-size: var(--dt-size-550);     /* → layout-24px (24px) */
+  max-block-size: var(--dt-size-550); /* → layout-24px (24px) */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/size-to-layout-test-examples.vue`
around lines 126 - 129, The CSS sample duplicates block-size (var(--dt-size-200)
and var(--dt-size-550)), causing the earlier mapping to be shadowed; update the
later occurrence (the var(--dt-size-550) 24px case) to a distinct layout
property (for example inline-size, min-block-size, max-block-size, or
max-inline-size) so each size-to-layout mapping remains independently
visible—locate the two block-size entries in the test example and replace the
second one with the chosen distinct property while keeping the comment mapping
consistent.
packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/utility-class-to-token-stops.test.mjs (1)

15-16: Add off-scale coverage for d-size* legacy selectors.

Line 15 currently omits the size prefix from the off-scale matrix. Since this PR introduces pixel-indexed size utilities too, add size here (or add an explicit non-support assertion) so regressions on that path are caught.

Proposed test update
-    const prefixes = ['h', 'w', 'hmn', 'hmx', 'wmn', 'wmx'];
+    const prefixes = ['h', 'w', 'size', 'hmn', 'hmx', 'wmn', 'wmx'];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/utility-class-to-token-stops.test.mjs`
around lines 15 - 16, The test currently builds an off-scale matrix using the
prefixes array but omits the legacy "size" prefix, so update the prefixes
constant used in the test (prefixes = ['h','w','hmn','hmx','wmn','wmx']) to
include "size" (i.e. add 'size' into the array) so the pixel-indexed size
utilities are covered; alternatively, if you don't want to assert support for
legacy d-size, add an explicit non-support assertion in the same test that
documents and checks that "size" is intentionally unsupported.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/size-to-layout-test-examples.vue`:
- Around line 126-129: The CSS sample duplicates block-size (var(--dt-size-200)
and var(--dt-size-550)), causing the earlier mapping to be shadowed; update the
later occurrence (the var(--dt-size-550) 24px case) to a distinct layout
property (for example inline-size, min-block-size, max-block-size, or
max-inline-size) so each size-to-layout mapping remains independently
visible—locate the two block-size entries in the test example and replace the
second one with the chosen distinct property while keeping the comment mapping
consistent.

In
`@packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/utility-class-to-token-stops.test.mjs`:
- Around line 15-16: The test currently builds an off-scale matrix using the
prefixes array but omits the legacy "size" prefix, so update the prefixes
constant used in the test (prefixes = ['h','w','hmn','hmx','wmn','wmx']) to
include "size" (i.e. add 'size' into the array) so the pixel-indexed size
utilities are covered; alternatively, if you don't want to assert support for
legacy d-size, add an explicit non-support assertion in the same test that
documents and checks that "size" is intentionally unsupported.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 90cac726-1e1b-4a99-a580-6e7d32d0e59b

📥 Commits

Reviewing files that changed from the base of the PR and between f12ab1c and 27efd27.

📒 Files selected for processing (8)
  • .claude/skills/dt-migrate.md
  • packages/dialtone-css/lib/build/js/dialtone_migration_helper/configs/size-to-layout.mjs
  • packages/dialtone-css/lib/build/js/dialtone_migration_helper/configs/utility-class-to-token-stops.mjs
  • packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/size-to-layout-test-examples.vue
  • packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/size-to-layout.test.mjs
  • packages/dialtone-css/lib/build/js/dialtone_migration_helper/tests/utility-class-to-token-stops.test.mjs
  • packages/eslint-plugin-dialtone/lib/rules/deprecated-pixel-utility-classes.js
  • packages/eslint-plugin-dialtone/tests/lib/rules/deprecated-pixel-utility-classes.js
✅ Files skipped from review due to trivial changes (3)
  • packages/dialtone-css/lib/build/js/dialtone_migration_helper/configs/size-to-layout.mjs
  • .claude/skills/dt-migrate.md
  • packages/dialtone-css/lib/build/js/dialtone_migration_helper/configs/utility-class-to-token-stops.mjs

@francisrupert
Copy link
Copy Markdown
Contributor Author

Thanks for the review!

Finding 1 (duplicate block-size in size-to-layout-test-examples.vue): Applied. Changed line 129 from block-size to max-block-size so each off-scale fixture row uses a distinct layout property. The migration is regex-based (no CSS cascade at run time), so correctness was unaffected, but the fixture is easier to scan now.

Finding 2 (add size prefix to off-scale matrix in utility-class-to-token-stops.test.mjs): Deliberately excluded. There is no legacy .d-size<N> (non-hyphenated) selector in the old generator — .d-size-* is a new-convention-only selector introduced in the same PR as the hyphenated scale (via tokenSizingUtilities in dialtone-generators.cjs), so there's nothing to migrate from. The 6 prefixes in the test (h|w|hmn|hmx|wmn|wmx) match the migration config's actual coverage.

@github-actions
Copy link
Copy Markdown
Contributor

✔️ Deploy previews ready!
😎 Dialtone documentation preview: https://dialtone.dialpad.com/deploy-previews/pr-1206/
😎 Dialtone-vue preview: https://dialtone.dialpad.com/vue/deploy-previews/pr-1206/

@francisrupert Francis Rupert (francisrupert) merged commit 1054875 into next Apr 17, 2026
11 of 12 checks passed
@francisrupert Francis Rupert (francisrupert) deleted the off-scale-layout-tokens branch April 17, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-visual-test Add this tag when the PR does not need visual testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants