@acronis-platform/ui-react 0.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -0
  3. package/dist/components/ui/breadcrumb/breadcrumb.js +116 -0
  4. package/dist/components/ui/breadcrumb/breadcrumb.js.map +1 -0
  5. package/dist/components/ui/button/button.js +50 -0
  6. package/dist/components/ui/button/button.js.map +1 -0
  7. package/dist/components/ui/button-dropdown/button-dropdown.js +52 -0
  8. package/dist/components/ui/button-dropdown/button-dropdown.js.map +1 -0
  9. package/dist/components/ui/button-icon/button-icon.js +35 -0
  10. package/dist/components/ui/button-icon/button-icon.js.map +1 -0
  11. package/dist/components/ui/checkbox/checkbox.js +68 -0
  12. package/dist/components/ui/checkbox/checkbox.js.map +1 -0
  13. package/dist/components/ui/input/input.js +22 -0
  14. package/dist/components/ui/input/input.js.map +1 -0
  15. package/dist/components/ui/input-text-area/input-text-area.js +21 -0
  16. package/dist/components/ui/input-text-area/input-text-area.js.map +1 -0
  17. package/dist/components/ui/radio/radio.js +44 -0
  18. package/dist/components/ui/radio/radio.js.map +1 -0
  19. package/dist/components/ui/search/search.js +93 -0
  20. package/dist/components/ui/search/search.js.map +1 -0
  21. package/dist/components/ui/select/select.js +105 -0
  22. package/dist/components/ui/select/select.js.map +1 -0
  23. package/dist/components/ui/sidebar-primary/sidebar-primary.js +242 -0
  24. package/dist/components/ui/sidebar-primary/sidebar-primary.js.map +1 -0
  25. package/dist/components/ui/sidebar-secondary/sidebar-secondary.js +372 -0
  26. package/dist/components/ui/sidebar-secondary/sidebar-secondary.js.map +1 -0
  27. package/dist/components/ui/switch/switch.js +41 -0
  28. package/dist/components/ui/switch/switch.js.map +1 -0
  29. package/dist/components/ui/tag/tag.js +47 -0
  30. package/dist/components/ui/tag/tag.js.map +1 -0
  31. package/dist/components/ui/tooltip/tooltip.js +49 -0
  32. package/dist/components/ui/tooltip/tooltip.js.map +1 -0
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.js +79 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/lib/utils.js +9 -0
  37. package/dist/lib/utils.js.map +1 -0
  38. package/dist/node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.js +36 -0
  39. package/dist/node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.js.map +1 -0
  40. package/dist/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js +17 -0
  41. package/dist/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js.map +1 -0
  42. package/dist/node_modules/.pnpm/tailwind-merge@3.6.0/node_modules/tailwind-merge/dist/bundle-mjs.js +2996 -0
  43. package/dist/node_modules/.pnpm/tailwind-merge@3.6.0/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  44. package/dist/react.d.ts +2 -0
  45. package/dist/react.js +79 -0
  46. package/dist/react.js.map +1 -0
  47. package/dist/src/components/ui/breadcrumb/breadcrumb.d.ts +30 -0
  48. package/dist/src/components/ui/breadcrumb/index.d.ts +1 -0
  49. package/dist/src/components/ui/button/button.d.ts +16 -0
  50. package/dist/src/components/ui/button/index.d.ts +1 -0
  51. package/dist/src/components/ui/button-dropdown/button-dropdown.d.ts +29 -0
  52. package/dist/src/components/ui/button-dropdown/index.d.ts +1 -0
  53. package/dist/src/components/ui/button-icon/button-icon.d.ts +20 -0
  54. package/dist/src/components/ui/button-icon/index.d.ts +1 -0
  55. package/dist/src/components/ui/checkbox/checkbox.d.ts +10 -0
  56. package/dist/src/components/ui/checkbox/index.d.ts +1 -0
  57. package/dist/src/components/ui/input/index.d.ts +1 -0
  58. package/dist/src/components/ui/input/input.d.ts +4 -0
  59. package/dist/src/components/ui/input-text-area/index.d.ts +1 -0
  60. package/dist/src/components/ui/input-text-area/input-text-area.d.ts +4 -0
  61. package/dist/src/components/ui/radio/index.d.ts +1 -0
  62. package/dist/src/components/ui/radio/radio.d.ts +8 -0
  63. package/dist/src/components/ui/search/index.d.ts +1 -0
  64. package/dist/src/components/ui/search/search.d.ts +7 -0
  65. package/dist/src/components/ui/select/index.d.ts +1 -0
  66. package/dist/src/components/ui/select/select.d.ts +14 -0
  67. package/dist/src/components/ui/sidebar-primary/index.d.ts +1 -0
  68. package/dist/src/components/ui/sidebar-primary/sidebar-primary.d.ts +54 -0
  69. package/dist/src/components/ui/sidebar-secondary/index.d.ts +1 -0
  70. package/dist/src/components/ui/sidebar-secondary/sidebar-secondary.d.ts +85 -0
  71. package/dist/src/components/ui/switch/index.d.ts +1 -0
  72. package/dist/src/components/ui/switch/switch.d.ts +8 -0
  73. package/dist/src/components/ui/tag/index.d.ts +1 -0
  74. package/dist/src/components/ui/tag/tag.d.ts +12 -0
  75. package/dist/src/components/ui/tooltip/index.d.ts +1 -0
  76. package/dist/src/components/ui/tooltip/tooltip.d.ts +13 -0
  77. package/dist/src/index.d.ts +16 -0
  78. package/dist/src/lib/utils.d.ts +2 -0
  79. package/dist/src/react.d.ts +1 -0
  80. package/dist/styles.d.ts +1 -0
  81. package/dist/ui-react.css +1 -0
  82. package/package.json +119 -0
@@ -0,0 +1,44 @@
1
+ import { jsx as e } from "react/jsx-runtime";
2
+ import * as i from "react";
3
+ import { Radio as r } from "@base-ui/react/radio";
4
+ import { RadioGroup as b } from "@base-ui/react/radio-group";
5
+ import { cn as c } from "../../../lib/utils.js";
6
+ const l = i.forwardRef(({ className: o, ...d }, a) => /* @__PURE__ */ e(
7
+ b,
8
+ {
9
+ ref: a,
10
+ className: c("flex flex-col gap-2", o),
11
+ ...d
12
+ }
13
+ ));
14
+ l.displayName = "RadioGroup";
15
+ const t = i.forwardRef(({ className: o, ...d }, a) => /* @__PURE__ */ e(
16
+ r.Root,
17
+ {
18
+ ref: a,
19
+ className: c(
20
+ // geometry + focus ring
21
+ "inline-flex size-[var(--ui-radio-global-box-size)] shrink-0 cursor-pointer items-center justify-center rounded-full border outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-[var(--ui-focus-primary)]",
22
+ // unchecked (base): idle / hover / active
23
+ "bg-[var(--ui-radio-unchecked-box-color-idle)] border-[var(--ui-radio-unchecked-box-border-color-idle)]",
24
+ "not-data-[disabled]:hover:bg-[var(--ui-radio-unchecked-box-color-hover)] not-data-[disabled]:hover:border-[var(--ui-radio-unchecked-box-border-color-hover)]",
25
+ "not-data-[disabled]:active:bg-[var(--ui-radio-unchecked-box-color-active)] not-data-[disabled]:active:border-[var(--ui-radio-unchecked-box-border-color-active)]",
26
+ // checked: idle / hover / active
27
+ "data-[checked]:not-data-[disabled]:bg-[var(--ui-radio-checked-box-color-idle)] data-[checked]:not-data-[disabled]:border-[var(--ui-radio-checked-box-border-color-idle)]",
28
+ "data-[checked]:not-data-[disabled]:hover:bg-[var(--ui-radio-checked-box-color-hover)] data-[checked]:not-data-[disabled]:hover:border-[var(--ui-radio-checked-box-border-color-hover)]",
29
+ "data-[checked]:not-data-[disabled]:active:bg-[var(--ui-radio-checked-box-color-active)] data-[checked]:not-data-[disabled]:active:border-[var(--ui-radio-checked-box-border-color-active)]",
30
+ // disabled (unchecked base + checked override)
31
+ "data-[disabled]:cursor-not-allowed data-[disabled]:bg-[var(--ui-radio-unchecked-box-color-disabled)] data-[disabled]:border-[var(--ui-radio-unchecked-box-border-color-disabled)]",
32
+ "data-[disabled]:data-[checked]:bg-[var(--ui-radio-checked-box-color-disabled)] data-[disabled]:data-[checked]:border-[var(--ui-radio-checked-box-border-color-disabled)]",
33
+ o
34
+ ),
35
+ ...d,
36
+ children: /* @__PURE__ */ e(r.Indicator, { className: "size-2 rounded-full bg-[var(--ui-radio-checked-icon-color-idle)] data-[disabled]:bg-[var(--ui-radio-checked-icon-color-disabled)]" })
37
+ }
38
+ ));
39
+ t.displayName = "Radio";
40
+ export {
41
+ t as Radio,
42
+ l as RadioGroup
43
+ };
44
+ //# sourceMappingURL=radio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radio.js","sources":["../../../../src/components/ui/radio/radio.tsx"],"sourcesContent":["import * as React from 'react';\nimport { Radio as RadioPrimitive } from '@base-ui/react/radio';\nimport { RadioGroup as RadioGroupPrimitive } from '@base-ui/react/radio-group';\n\nimport { cn } from '@/lib/utils';\n\n// Radio group + item, wrapping Base UI's RadioGroup / Radio primitives. Radios\n// are mutually exclusive, so the group owns the selected value; each Radio takes\n// a `value`. Colors and geometry come from the dedicated next-gen `--ui-radio-*`\n// token tier from @acronis-platform/tokens-pd (which mirrors `--ui-checkbox-*`):\n// the circle has two logical states — `unchecked` (the base) and `checked` —\n// each with its own per-interaction (idle / hover / active / disabled) fill\n// (`*-box-color-*`) and border (`*-box-border-color-*`) tokens. `unchecked` is\n// the base layer (lowest specificity); `data-[checked]` overrides it, and\n// `data-[disabled]:data-[checked]` overrides that in turn. The inner dot fill\n// uses `--ui-radio-checked-icon-color-*`. Box geometry (16px size) comes from\n// `--ui-radio-global-box-size`; the focus ring uses `--ui-focus-primary`. Each\n// state is wired to its own token, and the checked overrides are scoped with\n// `not-data-[disabled]` so the disabled tokens win.\n\nexport type RadioGroupProps = React.ComponentPropsWithoutRef<\n typeof RadioGroupPrimitive\n>;\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive>,\n RadioGroupProps\n>(({ className, ...props }, ref) => (\n <RadioGroupPrimitive\n ref={ref}\n className={cn('flex flex-col gap-2', className)}\n {...props}\n />\n));\nRadioGroup.displayName = 'RadioGroup';\n\nexport type RadioProps = React.ComponentPropsWithoutRef<\n typeof RadioPrimitive.Root\n>;\n\nconst Radio = React.forwardRef<\n React.ElementRef<typeof RadioPrimitive.Root>,\n RadioProps\n>(({ className, ...props }, ref) => (\n <RadioPrimitive.Root\n ref={ref}\n className={cn(\n // geometry + focus ring\n 'inline-flex size-[var(--ui-radio-global-box-size)] shrink-0 cursor-pointer items-center justify-center rounded-full border outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-[var(--ui-focus-primary)]',\n // unchecked (base): idle / hover / active\n 'bg-[var(--ui-radio-unchecked-box-color-idle)] border-[var(--ui-radio-unchecked-box-border-color-idle)]',\n 'not-data-[disabled]:hover:bg-[var(--ui-radio-unchecked-box-color-hover)] not-data-[disabled]:hover:border-[var(--ui-radio-unchecked-box-border-color-hover)]',\n 'not-data-[disabled]:active:bg-[var(--ui-radio-unchecked-box-color-active)] not-data-[disabled]:active:border-[var(--ui-radio-unchecked-box-border-color-active)]',\n // checked: idle / hover / active\n 'data-[checked]:not-data-[disabled]:bg-[var(--ui-radio-checked-box-color-idle)] data-[checked]:not-data-[disabled]:border-[var(--ui-radio-checked-box-border-color-idle)]',\n 'data-[checked]:not-data-[disabled]:hover:bg-[var(--ui-radio-checked-box-color-hover)] data-[checked]:not-data-[disabled]:hover:border-[var(--ui-radio-checked-box-border-color-hover)]',\n 'data-[checked]:not-data-[disabled]:active:bg-[var(--ui-radio-checked-box-color-active)] data-[checked]:not-data-[disabled]:active:border-[var(--ui-radio-checked-box-border-color-active)]',\n // disabled (unchecked base + checked override)\n 'data-[disabled]:cursor-not-allowed data-[disabled]:bg-[var(--ui-radio-unchecked-box-color-disabled)] data-[disabled]:border-[var(--ui-radio-unchecked-box-border-color-disabled)]',\n 'data-[disabled]:data-[checked]:bg-[var(--ui-radio-checked-box-color-disabled)] data-[disabled]:data-[checked]:border-[var(--ui-radio-checked-box-border-color-disabled)]',\n className\n )}\n {...props}\n >\n <RadioPrimitive.Indicator className=\"size-2 rounded-full bg-[var(--ui-radio-checked-icon-color-idle)] data-[disabled]:bg-[var(--ui-radio-checked-icon-color-disabled)]\" />\n </RadioPrimitive.Root>\n));\nRadio.displayName = 'Radio';\n\nexport { RadioGroup, Radio };\n"],"names":["RadioGroup","React","className","props","ref","jsx","RadioGroupPrimitive","cn","Radio","RadioPrimitive"],"mappings":";;;;;AAwBA,MAAMA,IAAaC,EAAM,WAGvB,CAAC,EAAE,WAAAC,GAAW,GAAGC,EAAA,GAASC,MAC1B,gBAAAC;AAAA,EAACC;AAAAA,EAAA;AAAA,IACC,KAAAF;AAAA,IACA,WAAWG,EAAG,uBAAuBL,CAAS;AAAA,IAC7C,GAAGC;AAAA,EAAA;AACN,CACD;AACDH,EAAW,cAAc;AAMzB,MAAMQ,IAAQP,EAAM,WAGlB,CAAC,EAAE,WAAAC,GAAW,GAAGC,EAAA,GAASC,MAC1B,gBAAAC;AAAA,EAACI,EAAe;AAAA,EAAf;AAAA,IACC,KAAAL;AAAA,IACA,WAAWG;AAAA;AAAA,MAET;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACAL;AAAA,IAAA;AAAA,IAED,GAAGC;AAAA,IAEJ,UAAA,gBAAAE,EAACI,EAAe,WAAf,EAAyB,WAAU,oIAAA,CAAoI;AAAA,EAAA;AAC1K,CACD;AACDD,EAAM,cAAc;"}
@@ -0,0 +1,93 @@
1
+ import { jsxs as w, jsx as o } from "react/jsx-runtime";
2
+ import * as t from "react";
3
+ import { MagnifierIcon as S, TimesIcon as k } from "@acronis-platform/icons-react/stroke-mono";
4
+ import { cn as N } from "../../../lib/utils.js";
5
+ const j = t.forwardRef(
6
+ ({
7
+ className: b,
8
+ type: v = "search",
9
+ disabled: s,
10
+ onClear: n,
11
+ onChange: c,
12
+ value: r,
13
+ defaultValue: u,
14
+ ...f
15
+ }, i) => {
16
+ const d = t.useRef(null), [x, l] = t.useState(
17
+ () => String(r ?? u ?? "").length > 0
18
+ );
19
+ t.useEffect(() => {
20
+ r !== void 0 && l(String(r).length > 0);
21
+ }, [r]);
22
+ const g = t.useCallback(
23
+ (e) => {
24
+ d.current = e, typeof i == "function" ? i(e) : i && (i.current = e);
25
+ },
26
+ [i]
27
+ ), m = (e) => {
28
+ l(e.target.value.length > 0), c == null || c(e);
29
+ }, y = () => {
30
+ var h, p;
31
+ const e = d.current;
32
+ if (!e) return;
33
+ let a;
34
+ try {
35
+ a = (p = Object.getOwnPropertyDescriptor(
36
+ (h = globalThis.HTMLInputElement) == null ? void 0 : h.prototype,
37
+ "value"
38
+ )) == null ? void 0 : p.set;
39
+ } catch {
40
+ a = void 0;
41
+ }
42
+ a ? a.call(e, "") : e.value = "", e.dispatchEvent(new Event("input", { bubbles: !0 })), l(!1), e.focus(), n == null || n();
43
+ };
44
+ return /* @__PURE__ */ w(
45
+ "div",
46
+ {
47
+ "data-disabled": s || void 0,
48
+ className: N(
49
+ "group inline-flex h-[var(--ui-input-search-box-height)] w-full min-w-0 items-center gap-[var(--ui-input-search-box-gap)] rounded-[var(--ui-input-search-box-border-radius)] border bg-[var(--ui-input-search-box-color-idle)] border-[var(--ui-input-search-border-color-idle)] px-[var(--ui-input-search-box-padding-x)] text-sm leading-6 text-[var(--ui-input-search-value-color-idle)] transition-colors not-data-[disabled]:hover:bg-[var(--ui-input-search-box-color-hover)] not-data-[disabled]:hover:border-[var(--ui-input-search-border-color-hover)] focus-within:border-[var(--ui-input-search-border-color-hover)] focus-within:ring-[3px] focus-within:ring-[var(--ui-focus-primary)] data-[disabled]:cursor-not-allowed data-[disabled]:border-[var(--ui-input-search-border-color-disabled)] data-[disabled]:bg-[var(--ui-input-search-box-color-disabled)] data-[disabled]:text-[var(--ui-input-search-value-color-disabled)]",
50
+ b
51
+ ),
52
+ children: [
53
+ /* @__PURE__ */ o(
54
+ S,
55
+ {
56
+ size: 16,
57
+ className: "shrink-0 text-[var(--ui-input-search-icon-search-color-idle)] group-data-[disabled]:text-[var(--ui-input-search-icon-search-color-disabled)]"
58
+ }
59
+ ),
60
+ /* @__PURE__ */ o(
61
+ "input",
62
+ {
63
+ ref: g,
64
+ type: v,
65
+ disabled: s,
66
+ value: r,
67
+ defaultValue: u,
68
+ onChange: m,
69
+ "aria-label": "Search",
70
+ className: "h-full min-w-0 flex-1 border-0 bg-transparent p-0 text-inherit outline-none placeholder:text-[var(--ui-input-search-placeholder-color-idle)] disabled:cursor-not-allowed [&::-webkit-search-cancel-button]:appearance-none",
71
+ ...f
72
+ }
73
+ ),
74
+ x && !s && /* @__PURE__ */ o(
75
+ "button",
76
+ {
77
+ type: "button",
78
+ "aria-label": "Clear search",
79
+ onClick: y,
80
+ className: "inline-flex shrink-0 cursor-pointer items-center justify-center rounded-sm text-[var(--ui-input-search-clear-icon-color)] outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-focus-primary)] [&>svg]:size-4",
81
+ children: /* @__PURE__ */ o(k, { size: 16 })
82
+ }
83
+ )
84
+ ]
85
+ }
86
+ );
87
+ }
88
+ );
89
+ j.displayName = "Search";
90
+ export {
91
+ j as Search
92
+ };
93
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sources":["../../../../src/components/ui/search/search.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n MagnifierIcon,\n TimesIcon,\n} from '@acronis-platform/icons-react/stroke-mono';\n\nimport { cn } from '@/lib/utils';\n\n// A search field: a bordered box (the dedicated `--ui-input-search-*` token\n// tier) holding a leading magnifier, a borderless native input, and a trailing\n// clear button shown once there's a value. The box owns the visual state via\n// `focus-within` (the input-search tier has no focus/active border token, so the\n// focused border reuses `--ui-input-search-border-color-hover` plus a 3px\n// `--ui-focus-primary` ring) / hover / disabled; the magnifier uses\n// `--ui-input-search-icon-search-color-{idle,disabled}` (via the `group`) and the\n// clear button uses `--ui-input-search-clear-icon-color`.\n\nexport interface SearchProps extends React.ComponentPropsWithoutRef<'input'> {\n /** Called when the clear (×) button is pressed, after the value is cleared. */\n onClear?: () => void;\n}\n\nconst Search = React.forwardRef<HTMLInputElement, SearchProps>(\n (\n {\n className,\n type = 'search',\n disabled,\n onClear,\n onChange,\n value,\n defaultValue,\n ...props\n },\n forwardedRef\n ) => {\n const innerRef = React.useRef<HTMLInputElement>(null);\n const [hasValue, setHasValue] = React.useState(\n () => String(value ?? defaultValue ?? '').length > 0\n );\n\n // Keep the clear button in sync when the value is controlled externally.\n React.useEffect(() => {\n if (value !== undefined) setHasValue(String(value).length > 0);\n }, [value]);\n\n const setRefs = React.useCallback(\n (node: HTMLInputElement | null) => {\n innerRef.current = node;\n if (typeof forwardedRef === 'function') forwardedRef(node);\n else if (forwardedRef) forwardedRef.current = node;\n },\n [forwardedRef]\n );\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setHasValue(event.target.value.length > 0);\n onChange?.(event);\n };\n\n const handleClear = () => {\n const input = innerRef.current;\n if (!input) return;\n // Use the native value setter when available + dispatch a real input event\n // so React's onChange fires for both controlled and uncontrolled usage.\n let setter: ((this: HTMLInputElement, value: string) => void) | undefined;\n try {\n setter = Object.getOwnPropertyDescriptor(\n globalThis.HTMLInputElement?.prototype,\n 'value'\n )?.set;\n } catch {\n setter = undefined;\n }\n\n if (setter) setter.call(input, '');\n else input.value = '';\n\n input.dispatchEvent(new Event('input', { bubbles: true }));\n setHasValue(false);\n input.focus();\n onClear?.();\n };\n\n return (\n <div\n data-disabled={disabled || undefined}\n className={cn(\n 'group inline-flex h-[var(--ui-input-search-box-height)] w-full min-w-0 items-center gap-[var(--ui-input-search-box-gap)] rounded-[var(--ui-input-search-box-border-radius)] border bg-[var(--ui-input-search-box-color-idle)] border-[var(--ui-input-search-border-color-idle)] px-[var(--ui-input-search-box-padding-x)] text-sm leading-6 text-[var(--ui-input-search-value-color-idle)] transition-colors not-data-[disabled]:hover:bg-[var(--ui-input-search-box-color-hover)] not-data-[disabled]:hover:border-[var(--ui-input-search-border-color-hover)] focus-within:border-[var(--ui-input-search-border-color-hover)] focus-within:ring-[3px] focus-within:ring-[var(--ui-focus-primary)] data-[disabled]:cursor-not-allowed data-[disabled]:border-[var(--ui-input-search-border-color-disabled)] data-[disabled]:bg-[var(--ui-input-search-box-color-disabled)] data-[disabled]:text-[var(--ui-input-search-value-color-disabled)]',\n className\n )}\n >\n <MagnifierIcon\n size={16}\n className=\"shrink-0 text-[var(--ui-input-search-icon-search-color-idle)] group-data-[disabled]:text-[var(--ui-input-search-icon-search-color-disabled)]\"\n />\n <input\n ref={setRefs}\n type={type}\n disabled={disabled}\n value={value}\n defaultValue={defaultValue}\n onChange={handleChange}\n aria-label=\"Search\"\n className=\"h-full min-w-0 flex-1 border-0 bg-transparent p-0 text-inherit outline-none placeholder:text-[var(--ui-input-search-placeholder-color-idle)] disabled:cursor-not-allowed [&::-webkit-search-cancel-button]:appearance-none\"\n {...props}\n />\n {hasValue && !disabled && (\n <button\n type=\"button\"\n aria-label=\"Clear search\"\n onClick={handleClear}\n className=\"inline-flex shrink-0 cursor-pointer items-center justify-center rounded-sm text-[var(--ui-input-search-clear-icon-color)] outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-focus-primary)] [&>svg]:size-4\"\n >\n <TimesIcon size={16} />\n </button>\n )}\n </div>\n );\n }\n);\nSearch.displayName = 'Search';\n\nexport { Search };\n"],"names":["Search","React","className","type","disabled","onClear","onChange","value","defaultValue","props","forwardedRef","innerRef","hasValue","setHasValue","setRefs","node","handleChange","event","handleClear","input","setter","_b","_a","jsxs","cn","jsx","MagnifierIcon","TimesIcon"],"mappings":";;;;AAsBA,MAAMA,IAASC,EAAM;AAAA,EACnB,CACE;AAAA,IACE,WAAAC;AAAA,IACA,MAAAC,IAAO;AAAA,IACP,UAAAC;AAAA,IACA,SAAAC;AAAA,IACA,UAAAC;AAAA,IACA,OAAAC;AAAA,IACA,cAAAC;AAAA,IACA,GAAGC;AAAA,EAAA,GAELC,MACG;AACH,UAAMC,IAAWV,EAAM,OAAyB,IAAI,GAC9C,CAACW,GAAUC,CAAW,IAAIZ,EAAM;AAAA,MACpC,MAAM,OAAOM,KAASC,KAAgB,EAAE,EAAE,SAAS;AAAA,IAAA;AAIrD,IAAAP,EAAM,UAAU,MAAM;AACpB,MAAIM,MAAU,UAAWM,EAAY,OAAON,CAAK,EAAE,SAAS,CAAC;AAAA,IAC/D,GAAG,CAACA,CAAK,CAAC;AAEV,UAAMO,IAAUb,EAAM;AAAA,MACpB,CAACc,MAAkC;AACjC,QAAAJ,EAAS,UAAUI,GACf,OAAOL,KAAiB,aAAYA,EAAaK,CAAI,IAChDL,QAA2B,UAAUK;AAAA,MAChD;AAAA,MACA,CAACL,CAAY;AAAA,IAAA,GAGTM,IAAe,CAACC,MAA+C;AACnE,MAAAJ,EAAYI,EAAM,OAAO,MAAM,SAAS,CAAC,GACzCX,KAAA,QAAAA,EAAWW;AAAA,IACb,GAEMC,IAAc,MAAM;;AACxB,YAAMC,IAAQR,EAAS;AACvB,UAAI,CAACQ,EAAO;AAGZ,UAAIC;AACJ,UAAI;AACF,QAAAA,KAASC,IAAA,OAAO;AAAA,WACdC,IAAA,WAAW,qBAAX,gBAAAA,EAA6B;AAAA,UAC7B;AAAA,QAAA,MAFO,gBAAAD,EAGN;AAAA,MACL,QAAQ;AACN,QAAAD,IAAS;AAAA,MACX;AAEA,MAAIA,IAAQA,EAAO,KAAKD,GAAO,EAAE,MACtB,QAAQ,IAEnBA,EAAM,cAAc,IAAI,MAAM,SAAS,EAAE,SAAS,GAAA,CAAM,CAAC,GACzDN,EAAY,EAAK,GACjBM,EAAM,MAAA,GACNd,KAAA,QAAAA;AAAA,IACF;AAEA,WACE,gBAAAkB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,iBAAenB,KAAY;AAAA,QAC3B,WAAWoB;AAAA,UACT;AAAA,UACAtB;AAAA,QAAA;AAAA,QAGF,UAAA;AAAA,UAAA,gBAAAuB;AAAA,YAACC;AAAA,YAAA;AAAA,cACC,MAAM;AAAA,cACN,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,UAEZ,gBAAAD;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,KAAKX;AAAA,cACL,MAAAX;AAAA,cACA,UAAAC;AAAA,cACA,OAAAG;AAAA,cACA,cAAAC;AAAA,cACA,UAAUQ;AAAA,cACV,cAAW;AAAA,cACX,WAAU;AAAA,cACT,GAAGP;AAAA,YAAA;AAAA,UAAA;AAAA,UAELG,KAAY,CAACR,KACZ,gBAAAqB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAW;AAAA,cACX,SAASP;AAAA,cACT,WAAU;AAAA,cAEV,UAAA,gBAAAO,EAACE,GAAA,EAAU,MAAM,GAAA,CAAI;AAAA,YAAA;AAAA,UAAA;AAAA,QACvB;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AACA3B,EAAO,cAAc;"}
@@ -0,0 +1,105 @@
1
+ import { jsx as r, jsxs as n } from "react/jsx-runtime";
2
+ import * as d from "react";
3
+ import { Select as e } from "@base-ui/react/select";
4
+ import { ChevronDownIcon as u, CheckIcon as p } from "@acronis-platform/icons-react/stroke-mono";
5
+ import { cn as l } from "../../../lib/utils.js";
6
+ const y = e.Root, I = e.Group, f = d.forwardRef(({ className: t, ...a }, o) => /* @__PURE__ */ r(
7
+ e.Value,
8
+ {
9
+ ref: o,
10
+ className: l(
11
+ "min-w-0 flex-1 truncate text-left text-[var(--ui-form-text-value)] data-[placeholder]:text-[var(--ui-form-text-placeholder)]",
12
+ // Disabled wins over the value/placeholder color regardless of variant order.
13
+ "group-data-[disabled]:!text-[var(--ui-form-text-disabled)]",
14
+ t
15
+ ),
16
+ ...a
17
+ }
18
+ ));
19
+ f.displayName = "SelectValue";
20
+ const b = d.forwardRef(({ className: t, children: a, ...o }, i) => /* @__PURE__ */ n(
21
+ e.Trigger,
22
+ {
23
+ ref: i,
24
+ className: l(
25
+ "group flex h-8 w-full min-w-0 items-center gap-2 rounded border bg-[var(--ui-form-background-idle)] border-[var(--ui-form-border-idle)] px-3 text-sm leading-6 text-[var(--ui-form-text-value)] outline-none transition-colors",
26
+ "not-data-[disabled]:hover:border-[var(--ui-form-border-hover)]",
27
+ "focus-visible:border-[var(--ui-form-border-active)] focus-visible:ring-[3px] focus-visible:ring-[var(--ui-focus-primary)]",
28
+ "data-[popup-open]:border-[var(--ui-form-border-active)] data-[popup-open]:ring-[3px] data-[popup-open]:ring-[var(--ui-focus-primary)]",
29
+ "data-[disabled]:cursor-not-allowed data-[disabled]:border-[var(--ui-form-border-disabled)] data-[disabled]:bg-[var(--ui-form-background-disabled)] data-[disabled]:text-[var(--ui-form-text-disabled)]",
30
+ t
31
+ ),
32
+ ...o,
33
+ children: [
34
+ a,
35
+ /* @__PURE__ */ r(e.Icon, { className: "flex shrink-0 items-center text-[var(--ui-form-icon-idle)] group-data-[disabled]:text-[var(--ui-form-icon-disabled)]", children: /* @__PURE__ */ r(
36
+ u,
37
+ {
38
+ size: 16,
39
+ className: "transition-transform group-data-[popup-open]:rotate-180"
40
+ }
41
+ ) })
42
+ ]
43
+ }
44
+ ));
45
+ b.displayName = "SelectTrigger";
46
+ const x = d.forwardRef(({ className: t, children: a, sideOffset: o = 4, align: i = "start", side: s = "bottom", ...c }, m) => /* @__PURE__ */ r(e.Portal, { children: /* @__PURE__ */ r(
47
+ e.Positioner,
48
+ {
49
+ sideOffset: o,
50
+ align: i,
51
+ side: s,
52
+ alignItemWithTrigger: !1,
53
+ className: "z-50 outline-none",
54
+ children: /* @__PURE__ */ r(
55
+ e.Popup,
56
+ {
57
+ ref: m,
58
+ className: l(
59
+ "max-h-[var(--available-height)] min-w-[var(--anchor-width)] overflow-y-auto rounded border border-border bg-background py-1 text-sm text-foreground shadow-md outline-none",
60
+ t
61
+ ),
62
+ ...c,
63
+ children: a
64
+ }
65
+ )
66
+ }
67
+ ) }));
68
+ x.displayName = "SelectContent";
69
+ const g = d.forwardRef(({ className: t, children: a, ...o }, i) => /* @__PURE__ */ n(
70
+ e.Item,
71
+ {
72
+ ref: i,
73
+ className: l(
74
+ "relative flex cursor-default items-center gap-2 py-1.5 pr-8 pl-3 leading-6 outline-none select-none",
75
+ "data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground",
76
+ "data-[disabled]:pointer-events-none data-[disabled]:text-[var(--ui-form-text-disabled)]",
77
+ t
78
+ ),
79
+ ...o,
80
+ children: [
81
+ /* @__PURE__ */ r(e.ItemText, { className: "min-w-0 flex-1 truncate", children: a }),
82
+ /* @__PURE__ */ r(e.ItemIndicator, { className: "absolute right-2 flex items-center text-[var(--ui-form-icon-idle)]", children: /* @__PURE__ */ r(p, { size: 16 }) })
83
+ ]
84
+ }
85
+ ));
86
+ g.displayName = "SelectItem";
87
+ const v = d.forwardRef(({ className: t, ...a }, o) => /* @__PURE__ */ r(
88
+ e.GroupLabel,
89
+ {
90
+ ref: o,
91
+ className: l("px-3 py-1.5 text-xs text-muted-foreground", t),
92
+ ...a
93
+ }
94
+ ));
95
+ v.displayName = "SelectGroupLabel";
96
+ export {
97
+ y as Select,
98
+ x as SelectContent,
99
+ I as SelectGroup,
100
+ v as SelectGroupLabel,
101
+ g as SelectItem,
102
+ b as SelectTrigger,
103
+ f as SelectValue
104
+ };
105
+ //# sourceMappingURL=select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.js","sources":["../../../../src/components/ui/select/select.tsx"],"sourcesContent":["import * as React from 'react';\nimport { Select as SelectPrimitive } from '@base-ui/react/select';\nimport { CheckIcon, ChevronDownIcon } from '@acronis-platform/icons-react/stroke-mono';\n\nimport { cn } from '@/lib/utils';\n\n// STRANDED THEME: this component still binds to the legacy `--ui-form-*` token\n// tier, which is NOT shipped by @acronis-platform/tokens-pd. The Figma sync\n// (#308) added next-gen tiers for Radio (`--ui-radio-*`), Search\n// (`--ui-input-search-*`) and Input (`--ui-input-text-*`) but NOT for Select, so\n// there is nothing to rewire to yet — Select renders with unresolved colors until\n// a `--ui-select-*` tier ships. Re-theme it once those tokens land (tracked\n// alongside the token-drift guard, issue #297).\n//\n// A select: a Base UI `Select` themed with the shared `--ui-form-*` token tier\n// (the same tier Input/Search use). The trigger is the Figma \"Select\" box —\n// 32px tall, bordered, rounded — and wires each state to its own token:\n// idle / hover (`--ui-form-border-hover`) / open+focus (`--ui-form-border-active`\n// + a 3px `--ui-focus-primary` ring) / disabled. The chevron uses\n// `--ui-form-icon-idle` and rotates when the popup is open. The popup and items\n// aren't in the Figma spec, so they use the shared semantic surface vocabulary\n// (`bg-background`, `bg-accent`, `border-border`). Label, description, and error\n// message are composed by the consumer (a Field component is future work).\n\nconst Select = SelectPrimitive.Root;\n\nconst SelectGroup = SelectPrimitive.Group;\n\nconst SelectValue = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Value>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Value>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.Value\n ref={ref}\n className={cn(\n 'min-w-0 flex-1 truncate text-left text-[var(--ui-form-text-value)] data-[placeholder]:text-[var(--ui-form-text-placeholder)]',\n // Disabled wins over the value/placeholder color regardless of variant order.\n 'group-data-[disabled]:!text-[var(--ui-form-text-disabled)]',\n className\n )}\n {...props}\n />\n));\nSelectValue.displayName = 'SelectValue';\n\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(\n 'group flex h-8 w-full min-w-0 items-center gap-2 rounded border bg-[var(--ui-form-background-idle)] border-[var(--ui-form-border-idle)] px-3 text-sm leading-6 text-[var(--ui-form-text-value)] outline-none transition-colors',\n 'not-data-[disabled]:hover:border-[var(--ui-form-border-hover)]',\n 'focus-visible:border-[var(--ui-form-border-active)] focus-visible:ring-[3px] focus-visible:ring-[var(--ui-focus-primary)]',\n 'data-[popup-open]:border-[var(--ui-form-border-active)] data-[popup-open]:ring-[3px] data-[popup-open]:ring-[var(--ui-focus-primary)]',\n 'data-[disabled]:cursor-not-allowed data-[disabled]:border-[var(--ui-form-border-disabled)] data-[disabled]:bg-[var(--ui-form-background-disabled)] data-[disabled]:text-[var(--ui-form-text-disabled)]',\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon className=\"flex shrink-0 items-center text-[var(--ui-form-icon-idle)] group-data-[disabled]:text-[var(--ui-form-icon-disabled)]\">\n <ChevronDownIcon\n size={16}\n className=\"transition-transform group-data-[popup-open]:rotate-180\"\n />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n));\nSelectTrigger.displayName = 'SelectTrigger';\n\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Popup>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Popup> & {\n sideOffset?: number;\n align?: SelectPrimitive.Positioner.Props['align'];\n side?: SelectPrimitive.Positioner.Props['side'];\n }\n>(({ className, children, sideOffset = 4, align = 'start', side = 'bottom', ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Positioner\n sideOffset={sideOffset}\n align={align}\n side={side}\n alignItemWithTrigger={false}\n className=\"z-50 outline-none\"\n >\n <SelectPrimitive.Popup\n ref={ref}\n className={cn(\n 'max-h-[var(--available-height)] min-w-[var(--anchor-width)] overflow-y-auto rounded border border-border bg-background py-1 text-sm text-foreground shadow-md outline-none',\n className\n )}\n {...props}\n >\n {children}\n </SelectPrimitive.Popup>\n </SelectPrimitive.Positioner>\n </SelectPrimitive.Portal>\n));\nSelectContent.displayName = 'SelectContent';\n\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex cursor-default items-center gap-2 py-1.5 pr-8 pl-3 leading-6 outline-none select-none',\n 'data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground',\n 'data-[disabled]:pointer-events-none data-[disabled]:text-[var(--ui-form-text-disabled)]',\n className\n )}\n {...props}\n >\n <SelectPrimitive.ItemText className=\"min-w-0 flex-1 truncate\">\n {children}\n </SelectPrimitive.ItemText>\n <SelectPrimitive.ItemIndicator className=\"absolute right-2 flex items-center text-[var(--ui-form-icon-idle)]\">\n <CheckIcon size={16} />\n </SelectPrimitive.ItemIndicator>\n </SelectPrimitive.Item>\n));\nSelectItem.displayName = 'SelectItem';\n\nconst SelectGroupLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.GroupLabel>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.GroupLabel>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.GroupLabel\n ref={ref}\n className={cn('px-3 py-1.5 text-xs text-muted-foreground', className)}\n {...props}\n />\n));\nSelectGroupLabel.displayName = 'SelectGroupLabel';\n\nexport {\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n SelectGroup,\n SelectGroupLabel,\n};\n"],"names":["Select","SelectPrimitive","SelectGroup","SelectValue","React","className","props","ref","jsx","cn","SelectTrigger","children","jsxs","ChevronDownIcon","SelectContent","sideOffset","align","side","SelectItem","CheckIcon","SelectGroupLabel"],"mappings":";;;;;AAwBA,MAAMA,IAASC,EAAgB,MAEzBC,IAAcD,EAAgB,OAE9BE,IAAcC,EAAM,WAGxB,CAAC,EAAE,WAAAC,GAAW,GAAGC,EAAA,GAASC,MAC1B,gBAAAC;AAAA,EAACP,EAAgB;AAAA,EAAhB;AAAA,IACC,KAAAM;AAAA,IACA,WAAWE;AAAA,MACT;AAAA;AAAA,MAEA;AAAA,MACAJ;AAAA,IAAA;AAAA,IAED,GAAGC;AAAA,EAAA;AACN,CACD;AACDH,EAAY,cAAc;AAE1B,MAAMO,IAAgBN,EAAM,WAG1B,CAAC,EAAE,WAAAC,GAAW,UAAAM,GAAU,GAAGL,KAASC,MACpC,gBAAAK;AAAA,EAACX,EAAgB;AAAA,EAAhB;AAAA,IACC,KAAAM;AAAA,IACA,WAAWE;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACAJ;AAAA,IAAA;AAAA,IAED,GAAGC;AAAA,IAEH,UAAA;AAAA,MAAAK;AAAA,MACD,gBAAAH,EAACP,EAAgB,MAAhB,EAAqB,WAAU,wHAC9B,UAAA,gBAAAO;AAAA,QAACK;AAAA,QAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,QAAA;AAAA,MAAA,EACZ,CACF;AAAA,IAAA;AAAA,EAAA;AACF,CACD;AACDH,EAAc,cAAc;AAE5B,MAAMI,IAAgBV,EAAM,WAO1B,CAAC,EAAE,WAAAC,GAAW,UAAAM,GAAU,YAAAI,IAAa,GAAG,OAAAC,IAAQ,SAAS,MAAAC,IAAO,UAAU,GAAGX,EAAA,GAASC,MACtF,gBAAAC,EAACP,EAAgB,QAAhB,EACC,UAAA,gBAAAO;AAAA,EAACP,EAAgB;AAAA,EAAhB;AAAA,IACC,YAAAc;AAAA,IACA,OAAAC;AAAA,IACA,MAAAC;AAAA,IACA,sBAAsB;AAAA,IACtB,WAAU;AAAA,IAEV,UAAA,gBAAAT;AAAA,MAACP,EAAgB;AAAA,MAAhB;AAAA,QACC,KAAAM;AAAA,QACA,WAAWE;AAAA,UACT;AAAA,UACAJ;AAAA,QAAA;AAAA,QAED,GAAGC;AAAA,QAEH,UAAAK;AAAA,MAAA;AAAA,IAAA;AAAA,EACH;AACF,GACF,CACD;AACDG,EAAc,cAAc;AAE5B,MAAMI,IAAad,EAAM,WAGvB,CAAC,EAAE,WAAAC,GAAW,UAAAM,GAAU,GAAGL,KAASC,MACpC,gBAAAK;AAAA,EAACX,EAAgB;AAAA,EAAhB;AAAA,IACC,KAAAM;AAAA,IACA,WAAWE;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACAJ;AAAA,IAAA;AAAA,IAED,GAAGC;AAAA,IAEJ,UAAA;AAAA,MAAA,gBAAAE,EAACP,EAAgB,UAAhB,EAAyB,WAAU,2BACjC,UAAAU,GACH;AAAA,MACA,gBAAAH,EAACP,EAAgB,eAAhB,EAA8B,WAAU,sEACvC,UAAA,gBAAAO,EAACW,GAAA,EAAU,MAAM,GAAA,CAAI,EAAA,CACvB;AAAA,IAAA;AAAA,EAAA;AACF,CACD;AACDD,EAAW,cAAc;AAEzB,MAAME,IAAmBhB,EAAM,WAG7B,CAAC,EAAE,WAAAC,GAAW,GAAGC,EAAA,GAASC,MAC1B,gBAAAC;AAAA,EAACP,EAAgB;AAAA,EAAhB;AAAA,IACC,KAAAM;AAAA,IACA,WAAWE,EAAG,6CAA6CJ,CAAS;AAAA,IACnE,GAAGC;AAAA,EAAA;AACN,CACD;AACDc,EAAiB,cAAc;"}
@@ -0,0 +1,242 @@
1
+ import { jsx as i, jsxs as b, Fragment as N } from "react/jsx-runtime";
2
+ import * as t from "react";
3
+ import { mergeProps as y } from "@base-ui/react/merge-props";
4
+ import { useRender as g } from "@base-ui/react/use-render";
5
+ import { SquareArrowUpRightIcon as P } from "@acronis-platform/icons-react/stroke-mono";
6
+ import { cva as S } from "../../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.js";
7
+ import { cn as l } from "../../../lib/utils.js";
8
+ const x = t.createContext(null);
9
+ function v() {
10
+ return t.useContext(x) ?? {
11
+ expanded: !0,
12
+ toggleExpanded: () => {
13
+ }
14
+ };
15
+ }
16
+ function R(a, e, r) {
17
+ const [o, d] = t.useState(e), n = a !== void 0, m = n ? a : o, c = t.useCallback(
18
+ (s) => {
19
+ n || d(s), r == null || r(s);
20
+ },
21
+ [n, r]
22
+ );
23
+ return [m, c];
24
+ }
25
+ const _ = t.forwardRef(
26
+ ({
27
+ className: a,
28
+ expanded: e,
29
+ defaultExpanded: r = !0,
30
+ onExpandedChange: o,
31
+ "aria-label": d = "Primary",
32
+ render: n,
33
+ children: m,
34
+ ...c
35
+ }, s) => {
36
+ const [u, p] = R(
37
+ e,
38
+ r,
39
+ o
40
+ ), h = t.useMemo(
41
+ () => ({ expanded: u, toggleExpanded: () => p(!u) }),
42
+ [u, p]
43
+ ), w = g({
44
+ render: n,
45
+ ref: s,
46
+ defaultTagName: "nav",
47
+ props: y(
48
+ {
49
+ "aria-label": d,
50
+ "data-state": u ? "expanded" : "collapsed",
51
+ className: l(
52
+ "group/sidebar flex h-full flex-col bg-[var(--ui-sidebar-primary-global-container-color)] w-[var(--ui-sidebar-primary-collapsed-container-width)] data-[state=expanded]:w-[var(--ui-sidebar-primary-expanded-container-width)] transition-[width]",
53
+ a
54
+ ),
55
+ children: m
56
+ },
57
+ c
58
+ )
59
+ });
60
+ return /* @__PURE__ */ i(x.Provider, { value: h, children: w });
61
+ }
62
+ );
63
+ _.displayName = "SidebarPrimary";
64
+ const M = t.forwardRef(({ className: a, ...e }, r) => (
65
+ // Hosts a consumer-provided logo (R7 — no Logo part is built). Padding and the
66
+ // logo height switch on expanded/collapsed; `[&_*]:h-…` sizes whatever the
67
+ // consumer slots in. The logo color token tints any `currentColor` mark.
68
+ /* @__PURE__ */ i(
69
+ "div",
70
+ {
71
+ ref: r,
72
+ className: l(
73
+ "flex items-center shrink-0 text-[var(--ui-sidebar-primary-global-logo-color)]",
74
+ "px-[var(--ui-sidebar-primary-collapsed-container-header-padding-x)] py-[var(--ui-sidebar-primary-collapsed-container-header-padding-y)]",
75
+ "[&_:where(img,svg)]:h-[var(--ui-sidebar-primary-collapsed-logo-height)] [&_:where(img,svg)]:w-auto",
76
+ "group-data-[state=expanded]/sidebar:px-[var(--ui-sidebar-primary-expanded-container-header-padding-x)] group-data-[state=expanded]/sidebar:py-[var(--ui-sidebar-primary-expanded-container-header-padding-y)]",
77
+ "group-data-[state=expanded]/sidebar:[&_:where(img,svg)]:h-[var(--ui-sidebar-primary-expanded-logo-height)]",
78
+ a
79
+ ),
80
+ ...e
81
+ }
82
+ )
83
+ ));
84
+ M.displayName = "SidebarPrimaryHeader";
85
+ const E = t.forwardRef(({ className: a, ...e }, r) => /* @__PURE__ */ i(
86
+ "div",
87
+ {
88
+ ref: r,
89
+ className: l(
90
+ "flex flex-1 flex-col overflow-y-auto gap-[var(--ui-sidebar-primary-global-section-list-gap)]",
91
+ a
92
+ ),
93
+ ...e
94
+ }
95
+ ));
96
+ E.displayName = "SidebarPrimaryContent";
97
+ const k = t.forwardRef(({ className: a, ...e }, r) => /* @__PURE__ */ i(
98
+ "div",
99
+ {
100
+ ref: r,
101
+ className: l(
102
+ "flex flex-col shrink-0 gap-[var(--ui-sidebar-primary-global-footer-list-gap)]",
103
+ "border-t border-[var(--ui-sidebar-primary-global-container-footer-border-color)] [border-top-width:var(--ui-sidebar-primary-global-container-footer-border-width)]",
104
+ "py-[var(--ui-sidebar-primary-section-container-padding-y)]",
105
+ a
106
+ ),
107
+ ...e
108
+ }
109
+ ));
110
+ k.displayName = "SidebarPrimaryFooter";
111
+ const I = t.forwardRef(({ className: a, ...e }, r) => (
112
+ // `firstSection` in Figma only toggles the top divider — derive it from DOM
113
+ // position (`:not(:first-child)`) instead of a prop.
114
+ /* @__PURE__ */ i(
115
+ "div",
116
+ {
117
+ ref: r,
118
+ className: l(
119
+ "flex flex-col py-[var(--ui-sidebar-primary-section-container-padding-y)]",
120
+ "[&:not(:first-child)]:border-t [&:not(:first-child)]:border-[var(--ui-sidebar-primary-section-container-border-color)] [&:not(:first-child)]:[border-top-width:var(--ui-sidebar-primary-section-container-border-width)]",
121
+ a
122
+ ),
123
+ ...e
124
+ }
125
+ )
126
+ ));
127
+ I.displayName = "SidebarPrimarySection";
128
+ const z = t.forwardRef(({ className: a, ...e }, r) => /* @__PURE__ */ i(
129
+ "ul",
130
+ {
131
+ ref: r,
132
+ className: l(
133
+ "flex flex-col gap-[var(--ui-sidebar-primary-section-menu-item-list-gap)]",
134
+ a
135
+ ),
136
+ ...e
137
+ }
138
+ ));
139
+ z.displayName = "SidebarPrimaryMenu";
140
+ const f = S(
141
+ "group/menu-item flex w-full items-center gap-[var(--ui-sidebar-primary-menu-item-global-container-gap)] h-[var(--ui-sidebar-primary-menu-item-global-container-height)] px-[var(--ui-sidebar-primary-menu-item-global-container-padding-x)] py-[var(--ui-sidebar-primary-menu-item-global-container-padding-y)] no-underline ui-sidebar-primary-menu-item-global-label-text-style transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-focus-brand)] focus-visible:ring-inset [&_svg]:shrink-0 [&_svg]:size-[var(--ui-sidebar-primary-menu-item-global-icon-size)]",
142
+ {
143
+ variants: {
144
+ variant: {
145
+ unselected: "bg-[var(--ui-sidebar-primary-menu-item-unselected-container-color-idle)] text-[var(--ui-sidebar-primary-menu-item-unselected-label-color-idle)] [&_svg]:text-[var(--ui-sidebar-primary-menu-item-unselected-icon-color-idle)] hover:bg-[var(--ui-sidebar-primary-menu-item-unselected-container-color-hover)] hover:text-[var(--ui-sidebar-primary-menu-item-unselected-label-color-hover)] hover:[&_svg]:text-[var(--ui-sidebar-primary-menu-item-unselected-icon-color-hover)] active:bg-[var(--ui-sidebar-primary-menu-item-unselected-container-color-active)] active:text-[var(--ui-sidebar-primary-menu-item-unselected-label-color-active)] active:[&_svg]:text-[var(--ui-sidebar-primary-menu-item-unselected-icon-color-active)]",
146
+ selected: "bg-[var(--ui-sidebar-primary-menu-item-selected-container-color-idle)] text-[var(--ui-sidebar-primary-menu-item-selected-label-color-idle)] [&_svg]:text-[var(--ui-sidebar-primary-menu-item-selected-icon-color-idle)] hover:bg-[var(--ui-sidebar-primary-menu-item-selected-container-color-hover)] hover:text-[var(--ui-sidebar-primary-menu-item-selected-label-color-hover)] hover:[&_svg]:text-[var(--ui-sidebar-primary-menu-item-selected-icon-color-hover)] active:bg-[var(--ui-sidebar-primary-menu-item-selected-container-color-active)] active:text-[var(--ui-sidebar-primary-menu-item-selected-label-color-active)] active:[&_svg]:text-[var(--ui-sidebar-primary-menu-item-selected-icon-color-active)]"
147
+ }
148
+ },
149
+ defaultVariants: {
150
+ variant: "unselected"
151
+ }
152
+ }
153
+ ), T = t.forwardRef(({ className: a, selected: e = !1, icon: r, render: o, children: d, ...n }, m) => {
154
+ const { expanded: c } = v(), s = g({
155
+ render: o,
156
+ ref: m,
157
+ defaultTagName: "a",
158
+ props: y(
159
+ {
160
+ className: l(
161
+ f({
162
+ variant: e ? "selected" : "unselected"
163
+ }),
164
+ a
165
+ ),
166
+ "aria-current": e ? "page" : void 0,
167
+ children: /* @__PURE__ */ b(N, { children: [
168
+ r != null && /* @__PURE__ */ i("span", { className: "flex shrink-0 items-center self-start mt-[var(--ui-sidebar-primary-menu-item-global-icon-margin-t)]", children: r }),
169
+ /* @__PURE__ */ i("span", { className: l("flex-1 truncate text-left", !c && "sr-only"), children: d })
170
+ ] })
171
+ },
172
+ n
173
+ )
174
+ });
175
+ return /* @__PURE__ */ i("li", { className: "contents", children: s });
176
+ });
177
+ T.displayName = "SidebarPrimaryMenuItem";
178
+ const C = t.forwardRef(({ className: a, variant: e, shortcut: r, tag: o, children: d, ...n }, m) => {
179
+ const { expanded: c } = v(), s = e === "tag" || e === "tag-externalLink", u = e === "externalLink" || e === "tag-externalLink", p = e === "shortcut";
180
+ return /* @__PURE__ */ b(
181
+ "span",
182
+ {
183
+ ref: m,
184
+ className: l(
185
+ "inline-flex items-center gap-[var(--ui-sidebar-primary-menu-item-extras-global-container-gap)]",
186
+ !c && "hidden",
187
+ a
188
+ ),
189
+ ...n,
190
+ children: [
191
+ s && (o ?? d),
192
+ p && /* @__PURE__ */ i("span", { className: "ui-sidebar-primary-menu-item-extras-global-shortcut-text-style text-[var(--ui-sidebar-primary-menu-item-extras-global-shortcut-color)]", children: r ?? d }),
193
+ u && /* @__PURE__ */ i(
194
+ P,
195
+ {
196
+ size: 16,
197
+ className: "text-[var(--ui-sidebar-primary-menu-item-extras-global-external-icon-color)] size-[var(--ui-sidebar-primary-menu-item-extras-global-external-icon-size)]"
198
+ }
199
+ )
200
+ ]
201
+ }
202
+ );
203
+ });
204
+ C.displayName = "SidebarPrimaryMenuItemExtras";
205
+ const F = t.forwardRef(({ className: a, icon: e, children: r, onClick: o, ...d }, n) => {
206
+ const { expanded: m, toggleExpanded: c } = v();
207
+ return /* @__PURE__ */ i("li", { className: "contents", children: /* @__PURE__ */ b(
208
+ "button",
209
+ {
210
+ ref: n,
211
+ type: "button",
212
+ "aria-expanded": m,
213
+ className: l(
214
+ f({ variant: "unselected" }),
215
+ "text-left",
216
+ a
217
+ ),
218
+ onClick: (s) => {
219
+ o == null || o(s), s.defaultPrevented || c();
220
+ },
221
+ ...d,
222
+ children: [
223
+ e != null && /* @__PURE__ */ i("span", { className: "flex shrink-0 items-center self-start mt-[var(--ui-sidebar-primary-menu-item-global-icon-margin-t)]", children: e }),
224
+ /* @__PURE__ */ i("span", { className: l("flex-1 truncate", !m && "sr-only"), children: r })
225
+ ]
226
+ }
227
+ ) });
228
+ });
229
+ F.displayName = "SidebarPrimaryCollapseTrigger";
230
+ export {
231
+ _ as SidebarPrimary,
232
+ F as SidebarPrimaryCollapseTrigger,
233
+ E as SidebarPrimaryContent,
234
+ k as SidebarPrimaryFooter,
235
+ M as SidebarPrimaryHeader,
236
+ z as SidebarPrimaryMenu,
237
+ T as SidebarPrimaryMenuItem,
238
+ C as SidebarPrimaryMenuItemExtras,
239
+ I as SidebarPrimarySection,
240
+ f as sidebarPrimaryMenuItemVariants
241
+ };
242
+ //# sourceMappingURL=sidebar-primary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar-primary.js","sources":["../../../../src/components/ui/sidebar-primary/sidebar-primary.tsx"],"sourcesContent":["import * as React from 'react';\nimport { mergeProps } from '@base-ui/react/merge-props';\nimport { useRender } from '@base-ui/react/use-render';\nimport { SquareArrowUpRightIcon } from '@acronis-platform/icons-react/stroke-mono';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\nimport { cn } from '@/lib/utils';\n\n// Composable SidebarPrimary primitives mirroring the Figma \"SidebarPrimary\"\n// component set (node 2092:4359, variant expanded|collapsed). Every color and\n// metric is wired to a next-gen `--ui-sidebar-primary-*` token from\n// @acronis-platform/tokens-pd — no hex, no invented tokens.\n//\n// expanded/collapsed is a width-reflow state, not a panel show/hide, so it is\n// modelled as a controlled/uncontrolled `expanded` prop (default true) that sets\n// `data-state=\"expanded|collapsed\"` on the root. Every metric token has a\n// distinct `collapsed-*` / `expanded-*` name, switched via `data-[state=…]`\n// attribute selectors — Base UI Collapsible would fight this (it hides a panel;\n// the rail never hides). Layout state is shared to descendants through a small\n// context so menu items know whether to show or `sr-only` their label/extras.\n//\n// R2 (menu-item border-radius): the token tier ships no radius token. Verified\n// against the Figma node — the menu-item COMPONENT and its container frame both\n// report cornerRadius=None (the only radius in the node is the COMPONENT_SET's\n// own variant-container chrome). Rows are therefore SQUARE; no `rounded-*` is\n// applied. The focus ring uses the shared `--ui-focus-brand` (no sidebar focus\n// token exists — R1), matching Button/Breadcrumb.\n\ninterface SidebarPrimaryContextValue {\n expanded: boolean;\n /** Flip the rail width — drives the controlled/uncontrolled `expanded` state. */\n toggleExpanded: () => void;\n}\n\nconst SidebarPrimaryContext =\n React.createContext<SidebarPrimaryContextValue | null>(null);\n\nfunction useSidebarPrimaryContext(): SidebarPrimaryContextValue {\n // Default to expanded so parts render standalone (e.g. in isolation tests /\n // stories) without a wrapping root; the toggle is a no-op outside a root.\n return (\n React.useContext(SidebarPrimaryContext) ?? {\n expanded: true,\n toggleExpanded: () => {},\n }\n );\n}\n\n/**\n * Controlled + uncontrolled boolean state (the Base UI idiom). When `controlled`\n * is provided it wins and the setter only emits the change callback; otherwise\n * the setter updates internal state. `onChange` is ALWAYS invoked with the next\n * value so a consumer can react in either mode.\n */\nfunction useControllableBoolean(\n controlled: boolean | undefined,\n defaultValue: boolean,\n onChange?: (next: boolean) => void\n): [boolean, (next: boolean) => void] {\n const [uncontrolled, setUncontrolled] = React.useState(defaultValue);\n const isControlled = controlled !== undefined;\n const value = isControlled ? controlled : uncontrolled;\n const setValue = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setUncontrolled(next);\n onChange?.(next);\n },\n [isControlled, onChange]\n );\n return [value, setValue];\n}\n\nexport interface SidebarPrimaryProps\n extends React.ComponentPropsWithoutRef<'nav'> {\n /** Controlled expanded (rail width) state. */\n expanded?: boolean;\n /** Uncontrolled initial expanded state. Defaults to `true` (full width). */\n defaultExpanded?: boolean;\n /** Fires when the expanded state changes (e.g. a consumer toggle). */\n onExpandedChange?: (expanded: boolean) => void;\n /**\n * Replace the rendered `<nav>` with another element or component\n * (Base UI composition). Accepts a React element or a render function.\n */\n render?: useRender.RenderProp;\n}\n\nconst SidebarPrimary = React.forwardRef<HTMLElement, SidebarPrimaryProps>(\n (\n {\n className,\n expanded: expandedProp,\n defaultExpanded = true,\n onExpandedChange,\n 'aria-label': ariaLabel = 'Primary',\n render,\n children,\n ...props\n },\n ref\n ) => {\n const [expanded, setExpanded] = useControllableBoolean(\n expandedProp,\n defaultExpanded,\n onExpandedChange\n );\n\n // Collapse is driven by the consumer through the layout context — the\n // `SidebarPrimaryCollapseTrigger` (the Figma \"Collapse menu\" footer item)\n // calls `toggleExpanded`, which updates uncontrolled state and always emits\n // `onExpandedChange`. Controlled consumers ignore the internal state and\n // react to the callback.\n const context = React.useMemo<SidebarPrimaryContextValue>(\n () => ({ expanded, toggleExpanded: () => setExpanded(!expanded) }),\n [expanded, setExpanded]\n );\n\n const element = useRender({\n render,\n ref,\n defaultTagName: 'nav',\n props: mergeProps<'nav'>(\n {\n 'aria-label': ariaLabel,\n // `data-state` drives every collapsed/expanded token switch via\n // attribute selectors; typed loosely because React's nav attribute\n // map doesn't include arbitrary data-* keys as literals.\n ...({ 'data-state': expanded ? 'expanded' : 'collapsed' } as Record<\n string,\n string\n >),\n className: cn(\n 'group/sidebar flex h-full flex-col bg-[var(--ui-sidebar-primary-global-container-color)] w-[var(--ui-sidebar-primary-collapsed-container-width)] data-[state=expanded]:w-[var(--ui-sidebar-primary-expanded-container-width)] transition-[width]',\n className\n ),\n children,\n },\n props\n ),\n });\n\n return (\n <SidebarPrimaryContext.Provider value={context}>\n {element}\n </SidebarPrimaryContext.Provider>\n );\n }\n);\nSidebarPrimary.displayName = 'SidebarPrimary';\n\nconst SidebarPrimaryHeader = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<'div'>\n>(({ className, ...props }, ref) => (\n // Hosts a consumer-provided logo (R7 — no Logo part is built). Padding and the\n // logo height switch on expanded/collapsed; `[&_*]:h-…` sizes whatever the\n // consumer slots in. The logo color token tints any `currentColor` mark.\n <div\n ref={ref}\n className={cn(\n 'flex items-center shrink-0 text-[var(--ui-sidebar-primary-global-logo-color)]',\n 'px-[var(--ui-sidebar-primary-collapsed-container-header-padding-x)] py-[var(--ui-sidebar-primary-collapsed-container-header-padding-y)]',\n '[&_:where(img,svg)]:h-[var(--ui-sidebar-primary-collapsed-logo-height)] [&_:where(img,svg)]:w-auto',\n 'group-data-[state=expanded]/sidebar:px-[var(--ui-sidebar-primary-expanded-container-header-padding-x)] group-data-[state=expanded]/sidebar:py-[var(--ui-sidebar-primary-expanded-container-header-padding-y)]',\n 'group-data-[state=expanded]/sidebar:[&_:where(img,svg)]:h-[var(--ui-sidebar-primary-expanded-logo-height)]',\n className\n )}\n {...props}\n />\n));\nSidebarPrimaryHeader.displayName = 'SidebarPrimaryHeader';\n\nconst SidebarPrimaryContent = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<'div'>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-1 flex-col overflow-y-auto gap-[var(--ui-sidebar-primary-global-section-list-gap)]',\n className\n )}\n {...props}\n />\n));\nSidebarPrimaryContent.displayName = 'SidebarPrimaryContent';\n\nconst SidebarPrimaryFooter = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<'div'>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col shrink-0 gap-[var(--ui-sidebar-primary-global-footer-list-gap)]',\n 'border-t border-[var(--ui-sidebar-primary-global-container-footer-border-color)] [border-top-width:var(--ui-sidebar-primary-global-container-footer-border-width)]',\n 'py-[var(--ui-sidebar-primary-section-container-padding-y)]',\n className\n )}\n {...props}\n />\n));\nSidebarPrimaryFooter.displayName = 'SidebarPrimaryFooter';\n\nconst SidebarPrimarySection = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<'div'>\n>(({ className, ...props }, ref) => (\n // `firstSection` in Figma only toggles the top divider — derive it from DOM\n // position (`:not(:first-child)`) instead of a prop.\n <div\n ref={ref}\n className={cn(\n 'flex flex-col py-[var(--ui-sidebar-primary-section-container-padding-y)]',\n '[&:not(:first-child)]:border-t [&:not(:first-child)]:border-[var(--ui-sidebar-primary-section-container-border-color)] [&:not(:first-child)]:[border-top-width:var(--ui-sidebar-primary-section-container-border-width)]',\n className\n )}\n {...props}\n />\n));\nSidebarPrimarySection.displayName = 'SidebarPrimarySection';\n\nconst SidebarPrimaryMenu = React.forwardRef<\n HTMLUListElement,\n React.ComponentPropsWithoutRef<'ul'>\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn(\n 'flex flex-col gap-[var(--ui-sidebar-primary-section-menu-item-list-gap)]',\n className\n )}\n {...props}\n />\n));\nSidebarPrimaryMenu.displayName = 'SidebarPrimaryMenu';\n\n// Primary recolors the container, the icon AND the label per variant\n// (selected|unselected) × interaction state (idle/hover/active). Every state is\n// wired to its own token even where acronis's value is unchanged, because these\n// are runtime `var()` references — a brand override is only honored if the\n// matching state token is referenced. (This is why Primary cannot share a cva\n// with Secondary, which recolors only the container — DESIGN §6.2.)\nconst sidebarPrimaryMenuItemVariants = cva(\n 'group/menu-item flex w-full items-center gap-[var(--ui-sidebar-primary-menu-item-global-container-gap)] h-[var(--ui-sidebar-primary-menu-item-global-container-height)] px-[var(--ui-sidebar-primary-menu-item-global-container-padding-x)] py-[var(--ui-sidebar-primary-menu-item-global-container-padding-y)] no-underline ui-sidebar-primary-menu-item-global-label-text-style transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-focus-brand)] focus-visible:ring-inset [&_svg]:shrink-0 [&_svg]:size-[var(--ui-sidebar-primary-menu-item-global-icon-size)]',\n {\n variants: {\n variant: {\n unselected:\n 'bg-[var(--ui-sidebar-primary-menu-item-unselected-container-color-idle)] text-[var(--ui-sidebar-primary-menu-item-unselected-label-color-idle)] [&_svg]:text-[var(--ui-sidebar-primary-menu-item-unselected-icon-color-idle)] hover:bg-[var(--ui-sidebar-primary-menu-item-unselected-container-color-hover)] hover:text-[var(--ui-sidebar-primary-menu-item-unselected-label-color-hover)] hover:[&_svg]:text-[var(--ui-sidebar-primary-menu-item-unselected-icon-color-hover)] active:bg-[var(--ui-sidebar-primary-menu-item-unselected-container-color-active)] active:text-[var(--ui-sidebar-primary-menu-item-unselected-label-color-active)] active:[&_svg]:text-[var(--ui-sidebar-primary-menu-item-unselected-icon-color-active)]',\n selected:\n 'bg-[var(--ui-sidebar-primary-menu-item-selected-container-color-idle)] text-[var(--ui-sidebar-primary-menu-item-selected-label-color-idle)] [&_svg]:text-[var(--ui-sidebar-primary-menu-item-selected-icon-color-idle)] hover:bg-[var(--ui-sidebar-primary-menu-item-selected-container-color-hover)] hover:text-[var(--ui-sidebar-primary-menu-item-selected-label-color-hover)] hover:[&_svg]:text-[var(--ui-sidebar-primary-menu-item-selected-icon-color-hover)] active:bg-[var(--ui-sidebar-primary-menu-item-selected-container-color-active)] active:text-[var(--ui-sidebar-primary-menu-item-selected-label-color-active)] active:[&_svg]:text-[var(--ui-sidebar-primary-menu-item-selected-icon-color-active)]',\n },\n },\n defaultVariants: {\n variant: 'unselected',\n },\n }\n);\n\nexport interface SidebarPrimaryMenuItemProps\n extends Omit<React.ComponentPropsWithoutRef<'a'>, 'children'>,\n Omit<VariantProps<typeof sidebarPrimaryMenuItemVariants>, 'variant'> {\n /** Marks the current route: sets the `selected` variant + `aria-current=\"page\"`. */\n selected?: boolean;\n /** Leading 16px icon (from `@acronis-platform/icons-react`). */\n icon?: React.ReactNode;\n children?: React.ReactNode;\n /**\n * Replace the rendered `<a>` with another element or component (e.g. a router\n * `Link` or a `<button>`) via Base UI composition.\n */\n render?: useRender.RenderProp;\n}\n\nconst SidebarPrimaryMenuItem = React.forwardRef<\n HTMLAnchorElement,\n SidebarPrimaryMenuItemProps\n>(({ className, selected = false, icon, render, children, ...props }, ref) => {\n const { expanded } = useSidebarPrimaryContext();\n\n const inner = useRender({\n render,\n ref,\n defaultTagName: 'a',\n props: mergeProps<'a'>(\n {\n className: cn(\n sidebarPrimaryMenuItemVariants({\n variant: selected ? 'selected' : 'unselected',\n }),\n className\n ),\n 'aria-current': selected ? 'page' : undefined,\n children: (\n <>\n {icon != null && (\n <span className=\"flex shrink-0 items-center self-start mt-[var(--ui-sidebar-primary-menu-item-global-icon-margin-t)]\">\n {icon}\n </span>\n )}\n {/* Keep the label in the DOM in collapsed/rail mode as `sr-only` so\n the icon-only row keeps an accessible name (a11y §7) — never\n `display:none` the text. Extras are visually dropped when\n collapsed but stay queryable for the same reason. */}\n <span className={cn('flex-1 truncate text-left', !expanded && 'sr-only')}>\n {children}\n </span>\n </>\n ),\n },\n props\n ),\n });\n\n return <li className=\"contents\">{inner}</li>;\n});\nSidebarPrimaryMenuItem.displayName = 'SidebarPrimaryMenuItem';\n\nexport interface SidebarPrimaryMenuItemExtrasProps\n extends React.ComponentPropsWithoutRef<'span'> {\n /** Which trailing affordance to render. */\n variant: 'tag' | 'externalLink' | 'shortcut' | 'tag-externalLink';\n /** Shortcut text (e.g. \"⌘H\") for the `shortcut` variant. */\n shortcut?: string;\n /** Tag content for the `tag` / `tag-externalLink` variants. */\n tag?: React.ReactNode;\n}\n\nconst SidebarPrimaryMenuItemExtras = React.forwardRef<\n HTMLSpanElement,\n SidebarPrimaryMenuItemExtrasProps\n>(({ className, variant, shortcut, tag, children, ...props }, ref) => {\n const { expanded } = useSidebarPrimaryContext();\n const showTag = variant === 'tag' || variant === 'tag-externalLink';\n const showExternal =\n variant === 'externalLink' || variant === 'tag-externalLink';\n const showShortcut = variant === 'shortcut';\n\n return (\n <span\n ref={ref}\n // The extras cluster is rail-mode noise — drop it when collapsed.\n className={cn(\n 'inline-flex items-center gap-[var(--ui-sidebar-primary-menu-item-extras-global-container-gap)]',\n !expanded && 'hidden',\n className\n )}\n {...props}\n >\n {showTag && (tag ?? children)}\n {showShortcut && (\n <span className=\"ui-sidebar-primary-menu-item-extras-global-shortcut-text-style text-[var(--ui-sidebar-primary-menu-item-extras-global-shortcut-color)]\">\n {shortcut ?? children}\n </span>\n )}\n {showExternal && (\n <SquareArrowUpRightIcon\n size={16}\n className=\"text-[var(--ui-sidebar-primary-menu-item-extras-global-external-icon-color)] size-[var(--ui-sidebar-primary-menu-item-extras-global-external-icon-size)]\"\n />\n )}\n </span>\n );\n});\nSidebarPrimaryMenuItemExtras.displayName = 'SidebarPrimaryMenuItemExtras';\n\nexport interface SidebarPrimaryCollapseTriggerProps\n extends Omit<React.ComponentPropsWithoutRef<'button'>, 'children'> {\n /** Leading 16px icon (e.g. a panel-left glyph). */\n icon?: React.ReactNode;\n children?: React.ReactNode;\n}\n\n// The footer \"Collapse menu\" affordance (Figma). A menu-item-styled `<button>`\n// that flips the rail width via the layout context — this is the live wiring\n// for the controllable `expanded` state (B1). In collapsed mode it keeps its\n// label as `sr-only` like every other row.\nconst SidebarPrimaryCollapseTrigger = React.forwardRef<\n HTMLButtonElement,\n SidebarPrimaryCollapseTriggerProps\n>(({ className, icon, children, onClick, ...props }, ref) => {\n const { expanded, toggleExpanded } = useSidebarPrimaryContext();\n\n return (\n <li className=\"contents\">\n <button\n ref={ref}\n type=\"button\"\n aria-expanded={expanded}\n className={cn(\n sidebarPrimaryMenuItemVariants({ variant: 'unselected' }),\n 'text-left',\n className\n )}\n onClick={(event) => {\n onClick?.(event);\n if (!event.defaultPrevented) toggleExpanded();\n }}\n {...props}\n >\n {icon != null && (\n <span className=\"flex shrink-0 items-center self-start mt-[var(--ui-sidebar-primary-menu-item-global-icon-margin-t)]\">\n {icon}\n </span>\n )}\n <span className={cn('flex-1 truncate', !expanded && 'sr-only')}>\n {children}\n </span>\n </button>\n </li>\n );\n});\nSidebarPrimaryCollapseTrigger.displayName = 'SidebarPrimaryCollapseTrigger';\n\nexport {\n SidebarPrimary,\n SidebarPrimaryHeader,\n SidebarPrimaryContent,\n SidebarPrimaryFooter,\n SidebarPrimarySection,\n SidebarPrimaryMenu,\n SidebarPrimaryMenuItem,\n SidebarPrimaryMenuItemExtras,\n SidebarPrimaryCollapseTrigger,\n sidebarPrimaryMenuItemVariants,\n};\n"],"names":["SidebarPrimaryContext","React","useSidebarPrimaryContext","useControllableBoolean","controlled","defaultValue","onChange","uncontrolled","setUncontrolled","isControlled","value","setValue","next","SidebarPrimary","className","expandedProp","defaultExpanded","onExpandedChange","ariaLabel","render","children","props","ref","expanded","setExpanded","context","element","useRender","mergeProps","cn","SidebarPrimaryHeader","jsx","SidebarPrimaryContent","SidebarPrimaryFooter","SidebarPrimarySection","SidebarPrimaryMenu","sidebarPrimaryMenuItemVariants","cva","SidebarPrimaryMenuItem","selected","icon","inner","jsxs","Fragment","SidebarPrimaryMenuItemExtras","variant","shortcut","tag","showTag","showExternal","showShortcut","SquareArrowUpRightIcon","SidebarPrimaryCollapseTrigger","onClick","toggleExpanded","event"],"mappings":"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"}