@weasel-js/ui 1.0.0 → 1.0.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.
- package/dist/chunks/ActionsBar-9aR5N3lU.js +41 -0
- package/dist/chunks/ActionsBar-9aR5N3lU.js.map +1 -0
- package/dist/chunks/{Callout-CxxrEcSb.js → Callout-CFqG5xho.js} +1 -1
- package/dist/chunks/{Callout-CxxrEcSb.js.map → Callout-CFqG5xho.js.map} +1 -1
- package/dist/chunks/{Checkbox-Cf6YHVWV.js → Checkbox-KQ5L8APP.js} +1 -1
- package/dist/chunks/{Checkbox-Cf6YHVWV.js.map → Checkbox-KQ5L8APP.js.map} +1 -1
- package/dist/chunks/{ColorField-sGLnThpB.js → ColorField-ykpiD3XU.js} +1 -1
- package/dist/chunks/{ColorField-sGLnThpB.js.map → ColorField-ykpiD3XU.js.map} +1 -1
- package/dist/chunks/{ComboBox-EnV1IytN.js → ComboBox-DpxsFVBy.js} +2 -2
- package/dist/chunks/{ComboBox-EnV1IytN.js.map → ComboBox-DpxsFVBy.js.map} +1 -1
- package/dist/chunks/{CurveEditor-DAb2EMyR.js → CurveEditor-fRctbmoV.js} +1 -1
- package/dist/chunks/{CurveEditor-DAb2EMyR.js.map → CurveEditor-fRctbmoV.js.map} +1 -1
- package/dist/chunks/{Dialog-CQymDCAl.js → Dialog-3FCd_gYi.js} +1 -1
- package/dist/chunks/{Dialog-CQymDCAl.js.map → Dialog-3FCd_gYi.js.map} +1 -1
- package/dist/chunks/{Field-BHSu2F3E.js → Field-VQwmrIna.js} +1 -1
- package/dist/chunks/{Field-BHSu2F3E.js.map → Field-VQwmrIna.js.map} +1 -1
- package/dist/chunks/{GradientEditor-Co9aGyRe.js → GradientEditor-BL5kg7a_.js} +3 -3
- package/dist/chunks/{GradientEditor-Co9aGyRe.js.map → GradientEditor-BL5kg7a_.js.map} +1 -1
- package/dist/chunks/{Input-qk44ESKC.js → Input-DpkwYtUY.js} +2 -2
- package/dist/chunks/{Input-qk44ESKC.js.map → Input-DpkwYtUY.js.map} +1 -1
- package/dist/chunks/{NumberField-CYhQeWoM.js → NumberField-BbzI0GtU.js} +2 -2
- package/dist/chunks/{NumberField-CYhQeWoM.js.map → NumberField-BbzI0GtU.js.map} +1 -1
- package/dist/chunks/OptionsBar-CHvH4n4u.js +45 -0
- package/dist/chunks/OptionsBar-CHvH4n4u.js.map +1 -0
- package/dist/chunks/{PointPlotter-EkbCBK9j.js → PointPlotter-R8hguJPq.js} +2 -2
- package/dist/chunks/{PointPlotter-EkbCBK9j.js.map → PointPlotter-R8hguJPq.js.map} +1 -1
- package/dist/chunks/{Powerline-Bg9M5oBK.js → Powerline-Dd9Ukhcl.js} +1 -1
- package/dist/chunks/{Powerline-Bg9M5oBK.js.map → Powerline-Dd9Ukhcl.js.map} +1 -1
- package/dist/chunks/{Prefs-DZjXp2Ln.js → Prefs-lgI4x4jF.js} +10 -10
- package/dist/chunks/{Prefs-DZjXp2Ln.js.map → Prefs-lgI4x4jF.js.map} +1 -1
- package/dist/chunks/{RadioGroup-rL2i3afr.js → RadioGroup-CIpHr3g6.js} +2 -2
- package/dist/chunks/{RadioGroup-rL2i3afr.js.map → RadioGroup-CIpHr3g6.js.map} +1 -1
- package/dist/chunks/{RangeSlider-DPldYd4O.js → RangeSlider-CaDogGTj.js} +1 -1
- package/dist/chunks/{RangeSlider-DPldYd4O.js.map → RangeSlider-CaDogGTj.js.map} +1 -1
- package/dist/chunks/{ResizeHandle-DR8X229y.js → ResizeHandle-CCQ2y87y.js} +1 -1
- package/dist/chunks/{ResizeHandle-DR8X229y.js.map → ResizeHandle-CCQ2y87y.js.map} +1 -1
- package/dist/chunks/{Select-vSeAbspK.js → Select-BE3Y1NrH.js} +2 -2
- package/dist/chunks/{Select-vSeAbspK.js.map → Select-BE3Y1NrH.js.map} +1 -1
- package/dist/chunks/{SelectionPanel-1mmALQba.js → SelectionPanel-Zaw8tYQH.js} +6 -6
- package/dist/chunks/{SelectionPanel-1mmALQba.js.map → SelectionPanel-Zaw8tYQH.js.map} +1 -1
- package/dist/chunks/{Sidebar-CigrFvpL.js → Sidebar-DP_nyJze.js} +1 -1
- package/dist/chunks/{Sidebar-CigrFvpL.js.map → Sidebar-DP_nyJze.js.map} +1 -1
- package/dist/chunks/{SidebarPanel-C0w16BrF.js → SidebarPanel-BpD0ptyg.js} +1 -1
- package/dist/chunks/{SidebarPanel-C0w16BrF.js.map → SidebarPanel-BpD0ptyg.js.map} +1 -1
- package/dist/chunks/{StatusBar-lt_Ok6WK.js → StatusBar-DBO0E0Yd.js} +1 -1
- package/dist/chunks/{StatusBar-lt_Ok6WK.js.map → StatusBar-DBO0E0Yd.js.map} +1 -1
- package/dist/chunks/{Switch-BYj762hm.js → Switch-JyVSSAzC.js} +1 -1
- package/dist/chunks/{Switch-BYj762hm.js.map → Switch-JyVSSAzC.js.map} +1 -1
- package/dist/chunks/{Tabs-DOW5jtnq.js → Tabs-Df0sDomx.js} +1 -1
- package/dist/chunks/{Tabs-DOW5jtnq.js.map → Tabs-Df0sDomx.js.map} +1 -1
- package/dist/chunks/{Toast-DLM2AsTz.js → Toast-DFw4IrD_.js} +1 -1
- package/dist/chunks/{Toast-DLM2AsTz.js.map → Toast-DFw4IrD_.js.map} +1 -1
- package/dist/chunks/ToggleBar-BP1zFcvg.js +74 -0
- package/dist/chunks/ToggleBar-BP1zFcvg.js.map +1 -0
- package/dist/chunks/{ToolButton-5L1sAlJC.js → ToolButton-DpT-mukU.js} +6 -5
- package/dist/chunks/ToolButton-DpT-mukU.js.map +1 -0
- package/dist/chunks/{ToolGroup-BAthcF5H.js → ToolGroup-BTIwd4U4.js} +1 -1
- package/dist/chunks/{ToolGroup-BAthcF5H.js.map → ToolGroup-BTIwd4U4.js.map} +1 -1
- package/dist/chunks/{ToolOptionsBar-D4xmXa_a.js → ToolOptionsBar-JvmY7iNe.js} +1 -1
- package/dist/chunks/{ToolOptionsBar-D4xmXa_a.js.map → ToolOptionsBar-JvmY7iNe.js.map} +1 -1
- package/dist/chunks/{ToolPalette-BDkvV3pJ.js → ToolPalette-DPn0owno.js} +27 -47
- package/dist/chunks/ToolPalette-DPn0owno.js.map +1 -0
- package/dist/chunks/segmentedControl.module-DCyuDbj1.js +11 -0
- package/dist/chunks/segmentedControl.module-DCyuDbj1.js.map +1 -0
- package/dist/chunks/useRovingTabIndex-DBZtq4IH.js +65 -0
- package/dist/chunks/useRovingTabIndex-DBZtq4IH.js.map +1 -0
- package/dist/components/ActionsBar/ActionsBar.d.ts.map +1 -1
- package/dist/components/ActionsBar/index.js +1 -1
- package/dist/components/Callout/index.js +1 -1
- package/dist/components/Checkbox/index.js +1 -1
- package/dist/components/ColorField/index.js +1 -1
- package/dist/components/ComboBox/index.js +1 -1
- package/dist/components/CurveEditor/index.js +1 -1
- package/dist/components/Dialog/index.js +1 -1
- package/dist/components/Field/index.js +1 -1
- package/dist/components/GradientEditor/index.js +1 -1
- package/dist/components/Input/index.js +1 -1
- package/dist/components/NumberField/index.js +1 -1
- package/dist/components/OptionsBar/OptionsBar.d.ts.map +1 -1
- package/dist/components/OptionsBar/index.js +1 -1
- package/dist/components/PointPlotter/index.js +1 -1
- package/dist/components/Powerline/index.js +1 -1
- package/dist/components/Prefs/index.js +1 -1
- package/dist/components/RadioGroup/index.js +1 -1
- package/dist/components/RangeSlider/index.js +1 -1
- package/dist/components/ResizeHandle/index.js +1 -1
- package/dist/components/Select/index.js +1 -1
- package/dist/components/SelectionPanel/index.js +1 -1
- package/dist/components/Sidebar/index.js +1 -1
- package/dist/components/SidebarPanel/index.js +1 -1
- package/dist/components/StatusBar/index.js +1 -1
- package/dist/components/Switch/index.js +1 -1
- package/dist/components/Tabs/index.js +1 -1
- package/dist/components/Toast/index.js +1 -1
- package/dist/components/ToggleBar/ToggleBar.d.ts.map +1 -1
- package/dist/components/ToggleBar/index.js +1 -1
- package/dist/components/ToolButton/ToolButton.d.ts +4 -1
- package/dist/components/ToolButton/ToolButton.d.ts.map +1 -1
- package/dist/components/ToolButton/index.js +1 -1
- package/dist/components/ToolGroup/index.js +1 -1
- package/dist/components/ToolOptionsBar/index.js +1 -1
- package/dist/components/ToolPalette/ToolPalette.d.ts.map +1 -1
- package/dist/components/ToolPalette/index.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -37
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/useRovingTabIndex.d.ts +52 -0
- package/dist/useRovingTabIndex.d.ts.map +1 -0
- package/package.json +2 -2
- package/dist/chunks/ActionsBar-CzU6Of3B.js +0 -94
- package/dist/chunks/ActionsBar-CzU6Of3B.js.map +0 -1
- package/dist/chunks/OptionsBar-CHOP_CiW.js +0 -98
- package/dist/chunks/OptionsBar-CHOP_CiW.js.map +0 -1
- package/dist/chunks/ToggleBar-Defj6Asn.js +0 -129
- package/dist/chunks/ToggleBar-Defj6Asn.js.map +0 -1
- package/dist/chunks/ToolButton-5L1sAlJC.js.map +0 -1
- package/dist/chunks/ToolPalette-BDkvV3pJ.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NumberField-
|
|
1
|
+
{"version":3,"file":"NumberField-BbzI0GtU.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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { t as e } from "./useRovingTabIndex-DBZtq4IH.js";
|
|
2
|
+
import { t } from "./segmentedControl.module-DCyuDbj1.js";
|
|
3
|
+
import "react";
|
|
4
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/OptionsBar/OptionsBar.tsx
|
|
6
|
+
function r(r) {
|
|
7
|
+
let { items: i, ariaLabel: a, className: o, height: s, size: c, variant: l } = r, u = (e) => {
|
|
8
|
+
let t = i[e];
|
|
9
|
+
t.disabled || t.onChange(!t.selected);
|
|
10
|
+
}, d = e({
|
|
11
|
+
items: i,
|
|
12
|
+
itemClassName: t.segment,
|
|
13
|
+
onActivate: u
|
|
14
|
+
}), f = s === void 0 ? void 0 : { "--wzl-tb-height": `${s}px` }, p = [
|
|
15
|
+
t.root,
|
|
16
|
+
c && t[`size_${c}`],
|
|
17
|
+
l && t[`variant_${l}`],
|
|
18
|
+
o
|
|
19
|
+
].filter(Boolean).join(" ");
|
|
20
|
+
return /* @__PURE__ */ n("div", {
|
|
21
|
+
ref: d.rootRef,
|
|
22
|
+
className: p,
|
|
23
|
+
role: "group",
|
|
24
|
+
"aria-label": a,
|
|
25
|
+
style: f,
|
|
26
|
+
children: i.map((e, r) => {
|
|
27
|
+
let i = `${t.segment}${e.selected ? ` ${t.segmentSelected}` : ""}`;
|
|
28
|
+
return /* @__PURE__ */ n("button", {
|
|
29
|
+
type: "button",
|
|
30
|
+
"aria-pressed": e.selected,
|
|
31
|
+
"aria-label": e.ariaLabel,
|
|
32
|
+
disabled: e.disabled,
|
|
33
|
+
tabIndex: d.tabIndexFor(r),
|
|
34
|
+
className: i,
|
|
35
|
+
onClick: () => u(r),
|
|
36
|
+
onKeyDown: d.onKeyDown(r),
|
|
37
|
+
children: e.label
|
|
38
|
+
}, e.value);
|
|
39
|
+
})
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { r as t };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=OptionsBar-CHvH4n4u.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OptionsBar-CHvH4n4u.js","names":[],"sources":["../../src/components/OptionsBar/OptionsBar.tsx"],"sourcesContent":["import { type CSSProperties, type ReactElement, type ReactNode } from 'react';\nimport s from '../segmentedControl.module.css';\nimport { useRovingTabIndex } from '../../useRovingTabIndex';\n\nexport type OptionsBarItem<V extends string | number = string> = {\n value: V;\n label?: ReactNode;\n ariaLabel?: string;\n disabled?: boolean;\n selected: boolean;\n onChange: (next: boolean) => void;\n};\n\nexport type OptionsBarSize = 'sm' | 'md';\nexport type OptionsBarVariant = 'default' | 'minimal';\n\nexport type OptionsBarProps<V extends string | number = string> = {\n items: readonly OptionsBarItem<V>[];\n ariaLabel?: string;\n className?: string;\n height?: number;\n /** Size variant. `sm` is ~60% of the default height with reduced padding\n * and font size — sized for dense surfaces like lab control panels. */\n size?: OptionsBarSize;\n /** Visual variant. `minimal` strips the pill track and glass treatment;\n * selection becomes a flat accent. For dense diagnostic surfaces. */\n variant?: OptionsBarVariant;\n};\n\nexport function OptionsBar<V extends string | number = string>(props: OptionsBarProps<V>): ReactElement {\n const { items, ariaLabel, className, height, size, variant } = props;\n\n const toggle = (index: number) => {\n const item = items[index];\n if (item.disabled) return;\n item.onChange(!item.selected);\n };\n\n const roving = useRovingTabIndex({ items, itemClassName: s.segment, onActivate: toggle });\n\n const style: CSSProperties | undefined = height !== undefined\n ? ({ ['--wzl-tb-height' as string]: `${height}px` } as CSSProperties)\n : undefined;\n\n const rootCls = [\n s.root,\n size && s[`size_${size}`],\n variant && s[`variant_${variant}`],\n className,\n ].filter(Boolean).join(' ');\n\n return (\n <div\n ref={roving.rootRef}\n className={rootCls}\n role=\"group\"\n aria-label={ariaLabel}\n style={style}\n >\n {items.map((item, i) => {\n const cls = `${s.segment}${item.selected ? ` ${s.segmentSelected}` : ''}`;\n return (\n <button\n key={item.value}\n type=\"button\"\n aria-pressed={item.selected}\n aria-label={item.ariaLabel}\n disabled={item.disabled}\n tabIndex={roving.tabIndexFor(i)}\n className={cls}\n onClick={() => toggle(i)}\n onKeyDown={roving.onKeyDown(i)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;AA6BA,SAAgB,EAA+C,GAAyC;CACtG,IAAM,EAAE,UAAO,cAAW,cAAW,WAAQ,SAAM,eAAY,GAEzD,KAAU,MAAkB;EAChC,IAAM,IAAO,EAAM;AACf,IAAK,YACT,EAAK,SAAS,CAAC,EAAK,SAAS;IAGzB,IAAS,EAAkB;EAAE;EAAO,eAAe,EAAE;EAAS,YAAY;EAAQ,CAAC,EAEnF,IAAmC,MAAW,KAAA,IAEhD,KAAA,IADC,EAAG,mBAA8B,GAAG,EAAO,KAAK,EAG/C,IAAU;EACd,EAAE;EACF,KAAQ,EAAE,QAAQ;EAClB,KAAW,EAAE,WAAW;EACxB;EACD,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;AAE3B,QACE,kBAAC,OAAD;EACE,KAAK,EAAO;EACZ,WAAW;EACX,MAAK;EACL,cAAY;EACL;YAEN,EAAM,KAAK,GAAM,MAAM;GACtB,IAAM,IAAM,GAAG,EAAE,UAAU,EAAK,WAAW,IAAI,EAAE,oBAAoB;AACrE,UACE,kBAAC,UAAD;IAEE,MAAK;IACL,gBAAc,EAAK;IACnB,cAAY,EAAK;IACjB,UAAU,EAAK;IACf,UAAU,EAAO,YAAY,EAAE;IAC/B,WAAW;IACX,eAAe,EAAO,EAAE;IACxB,WAAW,EAAO,UAAU,EAAE;cAE7B,EAAK;IACC,EAXF,EAAK,MAWH;IAEX;EACE,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e } from "./CurveEditor-
|
|
1
|
+
import { n as e } from "./CurveEditor-fRctbmoV.js";
|
|
2
2
|
import { jsx as t } from "react/jsx-runtime";
|
|
3
3
|
//#region src/components/PointPlotter/PointPlotter.tsx
|
|
4
4
|
function n(n) {
|
|
@@ -13,4 +13,4 @@ function n(n) {
|
|
|
13
13
|
//#endregion
|
|
14
14
|
export { n as t };
|
|
15
15
|
|
|
16
|
-
//# sourceMappingURL=PointPlotter-
|
|
16
|
+
//# sourceMappingURL=PointPlotter-R8hguJPq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PointPlotter-
|
|
1
|
+
{"version":3,"file":"PointPlotter-R8hguJPq.js","names":[],"sources":["../../src/components/PointPlotter/PointPlotter.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport {\n CurveEditor,\n type AnchorRenderProps,\n type ControlPoint,\n type CurveEditorProps,\n} from '../CurveEditor';\nimport type { GridSettings, AxesSettings } from '../Plot2D';\n\nexport interface PointPlotterProps {\n /** Plotted points; caller-owned. */\n value: readonly ControlPoint[];\n /** Fires every frame during drag with the live in-flight value. */\n onChange: (next: ControlPoint[]) => void;\n /** Fires once per discrete user action (drag-end, add, delete) with\n * the new value and the value at gesture start. Wire history here. */\n onChangeCommit?: (next: ControlPoint[], prev: readonly ControlPoint[]) => void;\n /** Model-space x range. Default [0, 1]. */\n xRange?: readonly [number, number];\n /** Model-space y range. Default [0, 1]. */\n yRange?: readonly [number, number];\n width: number;\n height: number;\n grid?: GridSettings | false | null;\n axes?: AxesSettings | false | null;\n /** Minimum allowed point count. User-initiated deletion is refused\n * while `value.length <= minPoints`. */\n minPoints?: number;\n /** Maximum allowed point count. User-initiated insertion is refused\n * while `value.length >= maxPoints`. */\n maxPoints?: number;\n /** How new points are added. Default `'click-empty'`. Set to `'never'`\n * to disable insertion entirely. */\n addPointMode?: 'click-empty' | 'never';\n /** Built-in undo/redo via keyboard when the component has focus.\n * Default `true`. See `CurveEditor.history` for details. */\n history?: boolean;\n /** Custom per-anchor renderer. See `CurveEditor.renderAnchor`. */\n renderAnchor?: (info: AnchorRenderProps) => ReactNode;\n /** Extra SVG content beneath the anchors. See `CurveEditor.decorations`. */\n decorations?: ReactNode;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * 2D point plotter — a CurveEditor with the curve hidden. Anchors,\n * drag, shift+click delete, right-click delete, and click-empty insert\n * are inherited from CurveEditor verbatim, so the two components share\n * gesture semantics and stay in sync as CurveEditor evolves.\n *\n * Differences from CurveEditor: no curve `<path>` drawn, no fill, no\n * endpoint pinning, no interpolation, default `addPointMode` is\n * `'click-empty'` (CurveEditor defaults to `'click-curve'`, which\n * doesn't make sense without a curve to hit-test against).\n */\nexport function PointPlotter(props: PointPlotterProps) {\n const curveProps: CurveEditorProps = {\n ...props,\n addPointMode: props.addPointMode ?? 'click-empty',\n curve: false,\n fill: false,\n endpoints: 'free',\n };\n return <CurveEditor {...curveProps} />;\n}\n"],"mappings":";;;AAwDA,SAAgB,EAAa,GAA0B;AAQrD,QAAO,kBAAC,GAAD;EANL,GAAG;EACH,cAAc,EAAM,gBAAgB;EACpC,OAAO;EACP,MAAM;EACN,WAAW;EAEyB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Powerline-
|
|
1
|
+
{"version":3,"file":"Powerline-Dd9Ukhcl.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,13 +1,13 @@
|
|
|
1
1
|
import { n as e, t } from "./Tooltip-Clgn4trm.js";
|
|
2
|
-
import { t as n } from "./Checkbox-
|
|
3
|
-
import { t as r } from "./ColorField-
|
|
4
|
-
import { t as i } from "./Input-
|
|
5
|
-
import { t as a } from "./NumberField-
|
|
6
|
-
import { n as o, t as s } from "./RadioGroup-
|
|
7
|
-
import { t as c } from "./RangeSlider-
|
|
8
|
-
import { t as l } from "./Select-
|
|
9
|
-
import { t as u } from "./Switch-
|
|
10
|
-
import { t as d } from "./Dialog-
|
|
2
|
+
import { t as n } from "./Checkbox-KQ5L8APP.js";
|
|
3
|
+
import { t as r } from "./ColorField-ykpiD3XU.js";
|
|
4
|
+
import { t as i } from "./Input-DpkwYtUY.js";
|
|
5
|
+
import { t as a } from "./NumberField-BbzI0GtU.js";
|
|
6
|
+
import { n as o, t as s } from "./RadioGroup-CIpHr3g6.js";
|
|
7
|
+
import { t as c } from "./RangeSlider-CaDogGTj.js";
|
|
8
|
+
import { t as l } from "./Select-BE3Y1NrH.js";
|
|
9
|
+
import { t as u } from "./Switch-JyVSSAzC.js";
|
|
10
|
+
import { t as d } from "./Dialog-3FCd_gYi.js";
|
|
11
11
|
import { useMemo as f } from "react";
|
|
12
12
|
import { Focusable as p } from "react-aria-components";
|
|
13
13
|
import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
@@ -235,4 +235,4 @@ function T(e) {
|
|
|
235
235
|
//#endregion
|
|
236
236
|
export { y as a, v as i, x as n, _ as r, T as t };
|
|
237
237
|
|
|
238
|
-
//# sourceMappingURL=Prefs-
|
|
238
|
+
//# sourceMappingURL=Prefs-lgI4x4jF.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Prefs-DZjXp2Ln.js","names":[],"sources":["../../src/components/Prefs/schema.ts","../../src/components/Prefs/Prefs.module.css","../../src/components/Prefs/PrefsForm.tsx","../../src/components/Prefs/PrefsDialog.tsx"],"sourcesContent":["// Preference-schema vocabulary for PrefsForm / PrefsDialog.\n//\n// Deliberately field-compatible with core's `ToolPref*` family\n// (src/tools/prefs.ts): this schema module deliberately avoids importing\n// @weasel-js/core, so the contract is structural — a `ToolPrefGroup` (and\n// any host-app superset, like WeaselDraw's registry) assigns into\n// `PrefGroup` with no import and no cast. Keep the two in sync\n// field-for-field.\n\n/** Control-presentation hints per kind — visually-equivalent renderings\n * of the same value type. The persisted value is unchanged either way. */\nexport type PrefNumberControl = 'input' | 'slider';\nexport type PrefBooleanControl = 'checkbox' | 'switch';\nexport type PrefStringControl = 'input' | 'textarea';\nexport type PrefEnumControl = 'select' | 'radio';\n\ninterface PrefBase<K extends string, Value> {\n kind: K;\n /** Human-readable label, e.g. \"Show grid\". */\n name: string;\n /** Longer help text — surfaces as a tooltip on the row label. */\n description: string;\n /** Fallback when `values` holds nothing at this leaf's path. */\n default: Value;\n /** Omitted from the form unless `showHidden` is set. */\n hidden?: boolean;\n /** Render the control full-width with no label/tooltip row — for\n * controls that supply their own chrome (embedded sub-panel editors).\n * The `description` still applies wherever the renderer surfaces it. */\n block?: boolean;\n /** Row-pairing hint for compact property UIs (`SelectionPanel`):\n * leaves sharing a `pair` id render side-by-side on one row labeled\n * with the `pair` string. Purely presentational. */\n pair?: string;\n}\n\n/** Display-unit conversion for number leaves whose stored value uses a\n * canonical unit the user shouldn't see (radians → degrees). Mirrors\n * core's `ToolPrefNumberUnit`. */\nexport interface PrefNumberUnit {\n toDisplay: (stored: number) => number;\n fromDisplay: (display: number) => number;\n suffix?: string;\n}\n\nexport interface PrefNumber extends PrefBase<'number', number> {\n min?: number;\n max?: number;\n step?: number;\n control?: PrefNumberControl;\n unit?: PrefNumberUnit;\n}\nexport interface PrefBoolean extends PrefBase<'boolean', boolean> {\n control?: PrefBooleanControl;\n}\nexport interface PrefString extends PrefBase<'string', string> {\n control?: PrefStringControl;\n}\nexport interface PrefEnum<T extends string = string> extends PrefBase<'enum', T> {\n options: readonly { value: T; label: string }[];\n control?: PrefEnumControl;\n}\n\nexport interface PrefColor extends PrefBase<'color', string> {\n /** Value is `#rrggbb`, or `#rrggbbaa` when `alpha` is set. */\n alpha?: boolean;\n}\n\nexport type BuiltinPref = PrefNumber | PrefBoolean | PrefString | PrefEnum | PrefColor;\n\n/**\n * Open leaf: any node with a `kind` the form doesn't know renders via the\n * `renderers` map (`renderers[kind]`). App schemas keep their extra fields\n * (e.g. a registry-enum's `source`/`filter`) — renderers receive the node\n * and narrow it themselves. Deliberately NOT index-signatured so concrete\n * app interfaces stay assignable.\n */\nexport interface PrefCustom extends PrefBase<string, unknown> {}\n\nexport type PrefLeaf = BuiltinPref | PrefCustom;\n\n/** Nestable group: branch nodes in the schema tree. */\nexport interface PrefGroup {\n name: string;\n description?: string;\n children: Record<string, PrefLeaf | PrefGroup>;\n}\n\nexport function isPrefLeaf(node: PrefLeaf | PrefGroup): node is PrefLeaf {\n return 'kind' in node;\n}\n\n/** Get the value at a dotted path inside a nested value tree. Returns\n * `undefined` when a segment is missing or hits a non-object. */\nexport function prefValueAtPath(values: unknown, path: string): unknown {\n let cur: unknown = values;\n for (const seg of path.split('.')) {\n if (cur == null || typeof cur !== 'object') return undefined;\n cur = (cur as Record<string, unknown>)[seg];\n }\n return cur;\n}\n\n/**\n * Recursively drop `hidden` leaves (unless `showHidden`), pruning groups\n * that end up empty. Returns null when the entire subtree is hidden.\n */\nexport function visiblePrefSubtree<T extends PrefLeaf | PrefGroup>(\n node: T,\n showHidden: boolean,\n): T | null {\n if (isPrefLeaf(node)) return node.hidden && !showHidden ? null : node;\n const group = node as PrefGroup;\n const children: Record<string, PrefLeaf | PrefGroup> = {};\n for (const [key, child] of Object.entries(group.children)) {\n const kept = visiblePrefSubtree(child, showHidden);\n if (kept) children[key] = kept;\n }\n if (Object.keys(children).length === 0) return null;\n return { ...node, children };\n}\n","/* Ported from WeaselDraw's wd-prefs-* rules (apps/draw/src/app.css),\n * generalized onto theme tokens. Column width is overridable via\n * --wzl-prefs-column-width at any ancestor scope. */\n\n.columns {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: 12px;\n overflow-y: auto;\n padding-right: 4px;\n}\n\n.column {\n flex: 0 0 var(--wzl-prefs-column-width, 300px);\n width: var(--wzl-prefs-column-width, 300px);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.panel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n}\n\n.subpanel {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-top: 6px;\n padding: 8px 8px 8px 10px;\n background: var(--wzl-surface-sunken);\n border-left: 2px solid var(--wzl-border);\n border-radius: 2px;\n}\n\n.groupHeader {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--wzl-border);\n}\n\n.subpanel .groupHeader {\n border-bottom: none;\n padding-bottom: 2px;\n}\n\n.groupTitle {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--wzl-fg);\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n.subpanel .groupTitle {\n font-size: 11px;\n text-transform: none;\n letter-spacing: 0;\n}\n\n.groupDesc {\n margin: 0;\n font-size: 11px;\n color: var(--wzl-fg-subtle);\n line-height: 1.35;\n}\n\n.rows {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n font-size: 12px;\n color: var(--wzl-fg);\n cursor: default;\n}\n\n.rowLabel {\n flex: 1 1 auto;\n min-width: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n/* Description affordance — quiet until hovered/focused. */\n.help {\n flex: 0 0 auto;\n padding: 0;\n border: none;\n background: none;\n color: var(--wzl-fg-subtle);\n font-size: 11px;\n line-height: 1;\n cursor: help;\n border-radius: var(--wzl-radius-sm);\n}\n\n.help:hover {\n color: var(--wzl-fg);\n}\n\n.help:focus-visible {\n outline: 2px solid var(--wzl-focus-ring);\n outline-offset: 1px;\n color: var(--wzl-fg);\n}\n\n/* Control slot — fixed width so the label can take the rest of the row.\n * Kit form controls render as block-level flex columns that fill it. */\n.rowControl {\n flex: 0 0 110px;\n min-width: 0;\n display: flex;\n align-items: center;\n}\n\n.textarea {\n width: 100%;\n padding: 4px 8px;\n background: var(--wzl-surface-sunken);\n color: var(--wzl-fg);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n font: inherit;\n font-size: 12px;\n resize: vertical;\n}\n\n.unrenderable {\n font-family: var(--wzl-font-mono);\n font-size: 11px;\n color: var(--wzl-fg-subtle);\n}\n\n/* PrefsDialog header row: title text + optional headerExtra chrome. */\n.titleRow {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n}\n\n.titleRow > span:first-child {\n flex: 1;\n min-width: 0;\n}\n","import { useMemo, type ReactNode } from 'react';\nimport { Focusable } from 'react-aria-components';\nimport { Checkbox } from '../Checkbox';\nimport { ColorField } from '../ColorField';\nimport { Input } from '../Input';\nimport { NumberField } from '../NumberField';\nimport { RadioGroup, Radio } from '../RadioGroup';\nimport { RangeSlider } from '../RangeSlider';\nimport { Select } from '../Select';\nimport { Switch } from '../Switch';\nimport { Tooltip, TooltipTrigger } from '../Tooltip';\nimport {\n isPrefLeaf,\n prefValueAtPath,\n visiblePrefSubtree,\n type PrefBoolean,\n type PrefColor,\n type PrefEnum,\n type PrefGroup,\n type PrefLeaf,\n type PrefNumber,\n type PrefString,\n} from './schema';\nimport s from './Prefs.module.css';\n\nexport interface PrefRenderContext {\n /** Dotted path of the leaf within the schema root. */\n path: string;\n /** The schema node. App renderers narrow this to their own kind shape. */\n pref: PrefLeaf;\n /** Current value — `values` at `path`, falling back to `pref.default`. */\n value: unknown;\n setValue: (value: unknown) => void;\n}\n\nexport type PrefRenderer = (ctx: PrefRenderContext) => ReactNode;\n\nexport interface PrefsFormProps {\n /** Root of the schema tree. Core `ToolPrefGroup`s assign structurally. */\n schema: PrefGroup;\n /** Nested value tree (shape mirrors the schema). Sparse is fine —\n * missing leaves fall back to their schema `default`. */\n values?: unknown;\n /** Change callback with the leaf's dotted path. Values apply live;\n * there is no dirty/commit state. */\n onChange: (path: string, value: unknown) => void;\n /**\n * Per-kind renderers for app-defined kinds. Entries also override the\n * built-in kinds when keys collide. A renderer owns the control cell\n * (the label/tooltip row chrome stays with the form, unless the leaf\n * sets `block`); returning `null` collapses the row entirely. Unknown\n * kinds with no renderer show a labeled placeholder instead of\n * crashing.\n */\n renderers?: Record<string, PrefRenderer>;\n /** Reveal `hidden` leaves (dev tooling). Default false. */\n showHidden?: boolean;\n className?: string;\n}\n\n/**\n * Schema-driven preferences form. Top-level groups render as columns,\n * nested groups as indented sub-panels, leaves as label + control rows.\n * Storage-agnostic: pair with `PrefsDialog` for the modal composition,\n * and persist however the app likes via `onChange`.\n */\nexport function PrefsForm(props: PrefsFormProps) {\n const { schema, values, onChange, renderers, showHidden = false, className } = props;\n const visibleRoot = useMemo(\n () => visiblePrefSubtree(schema, showHidden),\n [schema, showHidden],\n );\n const ctx: WalkCtx = { values, onChange, renderers };\n return (\n <div className={[s.columns, className].filter(Boolean).join(' ')}>\n {Object.entries(visibleRoot?.children ?? {}).map(([key, child]) => (\n <div key={key} className={s.column}>\n {isPrefLeaf(child) ? (\n // Top-level leaves are unusual but legal — give each its own\n // column for symmetry with grouped siblings.\n <PrefRow ctx={ctx} path={key} pref={child} />\n ) : (\n <GroupBody ctx={ctx} group={child} path={key} depth={0} />\n )}\n </div>\n ))}\n </div>\n );\n}\n\ninterface WalkCtx {\n values: unknown;\n onChange: (path: string, value: unknown) => void;\n renderers?: Record<string, PrefRenderer>;\n}\n\nfunction GroupBody({ ctx, group, path, depth }: {\n ctx: WalkCtx;\n group: PrefGroup;\n path: string;\n depth: number;\n}) {\n return (\n <div className={depth === 0 ? s.panel : s.subpanel}>\n <div className={s.groupHeader}>\n <h3 className={s.groupTitle}>{group.name}</h3>\n {group.description !== undefined && (\n <p className={s.groupDesc}>{group.description}</p>\n )}\n </div>\n <div className={s.rows}>\n {Object.entries(group.children).map(([key, child]) => {\n const childPath = `${path}.${key}`;\n return isPrefLeaf(child) ? (\n <PrefRow key={key} ctx={ctx} path={childPath} pref={child} />\n ) : (\n <GroupBody key={key} ctx={ctx} group={child} path={childPath} depth={depth + 1} />\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction PrefRow({ ctx, path, pref }: { ctx: WalkCtx; path: string; pref: PrefLeaf }) {\n const stored = prefValueAtPath(ctx.values, path);\n const renderCtx: PrefRenderContext = {\n path,\n pref,\n value: stored !== undefined ? stored : pref.default,\n setValue: (v) => ctx.onChange(path, v),\n };\n\n const custom = ctx.renderers?.[pref.kind];\n const control = custom ? custom(renderCtx) : renderBuiltin(renderCtx);\n if (custom && control === null) return null;\n\n // `block` leaves own their chrome (embedded editors with their own\n // header) — no label/tooltip row.\n if (pref.block) return <>{control}</>;\n\n return (\n <label className={s.row}>\n <span className={s.rowLabel}>\n {pref.name}\n {pref.description ? (\n // Help affordance carries the description tooltip. A tooltip\n // trigger must be interactive (keyboard-reachable), so this is\n // a real button — a bare label span would be neither focusable\n // nor announced.\n <TooltipTrigger>\n <Focusable>\n <button type=\"button\" className={s.help} aria-label={`About ${pref.name}`}>\n ⓘ\n </button>\n </Focusable>\n <Tooltip>{pref.description}</Tooltip>\n </TooltipTrigger>\n ) : null}\n </span>\n <span className={s.rowControl}>{control}</span>\n </label>\n );\n}\n\nfunction renderBuiltin(ctx: PrefRenderContext): ReactNode {\n const { pref, value, setValue } = ctx;\n switch (pref.kind) {\n case 'boolean': {\n const p = pref as PrefBoolean;\n const checked = Boolean(value);\n return p.control === 'switch' ? (\n <Switch isSelected={checked} onChange={setValue} aria-label={p.name} />\n ) : (\n <Checkbox isSelected={checked} onChange={setValue} aria-label={p.name} />\n );\n }\n case 'number': {\n const p = pref as PrefNumber;\n const n = typeof value === 'number' && Number.isFinite(value) ? value : 0;\n if (p.control === 'slider') {\n return (\n <RangeSlider\n value={n}\n onChange={(v) => setValue(typeof v === 'number' ? v : v[0])}\n minValue={p.min}\n maxValue={p.max}\n step={p.step ?? 1}\n aria-label={p.name}\n />\n );\n }\n return (\n <NumberField\n value={n}\n onChange={setValue}\n minValue={p.min}\n maxValue={p.max}\n step={p.step ?? 1}\n aria-label={p.name}\n />\n );\n }\n case 'string': {\n const p = pref as PrefString;\n const text = typeof value === 'string' ? value : '';\n if (p.control === 'textarea') {\n return (\n <textarea\n className={s.textarea}\n value={text}\n onChange={(e) => setValue(e.target.value)}\n aria-label={p.name}\n rows={3}\n />\n );\n }\n return <Input value={text} onChange={setValue} aria-label={p.name} />;\n }\n case 'enum': {\n const p = pref as PrefEnum;\n const selected = typeof value === 'string' ? value : p.default;\n if (p.control === 'radio') {\n return (\n <RadioGroup\n value={selected}\n onChange={(v) => setValue(v)}\n aria-label={p.name}\n >\n {p.options.map((o) => (\n <Radio key={o.value} value={o.value}>{o.label}</Radio>\n ))}\n </RadioGroup>\n );\n }\n return (\n <Select<string>\n options={p.options.map((o) => ({ value: o.value, label: o.label }))}\n selectedKey={selected}\n onSelectionChange={(v) => setValue(v)}\n aria-label={p.name}\n />\n );\n }\n case 'color': {\n const p = pref as PrefColor;\n const hex = typeof value === 'string' ? value : p.default;\n return (\n <ColorField\n value={hex}\n alpha={p.alpha}\n onChange={setValue}\n aria-label={p.name}\n />\n );\n }\n default:\n // Unknown kind with no renderer entry: labeled placeholder, not a\n // crash — a missing wiring should be visible and recoverable.\n return <span className={s.unrenderable}>({pref.kind}: no renderer)</span>;\n }\n}\n","import type { ReactNode } from 'react';\nimport { Dialog } from '../Dialog';\nimport { PrefsForm, type PrefsFormProps } from './PrefsForm';\nimport s from './Prefs.module.css';\n\nexport interface PrefsDialogProps extends PrefsFormProps {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n /** Dialog heading. Defaults to the schema root's `name`. */\n title?: ReactNode;\n /** Extra chrome rendered inline with the title (e.g. a dev-mode\n * \"Show hidden\" switch). */\n headerExtra?: ReactNode;\n /** Class applied to the dialog's modal box. */\n dialogClassName?: string;\n}\n\n/**\n * The kit's preferences dialog: `Dialog` + `PrefsForm`. Changes apply\n * live through `onChange` — there is no OK/Cancel staging. For custom\n * placement (sidebar, popover, inline page), compose `PrefsForm`\n * directly; this wrapper is intentionally thin.\n */\nexport function PrefsDialog(props: PrefsDialogProps) {\n const { isOpen, onOpenChange, title, headerExtra, dialogClassName, ...form } = props;\n return (\n <Dialog\n isOpen={isOpen}\n onOpenChange={onOpenChange}\n aria-label={typeof title === 'string' ? title : form.schema.name}\n className={dialogClassName}\n title={\n headerExtra !== undefined ? (\n <span className={s.titleRow}>\n <span>{title ?? form.schema.name}</span>\n {headerExtra}\n </span>\n ) : (\n title ?? form.schema.name\n )\n }\n >\n <PrefsForm {...form} />\n </Dialog>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Prefs-lgI4x4jF.js","names":[],"sources":["../../src/components/Prefs/schema.ts","../../src/components/Prefs/Prefs.module.css","../../src/components/Prefs/PrefsForm.tsx","../../src/components/Prefs/PrefsDialog.tsx"],"sourcesContent":["// Preference-schema vocabulary for PrefsForm / PrefsDialog.\n//\n// Deliberately field-compatible with core's `ToolPref*` family\n// (src/tools/prefs.ts): this schema module deliberately avoids importing\n// @weasel-js/core, so the contract is structural — a `ToolPrefGroup` (and\n// any host-app superset, like WeaselDraw's registry) assigns into\n// `PrefGroup` with no import and no cast. Keep the two in sync\n// field-for-field.\n\n/** Control-presentation hints per kind — visually-equivalent renderings\n * of the same value type. The persisted value is unchanged either way. */\nexport type PrefNumberControl = 'input' | 'slider';\nexport type PrefBooleanControl = 'checkbox' | 'switch';\nexport type PrefStringControl = 'input' | 'textarea';\nexport type PrefEnumControl = 'select' | 'radio';\n\ninterface PrefBase<K extends string, Value> {\n kind: K;\n /** Human-readable label, e.g. \"Show grid\". */\n name: string;\n /** Longer help text — surfaces as a tooltip on the row label. */\n description: string;\n /** Fallback when `values` holds nothing at this leaf's path. */\n default: Value;\n /** Omitted from the form unless `showHidden` is set. */\n hidden?: boolean;\n /** Render the control full-width with no label/tooltip row — for\n * controls that supply their own chrome (embedded sub-panel editors).\n * The `description` still applies wherever the renderer surfaces it. */\n block?: boolean;\n /** Row-pairing hint for compact property UIs (`SelectionPanel`):\n * leaves sharing a `pair` id render side-by-side on one row labeled\n * with the `pair` string. Purely presentational. */\n pair?: string;\n}\n\n/** Display-unit conversion for number leaves whose stored value uses a\n * canonical unit the user shouldn't see (radians → degrees). Mirrors\n * core's `ToolPrefNumberUnit`. */\nexport interface PrefNumberUnit {\n toDisplay: (stored: number) => number;\n fromDisplay: (display: number) => number;\n suffix?: string;\n}\n\nexport interface PrefNumber extends PrefBase<'number', number> {\n min?: number;\n max?: number;\n step?: number;\n control?: PrefNumberControl;\n unit?: PrefNumberUnit;\n}\nexport interface PrefBoolean extends PrefBase<'boolean', boolean> {\n control?: PrefBooleanControl;\n}\nexport interface PrefString extends PrefBase<'string', string> {\n control?: PrefStringControl;\n}\nexport interface PrefEnum<T extends string = string> extends PrefBase<'enum', T> {\n options: readonly { value: T; label: string }[];\n control?: PrefEnumControl;\n}\n\nexport interface PrefColor extends PrefBase<'color', string> {\n /** Value is `#rrggbb`, or `#rrggbbaa` when `alpha` is set. */\n alpha?: boolean;\n}\n\nexport type BuiltinPref = PrefNumber | PrefBoolean | PrefString | PrefEnum | PrefColor;\n\n/**\n * Open leaf: any node with a `kind` the form doesn't know renders via the\n * `renderers` map (`renderers[kind]`). App schemas keep their extra fields\n * (e.g. a registry-enum's `source`/`filter`) — renderers receive the node\n * and narrow it themselves. Deliberately NOT index-signatured so concrete\n * app interfaces stay assignable.\n */\nexport interface PrefCustom extends PrefBase<string, unknown> {}\n\nexport type PrefLeaf = BuiltinPref | PrefCustom;\n\n/** Nestable group: branch nodes in the schema tree. */\nexport interface PrefGroup {\n name: string;\n description?: string;\n children: Record<string, PrefLeaf | PrefGroup>;\n}\n\nexport function isPrefLeaf(node: PrefLeaf | PrefGroup): node is PrefLeaf {\n return 'kind' in node;\n}\n\n/** Get the value at a dotted path inside a nested value tree. Returns\n * `undefined` when a segment is missing or hits a non-object. */\nexport function prefValueAtPath(values: unknown, path: string): unknown {\n let cur: unknown = values;\n for (const seg of path.split('.')) {\n if (cur == null || typeof cur !== 'object') return undefined;\n cur = (cur as Record<string, unknown>)[seg];\n }\n return cur;\n}\n\n/**\n * Recursively drop `hidden` leaves (unless `showHidden`), pruning groups\n * that end up empty. Returns null when the entire subtree is hidden.\n */\nexport function visiblePrefSubtree<T extends PrefLeaf | PrefGroup>(\n node: T,\n showHidden: boolean,\n): T | null {\n if (isPrefLeaf(node)) return node.hidden && !showHidden ? null : node;\n const group = node as PrefGroup;\n const children: Record<string, PrefLeaf | PrefGroup> = {};\n for (const [key, child] of Object.entries(group.children)) {\n const kept = visiblePrefSubtree(child, showHidden);\n if (kept) children[key] = kept;\n }\n if (Object.keys(children).length === 0) return null;\n return { ...node, children };\n}\n","/* Ported from WeaselDraw's wd-prefs-* rules (apps/draw/src/app.css),\n * generalized onto theme tokens. Column width is overridable via\n * --wzl-prefs-column-width at any ancestor scope. */\n\n.columns {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: 12px;\n overflow-y: auto;\n padding-right: 4px;\n}\n\n.column {\n flex: 0 0 var(--wzl-prefs-column-width, 300px);\n width: var(--wzl-prefs-column-width, 300px);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.panel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n}\n\n.subpanel {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-top: 6px;\n padding: 8px 8px 8px 10px;\n background: var(--wzl-surface-sunken);\n border-left: 2px solid var(--wzl-border);\n border-radius: 2px;\n}\n\n.groupHeader {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--wzl-border);\n}\n\n.subpanel .groupHeader {\n border-bottom: none;\n padding-bottom: 2px;\n}\n\n.groupTitle {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--wzl-fg);\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n.subpanel .groupTitle {\n font-size: 11px;\n text-transform: none;\n letter-spacing: 0;\n}\n\n.groupDesc {\n margin: 0;\n font-size: 11px;\n color: var(--wzl-fg-subtle);\n line-height: 1.35;\n}\n\n.rows {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n font-size: 12px;\n color: var(--wzl-fg);\n cursor: default;\n}\n\n.rowLabel {\n flex: 1 1 auto;\n min-width: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n/* Description affordance — quiet until hovered/focused. */\n.help {\n flex: 0 0 auto;\n padding: 0;\n border: none;\n background: none;\n color: var(--wzl-fg-subtle);\n font-size: 11px;\n line-height: 1;\n cursor: help;\n border-radius: var(--wzl-radius-sm);\n}\n\n.help:hover {\n color: var(--wzl-fg);\n}\n\n.help:focus-visible {\n outline: 2px solid var(--wzl-focus-ring);\n outline-offset: 1px;\n color: var(--wzl-fg);\n}\n\n/* Control slot — fixed width so the label can take the rest of the row.\n * Kit form controls render as block-level flex columns that fill it. */\n.rowControl {\n flex: 0 0 110px;\n min-width: 0;\n display: flex;\n align-items: center;\n}\n\n.textarea {\n width: 100%;\n padding: 4px 8px;\n background: var(--wzl-surface-sunken);\n color: var(--wzl-fg);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n font: inherit;\n font-size: 12px;\n resize: vertical;\n}\n\n.unrenderable {\n font-family: var(--wzl-font-mono);\n font-size: 11px;\n color: var(--wzl-fg-subtle);\n}\n\n/* PrefsDialog header row: title text + optional headerExtra chrome. */\n.titleRow {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n}\n\n.titleRow > span:first-child {\n flex: 1;\n min-width: 0;\n}\n","import { useMemo, type ReactNode } from 'react';\nimport { Focusable } from 'react-aria-components';\nimport { Checkbox } from '../Checkbox';\nimport { ColorField } from '../ColorField';\nimport { Input } from '../Input';\nimport { NumberField } from '../NumberField';\nimport { RadioGroup, Radio } from '../RadioGroup';\nimport { RangeSlider } from '../RangeSlider';\nimport { Select } from '../Select';\nimport { Switch } from '../Switch';\nimport { Tooltip, TooltipTrigger } from '../Tooltip';\nimport {\n isPrefLeaf,\n prefValueAtPath,\n visiblePrefSubtree,\n type PrefBoolean,\n type PrefColor,\n type PrefEnum,\n type PrefGroup,\n type PrefLeaf,\n type PrefNumber,\n type PrefString,\n} from './schema';\nimport s from './Prefs.module.css';\n\nexport interface PrefRenderContext {\n /** Dotted path of the leaf within the schema root. */\n path: string;\n /** The schema node. App renderers narrow this to their own kind shape. */\n pref: PrefLeaf;\n /** Current value — `values` at `path`, falling back to `pref.default`. */\n value: unknown;\n setValue: (value: unknown) => void;\n}\n\nexport type PrefRenderer = (ctx: PrefRenderContext) => ReactNode;\n\nexport interface PrefsFormProps {\n /** Root of the schema tree. Core `ToolPrefGroup`s assign structurally. */\n schema: PrefGroup;\n /** Nested value tree (shape mirrors the schema). Sparse is fine —\n * missing leaves fall back to their schema `default`. */\n values?: unknown;\n /** Change callback with the leaf's dotted path. Values apply live;\n * there is no dirty/commit state. */\n onChange: (path: string, value: unknown) => void;\n /**\n * Per-kind renderers for app-defined kinds. Entries also override the\n * built-in kinds when keys collide. A renderer owns the control cell\n * (the label/tooltip row chrome stays with the form, unless the leaf\n * sets `block`); returning `null` collapses the row entirely. Unknown\n * kinds with no renderer show a labeled placeholder instead of\n * crashing.\n */\n renderers?: Record<string, PrefRenderer>;\n /** Reveal `hidden` leaves (dev tooling). Default false. */\n showHidden?: boolean;\n className?: string;\n}\n\n/**\n * Schema-driven preferences form. Top-level groups render as columns,\n * nested groups as indented sub-panels, leaves as label + control rows.\n * Storage-agnostic: pair with `PrefsDialog` for the modal composition,\n * and persist however the app likes via `onChange`.\n */\nexport function PrefsForm(props: PrefsFormProps) {\n const { schema, values, onChange, renderers, showHidden = false, className } = props;\n const visibleRoot = useMemo(\n () => visiblePrefSubtree(schema, showHidden),\n [schema, showHidden],\n );\n const ctx: WalkCtx = { values, onChange, renderers };\n return (\n <div className={[s.columns, className].filter(Boolean).join(' ')}>\n {Object.entries(visibleRoot?.children ?? {}).map(([key, child]) => (\n <div key={key} className={s.column}>\n {isPrefLeaf(child) ? (\n // Top-level leaves are unusual but legal — give each its own\n // column for symmetry with grouped siblings.\n <PrefRow ctx={ctx} path={key} pref={child} />\n ) : (\n <GroupBody ctx={ctx} group={child} path={key} depth={0} />\n )}\n </div>\n ))}\n </div>\n );\n}\n\ninterface WalkCtx {\n values: unknown;\n onChange: (path: string, value: unknown) => void;\n renderers?: Record<string, PrefRenderer>;\n}\n\nfunction GroupBody({ ctx, group, path, depth }: {\n ctx: WalkCtx;\n group: PrefGroup;\n path: string;\n depth: number;\n}) {\n return (\n <div className={depth === 0 ? s.panel : s.subpanel}>\n <div className={s.groupHeader}>\n <h3 className={s.groupTitle}>{group.name}</h3>\n {group.description !== undefined && (\n <p className={s.groupDesc}>{group.description}</p>\n )}\n </div>\n <div className={s.rows}>\n {Object.entries(group.children).map(([key, child]) => {\n const childPath = `${path}.${key}`;\n return isPrefLeaf(child) ? (\n <PrefRow key={key} ctx={ctx} path={childPath} pref={child} />\n ) : (\n <GroupBody key={key} ctx={ctx} group={child} path={childPath} depth={depth + 1} />\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction PrefRow({ ctx, path, pref }: { ctx: WalkCtx; path: string; pref: PrefLeaf }) {\n const stored = prefValueAtPath(ctx.values, path);\n const renderCtx: PrefRenderContext = {\n path,\n pref,\n value: stored !== undefined ? stored : pref.default,\n setValue: (v) => ctx.onChange(path, v),\n };\n\n const custom = ctx.renderers?.[pref.kind];\n const control = custom ? custom(renderCtx) : renderBuiltin(renderCtx);\n if (custom && control === null) return null;\n\n // `block` leaves own their chrome (embedded editors with their own\n // header) — no label/tooltip row.\n if (pref.block) return <>{control}</>;\n\n return (\n <label className={s.row}>\n <span className={s.rowLabel}>\n {pref.name}\n {pref.description ? (\n // Help affordance carries the description tooltip. A tooltip\n // trigger must be interactive (keyboard-reachable), so this is\n // a real button — a bare label span would be neither focusable\n // nor announced.\n <TooltipTrigger>\n <Focusable>\n <button type=\"button\" className={s.help} aria-label={`About ${pref.name}`}>\n ⓘ\n </button>\n </Focusable>\n <Tooltip>{pref.description}</Tooltip>\n </TooltipTrigger>\n ) : null}\n </span>\n <span className={s.rowControl}>{control}</span>\n </label>\n );\n}\n\nfunction renderBuiltin(ctx: PrefRenderContext): ReactNode {\n const { pref, value, setValue } = ctx;\n switch (pref.kind) {\n case 'boolean': {\n const p = pref as PrefBoolean;\n const checked = Boolean(value);\n return p.control === 'switch' ? (\n <Switch isSelected={checked} onChange={setValue} aria-label={p.name} />\n ) : (\n <Checkbox isSelected={checked} onChange={setValue} aria-label={p.name} />\n );\n }\n case 'number': {\n const p = pref as PrefNumber;\n const n = typeof value === 'number' && Number.isFinite(value) ? value : 0;\n if (p.control === 'slider') {\n return (\n <RangeSlider\n value={n}\n onChange={(v) => setValue(typeof v === 'number' ? v : v[0])}\n minValue={p.min}\n maxValue={p.max}\n step={p.step ?? 1}\n aria-label={p.name}\n />\n );\n }\n return (\n <NumberField\n value={n}\n onChange={setValue}\n minValue={p.min}\n maxValue={p.max}\n step={p.step ?? 1}\n aria-label={p.name}\n />\n );\n }\n case 'string': {\n const p = pref as PrefString;\n const text = typeof value === 'string' ? value : '';\n if (p.control === 'textarea') {\n return (\n <textarea\n className={s.textarea}\n value={text}\n onChange={(e) => setValue(e.target.value)}\n aria-label={p.name}\n rows={3}\n />\n );\n }\n return <Input value={text} onChange={setValue} aria-label={p.name} />;\n }\n case 'enum': {\n const p = pref as PrefEnum;\n const selected = typeof value === 'string' ? value : p.default;\n if (p.control === 'radio') {\n return (\n <RadioGroup\n value={selected}\n onChange={(v) => setValue(v)}\n aria-label={p.name}\n >\n {p.options.map((o) => (\n <Radio key={o.value} value={o.value}>{o.label}</Radio>\n ))}\n </RadioGroup>\n );\n }\n return (\n <Select<string>\n options={p.options.map((o) => ({ value: o.value, label: o.label }))}\n selectedKey={selected}\n onSelectionChange={(v) => setValue(v)}\n aria-label={p.name}\n />\n );\n }\n case 'color': {\n const p = pref as PrefColor;\n const hex = typeof value === 'string' ? value : p.default;\n return (\n <ColorField\n value={hex}\n alpha={p.alpha}\n onChange={setValue}\n aria-label={p.name}\n />\n );\n }\n default:\n // Unknown kind with no renderer entry: labeled placeholder, not a\n // crash — a missing wiring should be visible and recoverable.\n return <span className={s.unrenderable}>({pref.kind}: no renderer)</span>;\n }\n}\n","import type { ReactNode } from 'react';\nimport { Dialog } from '../Dialog';\nimport { PrefsForm, type PrefsFormProps } from './PrefsForm';\nimport s from './Prefs.module.css';\n\nexport interface PrefsDialogProps extends PrefsFormProps {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n /** Dialog heading. Defaults to the schema root's `name`. */\n title?: ReactNode;\n /** Extra chrome rendered inline with the title (e.g. a dev-mode\n * \"Show hidden\" switch). */\n headerExtra?: ReactNode;\n /** Class applied to the dialog's modal box. */\n dialogClassName?: string;\n}\n\n/**\n * The kit's preferences dialog: `Dialog` + `PrefsForm`. Changes apply\n * live through `onChange` — there is no OK/Cancel staging. For custom\n * placement (sidebar, popover, inline page), compose `PrefsForm`\n * directly; this wrapper is intentionally thin.\n */\nexport function PrefsDialog(props: PrefsDialogProps) {\n const { isOpen, onOpenChange, title, headerExtra, dialogClassName, ...form } = props;\n return (\n <Dialog\n isOpen={isOpen}\n onOpenChange={onOpenChange}\n aria-label={typeof title === 'string' ? title : form.schema.name}\n className={dialogClassName}\n title={\n headerExtra !== undefined ? (\n <span className={s.titleRow}>\n <span>{title ?? form.schema.name}</span>\n {headerExtra}\n </span>\n ) : (\n title ?? form.schema.name\n )\n }\n >\n <PrefsForm {...form} />\n </Dialog>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e } from "./Field-
|
|
1
|
+
import { n as e } from "./Field-VQwmrIna.js";
|
|
2
2
|
import { FieldError as t, Label as n, Radio as r, RadioGroup as i, Text as a } from "react-aria-components";
|
|
3
3
|
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
4
4
|
var c = {
|
|
@@ -46,4 +46,4 @@ function u({ children: e, className: t, ...n }) {
|
|
|
46
46
|
//#endregion
|
|
47
47
|
export { l as n, u as t };
|
|
48
48
|
|
|
49
|
-
//# sourceMappingURL=RadioGroup-
|
|
49
|
+
//# sourceMappingURL=RadioGroup-CIpHr3g6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup-
|
|
1
|
+
{"version":3,"file":"RadioGroup-CIpHr3g6.js","names":[],"sources":["../../src/components/RadioGroup/RadioGroup.module.css","../../src/components/RadioGroup/RadioGroup.tsx"],"sourcesContent":[".group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-family: var(--wzl-font-ui);\n color: var(--wzl-fg);\n}\n\n.group[data-orientation=\"horizontal\"] {\n flex-direction: row;\n gap: 16px;\n}\n\n.legend {\n font-size: 12px;\n font-weight: 500;\n color: var(--wzl-fg);\n}\n\n.radio {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n font-size: 13px;\n color: var(--wzl-fg);\n user-select: none;\n -webkit-user-select: none;\n}\n\n.radio[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.dot {\n position: relative;\n flex: 0 0 auto;\n width: 14px;\n height: 14px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border-strong);\n border-radius: 50%;\n transition: border-color var(--wzl-motion-fast), box-shadow var(--wzl-motion-fast);\n}\n\n.radio[data-focus-visible] .dot {\n box-shadow: 0 0 0 2px var(--wzl-focus-ring);\n}\n\n.radio[data-hovered]:not([data-disabled]) .dot {\n border-color: var(--wzl-fg-muted);\n}\n\n.radio[data-selected] .dot {\n border-color: var(--wzl-accent-strong);\n}\n\n.dot::after {\n content: '';\n position: absolute;\n inset: 3px;\n border-radius: 50%;\n background: var(--wzl-accent-strong);\n transform: scale(0);\n transition: transform var(--wzl-motion-fast);\n}\n\n.radio[data-selected] .dot::after {\n transform: scale(1);\n}\n","import type { ReactNode } from 'react';\nimport {\n RadioGroup as RACRadioGroup,\n Radio as RACRadio,\n Label,\n Text,\n FieldError,\n type RadioGroupProps as RACRadioGroupProps,\n type RadioProps as RACRadioProps,\n type ValidationResult,\n} from 'react-aria-components';\nimport { fieldClasses } from '../Field/Field';\nimport s from './RadioGroup.module.css';\n\nexport type RadioGroupProps = Omit<RACRadioGroupProps, 'children' | 'className'> & {\n label?: ReactNode;\n description?: ReactNode;\n errorMessage?: ReactNode | ((v: ValidationResult) => ReactNode);\n children?: ReactNode;\n className?: string;\n};\n\nexport function RadioGroup(props: RadioGroupProps) {\n const { label, description, errorMessage, children, className, ...rest } = props;\n return (\n <RACRadioGroup\n {...rest}\n className={[s.group, fieldClasses.root, className].filter(Boolean).join(' ')}\n >\n {label !== undefined && <Label className={s.legend}>{label}</Label>}\n {children}\n {description !== undefined && (\n <Text slot=\"description\" className={fieldClasses.hint}>\n {description}\n </Text>\n )}\n <FieldError className={fieldClasses.error}>{errorMessage}</FieldError>\n </RACRadioGroup>\n );\n}\n\nexport type RadioProps = Omit<RACRadioProps, 'className' | 'children'> & {\n children?: ReactNode;\n className?: string;\n};\n\nexport function Radio({ children, className, ...rest }: RadioProps) {\n return (\n <RACRadio {...rest} className={[s.radio, className].filter(Boolean).join(' ')}>\n <span className={s.dot} />\n {children !== undefined && <span>{children}</span>}\n </RACRadio>\n );\n}\n"],"mappings":";;;;;;;;;;;ACsBA,SAAgB,EAAW,GAAwB;CACjD,IAAM,EAAE,UAAO,gBAAa,iBAAc,aAAU,cAAW,GAAG,MAAS;AAC3E,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,EAAE;cAAS;IAAc,CAAA;GAClE;GACA,MAAgB,KAAA,KACf,kBAAC,GAAD;IAAM,MAAK;IAAc,WAAW,EAAa;cAC9C;IACI,CAAA;GAET,kBAAC,GAAD;IAAY,WAAW,EAAa;cAAQ;IAA0B,CAAA;GACxD;;;AASpB,SAAgB,EAAM,EAAE,aAAU,cAAW,GAAG,KAAoB;AAClE,QACE,kBAAC,GAAD;EAAU,GAAI;EAAM,WAAW,CAAC,EAAE,OAAO,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAA7E,CACE,kBAAC,QAAD,EAAM,WAAW,EAAE,KAAO,CAAA,EACzB,MAAa,KAAA,KAAa,kBAAC,QAAD,EAAO,aAAgB,CAAA,CACzC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RangeSlider-
|
|
1
|
+
{"version":3,"file":"RangeSlider-CaDogGTj.js","names":[],"sources":["../../src/components/RangeSlider/RangeSlider.module.css","../../src/components/RangeSlider/RangeSlider.tsx"],"sourcesContent":[".slider {\n display: flex;\n flex-direction: column;\n width: 100%;\n gap: 4px;\n font-family: var(--wzl-font-ui);\n color: var(--wzl-fg);\n}\n\n.slider[data-orientation=\"vertical\"] {\n flex-direction: row;\n align-items: stretch;\n width: 28px;\n height: 160px;\n}\n\n.head {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 8px;\n}\n\n.label {\n font-size: 12px;\n font-weight: 500;\n color: var(--wzl-fg);\n}\n\n.output {\n font-size: 12px;\n color: var(--wzl-fg-subtle);\n font-variant-numeric: tabular-nums;\n}\n\n.track {\n position: relative;\n height: 6px;\n min-width: 80px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: 3px;\n}\n\n.slider[data-orientation=\"vertical\"] .track {\n width: 6px;\n height: 100%;\n}\n\n.fill {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n background: var(--wzl-accent-strong);\n border-radius: 3px;\n}\n\n.thumb {\n width: 14px;\n height: 14px;\n background: var(--wzl-fg-muted);\n border: 1px solid var(--wzl-border-strong);\n border-radius: 50%;\n cursor: ew-resize;\n outline: none;\n transition: box-shadow var(--wzl-motion-fast);\n}\n\n.slider[data-orientation=\"vertical\"] .thumb {\n cursor: ns-resize;\n}\n\n.thumb[data-focus-visible] {\n box-shadow: 0 0 0 2px var(--wzl-focus-ring);\n}\n\n.thumb[data-dragging] {\n background: var(--wzl-accent-strong);\n}\n\n.slider[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n","import type { ReactNode } from 'react';\nimport {\n Slider as RACSlider,\n SliderOutput,\n SliderTrack,\n SliderThumb,\n Label,\n type SliderProps as RACSliderProps,\n} from 'react-aria-components';\nimport s from './RangeSlider.module.css';\n\nexport type RangeSliderProps = Omit<RACSliderProps, 'children' | 'className'> & {\n label?: ReactNode;\n /** Show the current value next to the label. Defaults to true when a\n * label is supplied. */\n showOutput?: boolean;\n /** Format the rendered value(s). Useful for units (`v => `${v}%``). */\n formatOutput?: (v: number | number[]) => ReactNode;\n className?: string;\n};\n\n/**\n * Linear range slider on React Aria. Single-value by default; pass an array\n * to `value` / `defaultValue` for multi-thumb. Distinct from the kit's\n * canvas-scrub `Slider`, which is shaped for tool-canvas interactions.\n */\nexport function RangeSlider(props: RangeSliderProps) {\n const { label, showOutput, formatOutput, className, ...rest } = props;\n const wantOutput = showOutput ?? label !== undefined;\n return (\n <RACSlider {...rest} className={[s.slider, className].filter(Boolean).join(' ')}>\n {(label !== undefined || wantOutput) && (\n <div className={s.head}>\n {label !== undefined && <Label className={s.label}>{label}</Label>}\n {wantOutput && (\n <SliderOutput className={s.output}>\n {({ state }) => {\n const v = state.values.length === 1 ? state.values[0] : state.values;\n return formatOutput ? formatOutput(v) : Array.isArray(v) ? v.join(' – ') : String(v);\n }}\n </SliderOutput>\n )}\n </div>\n )}\n <SliderTrack className={s.track}>\n {({ state }) => {\n // Single-thumb: fill from start to thumb. Multi-thumb: fill\n // between adjacent thumbs (simplest = between first and last).\n const fillStart = state.values.length > 1 ? state.getThumbPercent(0) * 100 : 0;\n const fillEnd = state.getThumbPercent(state.values.length - 1) * 100;\n return (\n <>\n <div\n className={s.fill}\n style={{ left: `${fillStart}%`, right: `${100 - fillEnd}%` }}\n />\n {state.values.map((_, i) => (\n <SliderThumb key={i} index={i} className={s.thumb} />\n ))}\n </>\n );\n }}\n </SliderTrack>\n </RACSlider>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AC0BA,SAAgB,EAAY,GAAyB;CACnD,IAAM,EAAE,UAAO,eAAY,iBAAc,cAAW,GAAG,MAAS,GAC1D,IAAa,KAAc,MAAU,KAAA;AAC3C,QACE,kBAAC,GAAD;EAAW,GAAI;EAAM,WAAW,CAAC,EAAE,QAAQ,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAA/E,EACI,MAAU,KAAA,KAAa,MACvB,kBAAC,OAAD;GAAK,WAAW,EAAE;aAAlB,CACG,MAAU,KAAA,KAAa,kBAAC,GAAD;IAAO,WAAW,EAAE;cAAQ;IAAc,CAAA,EACjE,KACC,kBAAC,GAAD;IAAc,WAAW,EAAE;eACvB,EAAE,eAAY;KACd,IAAM,IAAI,EAAM,OAAO,WAAW,IAAI,EAAM,OAAO,KAAK,EAAM;AAC9D,YAAO,IAAe,EAAa,EAAE,GAAG,MAAM,QAAQ,EAAE,GAAG,EAAE,KAAK,MAAM,GAAG,OAAO,EAAE;;IAEzE,CAAA,CAEb;MAER,kBAAC,GAAD;GAAa,WAAW,EAAE;cACtB,EAAE,eAAY;IAGd,IAAM,IAAY,EAAM,OAAO,SAAS,IAAI,EAAM,gBAAgB,EAAE,GAAG,MAAM,GACvE,IAAU,EAAM,gBAAgB,EAAM,OAAO,SAAS,EAAE,GAAG;AACjE,WACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;KACE,WAAW,EAAE;KACb,OAAO;MAAE,MAAM,GAAG,EAAU;MAAI,OAAO,GAAG,MAAM,EAAQ;MAAI;KAC5D,CAAA,EACD,EAAM,OAAO,KAAK,GAAG,MACpB,kBAAC,GAAD;KAAqB,OAAO;KAAG,WAAW,EAAE;KAAS,EAAnC,EAAmC,CACrD,CACD,EAAA,CAAA;;GAGK,CAAA,CACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResizeHandle-
|
|
1
|
+
{"version":3,"file":"ResizeHandle-CCQ2y87y.js","names":[],"sources":["../../src/components/ResizeHandle/ResizeHandle.module.css","../../src/components/ResizeHandle/ResizeHandle.tsx"],"sourcesContent":[".handle {\n flex-shrink: 0;\n width: 4px;\n align-self: stretch;\n cursor: ew-resize;\n background: transparent;\n border-left: 1px solid var(--wzl-border);\n /* The bar is 4px of hit area — thin enough to read as a seam, wide\n enough to grab. `touch-action: none` keeps a touch drag from being\n stolen by the scroll container it usually sits inside. */\n touch-action: none;\n}\n\n.handle.horizontal {\n width: auto;\n height: 4px;\n align-self: auto;\n cursor: ns-resize;\n border-left: none;\n border-top: 1px solid var(--wzl-border);\n}\n\n.handle:hover {\n background: var(--wzl-border);\n}\n\n.handle:focus-visible {\n outline: 2px solid var(--wzl-focus-ring, var(--wzl-accent));\n outline-offset: -1px;\n}\n","import { useCallback, useRef, type KeyboardEvent, type PointerEvent } from 'react';\nimport s from './ResizeHandle.module.css';\n\nexport interface ResizeHandleProps {\n /**\n * Which way the handle *runs*, matching `aria-orientation` on the\n * separator role: a `vertical` handle is a vertical bar between two\n * side-by-side panes and drags horizontally. `horizontal` is the\n * stacked case (a bar between rows, dragged up and down).\n */\n orientation?: 'vertical' | 'horizontal';\n /** Current size of the pane being resized, in pixels. */\n value: number;\n min: number;\n max: number;\n /**\n * Flip the sign of the drag. Panes docked to the *trailing* edge (a\n * right sidebar, a bottom drawer) grow as the pointer moves toward the\n * start of the axis, so they want `invert`. Leading-edge panes don't.\n */\n invert?: boolean;\n /**\n * Fires continuously while dragging and on each keyboard step, always\n * clamped to [min, max]. Drive the live size from this.\n */\n onChange(next: number): void;\n /**\n * Fires once when a drag ends or a keyboard step settles, with the final\n * size. Persist here rather than in `onChange` — one write per gesture\n * instead of one per pointer sample.\n */\n onChangeEnd?(next: number): void;\n /**\n * The granularity of `value`. Arrow keys move by one step (Shift by\n * eight), and pointer drags snap to the same grid — a pointer reports\n * fractional coordinates on a scaled display, and nobody wants\n * `362.9453125` in their persisted layout. Set a fractional step for a\n * pane measured in something finer than whole pixels.\n */\n step?: number;\n ariaLabel?: string;\n className?: string;\n}\n\nconst clamp = (n: number, min: number, max: number): number => Math.min(max, Math.max(min, n));\n\n/**\n * Snap to the step grid, then clamp. Bounds win over the grid: `min`/`max`\n * are hard limits, so a range that isn't a whole number of steps clips to\n * the bound rather than overshooting it.\n */\nfunction settle(n: number, min: number, max: number, step: number): number {\n const snapped = step > 0 ? Math.round(n / step) * step : n;\n // Re-round to kill the float dust `x / 0.1 * 0.1` leaves behind.\n const precise = Number.isInteger(step) ? snapped : Number(snapped.toFixed(10));\n return clamp(precise, min, max);\n}\n\n/**\n * Draggable divider for resizing a pane — the \"window splitter\" pattern.\n * Owns no size of its own: the consumer holds `value` and applies it\n * (typically as a CSS custom property on the pane), which keeps the handle\n * usable for flex, grid, and absolutely-positioned layouts alike.\n *\n * Keyboard-operable as a matter of course: it's focusable, arrows step by\n * `step` (Shift for a coarse step), Home/End jump to the bounds. A splitter\n * that only responds to a pointer drag strands anyone who can't make one.\n */\nexport function ResizeHandle(props: ResizeHandleProps) {\n const {\n orientation = 'vertical', value, min, max, invert, onChange, onChangeEnd,\n step = 1, ariaLabel, className,\n } = props;\n\n // Drag origin. Captured on pointerdown so every move is measured against\n // the gesture's start rather than the previous sample — accumulating\n // per-sample deltas drifts once the pointer leaves the clamped range.\n const drag = useRef<{ origin: number; startValue: number } | null>(null);\n\n const axisOf = useCallback(\n (e: PointerEvent<HTMLDivElement>) => (orientation === 'vertical' ? e.clientX : e.clientY),\n [orientation],\n );\n\n const onPointerDown = useCallback((e: PointerEvent<HTMLDivElement>) => {\n if (e.button !== 0) return;\n drag.current = { origin: axisOf(e), startValue: value };\n // jsdom has no pointer capture; the guard keeps tests on the real path.\n e.currentTarget.setPointerCapture?.(e.pointerId);\n e.preventDefault();\n }, [axisOf, value]);\n\n const onPointerMove = useCallback((e: PointerEvent<HTMLDivElement>) => {\n const d = drag.current;\n if (!d) return;\n const delta = axisOf(e) - d.origin;\n onChange(settle(d.startValue + (invert ? -delta : delta), min, max, step));\n }, [axisOf, invert, max, min, onChange, step]);\n\n const endDrag = useCallback((e: PointerEvent<HTMLDivElement>) => {\n const d = drag.current;\n if (!d) return;\n drag.current = null;\n e.currentTarget.releasePointerCapture?.(e.pointerId);\n const delta = axisOf(e) - d.origin;\n onChangeEnd?.(settle(d.startValue + (invert ? -delta : delta), min, max, step));\n }, [axisOf, invert, max, min, onChangeEnd, step]);\n\n const onKeyDown = useCallback((e: KeyboardEvent<HTMLDivElement>) => {\n const grow = orientation === 'vertical' ? 'ArrowRight' : 'ArrowDown';\n const shrink = orientation === 'vertical' ? 'ArrowLeft' : 'ArrowUp';\n const amount = step * (e.shiftKey ? 8 : 1) * (invert ? -1 : 1);\n let next: number | undefined;\n if (e.key === grow) next = value + amount;\n else if (e.key === shrink) next = value - amount;\n else if (e.key === 'Home') next = invert ? max : min;\n else if (e.key === 'End') next = invert ? min : max;\n if (next === undefined) return;\n e.preventDefault();\n const settled = settle(next, min, max, step);\n onChange(settled);\n onChangeEnd?.(settled);\n }, [invert, max, min, onChange, onChangeEnd, orientation, step, value]);\n\n const cls = [s.handle, orientation === 'horizontal' && s.horizontal, className]\n .filter(Boolean).join(' ');\n\n return (\n <div\n className={cls}\n role=\"separator\"\n tabIndex={0}\n aria-label={ariaLabel}\n aria-orientation={orientation}\n aria-valuenow={value}\n aria-valuemin={min}\n aria-valuemax={max}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onKeyDown={onKeyDown}\n />\n );\n}\n"],"mappings":";;;;;GC4CM,KAAS,GAAW,GAAa,MAAwB,KAAK,IAAI,GAAK,KAAK,IAAI,GAAK,EAAE,CAAC;AAO9F,SAAS,EAAO,GAAW,GAAa,GAAa,GAAsB;CACzE,IAAM,IAAU,IAAO,IAAI,KAAK,MAAM,IAAI,EAAK,GAAG,IAAO;AAGzD,QAAO,EADS,OAAO,UAAU,EAAK,GAAG,IAAU,OAAO,EAAQ,QAAQ,GAAG,CAAC,EACxD,GAAK,EAAI;;AAajC,SAAgB,EAAa,GAA0B;CACrD,IAAM,EACJ,iBAAc,YAAY,UAAO,QAAK,QAAK,WAAQ,aAAU,gBAC7D,UAAO,GAAG,cAAW,iBACnB,GAKE,IAAO,EAAsD,KAAK,EAElE,IAAS,GACZ,MAAqC,MAAgB,aAAa,EAAE,UAAU,EAAE,SACjF,CAAC,EAAY,CACd,EAEK,IAAgB,GAAa,MAAoC;AACjE,IAAE,WAAW,MACjB,EAAK,UAAU;GAAE,QAAQ,EAAO,EAAE;GAAE,YAAY;GAAO,EAEvD,EAAE,cAAc,oBAAoB,EAAE,UAAU,EAChD,EAAE,gBAAgB;IACjB,CAAC,GAAQ,EAAM,CAAC,EAEb,IAAgB,GAAa,MAAoC;EACrE,IAAM,IAAI,EAAK;AACf,MAAI,CAAC,EAAG;EACR,IAAM,IAAQ,EAAO,EAAE,GAAG,EAAE;AAC5B,IAAS,EAAO,EAAE,cAAc,IAAS,CAAC,IAAQ,IAAQ,GAAK,GAAK,EAAK,CAAC;IACzE;EAAC;EAAQ;EAAQ;EAAK;EAAK;EAAU;EAAK,CAAC,EAExC,IAAU,GAAa,MAAoC;EAC/D,IAAM,IAAI,EAAK;AACf,MAAI,CAAC,EAAG;AAER,EADA,EAAK,UAAU,MACf,EAAE,cAAc,wBAAwB,EAAE,UAAU;EACpD,IAAM,IAAQ,EAAO,EAAE,GAAG,EAAE;AAC5B,MAAc,EAAO,EAAE,cAAc,IAAS,CAAC,IAAQ,IAAQ,GAAK,GAAK,EAAK,CAAC;IAC9E;EAAC;EAAQ;EAAQ;EAAK;EAAK;EAAa;EAAK,CAAC,EAE3C,IAAY,GAAa,MAAqC;EAClE,IAAM,IAAO,MAAgB,aAAa,eAAe,aACnD,IAAS,MAAgB,aAAa,cAAc,WACpD,IAAS,KAAQ,EAAE,WAAW,IAAI,MAAM,IAAS,KAAK,IACxD;AAKJ,MAJI,EAAE,QAAQ,IAAM,IAAO,IAAQ,IAC1B,EAAE,QAAQ,IAAQ,IAAO,IAAQ,IACjC,EAAE,QAAQ,SAAQ,IAAO,IAAS,IAAM,IACxC,EAAE,QAAQ,UAAO,IAAO,IAAS,IAAM,IAC5C,MAAS,KAAA,EAAW;AACxB,IAAE,gBAAgB;EAClB,IAAM,IAAU,EAAO,GAAM,GAAK,GAAK,EAAK;AAE5C,EADA,EAAS,EAAQ,EACjB,IAAc,EAAQ;IACrB;EAAC;EAAQ;EAAK;EAAK;EAAU;EAAa;EAAa;EAAM;EAAM,CAAC;AAKvE,QACE,kBAAC,OAAD;EACE,WALQ;GAAC,EAAE;GAAQ,MAAgB,gBAAgB,EAAE;GAAY;GAAU,CAC5E,OAAO,QAAQ,CAAC,KAAK,IAIT;EACX,MAAK;EACL,UAAU;EACV,cAAY;EACZ,oBAAkB;EAClB,iBAAe;EACf,iBAAe;EACf,iBAAe;EACA;EACA;EACf,aAAa;EACb,iBAAiB;EACN;EACX,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e } from "./Field-
|
|
1
|
+
import { n as e } from "./Field-VQwmrIna.js";
|
|
2
2
|
import { Button as t, FieldError as n, Label as r, ListBox as i, ListBoxItem as a, Popover as o, Select as s, SelectValue 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 = {
|
|
@@ -100,4 +100,4 @@ function h({ children: e, className: t, textValue: n, ...r }) {
|
|
|
100
100
|
//#endregion
|
|
101
101
|
export { h as n, p as t };
|
|
102
102
|
|
|
103
|
-
//# sourceMappingURL=Select-
|
|
103
|
+
//# sourceMappingURL=Select-BE3Y1NrH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select-
|
|
1
|
+
{"version":3,"file":"Select-BE3Y1NrH.js","names":[],"sources":["../../src/components/Select/Select.module.css","../../src/components/Select/Select.tsx"],"sourcesContent":[".field {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n gap: 4px;\n}\n\n.trigger {\n display: flex;\n width: 100%;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 6px 0 10px;\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 cursor: pointer;\n transition: border-color var(--wzl-motion-fast), box-shadow var(--wzl-motion-fast);\n}\n\n.trigger[data-focus-visible] {\n border-color: var(--wzl-focus-ring);\n box-shadow: 0 0 0 1px var(--wzl-focus-ring);\n}\n\n.field[data-invalid] .trigger {\n border-color: var(--wzl-danger, #ff5b5b);\n}\n\n.trigger[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.value {\n flex: 1;\n min-width: 0;\n text-align: left;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.value[data-placeholder] {\n color: var(--wzl-fg-subtle);\n}\n\n.chevron {\n width: 10px;\n height: 10px;\n color: var(--wzl-fg-muted);\n flex: 0 0 auto;\n}\n\n.popover {\n min-width: var(--trigger-width);\n max-height: inherit;\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 gap: 8px;\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 color: var(--wzl-fg);\n font-weight: 500;\n}\n\n.option[data-disabled] {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.check {\n width: 10px;\n height: 10px;\n flex: 0 0 auto;\n opacity: 0;\n}\n\n.option[data-selected] .check {\n opacity: 1;\n}\n","import type { ReactNode } from 'react';\nimport {\n Select as RACSelect,\n Label,\n Button as RACButton,\n SelectValue,\n Popover as RACPopover,\n ListBox as RACListBox,\n ListBoxItem as RACListBoxItem,\n Text,\n FieldError,\n type SelectProps as RACSelectProps,\n type ListBoxItemProps as RACListBoxItemProps,\n type ValidationResult,\n} from 'react-aria-components';\nimport { fieldClasses } from '../Field/Field';\nimport s from './Select.module.css';\n\nexport type SelectOption = {\n value: string;\n label: ReactNode;\n isDisabled?: boolean;\n /**\n * Plain-text form of `label`, for type-to-select and screen readers.\n * Only needed when `label` isn't a bare string — a label built from\n * elements has no text React Aria can read off it. A string label\n * supplies this itself.\n */\n textValue?: string;\n};\n\ntype Key = string | number;\n\nexport type SelectProps<T extends Key = string> = Omit<RACSelectProps<object>, 'children' | 'className' | 'selectedKey' | 'defaultSelectedKey' | 'onSelectionChange'> & {\n label?: ReactNode;\n description?: ReactNode;\n errorMessage?: ReactNode | ((v: ValidationResult) => ReactNode);\n placeholder?: string;\n /** Either pass `options` for a quick render, or `children` for full control. */\n options?: ReadonlyArray<SelectOption & { value: T }>;\n children?: ReactNode;\n selectedKey?: T | null;\n defaultSelectedKey?: T;\n onSelectionChange?: (key: T) => void;\n className?: string;\n};\n\n/**\n * Form select wrapping React Aria's Select. Pass either `options` for a\n * quick declarative render or `children` of `<SelectItem>` for control over\n * each row.\n *\n * The selection key type is parameterized so consumers with a string-literal\n * union for `value` (e.g. `'r' | 'g' | 'b'`) get a typed `onSelectionChange`.\n */\nexport function Select<T extends Key = string>(props: SelectProps<T>) {\n const {\n label,\n description,\n errorMessage,\n placeholder,\n options,\n children,\n selectedKey,\n defaultSelectedKey,\n onSelectionChange,\n className,\n ...rest\n } = props;\n\n return (\n <RACSelect\n {...rest}\n selectedKey={selectedKey ?? undefined}\n defaultSelectedKey={defaultSelectedKey}\n onSelectionChange={onSelectionChange ? (k) => onSelectionChange(k as T) : undefined}\n className={[s.field, fieldClasses.root, className].filter(Boolean).join(' ')}\n >\n {label !== undefined && <Label className={fieldClasses.label}>{label}</Label>}\n <RACButton className={s.trigger}>\n <SelectValue className={s.value}>\n {({ defaultChildren, isPlaceholder }) =>\n isPlaceholder ? (placeholder ?? defaultChildren) : defaultChildren\n }\n </SelectValue>\n <svg className={s.chevron} 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 {description !== undefined && (\n <Text slot=\"description\" className={fieldClasses.hint}>\n {description}\n </Text>\n )}\n <FieldError className={fieldClasses.error}>{errorMessage}</FieldError>\n {/* `data-weasel-overlay` marks DOM that belongs to this control but\n renders in a portal, outside the subtree the trigger sits in. Any\n consumer reasoning about \"did focus leave my component?\" via\n `closest()` gets the wrong answer without it — a text editor whose\n font menu lives here would end its session the moment the menu is\n clicked. */}\n <RACPopover className={s.popover} data-weasel-overlay=\"\">\n <RACListBox className={s.listbox}>\n {options !== undefined\n ? options.map((o) => (\n <SelectItem\n key={String(o.value)}\n id={o.value}\n isDisabled={o.isDisabled}\n textValue={o.textValue}\n >\n {o.label}\n </SelectItem>\n ))\n : children}\n </RACListBox>\n </RACPopover>\n </RACSelect>\n );\n}\n\nexport type SelectItemProps = Omit<RACListBoxItemProps, 'className' | 'children'> & {\n children?: ReactNode;\n className?: string;\n};\n\n/**\n * Every row renders a check mark beside its label, so from React Aria's\n * side the children are never plain text and it can't derive the string\n * type-to-select and screen readers need — it warns once per row. A string\n * label already *is* that string, so derive it rather than making every\n * call site restate it; anything richer has to say what it reads as.\n */\nfunction textValueOf(children: ReactNode, explicit: string | undefined): string | undefined {\n if (explicit !== undefined) return explicit;\n return typeof children === 'string' || typeof children === 'number'\n ? String(children)\n : undefined;\n}\n\nexport function SelectItem({ children, className, textValue, ...rest }: SelectItemProps) {\n return (\n <RACListBoxItem\n {...rest}\n textValue={textValueOf(children, textValue)}\n className={[s.option, className].filter(Boolean).join(' ')}\n >\n <svg className={s.check} viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <polyline points=\"1.5,5 4,7.5 8.5,3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n {children}\n </RACListBoxItem>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;ACuDA,SAAgB,EAA+B,GAAuB;CACpE,IAAM,EACJ,UACA,gBACA,iBACA,gBACA,YACA,aACA,gBACA,uBACA,sBACA,cACA,GAAG,MACD;AAEJ,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,aAAa,KAAe,KAAA;EACR;EACpB,mBAAmB,KAAqB,MAAM,EAAkB,EAAO,GAAG,KAAA;EAC1E,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,GAAD;IAAW,WAAW,EAAE;cAAxB,CACE,kBAAC,GAAD;KAAa,WAAW,EAAE;gBACtB,EAAE,oBAAiB,uBACnB,IAAiB,KAAe,IAAmB;KAEzC,CAAA,EACd,kBAAC,OAAD;KAAK,WAAW,EAAE;KAAS,SAAQ;KAAY,eAAY;eACzD,kBAAC,QAAD;MAAM,GAAE;MAAiB,MAAK;MAAO,QAAO;MAAe,aAAY;MAAM,eAAc;MAAQ,gBAAe;MAAU,CAAA;KACxH,CAAA,CACI;;GACX,MAAgB,KAAA,KACf,kBAAC,GAAD;IAAM,MAAK;IAAc,WAAW,EAAa;cAC9C;IACI,CAAA;GAET,kBAAC,GAAD;IAAY,WAAW,EAAa;cAAQ;IAA0B,CAAA;GAOtE,kBAAC,GAAD;IAAY,WAAW,EAAE;IAAS,uBAAoB;cACpD,kBAAC,GAAD;KAAY,WAAW,EAAE;eACtB,MAAY,KAAA,IAWT,IAVA,EAAQ,KAAK,MACX,kBAAC,GAAD;MAEE,IAAI,EAAE;MACN,YAAY,EAAE;MACd,WAAW,EAAE;gBAEZ,EAAE;MACQ,EANN,OAAO,EAAE,MAAM,CAMT,CACb;KAEK,CAAA;IACF,CAAA;GACH;;;AAgBhB,SAAS,EAAY,GAAqB,GAAkD;AAE1F,QADI,MAAa,KAAA,IACV,OAAO,KAAa,YAAY,OAAO,KAAa,WACvD,OAAO,EAAS,GAChB,KAAA,IAH+B;;AAMrC,SAAgB,EAAW,EAAE,aAAU,cAAW,cAAW,GAAG,KAAyB;AACvF,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,WAAW,EAAY,GAAU,EAAU;EAC3C,WAAW,CAAC,EAAE,QAAQ,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAH5D,CAKE,kBAAC,OAAD;GAAK,WAAW,EAAE;GAAO,SAAQ;GAAY,eAAY;aACvD,kBAAC,YAAD;IAAU,QAAO;IAAoB,MAAK;IAAO,QAAO;IAAe,aAAY;IAAM,eAAc;IAAQ,gBAAe;IAAU,CAAA;GACpI,CAAA,EACL,EACc"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as e } from "./ColorField-
|
|
2
|
-
import { t } from "./Input-
|
|
3
|
-
import { t as n } from "./NumberField-
|
|
4
|
-
import { t as r } from "./Select-
|
|
5
|
-
import { t as i } from "./Switch-
|
|
1
|
+
import { t as e } from "./ColorField-ykpiD3XU.js";
|
|
2
|
+
import { t } from "./Input-DpkwYtUY.js";
|
|
3
|
+
import { t as n } from "./NumberField-BbzI0GtU.js";
|
|
4
|
+
import { t as r } from "./Select-BE3Y1NrH.js";
|
|
5
|
+
import { t as i } from "./Switch-JyVSSAzC.js";
|
|
6
6
|
import { Fragment as a, useState as o, useSyncExternalStore as s } from "react";
|
|
7
7
|
import { MIXED as c, asNodeId as l } from "@weasel-js/core";
|
|
8
8
|
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
@@ -300,4 +300,4 @@ function O({ text: e, placeholder: n, ariaLabel: r, onCommit: i }) {
|
|
|
300
300
|
//#endregion
|
|
301
301
|
export { _ as a, y as c, p as i, c as n, x as o, b as r, v as s, w as t };
|
|
302
302
|
|
|
303
|
-
//# sourceMappingURL=SelectionPanel-
|
|
303
|
+
//# sourceMappingURL=SelectionPanel-Zaw8tYQH.js.map
|