@hirobius/design-system 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/AGENTS.md +125 -0
  2. package/CHANGELOG.md +969 -0
  3. package/CONSUMING.md +27 -11
  4. package/DESIGN.md +28 -17
  5. package/MIGRATIONS.md +603 -0
  6. package/NOTICE.md +1 -1
  7. package/README.md +39 -5
  8. package/UPGRADING.md +222 -0
  9. package/codemods/hds-prefix.mjs +28 -13
  10. package/codemods/jsx-fold.mjs +28 -13
  11. package/codemods/lib/atomic-write.mjs +28 -0
  12. package/codemods/lib/installed-version.mjs +354 -0
  13. package/codemods/lib/project.mjs +395 -0
  14. package/codemods/lib/record.mjs +110 -0
  15. package/codemods/lib/scan.mjs +323 -0
  16. package/codemods/lib/semver.mjs +57 -0
  17. package/codemods/not-found-pattern.mjs +3 -3
  18. package/codemods/patterns-subpath.mjs +28 -12
  19. package/codemods/registry.mjs +67 -0
  20. package/codemods/tile-grid.mjs +3 -3
  21. package/codemods/upgrade.mjs +909 -0
  22. package/dist/chunks/empty-state-DNoThgfV.js +1227 -0
  23. package/dist/chunks/form-By82qZcC.js +66 -0
  24. package/dist/fonts/geist-mono-400.woff2 +0 -0
  25. package/dist/fonts/satoshi-400.woff2 +0 -0
  26. package/dist/fonts/satoshi-500.woff2 +0 -0
  27. package/dist/fonts/satoshi-700.woff2 +0 -0
  28. package/dist/fonts.css +53 -0
  29. package/dist/form.js +1 -1
  30. package/dist/hirobius-ui.js +876 -877
  31. package/dist/manifest.js +3 -3
  32. package/dist/patterns.js +189 -170
  33. package/dist/styles.css +2 -2
  34. package/dist/tokens.css +1 -1
  35. package/dist/tokens.js +136 -57
  36. package/dist/types/src/app/components/alert-dialog.d.ts +5 -0
  37. package/dist/types/src/app/components/alert.d.ts +1 -1
  38. package/dist/types/src/app/components/asset-img.d.ts +1 -0
  39. package/dist/types/src/app/components/avatar-group.d.ts +1 -0
  40. package/dist/types/src/app/components/avatar.d.ts +1 -1
  41. package/dist/types/src/app/components/badge.d.ts +2 -2
  42. package/dist/types/src/app/components/blockquote.d.ts +1 -0
  43. package/dist/types/src/app/components/breadcrumb.d.ts +1 -1
  44. package/dist/types/src/app/components/button.d.ts +3 -1
  45. package/dist/types/src/app/components/callout.d.ts +1 -1
  46. package/dist/types/src/app/components/card.d.ts +4 -3
  47. package/dist/types/src/app/components/checkbox.d.ts +1 -1
  48. package/dist/types/src/app/components/code-block.d.ts +1 -1
  49. package/dist/types/src/app/components/combobox.d.ts +1 -1
  50. package/dist/types/src/app/components/data-table-section.d.ts +1 -0
  51. package/dist/types/src/app/components/destructive-section.d.ts +1 -0
  52. package/dist/types/src/app/components/dialog.d.ts +2 -1
  53. package/dist/types/src/app/components/disclosure.d.ts +1 -1
  54. package/dist/types/src/app/components/divider.d.ts +1 -1
  55. package/dist/types/src/app/components/empty-state.d.ts +1 -1
  56. package/dist/types/src/app/components/error-pattern.d.ts +6 -1
  57. package/dist/types/src/app/components/field.d.ts +1 -1
  58. package/dist/types/src/app/components/form-actions.d.ts +1 -0
  59. package/dist/types/src/app/components/form-control.d.ts +10 -0
  60. package/dist/types/src/app/components/form.d.ts +1 -1
  61. package/dist/types/src/app/components/grid.d.ts +5 -0
  62. package/dist/types/src/app/components/hds-tooltip.d.ts +1 -1
  63. package/dist/types/src/app/components/icon.d.ts +1 -0
  64. package/dist/types/src/app/components/inline-link.d.ts +1 -1
  65. package/dist/types/src/app/components/input.d.ts +1 -1
  66. package/dist/types/src/app/components/kbd.d.ts +1 -0
  67. package/dist/types/src/app/components/menu.d.ts +1 -1
  68. package/dist/types/src/app/components/metadata-list.d.ts +1 -0
  69. package/dist/types/src/app/components/metric-tiles.d.ts +1 -0
  70. package/dist/types/src/app/components/pagination.d.ts +1 -1
  71. package/dist/types/src/app/components/popover.d.ts +1 -1
  72. package/dist/types/src/app/components/progress.d.ts +2 -2
  73. package/dist/types/src/app/components/radio.d.ts +1 -1
  74. package/dist/types/src/app/components/select.d.ts +1 -1
  75. package/dist/types/src/app/components/skeleton.d.ts +2 -2
  76. package/dist/types/src/app/components/slider.d.ts +1 -1
  77. package/dist/types/src/app/components/spinner.d.ts +1 -1
  78. package/dist/types/src/app/components/stat.d.ts +5 -4
  79. package/dist/types/src/app/components/status-list-item.d.ts +1 -1
  80. package/dist/types/src/app/components/status-tile.d.ts +4 -3
  81. package/dist/types/src/app/components/table.d.ts +6 -1
  82. package/dist/types/src/app/components/tabs.d.ts +1 -1
  83. package/dist/types/src/app/components/tag.d.ts +1 -1
  84. package/dist/types/src/app/components/text.d.ts +53 -6
  85. package/dist/types/src/app/components/textarea.d.ts +1 -1
  86. package/dist/types/src/app/components/timestamp.d.ts +1 -0
  87. package/dist/types/src/app/components/toast.d.ts +1 -1
  88. package/dist/types/src/app/components/toggle.d.ts +1 -1
  89. package/dist/types/src/app/data/manifest-types.d.ts +4 -0
  90. package/dist/types/src/app/design-system/generated-token-refs.d.ts +37 -28
  91. package/dist/types/src/app/design-system/generated-token-values.d.ts +3 -0
  92. package/dist/types/src/app/design-system/tokens.d.ts +117 -15
  93. package/dist/types/src/index.d.ts +122 -72
  94. package/dist/variables.css +41 -33
  95. package/docs/CONSUMING.md +63 -39
  96. package/hirobius.tokens.json +163 -112
  97. package/llms.txt +158 -50
  98. package/mcp/catalog.mjs +369 -0
  99. package/mcp/core-set.mjs +66 -0
  100. package/mcp/guide.mjs +272 -0
  101. package/mcp/hds-mcp.mjs +49 -0
  102. package/mcp/server.mjs +94 -0
  103. package/package.json +53 -11
  104. package/public/hds-manifest.json +430 -336
  105. package/public/llms/components.txt +4 -3
  106. package/public/llms/layout.txt +1 -1
  107. package/public/llms-full.txt +190 -70
  108. package/public/llms.txt +158 -50
  109. package/scripts/eslint-plugin-hds/index.d.mts +29 -0
  110. package/scripts/eslint-plugin-hds/index.mjs +55 -0
  111. package/scripts/eslint-plugin-hds/package.json +30 -0
  112. package/scripts/eslint-plugin-hds/rules/no-raw-controls.mjs +47 -0
  113. package/scripts/eslint-plugin-hds/rules/no-raw-hex.mjs +70 -0
  114. package/scripts/eslint-plugin-hds/rules/no-raw-px-spacing.mjs +125 -0
  115. package/scripts/eslint-plugin-hds/rules/prefer-hds-layout-primitive.mjs +54 -0
  116. package/scripts/eslint-plugin-hds/rules/sx-token-first.mjs +111 -0
  117. package/scripts/eslint-plugin-hds/rules/utils.mjs +66 -0
  118. package/src/app/data/component-api.json +154 -93
  119. package/upgrade/index.json +208 -0
  120. package/upgrade/releases/0.17.0.json +962 -0
  121. package/upgrade/releases/0.18.0.json +8 -0
  122. package/upgrade/releases/0.19.0.json +233 -0
  123. package/upgrade/releases/0.19.1.json +8 -0
  124. package/upgrade/releases/0.20.0.json +5108 -0
  125. package/upgrade/releases/0.21.0.json +538 -0
  126. package/upgrade/releases/0.22.0.json +94 -0
  127. package/upgrade/schema.json +989 -0
  128. package/dist/chunks/empty-state-BBqhCx0S.js +0 -1217
  129. package/dist/chunks/form-COP3vK9_.js +0 -66
  130. package/dist/types/src/app/components/status-dot.d.ts +0 -39
@@ -0,0 +1,54 @@
1
+ /**
2
+ * hds/prefer-hds-layout-primitive
3
+ *
4
+ * Warns (never errors) on ad-hoc `display: 'flex' | 'grid'` inside an
5
+ * inline `style={{ ... }}` object, where a named HDS layout primitive
6
+ * (Stack for flex, Grid for grid — see src/app/components/box.tsx's
7
+ * "reach for Stack/Grid/Container first" guidance) likely fits better than
8
+ * a one-off flex/grid container. Intentionally a warning: ad-hoc flex is
9
+ * sometimes the right call (e.g. deeply nested one-off alignment), so this
10
+ * nudges rather than blocks.
11
+ */
12
+ import { attrName, jsxObjectExpression, propName, stringLiteralValue } from './utils.mjs';
13
+
14
+ const FLEX_GRID_RE = /^(?:inline-)?(flex|grid)$/;
15
+
16
+ export default {
17
+ meta: {
18
+ type: 'suggestion',
19
+ docs: {
20
+ description:
21
+ 'Warn on ad-hoc display:flex/grid in inline style where a named HDS layout primitive (Stack/Grid) likely fits.',
22
+ recommended: true,
23
+ url: 'https://github.com/hirobius/hds/blob/main/scripts/eslint-plugin-hds/README.md#hdsprefer-hds-layout-primitive',
24
+ },
25
+ schema: [],
26
+ messages: {
27
+ preferPrimitive:
28
+ 'Ad-hoc "display: {{display}}" in inline style — consider the named HDS layout primitive (Stack for flex, Grid for grid) instead of a one-off flex/grid container.',
29
+ },
30
+ },
31
+ create(context) {
32
+ return {
33
+ JSXAttribute(node) {
34
+ if (attrName(node) !== 'style') return;
35
+ const obj = jsxObjectExpression(node.value);
36
+ if (!obj) return;
37
+
38
+ const displayProp = obj.properties.find(
39
+ (p) => p.type === 'Property' && propName(p.key) === 'display',
40
+ );
41
+ if (!displayProp) return;
42
+
43
+ const value = stringLiteralValue(displayProp.value);
44
+ if (value != null && FLEX_GRID_RE.test(value)) {
45
+ context.report({
46
+ node: displayProp.value,
47
+ messageId: 'preferPrimitive',
48
+ data: { display: value },
49
+ });
50
+ }
51
+ },
52
+ };
53
+ },
54
+ };
@@ -0,0 +1,111 @@
1
+ /**
2
+ * hds/sx-token-first
3
+ *
4
+ * Errors on raw hex colors or raw px strings inside a `sx={{ ... }}` prop
5
+ * (Box's token-first layout engine — src/app/components/box.tsx). `sx` is
6
+ * the sanctioned escape hatch specifically because it forces spacing/color
7
+ * through HDS tokens. The spacing shorthands (`p`, `m`, `gap`, ...) take the
8
+ * t-shirt scale by name ('xs' | 'sm' | 'md' | 'lg' | 'xl', hds#206), and the
9
+ * fix this rule offers on them points there. No other key resolves those names
10
+ * (`width: 'md'` is invalid CSS), so a px string anywhere else is pointed at a
11
+ * token (`hds.space.*` or a `var(--...)`). Bare numbers still resolve off the
12
+ * 4px space scale (`p: 4` is 16px), so this rule does NOT flag them — only
13
+ * values that prove the author reached past the token system (hex strings,
14
+ * explicit 'Npx' strings). Nested objects (responsive `{ xs, sm, ... }` and
15
+ * `&`-selector blocks) are walked recursively since sx supports both; a value
16
+ * in a responsive map is reported against the key the map sits on.
17
+ */
18
+ import { attrName, jsxObjectExpression, propName, stringLiteralValue } from './utils.mjs';
19
+
20
+ const HEX_RE = /#[0-9a-fA-F]{3,4}\b|#[0-9a-fA-F]{6}\b|#[0-9a-fA-F]{8}\b/;
21
+ const PX_STRING_RE = /-?\d+(?:\.\d+)?px/;
22
+
23
+ // The Box sx keys whose values go through the spacing resolver, the only
24
+ // keys that take the t-shirt names (box-sx.ts SPACING_PROP_MAP).
25
+ const SPACING_KEYS = new Set([
26
+ 'm',
27
+ 'mt',
28
+ 'mr',
29
+ 'mb',
30
+ 'ml',
31
+ 'mx',
32
+ 'my',
33
+ 'p',
34
+ 'pt',
35
+ 'pr',
36
+ 'pb',
37
+ 'pl',
38
+ 'px',
39
+ 'py',
40
+ 'gap',
41
+ 'rowGap',
42
+ 'columnGap',
43
+ ]);
44
+
45
+ export default {
46
+ meta: {
47
+ type: 'problem',
48
+ docs: {
49
+ description:
50
+ 'Disallow raw hex/px string values inside Box sx — sx must resolve colors and spacing through HDS token keys.',
51
+ recommended: true,
52
+ url: 'https://github.com/hirobius/hds/blob/main/scripts/eslint-plugin-hds/README.md#hdssx-token-first',
53
+ },
54
+ schema: [],
55
+ messages: {
56
+ rawHexInSx:
57
+ 'Raw hex color "{{value}}" in sx prop "{{prop}}" bypasses HDS color tokens. Use a dotted token key (e.g. "content.primary", "surface.raised", "accent").',
58
+ rawPxInSx:
59
+ 'Raw px string "{{value}}" in sx prop "{{prop}}" bypasses the HDS spacing scale. Use a t-shirt step: "xs" | "sm" | "md" | "lg" | "xl" (8/16/24/32/48px at comfortable density; compact tightens them).',
60
+ rawPxInSxNonSpacing:
61
+ 'Raw px string "{{value}}" in sx prop "{{prop}}" bypasses HDS tokens. Use a token: an hds.space.* value or a var(--...) such as "var(--primitive-space-4)". Spacing step names apply to the spacing props (p, m, gap, ...) only.',
62
+ },
63
+ },
64
+ create(context) {
65
+ /**
66
+ * @param objExpr an sx object, an `&`-selector block, or a responsive map
67
+ * @param mapKey the key a responsive map sits on (null for an sx object or
68
+ * an `&` block, whose keys are real sx keys)
69
+ */
70
+ function walk(objExpr, mapKey = null) {
71
+ for (const prop of objExpr.properties) {
72
+ if (prop.type !== 'Property') continue; // skip SpreadElement
73
+ const name = propName(prop.key) ?? '?';
74
+
75
+ if (prop.value.type === 'ObjectExpression') {
76
+ // '&'-selector nesting holds sx keys again; anything else is a
77
+ // responsive { xs, sm, ... } map on this key.
78
+ walk(prop.value, name.startsWith('&') ? null : (mapKey ?? name));
79
+ continue;
80
+ }
81
+
82
+ const value = stringLiteralValue(prop.value);
83
+ if (value == null) continue;
84
+ const key = mapKey ?? name;
85
+
86
+ if (HEX_RE.test(value)) {
87
+ context.report({
88
+ node: prop.value,
89
+ messageId: 'rawHexInSx',
90
+ data: { value, prop: key },
91
+ });
92
+ } else if (PX_STRING_RE.test(value)) {
93
+ context.report({
94
+ node: prop.value,
95
+ messageId: SPACING_KEYS.has(key) ? 'rawPxInSx' : 'rawPxInSxNonSpacing',
96
+ data: { value, prop: key },
97
+ });
98
+ }
99
+ }
100
+ }
101
+
102
+ return {
103
+ JSXAttribute(node) {
104
+ if (attrName(node) !== 'sx') return;
105
+ const obj = jsxObjectExpression(node.value);
106
+ if (!obj) return;
107
+ walk(obj);
108
+ },
109
+ };
110
+ },
111
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Shared AST helpers for the HDS ESLint rules. Deliberately AST-based (not
3
+ * regex-over-source-text like the repo's internal scripts/check-*.mjs
4
+ * guardrails) because this plugin runs inside consumers' own ESLint configs
5
+ * against arbitrary TSX, where a plain parser is already available and gives
6
+ * us exact node types for free.
7
+ */
8
+
9
+ /** Resolve a JSXAttribute's name, e.g. `style` / `className` / `sx`. */
10
+ export function attrName(node) {
11
+ return node.name && node.name.type === 'JSXIdentifier' ? node.name.name : null;
12
+ }
13
+
14
+ /** Resolve an ObjectExpression Property key to a plain string, or null. */
15
+ export function propName(key) {
16
+ if (!key) return null;
17
+ if (key.type === 'Identifier') return key.name;
18
+ if (key.type === 'Literal' && typeof key.value === 'string') return key.value;
19
+ return null;
20
+ }
21
+
22
+ /**
23
+ * Resolve a JSXAttribute's `{ ... }` expression to the ObjectExpression it
24
+ * wraps, e.g. `style={{ margin: 0 }}` -> the `{ margin: 0 }` ObjectExpression.
25
+ * Returns null for anything else (identifiers, spreads-only, conditional
26
+ * expressions, etc.) — this plugin only understands literal object props.
27
+ */
28
+ export function jsxObjectExpression(attrValueNode) {
29
+ if (!attrValueNode || attrValueNode.type !== 'JSXExpressionContainer') return null;
30
+ const expr = attrValueNode.expression;
31
+ return expr && expr.type === 'ObjectExpression' ? expr : null;
32
+ }
33
+
34
+ /**
35
+ * Resolve a plain string literal value from a node — covers `'x'`/`"x"` and
36
+ * zero-interpolation template literals (`` `x` ``). Returns null for
37
+ * anything computed (identifiers, member expressions, interpolated
38
+ * templates) — this plugin only flags values it can prove are raw.
39
+ */
40
+ export function stringLiteralValue(node) {
41
+ if (!node) return null;
42
+ if (node.type === 'Literal' && typeof node.value === 'string') return node.value;
43
+ if (node.type === 'TemplateLiteral' && node.expressions.length === 0) {
44
+ return node.quasis.map((q) => q.value.cooked ?? '').join('');
45
+ }
46
+ return null;
47
+ }
48
+
49
+ /**
50
+ * Resolve a numeric literal value from a node, including unary-minus
51
+ * (`-8`), which the estree parser represents as UnaryExpression, not a
52
+ * negative Literal. Returns null for anything else.
53
+ */
54
+ export function numberLiteralValue(node) {
55
+ if (!node) return null;
56
+ if (node.type === 'Literal' && typeof node.value === 'number') return node.value;
57
+ if (
58
+ node.type === 'UnaryExpression' &&
59
+ node.operator === '-' &&
60
+ node.argument.type === 'Literal' &&
61
+ typeof node.argument.value === 'number'
62
+ ) {
63
+ return -node.argument.value;
64
+ }
65
+ return null;
66
+ }