@kanso-labs/kanso-ui 0.8.0 → 0.8.2

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 (55) hide show
  1. package/README.md +41 -3
  2. package/dist/components/app-bar/index.js +4 -3
  3. package/dist/components/app-bar/index.js.map +1 -1
  4. package/dist/components/avatar/index.js +3 -1
  5. package/dist/components/avatar/index.js.map +1 -1
  6. package/dist/components/badge/index.js +3 -1
  7. package/dist/components/badge/index.js.map +1 -1
  8. package/dist/components/button/index.d.ts +20 -3
  9. package/dist/components/button/index.js +7 -2
  10. package/dist/components/button/index.js.map +1 -1
  11. package/dist/components/card/index.js +3 -1
  12. package/dist/components/card/index.js.map +1 -1
  13. package/dist/components/chip/index.js +32 -26
  14. package/dist/components/chip/index.js.map +1 -1
  15. package/dist/components/code/index.js +42 -30
  16. package/dist/components/code/index.js.map +1 -1
  17. package/dist/components/copy-field/index.js +2 -1
  18. package/dist/components/copy-field/index.js.map +1 -1
  19. package/dist/components/currency/index.js +3 -1
  20. package/dist/components/currency/index.js.map +1 -1
  21. package/dist/components/feed/index.js +3 -1
  22. package/dist/components/feed/index.js.map +1 -1
  23. package/dist/components/icon-button/index.d.ts +20 -3
  24. package/dist/components/icon-button/index.js +7 -2
  25. package/dist/components/icon-button/index.js.map +1 -1
  26. package/dist/components/keycap/index.js +42 -30
  27. package/dist/components/keycap/index.js.map +1 -1
  28. package/dist/components/link/index.js +3 -1
  29. package/dist/components/link/index.js.map +1 -1
  30. package/dist/components/list-detail/index.js +6 -5
  31. package/dist/components/list-detail/index.js.map +1 -1
  32. package/dist/components/list-item/index.js +3 -2
  33. package/dist/components/list-item/index.js.map +1 -1
  34. package/dist/components/product-icon/index.js +3 -1
  35. package/dist/components/product-icon/index.js.map +1 -1
  36. package/dist/components/separator/index.js +3 -1
  37. package/dist/components/separator/index.js.map +1 -1
  38. package/dist/components/sheet/index.js +88 -67
  39. package/dist/components/sheet/index.js.map +1 -1
  40. package/dist/components/supporting-pane/index.js +69 -61
  41. package/dist/components/supporting-pane/index.js.map +1 -1
  42. package/dist/components/tabs/index.js +48 -26
  43. package/dist/components/tabs/index.js.map +1 -1
  44. package/dist/components/text/index.js +3 -1
  45. package/dist/components/text/index.js.map +1 -1
  46. package/dist/components/text-field/index.js +12 -11
  47. package/dist/components/text-field/index.js.map +1 -1
  48. package/dist/index.d.ts +1 -0
  49. package/dist/index.js +1 -0
  50. package/dist/render/nativeButton.js +26 -0
  51. package/dist/render/nativeButton.js.map +1 -0
  52. package/dist/styles/merge.js +57 -0
  53. package/dist/styles/merge.js.map +1 -0
  54. package/package.json +4 -3
  55. /package/dist/{assets/stylex.css → styles.css} +0 -0
package/README.md CHANGED
@@ -24,9 +24,47 @@ function Example() {
24
24
  }
25
25
  ```
26
26
 
27
- Components render correctly with no further setup every design token has a
28
- built-in default, in both light and dark (respecting the OS-level
29
- `prefers-color-scheme`).
27
+ Components render correctly with no further setup. Importing from the package
28
+ pulls in the stylesheet the library compiles, every design token has a built-in
29
+ default, in both light and dark (respecting the OS-level
30
+ `prefers-color-scheme`), and every component sizes itself with
31
+ `box-sizing: border-box` rather than leaving that to a reset you supply.
32
+
33
+ A bundler is what resolves that stylesheet. In an environment that cannot import
34
+ CSS from JavaScript — some server-side renderers, or a plain Node process —
35
+ import it yourself instead and the components style themselves the same way:
36
+
37
+ ```ts
38
+ import '@kanso-labs/kanso-ui/styles.css'
39
+ ```
40
+
41
+ `className` and `style` reach the element a component renders, so a component is
42
+ positioned from the call site like any other element:
43
+
44
+ ```tsx
45
+ <Card className="col-span-2" style={{ marginBlockStart: '2rem' }} />
46
+ ```
47
+
48
+ StyleX compiles the library's own rules into a CSS `@layer`, and your app's
49
+ stylesheet is unlayered, so your rules win the cascade wherever the two meet —
50
+ no specificity contest, and no `!important`.
51
+
52
+ ### Rendering as a different element
53
+
54
+ `render` swaps the element a component produces, keeping its styling:
55
+
56
+ ```tsx
57
+ <Text render={<h2 />}>Headline</Text>
58
+ <Card render={<a href="/items/1" />}>First item</Card>
59
+ <Button render={<a href="/items/1" />}>Label</Button>
60
+ ```
61
+
62
+ `Button` and `IconButton` read the tag off `render` and tell Base UI whether it
63
+ is a real `<button>`, so an anchor needs no `nativeButton={false}` and logs no
64
+ error. Base UI then supplies the button semantics that anchor has no native
65
+ version of, which means it is announced as a **button** rather than as a link.
66
+ For a control that should be announced as the link it is, reach for `Link`, or
67
+ `Card` with `render`.
30
68
 
31
69
  ## Theming
32
70
 
@@ -1,4 +1,5 @@
1
1
  import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
2
+ import { mergeStyles } from "../../styles/merge.js";
2
3
  import Text from "../text/index.js";
3
4
  import { useRender } from "@base-ui/react/use-render";
4
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -71,8 +72,8 @@ function AppBar({ align = "start", headline, leading, render, scrolled = false,
71
72
  }),
72
73
  /* @__PURE__ */ jsxs("div", {
73
74
  ...{
74
- 0: { className: "x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll x18fpw6u" },
75
- 1: { className: "x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll x18fpw6u x2b8uid" }
75
+ 0: { className: "x9f619 x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll x18fpw6u" },
76
+ 1: { className: "x9f619 x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll x18fpw6u x2b8uid" }
76
77
  }[!!(align === "center") << 0],
77
78
  children: [headline === void 0 ? null : /* @__PURE__ */ jsx(Text, {
78
79
  render: HEADING_1,
@@ -90,7 +91,7 @@ function AppBar({ align = "start", headline, leading, render, scrolled = false,
90
91
  children: trailing
91
92
  })
92
93
  ] }),
93
- ...props(styles.root, heightStyles.root(height), scrolled && styles.scrolled)
94
+ ...mergeStyles(props(styles.root, heightStyles.root(height), scrolled && styles.scrolled), props$1)
94
95
  },
95
96
  render
96
97
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/app-bar/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, spacing } from '../../tokens/design.tokens.stylex';\nimport Text from '../text';\n\n// Material 3's app bar, in the three sizes M3 Expressive recommends.\n//\n// The spec offers four variants. `search` is absent because it opens M3's\n// search view when selected, and that is a component in its own right that\n// this library does not have — half of a search bar would be worse than none.\n// The other three are here.\n//\n// `medium` and `large` are M3 Expressive's *flexible* bars. The baseline\n// medium and large ones they replaced are marked \"not recommended\" in the\n// spec, so there is no ambiguity to protect against and the shorter names are\n// the ones worth having at a call site.\n//\n// M3 also merged the old center-aligned variant into small as a configuration\n// rather than a variant, which is why alignment is a prop here and applies to\n// every size.\n//\n// Heights are M3's, and they are minimums rather than fixed. The spec says the\n// flexible bars \"hug the text contents\", and Expressive added multi-line\n// support and text wrapping, so a headline long enough to wrap has to be able\n// to make its bar taller. Fixing the height would truncate exactly the case\n// the variant was redesigned for.\nconst HEIGHTS = {\n large: {\n plain: '120px',\n withSubtitle: '152px'\n },\n medium: {\n plain: '112px',\n withSubtitle: '136px'\n },\n small: {\n plain: '64px',\n withSubtitle: '64px'\n }\n} as const;\nconst styles = {\n root: {\n kGNEyG: \"x6s0dn4\",\n kWkggS: \"x14s9m32\",\n kB7OPa: \"x9f619\",\n k1xSpc: \"x78zum5\",\n kOIVth: \"xzoy561\",\n kg3NbH: \"ximhkdq\",\n kIyJzY: \"xx6bhzk\",\n k1ekBW: \"x15406qy\",\n $$css: true\n },\n scrolled: {\n kWkggS: \"x1mjdul6\",\n $$css: true\n }\n};\n\n// One entry per size, and each names a type role rather than a figure. M3's\n// own tokens are `md.comp.app-bar.<size>.title.font`, aliases onto the type\n// scale rather than sizes of their own, so this maps to the scale the same\n// way and lets Text apply it.\nconst HEADLINE_VARIANT = {\n large: 'headlineMedium',\n medium: 'headlineSmall',\n small: 'titleLarge'\n} as const;\n\n// The headline is the page's title in M3's model, so it is the page's <h1>.\n// A bar nested somewhere that already has one can pass its own heading as\n// `headline` instead.\n// oxlint-disable-next-line jsx-a11y/heading-has-content -- filled by useRender\nconst HEADING_1 = <h1 />;\nconst PARAGRAPH = <p />;\n\n// Height is the one value the call site does not choose, and it depends on two\n// props at once, so it is a function style rather than one key per\n// combination. StyleX writes it to a custom property inline, the same\n// mechanism Feed uses for its cell minimum.\nconst _temp = {\n kAzted: \"x1chvrdh\",\n \"$$css\": true\n};\nconst heightStyles = {\n root: (minBlockSize: string) => [_temp, {\n \"--x-minBlockSize\": (val => typeof val === \"number\" ? val + \"px\" : val != null ? val : undefined)(minBlockSize)\n }]\n};\ntype AppBarProps = Omit<useRender.ComponentProps<'header'>, 'children'> & {\n /**\n * Which of M3's alignments the text takes. `center` is the configuration\n * that replaced the old center-aligned variant.\n * @default 'start'\n */\n align?: 'center' | 'start';\n /** The page's title. Wraps rather than truncating, and grows the bar with it. */\n headline?: ReactNode;\n /** Usually a back or menu icon button. Sits before the text. */\n leading?: ReactNode;\n /**\n * Whether the content beneath has been scrolled. M3 separates a bar from\n * scrolled content with a fill colour rather than a shadow, and this is what\n * applies it.\n *\n * Controlled, with no listener of its own: only the app knows which element\n * scrolls, and a bar that watched the window would be wrong inside every\n * pane and dialog that scrolls independently.\n * @default false\n */\n scrolled?: boolean;\n /**\n * Height and headline size. `medium` and `large` are M3 Expressive's\n * flexible bars, which hug their text — the baseline variants they replaced\n * are no longer recommended and are not offered.\n * @default 'small'\n */\n size?: 'large' | 'medium' | 'small';\n /** A second line under the headline. Makes `medium` and `large` taller. */\n subtitle?: ReactNode;\n /** Actions, at the far end. Usually icon buttons. */\n trailing?: ReactNode;\n};\n\n/**\n * Material 3's app bar: the container at the top of a page carrying its title,\n * one or two actions, and the way back out.\n *\n * Three sizes. `small` is a fixed 64px bar for a page whose title is a label;\n * `medium` and `large` are the flexible bars, which give the headline a larger\n * type role and grow to fit a subtitle or a headline that wraps.\n *\n * It paints its own surface, unlike the layout components, because separating\n * itself from the content beneath is the job — which is also why `scrolled`\n * exists.\n */\nfunction AppBar({\n align = 'start',\n headline,\n leading,\n render,\n scrolled = false,\n size = 'small',\n subtitle,\n trailing,\n ...props\n}: AppBarProps) {\n const height = subtitle === undefined || subtitle === null ? HEIGHTS[size].plain : HEIGHTS[size].withSubtitle;\n return useRender({\n defaultTagName: 'header',\n props: {\n ...props,\n children: <>\n {leading === undefined ? null : <div className=\"x6s0dn4 x78zum5 x2lah0s xzoy561\">{leading}</div>}\n <div {...{\n 0: {\n className: \"x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll x18fpw6u\"\n },\n 1: {\n className: \"x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll x18fpw6u x2b8uid\"\n }\n }[!!(align === 'center') << 0]}>\n {headline === undefined ? null : <Text render={HEADING_1} variant={HEADLINE_VARIANT[size]}>\n {headline}\n </Text>}\n {subtitle === undefined ? null : <Text render={PARAGRAPH} tone=\"muted\" variant=\"bodyMedium\">\n {subtitle}\n </Text>}\n </div>\n {trailing === undefined ? null : <div className=\"x6s0dn4 x78zum5 x2lah0s xzoy561\">{trailing}</div>}\n </>,\n ...stylex.props(styles.root, heightStyles.root(height), scrolled && styles.scrolled)\n },\n render\n });\n}\nexport type { AppBarProps };\nexport default AppBar;"],"mappings":";;;;;AA4BA,MAAM,UAAU;CACd,OAAO;EACL,OAAO;EACP,cAAc;CAChB;CACA,QAAQ;EACN,OAAO;EACP,cAAc;CAChB;CACA,OAAO;EACL,OAAO;EACP,cAAc;CAChB;AACF;AACA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAMA,MAAM,mBAAmB;CACvB,OAAO;CACP,QAAQ;CACR,OAAO;AACT;AAMA,MAAM,YAAY,oBAAC,MAAD,CAAG,CAAA;AACrB,MAAM,YAAY,oBAAC,KAAD,CAAE,CAAA;AAMpB,MAAM,QAAQ;CACZ,QAAQ;CACR,SAAS;AACX;AACA,MAAM,eAAe,EACnB,OAAO,iBAAyB,CAAC,OAAO,EACtC,sBAAqB,QAAO,OAAO,QAAQ,WAAW,MAAM,OAAO,OAAO,OAAO,MAAM,KAAA,EAAA,CAAW,YAAY,EAChH,CAAC,EACH;;;;;;;;;;;;;AAgDA,SAAS,OAAO,EACd,QAAQ,SACR,UACA,SACA,QACA,WAAW,OACX,OAAO,SACP,UACA,UACA,GAAG,WACW;CACd,MAAM,SAAS,aAAa,KAAA,KAAa,aAAa,OAAO,QAAQ,KAAK,CAAC,QAAQ,QAAQ,KAAK,CAAC;CACjG,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,UAAU,qBAAA,UAAA,EAAA,UAAA;IACL,YAAY,KAAA,IAAY,OAAO,oBAAC,OAAD;KAAK,WAAU;KAAmC,UAAA;IAAa,CAAA;IAC/F,qBAAC,OAAD;KAAK,GAAI;MACT,GAAG,EACD,WAAW,6DACb;MACA,GAAG,EACD,WAAW,qEACb;KACF,EAAE,CAAC,EAAE,UAAU,aAAa;KAP1B,UAAA,CAQG,aAAa,KAAA,IAAY,OAAO,oBAAC,MAAD;MAAM,QAAQ;MAAW,SAAS,iBAAiB;MAC/E,UAAA;KACG,CAAA,GACP,aAAa,KAAA,IAAY,OAAO,oBAAC,MAAD;MAAM,QAAQ;MAAW,MAAK;MAAQ,SAAQ;MAC1E,UAAA;KACG,CAAA,CACL;;IACJ,aAAa,KAAA,IAAY,OAAO,oBAAC,OAAD;KAAK,WAAU;KAAmC,UAAA;IAAc,CAAA;GACnG,EAAA,CAAA;GACF,GAAG,MAAa,OAAO,MAAM,aAAa,KAAK,MAAM,GAAG,YAAY,OAAO,QAAQ;EACrF;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/app-bar/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, spacing } from '../../tokens/design.tokens.stylex';\nimport Text from '../text';\n\n// Material 3's app bar, in the three sizes M3 Expressive recommends.\n//\n// The spec offers four variants. `search` is absent because it opens M3's\n// search view when selected, and that is a component in its own right that\n// this library does not have — half of a search bar would be worse than none.\n// The other three are here.\n//\n// `medium` and `large` are M3 Expressive's *flexible* bars. The baseline\n// medium and large ones they replaced are marked \"not recommended\" in the\n// spec, so there is no ambiguity to protect against and the shorter names are\n// the ones worth having at a call site.\n//\n// M3 also merged the old center-aligned variant into small as a configuration\n// rather than a variant, which is why alignment is a prop here and applies to\n// every size.\n//\n// Heights are M3's, and they are minimums rather than fixed. The spec says the\n// flexible bars \"hug the text contents\", and Expressive added multi-line\n// support and text wrapping, so a headline long enough to wrap has to be able\n// to make its bar taller. Fixing the height would truncate exactly the case\n// the variant was redesigned for.\nconst HEIGHTS = {\n large: {\n plain: '120px',\n withSubtitle: '152px'\n },\n medium: {\n plain: '112px',\n withSubtitle: '136px'\n },\n small: {\n plain: '64px',\n withSubtitle: '64px'\n }\n} as const;\nconst styles = {\n root: {\n kGNEyG: \"x6s0dn4\",\n kWkggS: \"x14s9m32\",\n kB7OPa: \"x9f619\",\n k1xSpc: \"x78zum5\",\n kOIVth: \"xzoy561\",\n kg3NbH: \"ximhkdq\",\n kIyJzY: \"xx6bhzk\",\n k1ekBW: \"x15406qy\",\n $$css: true\n },\n scrolled: {\n kWkggS: \"x1mjdul6\",\n $$css: true\n }\n};\n\n// One entry per size, and each names a type role rather than a figure. M3's\n// own tokens are `md.comp.app-bar.<size>.title.font`, aliases onto the type\n// scale rather than sizes of their own, so this maps to the scale the same\n// way and lets Text apply it.\nconst HEADLINE_VARIANT = {\n large: 'headlineMedium',\n medium: 'headlineSmall',\n small: 'titleLarge'\n} as const;\n\n// The headline is the page's title in M3's model, so it is the page's <h1>.\n// A bar nested somewhere that already has one can pass its own heading as\n// `headline` instead.\n// oxlint-disable-next-line jsx-a11y/heading-has-content -- filled by useRender\nconst HEADING_1 = <h1 />;\nconst PARAGRAPH = <p />;\n\n// Height is the one value the call site does not choose, and it depends on two\n// props at once, so it is a function style rather than one key per\n// combination. StyleX writes it to a custom property inline, the same\n// mechanism Feed uses for its cell minimum.\nconst _temp = {\n kAzted: \"x1chvrdh\",\n \"$$css\": true\n};\nconst heightStyles = {\n root: (minBlockSize: string) => [_temp, {\n \"--x-minBlockSize\": (val => typeof val === \"number\" ? val + \"px\" : val != null ? val : undefined)(minBlockSize)\n }]\n};\ntype AppBarProps = Omit<useRender.ComponentProps<'header'>, 'children'> & {\n /**\n * Which of M3's alignments the text takes. `center` is the configuration\n * that replaced the old center-aligned variant.\n * @default 'start'\n */\n align?: 'center' | 'start';\n /** The page's title. Wraps rather than truncating, and grows the bar with it. */\n headline?: ReactNode;\n /** Usually a back or menu icon button. Sits before the text. */\n leading?: ReactNode;\n /**\n * Whether the content beneath has been scrolled. M3 separates a bar from\n * scrolled content with a fill colour rather than a shadow, and this is what\n * applies it.\n *\n * Controlled, with no listener of its own: only the app knows which element\n * scrolls, and a bar that watched the window would be wrong inside every\n * pane and dialog that scrolls independently.\n * @default false\n */\n scrolled?: boolean;\n /**\n * Height and headline size. `medium` and `large` are M3 Expressive's\n * flexible bars, which hug their text — the baseline variants they replaced\n * are no longer recommended and are not offered.\n * @default 'small'\n */\n size?: 'large' | 'medium' | 'small';\n /** A second line under the headline. Makes `medium` and `large` taller. */\n subtitle?: ReactNode;\n /** Actions, at the far end. Usually icon buttons. */\n trailing?: ReactNode;\n};\n\n/**\n * Material 3's app bar: the container at the top of a page carrying its title,\n * one or two actions, and the way back out.\n *\n * Three sizes. `small` is a fixed 64px bar for a page whose title is a label;\n * `medium` and `large` are the flexible bars, which give the headline a larger\n * type role and grow to fit a subtitle or a headline that wraps.\n *\n * It paints its own surface, unlike the layout components, because separating\n * itself from the content beneath is the job — which is also why `scrolled`\n * exists.\n */\nfunction AppBar({\n align = 'start',\n headline,\n leading,\n render,\n scrolled = false,\n size = 'small',\n subtitle,\n trailing,\n ...props\n}: AppBarProps) {\n const height = subtitle === undefined || subtitle === null ? HEIGHTS[size].plain : HEIGHTS[size].withSubtitle;\n return useRender({\n defaultTagName: 'header',\n props: {\n ...props,\n children: <>\n {leading === undefined ? null : <div className=\"x6s0dn4 x78zum5 x2lah0s xzoy561\">{leading}</div>}\n <div {...{\n 0: {\n className: \"x9f619 x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll x18fpw6u\"\n },\n 1: {\n className: \"x9f619 x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll x18fpw6u x2b8uid\"\n }\n }[!!(align === 'center') << 0]}>\n {headline === undefined ? null : <Text render={HEADING_1} variant={HEADLINE_VARIANT[size]}>\n {headline}\n </Text>}\n {subtitle === undefined ? null : <Text render={PARAGRAPH} tone=\"muted\" variant=\"bodyMedium\">\n {subtitle}\n </Text>}\n </div>\n {trailing === undefined ? null : <div className=\"x6s0dn4 x78zum5 x2lah0s xzoy561\">{trailing}</div>}\n </>,\n ...mergeStyles(stylex.props(styles.root, heightStyles.root(height), scrolled && styles.scrolled), props)\n },\n render\n });\n}\nexport type { AppBarProps };\nexport default AppBar;"],"mappings":";;;;;;AA6BA,MAAM,UAAU;CACd,OAAO;EACL,OAAO;EACP,cAAc;CAChB;CACA,QAAQ;EACN,OAAO;EACP,cAAc;CAChB;CACA,OAAO;EACL,OAAO;EACP,cAAc;CAChB;AACF;AACA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAMA,MAAM,mBAAmB;CACvB,OAAO;CACP,QAAQ;CACR,OAAO;AACT;AAMA,MAAM,YAAY,oBAAC,MAAD,CAAG,CAAA;AACrB,MAAM,YAAY,oBAAC,KAAD,CAAE,CAAA;AAMpB,MAAM,QAAQ;CACZ,QAAQ;CACR,SAAS;AACX;AACA,MAAM,eAAe,EACnB,OAAO,iBAAyB,CAAC,OAAO,EACtC,sBAAqB,QAAO,OAAO,QAAQ,WAAW,MAAM,OAAO,OAAO,OAAO,MAAM,KAAA,EAAA,CAAW,YAAY,EAChH,CAAC,EACH;;;;;;;;;;;;;AAgDA,SAAS,OAAO,EACd,QAAQ,SACR,UACA,SACA,QACA,WAAW,OACX,OAAO,SACP,UACA,UACA,GAAG,WACW;CACd,MAAM,SAAS,aAAa,KAAA,KAAa,aAAa,OAAO,QAAQ,KAAK,CAAC,QAAQ,QAAQ,KAAK,CAAC;CACjG,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,UAAU,qBAAA,UAAA,EAAA,UAAA;IACL,YAAY,KAAA,IAAY,OAAO,oBAAC,OAAD;KAAK,WAAU;KAAmC,UAAA;IAAa,CAAA;IAC/F,qBAAC,OAAD;KAAK,GAAI;MACT,GAAG,EACD,WAAW,oEACb;MACA,GAAG,EACD,WAAW,4EACb;KACF,EAAE,CAAC,EAAE,UAAU,aAAa;KAP1B,UAAA,CAQG,aAAa,KAAA,IAAY,OAAO,oBAAC,MAAD;MAAM,QAAQ;MAAW,SAAS,iBAAiB;MAC/E,UAAA;KACG,CAAA,GACP,aAAa,KAAA,IAAY,OAAO,oBAAC,MAAD;MAAM,QAAQ;MAAW,MAAK;MAAQ,SAAQ;MAC1E,UAAA;KACG,CAAA,CACL;;IACJ,aAAa,KAAA,IAAY,OAAO,oBAAC,OAAD;KAAK,WAAU;KAAmC,UAAA;IAAc,CAAA;GACnG,EAAA,CAAA;GACF,GAAG,YAAY,MAAa,OAAO,MAAM,aAAa,KAAK,MAAM,GAAG,YAAY,OAAO,QAAQ,GAAG,OAAK;EACzG;EACA;CACF,CAAC;AACH"}
@@ -1,4 +1,5 @@
1
1
  import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
2
+ import { mergeStatefulStyles } from "../../styles/merge.js";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
4
  import { Avatar } from "@base-ui/react/avatar";
4
5
  //#region src/components/avatar/index.tsx
@@ -6,6 +7,7 @@ const styles = {
6
7
  base: {
7
8
  kGNEyG: "x6s0dn4",
8
9
  kaIpWk: "x3y1ksm",
10
+ kB7OPa: "x9f619",
9
11
  k1xSpc: "x3nfvp2",
10
12
  kmuXW: "x2lah0s",
11
13
  kMv6JI: "xkknnkr",
@@ -70,7 +72,7 @@ function Avatar$1({ name, size = "md", src, tone = "primary", ...props$1 }) {
70
72
  "aria-label": name,
71
73
  role: "img",
72
74
  ...props$1,
73
- ...props(styles.base, styles[size], styles[tone]),
75
+ ...mergeStatefulStyles(props(styles.base, styles[size], styles[tone]), props$1),
74
76
  children: [src === void 0 ? null : /* @__PURE__ */ jsx(Avatar.Image, {
75
77
  alt: "",
76
78
  src,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/avatar/index.tsx"],"sourcesContent":["import type { AvatarRootProps as BaseUIAvatarRootProps } from '@base-ui/react/avatar';\nimport { Avatar as BaseUIAvatar } from '@base-ui/react/avatar';\nimport * as stylex from '@stylexjs/stylex';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, typography } from '../../tokens/design.tokens.stylex';\n\n// Tones are container/on-container pairs rather than one colour each, so the\n// initials are always a role's own foreground and can't end up unreadable on\n// a tint they were never paired with. Which tone a given person gets is the\n// consuming app's decision — the design cycles colours per person, and that\n// cycle belongs where the list of people is, not in this component.\n//\n// Sizes carry their own type size but not their own weight or family: the\n// label face at medium weight holds across all three, so a large avatar is\n// bigger initials rather than differently-styled ones.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x3y1ksm\",\n k1xSpc: \"x3nfvp2\",\n kmuXW: \"x2lah0s\",\n kMv6JI: \"xkknnkr\",\n k63SB2: \"x1bf3uqz\",\n kjj79g: \"xl56j7k\",\n kVQacm: \"xb3r6kr\",\n kfSwDN: \"x87ps6o\",\n $$css: true\n },\n image: {\n kZKoxP: \"x5yr21d\",\n kzqmXN: \"xh8yej3\",\n kVIFPx: \"xl1xv1r\",\n $$css: true\n },\n lg: {\n kZKoxP: \"xnnlda6\",\n kGuDYH: \"x1848etk\",\n kzqmXN: \"x15yg21f\",\n $$css: true\n },\n md: {\n kZKoxP: \"x1vqgdyp\",\n kGuDYH: \"x14zspaw\",\n kzqmXN: \"x100vrsf\",\n $$css: true\n },\n negative: {\n kWkggS: \"xkz0cvf\",\n kMwMTN: \"xylzu7l\",\n $$css: true\n },\n positive: {\n kWkggS: \"xa3zu90\",\n kMwMTN: \"x1di7zbg\",\n $$css: true\n },\n primary: {\n kWkggS: \"xp89om9\",\n kMwMTN: \"xscdzaa\",\n $$css: true\n },\n secondary: {\n kWkggS: \"x15dekr4\",\n kMwMTN: \"x1sawysd\",\n $$css: true\n },\n sm: {\n kZKoxP: \"xc9qbxq\",\n kGuDYH: \"xkucv67\",\n kzqmXN: \"x14qfxbe\",\n $$css: true\n },\n tertiary: {\n kWkggS: \"xs6yvni\",\n kMwMTN: \"x3cbcwg\",\n $$css: true\n }\n};\ntype AvatarProps = Omit<BaseUIAvatarRootProps, 'children'> & {\n /**\n * The person this represents. Supplies both the initials and the accessible\n * name, so a screen reader announces who it is rather than reading two\n * letters aloud.\n */\n name: string;\n /**\n * Diameter: `sm` 36px, `md` 40px, `lg` 56px.\n * @default 'md'\n */\n size?: 'lg' | 'md' | 'sm';\n /**\n * A photo to show in place of the initials. The initials stay until it has\n * loaded, and come back if it fails.\n */\n src?: string;\n /**\n * Which container/on-container colour pair to tint with.\n * @default 'primary'\n */\n tone?: 'negative' | 'positive' | 'primary' | 'secondary' | 'tertiary';\n};\nfunction Avatar({\n name,\n size = 'md',\n src,\n tone = 'primary',\n ...props\n}: AvatarProps) {\n return (\n // role/aria-label rather than letting the initials be read: \"AL\" is not\n // what anyone means to announce. Marking the root as an image also makes\n // its contents presentational, so the photo and the initials can't be\n // announced a second time underneath the name.\n //\n // The lint rule below wants a real <img> tag instead of the role, which\n // cannot work here: an <img> is void, and this element's whole job is to\n // hold the initials shown when there is no photo, or none has loaded yet.\n <BaseUIAvatar.Root aria-label={name}\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- <img> takes no children\n role=\"img\" {...props} {...stylex.props(styles.base, styles[size], styles[tone])}>\n {src === undefined ? null : <BaseUIAvatar.Image alt=\"\" src={src} className=\"x5yr21d xh8yej3 xl1xv1r\" />}\n <BaseUIAvatar.Fallback>{initialsFrom(name)}</BaseUIAvatar.Fallback>\n </BaseUIAvatar.Root>\n );\n}\n\n// First letter of the first and last word, which handles both \"Ada\" and \"Ada\n// Lovelace\" without a separate prop for how many to take. Array.from rather\n// than indexing, so a name starting outside the Basic Multilingual Plane\n// yields its whole first character instead of half a surrogate pair.\nfunction initialsFrom(name: string) {\n const words = name.split(/\\s+/u).filter(Boolean);\n if (words.length === 0) {\n return '';\n }\n const first = Array.from(words[0] ?? '')[0] ?? '';\n const last = words.length > 1 ? Array.from(words.at(-1) ?? '')[0] ?? '' : '';\n return `${first}${last}`.toLocaleUpperCase();\n}\nexport type { AvatarProps };\nexport default Avatar;"],"mappings":";;;;AAeA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,WAAW;EACT,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAwBA,SAAS,SAAO,EACd,MACA,OAAO,MACP,KACA,OAAO,WACP,GAAG,WACW;CACd,OASE,qBAAC,OAAa,MAAd;EAAmB,cAAY;EAE/B,MAAK;EAAM,GAAI;EAAO,GAAI,MAAa,OAAO,MAAM,OAAO,OAAO,OAAO,KAAK;EAF9E,UAAA,CAGG,QAAQ,KAAA,IAAY,OAAO,oBAAC,OAAa,OAAd;GAAoB,KAAI;GAAQ;GAAK,WAAU;EAAyB,CAAA,GACpG,oBAAC,OAAa,UAAd,EAAA,UAAwB,aAAa,IAAI,EAAyB,CAAA,CACjD;;AAEvB;AAMA,SAAS,aAAa,MAAc;CAClC,MAAM,QAAQ,KAAK,MAAM,MAAM,CAAC,CAAC,OAAO,OAAO;CAC/C,IAAI,MAAM,WAAW,GACnB,OAAO;CAIT,OAAO,GAFO,MAAM,KAAK,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,KAClC,MAAM,SAAS,IAAI,MAAM,KAAK,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,KAAK,KACjD,kBAAkB;AAC7C"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/avatar/index.tsx"],"sourcesContent":["import type { AvatarRootProps as BaseUIAvatarRootProps } from '@base-ui/react/avatar';\nimport { Avatar as BaseUIAvatar } from '@base-ui/react/avatar';\nimport * as stylex from '@stylexjs/stylex';\nimport { mergeStatefulStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, typography } from '../../tokens/design.tokens.stylex';\n\n// Tones are container/on-container pairs rather than one colour each, so the\n// initials are always a role's own foreground and can't end up unreadable on\n// a tint they were never paired with. Which tone a given person gets is the\n// consuming app's decision — the design cycles colours per person, and that\n// cycle belongs where the list of people is, not in this component.\n//\n// Sizes carry their own type size but not their own weight or family: the\n// label face at medium weight holds across all three, so a large avatar is\n// bigger initials rather than differently-styled ones.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x3y1ksm\",\n kB7OPa: \"x9f619\",\n k1xSpc: \"x3nfvp2\",\n kmuXW: \"x2lah0s\",\n kMv6JI: \"xkknnkr\",\n k63SB2: \"x1bf3uqz\",\n kjj79g: \"xl56j7k\",\n kVQacm: \"xb3r6kr\",\n kfSwDN: \"x87ps6o\",\n $$css: true\n },\n image: {\n kZKoxP: \"x5yr21d\",\n kzqmXN: \"xh8yej3\",\n kVIFPx: \"xl1xv1r\",\n $$css: true\n },\n lg: {\n kZKoxP: \"xnnlda6\",\n kGuDYH: \"x1848etk\",\n kzqmXN: \"x15yg21f\",\n $$css: true\n },\n md: {\n kZKoxP: \"x1vqgdyp\",\n kGuDYH: \"x14zspaw\",\n kzqmXN: \"x100vrsf\",\n $$css: true\n },\n negative: {\n kWkggS: \"xkz0cvf\",\n kMwMTN: \"xylzu7l\",\n $$css: true\n },\n positive: {\n kWkggS: \"xa3zu90\",\n kMwMTN: \"x1di7zbg\",\n $$css: true\n },\n primary: {\n kWkggS: \"xp89om9\",\n kMwMTN: \"xscdzaa\",\n $$css: true\n },\n secondary: {\n kWkggS: \"x15dekr4\",\n kMwMTN: \"x1sawysd\",\n $$css: true\n },\n sm: {\n kZKoxP: \"xc9qbxq\",\n kGuDYH: \"xkucv67\",\n kzqmXN: \"x14qfxbe\",\n $$css: true\n },\n tertiary: {\n kWkggS: \"xs6yvni\",\n kMwMTN: \"x3cbcwg\",\n $$css: true\n }\n};\ntype AvatarProps = Omit<BaseUIAvatarRootProps, 'children'> & {\n /**\n * The person this represents. Supplies both the initials and the accessible\n * name, so a screen reader announces who it is rather than reading two\n * letters aloud.\n */\n name: string;\n /**\n * Diameter: `sm` 36px, `md` 40px, `lg` 56px.\n * @default 'md'\n */\n size?: 'lg' | 'md' | 'sm';\n /**\n * A photo to show in place of the initials. The initials stay until it has\n * loaded, and come back if it fails.\n */\n src?: string;\n /**\n * Which container/on-container colour pair to tint with.\n * @default 'primary'\n */\n tone?: 'negative' | 'positive' | 'primary' | 'secondary' | 'tertiary';\n};\nfunction Avatar({\n name,\n size = 'md',\n src,\n tone = 'primary',\n ...props\n}: AvatarProps) {\n return (\n // role/aria-label rather than letting the initials be read: \"AL\" is not\n // what anyone means to announce. Marking the root as an image also makes\n // its contents presentational, so the photo and the initials can't be\n // announced a second time underneath the name.\n //\n // The lint rule below wants a real <img> tag instead of the role, which\n // cannot work here: an <img> is void, and this element's whole job is to\n // hold the initials shown when there is no photo, or none has loaded yet.\n <BaseUIAvatar.Root aria-label={name}\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- <img> takes no children\n role=\"img\" {...props} {...mergeStatefulStyles(stylex.props(styles.base, styles[size], styles[tone]), props)}>\n {src === undefined ? null : <BaseUIAvatar.Image alt=\"\" src={src} className=\"x5yr21d xh8yej3 xl1xv1r\" />}\n <BaseUIAvatar.Fallback>{initialsFrom(name)}</BaseUIAvatar.Fallback>\n </BaseUIAvatar.Root>\n );\n}\n\n// First letter of the first and last word, which handles both \"Ada\" and \"Ada\n// Lovelace\" without a separate prop for how many to take. Array.from rather\n// than indexing, so a name starting outside the Basic Multilingual Plane\n// yields its whole first character instead of half a surrogate pair.\nfunction initialsFrom(name: string) {\n const words = name.split(/\\s+/u).filter(Boolean);\n if (words.length === 0) {\n return '';\n }\n const first = Array.from(words[0] ?? '')[0] ?? '';\n const last = words.length > 1 ? Array.from(words.at(-1) ?? '')[0] ?? '' : '';\n return `${first}${last}`.toLocaleUpperCase();\n}\nexport type { AvatarProps };\nexport default Avatar;"],"mappings":";;;;;AAgBA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,WAAW;EACT,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAwBA,SAAS,SAAO,EACd,MACA,OAAO,MACP,KACA,OAAO,WACP,GAAG,WACW;CACd,OASE,qBAAC,OAAa,MAAd;EAAmB,cAAY;EAE/B,MAAK;EAAM,GAAI;EAAO,GAAI,oBAAoB,MAAa,OAAO,MAAM,OAAO,OAAO,OAAO,KAAK,GAAG,OAAK;EAF1G,UAAA,CAGG,QAAQ,KAAA,IAAY,OAAO,oBAAC,OAAa,OAAd;GAAoB,KAAI;GAAQ;GAAK,WAAU;EAAyB,CAAA,GACpG,oBAAC,OAAa,UAAd,EAAA,UAAwB,aAAa,IAAI,EAAyB,CAAA,CACjD;;AAEvB;AAMA,SAAS,aAAa,MAAc;CAClC,MAAM,QAAQ,KAAK,MAAM,MAAM,CAAC,CAAC,OAAO,OAAO;CAC/C,IAAI,MAAM,WAAW,GACnB,OAAO;CAIT,OAAO,GAFO,MAAM,KAAK,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,KAClC,MAAM,SAAS,IAAI,MAAM,KAAK,MAAM,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,KAAK,KACjD,kBAAkB;AAC7C"}
@@ -1,4 +1,5 @@
1
1
  import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
2
+ import { mergeStyles } from "../../styles/merge.js";
2
3
  import { useRender } from "@base-ui/react/use-render";
3
4
  //#region src/components/badge/index.tsx
4
5
  const styles = { base: {
@@ -6,6 +7,7 @@ const styles = { base: {
6
7
  kaIpWk: "x1xdvaa9",
7
8
  ksu8eU: "x1y0btm7",
8
9
  kMzoRj: "xmkeg23",
10
+ kB7OPa: "x9f619",
9
11
  k1xSpc: "x3nfvp2",
10
12
  kmuXW: "x2lah0s",
11
13
  kMv6JI: "xs1w0rn",
@@ -82,7 +84,7 @@ function Badge({ render, tone = "neutral", variant = "filled", ...props$1 }) {
82
84
  defaultTagName: "span",
83
85
  props: {
84
86
  ...props$1,
85
- ...props(styles.base, toned)
87
+ ...mergeStyles(props(styles.base, toned), props$1)
86
88
  },
87
89
  render
88
90
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/badge/index.tsx"],"sourcesContent":["import { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, spacing, typography } from '../../tokens/design.tokens.stylex';\n\n// A badge states something about what it sits beside — a count, a status, a\n// version — and is never itself the thing you press. That is the whole line\n// between this and Chip: a chip is a two-state button announcing itself\n// through `aria-pressed`, so reaching for one to render a read-only label\n// puts a control in the accessibility tree that nothing can operate.\n//\n// Both variants carry a 1px border and `filled` makes it transparent rather\n// than dropping it, so a badge is the same size either way. Emphasising one\n// badge in a row otherwise nudges its neighbours by a pixel each side.\n//\n// Tabular figures are unconditional, for the same reason Currency sets them:\n// what ends up in a badge is mostly numeric — counts, versions, ports — and a\n// stack of them down a list wobbles on proportional digits. Text that happens\n// to carry no digits is unaffected.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x1xdvaa9\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xmkeg23\",\n k1xSpc: \"x3nfvp2\",\n kmuXW: \"x2lah0s\",\n kMv6JI: \"xs1w0rn\",\n kGuDYH: \"x1n35her\",\n kcqcaj: \"xss6m8b\",\n k63SB2: \"x1su64ma\",\n kOIVth: \"xzoy561\",\n kb6lSQ: \"xdlnduh\",\n kLWn49: \"xaomhve\",\n k8WAf4: \"xpg5a72\",\n kg3NbH: \"xn60lsn\",\n khDVqt: \"xuxw1ft\",\n $$css: true\n }\n};\n\n// `neutral` draws from the surface roles rather than a colour of its own,\n// which is what lets it state something without ranking it. The other three\n// name a direction, and are the same three Currency uses, plus primary for\n// the notable-but-not-good-or-bad case. `error` is deliberately absent:\n// negative already covers it, and offering both would leave the choice\n// between them to taste.\nconst filledTones = {\n negative: {\n kWkggS: \"xkz0cvf\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"xylzu7l\",\n $$css: true\n },\n neutral: {\n kWkggS: \"x1rrhr5q\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"x1w5n3ug\",\n $$css: true\n },\n positive: {\n kWkggS: \"xa3zu90\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"x1di7zbg\",\n $$css: true\n },\n primary: {\n kWkggS: \"xp89om9\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"xscdzaa\",\n $$css: true\n }\n};\n\n// Outlined takes the tone at full strength for both the rule and the text,\n// rather than the on-container pairing filled uses. There is no container\n// here for an on-colour to be legible against — the page is the background —\n// so the container roles would read as washed out.\nconst outlinedTones = {\n negative: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"x1xdi1zw\",\n kMwMTN: \"x12gp0t\",\n $$css: true\n },\n neutral: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"x133yhug\",\n kMwMTN: \"x1w5n3ug\",\n $$css: true\n },\n positive: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"xm76mbg\",\n kMwMTN: \"x4no3js\",\n $$css: true\n },\n primary: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"x1uajy3w\",\n kMwMTN: \"x1mxwv8y\",\n $$css: true\n }\n};\ntype BadgeProps = useRender.ComponentProps<'span'> & {\n /**\n * Which colour role the badge carries. `neutral` states without ranking;\n * the other three read as good, bad, or worth noticing.\n * @default 'neutral'\n */\n tone?: BadgeTone;\n /**\n * How much weight the badge pulls. `filled` sits on a container of its own;\n * `outlined` is a rule on the page, for a badge that should not compete\n * with the thing it labels.\n * @default 'filled'\n */\n variant?: BadgeVariant;\n};\ntype BadgeTone = 'negative' | 'neutral' | 'positive' | 'primary';\ntype BadgeVariant = 'filled' | 'outlined';\n\n/**\n * A short, read-only label attached to something else. It renders a `<span>`\n * and takes no interaction — for a label that can be selected, reach for Chip.\n */\nfunction Badge({\n render,\n tone = 'neutral',\n variant = 'filled',\n ...props\n}: BadgeProps) {\n const toned = variant === 'filled' ? filledTones[tone] : outlinedTones[tone];\n\n // stylex.props() spreads after `props` for the same reason Text and Currency\n // do it: it wins over a consumer-supplied className rather than merging with\n // one. useRender would otherwise join the two class strings, and which won\n // would come down to stylesheet order rather than anything visible at the\n // call site.\n return useRender({\n defaultTagName: 'span',\n props: {\n ...props,\n ...stylex.props(styles.base, toned)\n },\n render\n });\n}\nexport type { BadgeProps };\nexport default Badge;"],"mappings":";;;AAmBA,MAAM,SAAS,EACb,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;AACT,EACF;AAQA,MAAM,cAAc;CAClB,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAMA,MAAM,gBAAgB;CACpB,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;;;;;AAuBA,SAAS,MAAM,EACb,QACA,OAAO,WACP,UAAU,UACV,GAAG,WACU;CACb,MAAM,QAAQ,YAAY,WAAW,YAAY,QAAQ,cAAc;CAOvE,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,GAAG,MAAa,OAAO,MAAM,KAAK;EACpC;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/badge/index.tsx"],"sourcesContent":["import { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, spacing, typography } from '../../tokens/design.tokens.stylex';\n\n// A badge states something about what it sits beside — a count, a status, a\n// version — and is never itself the thing you press. That is the whole line\n// between this and Chip: a chip is a two-state button announcing itself\n// through `aria-pressed`, so reaching for one to render a read-only label\n// puts a control in the accessibility tree that nothing can operate.\n//\n// Both variants carry a 1px border and `filled` makes it transparent rather\n// than dropping it, so a badge is the same size either way. Emphasising one\n// badge in a row otherwise nudges its neighbours by a pixel each side.\n//\n// Tabular figures are unconditional, for the same reason Currency sets them:\n// what ends up in a badge is mostly numeric — counts, versions, ports — and a\n// stack of them down a list wobbles on proportional digits. Text that happens\n// to carry no digits is unaffected.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x1xdvaa9\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xmkeg23\",\n kB7OPa: \"x9f619\",\n k1xSpc: \"x3nfvp2\",\n kmuXW: \"x2lah0s\",\n kMv6JI: \"xs1w0rn\",\n kGuDYH: \"x1n35her\",\n kcqcaj: \"xss6m8b\",\n k63SB2: \"x1su64ma\",\n kOIVth: \"xzoy561\",\n kb6lSQ: \"xdlnduh\",\n kLWn49: \"xaomhve\",\n k8WAf4: \"xpg5a72\",\n kg3NbH: \"xn60lsn\",\n khDVqt: \"xuxw1ft\",\n $$css: true\n }\n};\n\n// `neutral` draws from the surface roles rather than a colour of its own,\n// which is what lets it state something without ranking it. The other three\n// name a direction, and are the same three Currency uses, plus primary for\n// the notable-but-not-good-or-bad case. `error` is deliberately absent:\n// negative already covers it, and offering both would leave the choice\n// between them to taste.\nconst filledTones = {\n negative: {\n kWkggS: \"xkz0cvf\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"xylzu7l\",\n $$css: true\n },\n neutral: {\n kWkggS: \"x1rrhr5q\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"x1w5n3ug\",\n $$css: true\n },\n positive: {\n kWkggS: \"xa3zu90\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"x1di7zbg\",\n $$css: true\n },\n primary: {\n kWkggS: \"xp89om9\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"xscdzaa\",\n $$css: true\n }\n};\n\n// Outlined takes the tone at full strength for both the rule and the text,\n// rather than the on-container pairing filled uses. There is no container\n// here for an on-colour to be legible against — the page is the background —\n// so the container roles would read as washed out.\nconst outlinedTones = {\n negative: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"x1xdi1zw\",\n kMwMTN: \"x12gp0t\",\n $$css: true\n },\n neutral: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"x133yhug\",\n kMwMTN: \"x1w5n3ug\",\n $$css: true\n },\n positive: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"xm76mbg\",\n kMwMTN: \"x4no3js\",\n $$css: true\n },\n primary: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"x1uajy3w\",\n kMwMTN: \"x1mxwv8y\",\n $$css: true\n }\n};\ntype BadgeProps = useRender.ComponentProps<'span'> & {\n /**\n * Which colour role the badge carries. `neutral` states without ranking;\n * the other three read as good, bad, or worth noticing.\n * @default 'neutral'\n */\n tone?: BadgeTone;\n /**\n * How much weight the badge pulls. `filled` sits on a container of its own;\n * `outlined` is a rule on the page, for a badge that should not compete\n * with the thing it labels.\n * @default 'filled'\n */\n variant?: BadgeVariant;\n};\ntype BadgeTone = 'negative' | 'neutral' | 'positive' | 'primary';\ntype BadgeVariant = 'filled' | 'outlined';\n\n/**\n * A short, read-only label attached to something else. It renders a `<span>`\n * and takes no interaction — for a label that can be selected, reach for Chip.\n */\nfunction Badge({\n render,\n tone = 'neutral',\n variant = 'filled',\n ...props\n}: BadgeProps) {\n const toned = variant === 'filled' ? filledTones[tone] : outlinedTones[tone];\n return useRender({\n defaultTagName: 'span',\n props: {\n ...props,\n ...mergeStyles(stylex.props(styles.base, toned), props)\n },\n render\n });\n}\nexport type { BadgeProps };\nexport default Badge;"],"mappings":";;;;AAoBA,MAAM,SAAS,EACb,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;AACT,EACF;AAQA,MAAM,cAAc;CAClB,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAMA,MAAM,gBAAgB;CACpB,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;;;;;AAuBA,SAAS,MAAM,EACb,QACA,OAAO,WACP,UAAU,UACV,GAAG,WACU;CACb,MAAM,QAAQ,YAAY,WAAW,YAAY,QAAQ,cAAc;CACvE,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,GAAG,YAAY,MAAa,OAAO,MAAM,KAAK,GAAG,OAAK;EACxD;EACA;CACF,CAAC;AACH"}
@@ -1,12 +1,29 @@
1
1
  import { ButtonProps } from "@base-ui/react/button";
2
2
  //#region src/components/button/index.d.ts
3
- type ButtonProps$1 = ButtonProps & {
3
+ type ButtonProps$1 = {
4
4
  /**
5
5
  * Disables the press ripple. The hover/pressed background state layer is
6
6
  * unaffected.
7
7
  * @default false
8
8
  */
9
9
  disableRipple?: boolean;
10
+ /**
11
+ * Whether the element `render` produces is a real `<button>`, which decides
12
+ * whether Base UI supplies the button role, keyboard activation and
13
+ * disabled semantics itself.
14
+ *
15
+ * Read off `render` when that is a plain element, so
16
+ * `render={<a href="…" />}` needs nothing here. Worth setting only when
17
+ * `render` is a component or a function, where the tag it will produce
18
+ * cannot be read ahead of time.
19
+ *
20
+ * An anchor rendered this way is announced as a button rather than as a
21
+ * link, since that is what Base UI's non-native mode applies. For a control
22
+ * that should be announced as the link it is, reach for `Link`, or `Card`
23
+ * with `render`, neither of which imposes button semantics.
24
+ * @default true
25
+ */
26
+ nativeButton?: boolean;
10
27
  /**
11
28
  * Control height: `xs` 32px, `md` 40px, `lg` 56px, `xl` 80px. Sizes other
12
29
  * than `md` also set their own inline padding.
@@ -15,8 +32,8 @@ type ButtonProps$1 = ButtonProps & {
15
32
  size?: 'lg' | 'md' | 'xl' | 'xs';
16
33
  /** @default 'filled' */
17
34
  variant?: 'filled' | 'outlined' | 'text' | 'tonal';
18
- };
19
- declare function Button$1({ children, disabled, disableRipple, onClick, onContextMenu, onPointerCancel, onPointerDown, onPointerLeave, onPointerUp, size, variant, ...props }: ButtonProps$1): import("react").JSX.Element;
35
+ } & ButtonProps;
36
+ declare function Button$1({ children, disabled, disableRipple, nativeButton, onClick, onContextMenu, onPointerCancel, onPointerDown, onPointerLeave, onPointerUp, size, variant, ...props }: ButtonProps$1): import("react").JSX.Element;
20
37
  //#endregion
21
38
  export { type ButtonProps$1 as ButtonProps, Button$1 as default };
22
39
  //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,7 @@
1
1
  import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
2
+ import { mergeStatefulStyles } from "../../styles/merge.js";
2
3
  import { useRipple } from "../../hooks/useRipple.js";
4
+ import { rendersNativeButton } from "../../render/nativeButton.js";
3
5
  import { jsxs } from "react/jsx-runtime";
4
6
  import { Button } from "@base-ui/react/button";
5
7
  //#region src/components/button/index.tsx
@@ -8,6 +10,7 @@ const styles = {
8
10
  kGNEyG: "x6s0dn4",
9
11
  kaIpWk: "x3y1ksm",
10
12
  kMzoRj: "xc342km",
13
+ kB7OPa: "x9f619",
11
14
  kkrTdU: "x1s07b3s x1ypdohk",
12
15
  k1xSpc: "x3nfvp2",
13
16
  kMv6JI: "xkknnkr",
@@ -21,6 +24,7 @@ const styles = {
21
24
  k3XXqK: "x9v5kkp x1t137rt",
22
25
  kMeerF: "x1de99jn",
23
26
  kVAEAm: "x1n2onr6",
27
+ kybGjl: "x1hl2dhg",
24
28
  $$css: true
25
29
  },
26
30
  filled: {
@@ -78,7 +82,7 @@ const styles = {
78
82
  $$css: true
79
83
  }
80
84
  };
81
- function Button$1({ children, disabled = false, disableRipple = false, onClick, onContextMenu, onPointerCancel, onPointerDown, onPointerLeave, onPointerUp, size = "md", variant = "filled", ...props$1 }) {
85
+ function Button$1({ children, disabled = false, disableRipple = false, nativeButton, onClick, onContextMenu, onPointerCancel, onPointerDown, onPointerLeave, onPointerUp, size = "md", variant = "filled", ...props$1 }) {
82
86
  const ripple = useRipple(!disableRipple, {
83
87
  onClick,
84
88
  onContextMenu,
@@ -89,9 +93,10 @@ function Button$1({ children, disabled = false, disableRipple = false, onClick,
89
93
  });
90
94
  return /* @__PURE__ */ jsxs(Button, {
91
95
  disabled,
96
+ nativeButton: nativeButton ?? rendersNativeButton(props$1.render),
92
97
  ...ripple.handlers,
93
98
  ...props$1,
94
- ...props(styles.base, styles[variant], styles[size]),
99
+ ...mergeStatefulStyles(props(styles.base, styles[variant], styles[size]), props$1),
95
100
  children: [children, ripple.surface]
96
101
  });
97
102
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/button/index.tsx"],"sourcesContent":["import type { ButtonProps as BaseUIButtonProps } from '@base-ui/react/button';\nimport { Button as BaseUIButton } from '@base-ui/react/button';\nimport * as stylex from '@stylexjs/stylex';\nimport { useRipple } from '../../hooks/useRipple';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, shadows, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// Each variant composites an 'on-color' (filled) or the brand color itself\n// (outlined/text, over a transparent container) at the interaction state's\n// opacity, rather than swapping in a separate hover/pressed color.\n// calc(<opacity> * 100%) turns the token's unitless 0-1 ratio into the\n// percentage color-mix() takes. Inlined rather than factored into a helper:\n// @stylexjs/babel-plugin only statically recognizes expressions written\n// directly as property values, and a call to an externally-defined function\n// isn't one of them.\n//\n// :hover and :active still match a disabled native <button>, and stylex's\n// fixed pseudo-class ordering places both after :disabled, so without the\n// :not(:disabled) guard a hovered/pressed disabled button would render with\n// the interaction color instead of the disabled one.\n//\n// Two independent axes, applied base -> variant -> size. The order is what\n// lets `text` keep its tighter inline padding at the default size while the\n// other sizes still set their own: `md` deliberately declares no\n// paddingInline, so a medium button falls through to whatever its variant\n// asked for, and every other size overrides it. That mirrors the source\n// design's own cascade, where the size classes are declared after the\n// variant ones and win on padding for exactly the same reason.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x3y1ksm\",\n kMzoRj: \"xc342km\",\n kkrTdU: \"x1s07b3s x1ypdohk\",\n k1xSpc: \"x3nfvp2\",\n kMv6JI: \"xkknnkr\",\n kGuDYH: \"x14zspaw\",\n k63SB2: \"x1v9cpvo\",\n kOIVth: \"x126z3so\",\n kb6lSQ: \"x155f00i\",\n kLWn49: \"x1lz68p4\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kVAEAm: \"x1n2onr6\",\n $$css: true\n },\n filled: {\n kWkggS: \"xm7dzmu x1n0xrd1 x16z974x x197hsbc xnety89\",\n kGVxlE: \"xfj5659 xv7jn9b x1gnnqk1\",\n kMwMTN: \"xhfb3ry xwjo7ld\",\n kg3NbH: \"xg0ps1x\",\n $$css: true\n },\n lg: {\n kZKoxP: \"xnnlda6\",\n kGuDYH: \"x1848etk\",\n kLWn49: \"xh7dzej\",\n kg3NbH: \"x6e1k4i\",\n $$css: true\n },\n md: {\n kZKoxP: \"x1vqgdyp\",\n $$css: true\n },\n outlined: {\n kWkggS: \"x117izkb x598nmq x1pi8zt8 xjbqb8w\",\n kVAM5u: \"xd8uu4e x1fwvt7v\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xmkeg23\",\n kMwMTN: \"xhfb3ry x1mxwv8y\",\n kg3NbH: \"xg0ps1x\",\n $$css: true\n },\n text: {\n kWkggS: \"x117izkb x598nmq x1pi8zt8 xjbqb8w\",\n kMwMTN: \"xhfb3ry x1mxwv8y\",\n kg3NbH: \"x790zyz\",\n $$css: true\n },\n tonal: {\n kWkggS: \"x1c3n7wt x1n0xrd1 x1uyy5zb xwypj8i xp89om9\",\n kGVxlE: \"xfj5659 xv7jn9b x1gnnqk1\",\n kMwMTN: \"xhfb3ry xscdzaa\",\n kg3NbH: \"xg0ps1x\",\n $$css: true\n },\n xl: {\n kZKoxP: \"xwzfr38\",\n kGuDYH: \"xete2z3\",\n kLWn49: \"x2divse\",\n kg3NbH: \"x1sdxjpb\",\n $$css: true\n },\n xs: {\n kZKoxP: \"x10w6t97\",\n kGuDYH: \"xkucv67\",\n kLWn49: \"xvzb9hk\",\n kg3NbH: \"x790zyz\",\n $$css: true\n }\n};\ntype ButtonProps = BaseUIButtonProps & {\n /**\n * Disables the press ripple. The hover/pressed background state layer is\n * unaffected.\n * @default false\n */\n disableRipple?: boolean;\n /**\n * Control height: `xs` 32px, `md` 40px, `lg` 56px, `xl` 80px. Sizes other\n * than `md` also set their own inline padding.\n * @default 'md'\n */\n size?: 'lg' | 'md' | 'xl' | 'xs';\n /** @default 'filled' */\n variant?: 'filled' | 'outlined' | 'text' | 'tonal';\n};\nfunction Button({\n children,\n disabled = false,\n disableRipple = false,\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp,\n size = 'md',\n variant = 'filled',\n ...props\n}: ButtonProps) {\n // `props` (className/style/render, etc.) is spread separately: `className`\n // and `style` there may be functions of render state, a Base UI extension\n // ripple's own handler-only merge doesn't need to know about.\n const ripple = useRipple<HTMLButtonElement>(!disableRipple, {\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp\n });\n return <BaseUIButton disabled={disabled} {...ripple.handlers} {...props} {...stylex.props(styles.base, styles[variant], styles[size])}>\n {children}\n {ripple.surface}\n </BaseUIButton>;\n}\nexport type { ButtonProps };\nexport default Button;"],"mappings":";;;;;AA4BA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,QAAQ;EACN,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAiBA,SAAS,SAAO,EACd,UACA,WAAW,OACX,gBAAgB,OAChB,SACA,eACA,iBACA,eACA,gBACA,aACA,OAAO,MACP,UAAU,UACV,GAAG,WACW;CAId,MAAM,SAAS,UAA6B,CAAC,eAAe;EAC1D;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,OAAO,qBAAC,QAAD;EAAwB;EAAU,GAAI,OAAO;EAAU,GAAI;EAAO,GAAI,MAAa,OAAO,MAAM,OAAO,UAAU,OAAO,KAAK;EAA7H,UAAA,CACF,UACA,OAAO,OACI;;AAClB"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/button/index.tsx"],"sourcesContent":["import type { ButtonProps as BaseUIButtonProps } from '@base-ui/react/button';\nimport { Button as BaseUIButton } from '@base-ui/react/button';\nimport * as stylex from '@stylexjs/stylex';\nimport { useRipple } from '../../hooks/useRipple';\nimport { rendersNativeButton } from '../../render/nativeButton';\nimport { mergeStatefulStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, shadows, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// Each variant composites an 'on-color' (filled) or the brand color itself\n// (outlined/text, over a transparent container) at the interaction state's\n// opacity, rather than swapping in a separate hover/pressed color.\n// calc(<opacity> * 100%) turns the token's unitless 0-1 ratio into the\n// percentage color-mix() takes. Inlined rather than factored into a helper:\n// @stylexjs/babel-plugin only statically recognizes expressions written\n// directly as property values, and a call to an externally-defined function\n// isn't one of them.\n//\n// :hover and :active still match a disabled native <button>, and stylex's\n// fixed pseudo-class ordering places both after :disabled, so without the\n// :not(:disabled) guard a hovered/pressed disabled button would render with\n// the interaction color instead of the disabled one.\n//\n// Two independent axes, applied base -> variant -> size. The order is what\n// lets `text` keep its tighter inline padding at the default size while the\n// other sizes still set their own: `md` deliberately declares no\n// paddingInline, so a medium button falls through to whatever its variant\n// asked for, and every other size overrides it. That mirrors the source\n// design's own cascade, where the size classes are declared after the\n// variant ones and win on padding for exactly the same reason.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x3y1ksm\",\n kMzoRj: \"xc342km\",\n kB7OPa: \"x9f619\",\n kkrTdU: \"x1s07b3s x1ypdohk\",\n k1xSpc: \"x3nfvp2\",\n kMv6JI: \"xkknnkr\",\n kGuDYH: \"x14zspaw\",\n k63SB2: \"x1v9cpvo\",\n kOIVth: \"x126z3so\",\n kb6lSQ: \"x155f00i\",\n kLWn49: \"x1lz68p4\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kVAEAm: \"x1n2onr6\",\n kybGjl: \"x1hl2dhg\",\n $$css: true\n },\n filled: {\n kWkggS: \"xm7dzmu x1n0xrd1 x16z974x x197hsbc xnety89\",\n kGVxlE: \"xfj5659 xv7jn9b x1gnnqk1\",\n kMwMTN: \"xhfb3ry xwjo7ld\",\n kg3NbH: \"xg0ps1x\",\n $$css: true\n },\n lg: {\n kZKoxP: \"xnnlda6\",\n kGuDYH: \"x1848etk\",\n kLWn49: \"xh7dzej\",\n kg3NbH: \"x6e1k4i\",\n $$css: true\n },\n md: {\n kZKoxP: \"x1vqgdyp\",\n $$css: true\n },\n outlined: {\n kWkggS: \"x117izkb x598nmq x1pi8zt8 xjbqb8w\",\n kVAM5u: \"xd8uu4e x1fwvt7v\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xmkeg23\",\n kMwMTN: \"xhfb3ry x1mxwv8y\",\n kg3NbH: \"xg0ps1x\",\n $$css: true\n },\n text: {\n kWkggS: \"x117izkb x598nmq x1pi8zt8 xjbqb8w\",\n kMwMTN: \"xhfb3ry x1mxwv8y\",\n kg3NbH: \"x790zyz\",\n $$css: true\n },\n tonal: {\n kWkggS: \"x1c3n7wt x1n0xrd1 x1uyy5zb xwypj8i xp89om9\",\n kGVxlE: \"xfj5659 xv7jn9b x1gnnqk1\",\n kMwMTN: \"xhfb3ry xscdzaa\",\n kg3NbH: \"xg0ps1x\",\n $$css: true\n },\n xl: {\n kZKoxP: \"xwzfr38\",\n kGuDYH: \"xete2z3\",\n kLWn49: \"x2divse\",\n kg3NbH: \"x1sdxjpb\",\n $$css: true\n },\n xs: {\n kZKoxP: \"x10w6t97\",\n kGuDYH: \"xkucv67\",\n kLWn49: \"xvzb9hk\",\n kg3NbH: \"x790zyz\",\n $$css: true\n }\n};\ntype ButtonProps = {\n /**\n * Disables the press ripple. The hover/pressed background state layer is\n * unaffected.\n * @default false\n */\n disableRipple?: boolean;\n /**\n * Whether the element `render` produces is a real `<button>`, which decides\n * whether Base UI supplies the button role, keyboard activation and\n * disabled semantics itself.\n *\n * Read off `render` when that is a plain element, so\n * `render={<a href=\"…\" />}` needs nothing here. Worth setting only when\n * `render` is a component or a function, where the tag it will produce\n * cannot be read ahead of time.\n *\n * An anchor rendered this way is announced as a button rather than as a\n * link, since that is what Base UI's non-native mode applies. For a control\n * that should be announced as the link it is, reach for `Link`, or `Card`\n * with `render`, neither of which imposes button semantics.\n * @default true\n */\n nativeButton?: boolean;\n /**\n * Control height: `xs` 32px, `md` 40px, `lg` 56px, `xl` 80px. Sizes other\n * than `md` also set their own inline padding.\n * @default 'md'\n */\n size?: 'lg' | 'md' | 'xl' | 'xs';\n /** @default 'filled' */\n variant?: 'filled' | 'outlined' | 'text' | 'tonal';\n} & BaseUIButtonProps;\nfunction Button({\n children,\n disabled = false,\n disableRipple = false,\n nativeButton,\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp,\n size = 'md',\n variant = 'filled',\n ...props\n}: ButtonProps) {\n // `props` (className/style/render, etc.) is spread separately: `className`\n // and `style` there may be functions of render state, a Base UI extension\n // ripple's own handler-only merge doesn't need to know about. It is also\n // why the styles below merge through mergeStatefulStyles rather than the\n // plain mergeStyles.\n const ripple = useRipple<HTMLButtonElement>(!disableRipple, {\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp\n });\n return <BaseUIButton disabled={disabled}\n // Destructured out of `props` above rather than left to flow through\n // with it: spread later, an absent `nativeButton` would arrive as an\n // explicit `undefined` and overwrite what is inferred here.\n nativeButton={nativeButton ?? rendersNativeButton(props.render)} {...ripple.handlers} {...props} {...mergeStatefulStyles(stylex.props(styles.base, styles[variant], styles[size]), props)}>\n {children}\n {ripple.surface}\n </BaseUIButton>;\n}\nexport type { ButtonProps };\nexport default Button;"],"mappings":";;;;;;;AA8BA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,QAAQ;EACN,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAkCA,SAAS,SAAO,EACd,UACA,WAAW,OACX,gBAAgB,OAChB,cACA,SACA,eACA,iBACA,eACA,gBACA,aACA,OAAO,MACP,UAAU,UACV,GAAG,WACW;CAMd,MAAM,SAAS,UAA6B,CAAC,eAAe;EAC1D;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,OAAO,qBAAC,QAAD;EAAwB;EAI/B,cAAc,gBAAgB,oBAAoB,QAAM,MAAM;EAAG,GAAI,OAAO;EAAU,GAAI;EAAO,GAAI,oBAAoB,MAAa,OAAO,MAAM,OAAO,UAAU,OAAO,KAAK,GAAG,OAAK;EAJjL,UAAA,CAKF,UACA,OAAO,OACI;;AAClB"}
@@ -1,4 +1,5 @@
1
1
  import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
2
+ import { mergeStyles } from "../../styles/merge.js";
2
3
  import { useRipple } from "../../hooks/useRipple.js";
3
4
  import { useRender } from "@base-ui/react/use-render";
4
5
  import { Fragment, jsxs } from "react/jsx-runtime";
@@ -7,6 +8,7 @@ const styles = {
7
8
  base: {
8
9
  kaIpWk: "xhpdng0",
9
10
  kMzoRj: "xc342km",
11
+ kB7OPa: "x9f619",
10
12
  kMwMTN: "x1heor9g",
11
13
  k1xSpc: "x1lliihq",
12
14
  kVQacm: "xb3r6kr",
@@ -94,7 +96,7 @@ function Card({ children, interactive = false, onClick, onContextMenu, onPointer
94
96
  ...interactive && render === void 0 ? { type: "button" } : void 0,
95
97
  ...ripple.handlers,
96
98
  children: /* @__PURE__ */ jsxs(Fragment, { children: [children, ripple.surface] }),
97
- ...props(styles.base, styles[variant], padded, interactive && styles.interactive, interactive && interactionStyles[variant])
99
+ ...mergeStyles(props(styles.base, styles[variant], padded, interactive && styles.interactive, interactive && interactionStyles[variant]), props$1)
98
100
  },
99
101
  render
100
102
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/card/index.tsx"],"sourcesContent":["import { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport { useRipple } from '../../hooks/useRipple';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, shadows, spacing, stateLayerOpacity } from '../../tokens/design.tokens.stylex';\n\n// The three variants differ only in how they separate themselves from the\n// page: a shadow, a darker fill, or a border. Each therefore sits on a\n// different background, which is why the interaction styles below are keyed\n// by variant too — a state layer composites an 'on-color' over whatever the\n// container already is, so it cannot be written once for all three.\n//\n// color-mix() is inlined at each property rather than factored into a helper:\n// @stylexjs/babel-plugin only statically recognizes expressions written\n// directly as property values. Button's header comment records the same\n// constraint, and the :not(:disabled) guard there applies here for the same\n// reason — stylex's fixed pseudo-class ordering puts :hover after :disabled.\nconst styles = {\n base: {\n kaIpWk: \"xhpdng0\",\n kMzoRj: \"xc342km\",\n kMwMTN: \"x1heor9g\",\n k1xSpc: \"x1lliihq\",\n kVQacm: \"xb3r6kr\",\n kVAEAm: \"x1n2onr6\",\n kybGjl: \"x1hl2dhg\",\n $$css: true\n },\n elevated: {\n kWkggS: \"x1vnz5z6\",\n kGVxlE: \"x19efjv6\",\n $$css: true\n },\n filled: {\n kWkggS: \"x1rrhr5q\",\n $$css: true\n },\n interactive: {\n kkrTdU: \"x1ypdohk\",\n kVVagm: \"xln7xf2\",\n kzqmXN: \"xh8yej3\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n k9WMMc: \"x1yc453h\",\n $$css: true\n },\n outlined: {\n kWkggS: \"x14s9m32\",\n kVAM5u: \"x133yhug\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xmkeg23\",\n $$css: true\n },\n paddingDefault: {\n kmVPX3: \"xgc26li\",\n $$css: true\n },\n paddingNone: {\n kmVPX3: \"x1717udv\",\n $$css: true\n }\n};\nconst interactionStyles = {\n elevated: {\n kWkggS: \"xu5m21g x5r8g2b x1vnz5z6\",\n kGVxlE: \"x1g60mc1 x1fzngjt x19efjv6\",\n $$css: true\n },\n filled: {\n kWkggS: \"x1w49kxs xovjh5a x1rrhr5q\",\n $$css: true\n },\n outlined: {\n kWkggS: \"x1jqfdmz x1dmgsxd x14s9m32\",\n $$css: true\n }\n};\n\n// Typed as the attributes a <div> accepts, because that is the surface every\n// element this can render shares. Anything element-specific — a button's\n// `type`, an anchor's `href` — would be wrong for the others, and does not\n// need to be here anyway: those are written on the element handed to\n// `render`, where TypeScript checks them against that element's own props.\ntype CardProps = {\n /**\n * Makes the card the thing you press: it ripples, lifts on hover, and takes\n * a focus ring. Renders a `<button>` unless `render` says otherwise. Leave\n * it off for a card that merely holds content, including one containing its\n * own buttons.\n * @default false\n */\n interactive?: boolean;\n /**\n * `none` removes the card's own padding, for a card whose children run to\n * its edges — a list of rows separated by rules.\n * @default 'default'\n */\n padding?: 'default' | 'none';\n /**\n * How the card separates itself from the page: `elevated` casts a shadow,\n * `filled` sits on a darker surface, `outlined` draws a border.\n * @default 'elevated'\n */\n variant?: CardVariant;\n} & useRender.ComponentProps<'div'>;\ntype CardVariant = 'elevated' | 'filled' | 'outlined';\n\n/**\n * A surface holding related content. `render` decides which element that\n * surface is, so a card that navigates can be a real `<a href>` — announced\n * as a link and opening in a new tab on a modifier click, which a `<button>`\n * with an onClick does neither of.\n *\n * `interactive` and `render` are separate axes. `interactive` says the card\n * is pressable and gives it the ripple, the hover lift, and a focus ring;\n * `render` says what it is. A pressable card with no `render` is a\n * `<button>`, which is the right default for one that acts rather than\n * navigates.\n */\nfunction Card({\n children,\n interactive = false,\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp,\n padding = 'default',\n render,\n variant = 'elevated',\n ...props\n}: CardProps) {\n // The consumer's own pointer handlers are handed to useRipple to merge\n // rather than spread over its handlers afterwards, which is what Button\n // does and for the same reason: a plain spread means whichever object\n // comes last silently wins, so an onPointerDown on the call site would\n // replace the one driving the ripple and the card would stop rippling.\n const ripple = useRipple(interactive, {\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp\n });\n const padded = padding === 'none' ? styles.paddingNone : styles.paddingDefault;\n return useRender({\n defaultTagName: interactive ? 'button' : 'div',\n props: {\n ...props,\n // Only when the default <button> is what renders. On an element the\n // call site chose, `type` is either meaningless or wrong — an <a>'s\n // `type` is a hint about the MIME type of what it links to — and that\n // element's own attributes are the call site's to write.\n ...(interactive && render === undefined ? {\n type: 'button'\n } : undefined),\n ...ripple.handlers,\n children: <>\n {children}\n {ripple.surface}\n </>,\n // Spread last so it wins over a consumer-supplied className rather than\n // being merged with one, matching Text and Badge. useRender joins the\n // two class strings otherwise, and which won would come down to\n // stylesheet order rather than anything visible at the call site.\n ...stylex.props(styles.base, styles[variant], padded, interactive && styles.interactive, interactive && interactionStyles[variant])\n },\n render\n });\n}\nexport type { CardProps };\nexport default Card;"],"mappings":";;;;;AAiBA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,QAAQ;EACN,QAAQ;EACR,OAAO;CACT;CACA,aAAa;EACX,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,gBAAgB;EACd,QAAQ;EACR,OAAO;CACT;CACA,aAAa;EACX,QAAQ;EACR,OAAO;CACT;AACF;AACA,MAAM,oBAAoB;CACxB,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,QAAQ;EACN,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,OAAO;CACT;AACF;;;;;;;;;;;;;AA2CA,SAAS,KAAK,EACZ,UACA,cAAc,OACd,SACA,eACA,iBACA,eACA,gBACA,aACA,UAAU,WACV,QACA,UAAU,YACV,GAAG,WACS;CAMZ,MAAM,SAAS,UAAU,aAAa;EACpC;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,SAAS,YAAY,SAAS,OAAO,cAAc,OAAO;CAChE,OAAO,UAAU;EACf,gBAAgB,cAAc,WAAW;EACzC,OAAO;GACL,GAAG;GAKH,GAAI,eAAe,WAAW,KAAA,IAAY,EACxC,MAAM,SACR,IAAI,KAAA;GACJ,GAAG,OAAO;GACV,UAAU,qBAAA,UAAA,EAAA,UAAA,CACL,UACA,OAAO,OACV,EAAA,CAAA;GAKF,GAAG,MAAa,OAAO,MAAM,OAAO,UAAU,QAAQ,eAAe,OAAO,aAAa,eAAe,kBAAkB,QAAQ;EACpI;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/card/index.tsx"],"sourcesContent":["import { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport { useRipple } from '../../hooks/useRipple';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, shadows, spacing, stateLayerOpacity } from '../../tokens/design.tokens.stylex';\n\n// The three variants differ only in how they separate themselves from the\n// page: a shadow, a darker fill, or a border. Each therefore sits on a\n// different background, which is why the interaction styles below are keyed\n// by variant too — a state layer composites an 'on-color' over whatever the\n// container already is, so it cannot be written once for all three.\n//\n// color-mix() is inlined at each property rather than factored into a helper:\n// @stylexjs/babel-plugin only statically recognizes expressions written\n// directly as property values. Button's header comment records the same\n// constraint, and the :not(:disabled) guard there applies here for the same\n// reason — stylex's fixed pseudo-class ordering puts :hover after :disabled.\nconst styles = {\n base: {\n kaIpWk: \"xhpdng0\",\n kMzoRj: \"xc342km\",\n kB7OPa: \"x9f619\",\n kMwMTN: \"x1heor9g\",\n k1xSpc: \"x1lliihq\",\n kVQacm: \"xb3r6kr\",\n kVAEAm: \"x1n2onr6\",\n kybGjl: \"x1hl2dhg\",\n $$css: true\n },\n elevated: {\n kWkggS: \"x1vnz5z6\",\n kGVxlE: \"x19efjv6\",\n $$css: true\n },\n filled: {\n kWkggS: \"x1rrhr5q\",\n $$css: true\n },\n interactive: {\n kkrTdU: \"x1ypdohk\",\n kVVagm: \"xln7xf2\",\n kzqmXN: \"xh8yej3\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n k9WMMc: \"x1yc453h\",\n $$css: true\n },\n outlined: {\n kWkggS: \"x14s9m32\",\n kVAM5u: \"x133yhug\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xmkeg23\",\n $$css: true\n },\n paddingDefault: {\n kmVPX3: \"xgc26li\",\n $$css: true\n },\n paddingNone: {\n kmVPX3: \"x1717udv\",\n $$css: true\n }\n};\nconst interactionStyles = {\n elevated: {\n kWkggS: \"xu5m21g x5r8g2b x1vnz5z6\",\n kGVxlE: \"x1g60mc1 x1fzngjt x19efjv6\",\n $$css: true\n },\n filled: {\n kWkggS: \"x1w49kxs xovjh5a x1rrhr5q\",\n $$css: true\n },\n outlined: {\n kWkggS: \"x1jqfdmz x1dmgsxd x14s9m32\",\n $$css: true\n }\n};\n\n// Typed as the attributes a <div> accepts, because that is the surface every\n// element this can render shares. Anything element-specific — a button's\n// `type`, an anchor's `href` — would be wrong for the others, and does not\n// need to be here anyway: those are written on the element handed to\n// `render`, where TypeScript checks them against that element's own props.\ntype CardProps = {\n /**\n * Makes the card the thing you press: it ripples, lifts on hover, and takes\n * a focus ring. Renders a `<button>` unless `render` says otherwise. Leave\n * it off for a card that merely holds content, including one containing its\n * own buttons.\n * @default false\n */\n interactive?: boolean;\n /**\n * `none` removes the card's own padding, for a card whose children run to\n * its edges — a list of rows separated by rules.\n * @default 'default'\n */\n padding?: 'default' | 'none';\n /**\n * How the card separates itself from the page: `elevated` casts a shadow,\n * `filled` sits on a darker surface, `outlined` draws a border.\n * @default 'elevated'\n */\n variant?: CardVariant;\n} & useRender.ComponentProps<'div'>;\ntype CardVariant = 'elevated' | 'filled' | 'outlined';\n\n/**\n * A surface holding related content. `render` decides which element that\n * surface is, so a card that navigates can be a real `<a href>` — announced\n * as a link and opening in a new tab on a modifier click, which a `<button>`\n * with an onClick does neither of.\n *\n * `interactive` and `render` are separate axes. `interactive` says the card\n * is pressable and gives it the ripple, the hover lift, and a focus ring;\n * `render` says what it is. A pressable card with no `render` is a\n * `<button>`, which is the right default for one that acts rather than\n * navigates.\n */\nfunction Card({\n children,\n interactive = false,\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp,\n padding = 'default',\n render,\n variant = 'elevated',\n ...props\n}: CardProps) {\n // The consumer's own pointer handlers are handed to useRipple to merge\n // rather than spread over its handlers afterwards, which is what Button\n // does and for the same reason: a plain spread means whichever object\n // comes last silently wins, so an onPointerDown on the call site would\n // replace the one driving the ripple and the card would stop rippling.\n const ripple = useRipple(interactive, {\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp\n });\n const padded = padding === 'none' ? styles.paddingNone : styles.paddingDefault;\n return useRender({\n defaultTagName: interactive ? 'button' : 'div',\n props: {\n ...props,\n // Only when the default <button> is what renders. On an element the\n // call site chose, `type` is either meaningless or wrong — an <a>'s\n // `type` is a hint about the MIME type of what it links to — and that\n // element's own attributes are the call site's to write.\n ...(interactive && render === undefined ? {\n type: 'button'\n } : undefined),\n ...ripple.handlers,\n children: <>\n {children}\n {ripple.surface}\n </>,\n ...mergeStyles(stylex.props(styles.base, styles[variant], padded, interactive && styles.interactive, interactive && interactionStyles[variant]), props)\n },\n render\n });\n}\nexport type { CardProps };\nexport default Card;"],"mappings":";;;;;;AAkBA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,QAAQ;EACN,QAAQ;EACR,OAAO;CACT;CACA,aAAa;EACX,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,gBAAgB;EACd,QAAQ;EACR,OAAO;CACT;CACA,aAAa;EACX,QAAQ;EACR,OAAO;CACT;AACF;AACA,MAAM,oBAAoB;CACxB,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,QAAQ;EACN,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,OAAO;CACT;AACF;;;;;;;;;;;;;AA2CA,SAAS,KAAK,EACZ,UACA,cAAc,OACd,SACA,eACA,iBACA,eACA,gBACA,aACA,UAAU,WACV,QACA,UAAU,YACV,GAAG,WACS;CAMZ,MAAM,SAAS,UAAU,aAAa;EACpC;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,SAAS,YAAY,SAAS,OAAO,cAAc,OAAO;CAChE,OAAO,UAAU;EACf,gBAAgB,cAAc,WAAW;EACzC,OAAO;GACL,GAAG;GAKH,GAAI,eAAe,WAAW,KAAA,IAAY,EACxC,MAAM,SACR,IAAI,KAAA;GACJ,GAAG,OAAO;GACV,UAAU,qBAAA,UAAA,EAAA,UAAA,CACL,UACA,OAAO,OACV,EAAA,CAAA;GACF,GAAG,YAAY,MAAa,OAAO,MAAM,OAAO,UAAU,QAAQ,eAAe,OAAO,aAAa,eAAe,kBAAkB,QAAQ,GAAG,OAAK;EACxJ;EACA;CACF,CAAC;AACH"}
@@ -1,3 +1,4 @@
1
+ import { mergeStatefulStyles } from "../../styles/merge.js";
1
2
  import { jsx } from "react/jsx-runtime";
2
3
  import { c } from "react/compiler-runtime";
3
4
  import { Toggle } from "@base-ui/react/toggle";
@@ -9,44 +10,49 @@ import { Toggle } from "@base-ui/react/toggle";
9
10
  * rather than a role of its own.
10
11
  */
11
12
  function Chip(t0) {
12
- const $ = c(6);
13
+ const $ = c(10);
14
+ let T0;
13
15
  let children;
14
- let props;
16
+ let t1;
17
+ let t2;
15
18
  if ($[0] !== t0) {
16
- ({children, ...props} = t0);
19
+ const { children: t3, ...props } = t0;
20
+ children = t3;
21
+ T0 = Toggle;
22
+ t1 = props;
23
+ t2 = mergeStatefulStyles(propsFor, props);
17
24
  $[0] = t0;
18
- $[1] = children;
19
- $[2] = props;
25
+ $[1] = T0;
26
+ $[2] = children;
27
+ $[3] = t1;
28
+ $[4] = t2;
20
29
  } else {
21
- children = $[1];
22
- props = $[2];
30
+ T0 = $[1];
31
+ children = $[2];
32
+ t1 = $[3];
33
+ t2 = $[4];
23
34
  }
24
- let t1;
25
- if ($[3] !== children || $[4] !== props) {
26
- t1 = /* @__PURE__ */ jsx(Toggle, {
27
- ...props,
28
- className: classNameForState,
29
- style: styleForState,
35
+ let t3;
36
+ if ($[5] !== T0 || $[6] !== children || $[7] !== t1 || $[8] !== t2) {
37
+ t3 = /* @__PURE__ */ jsx(T0, {
38
+ ...t1,
39
+ ...t2,
30
40
  children
31
41
  });
32
- $[3] = children;
33
- $[4] = props;
34
- $[5] = t1;
35
- } else t1 = $[5];
36
- return t1;
37
- }
38
- function classNameForState(state) {
39
- return propsFor(state).className;
42
+ $[5] = T0;
43
+ $[6] = children;
44
+ $[7] = t1;
45
+ $[8] = t2;
46
+ $[9] = t3;
47
+ } else t3 = $[9];
48
+ return t3;
40
49
  }
41
50
  function propsFor(state) {
42
51
  return {
43
- 0: { className: "x6s0dn4 x10w6t97 x1xdvaa9 x1y0btm7 xmkeg23 x1s07b3s x1ypdohk x3nfvp2 x2lah0s xkknnkr x14zspaw x1v9cpvo x126z3so x155f00i x1lz68p4 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1qno0dh x1eaenvl xpc4ca7 x1a42vn9 x6gcojk xjbqb8w xd8uu4e x1fwvt7v xhfb3ry x1w5n3ug" },
44
- 1: { className: "x6s0dn4 x10w6t97 x1xdvaa9 x1y0btm7 xmkeg23 x1s07b3s x1ypdohk x3nfvp2 x2lah0s xkknnkr x14zspaw x1v9cpvo x126z3so x155f00i x1lz68p4 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1qno0dh x1eaenvl xpc4ca7 xctpbsp x1n0xrd1 x1qndd53 x15dekr4 x9r1u3d xhfb3ry x1sawysd" }
52
+ 0: { className: "x6s0dn4 x10w6t97 x1xdvaa9 x1y0btm7 xmkeg23 x9f619 x1s07b3s x1ypdohk x3nfvp2 x2lah0s xkknnkr x14zspaw x1v9cpvo x126z3so x155f00i x1lz68p4 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1qno0dh x1eaenvl xpc4ca7 x1a42vn9 x6gcojk xjbqb8w xd8uu4e x1fwvt7v xhfb3ry x1w5n3ug" },
53
+ 1: { className: "x6s0dn4 x10w6t97 x1xdvaa9 x1y0btm7 xmkeg23 x9f619 x1s07b3s x1ypdohk x3nfvp2 x2lah0s xkknnkr x14zspaw x1v9cpvo x126z3so x155f00i x1lz68p4 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1qno0dh x1eaenvl xpc4ca7 xctpbsp x1n0xrd1 x1qndd53 x15dekr4 x9r1u3d xhfb3ry x1sawysd" }
45
54
  }[!!state.pressed << 0];
46
55
  }
47
- function styleForState(state) {
48
- return propsFor(state).style;
49
- }
50
56
  //#endregion
51
57
  export { Chip as default };
52
58
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["classNameForState","styleForState","children"],"sources":["../../../src/components/chip/index.tsx"],"sourcesContent":["import type { ToggleProps as BaseUIToggleProps, ToggleState as BaseUIToggleState } from '@base-ui/react/toggle';\nimport { Toggle as BaseUIToggle } from '@base-ui/react/toggle';\nimport * as stylex from '@stylexjs/stylex';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, motion, radii, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// Each state composites an 'on-color' over its own container at the\n// interaction state's opacity rather than swapping in a separate hover color.\n// calc(<opacity> * 100%) turns the token's unitless 0-1 ratio into the\n// percentage color-mix() takes, and it is inlined at each property because\n// @stylexjs/babel-plugin only statically recognizes expressions written\n// directly as property values.\n//\n// The selected chip drops its border rather than recolouring it: it has a\n// container of its own to define its edge, and a border on top of that reads\n// as a second, competing outline.\n\ntype ChipProps<Value extends string = string> = BaseUIToggleProps<Value>;\n\n/**\n * A chip is a two-state button, so its selected state is Base UI's `pressed`:\n * pass `pressed` with `onPressedChange` to control it, or `defaultPressed` to\n * let it keep its own state. Selection is announced through `aria-pressed`\n * rather than a role of its own.\n */\nfunction Chip<Value extends string = string>({\n children,\n ...props\n}: ChipProps<Value>) {\n return <BaseUIToggle {...props} className={classNameForState} style={styleForState}>\n {children}\n </BaseUIToggle>;\n}\nfunction classNameForState(state: BaseUIToggleState) {\n return propsFor(state).className;\n}\n\n// StyleX has no way to target [data-pressed] on the element it is styling, so\n// the selected styles cannot be chosen in CSS. Base UI's answer is to let\n// className and style be functions of the component's own state, which is\n// what these two are — and it is why an uncontrolled chip styles itself\n// correctly without this component keeping a copy of the state.\n//\n// Declared at module scope so each is one stable reference rather than a\n// fresh closure per render, which is what react-perf's no-new-function-as-prop\n// is after. They close over nothing, so there is nothing to capture.\nfunction propsFor(state: BaseUIToggleState) {\n return {\n 0: {\n className: \"x6s0dn4 x10w6t97 x1xdvaa9 x1y0btm7 xmkeg23 x1s07b3s x1ypdohk x3nfvp2 x2lah0s xkknnkr x14zspaw x1v9cpvo x126z3so x155f00i x1lz68p4 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1qno0dh x1eaenvl xpc4ca7 x1a42vn9 x6gcojk xjbqb8w xd8uu4e x1fwvt7v xhfb3ry x1w5n3ug\"\n },\n 1: {\n className: \"x6s0dn4 x10w6t97 x1xdvaa9 x1y0btm7 xmkeg23 x1s07b3s x1ypdohk x3nfvp2 x2lah0s xkknnkr x14zspaw x1v9cpvo x126z3so x155f00i x1lz68p4 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1qno0dh x1eaenvl xpc4ca7 xctpbsp x1n0xrd1 x1qndd53 x15dekr4 x9r1u3d xhfb3ry x1sawysd\"\n }\n }[!!state.pressed << 0];\n}\nfunction styleForState(state: BaseUIToggleState) {\n return propsFor(state).style;\n}\nexport type { ChipProps };\nexport default Chip;"],"mappings":";;;;;;;;;;AAyBA,SAAA,KAAA,IAAA;CAAA,MAAA,IAAA,EAAA,CAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,IAAA;EAA6C,CAAA,CAAA,UAAA,GAAA,SAAA;EAG1B,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA;EAAA,WAAA,EAAA;EAAA,QAAA,EAAA;CAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,YAAA,EAAA,OAAA,OAAA;EACV,KAAA,oBAAC,QAAD;GAAa,GAAK;GAAkBA,WAAA;GAA0BC,OAAA;GAChE;EADe,CAAA;EAEH,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAFV;AAEU;AAEnB,SAAS,kBAAkB,OAA0B;CACnD,OAAO,SAAS,KAAK,CAAC,CAAC;AACzB;AAWA,SAAS,SAAS,OAA0B;CAC1C,OAAO;EACL,GAAG,EACD,WAAW,qRACb;EACA,GAAG,EACD,WAAW,sRACb;CACF,EAAE,CAAC,CAAC,MAAM,WAAW;AACvB;AACA,SAAS,cAAc,OAA0B;CAC/C,OAAO,SAAS,KAAK,CAAC,CAAC;AACzB"}
1
+ {"version":3,"file":"index.js","names":["props","children"],"sources":["../../../src/components/chip/index.tsx"],"sourcesContent":["import type { ToggleProps as BaseUIToggleProps, ToggleState as BaseUIToggleState } from '@base-ui/react/toggle';\nimport { Toggle as BaseUIToggle } from '@base-ui/react/toggle';\nimport * as stylex from '@stylexjs/stylex';\nimport { mergeStatefulStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, motion, radii, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// Each state composites an 'on-color' over its own container at the\n// interaction state's opacity rather than swapping in a separate hover color.\n// calc(<opacity> * 100%) turns the token's unitless 0-1 ratio into the\n// percentage color-mix() takes, and it is inlined at each property because\n// @stylexjs/babel-plugin only statically recognizes expressions written\n// directly as property values.\n//\n// The selected chip drops its border rather than recolouring it: it has a\n// container of its own to define its edge, and a border on top of that reads\n// as a second, competing outline.\n\ntype ChipProps<Value extends string = string> = BaseUIToggleProps<Value>;\n\n/**\n * A chip is a two-state button, so its selected state is Base UI's `pressed`:\n * pass `pressed` with `onPressedChange` to control it, or `defaultPressed` to\n * let it keep its own state. Selection is announced through `aria-pressed`\n * rather than a role of its own.\n */\nfunction Chip<Value extends string = string>({\n children,\n ...props\n}: ChipProps<Value>) {\n return <BaseUIToggle {...props} {...mergeStatefulStyles(propsFor, props)}>\n {children}\n </BaseUIToggle>;\n}\n\n// StyleX has no way to target [data-pressed] on the element it is styling, so\n// the selected styles cannot be chosen in CSS. Base UI's answer is to let\n// className and style be functions of the component's own state, which is\n// what this is — and it is why an uncontrolled chip styles itself correctly\n// without this component keeping a copy of the state.\n//\n// mergeStatefulStyles takes the function rather than a computed result for\n// exactly that reason, and combines it with whatever the call site passed.\nfunction propsFor(state: BaseUIToggleState) {\n return {\n 0: {\n className: \"x6s0dn4 x10w6t97 x1xdvaa9 x1y0btm7 xmkeg23 x9f619 x1s07b3s x1ypdohk x3nfvp2 x2lah0s xkknnkr x14zspaw x1v9cpvo x126z3so x155f00i x1lz68p4 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1qno0dh x1eaenvl xpc4ca7 x1a42vn9 x6gcojk xjbqb8w xd8uu4e x1fwvt7v xhfb3ry x1w5n3ug\"\n },\n 1: {\n className: \"x6s0dn4 x10w6t97 x1xdvaa9 x1y0btm7 xmkeg23 x9f619 x1s07b3s x1ypdohk x3nfvp2 x2lah0s xkknnkr x14zspaw x1v9cpvo x126z3so x155f00i x1lz68p4 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1qno0dh x1eaenvl xpc4ca7 xctpbsp x1n0xrd1 x1qndd53 x15dekr4 x9r1u3d xhfb3ry x1sawysd\"\n }\n }[!!state.pressed << 0];\n}\nexport type { ChipProps };\nexport default Chip;"],"mappings":";;;;;;;;;;;AA0BA,SAAA,KAAA,IAAA;CAAA,MAAA,IAAA,EAAA,EAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,IAAA;EAA6C,MAAA,EAAA,UAAA,IAAA,GAAA,UAAA;EAAA,WAAA;EAInC,KAAA;EAAiBA,KAAA;EAAW,KAAA,oBAAoB,UAAU,KAAK;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA;EAAA,KAAA,EAAA;EAAA,WAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;CAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,EAAA,OAAA,YAAA,EAAA,OAAA,MAAA,EAAA,OAAA,IAAA;EAAjE,KAAA,oBAAC,IAAD;GAAa,GAAKA;GAAK,GAAM;GAC/B;EADe,CAAA;EAEH,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAFV;AAEU;AAWnB,SAAS,SAAS,OAA0B;CAC1C,OAAO;EACL,GAAG,EACD,WAAW,4RACb;EACA,GAAG,EACD,WAAW,6RACb;CACF,EAAE,CAAC,CAAC,MAAM,WAAW;AACvB"}
@@ -1,3 +1,4 @@
1
+ import { mergeStyles } from "../../styles/merge.js";
1
2
  import { useRender } from "@base-ui/react/use-render";
2
3
  import { c } from "react/compiler-runtime";
3
4
  //#region src/components/code/index.tsx
@@ -6,44 +7,55 @@ import { c } from "react/compiler-runtime";
6
7
  * renders a `<code>` and takes its scale from the text around it.
7
8
  */
8
9
  function Code(t0) {
9
- const $ = c(9);
10
- let props;
10
+ const $ = c(13);
11
11
  let render;
12
+ let t1;
13
+ let t2;
14
+ let t3;
15
+ let t4;
12
16
  if ($[0] !== t0) {
13
- ({render, ...props} = t0);
17
+ const { render: t5, ...props } = t0;
18
+ render = t5;
19
+ t4 = useRender;
20
+ t3 = "code";
21
+ t1 = props;
22
+ t2 = mergeStyles({ className: "x9f619 x139gbkf xbppi91 x1s8wshw xj0a0fe" }, props);
14
23
  $[0] = t0;
15
- $[1] = props;
16
- $[2] = render;
24
+ $[1] = render;
25
+ $[2] = t1;
26
+ $[3] = t2;
27
+ $[4] = t3;
28
+ $[5] = t4;
17
29
  } else {
18
- props = $[1];
19
- render = $[2];
30
+ render = $[1];
31
+ t1 = $[2];
32
+ t2 = $[3];
33
+ t3 = $[4];
34
+ t4 = $[5];
20
35
  }
21
- let t1;
22
- if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
23
- t1 = { className: "x139gbkf xbppi91 x1s8wshw xj0a0fe" };
24
- $[3] = t1;
25
- } else t1 = $[3];
26
- let t2;
27
- if ($[4] !== props) {
28
- t2 = {
29
- ...props,
30
- ...t1
36
+ let t5;
37
+ if ($[6] !== t1 || $[7] !== t2) {
38
+ t5 = {
39
+ ...t1,
40
+ ...t2
31
41
  };
32
- $[4] = props;
33
- $[5] = t2;
34
- } else t2 = $[5];
35
- let t3;
36
- if ($[6] !== render || $[7] !== t2) {
37
- t3 = {
38
- defaultTagName: "code",
39
- props: t2,
42
+ $[6] = t1;
43
+ $[7] = t2;
44
+ $[8] = t5;
45
+ } else t5 = $[8];
46
+ let t6;
47
+ if ($[9] !== render || $[10] !== t3 || $[11] !== t5) {
48
+ t6 = {
49
+ defaultTagName: t3,
50
+ props: t5,
40
51
  render
41
52
  };
42
- $[6] = render;
43
- $[7] = t2;
44
- $[8] = t3;
45
- } else t3 = $[8];
46
- return useRender(t3);
53
+ $[9] = render;
54
+ $[10] = t3;
55
+ $[11] = t5;
56
+ $[12] = t6;
57
+ } else t6 = $[12];
58
+ return t4(t6);
47
59
  }
48
60
  //#endregion
49
61
  export { Code as default };