@ada-cx/lovelace 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/components/Checkbox/Checkbox.css.d.ts +19 -5
  2. package/dist/components/Checkbox/Checkbox.css.js +11 -2
  3. package/dist/components/Checkbox/Checkbox.css.js.map +1 -1
  4. package/dist/components/Checkbox/Checkbox.d.ts +8 -1
  5. package/dist/components/Checkbox/Checkbox.js +12 -34
  6. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  7. package/dist/components/Checkbox/CheckboxIndicator.d.ts +23 -0
  8. package/dist/components/Checkbox/CheckboxIndicator.js +40 -0
  9. package/dist/components/Checkbox/CheckboxIndicator.js.map +1 -0
  10. package/dist/components/Checkbox/index.d.ts +1 -1
  11. package/dist/components/MenuItem/MenuItem.css.d.ts +0 -2
  12. package/dist/components/MenuItem/MenuItem.css.js +2 -2
  13. package/dist/components/MenuItem/MenuItem.css.js.map +1 -1
  14. package/dist/components/MenuItem/MenuItem.d.ts +12 -6
  15. package/dist/components/MenuItem/MenuItem.js +11 -7
  16. package/dist/components/MenuItem/MenuItem.js.map +1 -1
  17. package/dist/components/MenuItem/MenuItemCheckbox.d.ts +12 -0
  18. package/dist/components/MenuItem/MenuItemCheckbox.js +13 -0
  19. package/dist/components/MenuItem/MenuItemCheckbox.js.map +1 -0
  20. package/dist/components/MenuItem/MenuItemLabel.d.ts +15 -0
  21. package/dist/components/MenuItem/MenuItemLabel.js +14 -0
  22. package/dist/components/MenuItem/MenuItemLabel.js.map +1 -0
  23. package/dist/components/MenuItem/MenuItemRadio.d.ts +11 -0
  24. package/dist/components/MenuItem/MenuItemRadio.js +13 -0
  25. package/dist/components/MenuItem/MenuItemRadio.js.map +1 -0
  26. package/dist/components/MenuItem/MenuItemRoot.d.ts +11 -5
  27. package/dist/components/MenuItem/MenuItemRoot.js +16 -7
  28. package/dist/components/MenuItem/MenuItemRoot.js.map +1 -1
  29. package/dist/components/MenuItem/MenuItemToggle.d.ts +12 -0
  30. package/dist/components/MenuItem/MenuItemToggle.js +13 -0
  31. package/dist/components/MenuItem/MenuItemToggle.js.map +1 -0
  32. package/dist/components/MenuItem/index.d.ts +1 -1
  33. package/dist/components/Radio/Radio.css.d.ts +23 -2
  34. package/dist/components/Radio/Radio.css.js +11 -2
  35. package/dist/components/Radio/Radio.css.js.map +1 -1
  36. package/dist/components/Radio/Radio.d.ts +8 -1
  37. package/dist/components/Radio/Radio.js +11 -13
  38. package/dist/components/Radio/Radio.js.map +1 -1
  39. package/dist/components/Radio/RadioIndicator.d.ts +22 -0
  40. package/dist/components/Radio/RadioIndicator.js +18 -0
  41. package/dist/components/Radio/RadioIndicator.js.map +1 -0
  42. package/dist/components/Radio/index.d.ts +1 -1
  43. package/dist/components/Sheet/Sheet.css.js.map +1 -1
  44. package/dist/components/Toggle/Toggle.css.d.ts +16 -5
  45. package/dist/components/Toggle/Toggle.css.js +2 -2
  46. package/dist/components/Toggle/Toggle.css.js.map +1 -1
  47. package/dist/components/Toggle/Toggle.js +3 -5
  48. package/dist/components/Toggle/Toggle.js.map +1 -1
  49. package/dist/components/Toggle/ToggleIndicator.d.ts +21 -0
  50. package/dist/components/Toggle/ToggleIndicator.js +18 -0
  51. package/dist/components/Toggle/ToggleIndicator.js.map +1 -0
  52. package/dist/style.css +1 -1
  53. package/dist/styles/row.d.ts +22 -0
  54. package/package.json +1 -1
  55. package/dist/components/MenuItem/MenuItemLeading.d.ts +0 -11
  56. package/dist/components/MenuItem/MenuItemLeading.js +0 -17
  57. package/dist/components/MenuItem/MenuItemLeading.js.map +0 -1
  58. package/dist/components/MenuItem/MenuItemTrailing.d.ts +0 -14
  59. package/dist/components/MenuItem/MenuItemTrailing.js +0 -17
  60. package/dist/components/MenuItem/MenuItemTrailing.js.map +0 -1
@@ -1,5 +1,26 @@
1
1
  export declare const radioGroup: string;
2
- export declare const radioRoot: string;
2
+ /**
3
+ * The RAC `Radio` label. `inline` lays the control out beside its label; `row` is
4
+ * the 40px selectable row Figma draws for a menu item, for a `RadioGroup`
5
+ * rendered as a list of options.
6
+ */
7
+ export declare const radioRoot: import("@vanilla-extract/recipes").RuntimeFn<{
8
+ variant: {
9
+ inline: {
10
+ display: "inline-flex";
11
+ alignItems: "center";
12
+ gap: "var(--lovelace-color-neutral-0)" | "var(--lovelace-color-neutral-50)" | "var(--lovelace-color-neutral-100)" | "var(--lovelace-color-neutral-200)" | "var(--lovelace-color-neutral-300)" | "var(--lovelace-color-neutral-400)" | "var(--lovelace-color-neutral-500)" | "var(--lovelace-color-neutral-600)" | "var(--lovelace-color-neutral-700)" | "var(--lovelace-color-neutral-800)" | "var(--lovelace-color-neutral-900)" | "var(--lovelace-color-red-50)" | "var(--lovelace-color-orange-50)" | "var(--lovelace-color-green-50)" | "var(--lovelace-color-green-100)" | "var(--lovelace-color-green-200)" | "var(--lovelace-color-green-300)" | "var(--lovelace-color-green-400)" | "var(--lovelace-color-green-500)" | "var(--lovelace-color-green-600)" | "var(--lovelace-color-green-700)" | "var(--lovelace-color-green-800)" | "var(--lovelace-color-green-900)" | "var(--lovelace-color-orange-100)" | "var(--lovelace-color-orange-200)" | "var(--lovelace-color-orange-300)" | "var(--lovelace-color-orange-400)" | "var(--lovelace-color-orange-500)" | "var(--lovelace-color-orange-600)" | "var(--lovelace-color-orange-700)" | "var(--lovelace-color-orange-800)" | "var(--lovelace-color-orange-900)" | "var(--lovelace-color-red-100)" | "var(--lovelace-color-red-200)" | "var(--lovelace-color-red-300)" | "var(--lovelace-color-red-400)" | "var(--lovelace-color-red-500)" | "var(--lovelace-color-red-600)" | "var(--lovelace-color-red-700)" | "var(--lovelace-color-red-800)" | "var(--lovelace-color-red-900)" | "var(--lovelace-spacing-4)" | "var(--lovelace-spacing-8)" | "var(--lovelace-spacing-12)" | "var(--lovelace-spacing-16)" | "var(--lovelace-spacing-20)" | "var(--lovelace-spacing-24)" | "var(--lovelace-spacing-32)" | "var(--lovelace-spacing-40)" | "var(--lovelace-spacing-48)" | "var(--lovelace-font-weight-400)" | "var(--lovelace-font-weight-500)" | "var(--lovelace-font-weight-600)" | "var(--lovelace-color-blue-50)" | "var(--lovelace-color-blue-100)" | "var(--lovelace-color-blue-200)" | "var(--lovelace-color-blue-300)" | "var(--lovelace-color-blue-400)" | "var(--lovelace-color-blue-500)" | "var(--lovelace-color-blue-600)" | "var(--lovelace-color-blue-700)" | "var(--lovelace-color-blue-800)" | "var(--lovelace-color-blue-900)" | "var(--lovelace-font-size-12)" | "var(--lovelace-font-size-14)" | "var(--lovelace-font-size-16)" | "var(--lovelace-font-size-18)" | "var(--lovelace-font-size-20)" | "var(--lovelace-font-size-22)" | "var(--lovelace-font-size-24)" | "var(--lovelace-font-size-26)" | "var(--lovelace-font-size-28)" | "var(--lovelace-font-line-height-16)" | "var(--lovelace-font-line-height-18)" | "var(--lovelace-font-line-height-22)" | "var(--lovelace-font-line-height-24)" | "var(--lovelace-font-line-height-26)" | "var(--lovelace-font-line-height-28)" | "var(--lovelace-font-line-height-30)" | "var(--lovelace-font-line-height-32)" | "var(--lovelace-font-line-height-34)" | "var(--lovelace-border-radius-0)" | "var(--lovelace-p-border-radius-6)" | "var(--lovelace-p-border-radius-10)" | "var(--lovelace-p-border-radius-14)" | "var(--lovelace-p-border-radius-20)" | "var(--lovelace-p-border-radius-24)" | "var(--lovelace-border-radius-999)" | "var(--lovelace-font-paragraph-spacing-4)" | "var(--lovelace-font-paragraph-spacing-6)" | "var(--lovelace-font-paragraph-spacing-8)" | "var(--lovelace-font-paragraph-spacing-10)" | "var(--lovelace-font-paragraph-spacing-12)" | "var(--lovelace-color-accent-50)" | "var(--lovelace-color-accent-100)" | "var(--lovelace-color-accent-200)" | "var(--lovelace-color-accent-300)" | "var(--lovelace-color-accent-400)" | "var(--lovelace-color-accent-500)" | "var(--lovelace-color-accent-600)" | "var(--lovelace-color-accent-700)" | "var(--lovelace-color-accent-800)" | "var(--lovelace-color-accent-900)" | "var(--lovelace-font-family-sans-serif)" | "var(--lovelace-font-family-mono)" | "var(--lovelace-border-width-1)" | "var(--lovelace-border-width-2)" | "var(--lovelace-dimension-16)" | "var(--lovelace-dimension-20)" | "var(--lovelace-dimension-22)" | "var(--lovelace-dimension-24)" | "var(--lovelace-dimension-32)" | "var(--lovelace-dimension-36)" | "var(--lovelace-color-content-default)" | "var(--lovelace-color-content-secondary)" | "var(--lovelace-color-content-secondary-inverse)" | "var(--lovelace-color-content-disabled)" | "var(--lovelace-color-content-inverse)" | "var(--lovelace-color-background-default)" | "var(--lovelace-color-background-secondary)" | "var(--lovelace-color-background-tertiary)" | "var(--lovelace-color-background-quaternary)" | "var(--lovelace-color-background-disabled)" | "var(--lovelace-color-background-inverse)" | "var(--lovelace-color-background-neutral-overlay)" | "var(--lovelace-color-border-default)" | "var(--lovelace-color-border-medium)" | "var(--lovelace-color-border-strong)" | "var(--lovelace-color-content-link)" | "var(--lovelace-color-background-destructive)" | "var(--lovelace-color-content-destructive)" | "var(--lovelace-color-background-destructive-light)" | "var(--lovelace-color-border-destructive)" | "var(--lovelace-color-content-on-destructive)" | "var(--lovelace-color-content-warning)" | "var(--lovelace-color-background-warning)" | "var(--lovelace-color-background-warning-light)" | "var(--lovelace-color-border-warning)" | "var(--lovelace-color-content-success)" | "var(--lovelace-color-background-success)" | "var(--lovelace-color-background-success-light)" | "var(--lovelace-color-border-success)" | "var(--lovelace-color-content-accent)" | "var(--lovelace-color-content-on-accent)" | "var(--lovelace-color-content-on-scrim)" | "var(--lovelace-color-background-accent)" | "var(--lovelace-color-background-highlight-overlay)" | "var(--lovelace-color-border-focus)" | "var(--lovelace-color-border-accent)" | "var(--lovelace-color-border-highlight)" | "var(--lovelace-font-weight-regular)" | "var(--lovelace-font-size-caption)" | "var(--lovelace-line-height-caption)" | "var(--lovelace-paragraph-spacing-caption)" | "var(--lovelace-paragraph-spacing-body)" | "var(--lovelace-paragraph-spacing-title)" | "var(--lovelace-line-height-body)" | "var(--lovelace-line-height-title-small)" | "var(--lovelace-line-height-title-large)" | "var(--lovelace-font-size-body)" | "var(--lovelace-font-size-title-small)" | "var(--lovelace-font-size-title-large)" | "var(--lovelace-font-weight-medium)" | "var(--lovelace-font-weight-semi-bold)" | "var(--lovelace-font-family-body)" | "var(--lovelace-font-family-heading)" | "var(--lovelace-font-family-code)" | "var(--lovelace-border-radius-none)" | "var(--lovelace-border-radius-6)" | "var(--lovelace-border-radius-10)" | "var(--lovelace-border-radius-14)" | "var(--lovelace-border-radius-20)" | "var(--lovelace-border-radius-24)" | "var(--lovelace-border-radius-full)" | "var(--lovelace-padding-4)" | "var(--lovelace-padding-8)" | "var(--lovelace-padding-12)" | "var(--lovelace-gap-4)" | "var(--lovelace-padding-16)" | "var(--lovelace-gap-8)" | "var(--lovelace-gap-12)" | "var(--lovelace-gap-16)" | "var(--lovelace-gap-20)" | "var(--lovelace-padding-20)" | "var(--lovelace-border-width-default)" | "var(--lovelace-border-width-focus)" | "var(--lovelace-opacity-state-hover)" | "var(--lovelace-opacity-state-focus)" | "var(--lovelace-opacity-state-pressed)" | "var(--lovelace-icon-size-sm)" | "var(--lovelace-icon-size-md)" | "var(--lovelace-icon-size-control)" | "var(--lovelace-icon-size-lg)" | "var(--lovelace-easing-standard)" | "var(--lovelace-easing-emphasized)" | "var(--lovelace-easing-decelerate)" | "var(--lovelace-easing-accelerate)" | "var(--lovelace-duration-fast)" | "var(--lovelace-duration-medium)" | "var(--lovelace-duration-slow)" | "var(--lovelace-message-user-background)" | "var(--lovelace-message-user-content)" | "var(--lovelace-button-primary-background)" | "var(--lovelace-button-primary-content)" | "var(--lovelace-header-background)" | "var(--lovelace-pill-content-primary)" | "var(--lovelace-header-content)" | "var(--lovelace-chip-background-selected)" | "var(--lovelace-chatfab-background)" | "var(--lovelace-chatfab-content)" | "var(--lovelace-composer-background)" | "var(--lovelace-composer-border-default)" | "var(--lovelace-composer-content-default)" | "var(--lovelace-composer-content-secondary)" | "var(--lovelace-composer-border-focus)" | "var(--lovelace-composer-border-active)" | "var(--lovelace-avatar-background)" | "var(--lovelace-avatar-content)" | "var(--lovelace-scrollmarker-background)" | "var(--lovelace-scrollmarker-content)" | "var(--lovelace-send-button-background)" | "var(--lovelace-chat-background)" | "var(--lovelace-border-radius-button)" | "var(--lovelace-border-radius-message)" | "var(--lovelace-border-radius-input)" | "var(--lovelace-border-radius-composer)" | "var(--lovelace-border-radius-avatar)" | "var(--lovelace-border-radius-pill)" | "var(--lovelace-border-radius-media-preview)" | "var(--lovelace-border-radius-container)";
13
+ };
14
+ row: (string | import("@vanilla-extract/css").StyleRule)[];
15
+ };
16
+ }>;
17
+ /**
18
+ * The 24px control circle. Selection and interaction state are read from whichever
19
+ * host element carries React Aria's `data-*` — the RAC label, or a `MenuItem` row —
20
+ * so the rules below are child selectors that name no host. Interaction rules
21
+ * additionally require `[data-state-layer]`, which the indicator sets only when it
22
+ * is the sole affordance; inside a row the row paints hover and focus itself.
23
+ */
3
24
  export declare const radioControl: string;
4
- export declare const radioIndicator: string;
25
+ export declare const radioDot: string;
5
26
  export declare const radioLabel: string;
@@ -1,7 +1,16 @@
1
+ import { createRuntimeFn as e } from "../../vendor/@vanilla-extract/recipes/dist/createRuntimeFn-62c9670f.esm.js";
1
2
  /* empty css */
2
3
  //#region src/components/Radio/Radio.css.ts
3
- var e = "mufew30", t = "mufew31", n = "mufew32", r = "mufew33", i = "mufew34";
4
+ var t = "mufew31", n = e({
5
+ defaultClassName: "mufew32",
6
+ variantClassNames: { variant: {
7
+ inline: "mufew33",
8
+ row: "mufew34 mufew30"
9
+ } },
10
+ defaultVariants: { variant: "inline" },
11
+ compoundVariants: []
12
+ }), r = "mufew35", i = "mufew36", a = "mufew37";
4
13
  //#endregion
5
- export { n as radioControl, e as radioGroup, r as radioIndicator, i as radioLabel, t as radioRoot };
14
+ export { r as radioControl, i as radioDot, t as radioGroup, a as radioLabel, n as radioRoot };
6
15
 
7
16
  //# sourceMappingURL=Radio.css.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Radio.css.js","names":[],"sources":["../../../src/components/Radio/Radio.css.ts"],"sourcesContent":["import { style } from \"@vanilla-extract/css\";\nimport { t } from \"../../tokens/index.js\";\n\n// Figma's `button-size/xs` (24px) has no LovelaceToken; the checked indicator's\n// inset is likewise fixed visual detail Figma renders as a flattened raster with\n// no token (5px inset inside the 1px border → 12px center dot). Both are\n// hardcoded like a fixed frame size.\nconst CONTROL_SIZE = \"24px\";\nconst INDICATOR_INSET = \"5px\";\n\nexport const radioGroup = style({\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tgap: t(\"gap-20\"),\n\tselectors: {\n\t\t'&[data-orientation=\"horizontal\"]': {\n\t\t\tflexDirection: \"row\",\n\t\t},\n\t},\n});\n\nexport const radioRoot = style({\n\tdisplay: \"inline-flex\",\n\talignItems: \"center\",\n\tgap: t(\"gap-12\"),\n\tcursor: \"pointer\",\n\tuserSelect: \"none\",\n\tselectors: {\n\t\t\"&[data-disabled]\": {\n\t\t\tcursor: \"not-allowed\",\n\t\t},\n\t},\n});\n\nexport const radioControl = style({\n\tposition: \"relative\",\n\tboxSizing: \"border-box\",\n\tflexShrink: 0,\n\twidth: CONTROL_SIZE,\n\theight: CONTROL_SIZE,\n\tborderRadius: t(\"border-radius-full\"),\n\tborderStyle: \"solid\",\n\tborderWidth: t(\"border-width-default\"),\n\ttransition:\n\t\t\"background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease\",\n\tselectors: {\n\t\t// Unchecked — default resting state.\n\t\t[`${radioRoot}:not([data-selected]) &`]: {\n\t\t\tbackgroundColor: t(\"color-background-default\"),\n\t\t\tborderColor: t(\"color-border-default\"),\n\t\t},\n\t\t// Unchecked — hover darkens the border only (no fill).\n\t\t[`${radioRoot}[data-hovered]:not([data-selected]):not([data-disabled]) &`]:\n\t\t\t{\n\t\t\t\tborderColor: t(\"color-border-medium\"),\n\t\t\t},\n\t\t// Checked — solid inverse disc; the white ring is drawn by radioIndicator.\n\t\t[`${radioRoot}[data-selected] &`]: {\n\t\t\tbackgroundColor: t(\"color-background-inverse\"),\n\t\t\tborderColor: t(\"color-background-inverse\"),\n\t\t},\n\t\t// Focus — outer 2px focus ring for both states (matches Chip's double ring).\n\t\t[`${radioRoot}[data-focus-visible]:not([data-disabled]) &`]: {\n\t\t\tboxShadow: `0 0 0 ${t(\"border-width-focus\")} ${t(\"color-border-focus\")}`,\n\t\t},\n\t\t// Focus (unchecked) — inner accent border completes the double ring.\n\t\t[`${radioRoot}[data-focus-visible]:not([data-selected]):not([data-disabled]) &`]:\n\t\t\t{\n\t\t\t\tborderColor: t(\"color-border-accent\"),\n\t\t\t},\n\t\t// Disabled — unchecked.\n\t\t[`${radioRoot}[data-disabled]:not([data-selected]) &`]: {\n\t\t\tbackgroundColor: t(\"color-background-tertiary\"),\n\t\t\tborderColor: t(\"color-border-default\"),\n\t\t},\n\t\t// Disabled — checked disc fades to the disabled background.\n\t\t[`${radioRoot}[data-disabled][data-selected] &`]: {\n\t\t\tbackgroundColor: t(\"color-background-disabled\"),\n\t\t\tborderColor: t(\"color-background-disabled\"),\n\t\t},\n\t},\n\t\"@media\": {\n\t\t\"(forced-colors: active)\": {\n\t\t\tselectors: {\n\t\t\t\t[`${radioRoot}[data-focus-visible]:not([data-disabled]) &`]: {\n\t\t\t\t\toutline: \"2px solid Highlight\",\n\t\t\t\t\toutlineOffset: \"2px\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n});\n\n// Solid center dot on the checked disc (dark disc → filled light center circle).\n// Hidden (transparent) until the option is selected.\nexport const radioIndicator = style({\n\tposition: \"absolute\",\n\tinset: INDICATOR_INSET,\n\tborderRadius: t(\"border-radius-full\"),\n\tbackgroundColor: \"transparent\",\n\tpointerEvents: \"none\",\n\tselectors: {\n\t\t[`${radioRoot}[data-selected] &`]: {\n\t\t\tbackgroundColor: t(\"color-background-default\"),\n\t\t},\n\t\t[`${radioRoot}[data-selected][data-disabled] &`]: {\n\t\t\tbackgroundColor: t(\"color-background-tertiary\"),\n\t\t},\n\t},\n\t\"@media\": {\n\t\t// Author background-colors collapse to Canvas in forced-colors mode, so the\n\t\t// disc/dot contrast is lost — redraw the dot with a system color instead.\n\t\t\"(forced-colors: active)\": {\n\t\t\tselectors: {\n\t\t\t\t[`${radioRoot}[data-selected] &`]: {\n\t\t\t\t\tbackgroundColor: \"CanvasText\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n});\n\nexport const radioLabel = style({\n\tfontFamily: t(\"font-family-body\"),\n\tfontSize: t(\"font-size-body\"),\n\tfontWeight: t(\"font-weight-regular\"),\n\tlineHeight: t(\"line-height-body\"),\n\tcolor: t(\"color-content-default\"),\n\tselectors: {\n\t\t[`${radioRoot}[data-disabled] &`]: {\n\t\t\tcolor: t(\"color-content-disabled\"),\n\t\t},\n\t},\n});\n"],"mappings":""}
1
+ {"version":3,"file":"Radio.css.js","names":[],"sources":["../../../src/components/Radio/Radio.css.ts"],"sourcesContent":["import { globalStyle, style } from \"@vanilla-extract/css\";\nimport { recipe } from \"@vanilla-extract/recipes\";\nimport { rowFrame, rowSlotRules } from \"../../styles/row.js\";\nimport { t } from \"../../tokens/index.js\";\n\n// Figma's `button-size/xs` (24px) has no LovelaceToken; the checked indicator's\n// inset is likewise fixed visual detail Figma renders as a flattened raster with\n// no token (5px inset inside the 1px border → 12px center dot). Both are\n// hardcoded like a fixed frame size.\nconst CONTROL_SIZE = \"24px\";\nconst INDICATOR_INSET = \"5px\";\n\n// Empty handle class: a recipe can't target a descendant, so the row variant's\n// slot rules are attached to a stable class instead (same trick as Button's base).\nconst radioRowBase = style({});\n\nexport const radioGroup = style({\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tgap: t(\"gap-20\"),\n\tselectors: {\n\t\t'&[data-orientation=\"horizontal\"]': {\n\t\t\tflexDirection: \"row\",\n\t\t},\n\t},\n});\n\n/**\n * The RAC `Radio` label. `inline` lays the control out beside its label; `row` is\n * the 40px selectable row Figma draws for a menu item, for a `RadioGroup`\n * rendered as a list of options.\n */\nexport const radioRoot = recipe({\n\tbase: {\n\t\tcursor: \"pointer\",\n\t\tuserSelect: \"none\",\n\t\tselectors: {\n\t\t\t\"&[data-disabled]\": {\n\t\t\t\tcursor: \"not-allowed\",\n\t\t\t},\n\t\t},\n\t},\n\tvariants: {\n\t\tvariant: {\n\t\t\tinline: {\n\t\t\t\tdisplay: \"inline-flex\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\tgap: t(\"gap-12\"),\n\t\t\t},\n\t\t\trow: [radioRowBase, rowFrame],\n\t\t},\n\t},\n\tdefaultVariants: { variant: \"inline\" },\n});\n\nglobalStyle(`${radioRowBase} > [data-slot=\"icon\"]`, rowSlotRules.icon);\nglobalStyle(`${radioRowBase} > [data-slot=\"label\"]`, rowSlotRules.label);\n\n/**\n * The 24px control circle. Selection and interaction state are read from whichever\n * host element carries React Aria's `data-*` — the RAC label, or a `MenuItem` row —\n * so the rules below are child selectors that name no host. Interaction rules\n * additionally require `[data-state-layer]`, which the indicator sets only when it\n * is the sole affordance; inside a row the row paints hover and focus itself.\n */\nexport const radioControl = style({\n\tposition: \"relative\",\n\tboxSizing: \"border-box\",\n\tflexShrink: 0,\n\twidth: CONTROL_SIZE,\n\theight: CONTROL_SIZE,\n\tborderRadius: t(\"border-radius-full\"),\n\tborderStyle: \"solid\",\n\tborderWidth: t(\"border-width-default\"),\n\t// Unchecked resting state; the selected rules below override it.\n\tbackgroundColor: t(\"color-background-default\"),\n\tborderColor: t(\"color-border-default\"),\n\ttransitionProperty: \"background-color, border-color, box-shadow\",\n\ttransitionDuration: t(\"duration-fast\"),\n\ttransitionTimingFunction: t(\"easing-standard\"),\n\tselectors: {\n\t\t// Unchecked — hover darkens the border only (no fill).\n\t\t\"[data-hovered]:not([data-selected]):not([data-disabled]) > &[data-state-layer]\":\n\t\t\t{\n\t\t\t\tborderColor: t(\"color-border-medium\"),\n\t\t\t},\n\t\t// Checked — solid inverse disc; the white ring is drawn by radioDot.\n\t\t\"[data-selected] > &\": {\n\t\t\tbackgroundColor: t(\"color-background-inverse\"),\n\t\t\tborderColor: t(\"color-background-inverse\"),\n\t\t},\n\t\t// Focus — outer 2px focus ring for both states (matches Chip's double ring).\n\t\t\"[data-focus-visible]:not([data-disabled]) > &[data-state-layer]\": {\n\t\t\tboxShadow: `0 0 0 ${t(\"border-width-focus\")} ${t(\"color-border-focus\")}`,\n\t\t},\n\t\t// Focus (unchecked) — inner accent border completes the double ring.\n\t\t\"[data-focus-visible]:not([data-selected]):not([data-disabled]) > &[data-state-layer]\":\n\t\t\t{\n\t\t\t\tborderColor: t(\"color-border-accent\"),\n\t\t\t},\n\t\t// Disabled — unchecked.\n\t\t\"[data-disabled]:not([data-selected]) > &\": {\n\t\t\tbackgroundColor: t(\"color-background-tertiary\"),\n\t\t\tborderColor: t(\"color-border-default\"),\n\t\t},\n\t\t// Disabled — checked disc fades to the disabled background.\n\t\t\"[data-disabled][data-selected] > &\": {\n\t\t\tbackgroundColor: t(\"color-background-disabled\"),\n\t\t\tborderColor: t(\"color-background-disabled\"),\n\t\t},\n\t},\n\t\"@media\": {\n\t\t\"(forced-colors: active)\": {\n\t\t\tselectors: {\n\t\t\t\t\"[data-focus-visible]:not([data-disabled]) > &[data-state-layer]\": {\n\t\t\t\t\toutline: \"2px solid Highlight\",\n\t\t\t\t\toutlineOffset: \"2px\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n});\n\n// Solid center dot on the checked disc (dark disc → filled light center circle).\n// Hidden (transparent) until the option is selected.\nexport const radioDot = style({\n\tposition: \"absolute\",\n\tinset: INDICATOR_INSET,\n\tborderRadius: t(\"border-radius-full\"),\n\tbackgroundColor: \"transparent\",\n\tpointerEvents: \"none\",\n\tselectors: {\n\t\t[`[data-selected] > ${radioControl} > &`]: {\n\t\t\tbackgroundColor: t(\"color-background-default\"),\n\t\t},\n\t\t[`[data-selected][data-disabled] > ${radioControl} > &`]: {\n\t\t\tbackgroundColor: t(\"color-background-tertiary\"),\n\t\t},\n\t},\n\t\"@media\": {\n\t\t// Author background-colors collapse to Canvas in forced-colors mode, so the\n\t\t// disc/dot contrast is lost — redraw the dot with a system color instead.\n\t\t\"(forced-colors: active)\": {\n\t\t\tselectors: {\n\t\t\t\t[`[data-selected] > ${radioControl} > &`]: {\n\t\t\t\t\tbackgroundColor: \"CanvasText\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n});\n\nexport const radioLabel = style({\n\tfontFamily: t(\"font-family-body\"),\n\tfontSize: t(\"font-size-body\"),\n\tfontWeight: t(\"font-weight-regular\"),\n\tlineHeight: t(\"line-height-body\"),\n\tcolor: t(\"color-content-default\"),\n\tselectors: {\n\t\t\"[data-disabled] > &\": {\n\t\t\tcolor: t(\"color-content-disabled\"),\n\t\t},\n\t},\n});\n"],"mappings":""}
@@ -1,6 +1,13 @@
1
1
  import type { CSSProperties, ReactNode, Ref } from "react";
2
2
  import type { RadioProps as AriaRadioProps } from "react-aria-components";
3
+ export type RadioVariant = "inline" | "row";
3
4
  export interface RadioProps extends Omit<AriaRadioProps, "className" | "style" | "children"> {
5
+ /**
6
+ * `inline` (default) sits the control beside its label at content width. `row`
7
+ * renders the 40px selectable row Figma draws for a menu item — use it for a
8
+ * `RadioGroup` presented as a list of options.
9
+ */
10
+ variant?: RadioVariant;
4
11
  className?: string;
5
12
  style?: CSSProperties;
6
13
  ref?: Ref<HTMLLabelElement>;
@@ -12,4 +19,4 @@ export interface RadioProps extends Omit<AriaRadioProps, "className" | "style" |
12
19
  * checked/hover/focus/disabled states are driven by the data-attributes React
13
20
  * Aria sets on the label, so this component takes no state props of its own.
14
21
  */
15
- export declare function Radio({ className, children, ...rest }: RadioProps): import("react/jsx-runtime").JSX.Element;
22
+ export declare function Radio({ variant, className, children, ...rest }: RadioProps): import("react/jsx-runtime").JSX.Element;
@@ -1,23 +1,21 @@
1
1
  import { cx as e } from "../../utils/cx.js";
2
- import { radioControl as t, radioIndicator as n, radioRoot as r } from "./Radio.css.js";
3
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
4
- import { Radio as o } from "react-aria-components";
2
+ import { radioRoot as t } from "./Radio.css.js";
3
+ import { RadioIndicator as n } from "./RadioIndicator.js";
4
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
5
+ import { Radio as a } from "react-aria-components";
5
6
  //#region src/components/Radio/Radio.tsx
6
- function s({ className: s, children: c, ...l }) {
7
- return /* @__PURE__ */ a(o, {
7
+ function o({ variant: o = "inline", className: s, children: c, ...l }) {
8
+ return /* @__PURE__ */ i(a, {
8
9
  ...l,
9
- className: e(r, s),
10
- children: [/* @__PURE__ */ i("span", {
11
- className: t,
12
- "aria-hidden": "true",
13
- children: /* @__PURE__ */ i("span", { className: n })
14
- }), c != null && /* @__PURE__ */ i("span", {
15
- className: "mufew34",
10
+ className: e(t({ variant: o }), s),
11
+ children: [/* @__PURE__ */ r(n, { hasStateLayer: o === "inline" }), c != null && typeof c != "boolean" && /* @__PURE__ */ r("span", {
12
+ "data-slot": "label",
13
+ className: "mufew37",
16
14
  children: c
17
15
  })]
18
16
  });
19
17
  }
20
18
  //#endregion
21
- export { s as Radio };
19
+ export { o as Radio };
22
20
 
23
21
  //# sourceMappingURL=Radio.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Radio.js","names":[],"sources":["../../../src/components/Radio/Radio.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode, Ref } from \"react\";\nimport type { RadioProps as AriaRadioProps } from \"react-aria-components\";\nimport { Radio as AriaRadio } from \"react-aria-components\";\nimport { cx } from \"../../utils/cx.js\";\nimport {\n\tradioControl,\n\tradioIndicator,\n\tradioLabel,\n\tradioRoot,\n} from \"./Radio.css.js\";\n\nexport interface RadioProps\n\textends Omit<AriaRadioProps, \"className\" | \"style\" | \"children\"> {\n\tclassName?: string;\n\tstyle?: CSSProperties;\n\tref?: Ref<HTMLLabelElement>;\n\t/** Label shown beside the control. Omit only when the option is labelled externally. */\n\tchildren?: ReactNode;\n}\n\n/**\n * A single option within a `RadioGroup`. The visual circle is drawn here; the\n * checked/hover/focus/disabled states are driven by the data-attributes React\n * Aria sets on the label, so this component takes no state props of its own.\n */\nexport function Radio({ className, children, ...rest }: RadioProps) {\n\treturn (\n\t\t<AriaRadio {...rest} className={cx(radioRoot, className)}>\n\t\t\t<span className={radioControl} aria-hidden=\"true\">\n\t\t\t\t<span className={radioIndicator} />\n\t\t\t</span>\n\t\t\t{children != null && <span className={radioLabel}>{children}</span>}\n\t\t</AriaRadio>\n\t);\n}\n"],"mappings":";;;;;AAyBA,SAAgB,EAAM,EAAE,cAAW,aAAU,GAAG,KAAoB;AACnE,QACC,kBAAC,GAAD;EAAW,GAAI;EAAM,WAAW,EAAG,GAAW,EAAU;YAAxD,CACC,kBAAC,QAAD;GAAM,WAAW;GAAc,eAAY;aAC1C,kBAAC,QAAD,EAAM,WAAW,GAAkB,CAAA;GAC7B,CAAA,EACN,KAAY,QAAQ,kBAAC,QAAD;GAAM,WAAA;GAAwB;GAAgB,CAAA,CACxD"}
1
+ {"version":3,"file":"Radio.js","names":[],"sources":["../../../src/components/Radio/Radio.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode, Ref } from \"react\";\nimport type { RadioProps as AriaRadioProps } from \"react-aria-components\";\nimport { Radio as AriaRadio } from \"react-aria-components\";\nimport { cx } from \"../../utils/cx.js\";\nimport { radioLabel, radioRoot } from \"./Radio.css.js\";\nimport { RadioIndicator } from \"./RadioIndicator.js\";\n\nexport type RadioVariant = \"inline\" | \"row\";\n\nexport interface RadioProps\n\textends Omit<AriaRadioProps, \"className\" | \"style\" | \"children\"> {\n\t/**\n\t * `inline` (default) sits the control beside its label at content width. `row`\n\t * renders the 40px selectable row Figma draws for a menu item — use it for a\n\t * `RadioGroup` presented as a list of options.\n\t */\n\tvariant?: RadioVariant;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n\tref?: Ref<HTMLLabelElement>;\n\t/** Label shown beside the control. Omit only when the option is labelled externally. */\n\tchildren?: ReactNode;\n}\n\n/**\n * A single option within a `RadioGroup`. The visual circle is drawn here; the\n * checked/hover/focus/disabled states are driven by the data-attributes React\n * Aria sets on the label, so this component takes no state props of its own.\n */\nexport function Radio({\n\tvariant = \"inline\",\n\tclassName,\n\tchildren,\n\t...rest\n}: RadioProps) {\n\treturn (\n\t\t<AriaRadio {...rest} className={cx(radioRoot({ variant }), className)}>\n\t\t\t<RadioIndicator hasStateLayer={variant === \"inline\"} />\n\t\t\t{children != null && typeof children !== \"boolean\" && (\n\t\t\t\t<span data-slot=\"label\" className={radioLabel}>\n\t\t\t\t\t{children}\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</AriaRadio>\n\t);\n}\n"],"mappings":";;;;;;AA6BA,SAAgB,EAAM,EACrB,aAAU,UACV,cACA,aACA,GAAG,KACW;AACd,QACC,kBAAC,GAAD;EAAW,GAAI;EAAM,WAAW,EAAG,EAAU,EAAE,YAAS,CAAC,EAAE,EAAU;YAArE,CACC,kBAAC,GAAD,EAAgB,eAAe,MAAY,UAAY,CAAA,EACtD,KAAY,QAAQ,OAAO,KAAa,aACxC,kBAAC,QAAD;GAAM,aAAU;GAAQ,WAAA;GACtB;GACK,CAAA,CAEG"}
@@ -0,0 +1,22 @@
1
+ import type { Ref } from "react";
2
+ export interface RadioIndicatorProps {
3
+ /**
4
+ * Draw the control's own hover border, focus ring and state layer. True for a
5
+ * standalone `Radio`, where the circle is the only affordance; false inside a
6
+ * row, which draws those on the row itself — leaving it true there would paint
7
+ * both.
8
+ */
9
+ hasStateLayer?: boolean;
10
+ className?: string;
11
+ ref?: Ref<HTMLSpanElement>;
12
+ }
13
+ /**
14
+ * The 24px radio circle and its center dot, with no control of its own.
15
+ *
16
+ * Selection and disabled state are read from whichever ancestor element carries
17
+ * React Aria's `data-selected` / `data-disabled` — the RAC `Radio` label, or a
18
+ * `MenuItem` row — so the same markup and the same styles serve both hosts and
19
+ * cannot drift apart. It must stay a **direct** child of that element; the state
20
+ * rules use a child selector so an unrelated selected ancestor can't reach in.
21
+ */
22
+ export declare function RadioIndicator({ hasStateLayer, className, ref, }: RadioIndicatorProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { cx as e } from "../../utils/cx.js";
2
+ import { radioControl as t, radioDot as n } from "./Radio.css.js";
3
+ import { jsx as r } from "react/jsx-runtime";
4
+ //#region src/components/Radio/RadioIndicator.tsx
5
+ function i({ hasStateLayer: i = !0, className: a, ref: o }) {
6
+ return /* @__PURE__ */ r("span", {
7
+ ref: o,
8
+ "data-slot": "indicator",
9
+ "data-state-layer": i || void 0,
10
+ className: e(t, a),
11
+ "aria-hidden": "true",
12
+ children: /* @__PURE__ */ r("span", { className: n })
13
+ });
14
+ }
15
+ //#endregion
16
+ export { i as RadioIndicator };
17
+
18
+ //# sourceMappingURL=RadioIndicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioIndicator.js","names":[],"sources":["../../../src/components/Radio/RadioIndicator.tsx"],"sourcesContent":["import type { Ref } from \"react\";\nimport { cx } from \"../../utils/cx.js\";\nimport { radioControl, radioDot } from \"./Radio.css.js\";\n\nexport interface RadioIndicatorProps {\n\t/**\n\t * Draw the control's own hover border, focus ring and state layer. True for a\n\t * standalone `Radio`, where the circle is the only affordance; false inside a\n\t * row, which draws those on the row itself — leaving it true there would paint\n\t * both.\n\t */\n\thasStateLayer?: boolean;\n\tclassName?: string;\n\tref?: Ref<HTMLSpanElement>;\n}\n\n/**\n * The 24px radio circle and its center dot, with no control of its own.\n *\n * Selection and disabled state are read from whichever ancestor element carries\n * React Aria's `data-selected` / `data-disabled` — the RAC `Radio` label, or a\n * `MenuItem` row — so the same markup and the same styles serve both hosts and\n * cannot drift apart. It must stay a **direct** child of that element; the state\n * rules use a child selector so an unrelated selected ancestor can't reach in.\n */\nexport function RadioIndicator({\n\thasStateLayer = true,\n\tclassName,\n\tref,\n}: RadioIndicatorProps) {\n\treturn (\n\t\t<span\n\t\t\tref={ref}\n\t\t\tdata-slot=\"indicator\"\n\t\t\tdata-state-layer={hasStateLayer || undefined}\n\t\t\tclassName={cx(radioControl, className)}\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<span className={radioDot} />\n\t\t</span>\n\t);\n}\n"],"mappings":";;;;AAyBA,SAAgB,EAAe,EAC9B,mBAAgB,IAChB,cACA,UACuB;AACvB,QACC,kBAAC,QAAD;EACM;EACL,aAAU;EACV,oBAAkB,KAAiB,KAAA;EACnC,WAAW,EAAG,GAAc,EAAU;EACtC,eAAY;YAEZ,kBAAC,QAAD,EAAM,WAAW,GAAY,CAAA;EACvB,CAAA"}
@@ -1,4 +1,4 @@
1
- export type { RadioProps } from "./Radio.js";
1
+ export type { RadioProps, RadioVariant } from "./Radio.js";
2
2
  export { Radio } from "./Radio.js";
3
3
  export type { RadioGroupProps } from "./RadioGroup.js";
4
4
  export { RadioGroup } from "./RadioGroup.js";
@@ -1 +1 @@
1
- {"version":3,"file":"Sheet.css.js","names":[],"sources":["../../../src/components/Sheet/Sheet.css.ts"],"sourcesContent":["import { style } from \"@vanilla-extract/css\";\nimport { t } from \"../../tokens/index.js\";\n\n/* ── Sheet (bare content surface) ─────────────────────────────────────── */\n\nexport const sheetRoot = style({\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tflex: \"1 1 auto\",\n\tminHeight: 0,\n\tmaxHeight: \"100%\",\n\twidth: \"100%\",\n\tboxSizing: \"border-box\",\n\tbackgroundColor: t(\"color-background-default\"),\n\tcolor: t(\"color-content-default\"),\n\tfontFamily: t(\"font-family-body\"),\n\tfontSize: t(\"font-size-body\"),\n\tlineHeight: t(\"line-height-body\"),\n});\n\n/* ── Sheet.Header ─────────────────────────────────────────────────────── */\n\nexport const sheetHeader = style({\n\tposition: \"relative\",\n\tflexShrink: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n\t// Figma: fixed 56px header height.\n\theight: \"56px\",\n\tpaddingInline: t(\"padding-12\"),\n\tboxSizing: \"border-box\",\n});\n\nexport const sheetHeaderTitle = style({\n\tmargin: 0,\n\tcolor: t(\"color-content-default\"),\n\tfontFamily: t(\"font-family-body\"),\n\tfontWeight: t(\"font-weight-medium\"),\n\tfontSize: t(\"font-size-body\"),\n\tlineHeight: t(\"line-height-body\"),\n\ttextAlign: \"center\",\n});\n\n// Edge buttons are pinned (absolute) so the title stays centered even with a\n// single button present. Logical insets mirror correctly under RTL.\nexport const sheetHeaderStart = style({\n\tposition: \"absolute\",\n\tinsetInlineStart: t(\"padding-12\"),\n\ttop: 0,\n\tbottom: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n});\n\nexport const sheetHeaderEnd = style({\n\tposition: \"absolute\",\n\tinsetInlineEnd: t(\"padding-12\"),\n\ttop: 0,\n\tbottom: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n});\n\n// Back is a reading-direction affordance: the chevron mirrors under RTL.\nexport const sheetBackIcon = style({\n\tselectors: {\n\t\t'[dir=\"rtl\"] &': { transform: \"scaleX(-1)\" },\n\t},\n});\n\n/* ── Sheet.Body ───────────────────────────────────────────────────────── */\n\n// flex:0 1 auto + min-height:0 + overflow:auto is the single rule that makes\n// the body scroll when a parent caps the height (floating) and hug content\n// when uncapped (inline) — with no mode flag.\nexport const sheetBody = style({\n\tflex: \"0 1 auto\",\n\tminHeight: 0,\n\toverflowY: \"auto\",\n\tpadding: t(\"padding-12\"),\n\tboxSizing: \"border-box\",\n\tscrollbarWidth: \"thin\",\n\tscrollbarColor: `${t(\"color-border-default\")} transparent`,\n});\n\n/* ── Sheet.Actions ────────────────────────────────────────────────────── */\n\nexport const sheetActions = style({\n\tflexShrink: 0,\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\talignItems: \"stretch\",\n\tgap: t(\"gap-12\"),\n\tpadding: t(\"padding-12\"),\n\tboxSizing: \"border-box\",\n});\n"],"mappings":""}
1
+ {"version":3,"file":"Sheet.css.js","names":[],"sources":["../../../src/components/Sheet/Sheet.css.ts"],"sourcesContent":["import { style } from \"@vanilla-extract/css\";\nimport { t } from \"../../tokens/index.js\";\n\n/* ── Sheet (bare content surface) ─────────────────────────────────────── */\n\n/* `0 1 auto` hugs content but yields once the parent runs out of room, so an inline\n sheet never pushes its actions past the parent's edge. `1 1 auto` forced every\n inline consumer to override `flex`, and the natural override — `0 0 auto` — quietly\n deleted the shrink the body's scrolling depends on. `overflow-y` is the last\n resort: inert until the actions alone outgrow the sheet, where scrolling the whole\n sheet is the only thing that keeps them reachable. */\nexport const sheetRoot = style({\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\tflex: \"0 1 auto\",\n\tminHeight: 0,\n\tmaxHeight: \"100%\",\n\toverflowY: \"auto\",\n\twidth: \"100%\",\n\tboxSizing: \"border-box\",\n\tbackgroundColor: t(\"color-background-default\"),\n\tcolor: t(\"color-content-default\"),\n\tfontFamily: t(\"font-family-body\"),\n\tfontSize: t(\"font-size-body\"),\n\tlineHeight: t(\"line-height-body\"),\n});\n\n/* ── Sheet.Header ─────────────────────────────────────────────────────── */\n\nexport const sheetHeader = style({\n\tposition: \"relative\",\n\tflexShrink: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n\t// Figma: fixed 56px header height.\n\theight: \"56px\",\n\tpaddingInline: t(\"padding-12\"),\n\tboxSizing: \"border-box\",\n});\n\nexport const sheetHeaderTitle = style({\n\tmargin: 0,\n\tcolor: t(\"color-content-default\"),\n\tfontFamily: t(\"font-family-body\"),\n\tfontWeight: t(\"font-weight-medium\"),\n\tfontSize: t(\"font-size-body\"),\n\tlineHeight: t(\"line-height-body\"),\n\ttextAlign: \"center\",\n});\n\n// Edge buttons are pinned (absolute) so the title stays centered even with a\n// single button present. Logical insets mirror correctly under RTL.\nexport const sheetHeaderStart = style({\n\tposition: \"absolute\",\n\tinsetInlineStart: t(\"padding-12\"),\n\ttop: 0,\n\tbottom: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n});\n\nexport const sheetHeaderEnd = style({\n\tposition: \"absolute\",\n\tinsetInlineEnd: t(\"padding-12\"),\n\ttop: 0,\n\tbottom: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n});\n\n// Back is a reading-direction affordance: the chevron mirrors under RTL.\nexport const sheetBackIcon = style({\n\tselectors: {\n\t\t'[dir=\"rtl\"] &': { transform: \"scaleX(-1)\" },\n\t},\n});\n\n/* ── Sheet.Body ───────────────────────────────────────────────────────── */\n\n// flex:0 1 auto + overflow:auto is the single rule that makes the body scroll\n// when a parent caps the height (floating) and hug content when uncapped\n// (inline) — with no mode flag.\nexport const sheetBody = style({\n\tflex: \"0 1 auto\",\n\t// Floor so a squeezed body keeps one option row rather than collapsing to\n\t// nothing: past this the sheet itself scrolls instead.\n\tminHeight: t(\"spacing-48\"),\n\toverflowY: \"auto\",\n\tpadding: t(\"padding-12\"),\n\tboxSizing: \"border-box\",\n\tscrollbarWidth: \"thin\",\n\tscrollbarColor: `${t(\"color-border-default\")} transparent`,\n});\n\n/* ── Sheet.Actions ────────────────────────────────────────────────────── */\n\nexport const sheetActions = style({\n\tflexShrink: 0,\n\tdisplay: \"flex\",\n\tflexDirection: \"column\",\n\talignItems: \"stretch\",\n\tgap: t(\"gap-12\"),\n\tpadding: t(\"padding-12\"),\n\tboxSizing: \"border-box\",\n});\n"],"mappings":""}
@@ -1,11 +1,22 @@
1
1
  /**
2
- * The RAC `Switch` label, styled as the pill track. It is the interactive element,
3
- * so it carries the state `data-*` and hosts the shared state-layer `::after`
4
- * directly (self-selector form, like Button/Chip). `color` is the inverse content
5
- * color, so the `currentColor` overlay reads as a white veil over the green / neutral
6
- * track — matching Figma's white state overlays — with no per-state plumbing.
2
+ * The RAC `Switch` label. It carries the interaction `data-*` but draws nothing
3
+ * itself the pill is `toggleTrack`, so the same track can be hosted by a
4
+ * `MenuItem` row instead.
7
5
  */
8
6
  export declare const toggleRoot: string;
7
+ /**
8
+ * The pill track. Selection and interaction state are read from whichever host
9
+ * element carries React Aria's `data-*` — the RAC `Switch` label, or a `MenuItem`
10
+ * row — so the rules below are child selectors that name no host. `color` is the
11
+ * inverse content color, so the `currentColor` overlay reads as a white veil over
12
+ * the green / neutral track — matching Figma's white state overlays — with no
13
+ * per-state plumbing.
14
+ *
15
+ * Interaction rules additionally require `[data-state-layer]`, which the track
16
+ * sets only when it is the sole affordance; inside a row the row paints hover and
17
+ * focus itself.
18
+ */
19
+ export declare const toggleTrack: string;
9
20
  /**
10
21
  * The 22px thumb. Absolutely positioned and slid by `inset-inline-start` — a
11
22
  * logical property, so it mirrors leading↔trailing under `dir="rtl"` on its own,
@@ -1,7 +1,7 @@
1
1
  /* empty css */
2
2
  //#region src/components/Toggle/Toggle.css.ts
3
- var e = "_1s0itzy0", t = "_1s0itzy1";
3
+ var e = "_1s0itzy0", t = "_1s0itzy1", n = "_1s0itzy2";
4
4
  //#endregion
5
- export { e as toggleRoot, t as toggleThumb };
5
+ export { e as toggleRoot, n as toggleThumb, t as toggleTrack };
6
6
 
7
7
  //# sourceMappingURL=Toggle.css.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Toggle.css.js","names":[],"sources":["../../../src/components/Toggle/Toggle.css.ts"],"sourcesContent":["import { style } from \"@vanilla-extract/css\";\nimport { t } from \"../../tokens/index.js\";\n\n// Figma pins the track at a fixed 44×24 frame and the thumb at 22px with a 1px\n// inset — control-size tiers the token set doesn't expose yet (same treatment as\n// Checkbox's 24px box and Radio's indicator inset).\nconst TRACK_WIDTH = \"44px\";\nconst TRACK_HEIGHT = \"24px\";\nconst THUMB_SIZE = \"22px\";\nconst THUMB_INSET = \"1px\";\n// Trailing rest position: full track − thumb − the trailing inset.\nconst THUMB_TRAVEL_END = `calc(100% - ${THUMB_SIZE} - ${THUMB_INSET})`;\n\n// Elevation shadows Figma draws on the resting off-track and the thumb; no\n// elevation-* token tier exists yet, so these stay literal (contract rule 2).\nconst OFF_TRACK_ELEVATION = \"0 1px 1px rgba(0, 0, 0, 0.08)\";\nconst THUMB_ELEVATION = \"0 1px 2px rgba(0, 0, 0, 0.08)\";\n\nconst FOCUS_RING = `0 0 0 ${t(\"border-width-focus\")} ${t(\"color-border-focus\")}`;\n\n// TOKEN GAP: disabled-on is Figma's success green under a 30% white veil, which\n// no opacity-state-* member covers (hover .08 / focus .1 / pressed .1). The shared\n// currentColor overlay is raised to a literal 0.3 here until an\n// `opacity-state-disabled` token exists (surfaced per contract rule 3).\nconst DISABLED_OVERLAY_OPACITY = 0.3;\n\n/**\n * The RAC `Switch` label, styled as the pill track. It is the interactive element,\n * so it carries the state `data-*` and hosts the shared state-layer `::after`\n * directly (self-selector form, like Button/Chip). `color` is the inverse content\n * color, so the `currentColor` overlay reads as a white veil over the green / neutral\n * track — matching Figma's white state overlays — with no per-state plumbing.\n */\nexport const toggleRoot = style({\n\tposition: \"relative\",\n\tisolation: \"isolate\",\n\tboxSizing: \"border-box\",\n\tdisplay: \"inline-block\",\n\tflexShrink: 0,\n\twidth: TRACK_WIDTH,\n\theight: TRACK_HEIGHT,\n\tborderRadius: t(\"border-radius-full\"),\n\tbackgroundColor: t(\"color-background-quaternary\"),\n\tcolor: t(\"color-content-inverse\"),\n\tcursor: \"pointer\",\n\toutline: \"none\",\n\tboxShadow: OFF_TRACK_ELEVATION,\n\t\"::after\": {\n\t\tcontent: '\"\"',\n\t\tposition: \"absolute\",\n\t\tinset: 0,\n\t\tborderRadius: \"inherit\",\n\t\tbackgroundColor: \"currentColor\",\n\t\topacity: 0,\n\t\tpointerEvents: \"none\",\n\t\tzIndex: -1,\n\t},\n\tselectors: {\n\t\t// On — success-green track; the resting off-track elevation is dropped.\n\t\t\"&[data-selected]\": {\n\t\t\tbackgroundColor: t(\"color-background-success\"),\n\t\t\tboxShadow: \"none\",\n\t\t},\n\t\t// State layer — currentColor (white) veil at per-state opacity, off & on.\n\t\t\"&[data-hovered]:not([data-disabled])::after\": {\n\t\t\topacity: t(\"opacity-state-hover\"),\n\t\t},\n\t\t\"&[data-focus-visible]:not([data-disabled])::after\": {\n\t\t\topacity: t(\"opacity-state-focus\"),\n\t\t},\n\t\t\"&[data-pressed]:not([data-disabled])::after\": {\n\t\t\topacity: t(\"opacity-state-pressed\"),\n\t\t},\n\t\t// Focus ring — outset box-shadow so it never resizes the pill (matches\n\t\t// Checkbox/Radio); pairs with the focus veil above.\n\t\t\"&[data-focus-visible]:not([data-disabled])\": {\n\t\t\tboxShadow: FOCUS_RING,\n\t\t},\n\t\t// Disabled — off track fades to the disabled surface; pointer blocked.\n\t\t\"&[data-disabled]\": {\n\t\t\tcursor: \"not-allowed\",\n\t\t\tbackgroundColor: t(\"color-background-disabled\"),\n\t\t\tboxShadow: \"none\",\n\t\t},\n\t\t// Disabled — on track stays green under the 30% white veil (see const above).\n\t\t\"&[data-disabled][data-selected]\": {\n\t\t\tbackgroundColor: t(\"color-background-success\"),\n\t\t},\n\t\t\"&[data-disabled][data-selected]::after\": {\n\t\t\topacity: DISABLED_OVERLAY_OPACITY,\n\t\t},\n\t},\n\t\"@media\": {\n\t\t\"(prefers-reduced-motion: no-preference)\": {\n\t\t\ttransitionProperty: \"background-color, box-shadow\",\n\t\t\ttransitionDuration: t(\"duration-fast\"),\n\t\t\ttransitionTimingFunction: t(\"easing-standard\"),\n\t\t\tselectors: {\n\t\t\t\t\"&::after\": {\n\t\t\t\t\ttransition: `opacity ${t(\"duration-fast\")} ${t(\"easing-standard\")}`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Token-based focus rings vanish under forced colors — redraw in a system color.\n\t\t\"(forced-colors: active)\": {\n\t\t\tselectors: {\n\t\t\t\t\"&[data-focus-visible]:not([data-disabled])\": {\n\t\t\t\t\toutline: \"2px solid Highlight\",\n\t\t\t\t\toutlineOffset: \"2px\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n});\n\n/**\n * The 22px thumb. Absolutely positioned and slid by `inset-inline-start` — a\n * logical property, so it mirrors leading↔trailing under `dir=\"rtl\"` on its own,\n * with no direction prop or selector.\n */\nexport const toggleThumb = style({\n\tposition: \"absolute\",\n\tinsetBlockStart: THUMB_INSET,\n\tinsetInlineStart: THUMB_INSET,\n\twidth: THUMB_SIZE,\n\theight: THUMB_SIZE,\n\tborderRadius: t(\"border-radius-full\"),\n\tbackgroundColor: t(\"color-background-default\"),\n\tboxShadow: THUMB_ELEVATION,\n\tpointerEvents: \"none\",\n\tselectors: {\n\t\t[`${toggleRoot}[data-selected] &`]: {\n\t\t\tinsetInlineStart: THUMB_TRAVEL_END,\n\t\t},\n\t},\n\t\"@media\": {\n\t\t\"(prefers-reduced-motion: no-preference)\": {\n\t\t\ttransition: `inset-inline-start ${t(\"duration-fast\")} ${t(\"easing-standard\")}`,\n\t\t},\n\t},\n});\n"],"mappings":""}
1
+ {"version":3,"file":"Toggle.css.js","names":[],"sources":["../../../src/components/Toggle/Toggle.css.ts"],"sourcesContent":["import { style } from \"@vanilla-extract/css\";\nimport { t } from \"../../tokens/index.js\";\n\n// Figma pins the track at a fixed 44×24 frame and the thumb at 22px with a 1px\n// inset — control-size tiers the token set doesn't expose yet (same treatment as\n// Checkbox's 24px box and Radio's control size).\nconst TRACK_WIDTH = \"44px\";\nconst TRACK_HEIGHT = \"24px\";\nconst THUMB_SIZE = \"22px\";\nconst THUMB_INSET = \"1px\";\n// Trailing rest position: full track − thumb − the trailing inset.\nconst THUMB_TRAVEL_END = `calc(100% - ${THUMB_SIZE} - ${THUMB_INSET})`;\n\n// Elevation shadows Figma draws on the resting off-track and the thumb; no\n// elevation-* token tier exists yet, so these stay literal (contract rule 2).\nconst OFF_TRACK_ELEVATION = \"0 1px 1px rgba(0, 0, 0, 0.08)\";\nconst THUMB_ELEVATION = \"0 1px 2px rgba(0, 0, 0, 0.08)\";\n\nconst FOCUS_RING = `0 0 0 ${t(\"border-width-focus\")} ${t(\"color-border-focus\")}`;\n\n// TOKEN GAP: disabled-on is Figma's success green under a 30% white veil, which\n// no opacity-state-* member covers (hover .08 / focus .1 / pressed .1). The shared\n// currentColor overlay is raised to a literal 0.3 here until an\n// `opacity-state-disabled` token exists (surfaced per contract rule 3).\nconst DISABLED_OVERLAY_OPACITY = 0.3;\n\n/**\n * The RAC `Switch` label. It carries the interaction `data-*` but draws nothing\n * itself — the pill is `toggleTrack`, so the same track can be hosted by a\n * `MenuItem` row instead.\n */\nexport const toggleRoot = style({\n\tdisplay: \"inline-flex\",\n\tflexShrink: 0,\n\tcursor: \"pointer\",\n\toutline: \"none\",\n\tselectors: {\n\t\t\"&[data-disabled]\": {\n\t\t\tcursor: \"not-allowed\",\n\t\t},\n\t},\n});\n\n/**\n * The pill track. Selection and interaction state are read from whichever host\n * element carries React Aria's `data-*` the RAC `Switch` label, or a `MenuItem`\n * row so the rules below are child selectors that name no host. `color` is the\n * inverse content color, so the `currentColor` overlay reads as a white veil over\n * the green / neutral track — matching Figma's white state overlays — with no\n * per-state plumbing.\n *\n * Interaction rules additionally require `[data-state-layer]`, which the track\n * sets only when it is the sole affordance; inside a row the row paints hover and\n * focus itself.\n */\nexport const toggleTrack = style({\n\tposition: \"relative\",\n\tisolation: \"isolate\",\n\tboxSizing: \"border-box\",\n\tdisplay: \"inline-block\",\n\tflexShrink: 0,\n\twidth: TRACK_WIDTH,\n\theight: TRACK_HEIGHT,\n\tborderRadius: t(\"border-radius-full\"),\n\tbackgroundColor: t(\"color-background-quaternary\"),\n\tcolor: t(\"color-content-inverse\"),\n\tboxShadow: OFF_TRACK_ELEVATION,\n\t\"::after\": {\n\t\tcontent: '\"\"',\n\t\tposition: \"absolute\",\n\t\tinset: 0,\n\t\tborderRadius: \"inherit\",\n\t\tbackgroundColor: \"currentColor\",\n\t\topacity: 0,\n\t\tpointerEvents: \"none\",\n\t\tzIndex: -1,\n\t},\n\tselectors: {\n\t\t// On — success-green track; the resting off-track elevation is dropped.\n\t\t\"[data-selected] > &\": {\n\t\t\tbackgroundColor: t(\"color-background-success\"),\n\t\t\tboxShadow: \"none\",\n\t\t},\n\t\t// State layer — currentColor (white) veil at per-state opacity, off & on.\n\t\t\"[data-hovered]:not([data-disabled]) > &[data-state-layer]::after\": {\n\t\t\topacity: t(\"opacity-state-hover\"),\n\t\t},\n\t\t\"[data-focus-visible]:not([data-disabled]) > &[data-state-layer]::after\": {\n\t\t\topacity: t(\"opacity-state-focus\"),\n\t\t},\n\t\t\"[data-pressed]:not([data-disabled]) > &[data-state-layer]::after\": {\n\t\t\topacity: t(\"opacity-state-pressed\"),\n\t\t},\n\t\t// Focus ring — outset box-shadow so it never resizes the pill (matches\n\t\t// Checkbox/Radio); pairs with the focus veil above.\n\t\t\"[data-focus-visible]:not([data-disabled]) > &[data-state-layer]\": {\n\t\t\tboxShadow: FOCUS_RING,\n\t\t},\n\t\t// Disabled — off track fades to the disabled surface.\n\t\t\"[data-disabled] > &\": {\n\t\t\tbackgroundColor: t(\"color-background-disabled\"),\n\t\t\tboxShadow: \"none\",\n\t\t},\n\t\t// Disabled — on track stays green under the 30% white veil (see const above).\n\t\t\"[data-disabled][data-selected] > &\": {\n\t\t\tbackgroundColor: t(\"color-background-success\"),\n\t\t},\n\t\t\"[data-disabled][data-selected] > &::after\": {\n\t\t\topacity: DISABLED_OVERLAY_OPACITY,\n\t\t},\n\t},\n\t\"@media\": {\n\t\t\"(prefers-reduced-motion: no-preference)\": {\n\t\t\ttransitionProperty: \"background-color, box-shadow\",\n\t\t\ttransitionDuration: t(\"duration-fast\"),\n\t\t\ttransitionTimingFunction: t(\"easing-standard\"),\n\t\t\tselectors: {\n\t\t\t\t\"&::after\": {\n\t\t\t\t\ttransition: `opacity ${t(\"duration-fast\")} ${t(\"easing-standard\")}`,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Token-based focus rings vanish under forced colors — redraw in a system color.\n\t\t\"(forced-colors: active)\": {\n\t\t\tselectors: {\n\t\t\t\t\"[data-focus-visible]:not([data-disabled]) > &[data-state-layer]\": {\n\t\t\t\t\toutline: \"2px solid Highlight\",\n\t\t\t\t\toutlineOffset: \"2px\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n});\n\n/**\n * The 22px thumb. Absolutely positioned and slid by `inset-inline-start` — a\n * logical property, so it mirrors leading↔trailing under `dir=\"rtl\"` on its own,\n * with no direction prop or selector.\n */\nexport const toggleThumb = style({\n\tposition: \"absolute\",\n\tinsetBlockStart: THUMB_INSET,\n\tinsetInlineStart: THUMB_INSET,\n\twidth: THUMB_SIZE,\n\theight: THUMB_SIZE,\n\tborderRadius: t(\"border-radius-full\"),\n\tbackgroundColor: t(\"color-background-default\"),\n\tboxShadow: THUMB_ELEVATION,\n\tpointerEvents: \"none\",\n\tselectors: {\n\t\t[`[data-selected] > ${toggleTrack} > &`]: {\n\t\t\tinsetInlineStart: THUMB_TRAVEL_END,\n\t\t},\n\t},\n\t\"@media\": {\n\t\t\"(prefers-reduced-motion: no-preference)\": {\n\t\t\ttransition: `inset-inline-start ${t(\"duration-fast\")} ${t(\"easing-standard\")}`,\n\t\t},\n\t},\n});\n"],"mappings":""}
@@ -1,5 +1,6 @@
1
1
  import { cx as e } from "../../utils/cx.js";
2
- import { toggleRoot as t, toggleThumb as n } from "./Toggle.css.js";
2
+ import { toggleRoot as t } from "./Toggle.css.js";
3
+ import { ToggleIndicator as n } from "./ToggleIndicator.js";
3
4
  import { jsx as r } from "react/jsx-runtime";
4
5
  import { Switch as i } from "react-aria-components";
5
6
  //#region src/components/Toggle/Toggle.tsx
@@ -7,10 +8,7 @@ function a({ className: a, ...o }) {
7
8
  return /* @__PURE__ */ r(i, {
8
9
  ...o,
9
10
  className: e(t, a),
10
- children: /* @__PURE__ */ r("span", {
11
- className: n,
12
- "aria-hidden": "true"
13
- })
11
+ children: /* @__PURE__ */ r(n, {})
14
12
  });
15
13
  }
16
14
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"Toggle.js","names":[],"sources":["../../../src/components/Toggle/Toggle.tsx"],"sourcesContent":["import type { CSSProperties, Ref } from \"react\";\nimport type { SwitchProps as AriaSwitchProps } from \"react-aria-components\";\nimport { Switch as AriaSwitch } from \"react-aria-components\";\nimport { cx } from \"../../utils/cx.js\";\nimport { toggleRoot, toggleThumb } from \"./Toggle.css.js\";\n\nexport interface ToggleProps\n\textends Omit<AriaSwitchProps, \"children\" | \"className\" | \"style\"> {\n\tclassName?: string;\n\tstyle?: CSSProperties;\n\tref?: Ref<HTMLLabelElement>;\n}\n\n/**\n * A binary on/off switch that applies instantly (RAC `Switch`, `role=\"switch\"`).\n * On renders the success-green track with the thumb at the trailing edge; off\n * renders the neutral track with the thumb leading. Track-only — give it an\n * accessible name with `aria-label` / `aria-labelledby`.\n *\n * Value is `isSelected` / `defaultSelected` / `onChange`; disabled is `isDisabled`.\n * Interaction states (hover/focus/pressed) and RTL mirroring come from RAC `data-*`\n * and the ambient `dir` — not props.\n */\nexport function Toggle({ className, ...rest }: ToggleProps) {\n\treturn (\n\t\t<AriaSwitch {...rest} className={cx(toggleRoot, className)}>\n\t\t\t<span className={toggleThumb} aria-hidden=\"true\" />\n\t\t</AriaSwitch>\n\t);\n}\n"],"mappings":";;;;;AAuBA,SAAgB,EAAO,EAAE,cAAW,GAAG,KAAqB;AAC3D,QACC,kBAAC,GAAD;EAAY,GAAI;EAAM,WAAW,EAAG,GAAY,EAAU;YACzD,kBAAC,QAAD;GAAM,WAAW;GAAa,eAAY;GAAS,CAAA;EACvC,CAAA"}
1
+ {"version":3,"file":"Toggle.js","names":[],"sources":["../../../src/components/Toggle/Toggle.tsx"],"sourcesContent":["import type { CSSProperties, Ref } from \"react\";\nimport type { SwitchProps as AriaSwitchProps } from \"react-aria-components\";\nimport { Switch as AriaSwitch } from \"react-aria-components\";\nimport { cx } from \"../../utils/cx.js\";\nimport { toggleRoot } from \"./Toggle.css.js\";\nimport { ToggleIndicator } from \"./ToggleIndicator.js\";\n\nexport interface ToggleProps\n\textends Omit<AriaSwitchProps, \"children\" | \"className\" | \"style\"> {\n\tclassName?: string;\n\tstyle?: CSSProperties;\n\tref?: Ref<HTMLLabelElement>;\n}\n\n/**\n * A binary on/off switch that applies instantly (RAC `Switch`, `role=\"switch\"`).\n * On renders the success-green track with the thumb at the trailing edge; off\n * renders the neutral track with the thumb leading. Track-only — give it an\n * accessible name with `aria-label` / `aria-labelledby`.\n *\n * Value is `isSelected` / `defaultSelected` / `onChange`; disabled is `isDisabled`.\n * Interaction states (hover/focus/pressed) and RTL mirroring come from RAC `data-*`\n * and the ambient `dir` — not props.\n */\nexport function Toggle({ className, ...rest }: ToggleProps) {\n\treturn (\n\t\t<AriaSwitch {...rest} className={cx(toggleRoot, className)}>\n\t\t\t<ToggleIndicator />\n\t\t</AriaSwitch>\n\t);\n}\n"],"mappings":";;;;;;AAwBA,SAAgB,EAAO,EAAE,cAAW,GAAG,KAAqB;AAC3D,QACC,kBAAC,GAAD;EAAY,GAAI;EAAM,WAAW,EAAG,GAAY,EAAU;YACzD,kBAAC,GAAD,EAAmB,CAAA;EACP,CAAA"}
@@ -0,0 +1,21 @@
1
+ import type { Ref } from "react";
2
+ export interface ToggleIndicatorProps {
3
+ /**
4
+ * Draw the track's own focus ring and state-layer veil. True for a standalone
5
+ * `Toggle`, where the pill is the only affordance; false inside a row, which
6
+ * draws those on the row itself — leaving it true there would paint both.
7
+ */
8
+ hasStateLayer?: boolean;
9
+ className?: string;
10
+ ref?: Ref<HTMLSpanElement>;
11
+ }
12
+ /**
13
+ * The pill track and its thumb, with no control of its own.
14
+ *
15
+ * On/off and disabled state are read from whichever ancestor element carries React
16
+ * Aria's `data-selected` / `data-disabled` — the RAC `Switch` label, or a
17
+ * `MenuItem` row — so the same markup and the same styles serve both hosts and
18
+ * cannot drift apart. It must stay a **direct** child of that element; the state
19
+ * rules use a child selector so an unrelated selected ancestor can't reach in.
20
+ */
21
+ export declare function ToggleIndicator({ hasStateLayer, className, ref, }: ToggleIndicatorProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { cx as e } from "../../utils/cx.js";
2
+ import { toggleThumb as t, toggleTrack as n } from "./Toggle.css.js";
3
+ import { jsx as r } from "react/jsx-runtime";
4
+ //#region src/components/Toggle/ToggleIndicator.tsx
5
+ function i({ hasStateLayer: i = !0, className: a, ref: o }) {
6
+ return /* @__PURE__ */ r("span", {
7
+ ref: o,
8
+ "data-slot": "indicator",
9
+ "data-state-layer": i || void 0,
10
+ className: e(n, a),
11
+ "aria-hidden": "true",
12
+ children: /* @__PURE__ */ r("span", { className: t })
13
+ });
14
+ }
15
+ //#endregion
16
+ export { i as ToggleIndicator };
17
+
18
+ //# sourceMappingURL=ToggleIndicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleIndicator.js","names":[],"sources":["../../../src/components/Toggle/ToggleIndicator.tsx"],"sourcesContent":["import type { Ref } from \"react\";\nimport { cx } from \"../../utils/cx.js\";\nimport { toggleThumb, toggleTrack } from \"./Toggle.css.js\";\n\nexport interface ToggleIndicatorProps {\n\t/**\n\t * Draw the track's own focus ring and state-layer veil. True for a standalone\n\t * `Toggle`, where the pill is the only affordance; false inside a row, which\n\t * draws those on the row itself — leaving it true there would paint both.\n\t */\n\thasStateLayer?: boolean;\n\tclassName?: string;\n\tref?: Ref<HTMLSpanElement>;\n}\n\n/**\n * The pill track and its thumb, with no control of its own.\n *\n * On/off and disabled state are read from whichever ancestor element carries React\n * Aria's `data-selected` / `data-disabled` — the RAC `Switch` label, or a\n * `MenuItem` row — so the same markup and the same styles serve both hosts and\n * cannot drift apart. It must stay a **direct** child of that element; the state\n * rules use a child selector so an unrelated selected ancestor can't reach in.\n */\nexport function ToggleIndicator({\n\thasStateLayer = true,\n\tclassName,\n\tref,\n}: ToggleIndicatorProps) {\n\treturn (\n\t\t<span\n\t\t\tref={ref}\n\t\t\tdata-slot=\"indicator\"\n\t\t\tdata-state-layer={hasStateLayer || undefined}\n\t\t\tclassName={cx(toggleTrack, className)}\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<span className={toggleThumb} />\n\t\t</span>\n\t);\n}\n"],"mappings":";;;;AAwBA,SAAgB,EAAgB,EAC/B,mBAAgB,IAChB,cACA,UACwB;AACxB,QACC,kBAAC,QAAD;EACM;EACL,aAAU;EACV,oBAAkB,KAAiB,KAAA;EACnC,WAAW,EAAG,GAAa,EAAU;EACrC,eAAY;YAEZ,kBAAC,QAAD,EAAM,WAAW,GAAe,CAAA;EAC1B,CAAA"}