@astryxdesign/core 0.1.0 → 0.1.1-canary.129bf0e

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 (155) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +68 -0
  3. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  4. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  5. package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
  6. package/dist/Banner/Banner.d.ts +7 -0
  7. package/dist/Banner/Banner.d.ts.map +1 -1
  8. package/dist/Banner/Banner.js +9 -2
  9. package/dist/Button/Button.d.ts.map +1 -1
  10. package/dist/Button/Button.js +2 -0
  11. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  12. package/dist/Chat/ChatLayoutScrollButton.js +5 -1
  13. package/dist/ContextMenu/ContextMenu.js +2 -2
  14. package/dist/DropdownMenu/DropdownMenu.js +2 -2
  15. package/dist/DropdownMenu/{renderXDSDropdownItems.d.ts → renderDropdownItems.d.ts} +3 -3
  16. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -0
  17. package/dist/DropdownMenu/{renderXDSDropdownItems.js → renderDropdownItems.js} +2 -2
  18. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  19. package/dist/EmptyState/EmptyState.js +7 -1
  20. package/dist/HoverCard/HoverCard.d.ts +2 -2
  21. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  22. package/dist/HoverCard/HoverCard.js +18 -6
  23. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  24. package/dist/HoverCard/useHoverCard.js +6 -3
  25. package/dist/Layer/useLayer.d.ts +13 -0
  26. package/dist/Layer/useLayer.d.ts.map +1 -1
  27. package/dist/Layer/useLayer.js +7 -2
  28. package/dist/Layout/Layout.d.ts +10 -1
  29. package/dist/Layout/Layout.d.ts.map +1 -1
  30. package/dist/Layout/Layout.js +5 -1
  31. package/dist/Markdown/Markdown.d.ts.map +1 -1
  32. package/dist/Markdown/Markdown.js +13 -3
  33. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  34. package/dist/MobileNav/MobileNav.js +13 -0
  35. package/dist/Outline/Outline.d.ts +3 -2
  36. package/dist/Outline/Outline.d.ts.map +1 -1
  37. package/dist/Outline/Outline.js +23 -4
  38. package/dist/Outline/useScrollSpy.d.ts +14 -1
  39. package/dist/Outline/useScrollSpy.d.ts.map +1 -1
  40. package/dist/Outline/useScrollSpy.js +161 -50
  41. package/dist/Pagination/Pagination.d.ts.map +1 -1
  42. package/dist/Pagination/Pagination.js +31 -27
  43. package/dist/Resizable/useResizable.d.ts.map +1 -1
  44. package/dist/Resizable/useResizable.js +1 -5
  45. package/dist/Selector/Selector.d.ts.map +1 -1
  46. package/dist/Selector/Selector.js +1 -1
  47. package/dist/Table/BaseTable.d.ts.map +1 -1
  48. package/dist/Table/BaseTable.js +26 -8
  49. package/dist/Table/Table.d.ts.map +1 -1
  50. package/dist/Table/Table.js +30 -7
  51. package/dist/Table/index.d.ts +3 -1
  52. package/dist/Table/index.d.ts.map +1 -1
  53. package/dist/Table/index.js +1 -0
  54. package/dist/Table/plugins/stickyColumns/index.d.ts +3 -0
  55. package/dist/Table/plugins/stickyColumns/index.d.ts.map +1 -0
  56. package/dist/Table/plugins/stickyColumns/index.js +3 -0
  57. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts +25 -0
  58. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -0
  59. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +376 -0
  60. package/dist/Table/types.d.ts +90 -5
  61. package/dist/Table/types.d.ts.map +1 -1
  62. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  63. package/dist/Table/useBaseTablePlugins.js +1 -1
  64. package/dist/ToggleButton/ToggleButton.d.ts +10 -3
  65. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  66. package/dist/ToggleButton/ToggleButton.js +64 -18
  67. package/dist/astryx.css +11 -0
  68. package/dist/astryx.umd.js +147 -0
  69. package/dist/astryx.umd.js.map +7 -0
  70. package/dist/theme/Theme.js +1 -1
  71. package/dist/theme/defineTheme.d.ts +1 -1
  72. package/dist/theme/defineTheme.d.ts.map +1 -1
  73. package/dist/theme/defineTheme.js +1 -1
  74. package/dist/theme/index.d.ts +1 -1
  75. package/dist/theme/index.d.ts.map +1 -1
  76. package/dist/theme/index.js +1 -1
  77. package/dist/theme/syntax/defineSyntaxTheme.js +1 -1
  78. package/dist/theme/tokens.d.ts +1 -1
  79. package/dist/theme/tokens.js +4 -4
  80. package/dist/theme/useTheme.d.ts +2 -2
  81. package/dist/utils/dateParser.d.ts.map +1 -1
  82. package/dist/utils/dateParser.js +15 -2
  83. package/package.json +7 -3
  84. package/src/AvatarGroup/AvatarGroupOverflow.tsx +3 -0
  85. package/src/Banner/Banner.test.tsx +16 -7
  86. package/src/Banner/Banner.tsx +9 -2
  87. package/src/Button/Button.test.tsx +26 -11
  88. package/src/Button/Button.tsx +2 -0
  89. package/src/Chat/ChatLayoutScrollButton.tsx +7 -1
  90. package/src/Collapsible/useCollapsible.doc.mjs +2 -2
  91. package/src/ContextMenu/ContextMenu.tsx +2 -2
  92. package/src/DateInput/DateInput.test.tsx +68 -20
  93. package/src/Divider/Divider.doc.mjs +1 -1
  94. package/src/DropdownMenu/DropdownMenu.tsx +2 -2
  95. package/src/DropdownMenu/{renderXDSDropdownItems.tsx → renderDropdownItems.tsx} +2 -2
  96. package/src/EmptyState/EmptyState.test.tsx +4 -2
  97. package/src/EmptyState/EmptyState.tsx +6 -2
  98. package/src/FormLayout/FormLayout.doc.mjs +3 -3
  99. package/src/HoverCard/HoverCard.doc.mjs +3 -0
  100. package/src/HoverCard/HoverCard.test.tsx +178 -2
  101. package/src/HoverCard/HoverCard.tsx +20 -16
  102. package/src/HoverCard/useHoverCard.tsx +12 -10
  103. package/src/Icon/Icon.doc.mjs +4 -4
  104. package/src/Item/Item.doc.mjs +2 -2
  105. package/src/Layer/useLayer.doc.mjs +7 -2
  106. package/src/Layer/useLayer.tsx +19 -2
  107. package/src/Layout/Layout.doc.mjs +2 -1
  108. package/src/Layout/Layout.tsx +15 -1
  109. package/src/Layout/__tests__/childrenAsContent.test.tsx +59 -0
  110. package/src/Lightbox/Lightbox.doc.mjs +0 -2
  111. package/src/Link/Link.doc.mjs +3 -3
  112. package/src/Link/LinkProvider.doc.mjs +3 -3
  113. package/src/Markdown/Markdown.doc.mjs +6 -4
  114. package/src/Markdown/Markdown.test.tsx +17 -26
  115. package/src/Markdown/Markdown.tsx +16 -6
  116. package/src/MobileNav/MobileNav.doc.mjs +8 -8
  117. package/src/MobileNav/MobileNav.tsx +13 -0
  118. package/src/MobileNav/MobileNavReopen.test.tsx +118 -0
  119. package/src/Outline/Outline.doc.mjs +1 -1
  120. package/src/Outline/Outline.test.tsx +76 -38
  121. package/src/Outline/Outline.tsx +23 -4
  122. package/src/Outline/useScrollSpy.ts +196 -63
  123. package/src/Pagination/Pagination.test.tsx +137 -13
  124. package/src/Pagination/Pagination.tsx +33 -28
  125. package/src/Resizable/Resizable.doc.mjs +3 -3
  126. package/src/Resizable/useResizable.ts +1 -7
  127. package/src/Selector/Selector.doc.mjs +4 -0
  128. package/src/Selector/Selector.tsx +5 -6
  129. package/src/Skeleton/Skeleton.doc.mjs +11 -1
  130. package/src/Table/BaseTable.tsx +50 -24
  131. package/src/Table/Table.doc.mjs +3 -3
  132. package/src/Table/Table.tsx +22 -1
  133. package/src/Table/index.ts +3 -0
  134. package/src/Table/plugins/stickyColumns/index.ts +4 -0
  135. package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +163 -0
  136. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +414 -0
  137. package/src/Table/types.ts +96 -4
  138. package/src/Table/useBaseTablePlugins.ts +1 -0
  139. package/src/ToggleButton/ToggleButton.doc.mjs +2 -2
  140. package/src/ToggleButton/ToggleButton.test.tsx +148 -6
  141. package/src/ToggleButton/ToggleButton.tsx +83 -20
  142. package/src/Toolbar/Toolbar.doc.mjs +1 -1
  143. package/src/hooks/useEntryAnimation.doc.mjs +3 -3
  144. package/src/hooks/useMediaQuery.doc.mjs +2 -2
  145. package/src/hooks/useStreamingText.doc.mjs +3 -3
  146. package/src/theme/Theme.doc.mjs +2 -2
  147. package/src/theme/Theme.tsx +1 -1
  148. package/src/theme/defineTheme.ts +1 -1
  149. package/src/theme/index.ts +1 -1
  150. package/src/theme/syntax/defineSyntaxTheme.ts +1 -1
  151. package/src/theme/tokens.ts +4 -4
  152. package/src/theme/useTheme.ts +2 -2
  153. package/src/utils/dateParser.test.ts +26 -0
  154. package/src/utils/dateParser.ts +16 -2
  155. package/dist/DropdownMenu/renderXDSDropdownItems.d.ts.map +0 -1
@@ -115,7 +115,7 @@ function useThemeStyleInjection(theme) {
115
115
  // One-time perf hint per theme
116
116
  if (!warnedThemes.has(theme.name)) {
117
117
  warnedThemes.add(theme.name);
118
- console.warn(`[XDS] Theme "${theme.name}" is using runtime style injection. ` + `For better performance, use the pre-built theme:\n\n` + ` import {${theme.name}Theme} from '@astryxdesign/theme-${theme.name}/built';\n` + ` import '@astryxdesign/theme-${theme.name}/theme.css';\n\n` + `For custom themes, run \`npx astryx theme build <file>\` to generate ` + `the built artifacts.`);
118
+ console.warn(`[Astryx] Theme "${theme.name}" is using runtime style injection. ` + `For better performance, use the pre-built theme:\n\n` + ` import {${theme.name}Theme} from '@astryxdesign/theme-${theme.name}/built';\n` + ` import '@astryxdesign/theme-${theme.name}/theme.css';\n\n` + `For custom themes, run \`npx astryx theme build <file>\` to generate ` + `the built artifacts.`);
119
119
  }
120
120
  const {
121
121
  prose,
@@ -296,7 +296,7 @@ export interface DefinedTheme {
296
296
  __onLight?: ResolvedOnMedia;
297
297
  }
298
298
  /** All Astryx token defaults as a flat map. Useful for resolving full token sets. */
299
- export declare const xdsTokenDefaults: Record<string, string>;
299
+ export declare const tokenDefaults: Record<string, string>;
300
300
  /**
301
301
  * Create an Astryx theme.
302
302
  *
@@ -1 +1 @@
1
- {"version":3,"file":"defineTheme.d.ts","sourceRoot":"","sources":["../../src/theme/defineTheme.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"defineTheme.d.ts","sourceRoot":"","sources":["../../src/theme/defineTheme.ts"],"names":[],"mappings":"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"}
@@ -115,7 +115,7 @@ import { domainTokenDefaults } from "./domainTokens/index.js";
115
115
  // =============================================================================
116
116
 
117
117
  /** All Astryx token defaults as a flat map. Useful for resolving full token sets. */
118
- export const xdsTokenDefaults = {
118
+ export const tokenDefaults = {
119
119
  ...colorDefaults,
120
120
  ...spacingDefaults,
121
121
  ...sizeDefaults,
@@ -13,7 +13,7 @@
13
13
  export { Theme } from './Theme';
14
14
  export { MediaTheme } from './MediaTheme';
15
15
  export type { MediaThemeProps } from './MediaTheme';
16
- export { defineTheme, generateThemeCSS, generateThemeCSSFlat, generateOnMediaCSS, generateThemeRules, generateThemeRulesSplit, type ThemeCSSOutput, type ThemeRulesSplit, isDefinedTheme, xdsTokenDefaults, } from './defineTheme';
16
+ export { defineTheme, generateThemeCSS, generateThemeCSSFlat, generateOnMediaCSS, generateThemeRules, generateThemeRulesSplit, type ThemeCSSOutput, type ThemeRulesSplit, isDefinedTheme, tokenDefaults, } from './defineTheme';
17
17
  export type { DefineThemeInput, DefinedTheme, CoreTokenName, TokenName, TokenValue, ComponentStyleMap, StyleOverrides, } from './defineTheme';
18
18
  export type { SyntaxTokenName, DomainTokenName, DataTokenName, } from './domainTokens';
19
19
  export { syntaxTokenDefaults, domainTokenDefaults, dataTokenDefaults, } from './domainTokens';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@
16
16
  */
17
17
  export { Theme } from "./Theme.js";
18
18
  export { MediaTheme } from "./MediaTheme.js";
19
- export { defineTheme, generateThemeCSS, generateThemeCSSFlat, generateOnMediaCSS, generateThemeRules, generateThemeRulesSplit, isDefinedTheme, xdsTokenDefaults } from "./defineTheme.js";
19
+ export { defineTheme, generateThemeCSS, generateThemeCSSFlat, generateOnMediaCSS, generateThemeRules, generateThemeRulesSplit, isDefinedTheme, tokenDefaults } from "./defineTheme.js";
20
20
  export { syntaxTokenDefaults, domainTokenDefaults, dataTokenDefaults } from "./domainTokens/index.js";
21
21
 
22
22
  // Syntax theme API
@@ -97,7 +97,7 @@ export function resolveSyntaxTokenForMode(value, mode) {
97
97
  export function defineSyntaxTheme(input) {
98
98
  const missing = ALL_SYNTAX_KEYS.filter(key => !(key in input.tokens));
99
99
  if (missing.length > 0) {
100
- console.warn('[XDS] defineSyntaxTheme("' + input.name + '"): missing tokens: ' + missing.join(', ') + '. All 14 syntax tokens are required.');
100
+ console.warn('[Astryx] defineSyntaxTheme("' + input.name + '"): missing tokens: ' + missing.join(', ') + '. All 14 syntax tokens are required.');
101
101
  }
102
102
 
103
103
  // Resolve tuples to light-dark() CSS strings
@@ -48,7 +48,7 @@ export declare const tokenVars: Record<TokenName, string>;
48
48
  /**
49
49
  * Resolve all Astryx token values for a theme and effective color mode.
50
50
  *
51
- * The result starts with `xdsTokenDefaults`, applies `theme.tokens`, then
51
+ * The result starts with `tokenDefaults`, applies `theme.tokens`, then
52
52
  * reapplies `theme.__inputTokens` when available so explicit tuple overrides
53
53
  * retain their original light/dark sides instead of relying on CSS parsing.
54
54
  * This mirrors the token resolution used by `useTheme()` but does not need
@@ -15,7 +15,7 @@
15
15
  * - /packages/core/src/theme/index.ts
16
16
  */
17
17
 
18
- import { xdsTokenDefaults } from "./defineTheme.js";
18
+ import { tokenDefaults } from "./defineTheme.js";
19
19
 
20
20
  /** Resolved color mode used when choosing the side of light/dark token values. */
21
21
 
@@ -45,7 +45,7 @@ export function tokenVar(name) {
45
45
  }
46
46
 
47
47
  /** Flat map of every known Astryx token name to its `var(--token-name)` reference. */
48
- export const tokenVars = Object.fromEntries(Object.keys(xdsTokenDefaults).map(name => [name, tokenVar(name)]));
48
+ export const tokenVars = Object.fromEntries(Object.keys(tokenDefaults).map(name => [name, tokenVar(name)]));
49
49
 
50
50
  /**
51
51
  * Split the arguments of a CSS function body on the first top-level comma.
@@ -118,7 +118,7 @@ function resolveXDSTokenValue(value, mode) {
118
118
  /**
119
119
  * Resolve all Astryx token values for a theme and effective color mode.
120
120
  *
121
- * The result starts with `xdsTokenDefaults`, applies `theme.tokens`, then
121
+ * The result starts with `tokenDefaults`, applies `theme.tokens`, then
122
122
  * reapplies `theme.__inputTokens` when available so explicit tuple overrides
123
123
  * retain their original light/dark sides instead of relying on CSS parsing.
124
124
  * This mirrors the token resolution used by `useTheme()` but does not need
@@ -131,7 +131,7 @@ export function resolveThemeTokens(theme, options) {
131
131
  mode
132
132
  } = options;
133
133
  const resolved = {};
134
- for (const [key, value] of Object.entries(xdsTokenDefaults)) {
134
+ for (const [key, value] of Object.entries(tokenDefaults)) {
135
135
  resolved[key] = resolveXDSTokenValue(value, mode);
136
136
  }
137
137
  if (theme == null) {
@@ -30,7 +30,7 @@ export interface UseThemeReturn {
30
30
  * For tokens with [light, dark] tuples, returns the value matching
31
31
  * the current mode. For single-value tokens, returns the value as-is.
32
32
  *
33
- * Falls back to xdsTokenDefaults if the token isn't overridden by the theme.
33
+ * Falls back to tokenDefaults if the token isn't overridden by the theme.
34
34
  *
35
35
  * @example
36
36
  * ```
@@ -42,7 +42,7 @@ export interface UseThemeReturn {
42
42
  /**
43
43
  * All tokens resolved for the current color mode.
44
44
  *
45
- * Merges xdsTokenDefaults with the theme's overrides, resolving
45
+ * Merges tokenDefaults with the theme's overrides, resolving
46
46
  * light-dark() values based on the effective color mode.
47
47
  *
48
48
  * Memoized — stable reference unless theme or mode changes.
@@ -1 +1 @@
1
- {"version":3,"file":"dateParser.d.ts","sourceRoot":"","sources":["../../src/utils/dateParser.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAqC,MAAM,aAAa,CAAC;AAE/E,OAAO,EACL,gBAAgB,IAAI,QAAQ,EAC5B,cAAc,IAAI,SAAS,GAC5B,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAK1C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAwF9D"}
1
+ {"version":3,"file":"dateParser.d.ts","sourceRoot":"","sources":["../../src/utils/dateParser.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAqC,MAAM,aAAa,CAAC;AAE/E,OAAO,EACL,gBAAgB,IAAI,QAAQ,EAC5B,cAAc,IAAI,SAAS,GAC5B,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAK1C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAsG9D"}
@@ -112,10 +112,23 @@ export function parseDateInput(input) {
112
112
  return parseNumericDate(+first, +second, currentYear);
113
113
  }
114
114
 
115
- // 6. Fall back to native Date parsing for other formats
115
+ // 6. Fall back to native Date parsing for other formats.
116
+ //
117
+ // Skip bare numeric input (e.g. "0", "1", "01", "2026"). These are
118
+ // in-progress values a user is still typing, not complete dates. Native
119
+ // `Date` parsing coerces them into arbitrary dates ("0" -> year 2000 in V8,
120
+ // year 0 in some engines), which is both surprising and — when the year
121
+ // resolves to 0 — produces an out-of-range date that throws downstream.
122
+ // Treat them as not-yet-a-valid-date instead.
123
+ if (/^\d+$/.test(trimmed)) {
124
+ return null;
125
+ }
116
126
  const parsed = new Date(trimmed);
117
127
  if (!isNaN(parsed.getTime())) {
118
- return plainDateFromDate(parsed);
128
+ const fromDate = plainDateFromDate(parsed);
129
+ // Validate the result so we never return an out-of-range date (e.g. a
130
+ // year of 0), which would throw when later re-parsed.
131
+ return tryCreatePlainDate(fromDate.year, fromDate.month, fromDate.day);
119
132
  }
120
133
  return null;
121
134
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1-canary.129bf0e",
4
4
  "displayName": "XDS Core",
5
5
  "description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
6
6
  "author": "Meta Open Source",
@@ -15,7 +15,7 @@
15
15
  "url": "https://github.com/facebook/astryx/issues"
16
16
  },
17
17
  "keywords": [
18
- "xds",
18
+ "astryx",
19
19
  "design-system",
20
20
  "react",
21
21
  "components",
@@ -27,6 +27,8 @@
27
27
  "type": "module",
28
28
  "main": "./dist/index.js",
29
29
  "types": "./dist/index.d.ts",
30
+ "unpkg": "./dist/astryx.umd.js",
31
+ "jsdelivr": "./dist/astryx.umd.js",
30
32
  "sideEffects": [
31
33
  "**/*.stylex.ts",
32
34
  "**/*.stylex.js",
@@ -47,6 +49,7 @@
47
49
  "types": "./src/astryx.css.d.ts",
48
50
  "default": "./dist/astryx.css"
49
51
  },
52
+ "./astryx.umd.js": "./dist/astryx.umd.js",
50
53
  "./tailwind-theme.css": {
51
54
  "types": "./src/tailwind-theme.css.d.ts",
52
55
  "default": "./src/tailwind-theme.css"
@@ -635,9 +638,10 @@
635
638
  "@testing-library/react": "^16.3.2"
636
639
  },
637
640
  "scripts": {
638
- "build": "rm -rf dist && pnpm build:esm && tsc --project tsconfig.build.json && pnpm build:css",
641
+ "build": "rm -rf dist && pnpm build:esm && tsc --project tsconfig.build.json && pnpm build:css && pnpm build:umd",
639
642
  "build:esm": "babel src --out-dir dist --extensions '.ts,.tsx' --out-file-extension '.js' --ignore '**/*.test.ts,**/*.test.tsx,**/__tests__/**,**/*.perf.test.*,**/*.doc.mjs,**/*.d.ts,**/*.css,**/*.css.d.ts' --config-file ./babel.config.json",
640
643
  "build:css": "node ../../scripts/build-css.mjs",
644
+ "build:umd": "node ../../scripts/build-umd.mjs",
641
645
  "dev": "babel src --watch --out-dir dist --extensions '.ts,.tsx' --out-file-extension '.js' --ignore '**/*.test.*,**/*.doc.mjs,**/*.d.ts,**/*.css*' --config-file ./babel.config.json",
642
646
  "test": "vitest run --root ../..",
643
647
  "test:watch": "vitest --root ../..",
@@ -132,6 +132,7 @@ export function AvatarGroupOverflow({
132
132
  xstyle,
133
133
  className,
134
134
  style,
135
+ ...rest
135
136
  }: AvatarGroupOverflowProps): ReactNode {
136
137
  const group = useAvatarGroup();
137
138
  const numericSize = group?.numericSize ?? 36;
@@ -147,6 +148,7 @@ export function AvatarGroupOverflow({
147
148
  type="button"
148
149
  onClick={onClick}
149
150
  aria-label={label}
151
+ {...rest}
150
152
  {...mergeProps(
151
153
  themeProps('avatar-group-overflow'),
152
154
  stylex.props(
@@ -170,6 +172,7 @@ export function AvatarGroupOverflow({
170
172
  <span
171
173
  ref={ref}
172
174
  aria-label={label}
175
+ {...rest}
173
176
  {...mergeProps(
174
177
  themeProps('avatar-group-overflow'),
175
178
  stylex.props(
@@ -76,11 +76,22 @@ describe('Banner', () => {
76
76
  expect(screen.getByText('This is a description')).toBeInTheDocument();
77
77
  });
78
78
 
79
+ it('renders title and description as <div> (never <p>) for composition safety', () => {
80
+ const {container} = render(
81
+ <Banner status="info" title="Title" description="Description" />,
82
+ );
83
+ // Block content can be nested inside Banner text slots without tripping
84
+ // the phrasing-content trap that <p> imposes, so neither slot is a <p>.
85
+ expect(container.querySelector('p')).toBeNull();
86
+ expect(screen.getByText('Title').tagName).toBe('DIV');
87
+ expect(screen.getByText('Description').tagName).toBe('DIV');
88
+ });
89
+
79
90
  it('does not render description when not provided', () => {
80
- const {container} = render(<Banner status="info" title="Title Only" />);
81
- // Only one <p> for the title, no description
82
- const paragraphs = container.querySelectorAll('p');
83
- expect(paragraphs).toHaveLength(1);
91
+ render(<Banner status="info" title="Title Only" />);
92
+ // Title renders; no description text is present.
93
+ expect(screen.getByText('Title Only')).toBeInTheDocument();
94
+ expect(screen.queryByText('This is a description')).not.toBeInTheDocument();
84
95
  });
85
96
 
86
97
  it('renders dismiss button when isDismissable', () => {
@@ -158,9 +169,7 @@ describe('Banner', () => {
158
169
  });
159
170
 
160
171
  it('renders card container by default', () => {
161
- const {container} = render(
162
- <Banner status="info" title="Card Container" />,
163
- );
172
+ const {container} = render(<Banner status="info" title="Card Container" />);
164
173
  const root = container.firstElementChild;
165
174
  expect(root).toBeInTheDocument();
166
175
  });
@@ -16,6 +16,13 @@
16
16
  * - Each visual area owns its own border-radius (no overflow:clip on the container)
17
17
  * - When children are provided, a collapse/expand toggle button appears in the end area
18
18
  *
19
+ * Title and description render as <div> (not <p>): they accept arbitrary
20
+ * ReactNode content, and <p> cannot legally contain block-level children
21
+ * (the HTML parser reparents them, desyncing SSR markup from the hydrated
22
+ * DOM). Using <div> keeps these slots composable with any content. Their
23
+ * StyleX styles set margin: 0 and explicit typography, so the rendered
24
+ * appearance is identical to the previous <p>.
25
+ *
19
26
  * SYNC: When modified, update these files to stay in sync:
20
27
  * - /packages/core/src/Banner/Banner.doc.mjs (props table, features, implementation notes)
21
28
  * - /packages/core/src/Banner/Banner.test.tsx (tests for new/changed behavior)
@@ -441,9 +448,9 @@ export function Banner({
441
448
  )}
442
449
  </div>
443
450
  <div {...stylex.props(styles.headerContent)}>
444
- <p {...stylex.props(styles.title)}>{title}</p>
451
+ <div {...stylex.props(styles.title)}>{title}</div>
445
452
  {description != null && (
446
- <p {...stylex.props(styles.description)}>{description}</p>
453
+ <div {...stylex.props(styles.description)}>{description}</div>
447
454
  )}
448
455
  </div>
449
456
  {showEndArea && (
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import {describe, it, expect, vi} from 'vitest';
13
- import {render, screen} from '@testing-library/react';
13
+ import {render, screen, fireEvent, act} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
15
  import {Button} from './Button';
16
16
  import {Badge} from '../Badge/Badge';
@@ -228,11 +228,7 @@ describe('Button', () => {
228
228
  order.push('clickAction');
229
229
  });
230
230
  render(
231
- <Button
232
- label="Test"
233
- onClick={handleClick}
234
- clickAction={handleAction}
235
- />,
231
+ <Button label="Test" onClick={handleClick} clickAction={handleAction} />,
236
232
  );
237
233
 
238
234
  await user.click(screen.getByRole('button'));
@@ -246,11 +242,7 @@ describe('Button', () => {
246
242
  const handleClick = vi.fn((e: React.MouseEvent) => e.preventDefault());
247
243
  const handleAction = vi.fn();
248
244
  render(
249
- <Button
250
- label="Test"
251
- onClick={handleClick}
252
- clickAction={handleAction}
253
- />,
245
+ <Button label="Test" onClick={handleClick} clickAction={handleAction} />,
254
246
  );
255
247
 
256
248
  await user.click(screen.getByRole('button'));
@@ -258,6 +250,29 @@ describe('Button', () => {
258
250
  expect(handleAction).not.toHaveBeenCalled();
259
251
  });
260
252
 
253
+ it('fires clickAction once on a fast double-click (no double-submit)', async () => {
254
+ let resolveAction: (() => void) | undefined;
255
+ const handleAction = vi.fn(
256
+ async () =>
257
+ new Promise<void>(resolve => {
258
+ resolveAction = resolve;
259
+ }),
260
+ );
261
+ render(<Button label="Pay" clickAction={handleAction} />);
262
+
263
+ const button = screen.getByRole('button');
264
+ await act(async () => {
265
+ fireEvent.click(button);
266
+ fireEvent.click(button);
267
+ });
268
+ expect(handleAction).toHaveBeenCalledTimes(1);
269
+
270
+ await act(async () => {
271
+ resolveAction?.();
272
+ await Promise.resolve();
273
+ });
274
+ });
275
+
261
276
  // type/name/value/form props
262
277
  it('defaults type to button', () => {
263
278
  render(<Button label="Test" />);
@@ -513,6 +513,8 @@ export function Button({
513
513
  const buttonGroup = useButtonGroup();
514
514
 
515
515
  const [isPending, startTransition] = useTransition();
516
+ // clickAction is fire-once (submit/save/pay), so a same-tick double-click must
517
+ // dedupe — which neither isPending nor useOptimistic do. Hence the ref guard.
516
518
  const actionInFlightRef = useRef(false);
517
519
  const isLoadingState = isLoading || isPending;
518
520
  const groupDisabled = buttonGroup?.isDisabled ?? false;
@@ -90,6 +90,12 @@ const styles = stylex.create({
90
90
  whiteSpace: 'nowrap',
91
91
  paddingInline: spacingVars['--spacing-2'],
92
92
  },
93
+ // When a label is shown, the icon sits on the leading edge and the text on
94
+ // the trailing edge. Symmetric padding leaves the text cramped against the
95
+ // pill's rounded edge, so give the trailing side extra breathing room.
96
+ buttonWithLabel: {
97
+ paddingInlineEnd: spacingVars['--spacing-3'],
98
+ },
93
99
  });
94
100
 
95
101
  // =============================================================================
@@ -130,7 +136,7 @@ export function ChatLayoutScrollButton({
130
136
  variant="ghost"
131
137
  size="md"
132
138
  onClick={onClick}
133
- xstyle={styles.button}>
139
+ xstyle={[styles.button, label ? styles.buttonWithLabel : null]}>
134
140
  {label ?? undefined}
135
141
  </Button>
136
142
  </div>
@@ -38,7 +38,7 @@ export const docs = {
38
38
  usage: {
39
39
  description: 'Reusable hook that encapsulates the collapsible state machine. Supports three modes: group-controlled (inside CollapsibleGroup), controlled (isOpen + onOpenChange), and uncontrolled (self-managed with defaultIsOpen). Used internally by Card and Section.',
40
40
  bestPractices: [
41
- {guidance: true, description: 'Use the hook directly when building custom collapsible components that need XDS collapsible behavior without Collapsible wrapper.'},
41
+ {guidance: true, description: 'Use the hook directly when building custom collapsible components that need Astryx collapsible behavior without Collapsible wrapper.'},
42
42
  {guidance: true, description: 'For accordion behavior, wrap items in CollapsibleGroup and pass unique value props.'},
43
43
  {guidance: false, description: 'Implement your own open/close state when useCollapsible already provides it; the hook handles group coordination automatically.'},
44
44
  ],
@@ -64,7 +64,7 @@ export const docsDense = {
64
64
  usage: {
65
65
  description: 'Encapsulates collapsible state machine. 3 modes: group-controlled (inside CollapsibleGroup), controlled (isOpen + onOpenChange), uncontrolled (self-managed w/ defaultIsOpen). Used internally by Card + Section.',
66
66
  bestPractices: [
67
- {guidance: true, description: 'Use directly when building custom collapsible components needing XDS collapsible behavior w/o Collapsible wrapper.'},
67
+ {guidance: true, description: 'Use directly when building custom collapsible components needing Astryx collapsible behavior w/o Collapsible wrapper.'},
68
68
  {guidance: true, description: 'For accordion behavior, wrap items in CollapsibleGroup + pass unique value props.'},
69
69
  {guidance: false, description: 'Implement your own open/close state when useCollapsible already provides it; hook handles group coordination automatically.'},
70
70
  ],
@@ -36,7 +36,7 @@ import React, {
36
36
  import type {ReactNode} from 'react';
37
37
  import * as stylex from '@stylexjs/stylex';
38
38
  import {useLayer} from '../Layer/useLayer';
39
- import {renderXDSDropdownItems} from '../DropdownMenu/renderXDSDropdownItems';
39
+ import {renderDropdownItems} from '../DropdownMenu/renderDropdownItems';
40
40
  import {
41
41
  DropdownMenuContext,
42
42
  type DropdownMenuContextValue,
@@ -278,7 +278,7 @@ export function ContextMenu({
278
278
  );
279
279
 
280
280
  const resolvedMenuContent =
281
- props.items !== undefined ? renderXDSDropdownItems(items) : menuContent;
281
+ props.items !== undefined ? renderDropdownItems(items) : menuContent;
282
282
 
283
283
  return (
284
284
  <>
@@ -21,19 +21,13 @@ describe('DateInput', () => {
21
21
 
22
22
  it('renders with placeholder', () => {
23
23
  render(
24
- <DateInput
25
- label="Date"
26
- onChange={() => {}}
27
- placeholder="Pick a date"
28
- />,
24
+ <DateInput label="Date" onChange={() => {}} placeholder="Pick a date" />,
29
25
  );
30
26
  expect(screen.getByPlaceholderText('Pick a date')).toBeInTheDocument();
31
27
  });
32
28
 
33
29
  it('displays formatted date when value is provided', () => {
34
- render(
35
- <DateInput label="Date" value="2026-01-25" onChange={() => {}} />,
36
- );
30
+ render(<DateInput label="Date" value="2026-01-25" onChange={() => {}} />);
37
31
  expect(screen.getByDisplayValue('January 25, 2026')).toBeInTheDocument();
38
32
  });
39
33
 
@@ -118,9 +112,7 @@ describe('DateInput', () => {
118
112
 
119
113
  it('reverts to previous value on blur when input is invalid', async () => {
120
114
  const onChange = vi.fn();
121
- render(
122
- <DateInput label="Date" value="2026-01-25" onChange={onChange} />,
123
- );
115
+ render(<DateInput label="Date" value="2026-01-25" onChange={onChange} />);
124
116
 
125
117
  const input = screen.getByRole('combobox');
126
118
  fireEvent.change(input, {target: {value: 'not a date'}});
@@ -299,9 +291,7 @@ describe('DateInput', () => {
299
291
  // --- P1: Tab order: calendar button first, then input ---
300
292
 
301
293
  it('renders calendar button before input in DOM order', () => {
302
- const {container} = render(
303
- <DateInput label="Date" onChange={() => {}} />,
304
- );
294
+ const {container} = render(<DateInput label="Date" onChange={() => {}} />);
305
295
  const input = container.querySelector('input');
306
296
  const button = container.querySelector('button');
307
297
  // Calendar button should come before input in the DOM
@@ -389,9 +379,7 @@ describe('DateInput', () => {
389
379
 
390
380
  it('calls onChange with undefined when input is cleared and blurred', () => {
391
381
  const onChange = vi.fn();
392
- render(
393
- <DateInput label="Date" value="2026-01-25" onChange={onChange} />,
394
- );
382
+ render(<DateInput label="Date" value="2026-01-25" onChange={onChange} />);
395
383
 
396
384
  const input = screen.getByRole('combobox');
397
385
  fireEvent.change(input, {target: {value: ''}});
@@ -476,9 +464,7 @@ describe('DateInput', () => {
476
464
  });
477
465
 
478
466
  it('does not show clear button when hasClear is false', () => {
479
- render(
480
- <DateInput label="Date" value="2026-01-15" onChange={() => {}} />,
481
- );
467
+ render(<DateInput label="Date" value="2026-01-15" onChange={() => {}} />);
482
468
  expect(
483
469
  screen.queryByRole('button', {name: 'Clear Date'}),
484
470
  ).not.toBeInTheDocument();
@@ -514,6 +500,68 @@ describe('DateInput', () => {
514
500
  });
515
501
  });
516
502
 
503
+ // --- Regression: in-progress / leading-zero input must not crash ---
504
+
505
+ describe('incomplete typed input', () => {
506
+ it('does not crash or fire onChange when first digit typed is 0', () => {
507
+ const onChange = vi.fn();
508
+ render(<DateInput label="Date" onChange={onChange} />);
509
+
510
+ const input = screen.getByRole('combobox');
511
+ // Typing a leading "0" (e.g. starting "01" for January) must be treated
512
+ // as incomplete input, not coerced into an (invalid) date that crashes.
513
+ expect(() =>
514
+ fireEvent.change(input, {target: {value: '0'}}),
515
+ ).not.toThrow();
516
+
517
+ expect(onChange).not.toHaveBeenCalled();
518
+ expect(input).toHaveValue('0');
519
+ });
520
+
521
+ it('does not crash or fire onChange when first digit typed is 1', () => {
522
+ const onChange = vi.fn();
523
+ render(<DateInput label="Date" onChange={onChange} />);
524
+
525
+ const input = screen.getByRole('combobox');
526
+ expect(() =>
527
+ fireEvent.change(input, {target: {value: '1'}}),
528
+ ).not.toThrow();
529
+
530
+ expect(onChange).not.toHaveBeenCalled();
531
+ expect(input).toHaveValue('1');
532
+ });
533
+
534
+ it('does not crash while progressively typing a numeric date', () => {
535
+ const onChange = vi.fn();
536
+ render(<DateInput label="Date" onChange={onChange} />);
537
+
538
+ const input = screen.getByRole('combobox');
539
+ // Simulate keystroke-by-keystroke entry of "01/15/2026". The leading
540
+ // single-digit keystrokes must not crash (the original bug).
541
+ for (const partial of ['0', '01', '01/', '01/1', '01/15', '01/15/']) {
542
+ expect(() =>
543
+ fireEvent.change(input, {target: {value: partial}}),
544
+ ).not.toThrow();
545
+ }
546
+
547
+ // Completing the date commits it without error.
548
+ expect(() =>
549
+ fireEvent.change(input, {target: {value: '01/15/2026'}}),
550
+ ).not.toThrow();
551
+ expect(onChange).toHaveBeenCalledWith('2026-01-15');
552
+ });
553
+
554
+ it('does not crash on blur after typing an incomplete value', () => {
555
+ const onChange = vi.fn();
556
+ render(<DateInput label="Date" onChange={onChange} />);
557
+
558
+ const input = screen.getByRole('combobox');
559
+ fireEvent.change(input, {target: {value: '0'}});
560
+ expect(() => fireEvent.blur(input)).not.toThrow();
561
+ expect(onChange).not.toHaveBeenCalled();
562
+ });
563
+ });
564
+
517
565
  describe('external value changes', () => {
518
566
  it('clears pending input when value changes externally', () => {
519
567
  const onChange = vi.fn();
@@ -108,7 +108,7 @@ export const docsZh = {
108
108
 
109
109
  /** @type {import('../docs-types').TranslationDoc} */
110
110
  export const docsDense = {
111
- description: 'visual separator w/ optional label, using XDS design tokens',
111
+ description: 'visual separator w/ optional label, using Astryx design tokens',
112
112
  usage: {
113
113
  description: 'A visual separator that divides content into distinct sections. Use to create clear boundaries between groups of related content, or to demarcate interactive regions within a layout.',
114
114
  bestPractices: [
@@ -37,7 +37,7 @@ import {Button, type ButtonProps} from '../Button';
37
37
  import {Icon} from '../Icon';
38
38
  import type {IconType} from '../Icon';
39
39
 
40
- import {renderXDSDropdownItems} from './renderXDSDropdownItems';
40
+ import {renderDropdownItems} from './renderDropdownItems';
41
41
  import {
42
42
  DropdownMenuContext,
43
43
  type DropdownMenuContextValue,
@@ -366,7 +366,7 @@ export function DropdownMenu({
366
366
 
367
367
  // Resolve menu content: data-driven items become components
368
368
  const menuContent =
369
- props.items !== undefined ? renderXDSDropdownItems(items) : children;
369
+ props.items !== undefined ? renderDropdownItems(items) : children;
370
370
 
371
371
  return (
372
372
  <>
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file renderXDSDropdownItems.tsx
4
+ * @file renderDropdownItems.tsx
5
5
  * @output Converts data-driven menu items into DropdownMenuItem components
6
6
  * @position Utility; used by DropdownMenu to unify data-driven and compound paths
7
7
  */
@@ -49,7 +49,7 @@ function getSectionKey(section: DropdownMenuSection, index: number): string {
49
49
  * Converts data-driven items into DropdownMenuItem components,
50
50
  * so both modes share the same rendering and keyboard navigation path.
51
51
  */
52
- export function renderXDSDropdownItems(
52
+ export function renderDropdownItems(
53
53
  items: DropdownMenuOption[],
54
54
  ): ReactNode {
55
55
  const elements: ReactNode[] = [];