Skip to content

feat: unify typography and layout tokens#799

Merged
rohanchkrabrty merged 3 commits into
mainfrom
feat-tokens-unification
May 11, 2026
Merged

feat: unify typography and layout tokens#799
rohanchkrabrty merged 3 commits into
mainfrom
feat-tokens-unification

Conversation

@rohanchkrabrty
Copy link
Copy Markdown
Contributor

Summary

  • Text: drop numeric size (1–10) and free-form weights; keep micro | mini | small | regular | large and regular | medium.
  • Headline: drop small | medium | large aliases; keep t1 | t2 | t3 | t4.
  • Flex / Grid: unify gap (and columnGap / rowGap on Grid) to a numeric 1–17 scale mapped to --rs-space-1 through --rs-space-17; drop named aliases (extra-small | small | medium | large | extra-large). Values 1017 are newly accessible.
  • Share gap variants via a new shared/gap utility consumed by both Flex and Grid.
  • Update docs/V1-migration.md with per-prop migration maps and update internal consumers, demos, playground, and docs to the new scales.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
apsara Ready Ready Preview, Comment May 11, 2026 9:26am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR standardizes spacing and typography: introduces shared numeric gap utilities (1–17) and rewires Flex and Grid to use class-variant gap mappings. Text and Headline components drop deprecated sizes/weights in favor of narrowed tokens, with CSS and tests updated. Grid is refactored to class-based gaps and display variants. The apps and docs are migrated to numeric gaps and new Text/Headline props, including many playgrounds and examples.

Sequence Diagram(s)

(skip)

Possibly related issues

Suggested reviewers

  • paanSinghCoder
  • rsbh

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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/www/src/app/examples/page.tsx (2)

2513-2523: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix invalid Text size prop in custom zeroState.

Text no longer accepts numeric size values. Line 2517 uses size={2} which should be migrated to size='small'.

🐛 Proposed fix
                         <Text
-                          size={2}
+                          size='small'
                           style={{ color: 'var(--rs-color-text-subtle)' }}
                         >
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/www/src/app/examples/page.tsx` around lines 2513 - 2523, The Text
component in the zero-state UI is using a numeric size prop (size={2}) which is
invalid; update the JSX where Text is used (the secondary message Text element)
to use the new string token size='small' instead of size={2} so the component
renders with the correct small text styling.

1980-1984: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix invalid Text size prop.

Text no longer accepts numeric size values. The numeric scale (1–10) was removed in favor of named aliases.

🐛 Proposed fix
           <Text
-            size={10}
+            size='large'
             weight='medium'
             style={{ marginTop: '32px', marginBottom: '16px' }}
           >
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/www/src/app/examples/page.tsx` around lines 1980 - 1984, The Text
component is being passed a numeric size (size={10}) which is invalid now;
replace the numeric size prop on Text with the design-system named alias (for
example size="xl" or the appropriate alias your theme uses) in the Text JSX
where size={10} appears, update any similar occurrences, and run
TypeScript/linters to ensure the chosen alias matches the Text component's
allowed prop type.
🧹 Nitpick comments (3)
packages/raystack/shared/gap/gap.ts (1)

3-63: ⚡ Quick win

Reduce duplicated 1–17 mappings to avoid drift across gap variants.

The mappings are correct, but maintaining three hand-written scales in Line 3–Line 63 is brittle. A small generator keeps gap, column-gap, and row-gap guaranteed in sync.

♻️ Suggested refactor
 import styles from './gap.module.css';

+const gapScale = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] as const;
+export type GapValue = (typeof gapScale)[number];
+
+function createGapVariants(prefix: 'gap' | 'column-gap' | 'row-gap') {
+  return Object.fromEntries(
+    gapScale.map((value) => [value, styles[`${prefix}-${value}`]])
+  ) as Record<GapValue, string>;
+}
+
-export const gapVariants = {
-  1: styles['gap-1'],
-  ...
-  17: styles['gap-17']
-} as const;
+export const gapVariants = createGapVariants('gap');

-export const columnGapVariants = {
-  1: styles['column-gap-1'],
-  ...
-  17: styles['column-gap-17']
-} as const;
+export const columnGapVariants = createGapVariants('column-gap');

-export const rowGapVariants = {
-  1: styles['row-gap-1'],
-  ...
-  17: styles['row-gap-17']
-} as const;
+export const rowGapVariants = createGapVariants('row-gap');

-export type GapValue = keyof typeof gapVariants;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/raystack/shared/gap/gap.ts` around lines 3 - 63, The three
hand-written maps gapVariants, columnGapVariants, and rowGapVariants duplicate
the same 1–17 mapping and risk drifting; replace them by programmatically
generating each map (e.g., a small helper that iterates i from 1 to 17 and
assigns styles[`gap-${i}`], styles[`column-gap-${i}`], styles[`row-gap-${i}`])
so all scales stay in sync, then export the generated objects with the same
names (gapVariants, columnGapVariants, rowGapVariants) and keep GapValue defined
as keyof typeof gapVariants; ensure the generated objects are typed/returned as
const to preserve literal types.
apps/www/src/content/docs/components/grid/props.ts (1)

45-62: ⚡ Quick win

Extract the repeated spacing union into a shared type alias.

The 1 | ... | 17 union is duplicated three times. A single alias improves maintainability and keeps docs/types in sync.

Suggested refactor
 export interface GridProps {
+  // Consider hoisting this near the top-level exports
+  // export type GapScale = 1 | 2 | ... | 17;
+
   /**
    * Sets the gap between grid items.
    * Each step maps directly to `--rs-space-1` through `--rs-space-17`.
    */
-  gap?:
-    | 1
-    | 2
-    | 3
-    | 4
-    | 5
-    | 6
-    | 7
-    | 8
-    | 9
-    | 10
-    | 11
-    | 12
-    | 13
-    | 14
-    | 15
-    | 16
-    | 17;
+  gap?: GapScale;
@@
-  columnGap?:
-    | 1
-    | 2
-    | 3
-    | 4
-    | 5
-    | 6
-    | 7
-    | 8
-    | 9
-    | 10
-    | 11
-    | 12
-    | 13
-    | 14
-    | 15
-    | 16
-    | 17;
+  columnGap?: GapScale;
@@
-  rowGap?:
-    | 1
-    | 2
-    | 3
-    | 4
-    | 5
-    | 6
-    | 7
-    | 8
-    | 9
-    | 10
-    | 11
-    | 12
-    | 13
-    | 14
-    | 15
-    | 16
-    | 17;
+  rowGap?: GapScale;

Also applies to: 67-84, 89-106

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/www/src/content/docs/components/grid/props.ts` around lines 45 - 62,
Create a shared type alias (e.g., GridSpacing = 1 | 2 | ... | 17) and replace
each repeated numeric union for the gap properties with that alias; specifically
add the alias at the top of the file and update the three occurrences of the
verbose union (the gap? properties around the current blocks and the similar
unions at the other two locations referenced in the review) to use GridSpacing
instead, exporting the alias if these props are exported so consumers can
reference it.
packages/raystack/components/grid/__tests__/grid.test.tsx (1)

33-37: ⚡ Quick win

Assert base grid class in inline mode as well.

Inline mode should still include the base grid class; asserting both catches regressions where inline accidentally replaces base layout classing.

Proposed test hardening
     it('applies inline-grid class when inline is true', () => {
       const { container } = render(<Grid inline>Content</Grid>);
       const grid = container.firstChild as HTMLElement;
+      expect(grid).toHaveClass(styles.grid);
       expect(grid).toHaveClass(styles['grid-inline']);
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/raystack/components/grid/__tests__/grid.test.tsx` around lines 33 -
37, The test for Grid inline mode only asserts styles['grid-inline'] but should
also assert the base grid class is present; update the spec in
packages/raystack/components/grid/__tests__/grid.test.tsx to render <Grid
inline> and assert that the rendered element (grid) has both styles['grid'] and
styles['grid-inline'] (e.g., expect(grid).toHaveClass(styles['grid'],
styles['grid-inline'])), keeping the existing Grid component render and variable
names.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/www/src/content/docs/components/text/demo.ts`:
- Line 136: The example in the alignDemo uses both the Flex prop align="center"
and an inline style alignItems: "stretch", which conflict; update the alignDemo
snippet by removing the redundant alignment so intent is clear—either delete the
align="center" prop from the Flex component (to keep style={{ alignItems:
"stretch" }}) or remove alignItems: "stretch" from the style (to honor
align="center"); locate the Flex usage in the alignDemo and make one of these
two deletions so only a single alignment mechanism remains.

In `@docs/V1-migration.md`:
- Around line 1128-1148: The "After" example in the Headline migration still
uses deprecated aliases (size="large"/"medium"/"small"); update the example
instances to the new token names (size="t4", "t3", "t2") so it matches the text
and the new HeadlineProps['size'] contract, and confirm any adjacent prose or
examples no longer reference the removed aliases.

---

Outside diff comments:
In `@apps/www/src/app/examples/page.tsx`:
- Around line 2513-2523: The Text component in the zero-state UI is using a
numeric size prop (size={2}) which is invalid; update the JSX where Text is used
(the secondary message Text element) to use the new string token size='small'
instead of size={2} so the component renders with the correct small text
styling.
- Around line 1980-1984: The Text component is being passed a numeric size
(size={10}) which is invalid now; replace the numeric size prop on Text with the
design-system named alias (for example size="xl" or the appropriate alias your
theme uses) in the Text JSX where size={10} appears, update any similar
occurrences, and run TypeScript/linters to ensure the chosen alias matches the
Text component's allowed prop type.

---

Nitpick comments:
In `@apps/www/src/content/docs/components/grid/props.ts`:
- Around line 45-62: Create a shared type alias (e.g., GridSpacing = 1 | 2 | ...
| 17) and replace each repeated numeric union for the gap properties with that
alias; specifically add the alias at the top of the file and update the three
occurrences of the verbose union (the gap? properties around the current blocks
and the similar unions at the other two locations referenced in the review) to
use GridSpacing instead, exporting the alias if these props are exported so
consumers can reference it.

In `@packages/raystack/components/grid/__tests__/grid.test.tsx`:
- Around line 33-37: The test for Grid inline mode only asserts
styles['grid-inline'] but should also assert the base grid class is present;
update the spec in packages/raystack/components/grid/__tests__/grid.test.tsx to
render <Grid inline> and assert that the rendered element (grid) has both
styles['grid'] and styles['grid-inline'] (e.g.,
expect(grid).toHaveClass(styles['grid'], styles['grid-inline'])), keeping the
existing Grid component render and variable names.

In `@packages/raystack/shared/gap/gap.ts`:
- Around line 3-63: The three hand-written maps gapVariants, columnGapVariants,
and rowGapVariants duplicate the same 1–17 mapping and risk drifting; replace
them by programmatically generating each map (e.g., a small helper that iterates
i from 1 to 17 and assigns styles[`gap-${i}`], styles[`column-gap-${i}`],
styles[`row-gap-${i}`]) so all scales stay in sync, then export the generated
objects with the same names (gapVariants, columnGapVariants, rowGapVariants) and
keep GapValue defined as keyof typeof gapVariants; ensure the generated objects
are typed/returned as const to preserve literal types.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8b8634e3-48da-44fb-864b-c3ea8d197d7e

📥 Commits

Reviewing files that changed from the base of the PR and between 3056907 and f1bdf79.

📒 Files selected for processing (124)
  • apps/www/src/app/examples/datatable-virtual/page.tsx
  • apps/www/src/app/examples/datatable/page.tsx
  • apps/www/src/app/examples/dataview/page.tsx
  • apps/www/src/app/examples/page.tsx
  • apps/www/src/app/not-found.tsx
  • apps/www/src/components/playground/alert-dialog-examples.tsx
  • apps/www/src/components/playground/amount-examples.tsx
  • apps/www/src/components/playground/announcement-bar-examples.tsx
  • apps/www/src/components/playground/avatar-examples.tsx
  • apps/www/src/components/playground/badge-examples.tsx
  • apps/www/src/components/playground/breadcrumb-examples.tsx
  • apps/www/src/components/playground/button-examples.tsx
  • apps/www/src/components/playground/calendar-examples.tsx
  • apps/www/src/components/playground/callout-examples.tsx
  • apps/www/src/components/playground/checkbox-examples.tsx
  • apps/www/src/components/playground/chip-examples.tsx
  • apps/www/src/components/playground/code-block-examples.tsx
  • apps/www/src/components/playground/collapsible-examples.tsx
  • apps/www/src/components/playground/combobox-examples.tsx
  • apps/www/src/components/playground/command-examples.tsx
  • apps/www/src/components/playground/container-examples.tsx
  • apps/www/src/components/playground/context-menu-examples.tsx
  • apps/www/src/components/playground/dialog-examples.tsx
  • apps/www/src/components/playground/drawer-examples.tsx
  • apps/www/src/components/playground/field-examples.tsx
  • apps/www/src/components/playground/fieldset-examples.tsx
  • apps/www/src/components/playground/filter-chip-examples.tsx
  • apps/www/src/components/playground/flex-examples.tsx
  • apps/www/src/components/playground/floating-actions-examples.tsx
  • apps/www/src/components/playground/headline-examples.tsx
  • apps/www/src/components/playground/icon-button-examples.tsx
  • apps/www/src/components/playground/image-examples.tsx
  • apps/www/src/components/playground/indicator-examples.tsx
  • apps/www/src/components/playground/input-examples.tsx
  • apps/www/src/components/playground/label-examples.tsx
  • apps/www/src/components/playground/link-examples.tsx
  • apps/www/src/components/playground/menu-examples.tsx
  • apps/www/src/components/playground/menubar-examples.tsx
  • apps/www/src/components/playground/number-field-examples.tsx
  • apps/www/src/components/playground/popover-examples.tsx
  • apps/www/src/components/playground/preview-card-examples.tsx
  • apps/www/src/components/playground/radio-examples.tsx
  • apps/www/src/components/playground/search-examples.tsx
  • apps/www/src/components/playground/select-examples.tsx
  • apps/www/src/components/playground/separator-examples.tsx
  • apps/www/src/components/playground/sidebar-examples.tsx
  • apps/www/src/components/playground/skeleton-examples.tsx
  • apps/www/src/components/playground/slider-examples.tsx
  • apps/www/src/components/playground/spinner-examples.tsx
  • apps/www/src/components/playground/switch-examples.tsx
  • apps/www/src/components/playground/tabs-examples.tsx
  • apps/www/src/components/playground/text-area-examples.tsx
  • apps/www/src/components/playground/text-examples.tsx
  • apps/www/src/components/playground/toast-examples.tsx
  • apps/www/src/components/playground/toggle-examples.tsx
  • apps/www/src/components/playground/toolbar-examples.tsx
  • apps/www/src/components/playground/tooltip-examples.tsx
  • apps/www/src/content/docs/(overview)/getting-started.mdx
  • apps/www/src/content/docs/(overview)/styling.mdx
  • apps/www/src/content/docs/components/avatar/demo.ts
  • apps/www/src/content/docs/components/badge/demo.ts
  • apps/www/src/content/docs/components/breadcrumb/demo.ts
  • apps/www/src/content/docs/components/button/demo.ts
  • apps/www/src/content/docs/components/callout/demo.ts
  • apps/www/src/content/docs/components/checkbox/demo.ts
  • apps/www/src/content/docs/components/chip/demo.ts
  • apps/www/src/content/docs/components/combobox/demo.ts
  • apps/www/src/content/docs/components/copy-button/demo.ts
  • apps/www/src/content/docs/components/datatable/index.mdx
  • apps/www/src/content/docs/components/drawer/demo.ts
  • apps/www/src/content/docs/components/empty-state/demo.ts
  • apps/www/src/content/docs/components/flex/demo.ts
  • apps/www/src/content/docs/components/flex/props.ts
  • apps/www/src/content/docs/components/grid/demo.ts
  • apps/www/src/content/docs/components/grid/props.ts
  • apps/www/src/content/docs/components/headline/demo.ts
  • apps/www/src/content/docs/components/icon-button/demo.ts
  • apps/www/src/content/docs/components/image/demo.ts
  • apps/www/src/content/docs/components/indicator/demo.ts
  • apps/www/src/content/docs/components/input/demo.ts
  • apps/www/src/content/docs/components/label/demo.ts
  • apps/www/src/content/docs/components/link/demo.ts
  • apps/www/src/content/docs/components/meter/demo.ts
  • apps/www/src/content/docs/components/popover/demo.ts
  • apps/www/src/content/docs/components/preview-card/demo.ts
  • apps/www/src/content/docs/components/progress/demo.ts
  • apps/www/src/content/docs/components/radio/demo.ts
  • apps/www/src/content/docs/components/search/demo.ts
  • apps/www/src/content/docs/components/select/demo.ts
  • apps/www/src/content/docs/components/separator/demo.ts
  • apps/www/src/content/docs/components/sidebar/demo.ts
  • apps/www/src/content/docs/components/skeleton/demo.ts
  • apps/www/src/content/docs/components/slider/demo.ts
  • apps/www/src/content/docs/components/spinner/demo.ts
  • apps/www/src/content/docs/components/switch/demo.ts
  • apps/www/src/content/docs/components/tabs/demo.ts
  • apps/www/src/content/docs/components/text/demo.ts
  • apps/www/src/content/docs/components/textarea/demo.ts
  • apps/www/src/content/docs/components/toast/demo.ts
  • apps/www/src/content/docs/components/toggle/demo.ts
  • apps/www/src/content/docs/components/tooltip/demo.ts
  • docs/V1-migration.md
  • packages/raystack/components/announcement-bar/announcement-bar.tsx
  • packages/raystack/components/calendar/range-picker.tsx
  • packages/raystack/components/data-view-beta/components/grouping.tsx
  • packages/raystack/components/data-view-beta/components/ordering.tsx
  • packages/raystack/components/empty-state/empty-state.tsx
  • packages/raystack/components/filter-chip/filter-chip.tsx
  • packages/raystack/components/flex/__tests__/flex.test.tsx
  • packages/raystack/components/flex/flex.module.css
  • packages/raystack/components/flex/flex.tsx
  • packages/raystack/components/grid/__tests__/grid.test.tsx
  • packages/raystack/components/grid/grid.module.css
  • packages/raystack/components/grid/grid.tsx
  • packages/raystack/components/headline/__tests__/headline.test.tsx
  • packages/raystack/components/headline/headline.module.css
  • packages/raystack/components/headline/headline.tsx
  • packages/raystack/components/side-panel/side-panel.tsx
  • packages/raystack/components/text/__tests__/text.test.tsx
  • packages/raystack/components/text/text.module.css
  • packages/raystack/components/text/text.tsx
  • packages/raystack/shared/gap/gap.module.css
  • packages/raystack/shared/gap/gap.ts
  • packages/raystack/shared/gap/index.ts
💤 Files with no reviewable changes (3)
  • packages/raystack/components/headline/headline.module.css
  • packages/raystack/components/flex/flex.module.css
  • packages/raystack/components/text/text.module.css

Comment thread apps/www/src/content/docs/components/text/demo.ts
Comment thread docs/V1-migration.md
@rohanchkrabrty rohanchkrabrty merged commit cb1d0d5 into main May 11, 2026
5 checks passed
@rohanchkrabrty rohanchkrabrty deleted the feat-tokens-unification branch May 11, 2026 13:55
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.

2 participants