@elmeragroup/fuse 0.1.0-canary.73 → 0.1.0-canary.76

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.
package/README.md CHANGED
@@ -20,7 +20,7 @@ Adjust the `@source` path only when the stylesheet is not one directory below th
20
20
  `@elmeragroup/fuse/css` is not only the components' variants and control metrics. Importing it into a Tailwind build also changes these parts of the host theme, whether or not `themes.css` is imported:
21
21
 
22
22
  - **Role and primitive colours.** Its `@theme inline` block maps every role token (`--color-primary` → `var(--primary)` and so on) and remaps Tailwind's `neutral-50` to `neutral-950` palette onto `--neutral-*`. `themes.css` defines those; without it, `bg-neutral-200` and the other stock neutral utilities resolve to an undefined colour until you define `--neutral-*` yourself.
23
- - **Radius scale.** `rounded-xs` to `rounded-xl` become whole `--radius-step` multiples from `--radius` instead of Tailwind's fixed rems. The step falls back to `0px`, so with your own `--radius` and no `themes.css` every rung is that one radius; `--radius` itself has no fallback. Button rounds with `--radius-button`, which `themes.css` sets per theme; define it (`--radius-button: var(--radius)`) when you skip `themes.css`. Field boxes round with `--radius` until `--radius-step` is `2px`, and then with `--radius-field`.
23
+ - **Radius scale.** `rounded-xs` to `rounded-xl` become whole `--radius-step` multiples from `--radius` instead of Tailwind's fixed rems. The step falls back to `0px`, so with your own `--radius` and no `themes.css` every rung is that one radius; `--radius` itself has no fallback. Button rounds with `--radius-button`, which `themes.css` sets per theme; define it (`--radius-button: var(--radius)`) when you skip `themes.css`. Field boxes round with `--radius` until `--radius-step` is `2px`, and then with `--radius-field`, which `themes.css` aliases to `var(--radius)` on each theme element.
24
24
  - **State variants.** It declares `data-open`, `data-closed`, `data-checked`, `data-unchecked`, `data-selected`, `data-disabled`, `data-active`, `data-horizontal` and `data-vertical` as static variants, wrapped in `:where()`. They replace Tailwind's functional `data-*` variants of the same name in your own classes too: their specificity drops to one class, so a plain `hover:` rule beats a `data-selected:` rule, `data-open:` and the like also match Radix-style `data-state` values, and `data-selected:` matches only `data-selected="true"`. Other `data-*` names are untouched.
25
25
  - **Border colour.** A base-layer rule gives every element, host markup included, `border-color: var(--border, currentcolor)`, so a bare `border` draws in the border role instead of the text colour. Any border colour utility still wins, and a host base rule like `* { @apply border-border; }` can go. Import `fuse/css` after `tailwindcss`; a preflight-free build that imports Tailwind's sheets into layers declares `@layer theme, base, components, utilities;` before them.
26
26
  - **Also:** `enabled-hover:`, `enabled-active:`, `disabled-state:`, `hit-area-*`, `no-scrollbar`, the `rounded-button`, `rounded-inner`, `font-sans`, `font-heading` and `font-mono` utilities, the `xs`, `lg` and `3xl` breakpoints, `--spacing: 0.25rem`, the `overshoot` easing, `tw-animate-css`, the React Aria Tailwind plugin, and a reduced-motion rule that switches off transform and layout transitions document-wide.
@@ -58,11 +58,32 @@ Button's `outline` variant reads `--button-outline` and `--button-outline-width`
58
58
  }
59
59
  ```
60
60
 
61
- A checked `RadioItem` or `CheckboxItem` row draws its border in `--selection-checked-border`. Without it the row takes your `--primary`, as internal themes do. For the external themes' look, where the row keeps its resting border and the control alone shows the selection, set:
61
+ A `RadioItem` or `CheckboxItem` row draws its edge in `--selection-border`, and a checked row in `--selection-checked-border`. The line between stacked rows reads `--selection-divider`, and above and below a checked row `--selection-checked-divider`. Without them the row and its dividers take your `--border` and a checked row your `--primary`, as internal themes do. For the external themes' look, where stacked rows keep a grey separator but no outer edge and the control alone shows the selection, set the edge to a transparent colour, point the checked edge at it, and draw both dividers in `--border`. The border keeps its 1px width, so rows join and inset as before, but a row on a `--card`-coloured surface has no outline:
62
62
 
63
63
  ```css
64
64
  :root {
65
- --selection-checked-border: var(--border);
65
+ --selection-border: oklch(0 0 0 / 0);
66
+ --selection-checked-border: var(--selection-border);
67
+ --selection-divider: var(--border);
68
+ --selection-checked-divider: var(--selection-divider);
69
+ }
70
+ ```
71
+
72
+ A disabled `RadioItem` or `CheckboxItem` row, disabled itself or through its group, fills with `--selection-disabled-background` under a 45° hatch striped in `--selection-disabled-hatch`, its title and other label row text take `--selection-disabled-foreground`, and its control dims to 50%. Without them the row takes your `--muted` under black stripes at 2% alpha with `--foreground` text, as internal themes do. For the external themes' look, where a disabled row keeps the card fill of an enabled row, draws no stripes and greys its title, set:
73
+
74
+ ```css
75
+ :root {
76
+ --selection-disabled-background: var(--card);
77
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
78
+ --selection-disabled-foreground: var(--muted-foreground);
79
+ }
80
+ ```
81
+
82
+ The checked row's tint and the disabled fill win over a background class on the row, such as `bg-background` for a list that shows its surface through. For such a list, set the disabled fill to that surface too:
83
+
84
+ ```css
85
+ .plan-list {
86
+ --selection-disabled-background: var(--background);
66
87
  }
67
88
  ```
68
89
 
@@ -74,12 +95,11 @@ A checked `RadioItem` or `CheckboxItem` row draws its border in `--selection-che
74
95
  }
75
96
  ```
76
97
 
77
- Field boxes round with your `--radius`, as internal themes do. For the external themes' 4px field corner, set the external step and the field radius. The step also spreads the `rounded-*` scale in 2px steps around `--radius` and gives the checkbox and the calendar their external 4px corner:
98
+ Field boxes round with your `--radius`, as cards and the themes' fields do. For the external look, set the external step. It spreads the `rounded-*` scale in 2px steps around `--radius` and gives the checkbox and the calendar their external 4px corner. Fields then round with `--radius-field` where you set one, and with your `--radius` otherwise, so set it only for a field corner of your own:
78
99
 
79
100
  ```css
80
101
  :root {
81
102
  --radius-step: 2px;
82
- --radius-field: 0.25rem;
83
103
  }
84
104
  ```
85
105
 
@@ -4,7 +4,14 @@ import { SelectionItemDescription } from "../selection-item/selection-item-descr
4
4
  import { ReactElement, ReactNode } from "react";
5
5
  //#region src/components/checkbox/checkbox-item.d.ts
6
6
  type CheckboxItemBaseProps = {
7
- /** Forwards `disabled` to the inner Checkbox and applies disabled hatch styling on the shell. */
7
+ /**
8
+ * Forwards `disabled` to the inner Checkbox, which dims to 50%, and shows the disabled row: the
9
+ * theme's `--selection-disabled-background` fill and `--selection-disabled-hatch` stripes
10
+ * (internal themes stripe a muted fill, external themes keep the card fill without stripes)
11
+ * and the `not-allowed` cursor. The title and other label row text take
12
+ * `--selection-disabled-foreground`, the muted foreground in external themes; a SubSection
13
+ * keeps its colours. A disabled group shows its rows the same way.
14
+ */
8
15
  isDisabled?: boolean;
9
16
  /** Forwards `readOnly` to the inner Checkbox. */
10
17
  isReadOnly?: boolean;
@@ -17,6 +24,9 @@ type CheckboxItemBaseProps = {
17
24
  * Extra classes, merged onto the shell via `cn`. A `px-*` utility sets the card's side
18
25
  * inset, and a click in that inset beside the label row toggles the control. The row
19
26
  * paints the card fill (`bg-card`); a background class such as `bg-background` replaces it.
27
+ * The checked row's `bg-muted` tint and the disabled row's `--selection-disabled-background`
28
+ * fill win over such a class; set `--selection-disabled-background`, for example to
29
+ * `var(--background)`, to change the disabled fill.
20
30
  */
21
31
  className?: string;
22
32
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox-item.d.ts","names":[],"sources":["../../../src/components/checkbox/checkbox-item.tsx"],"mappings":";;;;;KAaK;;EAEH;;EAEA;;;;;EAKA;;;;;;EAMA;;;;;;;EAOA;;;;;EAKA,WAAW;;;;;;YAOD,oBAAoB;;EAIxB;;EAEA;;;EAIA;;EAEA;;;;;;;;wBAUQ,eACd,OACA,QACA,YACA,YACA,iBACA,WACA,wBACA,YACC,oBAAoB;yBATP;;oBAAA"}
1
+ {"version":3,"file":"checkbox-item.d.ts","names":[],"sources":["../../../src/components/checkbox/checkbox-item.tsx"],"mappings":";;;;;KAaK;;;;;;;;;EASH;;EAEA;;;;;EAKA;;;;;;;;;EASA;;;;;;;EAOA;;;;;EAKA,WAAW;;;;;;YAOD,oBAAoB;;EAIxB;;EAEA;;;EAIA;;EAEA;;;;;;;;wBAUQ,eACd,OACA,QACA,YACA,YACA,iBACA,WACA,wBACA,YACC,oBAAoB;yBATP;;oBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox-item.js","names":[],"sources":["../../../src/components/checkbox/checkbox-item.tsx"],"sourcesContent":["/**\n * Server-visible `CheckboxItem`. The row is hook-free, so this module has no directive:\n * a server component runs it and reads `CheckboxItem.Title` and the other parts, while\n * `Checkbox` and `SelectionItem.Shell` stay client references it renders. It partitions\n * its own SubSections (see `partitionSubSections`) and passes them to the shell.\n */\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport { SelectionItem } from \"../selection-item\";\nimport { partitionSubSections } from \"../selection-item/partition-sub-sections\";\nimport { SelectionItemShell } from \"../selection-item/selection-item\";\nimport { Checkbox } from \"./checkbox\";\n\ntype CheckboxItemBaseProps = {\n /** Forwards `disabled` to the inner Checkbox and applies disabled hatch styling on the shell. */\n isDisabled?: boolean;\n /** Forwards `readOnly` to the inner Checkbox. */\n isReadOnly?: boolean;\n /**\n * Where the control sits in the labelled row. Forwarded to `SelectionItem.Shell`.\n * Default `\"start\"`.\n */\n controlPosition?: \"start\" | \"end\";\n /**\n * Extra classes, merged onto the shell via `cn`. A `px-*` utility sets the card's side\n * inset, and a click in that inset beside the label row toggles the control. The row\n * paints the card fill (`bg-card`); a background class such as `bg-background` replaces it.\n */\n className?: string;\n /**\n * Lets a click on a SubSection's text, band or side padding toggle the control, while\n * links, buttons, fields and other focusable elements in it keep their own clicks.\n * Forwarded to `SelectionItem.Shell`; see it there. Leave it off when the SubSection\n * reveals fields under the control. Default `false`.\n */\n isSubSectionSelectable?: boolean;\n /**\n * Row children, partitioned by the row. Direct `CheckboxItem.SubSection` (the\n * same object as `SelectionItem.SubSection`) children render outside the label.\n */\n children?: ReactNode;\n};\n\n/**\n * Discriminated parent-vs-value union. Parent rows derive tri-state from the\n * group's `allValues` and must not set `value`.\n */\nexport type CheckboxItemProps = CheckboxItemBaseProps &\n (\n | {\n /** Member value in the group. Required unless `parent`. */\n value: string;\n /** When true, this row is the tri-state parent. Incompatible with `value`. */\n parent?: false;\n }\n | {\n /** Tri-state parent — checked/indeterminate/unchecked from the group's `allValues`. */\n parent: true;\n /** Parent rows must not set `value`. */\n value?: never;\n }\n );\n\n/**\n * Labeled selection row over `SelectionItem.Shell`. Server-compatible: it renders the\n * client `SelectionItem.Shell`, which wires Field.Item and the label. The namespace\n * aliases `Title`, `Description`, `Content`, `Actions` and `SubSection` are the exact\n * `SelectionItem.*` objects, so `child.type` partitioning works with either spelling.\n */\nexport function CheckboxItem({\n value,\n parent,\n isDisabled,\n isReadOnly,\n controlPosition = \"start\",\n className,\n isSubSectionSelectable,\n children,\n}: CheckboxItemProps): ReactElement {\n const { row, subSections } = partitionSubSections(children);\n return (\n <SelectionItemShell\n dataSlot=\"checkbox-item\"\n isDisabled={isDisabled}\n controlPosition={controlPosition}\n className={className}\n isSubSectionSelectable={isSubSectionSelectable}\n control={\n parent === true ? (\n <Checkbox parent disabled={isDisabled} readOnly={isReadOnly} />\n ) : (\n <Checkbox value={value} disabled={isDisabled} readOnly={isReadOnly} />\n )\n }\n subSections={subSections}>\n {row}\n </SelectionItemShell>\n );\n}\n\nCheckboxItem.displayName = \"CheckboxItem\";\n\nCheckboxItem.Title = SelectionItem.Title;\nCheckboxItem.Description = SelectionItem.Description;\nCheckboxItem.Content = SelectionItem.Content;\nCheckboxItem.Actions = SelectionItem.Actions;\nCheckboxItem.SubSection = SelectionItem.SubSection;\n"],"mappings":";;;;;;;;;;;;AAqEA,SAAgB,aAAa,EAC3B,OACA,QACA,YACA,YACA,kBAAkB,SAClB,WACA,wBACA,YACkC;CAClC,MAAM,EAAE,KAAK,gBAAgB,qBAAqB,QAAQ;CAC1D,OACE,oBAAC,oBAAD;EACE,UAAS;EACG;EACK;EACN;EACa;EACxB,SACE,WAAW,OACT,oBAAC,UAAD;GAAU,QAAA;GAAO,UAAU;GAAY,UAAU;EAAa,CAAA,IAE9D,oBAAC,UAAD;GAAiB;GAAO,UAAU;GAAY,UAAU;EAAa,CAAA;EAG5D;EACZ,UAAA;CACiB,CAAA;AAExB;AAEA,aAAa,cAAc;AAE3B,aAAa,QAAQ,cAAc;AACnC,aAAa,cAAc,cAAc;AACzC,aAAa,UAAU,cAAc;AACrC,aAAa,UAAU,cAAc;AACrC,aAAa,aAAa,cAAc"}
1
+ {"version":3,"file":"checkbox-item.js","names":[],"sources":["../../../src/components/checkbox/checkbox-item.tsx"],"sourcesContent":["/**\n * Server-visible `CheckboxItem`. The row is hook-free, so this module has no directive:\n * a server component runs it and reads `CheckboxItem.Title` and the other parts, while\n * `Checkbox` and `SelectionItem.Shell` stay client references it renders. It partitions\n * its own SubSections (see `partitionSubSections`) and passes them to the shell.\n */\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport { SelectionItem } from \"../selection-item\";\nimport { partitionSubSections } from \"../selection-item/partition-sub-sections\";\nimport { SelectionItemShell } from \"../selection-item/selection-item\";\nimport { Checkbox } from \"./checkbox\";\n\ntype CheckboxItemBaseProps = {\n /**\n * Forwards `disabled` to the inner Checkbox, which dims to 50%, and shows the disabled row: the\n * theme's `--selection-disabled-background` fill and `--selection-disabled-hatch` stripes\n * (internal themes stripe a muted fill, external themes keep the card fill without stripes)\n * and the `not-allowed` cursor. The title and other label row text take\n * `--selection-disabled-foreground`, the muted foreground in external themes; a SubSection\n * keeps its colours. A disabled group shows its rows the same way.\n */\n isDisabled?: boolean;\n /** Forwards `readOnly` to the inner Checkbox. */\n isReadOnly?: boolean;\n /**\n * Where the control sits in the labelled row. Forwarded to `SelectionItem.Shell`.\n * Default `\"start\"`.\n */\n controlPosition?: \"start\" | \"end\";\n /**\n * Extra classes, merged onto the shell via `cn`. A `px-*` utility sets the card's side\n * inset, and a click in that inset beside the label row toggles the control. The row\n * paints the card fill (`bg-card`); a background class such as `bg-background` replaces it.\n * The checked row's `bg-muted` tint and the disabled row's `--selection-disabled-background`\n * fill win over such a class; set `--selection-disabled-background`, for example to\n * `var(--background)`, to change the disabled fill.\n */\n className?: string;\n /**\n * Lets a click on a SubSection's text, band or side padding toggle the control, while\n * links, buttons, fields and other focusable elements in it keep their own clicks.\n * Forwarded to `SelectionItem.Shell`; see it there. Leave it off when the SubSection\n * reveals fields under the control. Default `false`.\n */\n isSubSectionSelectable?: boolean;\n /**\n * Row children, partitioned by the row. Direct `CheckboxItem.SubSection` (the\n * same object as `SelectionItem.SubSection`) children render outside the label.\n */\n children?: ReactNode;\n};\n\n/**\n * Discriminated parent-vs-value union. Parent rows derive tri-state from the\n * group's `allValues` and must not set `value`.\n */\nexport type CheckboxItemProps = CheckboxItemBaseProps &\n (\n | {\n /** Member value in the group. Required unless `parent`. */\n value: string;\n /** When true, this row is the tri-state parent. Incompatible with `value`. */\n parent?: false;\n }\n | {\n /** Tri-state parent — checked/indeterminate/unchecked from the group's `allValues`. */\n parent: true;\n /** Parent rows must not set `value`. */\n value?: never;\n }\n );\n\n/**\n * Labeled selection row over `SelectionItem.Shell`. Server-compatible: it renders the\n * client `SelectionItem.Shell`, which wires Field.Item and the label. The namespace\n * aliases `Title`, `Description`, `Content`, `Actions` and `SubSection` are the exact\n * `SelectionItem.*` objects, so `child.type` partitioning works with either spelling.\n */\nexport function CheckboxItem({\n value,\n parent,\n isDisabled,\n isReadOnly,\n controlPosition = \"start\",\n className,\n isSubSectionSelectable,\n children,\n}: CheckboxItemProps): ReactElement {\n const { row, subSections } = partitionSubSections(children);\n return (\n <SelectionItemShell\n dataSlot=\"checkbox-item\"\n isDisabled={isDisabled}\n controlPosition={controlPosition}\n className={className}\n isSubSectionSelectable={isSubSectionSelectable}\n control={\n parent === true ? (\n <Checkbox parent disabled={isDisabled} readOnly={isReadOnly} />\n ) : (\n <Checkbox value={value} disabled={isDisabled} readOnly={isReadOnly} />\n )\n }\n subSections={subSections}>\n {row}\n </SelectionItemShell>\n );\n}\n\nCheckboxItem.displayName = \"CheckboxItem\";\n\nCheckboxItem.Title = SelectionItem.Title;\nCheckboxItem.Description = SelectionItem.Description;\nCheckboxItem.Content = SelectionItem.Content;\nCheckboxItem.Actions = SelectionItem.Actions;\nCheckboxItem.SubSection = SelectionItem.SubSection;\n"],"mappings":";;;;;;;;;;;;AA+EA,SAAgB,aAAa,EAC3B,OACA,QACA,YACA,YACA,kBAAkB,SAClB,WACA,wBACA,YACkC;CAClC,MAAM,EAAE,KAAK,gBAAgB,qBAAqB,QAAQ;CAC1D,OACE,oBAAC,oBAAD;EACE,UAAS;EACG;EACK;EACN;EACa;EACxB,SACE,WAAW,OACT,oBAAC,UAAD;GAAU,QAAA;GAAO,UAAU;GAAY,UAAU;EAAa,CAAA,IAE9D,oBAAC,UAAD;GAAiB;GAAO,UAAU;GAAY,UAAU;EAAa,CAAA;EAG5D;EACZ,UAAA;CACiB,CAAA;AAExB;AAEA,aAAa,cAAc;AAE3B,aAAa,QAAQ,cAAc;AACnC,aAAa,cAAc,cAAc;AACzC,aAAa,UAAU,cAAc;AACrC,aAAa,UAAU,cAAc;AACrC,aAAa,aAAa,cAAc"}
@@ -6,7 +6,14 @@ import { ReactElement, ReactNode } from "react";
6
6
  export type RadioItemProps = {
7
7
  /** Member value in the group. Forwarded to the inner `RadioGroupItem`. */
8
8
  value: string;
9
- /** Forwards `disabled` to the inner control and applies disabled hatch styling on the shell. */
9
+ /**
10
+ * Forwards `disabled` to the inner control, which dims to 50%, and shows the disabled row: the
11
+ * theme's `--selection-disabled-background` fill and `--selection-disabled-hatch` stripes
12
+ * (internal themes stripe a muted fill, external themes keep the card fill without stripes)
13
+ * and the `not-allowed` cursor. The title and other label row text take
14
+ * `--selection-disabled-foreground`, the muted foreground in external themes; a SubSection
15
+ * keeps its colours. A disabled group shows its rows the same way.
16
+ */
10
17
  isDisabled?: boolean;
11
18
  /**
12
19
  * Where the control sits in the labelled row. Forwarded to `SelectionItem.Shell`.
@@ -17,6 +24,9 @@ export type RadioItemProps = {
17
24
  * Extra classes, merged onto the shell via `cn`. A `px-*` utility sets the card's side
18
25
  * inset, and a click in that inset beside the label row toggles the control. The row
19
26
  * paints the card fill (`bg-card`); a background class such as `bg-background` replaces it.
27
+ * The checked row's `bg-muted` tint and the disabled row's `--selection-disabled-background`
28
+ * fill win over such a class; set `--selection-disabled-background`, for example to
29
+ * `var(--background)`, to change the disabled fill.
20
30
  */
21
31
  className?: string;
22
32
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"radio-item.d.ts","names":[],"sources":["../../../src/components/radio-group/radio-item.tsx"],"mappings":";;;;;YAaY;;EAEV;;EAEA;;;;;EAKA;;;;;;EAMA;;;;;;;EAOA;;;;;EAKA,WAAW;;;;;;;;wBASG,YACd,OACA,YACA,iBACA,WACA,wBACA,YACC,iBAAiB;yBAPJ;;oBAAA"}
1
+ {"version":3,"file":"radio-item.d.ts","names":[],"sources":["../../../src/components/radio-group/radio-item.tsx"],"mappings":";;;;;YAaY;;EAEV;;;;;;;;;EASA;;;;;EAKA;;;;;;;;;EASA;;;;;;;EAOA;;;;;EAKA,WAAW;;;;;;;;wBASG,YACd,OACA,YACA,iBACA,WACA,wBACA,YACC,iBAAiB;yBAPJ;;oBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"radio-item.js","names":[],"sources":["../../../src/components/radio-group/radio-item.tsx"],"sourcesContent":["/**\n * Server-visible `RadioItem`. The row is hook-free, so this module has no directive:\n * a server component runs it and reads `RadioItem.Title` and the other parts, while\n * `RadioGroupItem` and `SelectionItem.Shell` stay client references it renders. It partitions\n * its own SubSections (see `partitionSubSections`) and passes them to the shell.\n */\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport { SelectionItem } from \"../selection-item\";\nimport { partitionSubSections } from \"../selection-item/partition-sub-sections\";\nimport { SelectionItemShell } from \"../selection-item/selection-item\";\nimport { RadioGroupItem } from \"./radio-group\";\n\nexport type RadioItemProps = {\n /** Member value in the group. Forwarded to the inner `RadioGroupItem`. */\n value: string;\n /** Forwards `disabled` to the inner control and applies disabled hatch styling on the shell. */\n isDisabled?: boolean;\n /**\n * Where the control sits in the labelled row. Forwarded to `SelectionItem.Shell`.\n * Default `\"start\"`.\n */\n controlPosition?: \"start\" | \"end\";\n /**\n * Extra classes, merged onto the shell via `cn`. A `px-*` utility sets the card's side\n * inset, and a click in that inset beside the label row toggles the control. The row\n * paints the card fill (`bg-card`); a background class such as `bg-background` replaces it.\n */\n className?: string;\n /**\n * Lets a click on a SubSection's text, band or side padding toggle the control, while\n * links, buttons, fields and other focusable elements in it keep their own clicks.\n * Forwarded to `SelectionItem.Shell`; see it there. Leave it off when the SubSection\n * reveals fields under the control. Default `false`.\n */\n isSubSectionSelectable?: boolean;\n /**\n * Row children, partitioned by the row. Direct `RadioItem.SubSection` (the\n * same object as `SelectionItem.SubSection`) children render outside the label.\n */\n children?: ReactNode;\n};\n\n/**\n * Labeled selection row over `SelectionItem.Shell`. Server-compatible: it renders the\n * client `SelectionItem.Shell`, which wires Field.Item and the label. The namespace\n * aliases `Title`, `Description`, `Content`, `Actions` and `SubSection` are the exact\n * `SelectionItem.*` objects, so `child.type` partitioning works with either spelling.\n */\nexport function RadioItem({\n value,\n isDisabled,\n controlPosition = \"start\",\n className,\n isSubSectionSelectable,\n children,\n}: RadioItemProps): ReactElement {\n const { row, subSections } = partitionSubSections(children);\n return (\n <SelectionItemShell\n dataSlot=\"radio-item\"\n isDisabled={isDisabled}\n controlPosition={controlPosition}\n className={className}\n isSubSectionSelectable={isSubSectionSelectable}\n control={<RadioGroupItem value={value} disabled={isDisabled} />}\n subSections={subSections}>\n {row}\n </SelectionItemShell>\n );\n}\n\nRadioItem.displayName = \"RadioItem\";\n\nRadioItem.Title = SelectionItem.Title;\nRadioItem.Description = SelectionItem.Description;\nRadioItem.Content = SelectionItem.Content;\nRadioItem.Actions = SelectionItem.Actions;\nRadioItem.SubSection = SelectionItem.SubSection;\n"],"mappings":";;;;;;;;;;;;AAiDA,SAAgB,UAAU,EACxB,OACA,YACA,kBAAkB,SAClB,WACA,wBACA,YAC+B;CAC/B,MAAM,EAAE,KAAK,gBAAgB,qBAAqB,QAAQ;CAC1D,OACE,oBAAC,oBAAD;EACE,UAAS;EACG;EACK;EACN;EACa;EACxB,SAAS,oBAAC,gBAAD;GAAuB;GAAO,UAAU;EAAa,CAAA;EACjD;EACZ,UAAA;CACiB,CAAA;AAExB;AAEA,UAAU,cAAc;AAExB,UAAU,QAAQ,cAAc;AAChC,UAAU,cAAc,cAAc;AACtC,UAAU,UAAU,cAAc;AAClC,UAAU,UAAU,cAAc;AAClC,UAAU,aAAa,cAAc"}
1
+ {"version":3,"file":"radio-item.js","names":[],"sources":["../../../src/components/radio-group/radio-item.tsx"],"sourcesContent":["/**\n * Server-visible `RadioItem`. The row is hook-free, so this module has no directive:\n * a server component runs it and reads `RadioItem.Title` and the other parts, while\n * `RadioGroupItem` and `SelectionItem.Shell` stay client references it renders. It partitions\n * its own SubSections (see `partitionSubSections`) and passes them to the shell.\n */\nimport type { ReactElement, ReactNode } from \"react\";\n\nimport { SelectionItem } from \"../selection-item\";\nimport { partitionSubSections } from \"../selection-item/partition-sub-sections\";\nimport { SelectionItemShell } from \"../selection-item/selection-item\";\nimport { RadioGroupItem } from \"./radio-group\";\n\nexport type RadioItemProps = {\n /** Member value in the group. Forwarded to the inner `RadioGroupItem`. */\n value: string;\n /**\n * Forwards `disabled` to the inner control, which dims to 50%, and shows the disabled row: the\n * theme's `--selection-disabled-background` fill and `--selection-disabled-hatch` stripes\n * (internal themes stripe a muted fill, external themes keep the card fill without stripes)\n * and the `not-allowed` cursor. The title and other label row text take\n * `--selection-disabled-foreground`, the muted foreground in external themes; a SubSection\n * keeps its colours. A disabled group shows its rows the same way.\n */\n isDisabled?: boolean;\n /**\n * Where the control sits in the labelled row. Forwarded to `SelectionItem.Shell`.\n * Default `\"start\"`.\n */\n controlPosition?: \"start\" | \"end\";\n /**\n * Extra classes, merged onto the shell via `cn`. A `px-*` utility sets the card's side\n * inset, and a click in that inset beside the label row toggles the control. The row\n * paints the card fill (`bg-card`); a background class such as `bg-background` replaces it.\n * The checked row's `bg-muted` tint and the disabled row's `--selection-disabled-background`\n * fill win over such a class; set `--selection-disabled-background`, for example to\n * `var(--background)`, to change the disabled fill.\n */\n className?: string;\n /**\n * Lets a click on a SubSection's text, band or side padding toggle the control, while\n * links, buttons, fields and other focusable elements in it keep their own clicks.\n * Forwarded to `SelectionItem.Shell`; see it there. Leave it off when the SubSection\n * reveals fields under the control. Default `false`.\n */\n isSubSectionSelectable?: boolean;\n /**\n * Row children, partitioned by the row. Direct `RadioItem.SubSection` (the\n * same object as `SelectionItem.SubSection`) children render outside the label.\n */\n children?: ReactNode;\n};\n\n/**\n * Labeled selection row over `SelectionItem.Shell`. Server-compatible: it renders the\n * client `SelectionItem.Shell`, which wires Field.Item and the label. The namespace\n * aliases `Title`, `Description`, `Content`, `Actions` and `SubSection` are the exact\n * `SelectionItem.*` objects, so `child.type` partitioning works with either spelling.\n */\nexport function RadioItem({\n value,\n isDisabled,\n controlPosition = \"start\",\n className,\n isSubSectionSelectable,\n children,\n}: RadioItemProps): ReactElement {\n const { row, subSections } = partitionSubSections(children);\n return (\n <SelectionItemShell\n dataSlot=\"radio-item\"\n isDisabled={isDisabled}\n controlPosition={controlPosition}\n className={className}\n isSubSectionSelectable={isSubSectionSelectable}\n control={<RadioGroupItem value={value} disabled={isDisabled} />}\n subSections={subSections}>\n {row}\n </SelectionItemShell>\n );\n}\n\nRadioItem.displayName = \"RadioItem\";\n\nRadioItem.Title = SelectionItem.Title;\nRadioItem.Description = SelectionItem.Description;\nRadioItem.Content = SelectionItem.Content;\nRadioItem.Actions = SelectionItem.Actions;\nRadioItem.SubSection = SelectionItem.SubSection;\n"],"mappings":";;;;;;;;;;;;AA2DA,SAAgB,UAAU,EACxB,OACA,YACA,kBAAkB,SAClB,WACA,wBACA,YAC+B;CAC/B,MAAM,EAAE,KAAK,gBAAgB,qBAAqB,QAAQ;CAC1D,OACE,oBAAC,oBAAD;EACE,UAAS;EACG;EACK;EACN;EACa;EACxB,SAAS,oBAAC,gBAAD;GAAuB;GAAO,UAAU;EAAa,CAAA;EACjD;EACZ,UAAA;CACiB,CAAA;AAExB;AAEA,UAAU,cAAc;AAExB,UAAU,QAAQ,cAAc;AAChC,UAAU,cAAc,cAAc;AACtC,UAAU,UAAU,cAAc;AAClC,UAAU,UAAU,cAAc;AAClC,UAAU,aAAa,cAAc"}
@@ -87,15 +87,25 @@ type SelectionItemShellProps = Omit<ComponentProps<typeof FieldItem>, "className
87
87
  */
88
88
  controlPosition?: "start" | "end";
89
89
  /**
90
- * Applies `cursor-not-allowed bg-muted` plus the shared `disabledHatch` overlay.
91
- * Does not disable the control — the control or group owns that.
90
+ * Shows the disabled row: the `not-allowed` cursor and the theme's
91
+ * `--selection-disabled-background` fill under a 45° hatch striped in
92
+ * `--selection-disabled-hatch`. Internal themes fill with `--muted` and black stripes at 2%
93
+ * alpha; external themes keep the card fill with no stripes. The label row's text takes
94
+ * `--selection-disabled-foreground`: the foreground in internal themes, the muted foreground in
95
+ * external ones. A description keeps its own muted text, a SubSection keeps its colours, and
96
+ * the control dims itself. A row whose group is disabled, or whose control in the control
97
+ * slot carries `data-disabled`, matches `:disabled` or is `aria-disabled="true"`, shows the
98
+ * same look without it. Does not disable the control — the control or group owns that.
92
99
  */
93
100
  isDisabled?: boolean;
94
101
  /**
95
102
  * Extra classes, merged last through `cn`. A `px-*` utility sets the card's side inset,
96
103
  * and a click in that inset beside the label row toggles the control. The row paints the
97
104
  * card fill (`bg-card`) like the other field boxes; a list on a surface that should show
98
- * through takes a background class such as `bg-background`, which replaces it.
105
+ * through takes a background class such as `bg-background`, which replaces it. The checked
106
+ * row's `bg-muted` tint and the disabled row's `--selection-disabled-background` fill win over
107
+ * such a class; set `--selection-disabled-background`, for example to `var(--background)`,
108
+ * to change the disabled fill.
99
109
  */
100
110
  className?: string;
101
111
  /**
@@ -140,16 +150,31 @@ type SelectionItemShellProps = Omit<ComponentProps<typeof FieldItem>, "className
140
150
  * covers the whole row, and a click on the band's passive parts toggles the control.
141
151
  * Nothing clips, so a focus ring at a zero inset paints whole.
142
152
  *
143
- * Vertical and default shells, in either group shape or outside any group, collapse
144
- * borders with `not-first:border-t-0`. A checked shell paints its border in the theme's
145
- * `--selection-checked-border`: `--primary` in internal themes, the resting `--border` in
146
- * external ones, whose radio card shows the selection through its control alone. A checked
147
- * non-first shell repaints its top border in that colour by pulling itself up one pixel
148
- * (`has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px`)
149
- * instead of a z-index lift; `className` margin overrides can break that. Horizontal
150
- * item groups render individually rounded full-border cards with no vertical border
151
- * collapse and no checked negative margin. Checked selectors are scoped to the
152
- * private control slot so a checked descendant in SubSection cannot repaint the shell.
153
+ * The shell's 1px edge is the theme's `--selection-border`, not Item's outline `--border`:
154
+ * `--border` in internal themes, a zero-alpha colour in external ones, which keeps the border's
155
+ * geometry but draws no line. A checked shell paints its edge in the theme's
156
+ * `--selection-checked-border`: `--primary` in internal themes, the resting `--selection-border`
157
+ * in external ones, whose radio card shows the selection through its control alone.
158
+ *
159
+ * Vertical and default shells, in either group shape or outside any group, collapse borders with
160
+ * `not-first:border-t-0`, so one line divides two rows. The bottom edge of a row with another
161
+ * row after it is the theme's `--selection-divider`, and a checked row's edges shared with another
162
+ * row are its `--selection-checked-divider`. Internal themes alias them to the row's own edges, so
163
+ * a checked row stays boxed in `--primary`. External themes draw both in `--border`: stacked rows
164
+ * keep a grey separator, checked or not, while the sides, the stack's outer top and bottom and a
165
+ * lone row beside other Field parts stay transparent. A checked non-first shell repaints its top border by pulling itself up one
166
+ * pixel (`has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px`) instead of a
167
+ * z-index lift; `className` margin overrides can break that. Horizontal item groups render
168
+ * individually rounded full-border cards with no vertical border collapse, no divider and no
169
+ * checked negative margin. Checked selectors are scoped to the private control slot so a checked
170
+ * descendant in SubSection cannot repaint the shell.
171
+ *
172
+ * A disabled shell, through `isDisabled`, a disabled group or its own disabled control, fills
173
+ * with the theme's `--selection-disabled-background` under a hatch of
174
+ * `--selection-disabled-hatch`, which outweighs the checked fill and a background class and
175
+ * leaves the checked border, joins and pull-up alone. The label row's text takes
176
+ * `--selection-disabled-foreground`, the control dims itself at 50%, and a SubSection keeps
177
+ * its colours.
153
178
  *
154
179
  * It publishes `--inner-corner`, its corner less its border and padding, for parts that round with
155
180
  * `rounded-inner`.
@@ -1 +1 @@
1
- {"version":3,"file":"selection-item.d.ts","names":[],"sources":["../../../src/components/selection-item/selection-item.tsx"],"mappings":";;;;;KAsEK;EACH,WAAW;EACX,aAAa;;;;;;;;;wBAUC,uBAAuB,UAAU,eAAe,4BAA4B;KAKvF;EACH,WAAW;;;;;EAKX,cAAc;;;;;;;;;wBAUA,qBACd,UACA,eACC,0BAA0B;;;;;;;;;;;;;;wBA2Bb,qBAAqB,cAAc,SAAS,sBAAsB,aAAa;yBAA/E;MAAA;;;;;;;;;wBAoBA,uBACd,cACG,SACF,sBAAsB,eAAe;yBAHxB;MAAA;;;;;;;;wBAkBA,0BACd,UACA,WACA,SACG,SACF,sBAAsB,cAAc;yBALvB;MAAA;;KAgBX,0BAA0B,KAAK,sBAAsB;;;;;EAKxD;;;;;;EAMA,SAAS;;;;;EAKT;;;;;EAKA;;;;;;;EAOA;;;;;;;;EAQA,cAAc;;;;;;;;;;EAUd;;;;;;;;;EASA,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA+BG,qBACd,UACA,SACA,iBACA,YACA,WACA,aAAa,mBACb,wBACA,aACG,SACF,0BAA0B;yBAVb;MAAA"}
1
+ {"version":3,"file":"selection-item.d.ts","names":[],"sources":["../../../src/components/selection-item/selection-item.tsx"],"mappings":";;;;;KA+GK;EACH,WAAW;EACX,aAAa;;;;;;;;;wBAUC,uBAAuB,UAAU,eAAe,4BAA4B;KAKvF;EACH,WAAW;;;;;EAKX,cAAc;;;;;;;;;wBAUA,qBACd,UACA,eACC,0BAA0B;;;;;;;;;;;;;;wBA2Bb,qBAAqB,cAAc,SAAS,sBAAsB,aAAa;yBAA/E;MAAA;;;;;;;;;wBAoBA,uBACd,cACG,SACF,sBAAsB,eAAe;yBAHxB;MAAA;;;;;;;;wBAkBA,0BACd,UACA,WACA,SACG,SACF,sBAAsB,cAAc;yBALvB;MAAA;;KAgBX,0BAA0B,KAAK,sBAAsB;;;;;EAKxD;;;;;;EAMA,SAAS;;;;;EAKT;;;;;;;;;;;;EAYA;;;;;;;;;;EAUA;;;;;;;;EAQA,cAAc;;;;;;;;;;EAUd;;;;;;;;;EASA,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA8CG,qBACd,UACA,SACA,iBACA,YACA,WACA,aAAa,mBACb,wBACA,aACG,SACF,0BAA0B;yBAVb;MAAA"}
@@ -1,6 +1,5 @@
1
1
  "use client";
2
2
  import { cn } from "../../styles/cn.js";
3
- import { disabledHatch } from "../../styles/utils.js";
4
3
  import { selectionItemShellClass } from "../../styles/inner-corner/item.js";
5
4
  import { itemVariants } from "../item/item-variants.js";
6
5
  import { ItemActions, ItemFooter, ItemMedia, ItemTitle } from "../item/item-markup.js";
@@ -15,11 +14,14 @@ import { Field } from "@base-ui/react/field";
15
14
  //#region src/components/selection-item/selection-item.tsx
16
15
  /** Resolved once at module scope — the shell always borrows the `outline` arm. */
17
16
  const outlineItemClass = itemVariants({ variant: "outline" });
18
- const labelClass = cn("contents cursor-pointer before:absolute before:inset-0 before:-z-1 has-disabled:cursor-not-allowed");
17
+ const connectedStackClass = cn("rounded-none not-first:border-t-0 first:rounded-t-lg last:rounded-b-lg has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px has-[[data-slot=selection-item-control]_[data-checked]]:not-first:border-t", "[&:has(+[data-selection-item])]:border-b-selection-divider has-[[data-slot=selection-item-control]_[data-checked]]:[&:has(+[data-selection-item])]:border-b-selection-checked-divider has-[[data-slot=selection-item-control]_[data-checked]]:[[data-selection-item]+&]:border-t-selection-checked-divider");
18
+ const labelClass = cn("contents cursor-pointer before:absolute before:inset-0 before:-z-1", "[[data-selection-item]:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))>&]:cursor-not-allowed");
19
19
  const labelRowTargetClass = cn("[[data-selection-item]:has(>[data-slot=selection-item-sub-sections]>div>[data-slot=item-footer]:not([data-mode=hidden]))>&]:before:row-[1/2]");
20
20
  const subSectionBandClass = cn("pointer-events-none col-span-full grid grid-cols-subgrid pb-3.5", "has-[>div>[data-slot=item-footer]:not([data-mode=hidden])]:pointer-events-auto");
21
- const selectableBandClass = cn("cursor-pointer [[data-selection-item]:has(>label>[data-slot=selection-item-control]_:disabled)>&]:cursor-not-allowed");
21
+ const selectableBandClass = cn("cursor-pointer", "[[data-selection-item]:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))>&]:cursor-not-allowed");
22
22
  const firstLineClass = cn("[--selection-first-line:var(--label-leading)] has-[>label_[data-slot=selection-item-title]]:[--selection-first-line:calc(var(--label-text)*var(--leading-snug))]");
23
+ const disabledShellClass = cn("[&:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))]:cursor-not-allowed", "[&:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))]:bg-selection-disabled-background", "[&:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))]:bg-[repeating-linear-gradient(45deg,transparent,transparent_8px,--theme(--color-selection-disabled-hatch)_8px,--theme(--color-selection-disabled-hatch)_16px)]");
24
+ const disabledLabelTextClass = cn("[[data-selection-item]:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))>label>&]:text-selection-disabled-foreground");
23
25
  /**
24
26
  * Elements in a SubSection that keep their own clicks under `isSubSectionSelectable`. A click
25
27
  * inside one of them, or inside an element that only takes focus, does not toggle the row.
@@ -126,16 +128,31 @@ function SelectionItemSubSection({ children, className, mode = "default", ...pro
126
128
  * covers the whole row, and a click on the band's passive parts toggles the control.
127
129
  * Nothing clips, so a focus ring at a zero inset paints whole.
128
130
  *
129
- * Vertical and default shells, in either group shape or outside any group, collapse
130
- * borders with `not-first:border-t-0`. A checked shell paints its border in the theme's
131
- * `--selection-checked-border`: `--primary` in internal themes, the resting `--border` in
132
- * external ones, whose radio card shows the selection through its control alone. A checked
133
- * non-first shell repaints its top border in that colour by pulling itself up one pixel
134
- * (`has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px`)
135
- * instead of a z-index lift; `className` margin overrides can break that. Horizontal
136
- * item groups render individually rounded full-border cards with no vertical border
137
- * collapse and no checked negative margin. Checked selectors are scoped to the
138
- * private control slot so a checked descendant in SubSection cannot repaint the shell.
131
+ * The shell's 1px edge is the theme's `--selection-border`, not Item's outline `--border`:
132
+ * `--border` in internal themes, a zero-alpha colour in external ones, which keeps the border's
133
+ * geometry but draws no line. A checked shell paints its edge in the theme's
134
+ * `--selection-checked-border`: `--primary` in internal themes, the resting `--selection-border`
135
+ * in external ones, whose radio card shows the selection through its control alone.
136
+ *
137
+ * Vertical and default shells, in either group shape or outside any group, collapse borders with
138
+ * `not-first:border-t-0`, so one line divides two rows. The bottom edge of a row with another
139
+ * row after it is the theme's `--selection-divider`, and a checked row's edges shared with another
140
+ * row are its `--selection-checked-divider`. Internal themes alias them to the row's own edges, so
141
+ * a checked row stays boxed in `--primary`. External themes draw both in `--border`: stacked rows
142
+ * keep a grey separator, checked or not, while the sides, the stack's outer top and bottom and a
143
+ * lone row beside other Field parts stay transparent. A checked non-first shell repaints its top border by pulling itself up one
144
+ * pixel (`has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px`) instead of a
145
+ * z-index lift; `className` margin overrides can break that. Horizontal item groups render
146
+ * individually rounded full-border cards with no vertical border collapse, no divider and no
147
+ * checked negative margin. Checked selectors are scoped to the private control slot so a checked
148
+ * descendant in SubSection cannot repaint the shell.
149
+ *
150
+ * A disabled shell, through `isDisabled`, a disabled group or its own disabled control, fills
151
+ * with the theme's `--selection-disabled-background` under a hatch of
152
+ * `--selection-disabled-hatch`, which outweighs the checked fill and a background class and
153
+ * leaves the checked border, joins and pull-up alone. The label row's text takes
154
+ * `--selection-disabled-foreground`, the control dims itself at 50%, and a SubSection keeps
155
+ * its colours.
139
156
  *
140
157
  * It publishes `--inner-corner`, its corner less its border and padding, for parts that round with
141
158
  * `rounded-inner`.
@@ -157,7 +174,7 @@ function SelectionItemShell({ dataSlot, control, controlPosition = "start", isDi
157
174
  children: control
158
175
  });
159
176
  const rowCluster = /* @__PURE__ */ jsx("div", {
160
- className: cn("flex min-w-0 items-start gap-2.5", rowCellClass),
177
+ className: cn("flex min-w-0 items-start gap-2.5", rowCellClass, disabledLabelTextClass),
161
178
  children: rowChildren
162
179
  });
163
180
  const spacer = /* @__PURE__ */ jsx("span", { "aria-hidden": true });
@@ -183,9 +200,10 @@ function SelectionItemShell({ dataSlot, control, controlPosition = "start", isDi
183
200
  ...inItemGroup ? { role: "listitem" } : null,
184
201
  ...props,
185
202
  ...isSubSectionSelectable ? mergeProps({ onClick: selectFromSubSection }, { onClick: props.onClick }) : null,
203
+ ...isDisabled ? { "data-disabled": "" } : null,
186
204
  "data-slot": dataSlot,
187
205
  "data-selection-item": "",
188
- className: cn(outlineItemClass, selectionItemShellClass, labelTypeClass, firstLineClass, "relative isolate box-border grid items-stretch gap-0 gap-x-2.5 bg-card py-0 transition-colors has-[[data-slot=selection-item-control]_[data-checked]]:border-selection-checked-border has-[[data-slot=selection-item-control]_[data-checked]]:bg-muted", controlAtEnd ? "grid-cols-[minmax(0,1fr)_auto]" : "grid-cols-[auto_minmax(0,1fr)]", connectedStack ? "rounded-none not-first:border-t-0 first:rounded-t-lg last:rounded-b-lg has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px has-[[data-slot=selection-item-control]_[data-checked]]:not-first:border-t" : "rounded-lg", isDisabled ? cn("cursor-not-allowed bg-muted", disabledHatch) : null, className),
206
+ className: cn(outlineItemClass, selectionItemShellClass, labelTypeClass, firstLineClass, "relative isolate box-border grid items-stretch gap-0 gap-x-2.5 border-selection-border bg-card py-0 transition-colors has-[[data-slot=selection-item-control]_[data-checked]]:border-selection-checked-border has-[[data-slot=selection-item-control]_[data-checked]]:bg-muted", controlAtEnd ? "grid-cols-[minmax(0,1fr)_auto]" : "grid-cols-[auto_minmax(0,1fr)]", connectedStack ? connectedStackClass : "rounded-lg", disabledShellClass, className),
189
207
  children: [/* @__PURE__ */ jsx(Field.Label, {
190
208
  className: cn(labelClass, isSubSectionSelectable ? null : labelRowTargetClass),
191
209
  children: controlAtEnd ? /* @__PURE__ */ jsxs(Fragment$1, { children: [rowCluster, controlSlot] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [controlSlot, rowCluster] })
@@ -1 +1 @@
1
- {"version":3,"file":"selection-item.js","names":["FieldPrimitive"],"sources":["../../../src/components/selection-item/selection-item.tsx"],"sourcesContent":["\"use client\";\n\nimport { Children, createContext, isValidElement, useContext, useMemo } from \"react\";\nimport type { ComponentProps, MouseEvent, ReactElement, ReactNode } from \"react\";\n\nimport { Field as FieldPrimitive } from \"@base-ui/react/field\";\nimport { mergeProps } from \"@base-ui/react/merge-props\";\n\nimport { cn } from \"../../styles/cn\";\nimport { selectionItemShellClass } from \"../../styles/inner-corner/item\";\nimport { labelTypeClass } from \"../../styles/label-type\";\nimport { disabledHatch } from \"../../styles/utils\";\nimport { FieldItem } from \"../field/field\";\nimport { ItemGroup } from \"../item/item\";\nimport { ItemActions, ItemFooter, ItemMedia, ItemTitle } from \"../item/item-markup\";\nimport { itemVariants } from \"../item/item-variants\";\nimport { selectionGroupOrientationVariants } from \"./selection-item-variants\";\nimport type { SelectionItemGroupOrientation } from \"./selection-item-variants\";\n\n/** Resolved once at module scope — the shell always borrows the `outline` arm. */\nconst outlineItemClass = itemVariants({ variant: \"outline\" });\n\n// The label's `::before` is the row's click target. With automatic grid lines it covers the\n// shell's padding box, so a row whose SubSections are all `mode=\"hidden\"` toggles from its\n// bottom inset like a plain row: the sub-section band keeps that 14px inset and lets clicks\n// through to the target. Once the band holds a footer that shows, the target shrinks to the\n// label row and the band takes its own clicks again, unless `isSubSectionSelectable` keeps the\n// whole box. Child combinators keep a selection row nested in a SubSection from counting.\n// Tailwind reads class names from the source text, so each selector is written out in full.\nconst labelClass = cn(\n \"contents cursor-pointer before:absolute before:inset-0 before:-z-1 has-disabled:cursor-not-allowed\"\n);\nconst labelRowTargetClass = cn(\n \"[[data-selection-item]:has(>[data-slot=selection-item-sub-sections]>div>[data-slot=item-footer]:not([data-mode=hidden]))>&]:before:row-[1/2]\"\n);\nconst subSectionBandClass = cn(\n \"pointer-events-none col-span-full grid grid-cols-subgrid pb-3.5\",\n \"has-[>div>[data-slot=item-footer]:not([data-mode=hidden])]:pointer-events-auto\"\n);\n// With `isSubSectionSelectable`, the band shows the label row's cursor, and the not-allowed one\n// while the control is disabled.\nconst selectableBandClass = cn(\n \"cursor-pointer [[data-selection-item]:has(>label>[data-slot=selection-item-control]_:disabled)>&]:cursor-not-allowed\"\n);\n\n// The row's first line, which the control and Actions centre on: one line of the label text\n// `--label-text` at `--label-leading` for a plain-text row, which inherits the shell's label type,\n// or one line of SelectionItem.Title, `--label-text` at `leading-snug`, once the label row holds\n// one. The shell owns it as `--selection-first-line`, so both parts read one value. The title\n// test looks through the label only, so a row nested in a SubSection does not count.\nconst firstLineClass = cn(\n \"[--selection-first-line:var(--label-leading)] has-[>label_[data-slot=selection-item-title]]:[--selection-first-line:calc(var(--label-text)*var(--leading-snug))]\"\n);\n\n/**\n * Elements in a SubSection that keep their own clicks under `isSubSectionSelectable`. A click\n * inside one of them, or inside an element that only takes focus, does not toggle the row.\n */\nconst subSectionOwnClickSelector =\n \"a, button, input, select, textarea, label, summary, audio[controls], video[controls], [contenteditable], [role=button], [role=link], [tabindex]\";\n\n/**\n * What a shell sits in: `false` outside any selection group; otherwise the enclosing\n * group's `orientation` plus whether that group is the private `role=\"list\"` card list\n * (`list: true`) or the plain group primitive (`list: false`).\n */\ntype SelectionItemGroupContextValue = false | { orientation: SelectionItemGroupOrientation; list: boolean };\n\nconst SelectionItemGroupContext = createContext<SelectionItemGroupContextValue>(false);\n\ntype SelectionGroupLayoutProps = {\n children?: ReactNode;\n orientation: SelectionItemGroupOrientation;\n};\n\n/**\n * Package-private layout announcer that `CheckboxGroup` and `RadioGroup` wrap their\n * primitive's children in. A shell placed directly in a plain\n * group then follows the group's `orientation` for its edge treatment — connected stack\n * when vertical, individually rounded card when horizontal — instead of always\n * assuming a connected stack. It adds no `role`; only `SelectionItemGroup` is a list.\n */\nexport function SelectionGroupLayout({ children, orientation }: SelectionGroupLayoutProps): ReactElement {\n const value = useMemo(() => ({ orientation, list: false }), [orientation]);\n return <SelectionItemGroupContext.Provider value={value}>{children}</SelectionItemGroupContext.Provider>;\n}\n\ntype SelectionItemGroupProps = {\n children?: ReactNode;\n /**\n * Layout of the actual item list. Vertical (default) is connected\n * `flex-col gap-0`. Horizontal is `flex-row flex-wrap`, gapped by `--surface-gap-lg`.\n */\n orientation?: SelectionItemGroupOrientation;\n};\n\n/**\n * Private stacked-card list wrapper. `Item.Group` still emits `role=\"list\"`;\n * `SelectionItem.Shell` reads this context and defaults to `role=\"listitem\"`.\n * Vertical remains a connected `flex-col gap-0` stack; horizontal is the actual\n * item list `flex-row flex-wrap`, gapped by `--surface-gap-lg`, with individually rounded shells.\n * Not part of the public `SelectionItem` namespace or entry.\n */\nexport function SelectionItemGroup({\n children,\n orientation = \"vertical\",\n}: SelectionItemGroupProps): ReactElement {\n const value = useMemo(() => ({ orientation, list: true }), [orientation]);\n return (\n <SelectionItemGroupContext.Provider value={value}>\n <ItemGroup\n // The layout axis, as Card writes it: a vertical stack of selection shells is connected.\n data-direction={orientation}\n className={cn(\"select-none\", selectionGroupOrientationVariants({ orientation }).list())}>\n {children}\n </ItemGroup>\n </SelectionItemGroupContext.Provider>\n );\n}\n\n/**\n * A selection row's title, `CheckboxItem.Title` and `RadioItem.Title`: the option's name, in its\n * own `selection-item-title` slot because it is label text. It takes the label text size,\n * `--label-text`, in place of `Item.Title`'s fixed `text-sm`. The size carries `leading-snug` as\n * its `/snug` modifier: a separate `leading-snug` before it would fall to tailwind-merge, which\n * drops a line height that comes before a font size, and the formatter sorts the classes inside a\n * string.\n *\n * Its weight comes from the theme's `--selection-title-weight`: 400 in internal themes and 500\n * in external ones, which matches the group legend and `CheckboxCard` titles. Without\n * `themes.css` it is 400 unless the host sets the role. A `className` weight, such as\n * `font-medium`, replaces it.\n */\nexport function SelectionItemTitle({ className, ...props }: ComponentProps<typeof ItemTitle>): ReactElement {\n return (\n <ItemTitle\n data-slot=\"selection-item-title\"\n className={cn(\n \"text-(length:--label-text)/snug font-[number:var(--selection-title-weight,400)]\",\n className\n )}\n {...props}\n />\n );\n}\n\n/**\n * A selection row's trailing content, such as a price or a badge: `CheckboxItem.Actions` and\n * `RadioItem.Actions`. Its box is at least one first line of the row tall, the line the control\n * centres on, and its text takes that line height, so one line of text or a badge up to a line\n * tall centres on the title's first line. Wrapped text keeps its first line there and grows the\n * row, and content taller than a line tops flush with the title.\n */\nexport function SelectionItemActions({\n className,\n ...props\n}: ComponentProps<typeof ItemActions>): ReactElement {\n return (\n <ItemActions\n className={cn(\"min-h-(--selection-first-line) leading-(--selection-first-line)\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Footer band rendered **outside** the row label. Direct `SelectionItem.SubSection`\n * children are partitioned by identity (`child.type === SelectionItem.SubSection`); a\n * Fragment, wrapper, or HOC hides the part from that filter and it stays inside the\n * label, so clicks would toggle the control.\n */\nexport function SelectionItemSubSection({\n children,\n className,\n mode = \"default\",\n ...props\n}: ComponentProps<typeof ItemFooter>): ReactElement | null {\n if (Children.toArray(children).length === 0) {\n return null;\n }\n return (\n <ItemFooter mode={mode} className={className} {...props}>\n {children}\n </ItemFooter>\n );\n}\n\ntype SelectionItemShellProps = Omit<ComponentProps<typeof FieldItem>, \"className\" | \"children\"> & {\n /**\n * Emitted as `data-slot` on the `Field.Item` root. Typical values are\n * `\"checkbox-item\"` and `\"radio-item\"`.\n */\n dataSlot: string;\n /**\n * The selection control rendered in the `Item.Media variant=\"icon\"` slot. Documented\n * escape hatch for custom indicators (switch, icon crossfade) that the dropped\n * external-card axes used to provide.\n */\n control: ReactNode;\n /**\n * Where the control sits in the labelled row. `\"end\"` places it after the row\n * children (trailing indicator). Default `\"start\"`.\n */\n controlPosition?: \"start\" | \"end\";\n /**\n * Applies `cursor-not-allowed bg-muted` plus the shared `disabledHatch` overlay.\n * Does not disable the control — the control or group owns that.\n */\n isDisabled?: boolean;\n /**\n * Extra classes, merged last through `cn`. A `px-*` utility sets the card's side inset,\n * and a click in that inset beside the label row toggles the control. The row paints the\n * card fill (`bg-card`) like the other field boxes; a list on a surface that should show\n * through takes a background class such as `bg-background`, which replaces it.\n */\n className?: string;\n /**\n * Sub-sections the caller already partitioned out of its row children, rendered outside\n * the label with any direct `SelectionItem.SubSection` children. `CheckboxItem` and\n * `RadioItem` pass them here because they partition where the element was created: a\n * server-authored SubSection reaches the client as a lazy reference, which the\n * `child.type` filter below cannot recognise.\n */\n subSections?: ReactNode;\n /**\n * Lets a click on a SubSection's passive parts toggle the control: its text, the band\n * around it and the side padding beside it. A click inside a link, button, form field,\n * label or other focusable element in the SubSection stays that element's, and a click\n * that ends a text selection does nothing. The control's accessible name stays the label\n * row, and keyboard and assistive-technology users toggle through the control. Leave it\n * off when the SubSection reveals fields under the control, so a click between those\n * fields does not clear the choice. Default `false`.\n */\n isSubSectionSelectable?: boolean;\n /**\n * Direct children are partitioned: `SelectionItem.SubSection` nodes render outside\n * the label so interactive content does not toggle the control. Everything else\n * renders in the label row. Wrapping a SubSection in a Fragment, another component,\n * or an HOC hides it from `child.type === SelectionItem.SubSection` and it stays\n * inside the label. Server-authored trees should pass SubSections through\n * `subSections`; see that prop.\n */\n children?: ReactNode;\n};\n\n/**\n * Shared card-row shell that CheckboxItem and RadioItem plug a control into. Client\n * component, because it reads Field.Item context. The control and sub-section columns\n * share one parent grid, so the spacer tracks the control slot without measuring it.\n * The shell's side padding is the one horizontal inset, so a `px-*` in `className` sets it.\n * The label is `display: contents`, so its cells are shell grid items and its `::before`\n * is an absolute child of the shell grid. With automatic columns, that pseudo-element\n * spans the shell's padding box, so a click anywhere across the label row toggles the\n * control at any inset. While a SubSection shows, it covers the label row only and the\n * sub-section band keeps its own clicks; while every SubSection is `mode=\"hidden\"`, it\n * covers the whole row, bottom inset included. With `isSubSectionSelectable` it always\n * covers the whole row, and a click on the band's passive parts toggles the control.\n * Nothing clips, so a focus ring at a zero inset paints whole.\n *\n * Vertical and default shells, in either group shape or outside any group, collapse\n * borders with `not-first:border-t-0`. A checked shell paints its border in the theme's\n * `--selection-checked-border`: `--primary` in internal themes, the resting `--border` in\n * external ones, whose radio card shows the selection through its control alone. A checked\n * non-first shell repaints its top border in that colour by pulling itself up one pixel\n * (`has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px`)\n * instead of a z-index lift; `className` margin overrides can break that. Horizontal\n * item groups render individually rounded full-border cards with no vertical border\n * collapse and no checked negative margin. Checked selectors are scoped to the\n * private control slot so a checked descendant in SubSection cannot repaint the shell.\n *\n * It publishes `--inner-corner`, its corner less its border and padding, for parts that round with\n * `rounded-inner`.\n */\nexport function SelectionItemShell({\n dataSlot,\n control,\n controlPosition = \"start\",\n isDisabled,\n className,\n subSections: passedSubSections,\n isSubSectionSelectable = false,\n children,\n ...props\n}: SelectionItemShellProps): ReactElement {\n const groupLayout = useContext(SelectionItemGroupContext);\n const inItemGroup = groupLayout !== false && groupLayout.list;\n const connectedStack = groupLayout === false || groupLayout.orientation !== \"horizontal\";\n const childArray = Children.toArray(children);\n const directSubSections = childArray.filter(\n (child) => isValidElement(child) && child.type === SelectionItemSubSection\n );\n const rowChildren = childArray.filter(\n (child) => !(isValidElement(child) && child.type === SelectionItemSubSection)\n );\n const hasSubSection = Children.toArray(passedSubSections).length > 0 || directSubSections.length > 0;\n const controlAtEnd = controlPosition === \"end\";\n\n const rowCellClass = cn(\"self-start pt-3.5\", hasSubSection ? null : \"pb-3.5\");\n // The slot's content box is one first line of the row tall and centres the control in it, so\n // the control sits on the first line at either density. Its height replaces icon media's\n // Item.Title line, which is 14px type, for SelectionItem.Description and the public\n // Item.Description alike.\n const controlSlot = (\n <ItemMedia\n variant=\"icon\"\n data-slot=\"selection-item-control\"\n className={cn(rowCellClass, \"box-content h-(--selection-first-line)\")}>\n {control}\n </ItemMedia>\n );\n const rowCluster = (\n <div className={cn(\"flex min-w-0 items-start gap-2.5\", rowCellClass)}>{rowChildren}</div>\n );\n const spacer = <span aria-hidden />;\n // `mergeProps` runs the consumer's `onClick` first; `preventBaseUIHandler()` there skips this.\n const selectFromSubSection = (event: MouseEvent<HTMLDivElement>) => {\n if (event.defaultPrevented || !(event.target instanceof Element)) {\n return;\n }\n // React bubbles clicks from portals and from rows nested in a SubSection; only a click\n // in this row's own band toggles it.\n const band = event.target.closest(\"[data-slot=selection-item-sub-sections]\");\n if (band?.parentElement !== event.currentTarget) {\n return;\n }\n const ownClick = event.target.closest(subSectionOwnClickSelector);\n if (ownClick && band.contains(ownClick)) {\n return;\n }\n // A selection elsewhere outlives a click in a `select-none` card list, so only one that\n // reaches into the band counts as the click that ended it.\n const selection = window.getSelection();\n const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;\n if (range && !range.collapsed && range.intersectsNode(band)) {\n return;\n }\n // The label's control is the hidden input. Clicking it toggles without dispatching another\n // click through the row, so ancestors and `onClick` see this one click only. Focusing it\n // moves focus to the visible control, as a click on the label row does, so the keyboard\n // carries on from the chosen row.\n const label = event.currentTarget.querySelector(\":scope > label\");\n const control = label instanceof HTMLLabelElement ? label.control : null;\n control?.click();\n control?.focus({ preventScroll: true });\n };\n // Separate child positions give each source its own key space; one merged array\n // would repeat the `.0` keys that the two `Children.toArray` calls assign independently.\n // The band ignores pointers until a footer shows, so the cluster takes them back: content in\n // a SubSection that `subSections` passes inside a wrapper stays clickable. A hidden footer\n // turns them off for itself.\n const subCluster = (\n <div className=\"pointer-events-auto min-w-0\">\n {passedSubSections}\n {directSubSections}\n </div>\n );\n\n return (\n <FieldItem\n {...(inItemGroup ? { role: \"listitem\" as const } : null)}\n {...props}\n {...(isSubSectionSelectable\n ? mergeProps<\"div\">({ onClick: selectFromSubSection }, { onClick: props.onClick })\n : null)}\n data-slot={dataSlot}\n data-selection-item=\"\"\n className={cn(\n outlineItemClass,\n selectionItemShellClass,\n labelTypeClass,\n firstLineClass,\n \"relative isolate box-border grid items-stretch gap-0 gap-x-2.5 bg-card py-0 transition-colors has-[[data-slot=selection-item-control]_[data-checked]]:border-selection-checked-border has-[[data-slot=selection-item-control]_[data-checked]]:bg-muted\",\n controlAtEnd ? \"grid-cols-[minmax(0,1fr)_auto]\" : \"grid-cols-[auto_minmax(0,1fr)]\",\n connectedStack\n ? \"rounded-none not-first:border-t-0 first:rounded-t-lg last:rounded-b-lg has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px has-[[data-slot=selection-item-control]_[data-checked]]:not-first:border-t\"\n : \"rounded-lg\",\n isDisabled ? cn(\"cursor-not-allowed bg-muted\", disabledHatch) : null,\n className\n )}>\n <FieldPrimitive.Label className={cn(labelClass, isSubSectionSelectable ? null : labelRowTargetClass)}>\n {controlAtEnd ? (\n <>\n {rowCluster}\n {controlSlot}\n </>\n ) : (\n <>\n {controlSlot}\n {rowCluster}\n </>\n )}\n </FieldPrimitive.Label>\n {hasSubSection ? (\n <div\n data-slot=\"selection-item-sub-sections\"\n className={cn(subSectionBandClass, isSubSectionSelectable ? selectableBandClass : null)}>\n {controlAtEnd ? (\n <>\n {subCluster}\n {spacer}\n </>\n ) : (\n <>\n {spacer}\n {subCluster}\n </>\n )}\n </div>\n ) : null}\n </FieldItem>\n );\n}\n\nSelectionItemShell.displayName = \"SelectionItem.Shell\";\nSelectionItemTitle.displayName = \"SelectionItem.Title\";\nSelectionItemActions.displayName = \"SelectionItem.Actions\";\nSelectionItemSubSection.displayName = \"SelectionItem.SubSection\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"selection-item.js","names":["FieldPrimitive"],"sources":["../../../src/components/selection-item/selection-item.tsx"],"sourcesContent":["\"use client\";\n\nimport { Children, createContext, isValidElement, useContext, useMemo } from \"react\";\nimport type { ComponentProps, MouseEvent, ReactElement, ReactNode } from \"react\";\n\nimport { Field as FieldPrimitive } from \"@base-ui/react/field\";\nimport { mergeProps } from \"@base-ui/react/merge-props\";\n\nimport { cn } from \"../../styles/cn\";\nimport { selectionItemShellClass } from \"../../styles/inner-corner/item\";\nimport { labelTypeClass } from \"../../styles/label-type\";\nimport { FieldItem } from \"../field/field\";\nimport { ItemGroup } from \"../item/item\";\nimport { ItemActions, ItemFooter, ItemMedia, ItemTitle } from \"../item/item-markup\";\nimport { itemVariants } from \"../item/item-variants\";\nimport { selectionGroupOrientationVariants } from \"./selection-item-variants\";\nimport type { SelectionItemGroupOrientation } from \"./selection-item-variants\";\n\n/** Resolved once at module scope — the shell always borrows the `outline` arm. */\nconst outlineItemClass = itemVariants({ variant: \"outline\" });\n\n// A connected stack's rows share one line per join: every row but the first drops its top border,\n// and a checked one pulls itself up one pixel to paint that line itself. The dividers key on an\n// adjacent selection row, not on first or last child, so a lone shell beside a Field.Description\n// or Field.Error draws no line. A row with a row after it takes the divider on its bottom edge,\n// which outranks the shell's resting edge (0,2,0 over 0,1,0) and yields to a checked row's\n// whole-box edge (0,3,0). A checked row takes the checked divider on each edge it shares with a\n// row, which outranks that box (0,4,0). Every other edge keeps the row's own.\nconst connectedStackClass = cn(\n \"rounded-none not-first:border-t-0 first:rounded-t-lg last:rounded-b-lg has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px has-[[data-slot=selection-item-control]_[data-checked]]:not-first:border-t\",\n \"[&:has(+[data-selection-item])]:border-b-selection-divider has-[[data-slot=selection-item-control]_[data-checked]]:[&:has(+[data-selection-item])]:border-b-selection-checked-divider has-[[data-slot=selection-item-control]_[data-checked]]:[[data-selection-item]+&]:border-t-selection-checked-divider\"\n);\n\n// The label's `::before` is the row's click target. With automatic grid lines it covers the\n// shell's padding box, so a row whose SubSections are all `mode=\"hidden\"` toggles from its\n// bottom inset like a plain row: the sub-section band keeps that 14px inset and lets clicks\n// through to the target. Once the band holds a footer that shows, the target shrinks to the\n// label row and the band takes its own clicks again, unless `isSubSectionSelectable` keeps the\n// whole box. Child combinators keep a selection row nested in a SubSection from counting.\n// Tailwind reads class names from the source text, so each selector is written out in full.\nconst labelClass = cn(\n \"contents cursor-pointer before:absolute before:inset-0 before:-z-1\",\n \"[[data-selection-item]:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))>&]:cursor-not-allowed\"\n);\nconst labelRowTargetClass = cn(\n \"[[data-selection-item]:has(>[data-slot=selection-item-sub-sections]>div>[data-slot=item-footer]:not([data-mode=hidden]))>&]:before:row-[1/2]\"\n);\nconst subSectionBandClass = cn(\n \"pointer-events-none col-span-full grid grid-cols-subgrid pb-3.5\",\n \"has-[>div>[data-slot=item-footer]:not([data-mode=hidden])]:pointer-events-auto\"\n);\n// With `isSubSectionSelectable`, the band shows the label row's cursor, and the not-allowed one\n// while the row is disabled, by the same predicate as the disabled row below.\nconst selectableBandClass = cn(\n \"cursor-pointer\",\n \"[[data-selection-item]:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))>&]:cursor-not-allowed\"\n);\n\n// The row's first line, which the control and Actions centre on: one line of the label text\n// `--label-text` at `--label-leading` for a plain-text row, which inherits the shell's label type,\n// or one line of SelectionItem.Title, `--label-text` at `leading-snug`, once the label row holds\n// one. The shell owns it as `--selection-first-line`, so both parts read one value. The title\n// test looks through the label only, so a row nested in a SubSection does not count.\nconst firstLineClass = cn(\n \"[--selection-first-line:var(--label-leading)] has-[>label_[data-slot=selection-item-title]]:[--selection-first-line:calc(var(--label-text)*var(--leading-snug))]\"\n);\n\n// The disabled row. A shell is disabled when its own `isDisabled` or a disabled group's Field\n// root marks it `data-disabled`, or when its own control is disabled: an element in this row's\n// control slot, not one nested in a SubSection, that carries `data-disabled`, matches the\n// `:disabled` pseudo-class or is `aria-disabled=\"true\"`, the `disabled-state` predicate of\n// fuse.css. The label and the selectable band key their `not-allowed` cursor on the same\n// predicate. The `:is()` takes the specificity of its `:has()` arm whichever arm matches, and\n// that arm's `label` type selector and `:not()` lift it to (0,4,1) over the checked row's\n// `bg-muted` rule at (0,3,0); keep the arm at least that heavy. A\n// disabled row fills with the disabled background role, checked or not, and that fill also\n// wins over a background class in `className`. The 45° hatch alternates 8px transparent bands\n// with 8px of the hatch role: a black alpha in internal themes, transparent in external ones.\n// Tailwind reads class names from the source text, so each selector is written out in full.\nconst disabledShellClass = cn(\n \"[&:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))]:cursor-not-allowed\",\n \"[&:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))]:bg-selection-disabled-background\",\n \"[&:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))]:bg-[repeating-linear-gradient(45deg,transparent,transparent_8px,--theme(--color-selection-disabled-hatch)_8px,--theme(--color-selection-disabled-hatch)_16px)]\"\n);\n\n// A disabled row's label row text takes `--selection-disabled-foreground`: the foreground in\n// internal themes, which keeps the title's colour, and the muted foreground in external ones.\n// It goes on the label row cluster, which also holds a plain-text row, rather than on the\n// title, and the `>label>&` combinators keep a row nested in a SubSection from inheriting it.\n// The SubSection band is a sibling of the label, so its content keeps its colours, a\n// description keeps its own muted text, and the control keeps its 50% face.\nconst disabledLabelTextClass = cn(\n \"[[data-selection-item]:is([data-disabled]:not([data-disabled=false]),:has(>label>[data-slot=selection-item-control]_:is([data-disabled]:not([data-disabled=false]),:disabled,[aria-disabled=true])))>label>&]:text-selection-disabled-foreground\"\n);\n\n/**\n * Elements in a SubSection that keep their own clicks under `isSubSectionSelectable`. A click\n * inside one of them, or inside an element that only takes focus, does not toggle the row.\n */\nconst subSectionOwnClickSelector =\n \"a, button, input, select, textarea, label, summary, audio[controls], video[controls], [contenteditable], [role=button], [role=link], [tabindex]\";\n\n/**\n * What a shell sits in: `false` outside any selection group; otherwise the enclosing\n * group's `orientation` plus whether that group is the private `role=\"list\"` card list\n * (`list: true`) or the plain group primitive (`list: false`).\n */\ntype SelectionItemGroupContextValue = false | { orientation: SelectionItemGroupOrientation; list: boolean };\n\nconst SelectionItemGroupContext = createContext<SelectionItemGroupContextValue>(false);\n\ntype SelectionGroupLayoutProps = {\n children?: ReactNode;\n orientation: SelectionItemGroupOrientation;\n};\n\n/**\n * Package-private layout announcer that `CheckboxGroup` and `RadioGroup` wrap their\n * primitive's children in. A shell placed directly in a plain\n * group then follows the group's `orientation` for its edge treatment — connected stack\n * when vertical, individually rounded card when horizontal — instead of always\n * assuming a connected stack. It adds no `role`; only `SelectionItemGroup` is a list.\n */\nexport function SelectionGroupLayout({ children, orientation }: SelectionGroupLayoutProps): ReactElement {\n const value = useMemo(() => ({ orientation, list: false }), [orientation]);\n return <SelectionItemGroupContext.Provider value={value}>{children}</SelectionItemGroupContext.Provider>;\n}\n\ntype SelectionItemGroupProps = {\n children?: ReactNode;\n /**\n * Layout of the actual item list. Vertical (default) is connected\n * `flex-col gap-0`. Horizontal is `flex-row flex-wrap`, gapped by `--surface-gap-lg`.\n */\n orientation?: SelectionItemGroupOrientation;\n};\n\n/**\n * Private stacked-card list wrapper. `Item.Group` still emits `role=\"list\"`;\n * `SelectionItem.Shell` reads this context and defaults to `role=\"listitem\"`.\n * Vertical remains a connected `flex-col gap-0` stack; horizontal is the actual\n * item list `flex-row flex-wrap`, gapped by `--surface-gap-lg`, with individually rounded shells.\n * Not part of the public `SelectionItem` namespace or entry.\n */\nexport function SelectionItemGroup({\n children,\n orientation = \"vertical\",\n}: SelectionItemGroupProps): ReactElement {\n const value = useMemo(() => ({ orientation, list: true }), [orientation]);\n return (\n <SelectionItemGroupContext.Provider value={value}>\n <ItemGroup\n // The layout axis, as Card writes it: a vertical stack of selection shells is connected.\n data-direction={orientation}\n className={cn(\"select-none\", selectionGroupOrientationVariants({ orientation }).list())}>\n {children}\n </ItemGroup>\n </SelectionItemGroupContext.Provider>\n );\n}\n\n/**\n * A selection row's title, `CheckboxItem.Title` and `RadioItem.Title`: the option's name, in its\n * own `selection-item-title` slot because it is label text. It takes the label text size,\n * `--label-text`, in place of `Item.Title`'s fixed `text-sm`. The size carries `leading-snug` as\n * its `/snug` modifier: a separate `leading-snug` before it would fall to tailwind-merge, which\n * drops a line height that comes before a font size, and the formatter sorts the classes inside a\n * string.\n *\n * Its weight comes from the theme's `--selection-title-weight`: 400 in internal themes and 500\n * in external ones, which matches the group legend and `CheckboxCard` titles. Without\n * `themes.css` it is 400 unless the host sets the role. A `className` weight, such as\n * `font-medium`, replaces it.\n */\nexport function SelectionItemTitle({ className, ...props }: ComponentProps<typeof ItemTitle>): ReactElement {\n return (\n <ItemTitle\n data-slot=\"selection-item-title\"\n className={cn(\n \"text-(length:--label-text)/snug font-[number:var(--selection-title-weight,400)]\",\n className\n )}\n {...props}\n />\n );\n}\n\n/**\n * A selection row's trailing content, such as a price or a badge: `CheckboxItem.Actions` and\n * `RadioItem.Actions`. Its box is at least one first line of the row tall, the line the control\n * centres on, and its text takes that line height, so one line of text or a badge up to a line\n * tall centres on the title's first line. Wrapped text keeps its first line there and grows the\n * row, and content taller than a line tops flush with the title.\n */\nexport function SelectionItemActions({\n className,\n ...props\n}: ComponentProps<typeof ItemActions>): ReactElement {\n return (\n <ItemActions\n className={cn(\"min-h-(--selection-first-line) leading-(--selection-first-line)\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Footer band rendered **outside** the row label. Direct `SelectionItem.SubSection`\n * children are partitioned by identity (`child.type === SelectionItem.SubSection`); a\n * Fragment, wrapper, or HOC hides the part from that filter and it stays inside the\n * label, so clicks would toggle the control.\n */\nexport function SelectionItemSubSection({\n children,\n className,\n mode = \"default\",\n ...props\n}: ComponentProps<typeof ItemFooter>): ReactElement | null {\n if (Children.toArray(children).length === 0) {\n return null;\n }\n return (\n <ItemFooter mode={mode} className={className} {...props}>\n {children}\n </ItemFooter>\n );\n}\n\ntype SelectionItemShellProps = Omit<ComponentProps<typeof FieldItem>, \"className\" | \"children\"> & {\n /**\n * Emitted as `data-slot` on the `Field.Item` root. Typical values are\n * `\"checkbox-item\"` and `\"radio-item\"`.\n */\n dataSlot: string;\n /**\n * The selection control rendered in the `Item.Media variant=\"icon\"` slot. Documented\n * escape hatch for custom indicators (switch, icon crossfade) that the dropped\n * external-card axes used to provide.\n */\n control: ReactNode;\n /**\n * Where the control sits in the labelled row. `\"end\"` places it after the row\n * children (trailing indicator). Default `\"start\"`.\n */\n controlPosition?: \"start\" | \"end\";\n /**\n * Shows the disabled row: the `not-allowed` cursor and the theme's\n * `--selection-disabled-background` fill under a 45° hatch striped in\n * `--selection-disabled-hatch`. Internal themes fill with `--muted` and black stripes at 2%\n * alpha; external themes keep the card fill with no stripes. The label row's text takes\n * `--selection-disabled-foreground`: the foreground in internal themes, the muted foreground in\n * external ones. A description keeps its own muted text, a SubSection keeps its colours, and\n * the control dims itself. A row whose group is disabled, or whose control in the control\n * slot carries `data-disabled`, matches `:disabled` or is `aria-disabled=\"true\"`, shows the\n * same look without it. Does not disable the control — the control or group owns that.\n */\n isDisabled?: boolean;\n /**\n * Extra classes, merged last through `cn`. A `px-*` utility sets the card's side inset,\n * and a click in that inset beside the label row toggles the control. The row paints the\n * card fill (`bg-card`) like the other field boxes; a list on a surface that should show\n * through takes a background class such as `bg-background`, which replaces it. The checked\n * row's `bg-muted` tint and the disabled row's `--selection-disabled-background` fill win over\n * such a class; set `--selection-disabled-background`, for example to `var(--background)`,\n * to change the disabled fill.\n */\n className?: string;\n /**\n * Sub-sections the caller already partitioned out of its row children, rendered outside\n * the label with any direct `SelectionItem.SubSection` children. `CheckboxItem` and\n * `RadioItem` pass them here because they partition where the element was created: a\n * server-authored SubSection reaches the client as a lazy reference, which the\n * `child.type` filter below cannot recognise.\n */\n subSections?: ReactNode;\n /**\n * Lets a click on a SubSection's passive parts toggle the control: its text, the band\n * around it and the side padding beside it. A click inside a link, button, form field,\n * label or other focusable element in the SubSection stays that element's, and a click\n * that ends a text selection does nothing. The control's accessible name stays the label\n * row, and keyboard and assistive-technology users toggle through the control. Leave it\n * off when the SubSection reveals fields under the control, so a click between those\n * fields does not clear the choice. Default `false`.\n */\n isSubSectionSelectable?: boolean;\n /**\n * Direct children are partitioned: `SelectionItem.SubSection` nodes render outside\n * the label so interactive content does not toggle the control. Everything else\n * renders in the label row. Wrapping a SubSection in a Fragment, another component,\n * or an HOC hides it from `child.type === SelectionItem.SubSection` and it stays\n * inside the label. Server-authored trees should pass SubSections through\n * `subSections`; see that prop.\n */\n children?: ReactNode;\n};\n\n/**\n * Shared card-row shell that CheckboxItem and RadioItem plug a control into. Client\n * component, because it reads Field.Item context. The control and sub-section columns\n * share one parent grid, so the spacer tracks the control slot without measuring it.\n * The shell's side padding is the one horizontal inset, so a `px-*` in `className` sets it.\n * The label is `display: contents`, so its cells are shell grid items and its `::before`\n * is an absolute child of the shell grid. With automatic columns, that pseudo-element\n * spans the shell's padding box, so a click anywhere across the label row toggles the\n * control at any inset. While a SubSection shows, it covers the label row only and the\n * sub-section band keeps its own clicks; while every SubSection is `mode=\"hidden\"`, it\n * covers the whole row, bottom inset included. With `isSubSectionSelectable` it always\n * covers the whole row, and a click on the band's passive parts toggles the control.\n * Nothing clips, so a focus ring at a zero inset paints whole.\n *\n * The shell's 1px edge is the theme's `--selection-border`, not Item's outline `--border`:\n * `--border` in internal themes, a zero-alpha colour in external ones, which keeps the border's\n * geometry but draws no line. A checked shell paints its edge in the theme's\n * `--selection-checked-border`: `--primary` in internal themes, the resting `--selection-border`\n * in external ones, whose radio card shows the selection through its control alone.\n *\n * Vertical and default shells, in either group shape or outside any group, collapse borders with\n * `not-first:border-t-0`, so one line divides two rows. The bottom edge of a row with another\n * row after it is the theme's `--selection-divider`, and a checked row's edges shared with another\n * row are its `--selection-checked-divider`. Internal themes alias them to the row's own edges, so\n * a checked row stays boxed in `--primary`. External themes draw both in `--border`: stacked rows\n * keep a grey separator, checked or not, while the sides, the stack's outer top and bottom and a\n * lone row beside other Field parts stay transparent. A checked non-first shell repaints its top border by pulling itself up one\n * pixel (`has-[[data-slot=selection-item-control]_[data-checked]]:not-first:-mt-px`) instead of a\n * z-index lift; `className` margin overrides can break that. Horizontal item groups render\n * individually rounded full-border cards with no vertical border collapse, no divider and no\n * checked negative margin. Checked selectors are scoped to the private control slot so a checked\n * descendant in SubSection cannot repaint the shell.\n *\n * A disabled shell, through `isDisabled`, a disabled group or its own disabled control, fills\n * with the theme's `--selection-disabled-background` under a hatch of\n * `--selection-disabled-hatch`, which outweighs the checked fill and a background class and\n * leaves the checked border, joins and pull-up alone. The label row's text takes\n * `--selection-disabled-foreground`, the control dims itself at 50%, and a SubSection keeps\n * its colours.\n *\n * It publishes `--inner-corner`, its corner less its border and padding, for parts that round with\n * `rounded-inner`.\n */\nexport function SelectionItemShell({\n dataSlot,\n control,\n controlPosition = \"start\",\n isDisabled,\n className,\n subSections: passedSubSections,\n isSubSectionSelectable = false,\n children,\n ...props\n}: SelectionItemShellProps): ReactElement {\n const groupLayout = useContext(SelectionItemGroupContext);\n const inItemGroup = groupLayout !== false && groupLayout.list;\n const connectedStack = groupLayout === false || groupLayout.orientation !== \"horizontal\";\n const childArray = Children.toArray(children);\n const directSubSections = childArray.filter(\n (child) => isValidElement(child) && child.type === SelectionItemSubSection\n );\n const rowChildren = childArray.filter(\n (child) => !(isValidElement(child) && child.type === SelectionItemSubSection)\n );\n const hasSubSection = Children.toArray(passedSubSections).length > 0 || directSubSections.length > 0;\n const controlAtEnd = controlPosition === \"end\";\n\n const rowCellClass = cn(\"self-start pt-3.5\", hasSubSection ? null : \"pb-3.5\");\n // The slot's content box is one first line of the row tall and centres the control in it, so\n // the control sits on the first line at either density. Its height replaces icon media's\n // Item.Title line, which is 14px type, for SelectionItem.Description and the public\n // Item.Description alike.\n const controlSlot = (\n <ItemMedia\n variant=\"icon\"\n data-slot=\"selection-item-control\"\n className={cn(rowCellClass, \"box-content h-(--selection-first-line)\")}>\n {control}\n </ItemMedia>\n );\n const rowCluster = (\n <div className={cn(\"flex min-w-0 items-start gap-2.5\", rowCellClass, disabledLabelTextClass)}>\n {rowChildren}\n </div>\n );\n const spacer = <span aria-hidden />;\n // `mergeProps` runs the consumer's `onClick` first; `preventBaseUIHandler()` there skips this.\n const selectFromSubSection = (event: MouseEvent<HTMLDivElement>) => {\n if (event.defaultPrevented || !(event.target instanceof Element)) {\n return;\n }\n // React bubbles clicks from portals and from rows nested in a SubSection; only a click\n // in this row's own band toggles it.\n const band = event.target.closest(\"[data-slot=selection-item-sub-sections]\");\n if (band?.parentElement !== event.currentTarget) {\n return;\n }\n const ownClick = event.target.closest(subSectionOwnClickSelector);\n if (ownClick && band.contains(ownClick)) {\n return;\n }\n // A selection elsewhere outlives a click in a `select-none` card list, so only one that\n // reaches into the band counts as the click that ended it.\n const selection = window.getSelection();\n const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;\n if (range && !range.collapsed && range.intersectsNode(band)) {\n return;\n }\n // The label's control is the hidden input. Clicking it toggles without dispatching another\n // click through the row, so ancestors and `onClick` see this one click only. Focusing it\n // moves focus to the visible control, as a click on the label row does, so the keyboard\n // carries on from the chosen row.\n const label = event.currentTarget.querySelector(\":scope > label\");\n const control = label instanceof HTMLLabelElement ? label.control : null;\n control?.click();\n control?.focus({ preventScroll: true });\n };\n // Separate child positions give each source its own key space; one merged array\n // would repeat the `.0` keys that the two `Children.toArray` calls assign independently.\n // The band ignores pointers until a footer shows, so the cluster takes them back: content in\n // a SubSection that `subSections` passes inside a wrapper stays clickable. A hidden footer\n // turns them off for itself.\n const subCluster = (\n <div className=\"pointer-events-auto min-w-0\">\n {passedSubSections}\n {directSubSections}\n </div>\n );\n\n return (\n <FieldItem\n {...(inItemGroup ? { role: \"listitem\" as const } : null)}\n {...props}\n {...(isSubSectionSelectable\n ? mergeProps<\"div\">({ onClick: selectFromSubSection }, { onClick: props.onClick })\n : null)}\n // Stamped directly: Field.Item's `disabled` prop would disable the control through\n // FieldItemContext.\n {...(isDisabled ? { \"data-disabled\": \"\" } : null)}\n data-slot={dataSlot}\n data-selection-item=\"\"\n className={cn(\n outlineItemClass,\n selectionItemShellClass,\n labelTypeClass,\n firstLineClass,\n \"relative isolate box-border grid items-stretch gap-0 gap-x-2.5 border-selection-border bg-card py-0 transition-colors has-[[data-slot=selection-item-control]_[data-checked]]:border-selection-checked-border has-[[data-slot=selection-item-control]_[data-checked]]:bg-muted\",\n controlAtEnd ? \"grid-cols-[minmax(0,1fr)_auto]\" : \"grid-cols-[auto_minmax(0,1fr)]\",\n connectedStack ? connectedStackClass : \"rounded-lg\",\n disabledShellClass,\n className\n )}>\n <FieldPrimitive.Label className={cn(labelClass, isSubSectionSelectable ? null : labelRowTargetClass)}>\n {controlAtEnd ? (\n <>\n {rowCluster}\n {controlSlot}\n </>\n ) : (\n <>\n {controlSlot}\n {rowCluster}\n </>\n )}\n </FieldPrimitive.Label>\n {hasSubSection ? (\n <div\n data-slot=\"selection-item-sub-sections\"\n className={cn(subSectionBandClass, isSubSectionSelectable ? selectableBandClass : null)}>\n {controlAtEnd ? (\n <>\n {subCluster}\n {spacer}\n </>\n ) : (\n <>\n {spacer}\n {subCluster}\n </>\n )}\n </div>\n ) : null}\n </FieldItem>\n );\n}\n\nSelectionItemShell.displayName = \"SelectionItem.Shell\";\nSelectionItemTitle.displayName = \"SelectionItem.Title\";\nSelectionItemActions.displayName = \"SelectionItem.Actions\";\nSelectionItemSubSection.displayName = \"SelectionItem.SubSection\";\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elmeragroup/fuse",
3
- "version": "0.1.0-canary.73",
3
+ "version": "0.1.0-canary.76",
4
4
  "description": "Fuse — whitelabel React components for Elmera Group's energy brands. One package, twenty theme permutations, ESM-only.",
5
5
  "keywords": [
6
6
  "react",
@@ -371,7 +371,7 @@
371
371
  "access": "public"
372
372
  },
373
373
  "elmeraRelease": {
374
- "commit": "c714d8140ff783be1d4d1adcee7f7f05c1a914ba",
374
+ "commit": "c3d38e925629fc68ca6206566157edab8f520b80",
375
375
  "channel": "canary"
376
376
  }
377
377
  }
@@ -1 +1 @@
1
- {"version":3,"file":"corner-radius.d.ts","names":[],"sources":["../../src/styles/corner-radius.ts"],"mappings":";;;;;;;qBAgEa;;;;;qBAQA;;;;;qBAQA;;;;;;;qBAUA;;;;;;;;qBAWA;;;;;qBAMA"}
1
+ {"version":3,"file":"corner-radius.d.ts","names":[],"sources":["../../src/styles/corner-radius.ts"],"mappings":";;;;;;;qBAkEa;;;;;qBAQA;;;;;qBAQA;;;;;;;qBAUA;;;;;;;;qBAWA;;;;;qBAMA"}
@@ -1 +1 @@
1
- {"version":3,"file":"corner-radius.js","names":[],"sources":["../../src/styles/corner-radius.ts"],"sourcesContent":["import { cn } from \"./cn\";\n\n// The corners here leave the `rounded-*` scale in external themes and round with `--radius`\n// in internal ones. Each class reads the element's own `--radius` and `--radius-step`, so it\n// follows the enclosing theme scope and a `--radius` override on the theme element.\n// `--radius-step` doubles as the variant switch. It is 0px in the internal variant and 2px\n// in the external one, and the formulas support no other value. `--radius - 1000 * step`\n// equals `--radius` at a 0px step and lies 2000px below it at a 2px step. A `max()` with it\n// raises a cap to at least `--radius` internally and leaves the cap as written externally.\n// Each read of the step falls back to 0px, as the rungs in fuse.css do, so a host without\n// themes.css rounds these corners with its own `--radius` instead of losing them.\n// Tailwind generates a class only from its whole literal, so each class spells its value.\n//\n// The field box declares its corner once, as `--field-corner`, the clamp `clamp(--radius -\n// 1000 * step, --radius-field, --radius + 1000 * step)`. Its bounds meet at `--radius` at a\n// 0px step, so internal fields keep reading `--radius` on the box itself and follow a\n// `--radius` override on a plain wrapper. At a 2px step they lie 4000px apart, and the theme's\n// `--radius-field` applies. The read of `--radius-field` falls back to `--radius` for a host\n// that sets the step but not the role. The property is unregistered, so the box substitutes\n// its own `var()` reads and the parts inside inherit the box's corner. The box publishes it\n// less its inset as the inner corner of the parts inside (`inner-corner/field.ts`).\n//\n// Inner corners are concentric: an inner part rounds with its shell's outer corner less the\n// inset, `max(0px, outer - inset)`, where the inset is the shell's padding plus border on the\n// axis that reaches the corner. Outer corners keep their rung. An inner part rounds with the\n// public `rounded-inner` utility in fuse.css, `var(--inner-corner, var(--radius))`, so outside\n// a shell it rounds with `--radius`. The shells live in `inner-corner/`, one private module per\n// component family, so a component bundles only its own. Each constant there pairs a part's\n// rung or padding with the corner it publishes, read through `--theme()` so it resolves in the\n// shell's own theme scope, and spells its values whole, because Tailwind generates a class only\n// from its whole literal. A part rounds concentrically only inside a shell; a block directly in\n// `Combobox.Content` rounds with `--radius`.\n//\n// Every shell boundary, a popup root or a padded part, states the whole corner state, so no\n// value from an outer shell crosses it. It writes its post-padding corner to a private\n// `--shell-inner`, or `initial` when the part does not publish a corner, and aliases the public\n// `--inner-corner` to it. It also clears the private `--shell-corner` relay with\n// `publishShellBoundary`, unless it is one of the parts that carry the relay:\n//\n// - a NavigationMenu popup, which sets `--shell-corner` to the corner its Content takes;\n// - a NavigationMenu Content, which reads it and subtracts its own padding;\n// - an inline NavigationMenu Viewport, which sets it from the inherited `--shell-inner` of the\n// Content around it, a value a ThemeScope reset leaves alone.\n//\n// Frame hands its corner on through its own private input instead (`inner-corner/frame.ts`):\n// the root writes `--frame-corner` onto its direct panels and table containers, and every panel\n// and container resets it at lower specificity, so only a Frame's direct child holds a value. A\n// Frame panel is an ordinary boundary.\n//\n// No custom property depends on itself, directly or indirectly, on one element, so any depth\n// subtracts each padding once. Where no shell is above a padded part, `--shell-corner` is\n// undefined, its `--inner-corner` is invalid at computed-value time, and `rounded-inner` falls\n// back to `--radius`. `--inner-corner` is unregistered and inherits as a computed length. Every\n// element with theme attributes resets `--inner-corner` to `initial` with a zero-specificity\n// rule in the utilities layer, so a part in a nested ThemeScope rounds with that scope's\n// `--radius` instead of the outer shell's px value, and a shell class on the same element wins\n// whatever layer order the host declares.\n\n/**\n * The field box corner: Input, Textarea, the Select trigger, NumberField, InputGroup, the\n * Combobox chips box and the React Aria field group. It declares `--field-corner` for the parts\n * inside the box and rounds with it. External themes round it with `--radius-field`, and\n * internal themes with `--radius`.\n */\nexport const fieldCornerClass = cn(\n \"rounded-(--field-corner) [--field-corner:clamp(var(--radius)-1000*var(--radius-step,0px),var(--radius-field,var(--radius)),var(--radius)+1000*var(--radius-step,0px))]\"\n);\n\n/**\n * The corner of a compact button that sits in a toolbar, the xs Toggle. External themes round it with `rounded-md` capped at 10px, and\n * internal themes with `--radius`.\n */\nexport const compactCornerClass = cn(\n \"rounded-[min(--theme(--radius-md),max(10px,var(--radius)-1000*var(--radius-step,0px)))]\"\n);\n\n/**\n * The Checkbox corner. External themes round it with `rounded-md` capped at 4px, and\n * internal themes with `--radius`.\n */\nexport const checkboxCornerClass = cn(\n \"rounded-[min(--theme(--radius-md),max(4px,var(--radius)-1000*var(--radius-step,0px)))]\"\n);\n\n/**\n * The corner of the standalone Calendar. External themes keep the reference's 4px whatever\n * the brand radius, and internal themes round it with `--radius`. The clamp's bounds meet at\n * `--radius` at a 0px step and lie 4000px apart at a 2px step, where the preferred 4px\n * applies.\n */\nexport const fixedCornerClass = cn(\n \"rounded-[clamp(var(--radius)-1000*var(--radius-step,0px),4px,var(--radius)+1000*var(--radius-step,0px))]\"\n);\n\n/**\n * The public corner a shell publishes: its private post-padding corner, `--shell-inner`. Only\n * the parts that carry the `--shell-corner` relay compose it alone; every other shell boundary\n * composes {@link publishShellBoundary}. Each composes it beside a `--shell-inner` declaration,\n * and only there, so a ThemeScope reset of `--inner-corner` is never undone by an inherited\n * `--shell-inner`.\n */\nexport const publishInnerCorner = cn(\"[--inner-corner:var(--shell-inner)]\");\n\n/**\n * {@link publishInnerCorner} for an independent shell boundary: it also clears the private\n * `--shell-corner` relay, so no relay from an outer shell reaches a part inside it.\n */\nexport const publishShellBoundary = cn(\"[--shell-corner:initial]\", publishInnerCorner);\n"],"mappings":";;;;;;;;AAgEA,MAAa,mBAAmB,GAC9B,wKACF;;;;;AAMA,MAAa,qBAAqB,GAChC,yFACF;;;;;AAMA,MAAa,sBAAsB,GACjC,wFACF;;;;;;;AAQA,MAAa,mBAAmB,GAC9B,0GACF;;;;;;;;AASA,MAAa,qBAAqB,GAAG,qCAAqC;;;;;AAM1E,MAAa,uBAAuB,GAAG,4BAA4B,kBAAkB"}
1
+ {"version":3,"file":"corner-radius.js","names":[],"sources":["../../src/styles/corner-radius.ts"],"sourcesContent":["import { cn } from \"./cn\";\n\n// The corners here leave the `rounded-*` scale in external themes and round with `--radius`\n// in internal ones. Each class reads the element's own `--radius` and `--radius-step`, so it\n// follows the enclosing theme scope and a `--radius` override on the theme element.\n// `--radius-step` doubles as the variant switch. It is 0px in the internal variant and 2px\n// in the external one, and the formulas support no other value. `--radius - 1000 * step`\n// equals `--radius` at a 0px step and lies 2000px below it at a 2px step. A `max()` with it\n// raises a cap to at least `--radius` internally and leaves the cap as written externally.\n// Each read of the step falls back to 0px, as the rungs in fuse.css do, so a host without\n// themes.css rounds these corners with its own `--radius` instead of losing them.\n// Tailwind generates a class only from its whole literal, so each class spells its value.\n//\n// The field box declares its corner once, as `--field-corner`, the clamp `clamp(--radius -\n// 1000 * step, --radius-field, --radius + 1000 * step)`. Its bounds meet at `--radius` at a\n// 0px step, so internal fields keep reading `--radius` on the box itself and follow a\n// `--radius` override on a plain wrapper. At a 2px step they lie 4000px apart, and the theme's\n// `--radius-field` applies. Every theme aliases it to `var(--radius)`, resolved on the theme\n// element as `--radius-button` is, so external fields round with the brand radius and a host\n// that sets the role still overrides it. The read of `--radius-field` falls back to `--radius`\n// for a host that sets the step but not the role. The property is unregistered, so the box\n// substitutes its own `var()` reads and the parts inside inherit the box's corner. The box\n// publishes it less its inset as the inner corner of the parts inside (`inner-corner/field.ts`).\n//\n// Inner corners are concentric: an inner part rounds with its shell's outer corner less the\n// inset, `max(0px, outer - inset)`, where the inset is the shell's padding plus border on the\n// axis that reaches the corner. Outer corners keep their rung. An inner part rounds with the\n// public `rounded-inner` utility in fuse.css, `var(--inner-corner, var(--radius))`, so outside\n// a shell it rounds with `--radius`. The shells live in `inner-corner/`, one private module per\n// component family, so a component bundles only its own. Each constant there pairs a part's\n// rung or padding with the corner it publishes, read through `--theme()` so it resolves in the\n// shell's own theme scope, and spells its values whole, because Tailwind generates a class only\n// from its whole literal. A part rounds concentrically only inside a shell; a block directly in\n// `Combobox.Content` rounds with `--radius`.\n//\n// Every shell boundary, a popup root or a padded part, states the whole corner state, so no\n// value from an outer shell crosses it. It writes its post-padding corner to a private\n// `--shell-inner`, or `initial` when the part does not publish a corner, and aliases the public\n// `--inner-corner` to it. It also clears the private `--shell-corner` relay with\n// `publishShellBoundary`, unless it is one of the parts that carry the relay:\n//\n// - a NavigationMenu popup, which sets `--shell-corner` to the corner its Content takes;\n// - a NavigationMenu Content, which reads it and subtracts its own padding;\n// - an inline NavigationMenu Viewport, which sets it from the inherited `--shell-inner` of the\n// Content around it, a value a ThemeScope reset leaves alone.\n//\n// Frame hands its corner on through its own private input instead (`inner-corner/frame.ts`):\n// the root writes `--frame-corner` onto its direct panels and table containers, and every panel\n// and container resets it at lower specificity, so only a Frame's direct child holds a value. A\n// Frame panel is an ordinary boundary.\n//\n// No custom property depends on itself, directly or indirectly, on one element, so any depth\n// subtracts each padding once. Where no shell is above a padded part, `--shell-corner` is\n// undefined, its `--inner-corner` is invalid at computed-value time, and `rounded-inner` falls\n// back to `--radius`. `--inner-corner` is unregistered and inherits as a computed length. Every\n// element with theme attributes resets `--inner-corner` to `initial` with a zero-specificity\n// rule in the utilities layer, so a part in a nested ThemeScope rounds with that scope's\n// `--radius` instead of the outer shell's px value, and a shell class on the same element wins\n// whatever layer order the host declares.\n\n/**\n * The field box corner: Input, Textarea, the Select trigger, NumberField, InputGroup, the\n * Combobox chips box and the React Aria field group. It declares `--field-corner` for the parts\n * inside the box and rounds with it. External themes round it with `--radius-field`, and\n * internal themes with `--radius`.\n */\nexport const fieldCornerClass = cn(\n \"rounded-(--field-corner) [--field-corner:clamp(var(--radius)-1000*var(--radius-step,0px),var(--radius-field,var(--radius)),var(--radius)+1000*var(--radius-step,0px))]\"\n);\n\n/**\n * The corner of a compact button that sits in a toolbar, the xs Toggle. External themes round it with `rounded-md` capped at 10px, and\n * internal themes with `--radius`.\n */\nexport const compactCornerClass = cn(\n \"rounded-[min(--theme(--radius-md),max(10px,var(--radius)-1000*var(--radius-step,0px)))]\"\n);\n\n/**\n * The Checkbox corner. External themes round it with `rounded-md` capped at 4px, and\n * internal themes with `--radius`.\n */\nexport const checkboxCornerClass = cn(\n \"rounded-[min(--theme(--radius-md),max(4px,var(--radius)-1000*var(--radius-step,0px)))]\"\n);\n\n/**\n * The corner of the standalone Calendar. External themes keep the reference's 4px whatever\n * the brand radius, and internal themes round it with `--radius`. The clamp's bounds meet at\n * `--radius` at a 0px step and lie 4000px apart at a 2px step, where the preferred 4px\n * applies.\n */\nexport const fixedCornerClass = cn(\n \"rounded-[clamp(var(--radius)-1000*var(--radius-step,0px),4px,var(--radius)+1000*var(--radius-step,0px))]\"\n);\n\n/**\n * The public corner a shell publishes: its private post-padding corner, `--shell-inner`. Only\n * the parts that carry the `--shell-corner` relay compose it alone; every other shell boundary\n * composes {@link publishShellBoundary}. Each composes it beside a `--shell-inner` declaration,\n * and only there, so a ThemeScope reset of `--inner-corner` is never undone by an inherited\n * `--shell-inner`.\n */\nexport const publishInnerCorner = cn(\"[--inner-corner:var(--shell-inner)]\");\n\n/**\n * {@link publishInnerCorner} for an independent shell boundary: it also clears the private\n * `--shell-corner` relay, so no relay from an outer shell reaches a part inside it.\n */\nexport const publishShellBoundary = cn(\"[--shell-corner:initial]\", publishInnerCorner);\n"],"mappings":";;;;;;;;AAkEA,MAAa,mBAAmB,GAC9B,wKACF;;;;;AAMA,MAAa,qBAAqB,GAChC,yFACF;;;;;AAMA,MAAa,sBAAsB,GACjC,wFACF;;;;;;;AAQA,MAAa,mBAAmB,GAC9B,0GACF;;;;;;;;AASA,MAAa,qBAAqB,GAAG,qCAAqC;;;;;AAM1E,MAAa,uBAAuB,GAAG,4BAA4B,kBAAkB"}
package/styles/fuse.css CHANGED
@@ -144,7 +144,16 @@
144
144
  --color-input: var(--input);
145
145
  --color-ring: var(--ring);
146
146
  --color-button-outline: var(--button-outline, var(--border));
147
+ --color-selection-border: var(--selection-border, var(--border));
147
148
  --color-selection-checked-border: var(--selection-checked-border, var(--primary));
149
+ --color-selection-divider: var(--selection-divider, var(--selection-border, var(--border)));
150
+ --color-selection-checked-divider: var(
151
+ --selection-checked-divider,
152
+ var(--selection-checked-border, var(--primary))
153
+ );
154
+ --color-selection-disabled-background: var(--selection-disabled-background, var(--muted));
155
+ --color-selection-disabled-hatch: var(--selection-disabled-hatch, oklch(0 0 0 / 0.02));
156
+ --color-selection-disabled-foreground: var(--selection-disabled-foreground, var(--foreground));
148
157
  --color-sidebar: var(--sidebar);
149
158
  --color-sidebar-foreground: var(--sidebar-foreground);
150
159
  --color-sidebar-accent: var(--sidebar-accent);
package/styles/utils.d.ts CHANGED
@@ -150,12 +150,7 @@ export declare const dataWithinInvalidFocusRingClass: string;
150
150
  * after both arms, so tailwind-merge keeps its ring over the plain focus ring's.
151
151
  */
152
152
  export declare const stateInvalidFocusRingVisibleClass: string;
153
- /**
154
- * Hatch texture and icon-crossfade faces. `elmera/no-primitive-colors` allowlists
155
- * the hatch as a whole
156
- * token, so the string must not split, re-space, or prefix it.
157
- */
158
- export declare const disabledHatch: string;
153
+ /** Icon-crossfade faces. */
159
154
  export declare const iconCrossfadeTransition: string;
160
155
  export declare const iconCrossfadeShown: string;
161
156
  export declare const iconCrossfadeHidden: string;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/styles/utils.ts"],"mappings":";;;;;;;;;;;;;;;qBAiBa,uCAAS;;IAOhB;MACE;;IAEF;MACE;MACA;;IAGF;MACE;;;;IAIF;IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAuBO;;;;;;qBAOA;;;;;;qBAOA;;;;;;;;;;;;;qBAcA;;;;;qBAMA;;;;;;;;;;qBAWA;;;;;qBAQA;;;;;;;;;;qBAaA;;;;;;;;qBAYA;;;;;;qBASA;;;;;;qBAOA;qBAGA;qBAGA;qBACA"}
1
+ {"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/styles/utils.ts"],"mappings":";;;;;;;;;;;;;;;qBAiBa,uCAAS;;IAOhB;MACE;;IAEF;MACE;MACA;;IAGF;MACE;;;;IAIF;IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAuBO;;;;;;qBAOA;;;;;;qBAOA;;;;;;;;;;;;;qBAcA;;;;;qBAMA;;;;;;;;;;qBAWA;;;;;qBAQA;;;;;;;;;;qBAaA;;;;;;;;qBAYA;;;;;;qBASA;;qBAGA;qBAGA;qBACA"}
package/styles/utils.js CHANGED
@@ -120,16 +120,11 @@ const dataWithinInvalidFocusRingClass = cn("data-invalid:has-[>[data-focus-ring-
120
120
  * after both arms, so tailwind-merge keeps its ring over the plain focus ring's.
121
121
  */
122
122
  const stateInvalidFocusRingVisibleClass = cn("ring-3 ring-error/20 ring-offset-1 ring-offset-error");
123
- /**
124
- * Hatch texture and icon-crossfade faces. `elmera/no-primitive-colors` allowlists
125
- * the hatch as a whole
126
- * token, so the string must not split, re-space, or prefix it.
127
- */
128
- const disabledHatch = cn("bg-[repeating-linear-gradient(45deg,transparent,transparent_8px,rgb(0_0_0/0.02)_8px,rgb(0_0_0/0.02)_16px)]");
123
+ /** Icon-crossfade faces. */
129
124
  const iconCrossfadeTransition = cn("transition-[opacity,filter,scale] duration-300 ease-[cubic-bezier(0.2,0,0,1)]");
130
125
  const iconCrossfadeShown = cn("scale-100 opacity-100 blur-none");
131
126
  const iconCrossfadeHidden = cn("scale-[0.25] opacity-0 blur-[4px]");
132
127
  //#endregion
133
- export { ariaInvalidFocusRingClass, dataInvalidFocusRingClass, dataWithinInvalidFocusRingClass, disabledHatch, focusRing, iconCrossfadeHidden, iconCrossfadeShown, iconCrossfadeTransition, selfFocusRingClass, stateFocusRingClass, stateFocusRingVisibleClass, stateInvalidFocusRingVisibleClass, withinFocusRingClass, withinFocusRingControlClass, withinInvalidFocusRingClass };
128
+ export { ariaInvalidFocusRingClass, dataInvalidFocusRingClass, dataWithinInvalidFocusRingClass, focusRing, iconCrossfadeHidden, iconCrossfadeShown, iconCrossfadeTransition, selfFocusRingClass, stateFocusRingClass, stateFocusRingVisibleClass, stateInvalidFocusRingVisibleClass, withinFocusRingClass, withinFocusRingControlClass, withinInvalidFocusRingClass };
134
129
 
135
130
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../src/styles/utils.ts"],"sourcesContent":["import { cn } from \"./cn\";\nimport { tv } from \"./tv\";\n\n/**\n * The shared keyboard focus ring: a 2px `--ring` box-shadow drawn flush against the control,\n * with no offset gap. The flush ring keeps one 2px reach in every target, so a ring never\n * paints the page colour between itself and the control, and the ring's colour is held to 3:1\n * against the page and card it is drawn on (`contrast-matrix.test.ts`).\n *\n * - `self` paints on the element that matches `:focus-visible`.\n * - `within` paints on a group whose `data-focus-ring-control` descendant is focus-visible;\n * its `control` slot cancels the control's own ring so the group paints once.\n * - `state` paints from React Aria's `isFocusVisible` render prop, for a non-focusable host.\n *\n * A focused invalid control paints the invalid focus face from the constants below instead,\n * which the state face composes: see {@link ariaInvalidFocusRingClass}.\n */\nexport const focusRing = tv({\n slots: {\n root: \"\",\n control: \"\",\n },\n variants: {\n target: {\n self: {\n root: \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none\",\n },\n within: {\n root: \"has-[[data-focus-ring-control]:focus-visible]:ring-2 has-[[data-focus-ring-control]:focus-visible]:ring-ring has-[[data-focus-ring-control]:focus-visible]:outline-none\",\n control:\n \"focus-visible:ring-0 focus-visible:outline-none aria-invalid:focus-visible:ring-0 aria-invalid:focus-visible:ring-offset-0 data-invalid:focus-visible:ring-0 data-invalid:focus-visible:ring-offset-0\",\n },\n state: {\n root: \"outline-none\",\n },\n },\n isFocusVisible: {\n true: {},\n false: {},\n },\n },\n compoundVariants: [\n {\n target: \"state\",\n isFocusVisible: true,\n class: {\n root: \"ring-2 ring-ring\",\n },\n },\n ],\n defaultVariants: {\n target: \"self\",\n },\n});\n\n/**\n * The self-target focus ring, resolved once at module scope and imported by every\n * consumer. Seventeen components used to hoist `focusRing({ target: \"self\" }).root()`\n * into a private module constant of their own; none does now, so the adapter is\n * evaluated once per process rather than once per module.\n */\nexport const selfFocusRingClass = focusRing({ target: \"self\" }).root();\n\n/**\n * The within-target focus ring root class, resolved once at module scope — the parent\n * face that lights up when the element carrying `data-focus-ring-control` is\n * keyboard-focused. Pair it with {@link withinFocusRingControlClass} on the control.\n */\nexport const withinFocusRingClass = focusRing({ target: \"within\" }).root();\n\n/**\n * The control half of the within-target focus ring: it suppresses the control's own\n * ring, the invalid face's offset line included, so only the parent paints one. Pair with\n * {@link withinFocusRingClass}.\n */\nexport const withinFocusRingControlClass = focusRing({ target: \"within\" }).control();\n\n/**\n * The state-target focus ring's resting face — `outline-none` alone, the half that does\n * not depend on RAC's `isFocusVisible` render prop. Pair it with\n * {@link stateFocusRingVisibleClass} on the recipe's `isFocusVisible: true` arm.\n *\n * The `state` target exists because the interim react-aria tier hangs the ring on a\n * non-focusable wrapper (a `Group`, a calendar cell, a grid row) and is told about focus\n * through a render prop rather than a `:focus-visible` selector. Its two *fixed* rungs\n * are still constants, so they are resolved here like the other two targets. The one\n * call that genuinely cannot be — `react-aria/link`, which passes a live\n * `isFocusVisible` per render — keeps calling {@link focusRing} directly.\n */\nexport const stateFocusRingClass = focusRing({ target: \"state\" }).root();\n\n/**\n * The state-target focus ring's keyboard-focused face, resolved once at module scope.\n * Recipes put it on their `isFocusVisible: true` arm; see {@link stateFocusRingClass}.\n */\nexport const stateFocusRingVisibleClass = focusRing({ target: \"state\", isFocusVisible: true }).root();\n\n/**\n * The focused invalid face for a control that carries `aria-invalid` itself. Outside the error\n * border it paints a solid 1px `--error` line flush against the box, and the resting 3px\n * `error/20` halo outside that line, reaching 4px. Tailwind's ring offset slot draws the solid\n * line and paints above the ring slot, whose spread is the halo's 3px plus the 1px offset.\n * Each arm stacks the invalid attribute on `:focus-visible`, so its selector outweighs both the\n * plain focus ring and the resting halo of the state face, whatever order Tailwind emits them\n * in. `state-face.ts` composes it into the aria arm of the invalid face.\n */\nexport const ariaInvalidFocusRingClass = cn(\n \"aria-invalid:focus-visible:ring-3 aria-invalid:focus-visible:ring-error/20 aria-invalid:focus-visible:ring-offset-1 aria-invalid:focus-visible:ring-offset-error\"\n);\n\n/**\n * The focused invalid face for a Base UI state root marked `data-invalid`. See\n * {@link ariaInvalidFocusRingClass}; `state-face.ts` composes it into the data-target face.\n */\nexport const dataInvalidFocusRingClass = cn(\n \"data-invalid:focus-visible:ring-3 data-invalid:focus-visible:ring-error/20 data-invalid:focus-visible:ring-offset-1 data-invalid:focus-visible:ring-offset-error\"\n);\n\n/**\n * The focused invalid face (see {@link ariaInvalidFocusRingClass}) on a within-target group.\n * One arm reads the group's own control, a direct child marked `data-focus-ring-control` with\n * `aria-invalid=\"true\"`, as the within state face does. The other covers a group that carries\n * `aria-invalid` itself, such as NumberField's, and also reads only its direct child, so a\n * valid control nested in an addon leaves an invalid outer group its resting halo. Each\n * selector outweighs the within ring and the halo, so source order never decides it.\n * `state-face.ts` composes it into the within-target face.\n */\nexport const withinInvalidFocusRingClass = cn(\n \"has-[>[data-focus-ring-control][aria-invalid=true]:focus-visible]:ring-3 has-[>[data-focus-ring-control][aria-invalid=true]:focus-visible]:ring-error/20 has-[>[data-focus-ring-control][aria-invalid=true]:focus-visible]:ring-offset-1 has-[>[data-focus-ring-control][aria-invalid=true]:focus-visible]:ring-offset-error\",\n \"aria-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-3 aria-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-error/20 aria-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-offset-1 aria-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-offset-error\"\n);\n\n/**\n * The focused invalid face (see {@link ariaInvalidFocusRingClass}) on a within-target host that\n * Base UI marks `data-invalid`, such as Slider's thumb, which paints the ring for the range\n * input nested in it as a direct child.\n * The thumb takes the data-target state face, so its halo and this ring key off the same\n * attribute. The selector outweighs the within ring and the halo.\n */\nexport const dataWithinInvalidFocusRingClass = cn(\n \"data-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-3 data-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-error/20 data-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-offset-1 data-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-offset-error\"\n);\n\n/**\n * The state-target focused invalid face (see {@link ariaInvalidFocusRingClass}), for a React\n * Aria recipe's compound of `isInvalid: true` and `isFocusVisible: true`. A compound applies\n * after both arms, so tailwind-merge keeps its ring over the plain focus ring's.\n */\nexport const stateInvalidFocusRingVisibleClass = cn(\"ring-3 ring-error/20 ring-offset-1 ring-offset-error\");\n\n/**\n * Hatch texture and icon-crossfade faces. `elmera/no-primitive-colors` allowlists\n * the hatch as a whole\n * token, so the string must not split, re-space, or prefix it.\n */\nexport const disabledHatch = cn(\n \"bg-[repeating-linear-gradient(45deg,transparent,transparent_8px,rgb(0_0_0/0.02)_8px,rgb(0_0_0/0.02)_16px)]\"\n);\nexport const iconCrossfadeTransition = cn(\n \"transition-[opacity,filter,scale] duration-300 ease-[cubic-bezier(0.2,0,0,1)]\"\n);\nexport const iconCrossfadeShown = cn(\"scale-100 opacity-100 blur-none\");\nexport const iconCrossfadeHidden = cn(\"scale-[0.25] opacity-0 blur-[4px]\");\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,MAAa,YAAY,GAAG;CAC1B,OAAO;EACL,MAAM;EACN,SAAS;CACX;CACA,UAAU;EACR,QAAQ;GACN,MAAM,EACJ,MAAM,0EACR;GACA,QAAQ;IACN,MAAM;IACN,SACE;GACJ;GACA,OAAO,EACL,MAAM,eACR;EACF;EACA,gBAAgB;GACd,MAAM,CAAC;GACP,OAAO,CAAC;EACV;CACF;CACA,kBAAkB,CAChB;EACE,QAAQ;EACR,gBAAgB;EAChB,OAAO,EACL,MAAM,mBACR;CACF,CACF;CACA,iBAAiB,EACf,QAAQ,OACV;AACF,CAAC;;;;;;;AAQD,MAAa,qBAAqB,UAAU,EAAE,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK;;;;;;AAOrE,MAAa,uBAAuB,UAAU,EAAE,QAAQ,SAAS,CAAC,CAAC,CAAC,KAAK;;;;;;AAOzE,MAAa,8BAA8B,UAAU,EAAE,QAAQ,SAAS,CAAC,CAAC,CAAC,QAAQ;;;;;;;;;;;;;AAcnF,MAAa,sBAAsB,UAAU,EAAE,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK;;;;;AAMvE,MAAa,6BAA6B,UAAU;CAAE,QAAQ;CAAS,gBAAgB;AAAK,CAAC,CAAC,CAAC,KAAK;;;;;;;;;;AAWpG,MAAa,4BAA4B,GACvC,kKACF;;;;;AAMA,MAAa,4BAA4B,GACvC,kKACF;;;;;;;;;;AAWA,MAAa,8BAA8B,GACzC,gUACA,sSACF;;;;;;;;AASA,MAAa,kCAAkC,GAC7C,sSACF;;;;;;AAOA,MAAa,oCAAoC,GAAG,sDAAsD;;;;;;AAO1G,MAAa,gBAAgB,GAC3B,4GACF;AACA,MAAa,0BAA0B,GACrC,+EACF;AACA,MAAa,qBAAqB,GAAG,iCAAiC;AACtE,MAAa,sBAAsB,GAAG,mCAAmC"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../src/styles/utils.ts"],"sourcesContent":["import { cn } from \"./cn\";\nimport { tv } from \"./tv\";\n\n/**\n * The shared keyboard focus ring: a 2px `--ring` box-shadow drawn flush against the control,\n * with no offset gap. The flush ring keeps one 2px reach in every target, so a ring never\n * paints the page colour between itself and the control, and the ring's colour is held to 3:1\n * against the page and card it is drawn on (`contrast-matrix.test.ts`).\n *\n * - `self` paints on the element that matches `:focus-visible`.\n * - `within` paints on a group whose `data-focus-ring-control` descendant is focus-visible;\n * its `control` slot cancels the control's own ring so the group paints once.\n * - `state` paints from React Aria's `isFocusVisible` render prop, for a non-focusable host.\n *\n * A focused invalid control paints the invalid focus face from the constants below instead,\n * which the state face composes: see {@link ariaInvalidFocusRingClass}.\n */\nexport const focusRing = tv({\n slots: {\n root: \"\",\n control: \"\",\n },\n variants: {\n target: {\n self: {\n root: \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none\",\n },\n within: {\n root: \"has-[[data-focus-ring-control]:focus-visible]:ring-2 has-[[data-focus-ring-control]:focus-visible]:ring-ring has-[[data-focus-ring-control]:focus-visible]:outline-none\",\n control:\n \"focus-visible:ring-0 focus-visible:outline-none aria-invalid:focus-visible:ring-0 aria-invalid:focus-visible:ring-offset-0 data-invalid:focus-visible:ring-0 data-invalid:focus-visible:ring-offset-0\",\n },\n state: {\n root: \"outline-none\",\n },\n },\n isFocusVisible: {\n true: {},\n false: {},\n },\n },\n compoundVariants: [\n {\n target: \"state\",\n isFocusVisible: true,\n class: {\n root: \"ring-2 ring-ring\",\n },\n },\n ],\n defaultVariants: {\n target: \"self\",\n },\n});\n\n/**\n * The self-target focus ring, resolved once at module scope and imported by every\n * consumer. Seventeen components used to hoist `focusRing({ target: \"self\" }).root()`\n * into a private module constant of their own; none does now, so the adapter is\n * evaluated once per process rather than once per module.\n */\nexport const selfFocusRingClass = focusRing({ target: \"self\" }).root();\n\n/**\n * The within-target focus ring root class, resolved once at module scope — the parent\n * face that lights up when the element carrying `data-focus-ring-control` is\n * keyboard-focused. Pair it with {@link withinFocusRingControlClass} on the control.\n */\nexport const withinFocusRingClass = focusRing({ target: \"within\" }).root();\n\n/**\n * The control half of the within-target focus ring: it suppresses the control's own\n * ring, the invalid face's offset line included, so only the parent paints one. Pair with\n * {@link withinFocusRingClass}.\n */\nexport const withinFocusRingControlClass = focusRing({ target: \"within\" }).control();\n\n/**\n * The state-target focus ring's resting face — `outline-none` alone, the half that does\n * not depend on RAC's `isFocusVisible` render prop. Pair it with\n * {@link stateFocusRingVisibleClass} on the recipe's `isFocusVisible: true` arm.\n *\n * The `state` target exists because the interim react-aria tier hangs the ring on a\n * non-focusable wrapper (a `Group`, a calendar cell, a grid row) and is told about focus\n * through a render prop rather than a `:focus-visible` selector. Its two *fixed* rungs\n * are still constants, so they are resolved here like the other two targets. The one\n * call that genuinely cannot be — `react-aria/link`, which passes a live\n * `isFocusVisible` per render — keeps calling {@link focusRing} directly.\n */\nexport const stateFocusRingClass = focusRing({ target: \"state\" }).root();\n\n/**\n * The state-target focus ring's keyboard-focused face, resolved once at module scope.\n * Recipes put it on their `isFocusVisible: true` arm; see {@link stateFocusRingClass}.\n */\nexport const stateFocusRingVisibleClass = focusRing({ target: \"state\", isFocusVisible: true }).root();\n\n/**\n * The focused invalid face for a control that carries `aria-invalid` itself. Outside the error\n * border it paints a solid 1px `--error` line flush against the box, and the resting 3px\n * `error/20` halo outside that line, reaching 4px. Tailwind's ring offset slot draws the solid\n * line and paints above the ring slot, whose spread is the halo's 3px plus the 1px offset.\n * Each arm stacks the invalid attribute on `:focus-visible`, so its selector outweighs both the\n * plain focus ring and the resting halo of the state face, whatever order Tailwind emits them\n * in. `state-face.ts` composes it into the aria arm of the invalid face.\n */\nexport const ariaInvalidFocusRingClass = cn(\n \"aria-invalid:focus-visible:ring-3 aria-invalid:focus-visible:ring-error/20 aria-invalid:focus-visible:ring-offset-1 aria-invalid:focus-visible:ring-offset-error\"\n);\n\n/**\n * The focused invalid face for a Base UI state root marked `data-invalid`. See\n * {@link ariaInvalidFocusRingClass}; `state-face.ts` composes it into the data-target face.\n */\nexport const dataInvalidFocusRingClass = cn(\n \"data-invalid:focus-visible:ring-3 data-invalid:focus-visible:ring-error/20 data-invalid:focus-visible:ring-offset-1 data-invalid:focus-visible:ring-offset-error\"\n);\n\n/**\n * The focused invalid face (see {@link ariaInvalidFocusRingClass}) on a within-target group.\n * One arm reads the group's own control, a direct child marked `data-focus-ring-control` with\n * `aria-invalid=\"true\"`, as the within state face does. The other covers a group that carries\n * `aria-invalid` itself, such as NumberField's, and also reads only its direct child, so a\n * valid control nested in an addon leaves an invalid outer group its resting halo. Each\n * selector outweighs the within ring and the halo, so source order never decides it.\n * `state-face.ts` composes it into the within-target face.\n */\nexport const withinInvalidFocusRingClass = cn(\n \"has-[>[data-focus-ring-control][aria-invalid=true]:focus-visible]:ring-3 has-[>[data-focus-ring-control][aria-invalid=true]:focus-visible]:ring-error/20 has-[>[data-focus-ring-control][aria-invalid=true]:focus-visible]:ring-offset-1 has-[>[data-focus-ring-control][aria-invalid=true]:focus-visible]:ring-offset-error\",\n \"aria-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-3 aria-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-error/20 aria-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-offset-1 aria-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-offset-error\"\n);\n\n/**\n * The focused invalid face (see {@link ariaInvalidFocusRingClass}) on a within-target host that\n * Base UI marks `data-invalid`, such as Slider's thumb, which paints the ring for the range\n * input nested in it as a direct child.\n * The thumb takes the data-target state face, so its halo and this ring key off the same\n * attribute. The selector outweighs the within ring and the halo.\n */\nexport const dataWithinInvalidFocusRingClass = cn(\n \"data-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-3 data-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-error/20 data-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-offset-1 data-invalid:has-[>[data-focus-ring-control]:focus-visible]:ring-offset-error\"\n);\n\n/**\n * The state-target focused invalid face (see {@link ariaInvalidFocusRingClass}), for a React\n * Aria recipe's compound of `isInvalid: true` and `isFocusVisible: true`. A compound applies\n * after both arms, so tailwind-merge keeps its ring over the plain focus ring's.\n */\nexport const stateInvalidFocusRingVisibleClass = cn(\"ring-3 ring-error/20 ring-offset-1 ring-offset-error\");\n\n/** Icon-crossfade faces. */\nexport const iconCrossfadeTransition = cn(\n \"transition-[opacity,filter,scale] duration-300 ease-[cubic-bezier(0.2,0,0,1)]\"\n);\nexport const iconCrossfadeShown = cn(\"scale-100 opacity-100 blur-none\");\nexport const iconCrossfadeHidden = cn(\"scale-[0.25] opacity-0 blur-[4px]\");\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,MAAa,YAAY,GAAG;CAC1B,OAAO;EACL,MAAM;EACN,SAAS;CACX;CACA,UAAU;EACR,QAAQ;GACN,MAAM,EACJ,MAAM,0EACR;GACA,QAAQ;IACN,MAAM;IACN,SACE;GACJ;GACA,OAAO,EACL,MAAM,eACR;EACF;EACA,gBAAgB;GACd,MAAM,CAAC;GACP,OAAO,CAAC;EACV;CACF;CACA,kBAAkB,CAChB;EACE,QAAQ;EACR,gBAAgB;EAChB,OAAO,EACL,MAAM,mBACR;CACF,CACF;CACA,iBAAiB,EACf,QAAQ,OACV;AACF,CAAC;;;;;;;AAQD,MAAa,qBAAqB,UAAU,EAAE,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK;;;;;;AAOrE,MAAa,uBAAuB,UAAU,EAAE,QAAQ,SAAS,CAAC,CAAC,CAAC,KAAK;;;;;;AAOzE,MAAa,8BAA8B,UAAU,EAAE,QAAQ,SAAS,CAAC,CAAC,CAAC,QAAQ;;;;;;;;;;;;;AAcnF,MAAa,sBAAsB,UAAU,EAAE,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAK;;;;;AAMvE,MAAa,6BAA6B,UAAU;CAAE,QAAQ;CAAS,gBAAgB;AAAK,CAAC,CAAC,CAAC,KAAK;;;;;;;;;;AAWpG,MAAa,4BAA4B,GACvC,kKACF;;;;;AAMA,MAAa,4BAA4B,GACvC,kKACF;;;;;;;;;;AAWA,MAAa,8BAA8B,GACzC,gUACA,sSACF;;;;;;;;AASA,MAAa,kCAAkC,GAC7C,sSACF;;;;;;AAOA,MAAa,oCAAoC,GAAG,sDAAsD;;AAG1G,MAAa,0BAA0B,GACrC,+EACF;AACA,MAAa,qBAAqB,GAAG,iCAAiC;AACtE,MAAa,sBAAsB,GAAG,mCAAmC"}
package/styles.css CHANGED
@@ -59,6 +59,7 @@
59
59
  --blur-xs: 4px;
60
60
  --default-transition-duration: 150ms;
61
61
  --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
62
+ --color-selection-disabled-hatch: var(--selection-disabled-hatch, oklch(0 0 0 / 0.02));
62
63
  }
63
64
  .\@container\/card-header {
64
65
  container-type: inline-size;
@@ -1254,6 +1255,9 @@
1254
1255
  .border-secondary {
1255
1256
  border-color: var(--secondary);
1256
1257
  }
1258
+ .border-selection-border {
1259
+ border-color: var(--selection-border, var(--border));
1260
+ }
1257
1261
  .border-sidebar-border {
1258
1262
  border-color: var(--sidebar-border);
1259
1263
  }
@@ -1386,9 +1390,6 @@
1386
1390
  .bg-warning-soft {
1387
1391
  background-color: var(--warning-soft);
1388
1392
  }
1389
- .bg-\[repeating-linear-gradient\(45deg\,transparent\,transparent_8px\,rgb\(0_0_0\/0\.02\)_8px\,rgb\(0_0_0\/0\.02\)_16px\)\] {
1390
- background-image: repeating-linear-gradient(45deg,transparent,transparent 8px,rgb(0 0 0/0.02) 8px,rgb(0 0 0/0.02) 16px);
1391
- }
1392
1393
  .bg-clip-padding {
1393
1394
  background-clip: padding-box;
1394
1395
  }
@@ -4877,12 +4878,30 @@
4877
4878
  .\[\&\:\:-webkit-search-cancel-button\]\:hidden::-webkit-search-cancel-button {
4878
4879
  display: none;
4879
4880
  }
4881
+ .\[\&\:has\(\+\[data-selection-item\]\)\]\:border-b-selection-divider:has( + [data-selection-item]) {
4882
+ border-bottom-color: var(--selection-divider, var(--selection-border, var(--border)));
4883
+ }
4884
+ .has-\[\[data-slot\=selection-item-control\]_\[data-checked\]\]\:\[\&\:has\(\+\[data-selection-item\]\)\]\:border-b-selection-checked-divider:has(:is([data-slot=selection-item-control] [data-checked])):has( + [data-selection-item]) {
4885
+ border-bottom-color: var(
4886
+ --selection-checked-divider,
4887
+ var(--selection-checked-border, var(--primary))
4888
+ );
4889
+ }
4880
4890
  .\[\.border-b\]\:pb-2:is(.border-b) {
4881
4891
  padding-bottom: calc(0.25rem * 2);
4882
4892
  }
4883
4893
  .\[\.border-t\]\:pt-2:is(.border-t) {
4884
4894
  padding-top: calc(0.25rem * 2);
4885
4895
  }
4896
+ .\[\&\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:has\(\>label\>\[data-slot\=selection-item-control\]_\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:disabled\,\[aria-disabled\=true\]\)\)\)\]\:cursor-not-allowed:is([data-disabled]:not([data-disabled=false]), :has( > label > [data-slot=selection-item-control] :is([data-disabled]:not([data-disabled=false]), :disabled, [aria-disabled=true]))) {
4897
+ cursor: not-allowed;
4898
+ }
4899
+ .\[\&\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:has\(\>label\>\[data-slot\=selection-item-control\]_\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:disabled\,\[aria-disabled\=true\]\)\)\)\]\:bg-selection-disabled-background:is([data-disabled]:not([data-disabled=false]), :has( > label > [data-slot=selection-item-control] :is([data-disabled]:not([data-disabled=false]), :disabled, [aria-disabled=true]))) {
4900
+ background-color: var(--selection-disabled-background, var(--muted));
4901
+ }
4902
+ .\[\&\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:has\(\>label\>\[data-slot\=selection-item-control\]_\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:disabled\,\[aria-disabled\=true\]\)\)\)\]\:bg-\[repeating-linear-gradient\(45deg\,transparent\,transparent_8px\,--theme\(--color-selection-disabled-hatch\)_8px\,--theme\(--color-selection-disabled-hatch\)_16px\)\]:is([data-disabled]:not([data-disabled=false]), :has( > label > [data-slot=selection-item-control] :is([data-disabled]:not([data-disabled=false]), :disabled, [aria-disabled=true]))) {
4903
+ background-image: repeating-linear-gradient(45deg,transparent,transparent 8px,var(--selection-disabled-hatch, oklch(0 0 0 / 0.02)) 8px,var(--selection-disabled-hatch, oklch(0 0 0 / 0.02)) 16px);
4904
+ }
4886
4905
  :is(.\*\:\[\[data-slot\=frame-panel\]\+\[data-slot\=frame-panel\]\]\:mt-1 > *):is([data-slot=frame-panel] + [data-slot=frame-panel]) {
4887
4906
  margin-top: 0.25rem;
4888
4907
  }
@@ -5205,13 +5224,22 @@
5205
5224
  [data-placement] > .\[\[data-placement\]\>\&\]\:\[--shell-inner\:max\(0px\,--theme\(--radius-md\)-1px-4\*var\(--spacing\)\)\] {
5206
5225
  --shell-inner: max(0px, calc(var(--radius) - var(--radius-step, 0px)) - 1px - 4 * var(--spacing));
5207
5226
  }
5227
+ [data-selection-item] + .has-\[\[data-slot\=selection-item-control\]_\[data-checked\]\]\:\[\[data-selection-item\]\+\&\]\:border-t-selection-checked-divider:has(:is([data-slot=selection-item-control] [data-checked])) {
5228
+ border-top-color: var(
5229
+ --selection-checked-divider,
5230
+ var(--selection-checked-border, var(--primary))
5231
+ );
5232
+ }
5208
5233
  [data-selection-item]:has( > [data-slot=selection-item-sub-sections] > div > [data-slot=item-footer]:not([data-mode=hidden])) > .\[\[data-selection-item\]\:has\(\>\[data-slot\=selection-item-sub-sections\]\>div\>\[data-slot\=item-footer\]\:not\(\[data-mode\=hidden\]\)\)\>\&\]\:before\:row-\[1\/2\]::before {
5209
5234
  content: var(--tw-content);
5210
5235
  grid-row: 1/2;
5211
5236
  }
5212
- [data-selection-item]:has( > label > [data-slot=selection-item-control] :disabled) > .\[\[data-selection-item\]\:has\(\>label\>\[data-slot\=selection-item-control\]_\:disabled\)\>\&\]\:cursor-not-allowed {
5237
+ [data-selection-item]:is([data-disabled]:not([data-disabled=false]), :has( > label > [data-slot=selection-item-control] :is([data-disabled]:not([data-disabled=false]), :disabled, [aria-disabled=true]))) > .\[\[data-selection-item\]\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:has\(\>label\>\[data-slot\=selection-item-control\]_\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:disabled\,\[aria-disabled\=true\]\)\)\)\>\&\]\:cursor-not-allowed {
5213
5238
  cursor: not-allowed;
5214
5239
  }
5240
+ [data-selection-item]:is([data-disabled]:not([data-disabled=false]), :has( > label > [data-slot=selection-item-control] :is([data-disabled]:not([data-disabled=false]), :disabled, [aria-disabled=true]))) > label > .\[\[data-selection-item\]\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:has\(\>label\>\[data-slot\=selection-item-control\]_\:is\(\[data-disabled\]\:not\(\[data-disabled\=false\]\)\,\:disabled\,\[aria-disabled\=true\]\)\)\)\>label\>\&\]\:text-selection-disabled-foreground {
5241
+ color: var(--selection-disabled-foreground, var(--foreground));
5242
+ }
5215
5243
  [data-side=left][data-collapsible=offcanvas] .\[\[data-side\=left\]\[data-collapsible\=offcanvas\]_\&\]\:-right-2 {
5216
5244
  right: calc(0.25rem * -2);
5217
5245
  }
package/themes.css CHANGED
@@ -78,7 +78,13 @@
78
78
  --input: oklch(0.9219 0 0);
79
79
  --ring: oklch(0.6 0 0);
80
80
  --button-outline: var(--border);
81
+ --selection-border: var(--border);
81
82
  --selection-checked-border: var(--primary);
83
+ --selection-divider: var(--selection-border);
84
+ --selection-checked-divider: var(--selection-checked-border);
85
+ --selection-disabled-background: var(--muted);
86
+ --selection-disabled-hatch: oklch(0 0 0 / 0.02);
87
+ --selection-disabled-foreground: var(--foreground);
82
88
  --sidebar: oklch(0.9851 0 0);
83
89
  --sidebar-foreground: oklch(0.16 0 0);
84
90
  --sidebar-accent: oklch(0.9219 0 0);
@@ -190,7 +196,13 @@
190
196
  --input: oklch(0.9219 0 0);
191
197
  --ring: oklch(0.6 0 0);
192
198
  --button-outline: var(--border);
199
+ --selection-border: var(--border);
193
200
  --selection-checked-border: var(--primary);
201
+ --selection-divider: var(--selection-border);
202
+ --selection-checked-divider: var(--selection-checked-border);
203
+ --selection-disabled-background: var(--muted);
204
+ --selection-disabled-hatch: oklch(0 0 0 / 0.02);
205
+ --selection-disabled-foreground: var(--foreground);
194
206
  --sidebar-ring: var(--ring);
195
207
  --radius: 0.375rem;
196
208
  --radius-button: var(--radius);
@@ -227,11 +239,17 @@
227
239
  --input: oklch(0.9232 0.0026 48.72);
228
240
  --ring: oklch(0.6 0 0);
229
241
  --button-outline: var(--foreground);
230
- --selection-checked-border: var(--border);
242
+ --selection-border: oklch(0 0 0 / 0);
243
+ --selection-checked-border: var(--selection-border);
244
+ --selection-divider: var(--border);
245
+ --selection-checked-divider: var(--selection-divider);
246
+ --selection-disabled-background: var(--card);
247
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
248
+ --selection-disabled-foreground: var(--muted-foreground);
231
249
  --sidebar-ring: var(--ring);
232
250
  --radius: 0.75rem;
233
251
  --radius-button: 1.8125rem;
234
- --radius-field: 0.25rem;
252
+ --radius-field: var(--radius);
235
253
  --radius-step: 2px;
236
254
  --button-outline-width: 2px;
237
255
  --selection-title-weight: 500;
@@ -284,11 +302,17 @@
284
302
  --input: oklch(0.929 0.0126 255.53);
285
303
  --ring: oklch(0.6 0 0);
286
304
  --button-outline: var(--foreground);
287
- --selection-checked-border: var(--border);
305
+ --selection-border: oklch(0 0 0 / 0);
306
+ --selection-checked-border: var(--selection-border);
307
+ --selection-divider: var(--border);
308
+ --selection-checked-divider: var(--selection-divider);
309
+ --selection-disabled-background: var(--card);
310
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
311
+ --selection-disabled-foreground: var(--muted-foreground);
288
312
  --sidebar-ring: var(--ring);
289
313
  --radius: 1rem;
290
314
  --radius-button: 1rem;
291
- --radius-field: 0.25rem;
315
+ --radius-field: var(--radius);
292
316
  --radius-step: 2px;
293
317
  --button-outline-width: 2px;
294
318
  --selection-title-weight: 500;
@@ -321,11 +345,17 @@
321
345
  --input: oklch(0.929 0.0126 255.53);
322
346
  --ring: oklch(0.6 0 0);
323
347
  --button-outline: var(--foreground);
324
- --selection-checked-border: var(--border);
348
+ --selection-border: oklch(0 0 0 / 0);
349
+ --selection-checked-border: var(--selection-border);
350
+ --selection-divider: var(--border);
351
+ --selection-checked-divider: var(--selection-divider);
352
+ --selection-disabled-background: var(--card);
353
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
354
+ --selection-disabled-foreground: var(--muted-foreground);
325
355
  --sidebar-ring: var(--ring);
326
356
  --radius: 0.5rem;
327
357
  --radius-button: 0.5rem;
328
- --radius-field: 0.25rem;
358
+ --radius-field: var(--radius);
329
359
  --radius-step: 2px;
330
360
  --button-outline-width: 2px;
331
361
  --selection-title-weight: 500;
@@ -358,11 +388,17 @@
358
388
  --input: oklch(0.9232 0.0026 48.72);
359
389
  --ring: oklch(0.6 0 0);
360
390
  --button-outline: var(--foreground);
361
- --selection-checked-border: var(--border);
391
+ --selection-border: oklch(0 0 0 / 0);
392
+ --selection-checked-border: var(--selection-border);
393
+ --selection-divider: var(--border);
394
+ --selection-checked-divider: var(--selection-divider);
395
+ --selection-disabled-background: var(--card);
396
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
397
+ --selection-disabled-foreground: var(--muted-foreground);
362
398
  --sidebar-ring: var(--ring);
363
399
  --radius: 0.75rem;
364
400
  --radius-button: 1.8125rem;
365
- --radius-field: 0.25rem;
401
+ --radius-field: var(--radius);
366
402
  --radius-step: 2px;
367
403
  --button-outline-width: 2px;
368
404
  --selection-title-weight: 500;
@@ -395,11 +431,17 @@
395
431
  --input: oklch(0.9232 0.0026 48.72);
396
432
  --ring: oklch(0.6 0 0);
397
433
  --button-outline: var(--foreground);
398
- --selection-checked-border: var(--border);
434
+ --selection-border: oklch(0 0 0 / 0);
435
+ --selection-checked-border: var(--selection-border);
436
+ --selection-divider: var(--border);
437
+ --selection-checked-divider: var(--selection-divider);
438
+ --selection-disabled-background: var(--card);
439
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
440
+ --selection-disabled-foreground: var(--muted-foreground);
399
441
  --sidebar-ring: var(--ring);
400
442
  --radius: 0.75rem;
401
443
  --radius-button: 1.8125rem;
402
- --radius-field: 0.25rem;
444
+ --radius-field: var(--radius);
403
445
  --radius-step: 2px;
404
446
  --button-outline-width: 2px;
405
447
  --selection-title-weight: 500;
@@ -432,11 +474,17 @@
432
474
  --input: oklch(0.9219 0 0);
433
475
  --ring: oklch(0.6 0 0);
434
476
  --button-outline: var(--foreground);
435
- --selection-checked-border: var(--border);
477
+ --selection-border: oklch(0 0 0 / 0);
478
+ --selection-checked-border: var(--selection-border);
479
+ --selection-divider: var(--border);
480
+ --selection-checked-divider: var(--selection-divider);
481
+ --selection-disabled-background: var(--card);
482
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
483
+ --selection-disabled-foreground: var(--muted-foreground);
436
484
  --sidebar-ring: var(--ring);
437
485
  --radius: 0.375rem;
438
486
  --radius-button: 0.375rem;
439
- --radius-field: 0.25rem;
487
+ --radius-field: var(--radius);
440
488
  --radius-step: 2px;
441
489
  --button-outline-width: 2px;
442
490
  --selection-title-weight: 500;
@@ -469,11 +517,17 @@
469
517
  --input: oklch(0.8256644 0.0145962 162.3965393);
470
518
  --ring: oklch(0.6 0 0);
471
519
  --button-outline: var(--foreground);
472
- --selection-checked-border: var(--border);
520
+ --selection-border: oklch(0 0 0 / 0);
521
+ --selection-checked-border: var(--selection-border);
522
+ --selection-divider: var(--border);
523
+ --selection-checked-divider: var(--selection-divider);
524
+ --selection-disabled-background: var(--card);
525
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
526
+ --selection-disabled-foreground: var(--muted-foreground);
473
527
  --sidebar-ring: var(--ring);
474
528
  --radius: 0.375rem;
475
529
  --radius-button: 1.8125rem;
476
- --radius-field: 0.25rem;
530
+ --radius-field: var(--radius);
477
531
  --radius-step: 2px;
478
532
  --button-outline-width: 2px;
479
533
  --selection-title-weight: 500;
@@ -529,7 +583,13 @@
529
583
  --input: oklch(1 0 0 / 40%);
530
584
  --ring: oklch(0.6 0 0);
531
585
  --button-outline: var(--border);
586
+ --selection-border: var(--border);
532
587
  --selection-checked-border: var(--primary);
588
+ --selection-divider: var(--selection-border);
589
+ --selection-checked-divider: var(--selection-checked-border);
590
+ --selection-disabled-background: var(--muted);
591
+ --selection-disabled-hatch: oklch(0 0 0 / 0.02);
592
+ --selection-disabled-foreground: var(--foreground);
533
593
  --sidebar: oklch(0.205 0 0);
534
594
  --sidebar-foreground: oklch(0.985 0 0);
535
595
  --sidebar-accent: oklch(0.269 0 0);
@@ -655,7 +715,13 @@
655
715
  --input: oklch(0.6543689 0.0037291 145.5328);
656
716
  --ring: oklch(0.6 0 0);
657
717
  --button-outline: var(--foreground);
658
- --selection-checked-border: var(--border);
718
+ --selection-border: oklch(0 0 0 / 0);
719
+ --selection-checked-border: var(--selection-border);
720
+ --selection-divider: var(--border);
721
+ --selection-checked-divider: var(--selection-divider);
722
+ --selection-disabled-background: var(--card);
723
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
724
+ --selection-disabled-foreground: var(--muted-foreground);
659
725
  --sidebar: oklch(0.1749487 0.003804 164.5613);
660
726
  --sidebar-foreground: oklch(0.9604175 0.0214022 46.9889);
661
727
  --sidebar-accent: oklch(0.2661671 0.0034366 164.8011);
@@ -683,7 +749,7 @@
683
749
  --sh-comment: oklch(0.8280204 0.0042636 121.5755);
684
750
  --radius: 0.75rem;
685
751
  --radius-button: 1.8125rem;
686
- --radius-field: 0.25rem;
752
+ --radius-field: var(--radius);
687
753
  --radius-step: 2px;
688
754
  --button-outline-width: 2px;
689
755
  --selection-title-weight: 500;
@@ -745,7 +811,13 @@
745
811
  --input: oklch(0.6543689 0.0037291 145.5328);
746
812
  --ring: oklch(0.6 0 0);
747
813
  --button-outline: var(--foreground);
748
- --selection-checked-border: var(--border);
814
+ --selection-border: oklch(0 0 0 / 0);
815
+ --selection-checked-border: var(--selection-border);
816
+ --selection-divider: var(--border);
817
+ --selection-checked-divider: var(--selection-divider);
818
+ --selection-disabled-background: var(--card);
819
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
820
+ --selection-disabled-foreground: var(--muted-foreground);
749
821
  --sidebar: oklch(0.1749487 0.003804 164.5613);
750
822
  --sidebar-foreground: oklch(0.9822955 0.0142785 213.0969);
751
823
  --sidebar-accent: oklch(0.2661671 0.0034366 164.8011);
@@ -773,7 +845,7 @@
773
845
  --sh-comment: oklch(0.8280204 0.0042636 121.5755);
774
846
  --radius: 0.75rem;
775
847
  --radius-button: 1.8125rem;
776
- --radius-field: 0.25rem;
848
+ --radius-field: var(--radius);
777
849
  --radius-step: 2px;
778
850
  --button-outline-width: 2px;
779
851
  --selection-title-weight: 500;
@@ -835,7 +907,13 @@
835
907
  --input: oklch(0.6543689 0.0037291 145.5328);
836
908
  --ring: oklch(0.6 0 0);
837
909
  --button-outline: var(--foreground);
838
- --selection-checked-border: var(--border);
910
+ --selection-border: oklch(0 0 0 / 0);
911
+ --selection-checked-border: var(--selection-border);
912
+ --selection-divider: var(--border);
913
+ --selection-checked-divider: var(--selection-divider);
914
+ --selection-disabled-background: var(--card);
915
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
916
+ --selection-disabled-foreground: var(--muted-foreground);
839
917
  --sidebar: oklch(0.1749487 0.003804 164.5613);
840
918
  --sidebar-foreground: oklch(0.9790218 0.0292767 188.8731);
841
919
  --sidebar-accent: oklch(0.2661671 0.0034366 164.8011);
@@ -863,7 +941,7 @@
863
941
  --sh-comment: oklch(0.8280204 0.0042636 121.5755);
864
942
  --radius: 1rem;
865
943
  --radius-button: 1rem;
866
- --radius-field: 0.25rem;
944
+ --radius-field: var(--radius);
867
945
  --radius-step: 2px;
868
946
  --button-outline-width: 2px;
869
947
  --selection-title-weight: 500;
@@ -925,7 +1003,13 @@
925
1003
  --input: oklch(0.6543689 0.0037291 145.5328);
926
1004
  --ring: oklch(0.6 0 0);
927
1005
  --button-outline: var(--foreground);
928
- --selection-checked-border: var(--border);
1006
+ --selection-border: oklch(0 0 0 / 0);
1007
+ --selection-checked-border: var(--selection-border);
1008
+ --selection-divider: var(--border);
1009
+ --selection-checked-divider: var(--selection-divider);
1010
+ --selection-disabled-background: var(--card);
1011
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
1012
+ --selection-disabled-foreground: var(--muted-foreground);
929
1013
  --sidebar: oklch(0.2029294 0.0334602 267.7195);
930
1014
  --sidebar-foreground: oklch(0.9592915 0.0326656 74.8018);
931
1015
  --sidebar-accent: oklch(0.2717674 0.038702 268.9648);
@@ -953,7 +1037,7 @@
953
1037
  --sh-comment: oklch(0.8280204 0.0042636 121.5755);
954
1038
  --radius: 0.5rem;
955
1039
  --radius-button: 0.5rem;
956
- --radius-field: 0.25rem;
1040
+ --radius-field: var(--radius);
957
1041
  --radius-step: 2px;
958
1042
  --button-outline-width: 2px;
959
1043
  --selection-title-weight: 500;
@@ -1015,7 +1099,13 @@
1015
1099
  --input: oklch(0.6543689 0.0037291 145.5328);
1016
1100
  --ring: oklch(0.6 0 0);
1017
1101
  --button-outline: var(--foreground);
1018
- --selection-checked-border: var(--border);
1102
+ --selection-border: oklch(0 0 0 / 0);
1103
+ --selection-checked-border: var(--selection-border);
1104
+ --selection-divider: var(--border);
1105
+ --selection-checked-divider: var(--selection-divider);
1106
+ --selection-disabled-background: var(--card);
1107
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
1108
+ --selection-disabled-foreground: var(--muted-foreground);
1019
1109
  --sidebar: oklch(0.1749487 0.003804 164.5613);
1020
1110
  --sidebar-foreground: oklch(0.9822955 0.0142785 213.0969);
1021
1111
  --sidebar-accent: oklch(0.2661671 0.0034366 164.8011);
@@ -1043,7 +1133,7 @@
1043
1133
  --sh-comment: oklch(0.8280204 0.0042636 121.5755);
1044
1134
  --radius: 0.75rem;
1045
1135
  --radius-button: 1.8125rem;
1046
- --radius-field: 0.25rem;
1136
+ --radius-field: var(--radius);
1047
1137
  --radius-step: 2px;
1048
1138
  --button-outline-width: 2px;
1049
1139
  --selection-title-weight: 500;
@@ -1105,7 +1195,13 @@
1105
1195
  --input: oklch(0.6543689 0.0037291 145.5328);
1106
1196
  --ring: oklch(0.6 0 0);
1107
1197
  --button-outline: var(--foreground);
1108
- --selection-checked-border: var(--border);
1198
+ --selection-border: oklch(0 0 0 / 0);
1199
+ --selection-checked-border: var(--selection-border);
1200
+ --selection-divider: var(--border);
1201
+ --selection-checked-divider: var(--selection-divider);
1202
+ --selection-disabled-background: var(--card);
1203
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
1204
+ --selection-disabled-foreground: var(--muted-foreground);
1109
1205
  --sidebar: oklch(0.1842633 0.0454734 244.0362);
1110
1206
  --sidebar-foreground: oklch(0.9801435 0.0172884 210.1893);
1111
1207
  --sidebar-accent: oklch(0.2250318 0.0601105 247.6754);
@@ -1133,7 +1229,7 @@
1133
1229
  --sh-comment: oklch(0.8280204 0.0042636 121.5755);
1134
1230
  --radius: 0.75rem;
1135
1231
  --radius-button: 1.8125rem;
1136
- --radius-field: 0.25rem;
1232
+ --radius-field: var(--radius);
1137
1233
  --radius-step: 2px;
1138
1234
  --button-outline-width: 2px;
1139
1235
  --selection-title-weight: 500;
@@ -1195,7 +1291,13 @@
1195
1291
  --input: oklch(0.6543689 0.0037291 145.5328);
1196
1292
  --ring: oklch(0.6 0 0);
1197
1293
  --button-outline: var(--foreground);
1198
- --selection-checked-border: var(--border);
1294
+ --selection-border: oklch(0 0 0 / 0);
1295
+ --selection-checked-border: var(--selection-border);
1296
+ --selection-divider: var(--border);
1297
+ --selection-checked-divider: var(--selection-divider);
1298
+ --selection-disabled-background: var(--card);
1299
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
1300
+ --selection-disabled-foreground: var(--muted-foreground);
1199
1301
  --sidebar: oklch(0.176932 0.0026206 247.9754);
1200
1302
  --sidebar-foreground: oklch(0.9817745 0.0118616 223.5201);
1201
1303
  --sidebar-accent: oklch(0.2675764 0.0014668 197.0689);
@@ -1223,7 +1325,7 @@
1223
1325
  --sh-comment: oklch(0.8280204 0.0042636 121.5755);
1224
1326
  --radius: 0.375rem;
1225
1327
  --radius-button: 0.375rem;
1226
- --radius-field: 0.25rem;
1328
+ --radius-field: var(--radius);
1227
1329
  --radius-step: 2px;
1228
1330
  --button-outline-width: 2px;
1229
1331
  --selection-title-weight: 500;
@@ -1285,7 +1387,13 @@
1285
1387
  --input: oklch(0.6543689 0.0037291 145.5328);
1286
1388
  --ring: oklch(0.6 0 0);
1287
1389
  --button-outline: var(--foreground);
1288
- --selection-checked-border: var(--border);
1390
+ --selection-border: oklch(0 0 0 / 0);
1391
+ --selection-checked-border: var(--selection-border);
1392
+ --selection-divider: var(--border);
1393
+ --selection-checked-divider: var(--selection-divider);
1394
+ --selection-disabled-background: var(--card);
1395
+ --selection-disabled-hatch: oklch(0 0 0 / 0);
1396
+ --selection-disabled-foreground: var(--muted-foreground);
1289
1397
  --sidebar: oklch(0.1860912 0.0074341 164.0507906);
1290
1398
  --sidebar-foreground: oklch(0.9126739 0.0051473 145.5332168);
1291
1399
  --sidebar-accent: oklch(0.2386117 0.0070183 164.349003);
@@ -1313,7 +1421,7 @@
1313
1421
  --sh-comment: oklch(0.8280204 0.0042636 121.5755);
1314
1422
  --radius: 0.375rem;
1315
1423
  --radius-button: 1.8125rem;
1316
- --radius-field: 0.25rem;
1424
+ --radius-field: var(--radius);
1317
1425
  --radius-step: 2px;
1318
1426
  --button-outline-width: 2px;
1319
1427
  --selection-title-weight: 500;