@weasel-js/ui 0.7.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/chunks/{ActionBar-CiKvEvXi.js → ActionBar-GThu74LC.js} +4 -4
  2. package/dist/chunks/ActionBar-GThu74LC.js.map +1 -0
  3. package/dist/chunks/{Badge-DU8ihE7Z.js → Badge-DZQqAV4d.js} +5 -5
  4. package/dist/chunks/Badge-DZQqAV4d.js.map +1 -0
  5. package/dist/chunks/{Checkbox-CtK8H_OQ.js → Checkbox-Cf6YHVWV.js} +5 -5
  6. package/dist/chunks/Checkbox-Cf6YHVWV.js.map +1 -0
  7. package/dist/chunks/{ComboBox-CotoRgNi.js → ComboBox-EnV1IytN.js} +8 -8
  8. package/dist/chunks/ComboBox-EnV1IytN.js.map +1 -0
  9. package/dist/chunks/{DataGrid-mUq38k0Q.js → DataGrid-BQklXGRl.js} +10 -10
  10. package/dist/chunks/DataGrid-BQklXGRl.js.map +1 -0
  11. package/dist/chunks/GradientEditor-Co9aGyRe.js +260 -0
  12. package/dist/chunks/GradientEditor-Co9aGyRe.js.map +1 -0
  13. package/dist/chunks/{Input-D_Xzgr2b.js → Input-qk44ESKC.js} +4 -4
  14. package/dist/chunks/Input-qk44ESKC.js.map +1 -0
  15. package/dist/chunks/{Keycaps-B9dJMYx_.js → Keycaps-CFX7UAj8.js} +5 -5
  16. package/dist/chunks/Keycaps-CFX7UAj8.js.map +1 -0
  17. package/dist/chunks/{NumberField-BQmELz32.js → NumberField-CYhQeWoM.js} +5 -5
  18. package/dist/chunks/NumberField-CYhQeWoM.js.map +1 -0
  19. package/dist/chunks/{Powerline-C8rddbbK.js → Powerline-Bg9M5oBK.js} +2 -2
  20. package/dist/chunks/{Powerline-C8rddbbK.js.map → Powerline-Bg9M5oBK.js.map} +1 -1
  21. package/dist/chunks/{Prefs-BkDJ5Cdz.js → Prefs-DZjXp2Ln.js} +23 -23
  22. package/dist/chunks/Prefs-DZjXp2Ln.js.map +1 -0
  23. package/dist/chunks/{RadioGroup-Ci-I9NEx.js → RadioGroup-rL2i3afr.js} +5 -5
  24. package/dist/chunks/RadioGroup-rL2i3afr.js.map +1 -0
  25. package/dist/chunks/{RangeSlider-CW-edtNx.js → RangeSlider-DPldYd4O.js} +8 -8
  26. package/dist/chunks/RangeSlider-DPldYd4O.js.map +1 -0
  27. package/dist/chunks/{ResizeHandle-C2OBMqTs.js → ResizeHandle-DR8X229y.js} +3 -3
  28. package/dist/chunks/ResizeHandle-DR8X229y.js.map +1 -0
  29. package/dist/chunks/{Select-CLyBisCS.js → Select-vSeAbspK.js} +9 -9
  30. package/dist/chunks/Select-vSeAbspK.js.map +1 -0
  31. package/dist/chunks/{SelectionPanel-DBdhAKIK.js → SelectionPanel-1mmALQba.js} +19 -19
  32. package/dist/chunks/SelectionPanel-1mmALQba.js.map +1 -0
  33. package/dist/chunks/{Sidebar-doLqiTZH.js → Sidebar-CigrFvpL.js} +4 -4
  34. package/dist/chunks/Sidebar-CigrFvpL.js.map +1 -0
  35. package/dist/chunks/{SidebarPanel-DjTfOzB9.js → SidebarPanel-C0w16BrF.js} +10 -10
  36. package/dist/chunks/SidebarPanel-C0w16BrF.js.map +1 -0
  37. package/dist/chunks/{Slider-sUJGgmKR.js → Slider-Di2kNqVy.js} +11 -11
  38. package/dist/chunks/Slider-Di2kNqVy.js.map +1 -0
  39. package/dist/chunks/{StatusBar-OOjfqCD8.js → StatusBar-lt_Ok6WK.js} +6 -6
  40. package/dist/chunks/StatusBar-lt_Ok6WK.js.map +1 -0
  41. package/dist/chunks/{Switch-DxJLMYki.js → Switch-BYj762hm.js} +5 -5
  42. package/dist/chunks/Switch-BYj762hm.js.map +1 -0
  43. package/dist/chunks/{ToolButton-Dv6NdZKh.js → ToolButton-5L1sAlJC.js} +6 -6
  44. package/dist/chunks/ToolButton-5L1sAlJC.js.map +1 -0
  45. package/dist/chunks/{ToolOptionsBar-ChiL-HVA.js → ToolOptionsBar-D4xmXa_a.js} +4 -4
  46. package/dist/chunks/ToolOptionsBar-D4xmXa_a.js.map +1 -0
  47. package/dist/chunks/{ToolPalette-DXVIEO0w.js → ToolPalette-BDkvV3pJ.js} +7 -7
  48. package/dist/chunks/ToolPalette-BDkvV3pJ.js.map +1 -0
  49. package/dist/components/ActionBar/index.js +1 -1
  50. package/dist/components/Badge/index.js +1 -1
  51. package/dist/components/Checkbox/index.js +1 -1
  52. package/dist/components/ComboBox/index.js +1 -1
  53. package/dist/components/DataGrid/index.js +1 -1
  54. package/dist/components/GradientEditor/GradientEditor.d.ts +34 -0
  55. package/dist/components/GradientEditor/GradientEditor.d.ts.map +1 -0
  56. package/dist/components/GradientEditor/GradientHandles.d.ts +53 -0
  57. package/dist/components/GradientEditor/GradientHandles.d.ts.map +1 -0
  58. package/dist/components/GradientEditor/index.d.ts +3 -0
  59. package/dist/components/GradientEditor/index.d.ts.map +1 -0
  60. package/dist/components/GradientEditor/index.js +2 -0
  61. package/dist/components/Input/index.js +1 -1
  62. package/dist/components/Keycaps/index.js +1 -1
  63. package/dist/components/NumberField/index.js +1 -1
  64. package/dist/components/Powerline/index.js +2 -2
  65. package/dist/components/Prefs/index.js +1 -1
  66. package/dist/components/RadioGroup/index.js +1 -1
  67. package/dist/components/RangeSlider/index.js +1 -1
  68. package/dist/components/ResizeHandle/index.js +1 -1
  69. package/dist/components/Select/index.js +1 -1
  70. package/dist/components/SelectionPanel/index.js +1 -1
  71. package/dist/components/Sidebar/index.js +1 -1
  72. package/dist/components/SidebarPanel/index.js +1 -1
  73. package/dist/components/Slider/index.js +1 -1
  74. package/dist/components/StatusBar/index.js +1 -1
  75. package/dist/components/Switch/index.js +1 -1
  76. package/dist/components/ToolButton/index.js +1 -1
  77. package/dist/components/ToolOptionsBar/index.js +1 -1
  78. package/dist/components/ToolPalette/ToolPalette.d.ts.map +1 -1
  79. package/dist/components/ToolPalette/index.js +1 -1
  80. package/dist/index.d.ts +1 -0
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +36 -70
  83. package/dist/index.js.map +1 -1
  84. package/dist/style.css +1 -1
  85. package/package.json +2 -2
  86. package/dist/chunks/ActionBar-CiKvEvXi.js.map +0 -1
  87. package/dist/chunks/Badge-DU8ihE7Z.js.map +0 -1
  88. package/dist/chunks/Checkbox-CtK8H_OQ.js.map +0 -1
  89. package/dist/chunks/ComboBox-CotoRgNi.js.map +0 -1
  90. package/dist/chunks/DataGrid-mUq38k0Q.js.map +0 -1
  91. package/dist/chunks/Input-D_Xzgr2b.js.map +0 -1
  92. package/dist/chunks/Keycaps-B9dJMYx_.js.map +0 -1
  93. package/dist/chunks/NumberField-BQmELz32.js.map +0 -1
  94. package/dist/chunks/Prefs-BkDJ5Cdz.js.map +0 -1
  95. package/dist/chunks/RadioGroup-Ci-I9NEx.js.map +0 -1
  96. package/dist/chunks/RangeSlider-CW-edtNx.js.map +0 -1
  97. package/dist/chunks/ResizeHandle-C2OBMqTs.js.map +0 -1
  98. package/dist/chunks/Select-CLyBisCS.js.map +0 -1
  99. package/dist/chunks/SelectionPanel-DBdhAKIK.js.map +0 -1
  100. package/dist/chunks/Sidebar-doLqiTZH.js.map +0 -1
  101. package/dist/chunks/SidebarPanel-DjTfOzB9.js.map +0 -1
  102. package/dist/chunks/Slider-sUJGgmKR.js.map +0 -1
  103. package/dist/chunks/StatusBar-OOjfqCD8.js.map +0 -1
  104. package/dist/chunks/Switch-DxJLMYki.js.map +0 -1
  105. package/dist/chunks/ToolButton-Dv6NdZKh.js.map +0 -1
  106. package/dist/chunks/ToolOptionsBar-ChiL-HVA.js.map +0 -1
  107. package/dist/chunks/ToolPalette-DXVIEO0w.js.map +0 -1
@@ -2,13 +2,13 @@ import { n as e } from "./Field-BHSu2F3E.js";
2
2
  import { Button as t, ComboBox as n, FieldError as r, Input as i, Label as a, ListBox as o, ListBoxItem as s, Popover as c, Text as l } from "react-aria-components";
3
3
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
4
4
  var f = {
5
- field: "_field_kzt6j_1",
6
- frame: "_frame_kzt6j_9",
7
- openButton: "_openButton_kzt6j_53",
8
- popover: "_popover_kzt6j_75",
9
- listbox: "_listbox_kzt6j_80",
10
- option: "_option_kzt6j_93",
11
- empty: "_empty_kzt6j_116"
5
+ field: "_field_7wlzm_1",
6
+ frame: "_frame_7wlzm_9",
7
+ openButton: "_openButton_7wlzm_53",
8
+ popover: "_popover_7wlzm_75",
9
+ listbox: "_listbox_7wlzm_80",
10
+ option: "_option_7wlzm_93",
11
+ empty: "_empty_7wlzm_116"
12
12
  };
13
13
  //#endregion
14
14
  //#region src/components/ComboBox/ComboBox.tsx
@@ -85,4 +85,4 @@ function m({ className: e, ...t }) {
85
85
  //#endregion
86
86
  export { m as n, p as t };
87
87
 
88
- //# sourceMappingURL=ComboBox-CotoRgNi.js.map
88
+ //# sourceMappingURL=ComboBox-EnV1IytN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComboBox-EnV1IytN.js","names":[],"sources":["../../src/components/ComboBox/ComboBox.module.css","../../src/components/ComboBox/ComboBox.tsx"],"sourcesContent":[".field {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n gap: 4px;\n}\n\n.frame {\n display: flex;\n align-items: stretch;\n height: 24px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n color: var(--wzl-fg);\n font-family: var(--wzl-font-ui);\n font-size: 13px;\n line-height: 1;\n overflow: hidden;\n transition: border-color var(--wzl-motion-fast), box-shadow var(--wzl-motion-fast);\n}\n\n.frame:focus-within {\n border-color: var(--wzl-focus-ring);\n box-shadow: 0 0 0 1px var(--wzl-focus-ring);\n}\n\n.field[data-invalid] .frame {\n border-color: var(--wzl-danger, #ff5b5b);\n}\n\n.field[data-disabled] .frame {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.frame input {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: none;\n outline: none;\n color: inherit;\n font: inherit;\n padding: 0 8px;\n}\n\n.frame input::placeholder {\n color: var(--wzl-fg-subtle);\n}\n\n.openButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n background: transparent;\n border: none;\n border-left: 1px solid var(--wzl-border);\n color: var(--wzl-fg-muted);\n cursor: pointer;\n padding: 0;\n}\n\n.openButton[data-hovered]:not([data-disabled]) {\n color: var(--wzl-fg);\n}\n\n.openButton svg {\n width: 10px;\n height: 10px;\n}\n\n.popover {\n min-width: var(--trigger-width);\n outline: none;\n}\n\n.listbox {\n background: var(--wzl-surface-raised);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-md);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);\n padding: 4px;\n max-height: 280px;\n overflow: auto;\n outline: none;\n font-family: var(--wzl-font-ui);\n font-size: 13px;\n}\n\n.option {\n display: flex;\n align-items: center;\n padding: 4px 8px;\n border-radius: 3px;\n cursor: pointer;\n color: var(--wzl-fg);\n outline: none;\n}\n\n.option[data-focused] {\n background: color-mix(in srgb, var(--wzl-fg) 10%, transparent);\n}\n\n.option[data-selected] {\n font-weight: 500;\n}\n\n.option[data-disabled] {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.empty {\n padding: 6px 8px;\n color: var(--wzl-fg-subtle);\n font-size: 12px;\n}\n","import type { ReactNode } from 'react';\nimport {\n ComboBox as RACComboBox,\n Label,\n Input as RACInput,\n Button as RACButton,\n Popover as RACPopover,\n ListBox as RACListBox,\n ListBoxItem as RACListBoxItem,\n Text,\n FieldError,\n type ComboBoxProps as RACComboBoxProps,\n type ListBoxItemProps as RACListBoxItemProps,\n type ValidationResult,\n} from 'react-aria-components';\nimport { fieldClasses } from '../Field/Field';\nimport s from './ComboBox.module.css';\n\nexport type ComboBoxOption = {\n value: string;\n label: ReactNode;\n textValue?: string;\n isDisabled?: boolean;\n};\n\ntype Key = string | number;\n\nexport type ComboBoxProps<T extends Key = string> = Omit<RACComboBoxProps<object>, 'children' | 'className' | 'selectedKey' | 'defaultSelectedKey' | 'onSelectionChange'> & {\n label?: ReactNode;\n description?: ReactNode;\n errorMessage?: ReactNode | ((v: ValidationResult) => ReactNode);\n placeholder?: string;\n options?: ReadonlyArray<ComboBoxOption & { value: T }>;\n children?: ReactNode;\n selectedKey?: T | null;\n defaultSelectedKey?: T;\n onSelectionChange?: (key: T | null) => void;\n emptyLabel?: ReactNode;\n className?: string;\n};\n\n/**\n * Filterable single-select wrapping React Aria's ComboBox. The user can\n * type to filter; selection commits to `onSelectionChange`. When no value\n * is in the input, selection clears (key becomes null).\n */\nexport function ComboBox<T extends Key = string>(props: ComboBoxProps<T>) {\n const {\n label,\n description,\n errorMessage,\n placeholder,\n options,\n children,\n selectedKey,\n defaultSelectedKey,\n onSelectionChange,\n emptyLabel = 'No matches',\n className,\n ...rest\n } = props;\n\n return (\n <RACComboBox\n {...rest}\n selectedKey={selectedKey ?? undefined}\n defaultSelectedKey={defaultSelectedKey}\n onSelectionChange={onSelectionChange ? (k) => onSelectionChange(k as T | null) : undefined}\n className={[s.field, fieldClasses.root, className].filter(Boolean).join(' ')}\n >\n {label !== undefined && <Label className={fieldClasses.label}>{label}</Label>}\n <div className={s.frame}>\n <RACInput placeholder={placeholder} />\n <RACButton className={s.openButton} aria-label=\"Show options\">\n <svg viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M2 4 L5 7 L8 4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </RACButton>\n </div>\n {description !== undefined && (\n <Text slot=\"description\" className={fieldClasses.hint}>\n {description}\n </Text>\n )}\n <FieldError className={fieldClasses.error}>{errorMessage}</FieldError>\n <RACPopover className={s.popover}>\n <RACListBox className={s.listbox} renderEmptyState={() => <div className={s.empty}>{emptyLabel}</div>}>\n {options !== undefined\n ? options.map((o) => (\n <ComboBoxItem key={String(o.value)} id={o.value} textValue={o.textValue} isDisabled={o.isDisabled}>\n {o.label}\n </ComboBoxItem>\n ))\n : children}\n </RACListBox>\n </RACPopover>\n </RACComboBox>\n );\n}\n\nexport type ComboBoxItemProps = Omit<RACListBoxItemProps, 'className'> & {\n className?: string;\n};\n\nexport function ComboBoxItem({ className, ...rest }: ComboBoxItemProps) {\n return <RACListBoxItem {...rest} className={[s.option, className].filter(Boolean).join(' ')} />;\n}\n"],"mappings":";;;;;;;;;;;;;;AC8CA,SAAgB,EAAiC,GAAyB;CACxE,IAAM,EACJ,UACA,gBACA,iBACA,gBACA,YACA,aACA,gBACA,uBACA,sBACA,gBAAa,cACb,cACA,GAAG,MACD;AAEJ,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,aAAa,KAAe,KAAA;EACR;EACpB,mBAAmB,KAAqB,MAAM,EAAkB,EAAc,GAAG,KAAA;EACjF,WAAW;GAAC,EAAE;GAAO,EAAa;GAAM;GAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAL9E;GAOG,MAAU,KAAA,KAAa,kBAAC,GAAD;IAAO,WAAW,EAAa;cAAQ;IAAc,CAAA;GAC7E,kBAAC,OAAD;IAAK,WAAW,EAAE;cAAlB,CACE,kBAAC,GAAD,EAAuB,gBAAe,CAAA,EACtC,kBAAC,GAAD;KAAW,WAAW,EAAE;KAAY,cAAW;eAC7C,kBAAC,OAAD;MAAK,SAAQ;MAAY,eAAY;gBACnC,kBAAC,QAAD;OAAM,GAAE;OAAiB,MAAK;OAAO,QAAO;OAAe,aAAY;OAAM,eAAc;OAAQ,gBAAe;OAAU,CAAA;MACxH,CAAA;KACI,CAAA,CACR;;GACL,MAAgB,KAAA,KACf,kBAAC,GAAD;IAAM,MAAK;IAAc,WAAW,EAAa;cAC9C;IACI,CAAA;GAET,kBAAC,GAAD;IAAY,WAAW,EAAa;cAAQ;IAA0B,CAAA;GACtE,kBAAC,GAAD;IAAY,WAAW,EAAE;cACvB,kBAAC,GAAD;KAAY,WAAW,EAAE;KAAS,wBAAwB,kBAAC,OAAD;MAAK,WAAW,EAAE;gBAAQ;MAAiB,CAAA;eAClG,MAAY,KAAA,IAMT,IALA,EAAQ,KAAK,MACX,kBAAC,GAAD;MAAoC,IAAI,EAAE;MAAO,WAAW,EAAE;MAAW,YAAY,EAAE;gBACpF,EAAE;MACU,EAFI,OAAO,EAAE,MAAM,CAEnB,CACf;KAEK,CAAA;IACF,CAAA;GACD;;;AAQlB,SAAgB,EAAa,EAAE,cAAW,GAAG,KAA2B;AACtE,QAAO,kBAAC,GAAD;EAAgB,GAAI;EAAM,WAAW,CAAC,EAAE,QAAQ,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;EAAI,CAAA"}
@@ -89,15 +89,15 @@ function s(e) {
89
89
  };
90
90
  }
91
91
  var c = {
92
- grid: "_grid_1hke3_1",
93
- table: "_table_1hke3_6",
94
- sortable: "_sortable_1hke3_34",
95
- sortActive: "_sortActive_1hke3_39",
96
- empty: "_empty_1hke3_41",
97
- handleCol: "_handleCol_1hke3_49",
98
- handleCell: "_handleCell_1hke3_50",
99
- dragging: "_dragging_1hke3_59",
100
- dropIndicator: "_dropIndicator_1hke3_61"
92
+ grid: "_grid_wvlvv_1",
93
+ table: "_table_wvlvv_6",
94
+ sortable: "_sortable_wvlvv_34",
95
+ sortActive: "_sortActive_wvlvv_39",
96
+ empty: "_empty_wvlvv_41",
97
+ handleCol: "_handleCol_wvlvv_49",
98
+ handleCell: "_handleCell_wvlvv_50",
99
+ dragging: "_dragging_wvlvv_59",
100
+ dropIndicator: "_dropIndicator_wvlvv_61"
101
101
  };
102
102
  //#endregion
103
103
  //#region src/components/DataGrid/DataGrid.tsx
@@ -183,4 +183,4 @@ function l(t) {
183
183
  //#endregion
184
184
  export { s as n, l as t };
185
185
 
186
- //# sourceMappingURL=DataGrid-mUq38k0Q.js.map
186
+ //# sourceMappingURL=DataGrid-BQklXGRl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataGrid-BQklXGRl.js","names":[],"sources":["../../src/useReorderDragList.ts","../../src/components/DataGrid/DataGrid.module.css","../../src/components/DataGrid/DataGrid.tsx"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\nimport type { ReactNode, PointerEvent as ReactPointerEvent, RefCallback } from 'react';\n\nexport interface LayerListItem {\n id: string;\n label: ReactNode;\n /** Locked rows cannot be dragged, cannot be crossed by drops, and\n * never combine with other rows in a multi-selection. */\n locked?: boolean;\n /** Optional color swatch rendered before the label. Any CSS color string. */\n swatch?: string;\n}\n\nexport interface UseReorderDragListOptions {\n items: LayerListItem[];\n selectedIds: string[];\n onReorder(ids: string[], targetIndex: number): void;\n /** Pointer-move distance (px) before pending drag engages. Default 4. */\n threshold?: number;\n}\n\nexport interface ReorderDragState {\n draggedIds: string[] | null;\n targetIndex: number | null;\n}\n\nexport interface ReorderDragHandlers {\n rowProps(id: string, index: number): { onPointerDown(e: ReactPointerEvent): void };\n containerProps: {\n ref: RefCallback<HTMLElement>;\n onPointerMove(e: ReactPointerEvent): void;\n onPointerUp(e: ReactPointerEvent): void;\n onPointerCancel(e: ReactPointerEvent): void;\n };\n state: ReorderDragState;\n}\n\ninterface PendingState {\n id: string;\n sourceIndex: number;\n startX: number;\n startY: number;\n pointerId: number;\n}\n\ninterface ActiveState extends PendingState {\n draggedIds: string[];\n targetIndex: number;\n}\n\nexport function useReorderDragList(opts: UseReorderDragListOptions): ReorderDragHandlers {\n const { threshold = 4 } = opts;\n const optsRef = useRef(opts);\n optsRef.current = opts;\n const containerRef = useRef<HTMLElement | null>(null);\n const pendingRef = useRef<PendingState | null>(null);\n const activeRef = useRef<ActiveState | null>(null);\n const [state, setState] = useState<ReorderDragState>({ draggedIds: null, targetIndex: null });\n\n const computeTargetIndex = useCallback((clientY: number): number => {\n const items = optsRef.current.items;\n // Locked rows act as walls — drops cannot cross them. Cap at the\n // first locked row's index (or items.length if none are locked).\n const firstLocked = items.findIndex((it) => it.locked);\n const cap = firstLocked === -1 ? items.length : firstLocked;\n const c = containerRef.current;\n if (!c) return 0;\n const rows = Array.from(c.children) as HTMLElement[];\n let raw = rows.length;\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n if (!row) continue;\n const r = row.getBoundingClientRect();\n if (clientY < r.bottom) { raw = i; break; }\n }\n return Math.min(raw, cap);\n }, []);\n\n const refCb = useCallback<RefCallback<HTMLElement>>((el) => {\n containerRef.current = el;\n }, []);\n\n const onPointerDownRow = useCallback((id: string, index: number, e: ReactPointerEvent) => {\n // Locked items cannot be dragged — skip recording the pending state so\n // pointer-move cannot engage. Plain click still works because LayerList\n // tracks click intent in its own ref, separate from drag candidacy.\n const item = optsRef.current.items[index];\n if (item?.locked) return;\n // Capture the pointer to the row so subsequent move/up events keep firing\n // (on the row, bubbling to the container) even when the user drags\n // outside the list's bounding box. Without capture, releasing outside\n // the container leaves the drag state stuck because pointerup fires on\n // the document, not the list.\n try { (e.currentTarget as Element).setPointerCapture?.(e.pointerId); } catch { /* unsupported / already captured */ }\n pendingRef.current = {\n id,\n sourceIndex: index,\n startX: e.clientX,\n startY: e.clientY,\n pointerId: e.pointerId,\n };\n }, []);\n\n const reset = useCallback(() => {\n pendingRef.current = null;\n activeRef.current = null;\n setState({ draggedIds: null, targetIndex: null });\n }, []);\n\n const onPointerMove = useCallback((e: ReactPointerEvent) => {\n const active = activeRef.current;\n if (active) {\n const targetIndex = computeTargetIndex(e.clientY);\n if (targetIndex !== active.targetIndex) {\n active.targetIndex = targetIndex;\n setState({ draggedIds: active.draggedIds, targetIndex });\n }\n return;\n }\n const pending = pendingRef.current;\n if (!pending) return;\n const dx = e.clientX - pending.startX;\n const dy = e.clientY - pending.startY;\n if (Math.hypot(dx, dy) < threshold) return;\n // Engage.\n const selected = optsRef.current.selectedIds;\n const inSelection = selected.includes(pending.id);\n const draggedIds = inSelection ? [...selected] : [pending.id];\n const targetIndex = computeTargetIndex(e.clientY);\n activeRef.current = { ...pending, draggedIds, targetIndex };\n setState({ draggedIds, targetIndex });\n }, [computeTargetIndex, threshold]);\n\n const onPointerUp = useCallback((e: ReactPointerEvent) => {\n const active = activeRef.current;\n if (!active) {\n reset();\n return;\n }\n const targetIndex = computeTargetIndex(e.clientY);\n // Skip no-op: target lands inside the dragged-ids contiguous block.\n const items = optsRef.current.items;\n const indices = active.draggedIds\n .map((id) => items.findIndex((it) => it.id === id))\n .filter((i) => i >= 0)\n .sort((a, b) => a - b);\n const isContiguous =\n indices.length > 0 &&\n indices.every((v, i) => {\n if (i === 0) return true;\n const prev = indices[i - 1];\n return prev !== undefined && v === prev + 1;\n });\n const first = indices[0];\n const last = indices[indices.length - 1];\n const wouldBeNoop =\n isContiguous &&\n first !== undefined &&\n last !== undefined &&\n targetIndex >= first &&\n targetIndex <= last + 1;\n if (!wouldBeNoop) {\n optsRef.current.onReorder(active.draggedIds, targetIndex);\n }\n reset();\n }, [computeTargetIndex, reset]);\n\n const onPointerCancel = useCallback(() => {\n reset();\n }, [reset]);\n\n return {\n rowProps: (id, index) => ({\n onPointerDown: (e) => onPointerDownRow(id, index, e),\n }),\n containerProps: {\n ref: refCb,\n onPointerMove,\n onPointerUp,\n onPointerCancel,\n },\n state,\n };\n}\n",".grid {\n position: relative;\n width: 100%;\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-size: 11px;\n}\n\n.table th,\n.table td {\n text-align: left;\n padding: 3px 6px;\n vertical-align: middle;\n}\n.table tbody tr {\n /* Subtle row separator — was a full-weight border on every cell.\n Drastically toned down per visual-weight feedback. */\n border-bottom: 1px solid rgba(255, 255, 255, 0.04);\n}\n\n.table th {\n font-weight: 600;\n color: var(--wzl-fg-muted);\n position: sticky;\n top: 0;\n background: var(--wzl-surface, #2a2018);\n z-index: 1;\n border-bottom: 1px solid var(--wzl-border);\n}\n\n.sortable {\n cursor: pointer;\n user-select: none;\n}\n.sortable:hover { color: var(--wzl-fg, #e6e7e9); }\n.sortActive { color: var(--wzl-fg, #e6e7e9); }\n\n.empty {\n color: var(--wzl-fg-muted);\n font-style: italic;\n padding: 8px 0;\n text-align: center;\n}\n\n/* Drag-handle column. */\n.handleCol { width: 14px; }\n.handleCell {\n width: 14px;\n cursor: grab;\n color: var(--wzl-fg-muted);\n user-select: none;\n text-align: center;\n}\n.handleCell:active { cursor: grabbing; }\n\n.dragging { opacity: 0.4; }\n\n.dropIndicator {\n position: absolute;\n left: 0;\n right: 0;\n height: 2px;\n background: var(--wzl-accent, #7fb069);\n pointer-events: none;\n}\n","/**\n * Lightweight sortable data grid. Use for inspector tables — action\n * registries, route maps, telemetry rows. Intentionally narrow:\n *\n * - Sortable columns (click header to cycle asc → desc → none)\n * - Custom cell render via per-column `render`\n * - Optional drag handles for row reordering (when `onReorder` is set)\n *\n * Not: virtual scrolling, column resizing, multi-column sort, filtering,\n * inline editing. Reach for a real grid library when you need those.\n */\nimport { Fragment, useMemo, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { useReorderDragList } from '../../useReorderDragList';\nimport s from './DataGrid.module.css';\n\nexport interface DataGridColumn<Row> {\n id: string;\n header: ReactNode;\n /** Pull a sortable value from the row. Defaults to `(row as any)[column.id]`. */\n accessor?: (row: Row) => string | number | null | undefined;\n /** Render the cell. Defaults to `String(accessor(row) ?? '')`. */\n render?: (row: Row) => ReactNode;\n /** Default true. Set false to suppress the sort affordance on this column. */\n sortable?: boolean;\n /** Optional CSS class on every <td> in this column. */\n className?: string;\n}\n\nexport interface DataGridProps<Row extends { id: string }> {\n rows: readonly Row[];\n columns: readonly DataGridColumn<Row>[];\n /** Initial sort. Omit for unsorted (rows render in input order). */\n defaultSort?: { columnId: string; direction: 'asc' | 'desc' };\n /** Enable drag handles in a leading column. Receives the reorder spec\n * (the existing `useReorderDragList` semantics — see weasel-ui). */\n onReorder?: (ids: string[], targetIndex: number) => void;\n /** Empty-state row text. Default `'—'`. */\n empty?: ReactNode;\n className?: string;\n}\n\ntype SortState = { columnId: string; direction: 'asc' | 'desc' } | null;\n\nexport function DataGrid<Row extends { id: string }>(props: DataGridProps<Row>) {\n const { rows, columns, defaultSort, onReorder, empty = '—', className } = props;\n const [sort, setSort] = useState<SortState>(defaultSort ?? null);\n\n const sortedRows = useMemo(() => {\n if (!sort) return [...rows];\n const col = columns.find((c) => c.id === sort.columnId);\n if (!col) return [...rows];\n const get = col.accessor ?? ((row: Row) => (row as unknown as Record<string, unknown>)[col.id] as string | number | null | undefined);\n const dir = sort.direction === 'asc' ? 1 : -1;\n return [...rows].sort((a, b) => {\n const av = get(a);\n const bv = get(b);\n if (av == null && bv == null) return 0;\n if (av == null) return 1;\n if (bv == null) return -1;\n if (av < bv) return -1 * dir;\n if (av > bv) return 1 * dir;\n return 0;\n });\n }, [rows, columns, sort]);\n\n const cycleSort = (columnId: string) => {\n setSort((cur) => {\n if (!cur || cur.columnId !== columnId) return { columnId, direction: 'asc' };\n if (cur.direction === 'asc') return { columnId, direction: 'desc' };\n return null;\n });\n };\n\n // Drag handles via useReorderDragList. Adapter: the hook expects\n // `{ id, label }`-shaped items; we map our rows to that shape (label\n // unused — the hook only uses id and locked).\n const drag = useReorderDragList({\n items: sortedRows.map((r) => ({ id: r.id, label: '' })),\n selectedIds: [],\n onReorder: onReorder ?? (() => {}),\n });\n const dragEnabled = !!onReorder;\n\n const cls = [s.grid, className].filter(Boolean).join(' ');\n\n return (\n <div\n className={cls}\n ref={dragEnabled ? (drag.containerProps.ref as React.RefCallback<HTMLDivElement>) : undefined}\n onPointerMove={dragEnabled ? drag.containerProps.onPointerMove : undefined}\n onPointerUp={dragEnabled ? drag.containerProps.onPointerUp : undefined}\n onPointerCancel={dragEnabled ? drag.containerProps.onPointerCancel : undefined}\n >\n <table className={s.table}>\n <thead>\n <tr>\n {dragEnabled && <th className={s.handleCol} aria-label=\"drag\" />}\n {columns.map((col) => {\n const sortable = col.sortable !== false;\n const active = sort?.columnId === col.id;\n const indicator = active ? (sort.direction === 'asc' ? ' ↑' : ' ↓') : '';\n return (\n <th\n key={col.id}\n className={[col.className, sortable ? s.sortable : '', active ? s.sortActive : '']\n .filter(Boolean).join(' ')}\n onClick={sortable ? () => cycleSort(col.id) : undefined}\n >\n {col.header}{indicator}\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody>\n {sortedRows.length === 0 && (\n <tr>\n <td colSpan={columns.length + (dragEnabled ? 1 : 0)} className={s.empty}>\n {empty}\n </td>\n </tr>\n )}\n {sortedRows.map((row, i) => {\n const isDragging = drag.state.draggedIds?.includes(row.id) ?? false;\n return (\n <Fragment key={row.id}>\n <tr className={isDragging ? s.dragging : undefined}>\n {dragEnabled && (\n <td\n className={s.handleCell}\n onPointerDown={(e) => drag.rowProps(row.id, i).onPointerDown(e)}\n >\n <span aria-hidden=\"true\">⋮⋮</span>\n </td>\n )}\n {columns.map((col) => {\n const get = col.accessor ?? ((r: Row) => (r as unknown as Record<string, unknown>)[col.id] as string | number | null | undefined);\n const content = col.render ? col.render(row) : String(get(row) ?? '');\n return (\n <td key={col.id} className={col.className}>\n {content}\n </td>\n );\n })}\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n {dragEnabled && drag.state.targetIndex !== null && (\n <div\n className={s.dropIndicator}\n style={{ top: `${drag.state.targetIndex * 28}px` }}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,260 @@
1
+ import { t as e } from "./Slider-Di2kNqVy.js";
2
+ import { t } from "./ToggleBar-Defj6Asn.js";
3
+ import { t as n } from "./ColorField-sGLnThpB.js";
4
+ import { useCallback as r, useRef as i } from "react";
5
+ import { gradientGeometry as a, sampleGradientStops as o, useHandleDrag as s, withGradientKind as c } from "@weasel-js/core";
6
+ import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
7
+ //#region src/paintGradientTrack.tsx
8
+ var f = {
9
+ angleDeg: 135,
10
+ stripe: 2,
11
+ gap: 4,
12
+ dim: 75
13
+ };
14
+ function p(e) {
15
+ let { gradient: t, samples: n = 16, activeRange: r, hatch: i } = e;
16
+ return (e) => {
17
+ let a = [];
18
+ for (let e = 0; e <= n; e++) {
19
+ let r = e / n;
20
+ a.push(`${t(r)} ${(r * 100).toFixed(1)}%`);
21
+ }
22
+ let o = `linear-gradient(to right, ${a.join(", ")})`, s = [];
23
+ if (r) {
24
+ let t = e.valueToFraction(r[0]) * 100, n = e.valueToFraction(r[1]) * 100, a = {
25
+ ...f,
26
+ ...i
27
+ }, o = `repeating-linear-gradient(${a.angleDeg}deg, transparent 0 ${a.stripe}px, var(--wzl-surface) ${a.stripe}px ${a.stripe + a.gap}px)`, c = `color-mix(in srgb, var(--wzl-surface) ${a.dim}%, transparent)`, l = `linear-gradient(${c}, ${c})`;
28
+ if (t > 0 && (s.push(`${l} left 0 / ${t.toFixed(2)}% 100% no-repeat`), s.push(`${o} left 0 / ${t.toFixed(2)}% 100% no-repeat`)), n < 100) {
29
+ let e = (100 - n).toFixed(2);
30
+ s.push(`${l} right 0 / ${e}% 100% no-repeat`), s.push(`${o} right 0 / ${e}% 100% no-repeat`);
31
+ }
32
+ }
33
+ return s.push(o), /* @__PURE__ */ u("div", { style: {
34
+ position: "absolute",
35
+ inset: 0,
36
+ background: s.join(", ")
37
+ } });
38
+ };
39
+ }
40
+ var m = {
41
+ root: "_root_15yko_1",
42
+ swatches: "_swatches_15yko_8",
43
+ swatch: "_swatch_15yko_8"
44
+ }, h = [
45
+ {
46
+ value: "linear-gradient",
47
+ label: "Linear"
48
+ },
49
+ {
50
+ value: "radial-gradient",
51
+ label: "Radial"
52
+ },
53
+ {
54
+ value: "conic-gradient",
55
+ label: "Conic"
56
+ }
57
+ ], g = 2;
58
+ function _(i) {
59
+ let { value: a, onInput: s, onChange: l, kindSwitch: f = !0, className: _ } = i, v = a.stops, y = r((e) => ({
60
+ ...a,
61
+ stops: e
62
+ }), [a]), b = v.map((e) => ({
63
+ value: e.offset,
64
+ color: e.color
65
+ })), x = (e) => e.map((e) => ({
66
+ offset: e.value,
67
+ color: e.color
68
+ })), S = (e, t) => v.map((n, r) => r === e ? {
69
+ ...n,
70
+ color: t
71
+ } : n), C = v.map((e, t) => ({
72
+ stop: e,
73
+ index: t
74
+ })).sort((e, t) => e.stop.offset - t.stop.offset);
75
+ return /* @__PURE__ */ d("div", {
76
+ className: [m.root, _].filter(Boolean).join(" "),
77
+ children: [
78
+ f && /* @__PURE__ */ u(t, {
79
+ items: h,
80
+ value: a.fill,
81
+ size: "sm",
82
+ ariaLabel: "Gradient kind",
83
+ onChange: (e) => e && l(c(a, e))
84
+ }),
85
+ /* @__PURE__ */ u(e, {
86
+ min: 0,
87
+ max: 1,
88
+ step: .005,
89
+ constraint: "free",
90
+ thumbs: b,
91
+ ariaLabel: "Gradient stops",
92
+ readoutPlacement: "none",
93
+ onChange: (e) => s?.(y(x(e))),
94
+ onCommit: (e) => l(y(x(e))),
95
+ onAddThumb: (e) => ({
96
+ value: e,
97
+ color: o(v, e)
98
+ }),
99
+ onRemoveThumb: () => v.length > g,
100
+ renderTrack: p({
101
+ gradient: (e) => o(v, e),
102
+ samples: 32
103
+ })
104
+ }),
105
+ /* @__PURE__ */ u("div", {
106
+ className: m.swatches,
107
+ children: C.map(({ stop: e, index: t }) => /* @__PURE__ */ u(n, {
108
+ value: e.color,
109
+ alpha: !0,
110
+ "aria-label": `Stop ${t + 1} at ${Math.round(e.offset * 100)}%`,
111
+ className: m.swatch,
112
+ onInput: (e) => s?.(y(S(t, e))),
113
+ onChange: (e) => l(y(S(t, e)))
114
+ }, t))
115
+ })
116
+ ]
117
+ });
118
+ }
119
+ var v = {
120
+ overlay: "_overlay_6yu3h_3",
121
+ guide: "_guide_6yu3h_13",
122
+ handle: "_handle_6yu3h_21"
123
+ };
124
+ //#endregion
125
+ //#region src/components/GradientEditor/GradientHandles.tsx
126
+ function y(e) {
127
+ let { value: t, toScreen: n, toLocal: r, onInput: i, onChange: a, width: o, height: s, className: c } = e;
128
+ return /* @__PURE__ */ u("svg", {
129
+ className: [v.overlay, c].filter(Boolean).join(" "),
130
+ width: o,
131
+ height: s,
132
+ children: b(t, n, r, i, a)
133
+ });
134
+ }
135
+ function b(e, t, n, r, i) {
136
+ let o = (e, t) => {
137
+ t === "input" ? r?.(e) : i(e);
138
+ };
139
+ if (e.fill === "linear-gradient") {
140
+ let r = t(e.from), i = t(e.to);
141
+ return /* @__PURE__ */ d(l, { children: [
142
+ /* @__PURE__ */ u(S, {
143
+ x1: r.x,
144
+ y1: r.y,
145
+ x2: i.x,
146
+ y2: i.y
147
+ }),
148
+ /* @__PURE__ */ u(C, {
149
+ at: r,
150
+ label: "Gradient start",
151
+ onDrag: (t, r) => o({
152
+ ...e,
153
+ from: n(t)
154
+ }, r)
155
+ }),
156
+ /* @__PURE__ */ u(C, {
157
+ at: i,
158
+ label: "Gradient end",
159
+ onDrag: (t, r) => o({
160
+ ...e,
161
+ to: n(t)
162
+ }, r)
163
+ })
164
+ ] });
165
+ }
166
+ if (e.fill === "radial-gradient") {
167
+ let r = t(e.center), i = t({
168
+ x: e.center.x + e.radius,
169
+ y: e.center.y
170
+ }), a = Math.hypot(i.x - r.x, i.y - r.y);
171
+ return /* @__PURE__ */ d(l, { children: [
172
+ /* @__PURE__ */ u("circle", {
173
+ className: v.guide,
174
+ cx: r.x,
175
+ cy: r.y,
176
+ r: a
177
+ }),
178
+ /* @__PURE__ */ u(C, {
179
+ at: r,
180
+ label: "Gradient center",
181
+ onDrag: (t, r) => o({
182
+ ...e,
183
+ center: n(t)
184
+ }, r)
185
+ }),
186
+ /* @__PURE__ */ u(C, {
187
+ at: i,
188
+ label: "Gradient radius",
189
+ onDrag: (t, r) => {
190
+ let i = n(t), a = Math.hypot(i.x - e.center.x, i.y - e.center.y);
191
+ o({
192
+ ...e,
193
+ radius: Math.max(x, a)
194
+ }, r);
195
+ }
196
+ })
197
+ ] });
198
+ }
199
+ let s = t(e.center), { radius: c } = a(e), f = t({
200
+ x: e.center.x + Math.cos(e.angle) * c,
201
+ y: e.center.y + Math.sin(e.angle) * c
202
+ });
203
+ return /* @__PURE__ */ d(l, { children: [
204
+ /* @__PURE__ */ u(S, {
205
+ x1: s.x,
206
+ y1: s.y,
207
+ x2: f.x,
208
+ y2: f.y
209
+ }),
210
+ /* @__PURE__ */ u(C, {
211
+ at: s,
212
+ label: "Gradient center",
213
+ onDrag: (t, r) => o({
214
+ ...e,
215
+ center: n(t)
216
+ }, r)
217
+ }),
218
+ /* @__PURE__ */ u(C, {
219
+ at: f,
220
+ label: "Gradient angle",
221
+ onDrag: (t, r) => {
222
+ let i = n(t), a = Math.atan2(i.y - e.center.y, i.x - e.center.x);
223
+ o({
224
+ ...e,
225
+ angle: a
226
+ }, r);
227
+ }
228
+ })
229
+ ] });
230
+ }
231
+ var x = 1;
232
+ function S(e) {
233
+ return /* @__PURE__ */ u("line", {
234
+ className: v.guide,
235
+ ...e
236
+ });
237
+ }
238
+ function C({ at: e, label: t, onDrag: n }) {
239
+ let r = i(e), a = s({
240
+ onMove: (e) => {
241
+ r.current = e, n(e, "input");
242
+ },
243
+ onEnd: () => n(r.current, "commit")
244
+ });
245
+ return /* @__PURE__ */ u("circle", {
246
+ className: v.handle,
247
+ cx: e.x,
248
+ cy: e.y,
249
+ r: w,
250
+ role: "slider",
251
+ "aria-label": t,
252
+ tabIndex: 0,
253
+ ...a
254
+ });
255
+ }
256
+ var w = 7;
257
+ //#endregion
258
+ export { _ as n, p as r, y as t };
259
+
260
+ //# sourceMappingURL=GradientEditor-Co9aGyRe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GradientEditor-Co9aGyRe.js","names":[],"sources":["../../src/paintGradientTrack.tsx","../../src/components/GradientEditor/GradientEditor.module.css","../../src/components/GradientEditor/GradientEditor.tsx","../../src/components/GradientEditor/GradientHandles.module.css","../../src/components/GradientEditor/GradientHandles.tsx"],"sourcesContent":["import type { ReactNode, CSSProperties } from 'react';\nimport type { TrackCtx } from './components/Slider';\n\nexport type GradientTrackOpts = {\n gradient: (t: number) => string;\n samples?: number;\n activeRange?: [number, number];\n hatch?: {\n angleDeg?: number;\n stripe?: number;\n gap?: number;\n dim?: number;\n };\n};\n\nconst DEFAULT_HATCH = { angleDeg: 135, stripe: 2, gap: 4, dim: 75 };\n\nexport function paintGradientTrack(opts: GradientTrackOpts): (ctx: TrackCtx) => ReactNode {\n const { gradient, samples = 16, activeRange, hatch } = opts;\n\n return (ctx: TrackCtx) => {\n const stops: string[] = [];\n for (let i = 0; i <= samples; i++) {\n const t = i / samples;\n stops.push(`${gradient(t)} ${(t * 100).toFixed(1)}%`);\n }\n const baseGradient = `linear-gradient(to right, ${stops.join(', ')})`;\n\n const layers: string[] = [];\n if (activeRange) {\n const lowPct = ctx.valueToFraction(activeRange[0]) * 100;\n const highPct = ctx.valueToFraction(activeRange[1]) * 100;\n const h = { ...DEFAULT_HATCH, ...hatch };\n const stripe = `repeating-linear-gradient(${h.angleDeg}deg, transparent 0 ${h.stripe}px, var(--wzl-surface) ${h.stripe}px ${h.stripe + h.gap}px)`;\n const dimColor = `color-mix(in srgb, var(--wzl-surface) ${h.dim}%, transparent)`;\n const dimOverlay = `linear-gradient(${dimColor}, ${dimColor})`;\n\n if (lowPct > 0) {\n layers.push(`${dimOverlay} left 0 / ${lowPct.toFixed(2)}% 100% no-repeat`);\n layers.push(`${stripe} left 0 / ${lowPct.toFixed(2)}% 100% no-repeat`);\n }\n if (highPct < 100) {\n const wR = (100 - highPct).toFixed(2);\n layers.push(`${dimOverlay} right 0 / ${wR}% 100% no-repeat`);\n layers.push(`${stripe} right 0 / ${wR}% 100% no-repeat`);\n }\n }\n layers.push(baseGradient);\n\n const style: CSSProperties = {\n position: 'absolute',\n inset: 0,\n background: layers.join(', '),\n };\n return <div style={style} />;\n };\n}\n",".root {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-inline-size: 0;\n}\n\n.swatches {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n/* Each stop's opacity slider would otherwise stretch the row to a width no\n * properties panel has; the chip stays legible, the slider yields. */\n.swatch {\n flex: 0 1 auto;\n min-inline-size: 0;\n}\n","import { useCallback, type ReactElement } from 'react';\nimport {\n sampleGradientStops,\n withGradientKind,\n type GradStop,\n type GradientFill,\n type GradientKind,\n} from '@weasel-js/core';\nimport { Slider, type Thumb } from '../Slider';\nimport { ColorField } from '../ColorField';\nimport { ToggleBar, type ToggleBarItem } from '../ToggleBar';\nimport { paintGradientTrack } from '../../paintGradientTrack';\nimport s from './GradientEditor.module.css';\n\nconst KINDS: readonly ToggleBarItem<GradientKind>[] = [\n { value: 'linear-gradient', label: 'Linear' },\n { value: 'radial-gradient', label: 'Radial' },\n { value: 'conic-gradient', label: 'Conic' },\n];\n\n/** Fewer than two stops is not a gradient any renderer can ramp between. */\nconst MIN_STOPS = 2;\n\nexport interface GradientEditorProps {\n /** The gradient being edited. */\n value: GradientFill;\n /**\n * Live value during a gesture — a stop drag, a color-picker scrub. Wire\n * it for preview; it fires many times per gesture and must not be\n * written to history.\n */\n onInput?: (next: GradientFill) => void;\n /** Committed value: one call per completed gesture. Pair with an\n * undoable write. */\n onChange: (next: GradientFill) => void;\n /** Show the linear / radial / conic switch. Default true; turn it off\n * when the surrounding UI already owns the kind. */\n kindSwitch?: boolean;\n className?: string;\n}\n\ntype StopThumb = Thumb & { color: string };\n\n/**\n * Editor for a gradient's kind and stop list.\n *\n * Geometry (`from`/`to`, `center`, `radius`, `angle`) is deliberately not\n * edited here — on a canvas that belongs on the artwork, via\n * `<GradientHandles>`. This component owns the parts with no spatial\n * meaning, so it composes into a properties panel at any width.\n *\n * Stops are addressed by their position in `value.stops`, which is never\n * reordered — dragging one stop past another leaves both indices alone, so\n * a drag can cross a neighbour without the two swapping under the pointer.\n * Rendering sorts a copy.\n */\nexport function GradientEditor(props: GradientEditorProps): ReactElement {\n const { value, onInput, onChange, kindSwitch = true, className } = props;\n const stops = value.stops;\n\n const withStops = useCallback(\n (next: GradStop[]): GradientFill => ({ ...value, stops: next }),\n [value],\n );\n\n const thumbs: StopThumb[] = stops.map((stop) => ({ value: stop.offset, color: stop.color }));\n\n const applyThumbs = (next: StopThumb[]): GradStop[] =>\n next.map((t) => ({ offset: t.value, color: t.color }));\n\n const setStopColor = (index: number, color: string): GradStop[] =>\n stops.map((stop, i) => (i === index ? { ...stop, color } : stop));\n\n // Sorted view for the swatch row, carrying each stop's real index so a\n // recolor writes back to the right entry.\n const ordered = stops\n .map((stop, index) => ({ stop, index }))\n .sort((a, b) => a.stop.offset - b.stop.offset);\n\n return (\n <div className={[s.root, className].filter(Boolean).join(' ')}>\n {kindSwitch && (\n <ToggleBar<GradientKind>\n items={KINDS}\n value={value.fill}\n size=\"sm\"\n ariaLabel=\"Gradient kind\"\n onChange={(kind) => kind && onChange(withGradientKind(value, kind))}\n />\n )}\n\n <Slider<StopThumb>\n min={0}\n max={1}\n step={0.005}\n constraint=\"free\"\n thumbs={thumbs}\n ariaLabel=\"Gradient stops\"\n readoutPlacement=\"none\"\n onChange={(next) => onInput?.(withStops(applyThumbs(next)))}\n onCommit={(next) => onChange(withStops(applyThumbs(next)))}\n onAddThumb={(at) => ({ value: at, color: sampleGradientStops(stops, at) })}\n onRemoveThumb={() => stops.length > MIN_STOPS}\n renderTrack={paintGradientTrack({\n gradient: (t) => sampleGradientStops(stops, t),\n samples: 32,\n })}\n />\n\n <div className={s.swatches}>\n {ordered.map(({ stop, index }) => (\n <ColorField\n key={index}\n value={stop.color}\n alpha\n aria-label={`Stop ${index + 1} at ${Math.round(stop.offset * 100)}%`}\n className={s.swatch}\n onInput={(hex) => onInput?.(withStops(setStopColor(index, hex)))}\n onChange={(hex) => onChange(withStops(setStopColor(index, hex)))}\n />\n ))}\n </div>\n </div>\n );\n}\n","/* The overlay covers the canvas but must not intercept tool input; only the\n * handles opt back into hit-testing. */\n.overlay {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n\n/* These sit over artwork of unknown color, not over the app's own surface,\n * so they are deliberately not themed: a themed handle disappears against\n * whatever the user painted underneath. White-on-dark reads on anything,\n * which is why every editor draws handles this way. */\n.guide {\n fill: none;\n stroke: #ffffff;\n stroke-opacity: 0.7;\n stroke-dasharray: 4 4;\n paint-order: stroke;\n}\n\n.handle {\n fill: #ffffff;\n stroke: #222222;\n stroke-width: 2;\n cursor: grab;\n pointer-events: auto;\n}\n\n.handle:active {\n cursor: grabbing;\n}\n\n.handle:focus-visible {\n outline: 2px solid var(--wzl-accent, #4a9eff);\n outline-offset: 2px;\n}\n","import { useRef, type ReactElement, type ReactNode } from 'react';\nimport { useHandleDrag, gradientGeometry, type GradientFill } from '@weasel-js/core';\nimport s from './GradientHandles.module.css';\n\n/** Structural, and deliberately not exported — `Plot2D` and `CurveEditor`\n * each publish their own `Point`, and a third would only be ambiguous at\n * the package barrel. Consumers pass any `{ x, y }`. */\ninterface Point {\n x: number;\n y: number;\n}\n\nexport interface GradientHandlesProps {\n /**\n * The gradient whose geometry these handles move, in a **resolved,\n * isotropic** frame — one where `radius` is a length in the same units as\n * `center.x` and a right angle is a right angle.\n *\n * A `units: 'bounds'` gradient is not such a frame: `x` and `y` are\n * fractions of two different lengths, so a circle there is an ellipse on\n * screen and polar math silently mixes scales. Resolve it first with\n * `fillInPoseFrame(fill, box)` and convert edits back with\n * `fillToBoundsFrame(next, box)`.\n */\n value: GradientFill;\n /**\n * Gradient space → overlay pixels. For a `units: 'local'` gradient this\n * is the node's local-to-screen transform; for `'world'`, the view.\n */\n toScreen: (p: Point) => Point;\n /** Overlay pixels → gradient space. Must invert `toScreen`. */\n toLocal: (p: Point) => Point;\n /** Live during a drag — wire for preview, do not write to history. */\n onInput?: (next: GradientFill) => void;\n /** Committed at drag end: one call per gesture. */\n onChange: (next: GradientFill) => void;\n /** Overlay size in CSS pixels. */\n width: number;\n height: number;\n className?: string;\n}\n\n/**\n * Direct-manipulation handles for a gradient's geometry, drawn as an SVG\n * overlay above a canvas: endpoints for linear, center and radius for\n * radial, center and angle arm for conic.\n *\n * Positioning is entirely the consumer's `toScreen` / `toLocal` — this\n * component never sees a view or a scene node, so the same handles serve a\n * node-local gradient, a world-space one, and a plain unzoomed preview.\n *\n * The overlay ignores pointer events except on the handles themselves, so\n * it can sit over live canvas content without swallowing tool input.\n */\nexport function GradientHandles(props: GradientHandlesProps): ReactElement {\n const { value, toScreen, toLocal, onInput, onChange, width, height, className } = props;\n\n return (\n <svg\n className={[s.overlay, className].filter(Boolean).join(' ')}\n width={width}\n height={height}\n >\n {renderForKind(value, toScreen, toLocal, onInput, onChange)}\n </svg>\n );\n}\n\nfunction renderForKind(\n value: GradientFill,\n toScreen: (p: Point) => Point,\n toLocal: (p: Point) => Point,\n onInput: ((next: GradientFill) => void) | undefined,\n onChange: (next: GradientFill) => void,\n): ReactNode {\n const emit = (next: GradientFill, phase: 'input' | 'commit'): void => {\n if (phase === 'input') onInput?.(next);\n else onChange(next);\n };\n\n if (value.fill === 'linear-gradient') {\n const from = toScreen(value.from);\n const to = toScreen(value.to);\n return (\n <>\n <Guide x1={from.x} y1={from.y} x2={to.x} y2={to.y} />\n <DragPoint\n at={from}\n label=\"Gradient start\"\n onDrag={(p, phase) => emit({ ...value, from: toLocal(p) }, phase)}\n />\n <DragPoint\n at={to}\n label=\"Gradient end\"\n onDrag={(p, phase) => emit({ ...value, to: toLocal(p) }, phase)}\n />\n </>\n );\n }\n\n if (value.fill === 'radial-gradient') {\n const center = toScreen(value.center);\n // The radius handle rides the +x axis of gradient space, so it stays on\n // the drawn circle under a rotated or anisotropic transform.\n const edge = toScreen({ x: value.center.x + value.radius, y: value.center.y });\n const screenRadius = Math.hypot(edge.x - center.x, edge.y - center.y);\n return (\n <>\n <circle className={s.guide} cx={center.x} cy={center.y} r={screenRadius} />\n <DragPoint\n at={center}\n label=\"Gradient center\"\n onDrag={(p, phase) => emit({ ...value, center: toLocal(p) }, phase)}\n />\n <DragPoint\n at={edge}\n label=\"Gradient radius\"\n onDrag={(p, phase) => {\n const local = toLocal(p);\n const radius = Math.hypot(local.x - value.center.x, local.y - value.center.y);\n emit({ ...value, radius: Math.max(MIN_RADIUS, radius) }, phase);\n }}\n />\n </>\n );\n }\n\n const center = toScreen(value.center);\n const { radius } = gradientGeometry(value);\n const tip = toScreen({\n x: value.center.x + Math.cos(value.angle) * radius,\n y: value.center.y + Math.sin(value.angle) * radius,\n });\n return (\n <>\n <Guide x1={center.x} y1={center.y} x2={tip.x} y2={tip.y} />\n <DragPoint\n at={center}\n label=\"Gradient center\"\n onDrag={(p, phase) => emit({ ...value, center: toLocal(p) }, phase)}\n />\n <DragPoint\n at={tip}\n label=\"Gradient angle\"\n onDrag={(p, phase) => {\n const local = toLocal(p);\n const angle = Math.atan2(local.y - value.center.y, local.x - value.center.x);\n emit({ ...value, angle }, phase);\n }}\n />\n </>\n );\n}\n\n/** A radius of zero divides by zero in the shader's `t`; keep it off the floor. */\nconst MIN_RADIUS = 1;\n\nfunction Guide(props: { x1: number; y1: number; x2: number; y2: number }): ReactElement {\n return <line className={s.guide} {...props} />;\n}\n\nfunction DragPoint({\n at,\n label,\n onDrag,\n}: {\n at: Point;\n label: string;\n onDrag: (p: Point, phase: 'input' | 'commit') => void;\n}): ReactElement {\n // `useHandleDrag` reports the pointer on move but not on end, so the last\n // position is held here to commit with — otherwise releasing the pointer\n // would write whatever the gradient held before the drag began.\n const last = useRef<Point>(at);\n const drag = useHandleDrag<SVGCircleElement>({\n onMove: (p) => {\n last.current = p;\n onDrag(p, 'input');\n },\n onEnd: () => onDrag(last.current, 'commit'),\n });\n return (\n <circle\n className={s.handle}\n cx={at.x}\n cy={at.y}\n r={HANDLE_RADIUS}\n role=\"slider\"\n aria-label={label}\n tabIndex={0}\n {...drag}\n />\n );\n}\n\nconst HANDLE_RADIUS = 7;\n"],"mappings":"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"}
@@ -3,9 +3,9 @@ import { forwardRef as t } from "react";
3
3
  import { FieldError as n, Input as r, Label as i, Text as a, TextField as o } from "react-aria-components";
4
4
  import { jsx as s, jsxs as c } from "react/jsx-runtime";
5
5
  var l = {
6
- field: "_field_uwe3t_1",
7
- frame: "_frame_uwe3t_9",
8
- adornment: "_adornment_uwe3t_54"
6
+ field: "_field_cahom_1",
7
+ frame: "_frame_cahom_9",
8
+ adornment: "_adornment_cahom_54"
9
9
  }, u = t(function(t, u) {
10
10
  let { label: d, description: f, errorMessage: p, placeholder: m, leadingAdornment: h, trailingAdornment: g, className: _, ...v } = t;
11
11
  return /* @__PURE__ */ c(o, {
@@ -52,4 +52,4 @@ var l = {
52
52
  //#endregion
53
53
  export { u as t };
54
54
 
55
- //# sourceMappingURL=Input-D_Xzgr2b.js.map
55
+ //# sourceMappingURL=Input-qk44ESKC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Input-qk44ESKC.js","names":[],"sources":["../../src/components/Input/Input.module.css","../../src/components/Input/Input.tsx"],"sourcesContent":[".field {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n gap: 4px;\n}\n\n.frame {\n display: flex;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 8px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n color: var(--wzl-fg);\n font-family: var(--wzl-font-ui);\n font-size: 13px;\n line-height: 1;\n transition: border-color var(--wzl-motion-fast), box-shadow var(--wzl-motion-fast);\n}\n\n.frame:focus-within {\n border-color: var(--wzl-focus-ring);\n box-shadow: 0 0 0 1px var(--wzl-focus-ring);\n}\n\n.field[data-invalid] .frame {\n border-color: var(--wzl-danger, #ff5b5b);\n}\n\n.field[data-disabled] .frame {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.frame input {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: none;\n outline: none;\n color: inherit;\n font: inherit;\n padding: 0;\n}\n\n.frame input::placeholder {\n color: var(--wzl-fg-subtle);\n}\n\n.adornment {\n display: inline-flex;\n align-items: center;\n color: var(--wzl-fg-subtle);\n font-size: 12px;\n pointer-events: none;\n}\n","import { forwardRef, type ReactNode, type Ref } from 'react';\nimport {\n TextField,\n Label,\n Input as RACInput,\n Text,\n FieldError,\n type TextFieldProps as RACTextFieldProps,\n type ValidationResult,\n} from 'react-aria-components';\nimport { fieldClasses } from '../Field/Field';\nimport s from './Input.module.css';\n\nexport type InputProps = Omit<RACTextFieldProps, 'children' | 'className'> & {\n label?: ReactNode;\n description?: ReactNode;\n errorMessage?: ReactNode | ((v: ValidationResult) => ReactNode);\n placeholder?: string;\n leadingAdornment?: ReactNode;\n trailingAdornment?: ReactNode;\n className?: string;\n};\n\n/**\n * Single-line text input wrapping React Aria's TextField. Supplies a\n * default skin against the `--wzl-*` token system, and exposes the\n * familiar label / description / errorMessage / adornment slot shape.\n *\n * `ref` forwards to the underlying `<input>`.\n */\nexport const Input = forwardRef(function Input(\n props: InputProps,\n ref: Ref<HTMLInputElement>,\n) {\n const {\n label,\n description,\n errorMessage,\n placeholder,\n leadingAdornment,\n trailingAdornment,\n className,\n ...textFieldProps\n } = props;\n\n return (\n <TextField {...textFieldProps} className={[s.field, fieldClasses.root, className].filter(Boolean).join(' ')}>\n {label !== undefined && <Label className={fieldClasses.label}>{label}</Label>}\n <div className={s.frame}>\n {leadingAdornment !== undefined && <span className={s.adornment}>{leadingAdornment}</span>}\n <RACInput ref={ref} placeholder={placeholder} />\n {trailingAdornment !== undefined && <span className={s.adornment}>{trailingAdornment}</span>}\n </div>\n {description !== undefined && (\n <Text slot=\"description\" className={fieldClasses.hint}>\n {description}\n </Text>\n )}\n <FieldError className={fieldClasses.error}>{errorMessage}</FieldError>\n </TextField>\n );\n});\n"],"mappings":";;;;;;;;GC8Ba,IAAQ,EAAW,SAC9B,GACA,GACA;CACA,IAAM,EACJ,UACA,gBACA,iBACA,gBACA,qBACA,sBACA,cACA,GAAG,MACD;AAEJ,QACE,kBAAC,GAAD;EAAW,GAAI;EAAgB,WAAW;GAAC,EAAE;GAAO,EAAa;GAAM;GAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAA3G;GACG,MAAU,KAAA,KAAa,kBAAC,GAAD;IAAO,WAAW,EAAa;cAAQ;IAAc,CAAA;GAC7E,kBAAC,OAAD;IAAK,WAAW,EAAE;cAAlB;KACG,MAAqB,KAAA,KAAa,kBAAC,QAAD;MAAM,WAAW,EAAE;gBAAY;MAAwB,CAAA;KAC1F,kBAAC,GAAD;MAAe;MAAkB;MAAe,CAAA;KAC/C,MAAsB,KAAA,KAAa,kBAAC,QAAD;MAAM,WAAW,EAAE;gBAAY;MAAyB,CAAA;KACxF;;GACL,MAAgB,KAAA,KACf,kBAAC,GAAD;IAAM,MAAK;IAAc,WAAW,EAAa;cAC9C;IACI,CAAA;GAET,kBAAC,GAAD;IAAY,WAAW,EAAa;cAAQ;IAA0B,CAAA;GAC5D;;EAEd"}
@@ -1,10 +1,10 @@
1
1
  import { Fragment as e } from "react";
2
2
  import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
3
  var r = {
4
- keys: "_keys_1ve0i_2",
5
- keysEmpty: "_keysEmpty_1ve0i_16",
6
- sep: "_sep_1ve0i_20",
7
- key: "_key_1ve0i_2"
4
+ keys: "_keys_n4bkk_2",
5
+ keysEmpty: "_keysEmpty_n4bkk_16",
6
+ sep: "_sep_n4bkk_20",
7
+ key: "_key_n4bkk_2"
8
8
  }, i = new Set([
9
9
  "⌘",
10
10
  "⇪",
@@ -394,4 +394,4 @@ function p(e, t = {}) {
394
394
  //#endregion
395
395
  export { s as a, c as i, p as n, o, d as r, u as t };
396
396
 
397
- //# sourceMappingURL=Keycaps-B9dJMYx_.js.map
397
+ //# sourceMappingURL=Keycaps-CFX7UAj8.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Keycaps-CFX7UAj8.js","names":[],"sources":["../../src/components/Keycaps/Keycaps.module.css","../../src/components/Keycaps/Keycap.tsx","../../src/components/Keycaps/Keycaps.tsx","../../src/components/Keycaps/keySpecsFromMods.ts"],"sourcesContent":["/* Keystroke \"key cap\" styling — each modifier and key in its own bordered chip. */\n.keys {\n display: inline-flex;\n gap: 3px;\n /* Bottom-align so chips with text labels and chips with icon glyphs\n (arrows, modifier symbols) line up at the same bottom edge. Baseline\n drifts because text baselines sit above icon centers. */\n align-items: flex-end;\n /* When this whole sequence sits inline in surrounding text (e.g.\n \"Press <KeySequence> to confirm.\"), the row anchors to the\n surrounding line's bottom edge, not its baseline. */\n vertical-align: bottom;\n flex-wrap: wrap;\n}\n\n.keysEmpty {\n color: var(--wzl-fg-muted);\n}\n\n.sep {\n color: var(--wzl-fg-muted);\n font-size: 11px;\n line-height: 1;\n}\n\n.key {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n height: 18px;\n padding: 0 4px;\n /* Light face, slightly-darker-than-face border, dark glyph — reads as\n a real keycap rather than a recessed slot in the panel. */\n background: var(--wzl-fg, #e6e7e9);\n border: 1px solid #25272c;\n border-bottom-width: 2px;\n border-radius: 3px;\n color: var(--wzl-surface);\n /* Keycaps are a deliberate exception to the site theme — the design-\n system UI font (often a display face like Oswald) is wrong for\n keyboard chips. Use a neutral sans stack so labels read like real\n key legends. Consumers wanting a specific face per chip pass the\n `font` prop on KeyCap. */\n font-family: ui-sans-serif, system-ui, sans-serif;\n font-size: 11px;\n font-weight: 700;\n line-height: 1;\n}\n\n/* Default chip is square — letters, digits, and single glyphs (⎋ ⌫ ↑ etc.)\n sit in a uniform key-cap box. */\n.key[data-kind='square'] {\n width: 18px;\n padding: 0;\n}\n\n/* Modifiers (⌘ ⇪ ⌥ ⌃) are wider to match the visual weight of how they\n appear on a real keyboard — and to differentiate them from the keys\n they modify in a stack. */\n.key[data-kind='modifier'] {\n min-width: 26px;\n padding: 0 6px;\n}\n\n/* Tab / Enter / Space — actual wide keys on a real keyboard. */\n.key[data-kind='wide'] {\n min-width: 32px;\n padding: 0 8px;\n}\n\n/* Optional/inverted (default variant): face flips to dark; legend drops\n to 60% opacity; dotted border drops to 40% opacity. Three soft cues\n stacked for \"may be held but isn't required.\" */\n.key[data-inverted] {\n background: var(--wzl-surface);\n color: color-mix(in srgb, var(--wzl-fg, #e6e7e9) 60%, transparent);\n border-style: dotted;\n border-color: color-mix(in srgb, var(--wzl-fg, #e6e7e9) 40%, transparent);\n border-width: 1.5px;\n border-bottom-width: 1.5px;\n}\n\n/* Minimal variant — no fill, borders and legend follow currentColor.\n Useful inline in colored prose / next to colored badges where the\n chip should take the surrounding text color. */\n.key[data-variant='minimal'] {\n background: transparent;\n border-color: currentColor;\n color: currentColor;\n}\n\n/* Optional + minimal: dotted border at full currentColor, legend at full\n currentColor. The dotted pattern alone carries the \"optional\" cue here\n — minimal's whole point is to defer color to the surrounding context,\n so dimming would fight that. (Default variant uses graded opacity as a\n stacked cue; minimal keeps it crisp.) */\n.key[data-variant='minimal'][data-inverted] {\n border-style: dotted;\n border-color: currentColor;\n color: currentColor;\n border-width: 1.5px;\n border-bottom-width: 1.5px;\n}\n","import type { CSSProperties } from 'react';\nimport s from './Keycaps.module.css';\n\nconst MODIFIER_GLYPHS = new Set(['⌘', '⇪', '⌥', '⌃', '⇧']);\nconst WIDE_GLYPHS = new Set(['⇥', '↵', '␣']);\n\nexport type KeycapKind = 'modifier' | 'wide' | 'square';\n\nexport function inferKeycapKind(label: string): KeycapKind {\n if (MODIFIER_GLYPHS.has(label)) return 'modifier';\n if (WIDE_GLYPHS.has(label)) return 'wide';\n if (label.length > 1) return 'wide';\n return 'square';\n}\n\nexport type KeyCapVariant = 'default' | 'minimal';\n\nexport interface KeyCapProps {\n /** Glyph rendered in the chip (modifier or key). */\n label: string;\n /** Marks the chip as not required to trigger the action. In the default\n * variant the chip face inverts (dark face / light glyph) for\n * emphasis. In the `'minimal'` variant the chip's border becomes\n * dotted to read as \"may be held, but isn't required.\" */\n inverted?: boolean;\n /** Visual style. `'default'` (default) renders a filled chip; `'minimal'`\n * renders an unfilled chip whose border and legend are `currentColor`\n * — useful inline in colored prose / next to colored badges where the\n * chip should take the surrounding text color. */\n variant?: KeyCapVariant;\n className?: string;\n /** Optional inline style. Useful for one-off width overrides (e.g.\n * building a keyboard-layout where the space bar spans several\n * standard-key widths). The component sets no inline styles of its\n * own — everything else comes from the CSS module. */\n style?: CSSProperties;\n /** Override the chip's font-family. Accepts any CSS font-family\n * string. When omitted, the chip inherits from the design-system\n * UI font token (`--wzl-font-ui`). Useful for one-off cases where\n * a different face is desired — though the canonical move is to\n * override the CSS variable at the consumer's scope, not the prop. */\n font?: string;\n}\n\n/** Single bordered keycap chip for one glyph (modifier or key). Use\n * `KeySequence` to render a full shortcut. */\nexport function KeyCap({ label, inverted = false, variant = 'default', className, style, font }: KeyCapProps) {\n const resolvedStyle = font ? { ...style, fontFamily: font } : style;\n return (\n <kbd\n className={[s.key, className].filter(Boolean).join(' ')}\n data-kind={inferKeycapKind(label)}\n data-variant={variant === 'default' ? undefined : variant}\n data-inverted={inverted || undefined}\n style={resolvedStyle}\n >\n {label}\n </kbd>\n );\n}\n","import { Fragment } from 'react';\nimport s from './Keycaps.module.css';\nimport { KeyCap, inferKeycapKind, type KeyCapVariant } from './Keycap';\n\nexport interface KeySpec {\n /** Glyph rendered in the chip (modifier or key). */\n label: string;\n /** When true, the chip renders inverted to mark it as not required to\n * trigger the action (e.g. an optional modifier). Defaults to false. */\n optional?: boolean;\n}\n\nexport interface KeySequenceProps {\n /** Keys to render. `undefined` or empty renders a muted em-dash.\n * Modifiers are always rendered first regardless of input order; relative\n * order within each group is preserved. */\n keys: readonly KeySpec[] | undefined;\n /** Character inserted between the trailing modifier chip and the first\n * non-modifier chip (e.g. `'+'` renders `⌘ + K`). `null` or `''`\n * suppresses it. Defaults to `'+'`. */\n separator?: string | null;\n /** Forwarded to every `KeyCap` in the sequence. `'minimal'` renders\n * unfilled chips whose border + legend are `currentColor`. */\n variant?: KeyCapVariant;\n /** Forwarded to every `KeyCap` in the sequence. Overrides the design-\n * system UI font for that chip only. */\n font?: string;\n className?: string;\n}\n\n/** Renders a shortcut as a row of `KeyCap` chips, one per key. Optional\n * keys render inverted to distinguish them from required ones. */\nexport function KeySequence({ keys, separator = '+', variant = 'default', font, className }: KeySequenceProps) {\n if (!keys || keys.length === 0) {\n return <span className={[s.keysEmpty, className].filter(Boolean).join(' ')}>—</span>;\n }\n const ordered = keys\n .map((k, i) => ({ k, i }))\n .sort((a, b) => {\n const am = inferKeycapKind(a.k.label) === 'modifier' ? 0 : 1;\n const bm = inferKeycapKind(b.k.label) === 'modifier' ? 0 : 1;\n return am - bm || a.i - b.i;\n })\n .map(({ k }) => k);\n const sepIdx = ordered.findIndex((k) => inferKeycapKind(k.label) !== 'modifier');\n const showSep = !!separator && sepIdx > 0 && sepIdx < ordered.length;\n return (\n <span className={[s.keys, className].filter(Boolean).join(' ')}>\n {ordered.map((k, i) => (\n <Fragment key={i}>\n {showSep && i === sepIdx ? <span className={s.sep}>{separator}</span> : null}\n <KeyCap label={k.label} inverted={k.optional ?? false} variant={variant} font={font} />\n </Fragment>\n ))}\n </span>\n );\n}\n","import type { KeySpec } from './Keycaps';\n\n/** Logical modifier name. Matches the kit's `ModifierKey` in shape — kept as a\n * local type so `weasel-ui` stays independent of `@weasel-js/core`. */\nexport type LogicalMod = 'mod' | 'shift' | 'alt' | 'ctrl' | 'meta';\n\n/** Detected (or overridden) platform. `'mod'` resolves to ⌘ on macOS,\n * Ctrl on Windows / Linux. */\nexport type Platform = 'macos' | 'windows' | 'linux';\n\n/** Visual form of a modifier or named-key label.\n *\n * - `'auto'` (default): the per-entry, per-platform default — whatever\n * label is actually printed on the physical key. macOS keys show the\n * Apple glyphs (⌘ ⌥ ⌃ ⇧ ⎋ ↵ ⇥). Windows keys mostly show text\n * (Ctrl, Alt, Shift) BUT the Win key shows its logo (⊞) and the\n * context-menu key shows ▤. Linux mirrors Windows with Super (⊞).\n * - `'symbol'` forces the Apple-style glyph everywhere a symbolic form\n * exists. Entries without a widely-recognized symbol still fall\n * back to text.\n * - `'text'` always spells the label out (Cmd / Option / Esc / Enter). */\nexport type LegendStyle = 'auto' | 'symbol' | 'text';\n\nexport interface LogicalModSpec {\n name: LogicalMod;\n /** Marks this modifier as optional (may be held but isn't required).\n * Forwarded as the resulting `KeySpec.optional`. */\n optional?: boolean;\n}\n\nexport interface KeySpecsFromModsOptions {\n /** Override OS detection. Defaults to the detected platform, or\n * `'macos'` when detection is unavailable (e.g. in tests, or when\n * `navigator` is missing). */\n platform?: Platform;\n /** Defaults to `'auto'` (symbol on macOS, text everywhere else). Pass\n * `'symbol'` or `'text'` to force a specific style regardless of\n * platform. */\n legend?: LegendStyle;\n}\n\nconst MOD_BY_PLATFORM: Record<LogicalMod, Record<Platform, Record<LegendStyle, string>>> = {\n mod: {\n macos: { auto: '⌘', symbol: '⌘', text: 'Cmd' },\n windows: { auto: 'Ctrl', symbol: 'Ctrl', text: 'Ctrl' },\n linux: { auto: 'Ctrl', symbol: 'Ctrl', text: 'Ctrl' },\n },\n shift: {\n macos: { auto: '⇧', symbol: '⇧', text: 'Shift' },\n windows: { auto: '⇧', symbol: '⇧', text: 'Shift' },\n linux: { auto: '⇧', symbol: '⇧', text: 'Shift' },\n },\n alt: {\n macos: { auto: '⌥', symbol: '⌥', text: 'Option' },\n windows: { auto: 'Alt', symbol: 'Alt', text: 'Alt' },\n linux: { auto: 'Alt', symbol: 'Alt', text: 'Alt' },\n },\n ctrl: {\n macos: { auto: '⌃', symbol: '⌃', text: 'Control' },\n windows: { auto: 'Ctrl', symbol: 'Ctrl', text: 'Ctrl' },\n linux: { auto: 'Ctrl', symbol: 'Ctrl', text: 'Ctrl' },\n },\n // Windows/Linux Meta has a recognized symbol on the physical key (⊞ Win\n // logo / Super logo), so `auto` shows it. Use `text` for Win / Super.\n meta: {\n macos: { auto: '⌘', symbol: '⌘', text: 'Cmd' },\n windows: { auto: '⊞', symbol: '⊞', text: 'Win' },\n linux: { auto: '⊞', symbol: '⊞', text: 'Super' },\n },\n};\n\n/** Detect the user's OS from the browser environment. UA sniffing — not\n * 100% reliable, but adequate for picking a modifier-glyph convention.\n * Falls back to `'macos'` (matches the kit's docs convention) when\n * `navigator` is unavailable. */\nexport function detectPlatform(): Platform {\n if (typeof navigator === 'undefined') return 'macos';\n // Prefer the modern userAgentData when available (Chromium-only today).\n const uaData = (navigator as Navigator & { userAgentData?: { platform?: string } }).userAgentData;\n const raw = (uaData?.platform ?? navigator.userAgent ?? '').toLowerCase();\n if (raw.includes('mac') || raw.includes('darwin') || raw.includes('iphone') || raw.includes('ipad')) return 'macos';\n if (raw.includes('win')) return 'windows';\n if (raw.includes('linux') || raw.includes('x11')) return 'linux';\n return 'macos';\n}\n\n/**\n * Map a list of **logical** modifiers (`'mod'`, `'shift'`, …) to **visual**\n * `KeySpec`s appropriate for the current platform.\n *\n * The kit-side gesture grammar uses logical names so the same route reads\n * correctly on every OS — `'mod'` means \"Cmd on Mac, Ctrl on Win/Linux\".\n * `KeySequence` is purely visual and renders the labels you give it; this\n * helper is the bridge.\n *\n * ```ts\n * <KeySequence\n * keys={keySpecsFromMods([{ name: 'mod' }, { name: 'shift', optional: true }])}\n * />\n * ```\n *\n * On a Mac: renders `⌘ ⇧`. On Windows: renders `Ctrl Shift`. Pass an\n * explicit `platform` to override detection (e.g. for docs that always\n * show the macOS form). Pass `legend: 'text'` to force \"Cmd\" over \"⌘\"\n * even on macOS.\n */\nexport function keySpecsFromMods(\n mods: readonly LogicalModSpec[],\n opts: KeySpecsFromModsOptions = {},\n): readonly KeySpec[] {\n const platform = opts.platform ?? detectPlatform();\n const legend = opts.legend ?? 'auto';\n return mods.map((m) => {\n const label = MOD_BY_PLATFORM[m.name][platform][legend];\n return m.optional ? { label, optional: true } : { label };\n });\n}\n\n/** Per-platform × per-legend table for named, non-modifier keys. `auto`\n * is whatever's printed on the physical key for that platform. Arrows\n * are universal symbols on every platform. */\nconst NAMED_KEY: Record<string, Record<Platform, Record<LegendStyle, string>>> = {\n Escape: { macos: { auto: '⎋', symbol: '⎋', text: 'Esc' }, windows: { auto: 'Esc', symbol: 'Esc', text: 'Esc' }, linux: { auto: 'Esc', symbol: 'Esc', text: 'Esc' } },\n Enter: { macos: { auto: '↵', symbol: '↵', text: 'Return' }, windows: { auto: 'Enter', symbol: 'Enter', text: 'Enter' }, linux: { auto: 'Enter', symbol: 'Enter', text: 'Enter' } },\n Return: { macos: { auto: '↵', symbol: '↵', text: 'Return' }, windows: { auto: 'Enter', symbol: 'Enter', text: 'Enter' }, linux: { auto: 'Enter', symbol: 'Enter', text: 'Enter' } },\n Tab: { macos: { auto: '⇥', symbol: '⇥', text: 'Tab' }, windows: { auto: 'Tab', symbol: 'Tab', text: 'Tab' }, linux: { auto: 'Tab', symbol: 'Tab', text: 'Tab' } },\n Space: { macos: { auto: '␣', symbol: '␣', text: 'Space' }, windows: { auto: 'Space', symbol: 'Space', text: 'Space' }, linux: { auto: 'Space', symbol: 'Space', text: 'Space' } },\n ' ': { macos: { auto: '␣', symbol: '␣', text: 'Space' }, windows: { auto: 'Space', symbol: 'Space', text: 'Space' }, linux: { auto: 'Space', symbol: 'Space', text: 'Space' } },\n Backspace: { macos: { auto: '⌫', symbol: '⌫', text: 'Backspace' }, windows: { auto: 'Backspace', symbol: 'Backspace', text: 'Backspace' }, linux: { auto: 'Backspace', symbol: 'Backspace', text: 'Backspace' } },\n Delete: { macos: { auto: '⌦', symbol: '⌦', text: 'Delete' }, windows: { auto: 'Delete', symbol: 'Delete', text: 'Delete' }, linux: { auto: 'Delete', symbol: 'Delete', text: 'Delete' } },\n // Context-menu key (the right-Ctrl-area key on Windows / Linux keyboards\n // with a ▤ icon). Mac has no equivalent; falls back to text 'Menu'.\n ContextMenu: { macos: { auto: 'Menu', symbol: 'Menu', text: 'Menu' }, windows: { auto: '▤', symbol: '▤', text: 'Menu' }, linux: { auto: '▤', symbol: '▤', text: 'Menu' } },\n ArrowUp: { macos: { auto: '↑', symbol: '↑', text: '↑' }, windows: { auto: '↑', symbol: '↑', text: '↑' }, linux: { auto: '↑', symbol: '↑', text: '↑' } },\n ArrowDown: { macos: { auto: '↓', symbol: '↓', text: '↓' }, windows: { auto: '↓', symbol: '↓', text: '↓' }, linux: { auto: '↓', symbol: '↓', text: '↓' } },\n ArrowLeft: { macos: { auto: '←', symbol: '←', text: '←' }, windows: { auto: '←', symbol: '←', text: '←' }, linux: { auto: '←', symbol: '←', text: '←' } },\n ArrowRight: { macos: { auto: '→', symbol: '→', text: '→' }, windows: { auto: '→', symbol: '→', text: '→' }, linux: { auto: '→', symbol: '→', text: '→' } },\n};\n\n/**\n * Render a raw `KeyboardEvent.key` value as a platform-appropriate\n * `KeySpec`. Named non-modifier keys (Esc, Enter, Tab, Space, Backspace,\n * Delete, arrows) get the platform's conventional form. Letter / digit /\n * other keys pass through upper-cased.\n *\n * ```ts\n * keySpecFromKey('Escape', { platform: 'macos' }) // { label: '⎋' }\n * keySpecFromKey('Escape', { platform: 'windows' }) // { label: 'Esc' }\n * keySpecFromKey('p') // { label: 'P' }\n * ```\n *\n * Symbol mode is only meaningful on macOS — Windows / Linux keyboards\n * print the text form on the physical key, so symbol mode there falls\n * back to text.\n */\nexport function keySpecFromKey(\n raw: string,\n opts: KeySpecsFromModsOptions & { optional?: boolean } = {},\n): KeySpec {\n const platform = opts.platform ?? detectPlatform();\n const legend = opts.legend ?? 'auto';\n const entry = NAMED_KEY[raw];\n const label = entry ? entry[platform][legend] : raw.length === 1 ? raw.toUpperCase() : raw;\n return opts.optional ? { label, optional: true } : { label };\n}\n"],"mappings":"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"}
@@ -3,10 +3,10 @@ import { forwardRef as t } from "react";
3
3
  import { Button as n, FieldError as r, Group as i, Input as a, Label as o, NumberField as s, Text as c } from "react-aria-components";
4
4
  import { jsx as l, jsxs as u } from "react/jsx-runtime";
5
5
  var d = {
6
- field: "_field_14yuu_1",
7
- frame: "_frame_14yuu_9",
8
- steppers: "_steppers_14yuu_57",
9
- stepper: "_stepper_14yuu_57"
6
+ field: "_field_e75yx_1",
7
+ frame: "_frame_e75yx_9",
8
+ steppers: "_steppers_e75yx_57",
9
+ stepper: "_stepper_e75yx_57"
10
10
  }, f = t(function(t, f) {
11
11
  let { label: p, description: m, errorMessage: h, hideSteppers: g, placeholder: _, className: v, ...y } = t;
12
12
  return /* @__PURE__ */ u(s, {
@@ -56,4 +56,4 @@ var d = {
56
56
  //#endregion
57
57
  export { f as t };
58
58
 
59
- //# sourceMappingURL=NumberField-BQmELz32.js.map
59
+ //# sourceMappingURL=NumberField-CYhQeWoM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NumberField-CYhQeWoM.js","names":[],"sources":["../../src/components/NumberField/NumberField.module.css","../../src/components/NumberField/NumberField.tsx"],"sourcesContent":[".field {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n gap: 4px;\n}\n\n.frame {\n display: flex;\n align-items: stretch;\n height: 24px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n color: var(--wzl-fg);\n font-family: var(--wzl-font-ui);\n font-size: 13px;\n line-height: 1;\n overflow: hidden;\n transition: border-color var(--wzl-motion-fast), box-shadow var(--wzl-motion-fast);\n}\n\n.frame:focus-within {\n border-color: var(--wzl-focus-ring);\n box-shadow: 0 0 0 1px var(--wzl-focus-ring);\n}\n\n.field[data-invalid] .frame {\n border-color: var(--wzl-danger, #ff5b5b);\n}\n\n.field[data-disabled] .frame {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.frame input {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: none;\n outline: none;\n color: inherit;\n font: inherit;\n padding: 0 8px;\n text-align: right;\n -moz-appearance: textfield;\n}\n\n.frame input::-webkit-outer-spin-button,\n.frame input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n.steppers {\n display: flex;\n flex-direction: column;\n border-left: 1px solid var(--wzl-border);\n}\n\n.stepper {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n flex: 1;\n background: transparent;\n border: none;\n color: var(--wzl-fg-muted);\n cursor: pointer;\n padding: 0;\n font-size: 9px;\n line-height: 1;\n}\n\n.stepper:not(:last-child) {\n border-bottom: 1px solid var(--wzl-border);\n}\n\n.stepper[data-hovered]:not([data-disabled]) {\n background: color-mix(in srgb, var(--wzl-fg) 10%, transparent);\n color: var(--wzl-fg);\n}\n\n.stepper[data-pressed]:not([data-disabled]) {\n background: color-mix(in srgb, var(--wzl-fg) 18%, transparent);\n}\n\n.stepper[data-disabled] {\n opacity: 0.4;\n cursor: not-allowed;\n}\n","import { forwardRef, type ReactNode, type Ref } from 'react';\nimport {\n NumberField as RACNumberField,\n Label,\n Input as RACInput,\n Group,\n Button as RACButton,\n Text,\n FieldError,\n type NumberFieldProps as RACNumberFieldProps,\n type ValidationResult,\n} from 'react-aria-components';\nimport { fieldClasses } from '../Field/Field';\nimport s from './NumberField.module.css';\n\nexport type NumberFieldProps = Omit<RACNumberFieldProps, 'children' | 'className'> & {\n label?: ReactNode;\n description?: ReactNode;\n errorMessage?: ReactNode | ((v: ValidationResult) => ReactNode);\n /** Hide the up/down stepper buttons. Defaults to false. */\n hideSteppers?: boolean;\n /** Native input placeholder — e.g. `'Mixed'` for a multi-selection\n * editor with no shared value. */\n placeholder?: string;\n className?: string;\n};\n\nexport const NumberField = forwardRef(function NumberField(\n props: NumberFieldProps,\n ref: Ref<HTMLInputElement>,\n) {\n const { label, description, errorMessage, hideSteppers, placeholder, className, ...rest } = props;\n return (\n <RACNumberField\n {...rest}\n className={[s.field, fieldClasses.root, className].filter(Boolean).join(' ')}\n >\n {label !== undefined && <Label className={fieldClasses.label}>{label}</Label>}\n <Group className={s.frame}>\n <RACInput ref={ref} placeholder={placeholder} />\n {!hideSteppers && (\n <div className={s.steppers}>\n <RACButton slot=\"increment\" className={s.stepper} aria-label=\"Increment\">▲</RACButton>\n <RACButton slot=\"decrement\" className={s.stepper} aria-label=\"Decrement\">▼</RACButton>\n </div>\n )}\n </Group>\n {description !== undefined && (\n <Text slot=\"description\" className={fieldClasses.hint}>\n {description}\n </Text>\n )}\n <FieldError className={fieldClasses.error}>{errorMessage}</FieldError>\n </RACNumberField>\n );\n});\n"],"mappings":";;;;;;;;;GC2Ba,IAAc,EAAW,SACpC,GACA,GACA;CACA,IAAM,EAAE,UAAO,gBAAa,iBAAc,iBAAc,gBAAa,cAAW,GAAG,MAAS;AAC5F,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,WAAW;GAAC,EAAE;GAAO,EAAa;GAAM;GAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAF9E;GAIG,MAAU,KAAA,KAAa,kBAAC,GAAD;IAAO,WAAW,EAAa;cAAQ;IAAc,CAAA;GAC7E,kBAAC,GAAD;IAAO,WAAW,EAAE;cAApB,CACE,kBAAC,GAAD;KAAe;KAAkB;KAAe,CAAA,EAC/C,CAAC,KACA,kBAAC,OAAD;KAAK,WAAW,EAAE;eAAlB,CACE,kBAAC,GAAD;MAAW,MAAK;MAAY,WAAW,EAAE;MAAS,cAAW;gBAAY;MAAa,CAAA,EACtF,kBAAC,GAAD;MAAW,MAAK;MAAY,WAAW,EAAE;MAAS,cAAW;gBAAY;MAAa,CAAA,CAClF;OAEF;;GACP,MAAgB,KAAA,KACf,kBAAC,GAAD;IAAM,MAAK;IAAc,WAAW,EAAa;cAC9C;IACI,CAAA;GAET,kBAAC,GAAD;IAAY,WAAW,EAAa;cAAQ;IAA0B,CAAA;GACvD;;EAEnB"}
@@ -1,4 +1,4 @@
1
- import { t as e } from "./Badge-DU8ihE7Z.js";
1
+ import { t as e } from "./Badge-DZQqAV4d.js";
2
2
  import { jsx as t } from "react/jsx-runtime";
3
3
  var n = {
4
4
  row: "_row_q3wun_1",
@@ -33,4 +33,4 @@ function r({ segments: r, startCap: i = "flat", size: a, variant: o, depth: s, g
33
33
  //#endregion
34
34
  export { r as t };
35
35
 
36
- //# sourceMappingURL=Powerline-C8rddbbK.js.map
36
+ //# sourceMappingURL=Powerline-Bg9M5oBK.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Powerline-C8rddbbK.js","names":[],"sources":["../../src/components/Powerline/Powerline.module.css","../../src/components/Powerline/Powerline.tsx"],"sourcesContent":[".row {\n display: inline-flex;\n align-items: stretch;\n gap: var(--powerline-gap, 0.2em);\n}\n\n.matrix {\n display: grid;\n gap: 12px;\n}\n\n/* Reset Badge's opinionated text defaults — Powerline segments should pick up\n * the surrounding text style instead of forcing uppercase / 10px / extra\n * tracking. Consumers can still override via className on Powerline. */\n.segment {\n font-size: inherit;\n text-transform: none;\n letter-spacing: normal;\n}\n","import type { CSSProperties, ReactNode } from 'react';\nimport { Badge } from '../Badge/Badge';\nimport type { BadgeSize, BadgeTone, BadgeVariant } from '../Badge/types';\nimport type { EdgeCap } from '../Badge/bases/edgeProfiles';\nimport s from './Powerline.module.css';\n\nexport interface PowerlineSegment {\n text: ReactNode;\n /** Cap on this segment's right edge. Next segment's left edge adopts the same profile. */\n endCap?: EdgeCap;\n tone?: BadgeTone;\n variant?: BadgeVariant;\n size?: BadgeSize;\n onClick?: () => void;\n href?: string;\n 'aria-label'?: string;\n}\n\nexport interface PowerlineProps {\n segments: PowerlineSegment[];\n /** Left edge of the first segment. Defaults to 'flat'. */\n startCap?: EdgeCap;\n /** Default size for every segment (per-segment `size` wins). */\n size?: BadgeSize;\n /** Default variant for every segment (per-segment `variant` wins). */\n variant?: BadgeVariant;\n /** Protrusion depth in CSS px, passed through to every segment's base. */\n depth?: number;\n /** Visible gap between adjacent segments. Number → px; string → literal CSS length.\n * Default: `0.2em` (scales with the row's font size). Pass `0` for flush. */\n gap?: number | string;\n className?: string;\n 'aria-label'?: string;\n}\n\nexport function Powerline({\n segments,\n startCap = 'flat',\n size,\n variant,\n depth,\n gap,\n className,\n ...rest\n}: PowerlineProps) {\n const cls = [s.row, className].filter(Boolean).join(' ');\n const style: CSSProperties | undefined = gap !== undefined\n ? { ['--powerline-gap' as never]: typeof gap === 'number' ? `${gap}px` : gap }\n : undefined;\n return (\n <span className={cls} style={style} aria-label={rest['aria-label']}>\n {segments.map((seg, i) => {\n const leftEdge: EdgeCap = i === 0 ? startCap : (segments[i - 1].endCap ?? 'flat');\n const rightEdge: EdgeCap = seg.endCap ?? 'flat';\n return (\n <Badge\n key={i}\n base=\"powerline\"\n baseParams={{ leftEdge, rightEdge, ...(depth !== undefined && { depth }) }}\n tone={seg.tone}\n variant={seg.variant ?? variant}\n size={seg.size ?? size}\n onClick={seg.onClick}\n href={seg.href}\n aria-label={seg['aria-label']}\n className={s.segment}\n >\n {seg.text}\n </Badge>\n );\n })}\n </span>\n );\n}\n"],"mappings":";;;;;;;;;ACmCA,SAAgB,EAAU,EACxB,aACA,cAAW,QACX,SACA,YACA,UACA,QACA,cACA,GAAG,KACc;AAKjB,QACE,kBAAC,QAAD;EAAM,WALI,CAAC,EAAE,KAAK,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAKjC;EAAY,OAJU,MAAQ,KAAA,IAE7C,KAAA,IADA,EAAG,mBAA6B,OAAO,KAAQ,WAAW,GAAG,EAAI,MAAM,GAAK;EAG1C,cAAY,EAAK;YAClD,EAAS,KAAK,GAAK,MAIhB,kBAAC,GAAD;GAEE,MAAK;GACL,YAAY;IAAE,UANQ,MAAM,IAAI,IAAY,EAAS,IAAI,GAAG,UAAU;IAM9C,WALD,EAAI,UAAU;IAKF,GAAI,MAAU,KAAA,KAAa,EAAE,UAAO;IAAG;GAC1E,MAAM,EAAI;GACV,SAAS,EAAI,WAAW;GACxB,MAAM,EAAI,QAAQ;GAClB,SAAS,EAAI;GACb,MAAM,EAAI;GACV,cAAY,EAAI;GAChB,WAAW,EAAE;aAEZ,EAAI;GACC,EAZD,EAYC,CAEV;EACG,CAAA"}
1
+ {"version":3,"file":"Powerline-Bg9M5oBK.js","names":[],"sources":["../../src/components/Powerline/Powerline.module.css","../../src/components/Powerline/Powerline.tsx"],"sourcesContent":[".row {\n display: inline-flex;\n align-items: stretch;\n gap: var(--powerline-gap, 0.2em);\n}\n\n.matrix {\n display: grid;\n gap: 12px;\n}\n\n/* Reset Badge's opinionated text defaults — Powerline segments should pick up\n * the surrounding text style instead of forcing uppercase / 10px / extra\n * tracking. Consumers can still override via className on Powerline. */\n.segment {\n font-size: inherit;\n text-transform: none;\n letter-spacing: normal;\n}\n","import type { CSSProperties, ReactNode } from 'react';\nimport { Badge } from '../Badge/Badge';\nimport type { BadgeSize, BadgeTone, BadgeVariant } from '../Badge/types';\nimport type { EdgeCap } from '../Badge/bases/edgeProfiles';\nimport s from './Powerline.module.css';\n\nexport interface PowerlineSegment {\n text: ReactNode;\n /** Cap on this segment's right edge. Next segment's left edge adopts the same profile. */\n endCap?: EdgeCap;\n tone?: BadgeTone;\n variant?: BadgeVariant;\n size?: BadgeSize;\n onClick?: () => void;\n href?: string;\n 'aria-label'?: string;\n}\n\nexport interface PowerlineProps {\n segments: PowerlineSegment[];\n /** Left edge of the first segment. Defaults to 'flat'. */\n startCap?: EdgeCap;\n /** Default size for every segment (per-segment `size` wins). */\n size?: BadgeSize;\n /** Default variant for every segment (per-segment `variant` wins). */\n variant?: BadgeVariant;\n /** Protrusion depth in CSS px, passed through to every segment's base. */\n depth?: number;\n /** Visible gap between adjacent segments. Number → px; string → literal CSS length.\n * Default: `0.2em` (scales with the row's font size). Pass `0` for flush. */\n gap?: number | string;\n className?: string;\n 'aria-label'?: string;\n}\n\nexport function Powerline({\n segments,\n startCap = 'flat',\n size,\n variant,\n depth,\n gap,\n className,\n ...rest\n}: PowerlineProps) {\n const cls = [s.row, className].filter(Boolean).join(' ');\n const style: CSSProperties | undefined = gap !== undefined\n ? { ['--powerline-gap' as never]: typeof gap === 'number' ? `${gap}px` : gap }\n : undefined;\n return (\n <span className={cls} style={style} aria-label={rest['aria-label']}>\n {segments.map((seg, i) => {\n const leftEdge: EdgeCap = i === 0 ? startCap : (segments[i - 1].endCap ?? 'flat');\n const rightEdge: EdgeCap = seg.endCap ?? 'flat';\n return (\n <Badge\n key={i}\n base=\"powerline\"\n baseParams={{ leftEdge, rightEdge, ...(depth !== undefined && { depth }) }}\n tone={seg.tone}\n variant={seg.variant ?? variant}\n size={seg.size ?? size}\n onClick={seg.onClick}\n href={seg.href}\n aria-label={seg['aria-label']}\n className={s.segment}\n >\n {seg.text}\n </Badge>\n );\n })}\n </span>\n );\n}\n"],"mappings":";;;;;;;;;ACmCA,SAAgB,EAAU,EACxB,aACA,cAAW,QACX,SACA,YACA,UACA,QACA,cACA,GAAG,KACc;AAKjB,QACE,kBAAC,QAAD;EAAM,WALI,CAAC,EAAE,KAAK,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAKjC;EAAY,OAJU,MAAQ,KAAA,IAE7C,KAAA,IADA,EAAG,mBAA6B,OAAO,KAAQ,WAAW,GAAG,EAAI,MAAM,GAAK;EAG1C,cAAY,EAAK;YAClD,EAAS,KAAK,GAAK,MAIhB,kBAAC,GAAD;GAEE,MAAK;GACL,YAAY;IAAE,UANQ,MAAM,IAAI,IAAY,EAAS,IAAI,GAAG,UAAU;IAM9C,WALD,EAAI,UAAU;IAKF,GAAI,MAAU,KAAA,KAAa,EAAE,UAAO;IAAG;GAC1E,MAAM,EAAI;GACV,SAAS,EAAI,WAAW;GACxB,MAAM,EAAI,QAAQ;GAClB,SAAS,EAAI;GACb,MAAM,EAAI;GACV,cAAY,EAAI;GAChB,WAAW,EAAE;aAEZ,EAAI;GACC,EAZD,EAYC,CAEV;EACG,CAAA"}