@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
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/code/index.tsx"],"sourcesContent":["import { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, typography } from '../../tokens/design.tokens.stylex';\n\n// Sized in em rather than px, so a fragment of code takes the scale of\n// whatever it interrupts. A mono face at the same nominal size as the prose\n// around it reads a little larger — its glyphs are wider and its x-height\n// taller — so 0.875em is what makes the two look level rather than what makes\n// them measure the same.\n//\n// No background. The mono face against the serif and sans faces the rest of\n// the system uses is already an unmistakable signal, and a tint here would\n// introduce a second surface inside Card and Sheet, competing with the\n// hierarchy those already establish. A call site wanting one can wrap this.\n\ntype CodeProps = useRender.ComponentProps<'code'>;\n\n/**\n * A fragment of code, a path, or an identifier set in the mono face. It\n * renders a `<code>` and takes its scale from the text around it.\n */\nfunction Code({\n render,\n ...props\n}: CodeProps) {\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, so which of the two applies is not left to stylesheet order.\n return useRender({\n defaultTagName: 'code',\n props: {\n ...props,\n ...{\n className: \"x139gbkf xbppi91 x1s8wshw xj0a0fe\"\n }\n },\n render\n });\n}\nexport type { CodeProps };\nexport default Code;"],"mappings":";;;;;;;AAsBA,SAAA,KAAA,IAAA;CAAA,MAAA,IAAA,EAAA,CAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,IAAA;EAAc,CAAA,CAAA,QAAA,GAAA,SAAA;EAGF,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA;EAAA,QAAA,EAAA;EAAA,SAAA,EAAA;CAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,OAAA,IAAA,2BAAA,GAAA;EAQH,KAAA,EAAA,WACU,oCACb;EAAC,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,OAAA;EAJI,KAAA;GAAA,GACF;GAAK,GACL;EAGL;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,UAAA,EAAA,OAAA,IAAA;EAPc,KAAA;GAAA,gBACC;GAAM,OACf;GAKN;EAEH;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OATM,UAAU,EAShB;AAAC"}
1
+ {"version":3,"file":"index.js","names":["useRender","props"],"sources":["../../../src/components/code/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, typography } from '../../tokens/design.tokens.stylex';\n\n// Sized in em rather than px, so a fragment of code takes the scale of\n// whatever it interrupts. A mono face at the same nominal size as the prose\n// around it reads a little larger — its glyphs are wider and its x-height\n// taller — so 0.875em is what makes the two look level rather than what makes\n// them measure the same.\n//\n// No background. The mono face against the serif and sans faces the rest of\n// the system uses is already an unmistakable signal, and a tint here would\n// introduce a second surface inside Card and Sheet, competing with the\n// hierarchy those already establish. A call site wanting one can wrap this.\n\ntype CodeProps = useRender.ComponentProps<'code'>;\n\n/**\n * A fragment of code, a path, or an identifier set in the mono face. It\n * renders a `<code>` and takes its scale from the text around it.\n */\nfunction Code({\n render,\n ...props\n}: CodeProps) {\n return useRender({\n defaultTagName: 'code',\n props: {\n ...props,\n ...mergeStyles({\n className: \"x9f619 x139gbkf xbppi91 x1s8wshw xj0a0fe\"\n }, props)\n },\n render\n });\n}\nexport type { CodeProps };\nexport default Code;"],"mappings":";;;;;;;;AAuBA,SAAA,KAAA,IAAA;CAAA,MAAA,IAAA,EAAA,EAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,IAAA;EAAc,MAAA,EAAA,QAAA,IAAA,GAAA,UAAA;EAAA,SAAA;EAILA,KAAA;EACW,KAAA;EAEXC,KAAA;EACA,KAAA,YAAY,EAAA,WACF,2CACb,GAAG,KAAK;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA;EAAA,SAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;CAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,EAAA,OAAA,IAAA;EAJJ,KAAA;GAAA,GACFA;GAAK,GACL;EAGL;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,UAAA,EAAA,QAAA,MAAA,EAAA,QAAA,IAAA;EAPc,KAAA;GAAA,gBACC;GAAM,OACf;GAKN;EAEH;EAAC,EAAA,KAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OATMD,GAAU,EAShB;AAAC"}
@@ -1,3 +1,4 @@
1
+ import { mergeStyles } from "../../styles/merge.js";
1
2
  import Button from "../button/index.js";
2
3
  import Code from "../code/index.js";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -34,7 +35,7 @@ function CopyField({ copiedLabel = "Copied", copyLabel = "Copy", onCopied, value
34
35
  }, [onCopied, value]);
35
36
  return /* @__PURE__ */ jsxs("div", {
36
37
  ...props,
37
- className: "x6s0dn4 x14s9m32 x1fwvt7v x1xdvaa9 x1y0btm7 xmkeg23 x78zum5 x126z3so xmqoko8 x18fpw6u",
38
+ ...mergeStyles({ className: "x6s0dn4 x14s9m32 x1fwvt7v x1xdvaa9 x1y0btm7 xmkeg23 x9f619 x78zum5 x126z3so xmqoko8 x18fpw6u" }, props),
38
39
  children: [
39
40
  /* @__PURE__ */ jsx("span", {
40
41
  className: "x1iyjqo2 x1b35g6e xeuugli",
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/copy-field/index.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react';\nimport * as stylex from '@stylexjs/stylex';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, spacing, typography } from '../../tokens/design.tokens.stylex';\nimport Button from '../button';\nimport Code from '../code';\n\n// How long the confirmation stands before the control returns to offering the\n// copy again. Not a motion token: those are transition durations, measured in\n// hundreds of milliseconds, and this is a dwell — long enough to be read\n// without being long enough to leave the button lying about what it will do.\nconst COPIED_RESET_MS = 2000;\ntype CopyFieldProps = {\n /**\n * What the button says once the value has been copied. It reverts to\n * `copyLabel` on its own after a couple of seconds.\n * @default 'Copied'\n */\n copiedLabel?: string;\n /**\n * What the button says at rest.\n * @default 'Copy'\n */\n copyLabel?: string;\n /**\n * Called with the value after it reaches the clipboard, never before.\n *\n * Named `onCopied` rather than `onCopy` because the root is a `<div>`, which\n * already has an `onCopy` of its own — React's handler for the native copy\n * event, fired when the reader presses the copy shortcut inside the element.\n * The two are different moments, and a prop that quietly shadowed the\n * built-in would be a trap rather than a convenience.\n */\n onCopied?: (value: string) => void;\n /** The text shown, and the text copied. */\n value: string;\n} & Omit<HTMLAttributes<HTMLDivElement>, 'children'>;\n\n/**\n * A value to be read and taken away — a repository URL, a token, a command.\n * It shows the value in the mono face and copies it on request, confirming\n * on the button itself.\n */\nfunction CopyField({\n copiedLabel = 'Copied',\n copyLabel = 'Copy',\n onCopied,\n value,\n ...props\n}: CopyFieldProps) {\n const [copied, setCopied] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n // Without this, a field unmounted inside the dwell leaves a timer holding a\n // setState for a tree that is gone.\n useEffect(() => () => {\n clearTimeout(timer.current);\n }, []);\n const handleCopy = useCallback(() => {\n const write = async () => {\n try {\n await navigator.clipboard.writeText(value);\n } catch {\n // A clipboard write is refused outside a secure context and wherever\n // the permission is denied, and neither is something the call site can\n // fix. Staying at rest is the honest report: the value is not on the\n // clipboard, so the control must not claim it is.\n setCopied(false);\n return;\n }\n setCopied(true);\n onCopied?.(value);\n clearTimeout(timer.current);\n timer.current = setTimeout(() => {\n setCopied(false);\n }, COPIED_RESET_MS);\n };\n void write();\n }, [onCopied, value]);\n return <div {...props} className=\"x6s0dn4 x14s9m32 x1fwvt7v x1xdvaa9 x1y0btm7 xmkeg23 x78zum5 x126z3so xmqoko8 x18fpw6u\">\n <span className=\"x1iyjqo2 x1b35g6e xeuugli\">\n <Code>{value}</Code>\n </span>\n <Button onClick={handleCopy} size=\"xs\" variant=\"text\">\n {copied ? copiedLabel : copyLabel}\n </Button>\n {/* The button's own label changes, but a label changing under a screen\n reader is not reliably announced. This is. `<output>` carries an\n implicit role of status, so it needs no role attribute of its own. */}\n <output className=\"xjm9jq1 x1hyvwdk x1i1rx1s xb3r6kr x10l6tqk xuxw1ft\">\n {copied ? copiedLabel : ''}\n </output>\n </div>;\n}\nexport type { CopyFieldProps };\nexport default CopyField;"],"mappings":";;;;;AAYA,MAAM,kBAAkB;;;;;;AAgCxB,SAAS,UAAU,EACjB,cAAc,UACd,YAAY,QACZ,UACA,OACA,GAAG,SACc;CACjB,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAC1C,MAAM,QAAQ,OAAkD,KAAA,CAAS;CAIzE,sBAAsB;EACpB,aAAa,MAAM,OAAO;CAC5B,GAAG,CAAA,CAAE;CACL,MAAM,aAAa,kBAAkB;EACnC,MAAM,QAAQ,YAAY;GACxB,IAAI;IACF,MAAM,UAAU,UAAU,UAAU,KAAK;GAC3C,QAAQ;IAKN,UAAU,KAAK;IACf;GACF;GACA,UAAU,IAAI;GACd,WAAW,KAAK;GAChB,aAAa,MAAM,OAAO;GAC1B,MAAM,UAAU,iBAAiB;IAC/B,UAAU,KAAK;GACjB,GAAG,eAAe;EACpB;EACA,MAAW;CACb,GAAG,CAAC,UAAU,KAAK,CAAC;CACpB,OAAO,qBAAC,OAAD;EAAK,GAAI;EAAO,WAAU;EAA1B,UAAA;GACH,oBAAC,QAAD;IAAM,WAAU;IACd,UAAA,oBAAC,MAAD,EAAA,UAAO,MAAY,CAAA;GACf,CAAA;GACN,oBAAC,QAAD;IAAQ,SAAS;IAAY,MAAK;IAAK,SAAQ;IAC5C,UAAA,SAAS,cAAc;GAClB,CAAA;GAIR,oBAAC,UAAD;IAAQ,WAAU;IACf,UAAA,SAAS,cAAc;GAClB,CAAA;EACL;;AACT"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/copy-field/index.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react';\nimport * as stylex from '@stylexjs/stylex';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, spacing, typography } from '../../tokens/design.tokens.stylex';\nimport Button from '../button';\nimport Code from '../code';\n\n// How long the confirmation stands before the control returns to offering the\n// copy again. Not a motion token: those are transition durations, measured in\n// hundreds of milliseconds, and this is a dwell — long enough to be read\n// without being long enough to leave the button lying about what it will do.\nconst COPIED_RESET_MS = 2000;\ntype CopyFieldProps = {\n /**\n * What the button says once the value has been copied. It reverts to\n * `copyLabel` on its own after a couple of seconds.\n * @default 'Copied'\n */\n copiedLabel?: string;\n /**\n * What the button says at rest.\n * @default 'Copy'\n */\n copyLabel?: string;\n /**\n * Called with the value after it reaches the clipboard, never before.\n *\n * Named `onCopied` rather than `onCopy` because the root is a `<div>`, which\n * already has an `onCopy` of its own — React's handler for the native copy\n * event, fired when the reader presses the copy shortcut inside the element.\n * The two are different moments, and a prop that quietly shadowed the\n * built-in would be a trap rather than a convenience.\n */\n onCopied?: (value: string) => void;\n /** The text shown, and the text copied. */\n value: string;\n} & Omit<HTMLAttributes<HTMLDivElement>, 'children'>;\n\n/**\n * A value to be read and taken away — a repository URL, a token, a command.\n * It shows the value in the mono face and copies it on request, confirming\n * on the button itself.\n */\nfunction CopyField({\n copiedLabel = 'Copied',\n copyLabel = 'Copy',\n onCopied,\n value,\n ...props\n}: CopyFieldProps) {\n const [copied, setCopied] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n // Without this, a field unmounted inside the dwell leaves a timer holding a\n // setState for a tree that is gone.\n useEffect(() => () => {\n clearTimeout(timer.current);\n }, []);\n const handleCopy = useCallback(() => {\n const write = async () => {\n try {\n await navigator.clipboard.writeText(value);\n } catch {\n // A clipboard write is refused outside a secure context and wherever\n // the permission is denied, and neither is something the call site can\n // fix. Staying at rest is the honest report: the value is not on the\n // clipboard, so the control must not claim it is.\n setCopied(false);\n return;\n }\n setCopied(true);\n onCopied?.(value);\n clearTimeout(timer.current);\n timer.current = setTimeout(() => {\n setCopied(false);\n }, COPIED_RESET_MS);\n };\n void write();\n }, [onCopied, value]);\n return <div {...props} {...mergeStyles({\n className: \"x6s0dn4 x14s9m32 x1fwvt7v x1xdvaa9 x1y0btm7 xmkeg23 x9f619 x78zum5 x126z3so xmqoko8 x18fpw6u\"\n }, props)}>\n <span className=\"x1iyjqo2 x1b35g6e xeuugli\">\n <Code>{value}</Code>\n </span>\n <Button onClick={handleCopy} size=\"xs\" variant=\"text\">\n {copied ? copiedLabel : copyLabel}\n </Button>\n {/* The button's own label changes, but a label changing under a screen\n reader is not reliably announced. This is. `<output>` carries an\n implicit role of status, so it needs no role attribute of its own. */}\n <output className=\"xjm9jq1 x1hyvwdk x1i1rx1s xb3r6kr x10l6tqk xuxw1ft\">\n {copied ? copiedLabel : ''}\n </output>\n </div>;\n}\nexport type { CopyFieldProps };\nexport default CopyField;"],"mappings":";;;;;;AAaA,MAAM,kBAAkB;;;;;;AAgCxB,SAAS,UAAU,EACjB,cAAc,UACd,YAAY,QACZ,UACA,OACA,GAAG,SACc;CACjB,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAC1C,MAAM,QAAQ,OAAkD,KAAA,CAAS;CAIzE,sBAAsB;EACpB,aAAa,MAAM,OAAO;CAC5B,GAAG,CAAA,CAAE;CACL,MAAM,aAAa,kBAAkB;EACnC,MAAM,QAAQ,YAAY;GACxB,IAAI;IACF,MAAM,UAAU,UAAU,UAAU,KAAK;GAC3C,QAAQ;IAKN,UAAU,KAAK;IACf;GACF;GACA,UAAU,IAAI;GACd,WAAW,KAAK;GAChB,aAAa,MAAM,OAAO;GAC1B,MAAM,UAAU,iBAAiB;IAC/B,UAAU,KAAK;GACjB,GAAG,eAAe;EACpB;EACA,MAAW;CACb,GAAG,CAAC,UAAU,KAAK,CAAC;CACpB,OAAO,qBAAC,OAAD;EAAK,GAAI;EAAO,GAAI,YAAY,EACrC,WAAW,+FACb,GAAG,KAAK;EAFD,UAAA;GAGH,oBAAC,QAAD;IAAM,WAAU;IACd,UAAA,oBAAC,MAAD,EAAA,UAAO,MAAY,CAAA;GACf,CAAA;GACN,oBAAC,QAAD;IAAQ,SAAS;IAAY,MAAK;IAAK,SAAQ;IAC5C,UAAA,SAAS,cAAc;GAClB,CAAA;GAIR,oBAAC,UAAD;IAAQ,WAAU;IACf,UAAA,SAAS,cAAc;GAClB,CAAA;EACL;;AACT"}
@@ -1,7 +1,9 @@
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/currency/index.tsx
4
5
  const styles = { base: {
6
+ kB7OPa: "x9f619",
5
7
  kMv6JI: "xbppi91",
6
8
  kcqcaj: "xss6m8b",
7
9
  k63SB2: "x1bf3uqz",
@@ -32,7 +34,7 @@ function Currency({ currency = "USD", locale, render, sign = "auto", tone = "aut
32
34
  locale,
33
35
  sign
34
36
  }),
35
- ...props(styles.base, tones[resolveTone(value, tone)])
37
+ ...mergeStyles(props(styles.base, tones[resolveTone(value, tone)]), props$1)
36
38
  },
37
39
  render
38
40
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/currency/index.tsx"],"sourcesContent":["import { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, typography } from '../../tokens/design.tokens.stylex';\n\n// Deliberately sets no font-size. The same value turns up at several sizes —\n// inside a list row, as a heading-scale figure, as a total — differing in\n// nothing else, so the size is the container's decision. What must never vary\n// is here: the mono face, tabular figures so a column of them lines up on the\n// decimal point, and the medium weight that separates a figure from the prose\n// around it.\nconst styles = {\n base: {\n kMv6JI: \"xbppi91\",\n kcqcaj: \"xss6m8b\",\n k63SB2: \"x1bf3uqz\",\n $$css: true\n }\n};\nconst tones = {\n negative: {\n kMwMTN: \"x12gp0t\",\n $$css: true\n },\n neutral: {\n kMwMTN: \"x139gbkf\",\n $$css: true\n },\n positive: {\n kMwMTN: \"x4no3js\",\n $$css: true\n }\n};\n\n// U+2212 MINUS SIGN, not the U+002D hyphen Intl actually emits. The hyphen is\n// a typographic stand-in: it is narrower than the plus it pairs with and does\n// not sit on the same optical centre as the digits, which shows up as a\n// wobbling column the moment amounts are stacked.\nconst MINUS_SIGN = '−';\ntype CurrencyProps = Omit<useRender.ComponentProps<'span'>, 'children'> & {\n /**\n * ISO 4217 code for the currency to format in.\n * @default 'USD'\n */\n currency?: string;\n /**\n * BCP 47 locale to format for. Defaults to the runtime's own locale, so an\n * app that has not chosen one still formats the way its reader expects.\n */\n locale?: string;\n /**\n * When to show the sign. `auto` shows one only on negatives, `always` also\n * prefixes positives with a plus, and `never` shows neither — which leaves\n * colour as the only thing separating a credit from a debt, so reach for it\n * only where the direction is already stated some other way.\n * @default 'auto'\n */\n sign?: SignDisplay;\n /**\n * Which colour role to render in. `auto` follows the sign of `value`, with\n * zero reading as neutral.\n * @default 'auto'\n */\n tone?: Tone;\n /** The amount, in the currency's major units. */\n value: number;\n};\ntype SignDisplay = 'always' | 'auto' | 'never';\ntype Tone = 'auto' | 'negative' | 'neutral' | 'positive';\nfunction Currency({\n currency = 'USD',\n locale,\n render,\n sign = 'auto',\n tone = 'auto',\n value,\n ...props\n}: CurrencyProps) {\n // stylex.props() spreads after `props` for the same reason Text does it: it\n // wins over a consumer-supplied className rather than merging with one.\n return useRender({\n defaultTagName: 'span',\n props: {\n ...props,\n children: formatCurrency(value, {\n currency,\n locale,\n sign\n }),\n ...stylex.props(styles.base, tones[resolveTone(value, tone)])\n },\n render\n });\n}\n\n// formatToParts rather than a replace over the formatted string, so only the\n// sign is substituted. A blind replace would also hit a hyphen inside a\n// locale's currency name or grouping, and locales that wrap negatives in\n// parentheses have no minus to swap at all — both of which this leaves alone.\nfunction formatCurrency(value: number, options: {\n currency: string;\n locale: string | undefined;\n sign: SignDisplay;\n}) {\n return new Intl.NumberFormat(options.locale, {\n currency: options.currency,\n signDisplay: options.sign,\n style: 'currency'\n }).formatToParts(value).map(part => part.type === 'minusSign' ? MINUS_SIGN : part.value).join('');\n}\n\n// Zero is neither owed nor owing, so it takes the neutral role rather than\n// being forced into one of the two. Negative zero lands here too, which is\n// what a rounded-away debt should read as.\nfunction resolveTone(value: number, tone: Tone) {\n if (tone !== 'auto') {\n return tone;\n }\n if (value > 0) {\n return 'positive';\n }\n if (value < 0) {\n return 'negative';\n }\n return 'neutral';\n}\nexport type { CurrencyProps };\nexport default Currency;"],"mappings":";;;AAWA,MAAM,SAAS,EACb,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;AACT,EACF;AACA,MAAM,QAAQ;CACZ,UAAU;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAMA,MAAM,aAAa;AA+BnB,SAAS,SAAS,EAChB,WAAW,OACX,QACA,QACA,OAAO,QACP,OAAO,QACP,OACA,GAAG,WACa;CAGhB,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,UAAU,eAAe,OAAO;IAC9B;IACA;IACA;GACF,CAAC;GACD,GAAG,MAAa,OAAO,MAAM,MAAM,YAAY,OAAO,IAAI,EAAE;EAC9D;EACA;CACF,CAAC;AACH;AAMA,SAAS,eAAe,OAAe,SAIpC;CACD,OAAO,IAAI,KAAK,aAAa,QAAQ,QAAQ;EAC3C,UAAU,QAAQ;EAClB,aAAa,QAAQ;EACrB,OAAO;CACT,CAAC,CAAC,CAAC,cAAc,KAAK,CAAC,CAAC,KAAI,SAAQ,KAAK,SAAS,cAAc,aAAa,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE;AAClG;AAKA,SAAS,YAAY,OAAe,MAAY;CAC9C,IAAI,SAAS,QACX,OAAO;CAET,IAAI,QAAQ,GACV,OAAO;CAET,IAAI,QAAQ,GACV,OAAO;CAET,OAAO;AACT"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/currency/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, typography } from '../../tokens/design.tokens.stylex';\n\n// Deliberately sets no font-size. The same value turns up at several sizes —\n// inside a list row, as a heading-scale figure, as a total — differing in\n// nothing else, so the size is the container's decision. What must never vary\n// is here: the mono face, tabular figures so a column of them lines up on the\n// decimal point, and the medium weight that separates a figure from the prose\n// around it.\nconst styles = {\n base: {\n kB7OPa: \"x9f619\",\n kMv6JI: \"xbppi91\",\n kcqcaj: \"xss6m8b\",\n k63SB2: \"x1bf3uqz\",\n $$css: true\n }\n};\nconst tones = {\n negative: {\n kMwMTN: \"x12gp0t\",\n $$css: true\n },\n neutral: {\n kMwMTN: \"x139gbkf\",\n $$css: true\n },\n positive: {\n kMwMTN: \"x4no3js\",\n $$css: true\n }\n};\n\n// U+2212 MINUS SIGN, not the U+002D hyphen Intl actually emits. The hyphen is\n// a typographic stand-in: it is narrower than the plus it pairs with and does\n// not sit on the same optical centre as the digits, which shows up as a\n// wobbling column the moment amounts are stacked.\nconst MINUS_SIGN = '−';\ntype CurrencyProps = Omit<useRender.ComponentProps<'span'>, 'children'> & {\n /**\n * ISO 4217 code for the currency to format in.\n * @default 'USD'\n */\n currency?: string;\n /**\n * BCP 47 locale to format for. Defaults to the runtime's own locale, so an\n * app that has not chosen one still formats the way its reader expects.\n */\n locale?: string;\n /**\n * When to show the sign. `auto` shows one only on negatives, `always` also\n * prefixes positives with a plus, and `never` shows neither — which leaves\n * colour as the only thing separating a credit from a debt, so reach for it\n * only where the direction is already stated some other way.\n * @default 'auto'\n */\n sign?: SignDisplay;\n /**\n * Which colour role to render in. `auto` follows the sign of `value`, with\n * zero reading as neutral.\n * @default 'auto'\n */\n tone?: Tone;\n /** The amount, in the currency's major units. */\n value: number;\n};\ntype SignDisplay = 'always' | 'auto' | 'never';\ntype Tone = 'auto' | 'negative' | 'neutral' | 'positive';\nfunction Currency({\n currency = 'USD',\n locale,\n render,\n sign = 'auto',\n tone = 'auto',\n value,\n ...props\n}: CurrencyProps) {\n return useRender({\n defaultTagName: 'span',\n props: {\n ...props,\n children: formatCurrency(value, {\n currency,\n locale,\n sign\n }),\n ...mergeStyles(stylex.props(styles.base, tones[resolveTone(value, tone)]), props)\n },\n render\n });\n}\n\n// formatToParts rather than a replace over the formatted string, so only the\n// sign is substituted. A blind replace would also hit a hyphen inside a\n// locale's currency name or grouping, and locales that wrap negatives in\n// parentheses have no minus to swap at all — both of which this leaves alone.\nfunction formatCurrency(value: number, options: {\n currency: string;\n locale: string | undefined;\n sign: SignDisplay;\n}) {\n return new Intl.NumberFormat(options.locale, {\n currency: options.currency,\n signDisplay: options.sign,\n style: 'currency'\n }).formatToParts(value).map(part => part.type === 'minusSign' ? MINUS_SIGN : part.value).join('');\n}\n\n// Zero is neither owed nor owing, so it takes the neutral role rather than\n// being forced into one of the two. Negative zero lands here too, which is\n// what a rounded-away debt should read as.\nfunction resolveTone(value: number, tone: Tone) {\n if (tone !== 'auto') {\n return tone;\n }\n if (value > 0) {\n return 'positive';\n }\n if (value < 0) {\n return 'negative';\n }\n return 'neutral';\n}\nexport type { CurrencyProps };\nexport default Currency;"],"mappings":";;;;AAYA,MAAM,SAAS,EACb,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;AACT,EACF;AACA,MAAM,QAAQ;CACZ,UAAU;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAMA,MAAM,aAAa;AA+BnB,SAAS,SAAS,EAChB,WAAW,OACX,QACA,QACA,OAAO,QACP,OAAO,QACP,OACA,GAAG,WACa;CAChB,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,UAAU,eAAe,OAAO;IAC9B;IACA;IACA;GACF,CAAC;GACD,GAAG,YAAY,MAAa,OAAO,MAAM,MAAM,YAAY,OAAO,IAAI,EAAE,GAAG,OAAK;EAClF;EACA;CACF,CAAC;AACH;AAMA,SAAS,eAAe,OAAe,SAIpC;CACD,OAAO,IAAI,KAAK,aAAa,QAAQ,QAAQ;EAC3C,UAAU,QAAQ;EAClB,aAAa,QAAQ;EACrB,OAAO;CACT,CAAC,CAAC,CAAC,cAAc,KAAK,CAAC,CAAC,KAAI,SAAQ,KAAK,SAAS,cAAc,aAAa,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE;AAClG;AAKA,SAAS,YAAY,OAAe,MAAY;CAC9C,IAAI,SAAS,QACX,OAAO;CAET,IAAI,QAAQ,GACV,OAAO;CAET,IAAI,QAAQ,GACV,OAAO;CAET,OAAO;AACT"}
@@ -1,8 +1,10 @@
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/feed/index.tsx
4
5
  const DEFAULT_MIN_ITEM_WIDTH = "180px";
5
6
  const _temp = {
7
+ kB7OPa: "x9f619",
6
8
  k1xSpc: "xrvj5dj",
7
9
  kOIVth: "xj2l1yv",
8
10
  kumcoG: "xqketvx",
@@ -28,7 +30,7 @@ function Feed({ minItemWidth = DEFAULT_MIN_ITEM_WIDTH, render, ...props$1 }) {
28
30
  defaultTagName: "div",
29
31
  props: {
30
32
  ...props$1,
31
- ...props(styles.root(minItemWidth))
33
+ ...mergeStyles(props(styles.root(minItemWidth)), props$1)
32
34
  },
33
35
  render
34
36
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/feed/index.tsx"],"sourcesContent":["import { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport '../../tokens/design.tokens.stylex';\nimport { spacing } from '../../tokens/design.tokens.stylex';\n\n// Material 3's example minimum for an adaptive grid cell, and the only number\n// the spec puts on one. It is a floor rather than a recommendation: how narrow\n// a card can get before its contents stop making sense is a property of the\n// contents, which is why M3 leaves it a parameter rather than fixing it. Most\n// feeds should say what theirs is instead of taking this.\nconst DEFAULT_MIN_ITEM_WIDTH = '180px';\n\n// The third of Material 3's canonical layouts, after list-detail and\n// supporting pane. Where those two divide a page into panes, this arranges one\n// pane into a grid of comparable things — the spec's own examples are news and\n// social feeds, and a catalogue of cards is the same shape.\n//\n// M3 describes the grid by its cell rather than by its columns: Compose spells\n// it `GridCells.Adaptive(minSize)`, meaning every column is at least that wide\n// and the grid fits as many as it can. `repeat(auto-fill, minmax(…, 1fr))` is\n// the same sentence in CSS.\n//\n// So there are no breakpoints here, and that is the point rather than an\n// omission. The layout answers to the room it is given instead of to the width\n// of the window, which is what lets a feed inside a pane reflow with the pane.\n// It also means none of the query emission-order care that ListDetail and\n// SupportingPane both have to document applies.\n//\n// A function style rather than a static one, because the cell minimum comes\n// from the call site and StyleX compiles its classes ahead of time. StyleX\n// resolves that by writing the value to a custom property inline, which is the\n// same mechanism the token gallery's `durationBar` uses.\nconst _temp = {\n k1xSpc: \"xrvj5dj\",\n kOIVth: \"xj2l1yv\",\n kumcoG: \"xqketvx\",\n \"$$css\": true\n};\nconst styles = {\n root: (minItemWidth: string) => [_temp, {\n \"--x-gridTemplateColumns\": `repeat(auto-fill, minmax(${minItemWidth}, 1fr))` != null ? `repeat(auto-fill, minmax(${minItemWidth}, 1fr))` : undefined\n }]\n};\ntype FeedProps = useRender.ComponentProps<'div'> & {\n /**\n * How narrow a cell may get before the grid drops a column. Every column is\n * at least this wide and the grid fits as many as the space allows, which is\n * how M3 describes an adaptive grid — by its cell rather than by a column\n * count per breakpoint.\n *\n * Worth setting. The default is the figure M3's own example uses, and it is\n * a floor rather than advice: only the contents know how narrow they can go.\n * @default '180px'\n */\n minItemWidth?: string;\n};\n\n/**\n * Material 3's feed layout: a grid of comparable items that fits as many\n * columns as the space allows, down to a single column when it allows only\n * one.\n *\n * Layout only — it paints no surface, and it gives its children no container\n * of their own, so each child is a grid cell exactly as it was written. That\n * is the difference from ListDetail and SupportingPane, which do wrap: those\n * two divide a page into named regions, where this one lays out however many\n * things it is handed.\n *\n * It reads the space it is in rather than the width of the window, so a feed\n * inside a pane reflows with the pane rather than with the browser.\n */\nfunction Feed({\n minItemWidth = DEFAULT_MIN_ITEM_WIDTH,\n render,\n ...props\n}: FeedProps) {\n return useRender({\n defaultTagName: 'div',\n props: {\n ...props,\n // Spread last so the grid wins over a consumer-supplied className,\n // matching Text, Badge and Card. The dynamic style carries the cell\n // minimum as a custom property, so this also has to come after `props`\n // for that value to survive.\n ...stylex.props(styles.root(minItemWidth))\n },\n render\n });\n}\nexport type { FeedProps };\nexport default Feed;"],"mappings":";;;AAUA,MAAM,yBAAyB;AAsB/B,MAAM,QAAQ;CACZ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;AACX;AACA,MAAM,SAAS,EACb,OAAO,iBAAyB,CAAC,OAAO,EACtC,2BAA2B,4BAA4B,aAAY,YAAa,OAAO,4BAA4B,aAAY,WAAY,KAAA,EAC7I,CAAC,EACH;;;;;;;;;;;;;;;AA6BA,SAAS,KAAK,EACZ,eAAe,wBACf,QACA,GAAG,WACS;CACZ,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GAKH,GAAG,MAAa,OAAO,KAAK,YAAY,CAAC;EAC3C;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/feed/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 { spacing } from '../../tokens/design.tokens.stylex';\n\n// Material 3's example minimum for an adaptive grid cell, and the only number\n// the spec puts on one. It is a floor rather than a recommendation: how narrow\n// a card can get before its contents stop making sense is a property of the\n// contents, which is why M3 leaves it a parameter rather than fixing it. Most\n// feeds should say what theirs is instead of taking this.\nconst DEFAULT_MIN_ITEM_WIDTH = '180px';\n\n// The third of Material 3's canonical layouts, after list-detail and\n// supporting pane. Where those two divide a page into panes, this arranges one\n// pane into a grid of comparable things — the spec's own examples are news and\n// social feeds, and a catalogue of cards is the same shape.\n//\n// M3 describes the grid by its cell rather than by its columns: Compose spells\n// it `GridCells.Adaptive(minSize)`, meaning every column is at least that wide\n// and the grid fits as many as it can. `repeat(auto-fill, minmax(…, 1fr))` is\n// the same sentence in CSS.\n//\n// So there are no breakpoints here, and that is the point rather than an\n// omission. The layout answers to the room it is given instead of to the width\n// of the window, which is what lets a feed inside a pane reflow with the pane.\n// It also means none of the query emission-order care that ListDetail and\n// SupportingPane both have to document applies.\n//\n// A function style rather than a static one, because the cell minimum comes\n// from the call site and StyleX compiles its classes ahead of time. StyleX\n// resolves that by writing the value to a custom property inline, which is the\n// same mechanism the token gallery's `durationBar` uses.\nconst _temp = {\n kB7OPa: \"x9f619\",\n k1xSpc: \"xrvj5dj\",\n kOIVth: \"xj2l1yv\",\n kumcoG: \"xqketvx\",\n \"$$css\": true\n};\nconst styles = {\n root: (minItemWidth: string) => [_temp, {\n \"--x-gridTemplateColumns\": `repeat(auto-fill, minmax(${minItemWidth}, 1fr))` != null ? `repeat(auto-fill, minmax(${minItemWidth}, 1fr))` : undefined\n }]\n};\ntype FeedProps = useRender.ComponentProps<'div'> & {\n /**\n * How narrow a cell may get before the grid drops a column. Every column is\n * at least this wide and the grid fits as many as the space allows, which is\n * how M3 describes an adaptive grid — by its cell rather than by a column\n * count per breakpoint.\n *\n * Worth setting. The default is the figure M3's own example uses, and it is\n * a floor rather than advice: only the contents know how narrow they can go.\n * @default '180px'\n */\n minItemWidth?: string;\n};\n\n/**\n * Material 3's feed layout: a grid of comparable items that fits as many\n * columns as the space allows, down to a single column when it allows only\n * one.\n *\n * Layout only — it paints no surface, and it gives its children no container\n * of their own, so each child is a grid cell exactly as it was written. That\n * is the difference from ListDetail and SupportingPane, which do wrap: those\n * two divide a page into named regions, where this one lays out however many\n * things it is handed.\n *\n * It reads the space it is in rather than the width of the window, so a feed\n * inside a pane reflows with the pane rather than with the browser.\n */\nfunction Feed({\n minItemWidth = DEFAULT_MIN_ITEM_WIDTH,\n render,\n ...props\n}: FeedProps) {\n return useRender({\n defaultTagName: 'div',\n props: {\n ...props,\n // The dynamic style carries the cell minimum as a custom property in\n // `style` rather than as a class, which is why the merge has to reach\n // `style` as well as `className` — see src/styles/merge.ts.\n ...mergeStyles(stylex.props(styles.root(minItemWidth)), props)\n },\n render\n });\n}\nexport type { FeedProps };\nexport default Feed;"],"mappings":";;;;AAWA,MAAM,yBAAyB;AAsB/B,MAAM,QAAQ;CACZ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;AACX;AACA,MAAM,SAAS,EACb,OAAO,iBAAyB,CAAC,OAAO,EACtC,2BAA2B,4BAA4B,aAAY,YAAa,OAAO,4BAA4B,aAAY,WAAY,KAAA,EAC7I,CAAC,EACH;;;;;;;;;;;;;;;AA6BA,SAAS,KAAK,EACZ,eAAe,wBACf,QACA,GAAG,WACS;CACZ,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GAIH,GAAG,YAAY,MAAa,OAAO,KAAK,YAAY,CAAC,GAAG,OAAK;EAC/D;EACA;CACF,CAAC;AACH"}
@@ -1,6 +1,6 @@
1
1
  import { ButtonProps } from "@base-ui/react/button";
2
2
  //#region src/components/icon-button/index.d.ts
3
- type IconButtonProps = ButtonProps & {
3
+ type IconButtonProps = {
4
4
  /**
5
5
  * What the button does, in words. Required rather than optional: an icon
6
6
  * on its own has no accessible name, so without this the control announces
@@ -13,6 +13,23 @@ type IconButtonProps = ButtonProps & {
13
13
  * @default false
14
14
  */
15
15
  disableRipple?: boolean;
16
+ /**
17
+ * Whether the element `render` produces is a real `<button>`, which decides
18
+ * whether Base UI supplies the button role, keyboard activation and
19
+ * disabled semantics itself.
20
+ *
21
+ * Read off `render` when that is a plain element, so
22
+ * `render={<a href="…" />}` needs nothing here. Worth setting only when
23
+ * `render` is a component or a function, where the tag it will produce
24
+ * cannot be read ahead of time.
25
+ *
26
+ * An anchor rendered this way is announced as a button rather than as a
27
+ * link, since that is what Base UI's non-native mode applies. For a control
28
+ * that should be announced as the link it is, reach for `Link`, or `Card`
29
+ * with `render`, neither of which imposes button semantics.
30
+ * @default true
31
+ */
32
+ nativeButton?: boolean;
16
33
  /**
17
34
  * Control size: `xs` 32px, `md` 40px, `lg` 56px — the same heights `Button`
18
35
  * uses, so the two line up beside each other in a row.
@@ -25,8 +42,8 @@ type IconButtonProps = ButtonProps & {
25
42
  * @default 'standard'
26
43
  */
27
44
  variant?: 'filled' | 'standard' | 'tonal';
28
- };
29
- declare function IconButton({ children, disabled, disableRipple, onClick, onContextMenu, onPointerCancel, onPointerDown, onPointerLeave, onPointerUp, size, variant, ...props }: IconButtonProps): import("react").JSX.Element;
45
+ } & ButtonProps;
46
+ declare function IconButton({ children, disabled, disableRipple, nativeButton, onClick, onContextMenu, onPointerCancel, onPointerDown, onPointerLeave, onPointerUp, size, variant, ...props }: IconButtonProps): import("react").JSX.Element;
30
47
  //#endregion
31
48
  export { type IconButtonProps, IconButton as default };
32
49
  //# 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/icon-button/index.tsx
@@ -8,6 +10,7 @@ const styles = {
8
10
  kGNEyG: "x6s0dn4",
9
11
  kaIpWk: "xtecew7 x3y1ksm",
10
12
  kMzoRj: "xc342km",
13
+ kB7OPa: "x9f619",
11
14
  kkrTdU: "x1s07b3s x1ypdohk",
12
15
  k1xSpc: "x3nfvp2",
13
16
  kmuXW: "x2lah0s",
@@ -18,6 +21,7 @@ const styles = {
18
21
  kMeerF: "x1de99jn",
19
22
  kmVPX3: "x1717udv",
20
23
  kVAEAm: "x1n2onr6",
24
+ kybGjl: "x1hl2dhg",
21
25
  kIyJzY: "x1iuyhda",
22
26
  k1ekBW: "xb5u718",
23
27
  kAMwcw: "x15l9jch",
@@ -57,7 +61,7 @@ const styles = {
57
61
  $$css: true
58
62
  }
59
63
  };
60
- function IconButton({ children, disabled = false, disableRipple = false, onClick, onContextMenu, onPointerCancel, onPointerDown, onPointerLeave, onPointerUp, size = "md", variant = "standard", ...props$1 }) {
64
+ function IconButton({ children, disabled = false, disableRipple = false, nativeButton, onClick, onContextMenu, onPointerCancel, onPointerDown, onPointerLeave, onPointerUp, size = "md", variant = "standard", ...props$1 }) {
61
65
  const ripple = useRipple(!disableRipple, {
62
66
  onClick,
63
67
  onContextMenu,
@@ -68,9 +72,10 @@ function IconButton({ children, disabled = false, disableRipple = false, onClick
68
72
  });
69
73
  return /* @__PURE__ */ jsxs(Button, {
70
74
  disabled,
75
+ nativeButton: nativeButton ?? rendersNativeButton(props$1.render),
71
76
  ...ripple.handlers,
72
77
  ...props$1,
73
- ...props(styles.base, styles[variant], styles[size]),
78
+ ...mergeStatefulStyles(props(styles.base, styles[variant], styles[size]), props$1),
74
79
  children: [children, ripple.surface]
75
80
  });
76
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/icon-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, motion, radii, stateLayerOpacity } from '../../tokens/design.tokens.stylex';\n\n// Each variant composites an 'on-color' over its own container at the\n// interaction state's opacity, rather than swapping in a separate hover\n// color. calc(<opacity> * 100%) turns the token's unitless 0-1 ratio into the\n// percentage color-mix() takes. Inlined at each property rather than factored\n// into a helper: @stylexjs/babel-plugin only statically recognizes\n// expressions written directly as property values.\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 disabled button would render with the\n// interaction color instead of the disabled one.\n//\n// The corner softens from a circle to a rounded square while pressed, which\n// is the shape morph the source design gives this control. The two\n// transitioned properties take different curves — the colour change is\n// linear-ish and the shape change is emphasized — so the timing functions are\n// a matching comma list rather than one value.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"xtecew7 x3y1ksm\",\n kMzoRj: \"xc342km\",\n kkrTdU: \"x1s07b3s x1ypdohk\",\n k1xSpc: \"x3nfvp2\",\n kmuXW: \"x2lah0s\",\n kjj79g: \"xl56j7k\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kmVPX3: \"x1717udv\",\n kVAEAm: \"x1n2onr6\",\n kIyJzY: \"x1iuyhda\",\n k1ekBW: \"xb5u718\",\n kAMwcw: \"x15l9jch\",\n $$css: true\n },\n filled: {\n kWkggS: \"xm7dzmu x1n0xrd1 x197hsbc xnety89\",\n kMwMTN: \"xhfb3ry xwjo7ld\",\n $$css: true\n },\n lg: {\n kZKoxP: \"xnnlda6\",\n kGuDYH: \"x1s3cmhv\",\n kzqmXN: \"x15yg21f\",\n $$css: true\n },\n md: {\n kZKoxP: \"x1vqgdyp\",\n kGuDYH: \"x1pvqxga\",\n kzqmXN: \"x100vrsf\",\n $$css: true\n },\n standard: {\n kWkggS: \"x1a42vn9 x6gcojk xjbqb8w\",\n kMwMTN: \"xhfb3ry x1w5n3ug\",\n $$css: true\n },\n tonal: {\n kWkggS: \"x1c3n7wt x1n0xrd1 xwypj8i xp89om9\",\n kMwMTN: \"xhfb3ry xscdzaa\",\n $$css: true\n },\n xs: {\n kZKoxP: \"x10w6t97\",\n kGuDYH: \"xwsyq91\",\n kzqmXN: \"x1td3qas\",\n $$css: true\n }\n};\ntype IconButtonProps = BaseUIButtonProps & {\n /**\n * What the button does, in words. Required rather than optional: an icon\n * on its own has no accessible name, so without this the control announces\n * nothing at all.\n */\n 'aria-label': string;\n /**\n * Disables the press ripple. The hover and pressed state layers are\n * unaffected.\n * @default false\n */\n disableRipple?: boolean;\n /**\n * Control size: `xs` 32px, `md` 40px, `lg` 56px — the same heights `Button`\n * uses, so the two line up beside each other in a row.\n * @default 'md'\n */\n size?: 'lg' | 'md' | 'xs';\n /**\n * `standard` is transparent and tints what it sits on; `filled` and `tonal`\n * carry a container of their own.\n * @default 'standard'\n */\n variant?: 'filled' | 'standard' | 'tonal';\n};\nfunction IconButton({\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 = 'standard',\n ...props\n}: IconButtonProps) {\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 { IconButtonProps };\nexport default IconButton;"],"mappings":";;;;;AAwBA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,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,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,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AA2BA,SAAS,WAAW,EAClB,UACA,WAAW,OACX,gBAAgB,OAChB,SACA,eACA,iBACA,eACA,gBACA,aACA,OAAO,MACP,UAAU,YACV,GAAG,WACe;CAIlB,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/icon-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, motion, radii, stateLayerOpacity } from '../../tokens/design.tokens.stylex';\n\n// Each variant composites an 'on-color' over its own container at the\n// interaction state's opacity, rather than swapping in a separate hover\n// color. calc(<opacity> * 100%) turns the token's unitless 0-1 ratio into the\n// percentage color-mix() takes. Inlined at each property rather than factored\n// into a helper: @stylexjs/babel-plugin only statically recognizes\n// expressions written directly as property values.\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 disabled button would render with the\n// interaction color instead of the disabled one.\n//\n// The corner softens from a circle to a rounded square while pressed, which\n// is the shape morph the source design gives this control. The two\n// transitioned properties take different curves — the colour change is\n// linear-ish and the shape change is emphasized — so the timing functions are\n// a matching comma list rather than one value.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"xtecew7 x3y1ksm\",\n kMzoRj: \"xc342km\",\n kB7OPa: \"x9f619\",\n kkrTdU: \"x1s07b3s x1ypdohk\",\n k1xSpc: \"x3nfvp2\",\n kmuXW: \"x2lah0s\",\n kjj79g: \"xl56j7k\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kmVPX3: \"x1717udv\",\n kVAEAm: \"x1n2onr6\",\n kybGjl: \"x1hl2dhg\",\n kIyJzY: \"x1iuyhda\",\n k1ekBW: \"xb5u718\",\n kAMwcw: \"x15l9jch\",\n $$css: true\n },\n filled: {\n kWkggS: \"xm7dzmu x1n0xrd1 x197hsbc xnety89\",\n kMwMTN: \"xhfb3ry xwjo7ld\",\n $$css: true\n },\n lg: {\n kZKoxP: \"xnnlda6\",\n kGuDYH: \"x1s3cmhv\",\n kzqmXN: \"x15yg21f\",\n $$css: true\n },\n md: {\n kZKoxP: \"x1vqgdyp\",\n kGuDYH: \"x1pvqxga\",\n kzqmXN: \"x100vrsf\",\n $$css: true\n },\n standard: {\n kWkggS: \"x1a42vn9 x6gcojk xjbqb8w\",\n kMwMTN: \"xhfb3ry x1w5n3ug\",\n $$css: true\n },\n tonal: {\n kWkggS: \"x1c3n7wt x1n0xrd1 xwypj8i xp89om9\",\n kMwMTN: \"xhfb3ry xscdzaa\",\n $$css: true\n },\n xs: {\n kZKoxP: \"x10w6t97\",\n kGuDYH: \"xwsyq91\",\n kzqmXN: \"x1td3qas\",\n $$css: true\n }\n};\ntype IconButtonProps = {\n /**\n * What the button does, in words. Required rather than optional: an icon\n * on its own has no accessible name, so without this the control announces\n * nothing at all.\n */\n 'aria-label': string;\n /**\n * Disables the press ripple. The hover and pressed state layers are\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 size: `xs` 32px, `md` 40px, `lg` 56px — the same heights `Button`\n * uses, so the two line up beside each other in a row.\n * @default 'md'\n */\n size?: 'lg' | 'md' | 'xs';\n /**\n * `standard` is transparent and tints what it sits on; `filled` and `tonal`\n * carry a container of their own.\n * @default 'standard'\n */\n variant?: 'filled' | 'standard' | 'tonal';\n} & BaseUIButtonProps;\nfunction IconButton({\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 = 'standard',\n ...props\n}: IconButtonProps) {\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 { IconButtonProps };\nexport default IconButton;"],"mappings":";;;;;;;AA0BA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,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,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,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AA4CA,SAAS,WAAW,EAClB,UACA,WAAW,OACX,gBAAgB,OAChB,cACA,SACA,eACA,iBACA,eACA,gBACA,aACA,OAAO,MACP,UAAU,YACV,GAAG,WACe;CAMlB,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,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/keycap/index.tsx
@@ -7,44 +8,55 @@ import { c } from "react/compiler-runtime";
7
8
  * chord is several of these, combined at the call site.
8
9
  */
9
10
  function Keycap(t0) {
10
- const $ = c(9);
11
- let props;
11
+ const $ = c(13);
12
12
  let render;
13
+ let t1;
14
+ let t2;
15
+ let t3;
16
+ let t4;
13
17
  if ($[0] !== t0) {
14
- ({render, ...props} = t0);
18
+ const { render: t5, ...props } = t0;
19
+ render = t5;
20
+ t4 = useRender;
21
+ t3 = "kbd";
22
+ t1 = props;
23
+ t2 = mergeStyles({ className: "xjbqb8w x1fwvt7v x1tfhd1 x1y0btm7 xmkeg23 x9f619 x139gbkf x1rg5ohu xbppi91 xuegzgz x37zpob xt970qd xdomwbk xuxw1ft" }, props);
15
24
  $[0] = t0;
16
- $[1] = props;
17
- $[2] = render;
25
+ $[1] = render;
26
+ $[2] = t1;
27
+ $[3] = t2;
28
+ $[4] = t3;
29
+ $[5] = t4;
18
30
  } else {
19
- props = $[1];
20
- render = $[2];
31
+ render = $[1];
32
+ t1 = $[2];
33
+ t2 = $[3];
34
+ t3 = $[4];
35
+ t4 = $[5];
21
36
  }
22
- let t1;
23
- if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
24
- t1 = { className: "xjbqb8w x1fwvt7v x1tfhd1 x1y0btm7 xmkeg23 x139gbkf x1rg5ohu xbppi91 xuegzgz x37zpob xt970qd xdomwbk xuxw1ft" };
25
- $[3] = t1;
26
- } else t1 = $[3];
27
- let t2;
28
- if ($[4] !== props) {
29
- t2 = {
30
- ...props,
31
- ...t1
37
+ let t5;
38
+ if ($[6] !== t1 || $[7] !== t2) {
39
+ t5 = {
40
+ ...t1,
41
+ ...t2
32
42
  };
33
- $[4] = props;
34
- $[5] = t2;
35
- } else t2 = $[5];
36
- let t3;
37
- if ($[6] !== render || $[7] !== t2) {
38
- t3 = {
39
- defaultTagName: "kbd",
40
- props: t2,
43
+ $[6] = t1;
44
+ $[7] = t2;
45
+ $[8] = t5;
46
+ } else t5 = $[8];
47
+ let t6;
48
+ if ($[9] !== render || $[10] !== t3 || $[11] !== t5) {
49
+ t6 = {
50
+ defaultTagName: t3,
51
+ props: t5,
41
52
  render
42
53
  };
43
- $[6] = render;
44
- $[7] = t2;
45
- $[8] = t3;
46
- } else t3 = $[8];
47
- return useRender(t3);
54
+ $[9] = render;
55
+ $[10] = t3;
56
+ $[11] = t5;
57
+ $[12] = t6;
58
+ } else t6 = $[12];
59
+ return t4(t6);
48
60
  }
49
61
  //#endregion
50
62
  export { Keycap as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/keycap/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// Named for the physical thing it draws rather than for the element it\n// renders. `Kbd` would match the tag, but a component library is read by\n// people writing call sites, not markup, and `Key` in that setting is already\n// spoken for several times over — an API key, an object key, React's own key\n// prop. A keycap is unambiguously the one on a keyboard.\n//\n// Sized in em for the same reason Code is: a key named inside a footnote and\n// one named inside a paragraph are the same component. The ratio is smaller\n// than Code's because the border adds height that the glyphs do not, and\n// matching Code's 0.875 leaves a keycap standing taller than the line it\n// sits in.\n//\n// Transparent rather than filled, so a keycap inside a Card or a Sheet does\n// not read as a nested surface. The border alone carries the metaphor.\n\ntype KeycapProps = useRender.ComponentProps<'kbd'>;\n\n/**\n * A single key on a keyboard, as named in an instruction — `Enter`, `Esc`,\n * `Ctrl`. It renders a `<kbd>` and takes its scale from the text around it. A\n * chord is several of these, combined at the call site.\n */\nfunction Keycap({\n render,\n ...props\n}: KeycapProps) {\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, so which of the two applies is not left to stylesheet order.\n return useRender({\n defaultTagName: 'kbd',\n props: {\n ...props,\n ...{\n className: \"xjbqb8w x1fwvt7v x1tfhd1 x1y0btm7 xmkeg23 x139gbkf x1rg5ohu xbppi91 xuegzgz x37zpob xt970qd xdomwbk xuxw1ft\"\n }\n },\n render\n });\n}\nexport type { KeycapProps };\nexport default Keycap;"],"mappings":";;;;;;;;AA2BA,SAAA,OAAA,IAAA;CAAA,MAAA,IAAA,EAAA,CAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,IAAA;EAAgB,CAAA,CAAA,QAAA,GAAA,SAAA;EAGF,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA;EAAA,QAAA,EAAA;EAAA,SAAA,EAAA;CAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,OAAA,IAAA,2BAAA,GAAA;EAQL,KAAA,EAAA,WACU,8GACb;EAAC,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,OAAA;EAJI,KAAA;GAAA,GACF;GAAK,GACL;EAGL;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,UAAA,EAAA,OAAA,IAAA;EAPc,KAAA;GAAA,gBACC;GAAK,OACd;GAKN;EAEH;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OATM,UAAU,EAShB;AAAC"}
1
+ {"version":3,"file":"index.js","names":["useRender","props"],"sources":["../../../src/components/keycap/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// Named for the physical thing it draws rather than for the element it\n// renders. `Kbd` would match the tag, but a component library is read by\n// people writing call sites, not markup, and `Key` in that setting is already\n// spoken for several times over — an API key, an object key, React's own key\n// prop. A keycap is unambiguously the one on a keyboard.\n//\n// Sized in em for the same reason Code is: a key named inside a footnote and\n// one named inside a paragraph are the same component. The ratio is smaller\n// than Code's because the border adds height that the glyphs do not, and\n// matching Code's 0.875 leaves a keycap standing taller than the line it\n// sits in.\n//\n// Transparent rather than filled, so a keycap inside a Card or a Sheet does\n// not read as a nested surface. The border alone carries the metaphor.\n\ntype KeycapProps = useRender.ComponentProps<'kbd'>;\n\n/**\n * A single key on a keyboard, as named in an instruction — `Enter`, `Esc`,\n * `Ctrl`. It renders a `<kbd>` and takes its scale from the text around it. A\n * chord is several of these, combined at the call site.\n */\nfunction Keycap({\n render,\n ...props\n}: KeycapProps) {\n return useRender({\n defaultTagName: 'kbd',\n props: {\n ...props,\n ...mergeStyles({\n className: \"xjbqb8w x1fwvt7v x1tfhd1 x1y0btm7 xmkeg23 x9f619 x139gbkf x1rg5ohu xbppi91 xuegzgz x37zpob xt970qd xdomwbk xuxw1ft\"\n }, props)\n },\n render\n });\n}\nexport type { KeycapProps };\nexport default Keycap;"],"mappings":";;;;;;;;;AA4BA,SAAA,OAAA,IAAA;CAAA,MAAA,IAAA,EAAA,EAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,IAAA;EAAgB,MAAA,EAAA,QAAA,IAAA,GAAA,UAAA;EAAA,SAAA;EAIPA,KAAA;EACW,KAAA;EAEXC,KAAA;EACA,KAAA,YAAY,EAAA,WACF,qHACb,GAAG,KAAK;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA;EAAA,SAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;CAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,EAAA,OAAA,IAAA;EAJJ,KAAA;GAAA,GACFA;GAAK,GACL;EAGL;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,UAAA,EAAA,QAAA,MAAA,EAAA,QAAA,IAAA;EAPc,KAAA;GAAA,gBACC;GAAK,OACd;GAKN;EAEH;EAAC,EAAA,KAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OATMD,GAAU,EAShB;AAAC"}
@@ -1,8 +1,10 @@
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/link/index.tsx
4
5
  const styles = { base: {
5
6
  kaIpWk: "x1tfhd1",
7
+ kB7OPa: "x9f619",
6
8
  kkrTdU: "x1ypdohk",
7
9
  kjBf7l: "xrgy624",
8
10
  kInvED: "x1hl8ikr",
@@ -50,7 +52,7 @@ function Link({ render, tone = "primary", underline = "always", ...props$1 }) {
50
52
  defaultTagName: "a",
51
53
  props: {
52
54
  ...props$1,
53
- ...props(styles.base, tones[tone], underlines[underline])
55
+ ...mergeStyles(props(styles.base, tones[tone], underlines[underline]), props$1)
54
56
  },
55
57
  render
56
58
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/link/index.tsx"],"sourcesContent":["import { useRender } from '@base-ui/react/use-render';\nimport * as stylex from '@stylexjs/stylex';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, motion, radii } from '../../tokens/design.tokens.stylex';\n\n// Deliberately sets no font size or family. A link is nearly always a run of\n// words inside something else — a paragraph, a list, a table cell — so its\n// type is the surrounding text's decision. What is here is only what makes it\n// read as a link: the colour, the rule under it, and the focus ring.\n//\n// The underline is on by default rather than an opt-in. Colour alone fails\n// anyone who cannot separate the two hues, so a link in prose that is not\n// underlined is only distinguishable to some readers.\nconst styles = {\n base: {\n kaIpWk: \"x1tfhd1\",\n kkrTdU: \"x1ypdohk\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kNySMw: \"xyi4chj\",\n kcSHmL: \"x1ohr1zr\",\n kIyJzY: \"x1qno0dh\",\n k1ekBW: \"xz1df8t\",\n kAMwcw: \"xpc4ca7\",\n $$css: true\n }\n};\n\n// Each tone gets a hover that means something. `primary` is already the accent\n// colour, so hovering it deepens the rule instead of restating the colour;\n// `inherit` sits in body text, so hovering moves it to the accent — which is\n// what tells the reader the words are a link and not emphasis.\nconst tones = {\n inherit: {\n kMwMTN: \"x1aetzt3 x1heor9g\",\n k1TLXF: \"x1rdisx9 x1dbr5dg\",\n $$css: true\n },\n primary: {\n kMwMTN: \"x1mxwv8y\",\n k1TLXF: \"x1rdisx9 xfhk6l2\",\n $$css: true\n }\n};\nconst underlines = {\n always: {\n kMnn75: \"xujl8zx\",\n $$css: true\n },\n hover: {\n kMnn75: \"x1sur9pj xkrqix3\",\n $$css: true\n },\n none: {\n kMnn75: \"xkrqix3\",\n $$css: true\n }\n};\ntype LinkProps = {\n /**\n * Which colour role to render in. `primary` marks the link out from the\n * text around it; `inherit` takes the surrounding colour and leans on the\n * underline alone, for a link in a place already understood to be links —\n * a footer, a breadcrumb, a nav.\n * @default 'primary'\n */\n tone?: LinkTone;\n /**\n * When to draw the rule. Leave it at `always` in prose: without it, colour\n * is the only thing separating the link from the sentence, which some\n * readers cannot see. `hover` and `none` are for links whose position\n * already announces them, such as a row of footer links.\n * @default 'always'\n */\n underline?: LinkUnderline;\n} & useRender.ComponentProps<'a'>;\ntype LinkTone = 'inherit' | 'primary';\ntype LinkUnderline = 'always' | 'hover' | 'none';\n\n/**\n * A navigational link. It renders an `<a>` and sets no type of its own, so it\n * takes the size and face of the text it sits in.\n */\nfunction Link({\n render,\n tone = 'primary',\n underline = 'always',\n ...props\n}: LinkProps) {\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, so which of the two applies is not left to stylesheet order.\n return useRender({\n defaultTagName: 'a',\n props: {\n ...props,\n ...stylex.props(styles.base, tones[tone], underlines[underline])\n },\n render\n });\n}\nexport type { LinkProps };\nexport default Link;"],"mappings":";;;AAaA,MAAM,SAAS,EACb,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;AACT,EACF;AAMA,MAAM,QAAQ;CACZ,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AACA,MAAM,aAAa;CACjB,QAAQ;EACN,QAAQ;EACR,OAAO;CACT;CACA,OAAO;EACL,QAAQ;EACR,OAAO;CACT;CACA,MAAM;EACJ,QAAQ;EACR,OAAO;CACT;AACF;;;;;AA0BA,SAAS,KAAK,EACZ,QACA,OAAO,WACP,YAAY,UACZ,GAAG,WACS;CAIZ,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,GAAG,MAAa,OAAO,MAAM,MAAM,OAAO,WAAW,UAAU;EACjE;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/link/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, motion, radii } from '../../tokens/design.tokens.stylex';\n\n// Deliberately sets no font size or family. A link is nearly always a run of\n// words inside something else — a paragraph, a list, a table cell — so its\n// type is the surrounding text's decision. What is here is only what makes it\n// read as a link: the colour, the rule under it, and the focus ring.\n//\n// The underline is on by default rather than an opt-in. Colour alone fails\n// anyone who cannot separate the two hues, so a link in prose that is not\n// underlined is only distinguishable to some readers.\nconst styles = {\n base: {\n kaIpWk: \"x1tfhd1\",\n kB7OPa: \"x9f619\",\n kkrTdU: \"x1ypdohk\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kNySMw: \"xyi4chj\",\n kcSHmL: \"x1ohr1zr\",\n kIyJzY: \"x1qno0dh\",\n k1ekBW: \"xz1df8t\",\n kAMwcw: \"xpc4ca7\",\n $$css: true\n }\n};\n\n// Each tone gets a hover that means something. `primary` is already the accent\n// colour, so hovering it deepens the rule instead of restating the colour;\n// `inherit` sits in body text, so hovering moves it to the accent — which is\n// what tells the reader the words are a link and not emphasis.\nconst tones = {\n inherit: {\n kMwMTN: \"x1aetzt3 x1heor9g\",\n k1TLXF: \"x1rdisx9 x1dbr5dg\",\n $$css: true\n },\n primary: {\n kMwMTN: \"x1mxwv8y\",\n k1TLXF: \"x1rdisx9 xfhk6l2\",\n $$css: true\n }\n};\nconst underlines = {\n always: {\n kMnn75: \"xujl8zx\",\n $$css: true\n },\n hover: {\n kMnn75: \"x1sur9pj xkrqix3\",\n $$css: true\n },\n none: {\n kMnn75: \"xkrqix3\",\n $$css: true\n }\n};\ntype LinkProps = {\n /**\n * Which colour role to render in. `primary` marks the link out from the\n * text around it; `inherit` takes the surrounding colour and leans on the\n * underline alone, for a link in a place already understood to be links —\n * a footer, a breadcrumb, a nav.\n * @default 'primary'\n */\n tone?: LinkTone;\n /**\n * When to draw the rule. Leave it at `always` in prose: without it, colour\n * is the only thing separating the link from the sentence, which some\n * readers cannot see. `hover` and `none` are for links whose position\n * already announces them, such as a row of footer links.\n * @default 'always'\n */\n underline?: LinkUnderline;\n} & useRender.ComponentProps<'a'>;\ntype LinkTone = 'inherit' | 'primary';\ntype LinkUnderline = 'always' | 'hover' | 'none';\n\n/**\n * A navigational link. It renders an `<a>` and sets no type of its own, so it\n * takes the size and face of the text it sits in.\n */\nfunction Link({\n render,\n tone = 'primary',\n underline = 'always',\n ...props\n}: LinkProps) {\n return useRender({\n defaultTagName: 'a',\n props: {\n ...props,\n ...mergeStyles(stylex.props(styles.base, tones[tone], underlines[underline]), props)\n },\n render\n });\n}\nexport type { LinkProps };\nexport default Link;"],"mappings":";;;;AAcA,MAAM,SAAS,EACb,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;AACT,EACF;AAMA,MAAM,QAAQ;CACZ,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AACA,MAAM,aAAa;CACjB,QAAQ;EACN,QAAQ;EACR,OAAO;CACT;CACA,OAAO;EACL,QAAQ;EACR,OAAO;CACT;CACA,MAAM;EACJ,QAAQ;EACR,OAAO;CACT;AACF;;;;;AA0BA,SAAS,KAAK,EACZ,QACA,OAAO,WACP,YAAY,UACZ,GAAG,WACS;CACZ,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,GAAG,YAAY,MAAa,OAAO,MAAM,MAAM,OAAO,WAAW,UAAU,GAAG,OAAK;EACrF;EACA;CACF,CAAC;AACH"}
@@ -1,3 +1,4 @@
1
+ import { mergeStyles } from "../../styles/merge.js";
1
2
  import { useRender } from "@base-ui/react/use-render";
2
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
4
  //#region src/components/list-detail/index.tsx
@@ -20,18 +21,18 @@ function ListDetail({ detail, list, render, showing = "list", ...props }) {
20
21
  ...props,
21
22
  children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
22
23
  ...{
23
- 0: { className: "xeuugli" },
24
- 1: { className: "xeuugli x1s85apg x9a4l8x" }
24
+ 0: { className: "x9f619 xeuugli" },
25
+ 1: { className: "x9f619 xeuugli x1s85apg x9a4l8x" }
25
26
  }[!!(showing === "detail") << 0],
26
27
  children: list
27
28
  }), /* @__PURE__ */ jsx("div", {
28
29
  ...{
29
- 0: { className: "xeuugli" },
30
- 1: { className: "xeuugli x1s85apg x9a4l8x" }
30
+ 0: { className: "x9f619 xeuugli" },
31
+ 1: { className: "x9f619 xeuugli x1s85apg x9a4l8x" }
31
32
  }[!!(showing === "list") << 0],
32
33
  children: detail
33
34
  })] }),
34
- className: "xrvj5dj xj2l1yv x1mkdm3x xkgydl7 xxxc7o5"
35
+ ...mergeStyles({ className: "x9f619 xrvj5dj xj2l1yv x1mkdm3x xkgydl7 xxxc7o5" }, props)
35
36
  },
36
37
  render
37
38
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/list-detail/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 { media, spacing } from '../../tokens/design.tokens.stylex';\n\n// Material 3's recommended snap widths for a fixed pane. The list is the\n// fixed one here — M3 points a fixed pane at \"lists with light information\n// density\" — and the detail pane is the flexible one that absorbs whatever is\n// left, which satisfies the spec's rule that every layout carry at least one\n// flexible pane.\nconst LIST_PANE = '360px';\nconst LIST_PANE_EXTRA_LARGE = '412px';\n\n// One of Material 3's canonical layouts, and the fixed-and-flexible shape of\n// its two-pane layouts. Unlike SupportingPane, the detail pane here stands on\n// its own: a message, a product, a file. That is what makes showing it\n// *instead of* the list a coherent thing to do when only one pane fits, and\n// why this layout has to be told which pane is showing while SupportingPane\n// does not.\n//\n// M3 puts the second pane on screen from expanded up. Below that the spec\n// shows one pane at a time, with selecting an item swapping to the detail and\n// back returning to the list — app navigation rather than layout, which is\n// why `showing` is controlled rather than held here.\n\ntype ListDetailProps = {\n /**\n * The selected item's content. Stands on its own, and takes the flexible\n * pane.\n */\n detail?: ReactNode;\n /**\n * The items to choose between. Takes the fixed pane — 360px wide, 412px at\n * extra-large.\n */\n list?: ReactNode;\n /**\n * Which pane to show while only one fits, below the expanded breakpoint.\n * Both are shown from expanded up, where this is ignored.\n *\n * Controlled, with no uncontrolled fallback: the layout cannot know that an\n * item was selected or that the reader went back, so holding that state\n * here would only ever be wrong.\n * @default 'list'\n */\n showing?: 'detail' | 'list';\n} & Omit<useRender.ComponentProps<'div'>, 'children'>;\n\n/**\n * Material 3's list-detail layout: a fixed list pane beside a flexible detail\n * pane, collapsing to one pane at a time below the expanded breakpoint.\n *\n * Layout only — neither pane paints a surface of its own, so what goes inside\n * them is composed at the call site. `render` swaps the container's element,\n * for a layout that should be a `<main>` rather than a `<div>`.\n *\n * The panes are written to the DOM in the order they are shown, which is what\n * M3 asks of co-planar panes: focus order has to match the arrangement on\n * screen.\n */\nfunction ListDetail({\n detail,\n list,\n render,\n showing = 'list',\n ...props\n}: ListDetailProps) {\n return useRender({\n defaultTagName: 'div',\n props: {\n ...props,\n children: <>\n <div {...{\n 0: {\n className: \"xeuugli\"\n },\n 1: {\n className: \"xeuugli x1s85apg x9a4l8x\"\n }\n }[!!(showing === 'detail') << 0]}>\n {list}\n </div>\n <div {...{\n 0: {\n className: \"xeuugli\"\n },\n 1: {\n className: \"xeuugli x1s85apg x9a4l8x\"\n }\n }[!!(showing === 'list') << 0]}>\n {detail}\n </div>\n </>,\n ...{\n className: \"xrvj5dj xj2l1yv x1mkdm3x xkgydl7 xxxc7o5\"\n }\n },\n render\n });\n}\nexport type { ListDetailProps };\nexport default ListDetail;"],"mappings":";;;;;;;;;;;;;;;AA6DA,SAAS,WAAW,EAClB,QACA,MACA,QACA,UAAU,QACV,GAAG,SACe;CAClB,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,UAAU,qBAAA,UAAA,EAAA,UAAA,CACN,oBAAC,OAAD;IAAK,GAAI;KACT,GAAG,EACD,WAAW,UACb;KACA,GAAG,EACD,WAAW,2BACb;IACF,EAAE,CAAC,EAAE,YAAY,aAAa;IACzB,UAAA;GACE,CAAA,GACL,oBAAC,OAAD;IAAK,GAAI;KACT,GAAG,EACD,WAAW,UACb;KACA,GAAG,EACD,WAAW,2BACb;IACF,EAAE,CAAC,EAAE,YAAY,WAAW;IACvB,UAAA;GACE,CAAA,CACP,EAAA,CAAA;GAEA,WAAW;EAEf;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/list-detail/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 { media, spacing } from '../../tokens/design.tokens.stylex';\n\n// Material 3's recommended snap widths for a fixed pane. The list is the\n// fixed one here — M3 points a fixed pane at \"lists with light information\n// density\" — and the detail pane is the flexible one that absorbs whatever is\n// left, which satisfies the spec's rule that every layout carry at least one\n// flexible pane.\nconst LIST_PANE = '360px';\nconst LIST_PANE_EXTRA_LARGE = '412px';\n\n// One of Material 3's canonical layouts, and the fixed-and-flexible shape of\n// its two-pane layouts. Unlike SupportingPane, the detail pane here stands on\n// its own: a message, a product, a file. That is what makes showing it\n// *instead of* the list a coherent thing to do when only one pane fits, and\n// why this layout has to be told which pane is showing while SupportingPane\n// does not.\n//\n// M3 puts the second pane on screen from expanded up. Below that the spec\n// shows one pane at a time, with selecting an item swapping to the detail and\n// back returning to the list — app navigation rather than layout, which is\n// why `showing` is controlled rather than held here.\n\ntype ListDetailProps = {\n /**\n * The selected item's content. Stands on its own, and takes the flexible\n * pane.\n */\n detail?: ReactNode;\n /**\n * The items to choose between. Takes the fixed pane — 360px wide, 412px at\n * extra-large.\n */\n list?: ReactNode;\n /**\n * Which pane to show while only one fits, below the expanded breakpoint.\n * Both are shown from expanded up, where this is ignored.\n *\n * Controlled, with no uncontrolled fallback: the layout cannot know that an\n * item was selected or that the reader went back, so holding that state\n * here would only ever be wrong.\n * @default 'list'\n */\n showing?: 'detail' | 'list';\n} & Omit<useRender.ComponentProps<'div'>, 'children'>;\n\n/**\n * Material 3's list-detail layout: a fixed list pane beside a flexible detail\n * pane, collapsing to one pane at a time below the expanded breakpoint.\n *\n * Layout only — neither pane paints a surface of its own, so what goes inside\n * them is composed at the call site. `render` swaps the container's element,\n * for a layout that should be a `<main>` rather than a `<div>`.\n *\n * The panes are written to the DOM in the order they are shown, which is what\n * M3 asks of co-planar panes: focus order has to match the arrangement on\n * screen.\n */\nfunction ListDetail({\n detail,\n list,\n render,\n showing = 'list',\n ...props\n}: ListDetailProps) {\n return useRender({\n defaultTagName: 'div',\n props: {\n ...props,\n children: <>\n <div {...{\n 0: {\n className: \"x9f619 xeuugli\"\n },\n 1: {\n className: \"x9f619 xeuugli x1s85apg x9a4l8x\"\n }\n }[!!(showing === 'detail') << 0]}>\n {list}\n </div>\n <div {...{\n 0: {\n className: \"x9f619 xeuugli\"\n },\n 1: {\n className: \"x9f619 xeuugli x1s85apg x9a4l8x\"\n }\n }[!!(showing === 'list') << 0]}>\n {detail}\n </div>\n </>,\n ...mergeStyles({\n className: \"x9f619 xrvj5dj xj2l1yv x1mkdm3x xkgydl7 xxxc7o5\"\n }, props)\n },\n render\n });\n}\nexport type { ListDetailProps };\nexport default ListDetail;"],"mappings":";;;;;;;;;;;;;;;;AA8DA,SAAS,WAAW,EAClB,QACA,MACA,QACA,UAAU,QACV,GAAG,SACe;CAClB,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,UAAU,qBAAA,UAAA,EAAA,UAAA,CACN,oBAAC,OAAD;IAAK,GAAI;KACT,GAAG,EACD,WAAW,iBACb;KACA,GAAG,EACD,WAAW,kCACb;IACF,EAAE,CAAC,EAAE,YAAY,aAAa;IACzB,UAAA;GACE,CAAA,GACL,oBAAC,OAAD;IAAK,GAAI;KACT,GAAG,EACD,WAAW,iBACb;KACA,GAAG,EACD,WAAW,kCACb;IACF,EAAE,CAAC,EAAE,YAAY,WAAW;IACvB,UAAA;GACE,CAAA,CACP,EAAA,CAAA;GACF,GAAG,YAAY,EACb,WAAW,kDACb,GAAG,KAAK;EACV;EACA;CACF,CAAC;AACH"}
@@ -1,3 +1,4 @@
1
+ import { mergeStyles } from "../../styles/merge.js";
1
2
  import { useRipple } from "../../hooks/useRipple.js";
2
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
4
  //#region src/components/list-item/index.tsx
@@ -25,14 +26,14 @@ function ListItem({ children, interactive = false, leading, supporting, trailing
25
26
  ] });
26
27
  if (!interactive) return /* @__PURE__ */ jsx("div", {
27
28
  ...props,
28
- className: "x6s0dn4 xjbqb8w xc342km x139gbkf x78zum5 xxj4525 xh8yej3 xbktkl8 x1uvvd8r x790zyz x1n2onr6 x1yc453h",
29
+ ...mergeStyles({ className: "x6s0dn4 xjbqb8w xc342km x9f619 x139gbkf x78zum5 xxj4525 xh8yej3 xbktkl8 x1uvvd8r x790zyz x1n2onr6 x1yc453h" }, props),
29
30
  children: content
30
31
  });
31
32
  return /* @__PURE__ */ jsxs("button", {
32
33
  type: "button",
33
34
  ...ripple.handlers,
34
35
  ...props,
35
- className: "x6s0dn4 xc342km x139gbkf x78zum5 xxj4525 xh8yej3 xbktkl8 x1uvvd8r x790zyz x1n2onr6 x1yc453h x83qkoq x1p2om7n xjbqb8w x1ypdohk xln7xf2 xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn",
36
+ ...mergeStyles({ className: "x6s0dn4 xc342km x9f619 x139gbkf x78zum5 xxj4525 xh8yej3 xbktkl8 x1uvvd8r x790zyz x1n2onr6 x1yc453h x83qkoq x1p2om7n xjbqb8w x1ypdohk xln7xf2 xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn" }, props),
36
37
  children: [content, ripple.surface]
37
38
  });
38
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/list-item/index.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react';\nimport * as stylex from '@stylexjs/stylex';\nimport { useRipple } from '../../hooks/useRipple';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// Laid out with flex rather than the grid the design draws. The design's\n// three columns are `auto 1fr auto`, which is what flex does natively — and\n// unlike a fixed three-column grid it stays correct when a row has no leading\n// or no trailing content, where the remaining children would otherwise slide\n// into the wrong columns.\n//\n// Rows align with each other through their leading content being the same\n// size, not through a fixed column width: a list of Avatars all at one size\n// lines up, and that is the same thing the design's 40px column achieves.\n//\n// The state layer composites over `transparent` rather than over a container\n// colour, because a row's own background is transparent and it therefore\n// tints whatever it happens to be sitting on — a card, or the page.\n\ntype ListItemProps = {\n /** The row's headline — the one thing it is mostly about. */\n children?: ReactNode;\n /**\n * Renders a `<button>` that ripples and tints on hover, for a row that is\n * itself pressable. Leave it off for a row that only presents.\n * @default false\n */\n interactive?: boolean;\n /** Content before the headline: an avatar, an icon, a checkbox. */\n leading?: ReactNode;\n /** A second line under the headline, in the muted role. */\n supporting?: ReactNode;\n /** Content after the headline, such as an amount or a control. */\n trailing?: ReactNode;\n} & HTMLAttributes<HTMLElement>;\nfunction ListItem({\n children,\n interactive = false,\n leading,\n supporting,\n trailing,\n ...props\n}: ListItemProps) {\n const ripple = useRipple<HTMLButtonElement>(interactive);\n const content = <>\n {leading === undefined ? null : <span className=\"x6s0dn4 x78zum5 x2lah0s\">{leading}</span>}\n <span className=\"x78zum5 xdt5ytf x1iyjqo2 x14qo01y xeuugli\">\n <span className=\"xkknnkr x14zspaw x1v9cpvo x155f00i x1lz68p4\">{children}</span>\n {supporting === undefined ? null : <span className=\"x1w5n3ug x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh\">{supporting}</span>}\n </span>\n {trailing === undefined ? null : <span className=\"x6s0dn4 x78zum5 x2lah0s\">{trailing}</span>}\n </>;\n if (!interactive) {\n return <div {...props} className=\"x6s0dn4 xjbqb8w xc342km x139gbkf x78zum5 xxj4525 xh8yej3 xbktkl8 x1uvvd8r x790zyz x1n2onr6 x1yc453h\">\n {content}\n </div>;\n }\n return <button type=\"button\" {...ripple.handlers} {...props} className=\"x6s0dn4 xc342km x139gbkf x78zum5 xxj4525 xh8yej3 xbktkl8 x1uvvd8r x790zyz x1n2onr6 x1yc453h x83qkoq x1p2om7n xjbqb8w x1ypdohk xln7xf2 xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn\">\n {content}\n {ripple.surface}\n </button>;\n}\nexport type { ListItemProps };\nexport default ListItem;"],"mappings":";;;AAoCA,SAAS,SAAS,EAChB,UACA,cAAc,OACd,SACA,YACA,UACA,GAAG,SACa;CAChB,MAAM,SAAS,UAA6B,WAAW;CACvD,MAAM,UAAU,qBAAA,UAAA,EAAA,UAAA;EACX,YAAY,KAAA,IAAY,OAAO,oBAAC,QAAD;GAAM,WAAU;GAA2B,UAAA;EAAc,CAAA;EACzF,qBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACE,oBAAC,QAAD;IAAM,WAAU;IAA+C;GAAe,CAAA,GAC7E,eAAe,KAAA,IAAY,OAAO,oBAAC,QAAD;IAAM,WAAU;IAAsD,UAAA;GAAiB,CAAA,CACtH;;EACL,aAAa,KAAA,IAAY,OAAO,oBAAC,QAAD;GAAM,WAAU;GAA2B,UAAA;EAAe,CAAA;CAC7F,EAAA,CAAA;CACF,IAAI,CAAC,aACH,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAO,WAAU;EAC5B,UAAA;CACE,CAAA;CAET,OAAO,qBAAC,UAAD;EAAQ,MAAK;EAAS,GAAI,OAAO;EAAU,GAAI;EAAO,WAAU;EAAhE,UAAA,CACF,SACA,OAAO,OACF;;AACZ"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/list-item/index.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react';\nimport * as stylex from '@stylexjs/stylex';\nimport { useRipple } from '../../hooks/useRipple';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// Laid out with flex rather than the grid the design draws. The design's\n// three columns are `auto 1fr auto`, which is what flex does natively — and\n// unlike a fixed three-column grid it stays correct when a row has no leading\n// or no trailing content, where the remaining children would otherwise slide\n// into the wrong columns.\n//\n// Rows align with each other through their leading content being the same\n// size, not through a fixed column width: a list of Avatars all at one size\n// lines up, and that is the same thing the design's 40px column achieves.\n//\n// The state layer composites over `transparent` rather than over a container\n// colour, because a row's own background is transparent and it therefore\n// tints whatever it happens to be sitting on — a card, or the page.\n\ntype ListItemProps = {\n /** The row's headline — the one thing it is mostly about. */\n children?: ReactNode;\n /**\n * Renders a `<button>` that ripples and tints on hover, for a row that is\n * itself pressable. Leave it off for a row that only presents.\n * @default false\n */\n interactive?: boolean;\n /** Content before the headline: an avatar, an icon, a checkbox. */\n leading?: ReactNode;\n /** A second line under the headline, in the muted role. */\n supporting?: ReactNode;\n /** Content after the headline, such as an amount or a control. */\n trailing?: ReactNode;\n} & HTMLAttributes<HTMLElement>;\nfunction ListItem({\n children,\n interactive = false,\n leading,\n supporting,\n trailing,\n ...props\n}: ListItemProps) {\n const ripple = useRipple<HTMLButtonElement>(interactive);\n const content = <>\n {leading === undefined ? null : <span className=\"x6s0dn4 x78zum5 x2lah0s\">{leading}</span>}\n <span className=\"x78zum5 xdt5ytf x1iyjqo2 x14qo01y xeuugli\">\n <span className=\"xkknnkr x14zspaw x1v9cpvo x155f00i x1lz68p4\">{children}</span>\n {supporting === undefined ? null : <span className=\"x1w5n3ug x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh\">{supporting}</span>}\n </span>\n {trailing === undefined ? null : <span className=\"x6s0dn4 x78zum5 x2lah0s\">{trailing}</span>}\n </>;\n if (!interactive) {\n return <div {...props} {...mergeStyles({\n className: \"x6s0dn4 xjbqb8w xc342km x9f619 x139gbkf x78zum5 xxj4525 xh8yej3 xbktkl8 x1uvvd8r x790zyz x1n2onr6 x1yc453h\"\n }, props)}>\n {content}\n </div>;\n }\n return <button type=\"button\" {...ripple.handlers} {...props} {...mergeStyles({\n className: \"x6s0dn4 xc342km x9f619 x139gbkf x78zum5 xxj4525 xh8yej3 xbktkl8 x1uvvd8r x790zyz x1n2onr6 x1yc453h x83qkoq x1p2om7n xjbqb8w x1ypdohk xln7xf2 xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn\"\n }, props)}>\n {content}\n {ripple.surface}\n </button>;\n}\nexport type { ListItemProps };\nexport default ListItem;"],"mappings":";;;;AAqCA,SAAS,SAAS,EAChB,UACA,cAAc,OACd,SACA,YACA,UACA,GAAG,SACa;CAChB,MAAM,SAAS,UAA6B,WAAW;CACvD,MAAM,UAAU,qBAAA,UAAA,EAAA,UAAA;EACX,YAAY,KAAA,IAAY,OAAO,oBAAC,QAAD;GAAM,WAAU;GAA2B,UAAA;EAAc,CAAA;EACzF,qBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACE,oBAAC,QAAD;IAAM,WAAU;IAA+C;GAAe,CAAA,GAC7E,eAAe,KAAA,IAAY,OAAO,oBAAC,QAAD;IAAM,WAAU;IAAsD,UAAA;GAAiB,CAAA,CACtH;;EACL,aAAa,KAAA,IAAY,OAAO,oBAAC,QAAD;GAAM,WAAU;GAA2B,UAAA;EAAe,CAAA;CAC7F,EAAA,CAAA;CACF,IAAI,CAAC,aACH,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAO,GAAI,YAAY,EACrC,WAAW,6GACb,GAAG,KAAK;EACH,UAAA;CACE,CAAA;CAET,OAAO,qBAAC,UAAD;EAAQ,MAAK;EAAS,GAAI,OAAO;EAAU,GAAI;EAAO,GAAI,YAAY,EAC3E,WAAW,yLACb,GAAG,KAAK;EAFD,UAAA,CAGF,SACA,OAAO,OACF;;AACZ"}
@@ -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/product-icon/index.tsx
@@ -6,6 +7,7 @@ const styles = {
6
7
  base: {
7
8
  kGNEyG: "x6s0dn4",
8
9
  kaIpWk: "x1xdvaa9",
10
+ kB7OPa: "x9f619",
9
11
  k1xSpc: "x3nfvp2",
10
12
  kmuXW: "x2lah0s",
11
13
  kMv6JI: "xkknnkr",
@@ -81,7 +83,7 @@ function ProductIcon({ name, size = "md", src, tone = "primary", ...props$1 }) {
81
83
  "aria-label": name,
82
84
  role: "img",
83
85
  ...props$1,
84
- ...props(styles.base, styles[size], styles[tone]),
86
+ ...mergeStatefulStyles(props(styles.base, styles[size], styles[tone]), props$1),
85
87
  children: [src === void 0 ? null : /* @__PURE__ */ jsx(Avatar.Image, {
86
88
  alt: "",
87
89
  src,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/product-icon/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// The counterpart to Avatar: Avatar stands for a person, this stands for\n// everything else — an application, a service, a brand. The two are the same\n// three sizes so either can fill a leading slot without moving what sits\n// beside it, and they differ in the two ways that matter for a mark rather\n// than a face.\n//\n// A rounded square rather than a circle. A logo is drawn to its own bounding\n// box, and a circle crops the corners it was composed with.\n//\n// `contain` rather than `cover`. Cropping a face to fill a circle loses\n// nothing anyone minds; cropping a wordmark loses the word. The cost is\n// letterboxing — a wide mark leaves space above and below — and that is the\n// right trade for a mark whose whole job is to be recognised.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x1xdvaa9\",\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: \"x19kjcj4\",\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 ProductIconProps = Omit<BaseUIAvatarRootProps, 'children'> & {\n /**\n * What this identifies. Supplies both the fallback initial and the\n * accessible name, so a screen reader announces the thing rather than\n * reading a letter aloud.\n */\n name: string;\n /**\n * Edge length: `sm` 36px, `md` 40px, `lg` 56px. The same three Avatar uses,\n * so the two are interchangeable wherever one leads a row or a card.\n * @default 'md'\n */\n size?: 'lg' | 'md' | 'sm';\n /**\n * The mark to show in place of the initial. The initial stays until it has\n * loaded, and comes back if it fails.\n */\n src?: string;\n /**\n * Which container/on-container colour pair to tint the fallback with. Has\n * no effect once `src` has loaded, since the mark covers it.\n * @default 'primary'\n */\n tone?: 'negative' | 'positive' | 'primary' | 'secondary' | 'tertiary';\n};\n\n// One letter, where Avatar takes two. A person has a first name and a last\n// name to initialise; a thing usually has neither, so the same rule applied\n// to \"Second Item\" would produce \"SI\" — a pair of initials for something that\n// was never two words in that sense. Array.from rather than indexing, so a\n// name starting outside the Basic Multilingual Plane yields its whole first\n// character instead of half a surrogate pair.\nfunction initialFrom(name: string) {\n const trimmed = name.trim();\n return (Array.from(trimmed)[0] ?? '').toLocaleUpperCase();\n}\n\n/**\n * A small square mark identifying something that is not a person — an\n * application, a service, a brand. Reach for Avatar when it is a person.\n *\n * The mark is letterboxed rather than cropped, so a logo of any aspect ratio\n * can be handed over as it was drawn.\n */\nfunction ProductIcon({\n name,\n size = 'md',\n src,\n tone = 'primary',\n ...props\n}: ProductIconProps) {\n return (\n // role/aria-label rather than letting the fallback letter be read: \"B\" is\n // not what anyone means to announce. Marking the root as an image also\n // makes its contents presentational, so neither the mark nor the letter\n // is 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 letter shown when there is no mark, 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 x19kjcj4\" />}\n <BaseUIAvatar.Fallback>{initialFrom(name)}</BaseUIAvatar.Fallback>\n </BaseUIAvatar.Root>\n );\n}\nexport type { ProductIconProps };\nexport default ProductIcon;"],"mappings":";;;;AAmBA,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;AAiCA,SAAS,YAAY,MAAc;CACjC,MAAM,UAAU,KAAK,KAAK;CAC1B,QAAQ,MAAM,KAAK,OAAO,CAAC,CAAC,MAAM,GAAA,CAAI,kBAAkB;AAC1D;;;;;;;;AASA,SAAS,YAAY,EACnB,MACA,OAAO,MACP,KACA,OAAO,WACP,GAAG,WACgB;CACnB,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;EAA0B,CAAA,GACrG,oBAAC,OAAa,UAAd,EAAA,UAAwB,YAAY,IAAI,EAAyB,CAAA,CAChD;;AAEvB"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/product-icon/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// The counterpart to Avatar: Avatar stands for a person, this stands for\n// everything else — an application, a service, a brand. The two are the same\n// three sizes so either can fill a leading slot without moving what sits\n// beside it, and they differ in the two ways that matter for a mark rather\n// than a face.\n//\n// A rounded square rather than a circle. A logo is drawn to its own bounding\n// box, and a circle crops the corners it was composed with.\n//\n// `contain` rather than `cover`. Cropping a face to fill a circle loses\n// nothing anyone minds; cropping a wordmark loses the word. The cost is\n// letterboxing — a wide mark leaves space above and below — and that is the\n// right trade for a mark whose whole job is to be recognised.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x1xdvaa9\",\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: \"x19kjcj4\",\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 ProductIconProps = Omit<BaseUIAvatarRootProps, 'children'> & {\n /**\n * What this identifies. Supplies both the fallback initial and the\n * accessible name, so a screen reader announces the thing rather than\n * reading a letter aloud.\n */\n name: string;\n /**\n * Edge length: `sm` 36px, `md` 40px, `lg` 56px. The same three Avatar uses,\n * so the two are interchangeable wherever one leads a row or a card.\n * @default 'md'\n */\n size?: 'lg' | 'md' | 'sm';\n /**\n * The mark to show in place of the initial. The initial stays until it has\n * loaded, and comes back if it fails.\n */\n src?: string;\n /**\n * Which container/on-container colour pair to tint the fallback with. Has\n * no effect once `src` has loaded, since the mark covers it.\n * @default 'primary'\n */\n tone?: 'negative' | 'positive' | 'primary' | 'secondary' | 'tertiary';\n};\n\n// One letter, where Avatar takes two. A person has a first name and a last\n// name to initialise; a thing usually has neither, so the same rule applied\n// to \"Second Item\" would produce \"SI\" — a pair of initials for something that\n// was never two words in that sense. Array.from rather than indexing, so a\n// name starting outside the Basic Multilingual Plane yields its whole first\n// character instead of half a surrogate pair.\nfunction initialFrom(name: string) {\n const trimmed = name.trim();\n return (Array.from(trimmed)[0] ?? '').toLocaleUpperCase();\n}\n\n/**\n * A small square mark identifying something that is not a person — an\n * application, a service, a brand. Reach for Avatar when it is a person.\n *\n * The mark is letterboxed rather than cropped, so a logo of any aspect ratio\n * can be handed over as it was drawn.\n */\nfunction ProductIcon({\n name,\n size = 'md',\n src,\n tone = 'primary',\n ...props\n}: ProductIconProps) {\n return (\n // role/aria-label rather than letting the fallback letter be read: \"B\" is\n // not what anyone means to announce. Marking the root as an image also\n // makes its contents presentational, so neither the mark nor the letter\n // is 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 letter shown when there is no mark, 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 x19kjcj4\" />}\n <BaseUIAvatar.Fallback>{initialFrom(name)}</BaseUIAvatar.Fallback>\n </BaseUIAvatar.Root>\n );\n}\nexport type { ProductIconProps };\nexport default ProductIcon;"],"mappings":";;;;;AAoBA,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;AAiCA,SAAS,YAAY,MAAc;CACjC,MAAM,UAAU,KAAK,KAAK;CAC1B,QAAQ,MAAM,KAAK,OAAO,CAAC,CAAC,MAAM,GAAA,CAAI,kBAAkB;AAC1D;;;;;;;;AASA,SAAS,YAAY,EACnB,MACA,OAAO,MACP,KACA,OAAO,WACP,GAAG,WACgB;CACnB,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;EAA0B,CAAA,GACrG,oBAAC,OAAa,UAAd,EAAA,UAAwB,YAAY,IAAI,EAAyB,CAAA,CAChD;;AAEvB"}