@adea-ai/ui 0.131.1 → 0.134.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.
- package/dist/components/composites/list-row/list-row-control.d.ts +9 -0
- package/dist/components/composites/list-row/list-row-control.d.ts.map +1 -1
- package/dist/components/composites/list-row/list-row-control.js +5 -1
- package/dist/components/composites/list-row/list-row-control.js.map +1 -1
- package/dist/components/composites/settings/settings.d.ts +8 -0
- package/dist/components/composites/settings/settings.d.ts.map +1 -1
- package/dist/components/composites/settings/settings.js +2 -1
- package/dist/components/composites/settings/settings.js.map +1 -1
- package/dist/components/ui/empty/empty-state.d.ts +21 -2
- package/dist/components/ui/empty/empty-state.d.ts.map +1 -1
- package/dist/components/ui/empty/empty-state.js +62 -18
- package/dist/components/ui/empty/empty-state.js.map +1 -1
- package/dist/components/ui/field/field.d.ts +5 -1
- package/dist/components/ui/field/field.d.ts.map +1 -1
- package/dist/components/ui/field/field.js +5 -1
- package/dist/components/ui/field/field.js.map +1 -1
- package/dist/components/ui/field/number-field.d.ts +18 -2
- package/dist/components/ui/field/number-field.d.ts.map +1 -1
- package/dist/components/ui/field/number-field.js +10 -4
- package/dist/components/ui/field/number-field.js.map +1 -1
- package/dist/components/ui/input-group/secret-input-group.d.ts +20 -1
- package/dist/components/ui/input-group/secret-input-group.d.ts.map +1 -1
- package/dist/components/ui/input-group/secret-input-group.js +15 -4
- package/dist/components/ui/input-group/secret-input-group.js.map +1 -1
- package/dist/components/ui/native-select/native-select.d.ts +8 -0
- package/dist/components/ui/native-select/native-select.d.ts.map +1 -1
- package/dist/components/ui/native-select/native-select.js +5 -3
- package/dist/components/ui/native-select/native-select.js.map +1 -1
- package/dist/r/src/components/composites/list-row/list-row-control.tsx +12 -1
- package/dist/r/src/components/composites/settings/settings.tsx +11 -1
- package/dist/r/src/components/ui/empty/empty-state.tsx +59 -21
- package/dist/r/src/components/ui/field/field.tsx +10 -2
- package/dist/r/src/components/ui/field/number-field.tsx +35 -4
- package/dist/r/src/components/ui/input-group/secret-input-group.tsx +28 -3
- package/dist/r/src/components/ui/native-select/native-select.tsx +14 -2
- package/package.json +1 -1
- package/src/components/composites/list-row/list-row-control.tsx +12 -1
- package/src/components/composites/settings/settings.tsx +11 -1
- package/src/components/ui/empty/empty-state.tsx +59 -21
- package/src/components/ui/field/field.tsx +10 -2
- package/src/components/ui/field/number-field.tsx +35 -4
- package/src/components/ui/input-group/secret-input-group.tsx +28 -3
- package/src/components/ui/native-select/native-select.tsx +14 -2
|
@@ -12,6 +12,15 @@ export type ListRowControlProps<T extends ValidComponent = 'div'> = PolymorphicP
|
|
|
12
12
|
trailing?: JSX.Element;
|
|
13
13
|
/** A second line that wraps and grows the row to fit its content. */
|
|
14
14
|
description?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Keep the description on one line and end it with an ellipsis instead of
|
|
17
|
+
* wrapping, so a described row stays at its minimum height however long the
|
|
18
|
+
* text is. Use it where rows must be a predictable height (a virtualised
|
|
19
|
+
* queue); leave it off where the whole description should be readable. Pair
|
|
20
|
+
* it with a `tooltip` when the full text matters, and with
|
|
21
|
+
* `stackTrailing={false}` to keep a trailing slot beside the text.
|
|
22
|
+
*/
|
|
23
|
+
truncateDescription?: boolean;
|
|
15
24
|
/**
|
|
16
25
|
* Whether a described row may drop its trailing slot onto its own line when
|
|
17
26
|
* the row gets narrow (the default). Pass `false` for a short, truncating
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-row-control.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/list-row/list-row-control.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAEjE,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAInE,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,IAAI,gBAAgB,CAClF,CAAC,EACD;IACE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,oDAAoD;IACpD,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,gEAAgE;IAChE,IAAI,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAA;CACxC,CACF,CAAA;AAMD,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"list-row-control.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/list-row/list-row-control.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAEjE,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAInE,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,IAAI,gBAAgB,CAClF,CAAC,EACD;IACE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,oDAAoD;IACpD,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACrB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACtB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,gEAAgE;IAChE,IAAI,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAA;CACxC,CACF,CAAA;AAMD,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,CAAC,SAAS,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,eAkF7F"}
|
|
@@ -17,6 +17,7 @@ function ListRowControl(props) {
|
|
|
17
17
|
"leading",
|
|
18
18
|
"trailing",
|
|
19
19
|
"description",
|
|
20
|
+
"truncateDescription",
|
|
20
21
|
"stackTrailing",
|
|
21
22
|
"type",
|
|
22
23
|
"tabIndex",
|
|
@@ -76,7 +77,10 @@ function ListRowControl(props) {
|
|
|
76
77
|
get children() {
|
|
77
78
|
var _el$5 = _tmpl$2();
|
|
78
79
|
insert(_el$5, () => local.description);
|
|
79
|
-
effect(() => className(_el$5, cn("text-xs
|
|
80
|
+
effect(() => className(_el$5, cn("text-xs", {
|
|
81
|
+
truncate: local.truncateDescription,
|
|
82
|
+
"break-words": !local.truncateDescription
|
|
83
|
+
}, local.selected ? "text-foreground" : "text-muted-foreground")));
|
|
80
84
|
return _el$5;
|
|
81
85
|
}
|
|
82
86
|
}), null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-row-control.js","names":["PolymorphicProps","Polymorphic","ComponentProps","JSX","ValidComponent","Show","splitProps","cn","ListRowControlProps","T","class","selected","dense","leading","Element","trailing","description","stackTrailing","type","ListRowControlBaseProps","as","ListRowControl","props","local","rest","hasClickHandler","Boolean","onClick","rowAs","_$createComponent","_$mergeProps","_$memo","tabIndex","undefined","aria-current","data-selected","data-description","data-stack-trailing","children","when","_el$","_tmpl$","_$insert","_el$2","_tmpl$4","_el$3","firstChild","_el$4","_el$5","_tmpl$2","_$effect","_$className","_el$6","_tmpl$3","_$createComponent","_$mergeProps","_$memo","_$className"],"sources":["../../../../src/components/composites/list-row/list-row-control.tsx"],"sourcesContent":["import type { PolymorphicProps } from '@kobalte/core/polymorphic'\nimport { Polymorphic } from '@kobalte/core/polymorphic'\nimport type { ComponentProps, JSX, ValidComponent } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\nexport type ListRowControlProps<T extends ValidComponent = 'div'> = PolymorphicProps<\n T,\n {\n class?: string\n /** Marks the row as current. Sets `aria-current` for a link row. */\n selected?: boolean\n /** Draw the row at the compact height. */\n dense?: boolean\n /** Leading slot: an avatar, an icon, a checkbox. */\n leading?: JSX.Element\n /** Trailing slot: a count, a menu trigger, a timestamp. */\n trailing?: JSX.Element\n /** A second line that wraps and grows the row to fit its content. */\n description?: string\n /**\n * Whether a described row may drop its trailing slot onto its own line when\n * the row gets narrow (the default). Pass `false` for a short, truncating\n * label whose single action must stay beside it.\n */\n stackTrailing?: boolean\n /** Native button type; defaults to `button` for button rows. */\n type?: ComponentProps<'button'>['type']\n }\n>\n\ntype ListRowControlBaseProps<T extends ValidComponent = 'div'> = ListRowControlProps<T> & {\n as?: T\n}\n\n/** A tree-shakeable ListRow renderer without optional tooltip behavior. */\nexport function ListRowControl<T extends ValidComponent = 'div'>(props: ListRowControlProps<T>) {\n const [local, rest] = splitProps(props as ListRowControlBaseProps, [\n 'as',\n 'class',\n 'selected',\n 'dense',\n 'leading',\n 'trailing',\n 'description',\n 'stackTrailing',\n 'type',\n 'tabIndex',\n 'children',\n ])\n const hasClickHandler = () => Boolean(rest.onClick || rest['on:click'])\n const rowAs = () => (local.as ?? (hasClickHandler() ? 'button' : 'div')) as T\n\n return (\n <Polymorphic\n as={rowAs()}\n data-slot=\"list-row\"\n type={rowAs() === 'button' ? (local.type ?? 'button') : local.type}\n tabIndex={local.tabIndex ?? (rowAs() === 'button' || rowAs() === 'a' ? 0 : undefined)}\n aria-current={local.selected ? 'true' : undefined}\n data-selected={local.selected ? '' : undefined}\n data-description={local.description ? '' : undefined}\n data-stack-trailing={local.stackTrailing === false ? 'never' : undefined}\n class={cn(\n 'group/row list-row-description flex min-w-0 items-center gap-2.5 rounded-md px-2 text-sm',\n 'transition-colors ease-out outline-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n {\n 'h-row-sm': local.dense && !local.description,\n 'h-row-md': !local.dense && !local.description,\n },\n {\n 'bg-primary-subtle text-foreground': local.selected,\n 'hover:bg-surface-hover': !local.selected,\n },\n local.class\n )}\n {...(rest as ComponentProps<'div'>)}\n >\n <Show when={local.leading}>\n <span\n data-slot=\"list-row-leading\"\n class=\"flex shrink-0 items-center justify-center [&_svg]:size-4\"\n >\n {local.leading}\n </span>\n </Show>\n <div data-slot=\"list-row-content\" class=\"flex min-w-0 flex-1 items-center gap-2.5\">\n <span data-slot=\"list-row-label\" class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\">{local.children}</span>\n <Show when={local.description}>\n <span\n data-slot=\"list-row-description\"\n class={cn(\n 'text-xs break-words',\n local.selected ? 'text-foreground' : 'text-muted-foreground'\n )}\n >\n {local.description}\n </span>\n </Show>\n </span>\n <Show when={local.trailing}>\n <span\n data-slot=\"list-row-trailing\"\n class={cn(\n 'ms-auto flex shrink-0 items-center gap-1',\n local.selected ? 'text-foreground' : 'text-muted-foreground'\n )}\n >\n {local.trailing}\n </span>\n </Show>\n </div>\n </Polymorphic>\n )\n}\n"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"list-row-control.js","names":["PolymorphicProps","Polymorphic","ComponentProps","JSX","ValidComponent","Show","splitProps","cn","ListRowControlProps","T","class","selected","dense","leading","Element","trailing","description","truncateDescription","stackTrailing","type","ListRowControlBaseProps","as","ListRowControl","props","local","rest","hasClickHandler","Boolean","onClick","rowAs","_$createComponent","_$mergeProps","_$memo","tabIndex","undefined","aria-current","data-selected","data-description","data-stack-trailing","children","when","_el$","_tmpl$","_$insert","_el$2","_tmpl$4","_el$3","firstChild","_el$4","_el$5","_tmpl$2","_$effect","_$className","truncate","_el$6","_tmpl$3","_$createComponent","_$mergeProps","_$memo","_$className"],"sources":["../../../../src/components/composites/list-row/list-row-control.tsx"],"sourcesContent":["import type { PolymorphicProps } from '@kobalte/core/polymorphic'\nimport { Polymorphic } from '@kobalte/core/polymorphic'\nimport type { ComponentProps, JSX, ValidComponent } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { cn } from '#lib/utils'\n\nexport type ListRowControlProps<T extends ValidComponent = 'div'> = PolymorphicProps<\n T,\n {\n class?: string\n /** Marks the row as current. Sets `aria-current` for a link row. */\n selected?: boolean\n /** Draw the row at the compact height. */\n dense?: boolean\n /** Leading slot: an avatar, an icon, a checkbox. */\n leading?: JSX.Element\n /** Trailing slot: a count, a menu trigger, a timestamp. */\n trailing?: JSX.Element\n /** A second line that wraps and grows the row to fit its content. */\n description?: string\n /**\n * Keep the description on one line and end it with an ellipsis instead of\n * wrapping, so a described row stays at its minimum height however long the\n * text is. Use it where rows must be a predictable height (a virtualised\n * queue); leave it off where the whole description should be readable. Pair\n * it with a `tooltip` when the full text matters, and with\n * `stackTrailing={false}` to keep a trailing slot beside the text.\n */\n truncateDescription?: boolean\n /**\n * Whether a described row may drop its trailing slot onto its own line when\n * the row gets narrow (the default). Pass `false` for a short, truncating\n * label whose single action must stay beside it.\n */\n stackTrailing?: boolean\n /** Native button type; defaults to `button` for button rows. */\n type?: ComponentProps<'button'>['type']\n }\n>\n\ntype ListRowControlBaseProps<T extends ValidComponent = 'div'> = ListRowControlProps<T> & {\n as?: T\n}\n\n/** A tree-shakeable ListRow renderer without optional tooltip behavior. */\nexport function ListRowControl<T extends ValidComponent = 'div'>(props: ListRowControlProps<T>) {\n const [local, rest] = splitProps(props as ListRowControlBaseProps, [\n 'as',\n 'class',\n 'selected',\n 'dense',\n 'leading',\n 'trailing',\n 'description',\n 'truncateDescription',\n 'stackTrailing',\n 'type',\n 'tabIndex',\n 'children',\n ])\n const hasClickHandler = () => Boolean(rest.onClick || rest['on:click'])\n const rowAs = () => (local.as ?? (hasClickHandler() ? 'button' : 'div')) as T\n\n return (\n <Polymorphic\n as={rowAs()}\n data-slot=\"list-row\"\n type={rowAs() === 'button' ? (local.type ?? 'button') : local.type}\n tabIndex={local.tabIndex ?? (rowAs() === 'button' || rowAs() === 'a' ? 0 : undefined)}\n aria-current={local.selected ? 'true' : undefined}\n data-selected={local.selected ? '' : undefined}\n data-description={local.description ? '' : undefined}\n data-stack-trailing={local.stackTrailing === false ? 'never' : undefined}\n class={cn(\n 'group/row list-row-description flex min-w-0 items-center gap-2.5 rounded-md px-2 text-sm',\n 'transition-colors ease-out outline-none',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n {\n 'h-row-sm': local.dense && !local.description,\n 'h-row-md': !local.dense && !local.description,\n },\n {\n 'bg-primary-subtle text-foreground': local.selected,\n 'hover:bg-surface-hover': !local.selected,\n },\n local.class\n )}\n {...(rest as ComponentProps<'div'>)}\n >\n <Show when={local.leading}>\n <span\n data-slot=\"list-row-leading\"\n class=\"flex shrink-0 items-center justify-center [&_svg]:size-4\"\n >\n {local.leading}\n </span>\n </Show>\n <div data-slot=\"list-row-content\" class=\"flex min-w-0 flex-1 items-center gap-2.5\">\n <span data-slot=\"list-row-label\" class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\">{local.children}</span>\n <Show when={local.description}>\n <span\n data-slot=\"list-row-description\"\n class={cn(\n 'text-xs',\n { truncate: local.truncateDescription, 'break-words': !local.truncateDescription },\n local.selected ? 'text-foreground' : 'text-muted-foreground'\n )}\n >\n {local.description}\n </span>\n </Show>\n </span>\n <Show when={local.trailing}>\n <span\n data-slot=\"list-row-trailing\"\n class={cn(\n 'ms-auto flex shrink-0 items-center gap-1',\n local.selected ? 'text-foreground' : 'text-muted-foreground'\n )}\n >\n {local.trailing}\n </span>\n </Show>\n </div>\n </Polymorphic>\n )\n}\n"],"mappings":";;;;;;;;;;AA6CA,SAAgBsB,eAAiDC,OAA+B;CAC9F,MAAM,CAACC,OAAOC,QAAQnB,WAAWiB,OAAkC;EACjE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAU,CACX;CACD,MAAMG,wBAAwBC,QAAQF,KAAKG,WAAWH,KAAK,WAAW;CACtE,MAAMI,cAAeL,MAAMH,OAAOK,gBAAgB,IAAI,WAAW;CAEjE,OAAAI,gBACG7B,aAAW8B,WAAA;EAAA,IACVV,KAAE;GAAA,OAAEQ,MAAM;EAAC;EAAA,aAAA;EAAA,IAEXV,OAAI;GAAA,OAAEa,WAAAH,MAAM,MAAM,QAAQ,CAAA,CAAA,IAAIL,MAAML,QAAQ,WAAYK,MAAML;EAAI;EAAA,IAClEc,WAAQ;GAAA,OAAET,MAAMS,aAAaJ,MAAM,MAAM,YAAYA,MAAM,MAAM,MAAM,IAAIK,KAAAA;EAAU;EAAA,KAAA,kBAAA;GAAA,OACvEV,MAAMb,WAAW,SAASuB,KAAAA;EAAS;EAAA,KAAA,mBAAA;GAAA,OAClCV,MAAMb,WAAW,KAAKuB,KAAAA;EAAS;EAAA,KAAA,sBAAA;GAAA,OAC5BV,MAAMR,cAAc,KAAKkB,KAAAA;EAAS;EAAA,KAAA,yBAAA;GAAA,OAC/BV,MAAMN,kBAAkB,QAAQ,UAAUgB,KAAAA;EAAS;EAAA,KAAA,WAAA;GAAA,OACjE3B,GACL,4FACA,2CACA,oFACA;IACE,YAAYiB,MAAMZ,SAAS,CAACY,MAAMR;IAClC,YAAY,CAACQ,MAAMZ,SAAS,CAACY,MAAMR;GACrC,GACA;IACE,qCAAqCQ,MAAMb;IAC3C,0BAA0B,CAACa,MAAMb;GACnC,GACAa,MAAMd,KACR;EAAC;CAAA,GACIe,MAA6B,EAAA,IAAAc,WAAA;EAAA,OAAA,CAAAT,gBAEjCzB,MAAI;GAAA,IAACmC,OAAI;IAAA,OAAEhB,MAAMX;GAAO;GAAA,IAAA0B,WAAA;IAAA,IAAAE,OAAAC,OAAA;IAAAC,OAAAF,YAKpBjB,MAAMX,OAAO;IAAA,OAAA4B;GAAA;EAAA,CAAA,UAAA;GAAA,IAAAG,QAAAC,QAAA,GAAAC,QAAAF,MAAAG,YAAAC,QAAAF,MAAAC;GAAAJ,OAAAK,aAKUxB,MAAMe,QAAQ;GAAAI,OAAAG,OAAAhB,gBACrCzB,MAAI;IAAA,IAACmC,OAAI;KAAA,OAAEhB,MAAMR;IAAW;IAAA,IAAAuB,WAAA;KAAA,IAAAU,QAAAC,QAAA;KAAAP,OAAAM,aASxBzB,MAAMR,WAAW;KAAAmC,aAAAC,UAAAH,OANX1C,GACL,WACA;MAAE8C,UAAU7B,MAAMP;MAAqB,eAAe,CAACO,MAAMP;KAAoB,GACjFO,MAAMb,WAAW,oBAAoB,uBACvC,CAAC,CAAA;KAAA,OAAAsC;IAAA;GAAA,CAAA,GAAA,IAAA;GAAAN,OAAAC,OAAAd,gBAMNzB,MAAI;IAAA,IAACmC,OAAI;KAAA,OAAEhB,MAAMT;IAAQ;IAAA,IAAAwB,WAAA;KAAA,IAAAe,QAAAC,QAAA;KAAAZ,OAAAW,aAQrB9B,MAAMT,QAAQ;KAAAoC,aAAAC,UAAAE,OALR/C,GACL,4CACAiB,MAAMb,WAAW,oBAAoB,uBACvC,CAAC,CAAA;KAAA,OAAA2C;IAAA;GAAA,CAAA,GAAA,IAAA;GAAA,OAAAV;EAAA,EAAA,CAAA,CAAA;CAAA,EAAA,CAAA,CAAA;AAQb"}
|
|
@@ -36,6 +36,14 @@ export declare function SettingsRow(props: ComponentProps<'div'> & {
|
|
|
36
36
|
orientation?: 'horizontal' | 'vertical';
|
|
37
37
|
/** Hide the divider this row would otherwise contribute. */
|
|
38
38
|
bare?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Drop the row's own 16px padding so its label and control sit on the same
|
|
41
|
+
* edges as the fields around it. For a row placed loose in a
|
|
42
|
+
* `bodyLayout="content"` section, where nothing encloses it and the section's
|
|
43
|
+
* gap already spaces it from its neighbours. Leave it off inside a divided
|
|
44
|
+
* rows body or a `Card`, whose edge the padding is there to clear.
|
|
45
|
+
*/
|
|
46
|
+
flush?: boolean;
|
|
39
47
|
}): JSX.Element;
|
|
40
48
|
/** A stacked label-and-control pair, for a control too wide for a row. */
|
|
41
49
|
export declare function SettingsField(props: ComponentProps<'div'> & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/settings/settings.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAMnD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,cAAc,CAAC,SAAS,CAAC,GAAG;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kEAAkE;IAClE,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACpB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAChC,eA0CF;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qEAAqE;IACrE,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAA;IACvC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/settings/settings.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAMnD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,cAAc,CAAC,SAAS,CAAC,GAAG;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kEAAkE;IAClE,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACpB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAChC,eA0CF;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qEAAqE;IACrE,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAA;IACvC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,eAwDF;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAC3B,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,eAiBzF;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,eASxD"}
|
|
@@ -85,6 +85,7 @@ function SettingsRow(props) {
|
|
|
85
85
|
"description",
|
|
86
86
|
"orientation",
|
|
87
87
|
"bare",
|
|
88
|
+
"flush",
|
|
88
89
|
"children"
|
|
89
90
|
]);
|
|
90
91
|
const rowId = createUniqueId();
|
|
@@ -103,7 +104,7 @@ function SettingsRow(props) {
|
|
|
103
104
|
get children() {
|
|
104
105
|
var _el$7 = _tmpl$4(), _el$8 = _el$7.firstChild, _el$9 = _el$8.firstChild, _el$1 = _el$8.nextSibling;
|
|
105
106
|
spread(_el$7, mergeProps({ get ["class"]() {
|
|
106
|
-
return cn("flex gap-4 p-4", local.orientation === "vertical" ? "flex-col" : "flex-col sm:flex-row sm:items-center sm:justify-between", local.class);
|
|
107
|
+
return cn("flex gap-4", local.flush ? "p-0" : "p-4", local.orientation === "vertical" ? "flex-col" : "flex-col sm:flex-row sm:items-center sm:justify-between", local.class);
|
|
107
108
|
} }, rest), false, true);
|
|
108
109
|
setAttribute(_el$9, "id", labelId);
|
|
109
110
|
insert(_el$9, () => local.label);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","names":["ComponentProps","JSX","createUniqueId","Show","splitProps","createFormFieldContext","FormFieldContext","cn","Heading","SettingsSection","props","title","description","action","Element","bodyLayout","local","rest","_el$","_tmpl$3","_el$2","firstChild","_el$3","_el$6","nextSibling","_$spread","_$mergeProps","class","_$insert","_$createComponent","as","size","children","when","_el$4","_tmpl$","_el$5","_tmpl$2","_$effect","_$className","SettingsRow","label","orientation","bare","rowId","labelId","descriptionId","field","defaultControlId","hint","error","undefined","group","Provider","value","_el$7","_tmpl$4","_el$8","_el$9","_el$1","_$setAttribute","_el$0","SettingsField","htmlFor","_el$10","_tmpl$5","_el$11","_el$12","_el$14","_el$13","SettingsPage","_el$15","_tmpl$6","_$mergeProps","_$createComponent","_$className","_$setAttribute"],"sources":["../../../../src/components/composites/settings/settings.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { createUniqueId, Show, splitProps } from 'solid-js'\nimport { createFormFieldContext, FormFieldContext } from '#lib/form-field'\nimport { cn } from '#lib/utils'\nimport { Heading } from '../../ui/typography'\n\n/**\n * SettingsSection and SettingsRow.\n *\n * A settings page is the most repetitive surface in any application, and the\n * one where drift is most visible: label sizes, control widths and description\n * placement all wander unless something fixes them.\n *\n * The row puts the label and description at the start and the control at the\n * end (stacked on a narrow window), so controls line up down the page's end\n * edge regardless of how long the labels are. `SettingsRow` also\n * exposes its label and description through the shared form-field context to\n * the first control inside it. `SettingsField` is the visual stacked layout;\n * use `FormField` when the control needs label, help, or validation wiring.\n */\nexport function SettingsSection(\n props: ComponentProps<'section'> & {\n title: string\n description?: string\n /** A control for the section as a whole, e.g. a master toggle. */\n action?: JSX.Element\n /** Use a spaced content stack for fields, alerts, and cards instead of divided rows. */\n bodyLayout?: 'rows' | 'content'\n }\n) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'title',\n 'description',\n 'action',\n 'bodyLayout',\n 'children',\n ])\n\n return (\n <section\n data-slot=\"settings-section\"\n class={cn('flex flex-col gap-4 px-5 py-5', local.class)}\n {...rest}\n >\n <div class=\"flex items-start justify-between gap-4\">\n <div class=\"flex min-w-0 flex-col gap-0.5\">\n <Heading as=\"h2\" size=\"card\">\n {local.title}\n </Heading>\n <Show when={local.description}>\n <p class=\"max-w-prose text-sm text-muted-foreground text-pretty\">{local.description}</p>\n </Show>\n </div>\n <Show when={local.action}>\n <div class=\"flex shrink-0 items-center gap-2\">{local.action}</div>\n </Show>\n </div>\n <div\n data-slot=\"settings-section-body\"\n class={cn(\n local.bodyLayout === 'content'\n ? 'flex flex-col gap-4'\n : 'divide-y divide-border rounded-xl border border-border [&>[data-slot=empty-description]]:p-4'\n )}\n >\n {local.children}\n </div>\n </section>\n )\n}\n\n/**\n * One setting: a label and description on the leading side, a control on the\n * trailing side.\n *\n * The label and description are linked to a shared control through field\n * context. An explicit `aria-label` or `aria-labelledby` on the control keeps\n * precedence; otherwise the visible row label names it.\n */\nexport function SettingsRow(\n props: ComponentProps<'div'> & {\n label: string\n description?: string\n /** Render a vertical stack when the control needs the full width. */\n orientation?: 'horizontal' | 'vertical'\n /** Hide the divider this row would otherwise contribute. */\n bare?: boolean\n }\n) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'label',\n 'description',\n 'orientation',\n 'bare',\n 'children',\n ])\n const rowId = createUniqueId()\n const labelId = `${rowId}-label`\n const descriptionId = `${rowId}-description`\n const field = createFormFieldContext({\n defaultControlId: rowId,\n labelId,\n descriptionId,\n hint: () => local.description,\n error: () => undefined,\n group: () => false,\n })\n\n return (\n <FormFieldContext.Provider value={field}>\n <div\n data-slot=\"settings-row\"\n class={cn(\n 'flex gap-4 p-4',\n local.orientation === 'vertical'\n ? 'flex-col'\n : 'flex-col sm:flex-row sm:items-center sm:justify-between',\n local.class\n )}\n {...rest}\n >\n <div class=\"flex min-w-0 flex-col gap-0.5\">\n <div id={labelId} data-slot=\"settings-row-label\" class=\"text-sm font-medium\">\n {local.label}\n </div>\n <Show when={local.description}>\n <p id={descriptionId} class=\"max-w-prose text-sm text-muted-foreground text-pretty\">\n {local.description}\n </p>\n </Show>\n </div>\n <div\n data-slot=\"settings-row-control\"\n class={cn('shrink-0', local.orientation === 'vertical' && 'w-full')}\n >\n {local.children}\n </div>\n </div>\n </FormFieldContext.Provider>\n )\n}\n\n/** A stacked label-and-control pair, for a control too wide for a row. */\nexport function SettingsField(\n props: ComponentProps<'div'> & { label: string; description?: string; htmlFor?: string }\n) {\n const [local, rest] = splitProps(props, ['class', 'label', 'description', 'htmlFor', 'children'])\n\n return (\n <div data-slot=\"settings-field\" class={cn('flex flex-col gap-2 p-4', local.class)} {...rest}>\n <div class=\"flex flex-col gap-0.5\">\n <label for={local.htmlFor} class=\"text-sm font-medium\">\n {local.label}\n </label>\n <Show when={local.description}>\n <p class=\"max-w-prose text-sm text-muted-foreground text-pretty\">{local.description}</p>\n </Show>\n </div>\n <div>{local.children}</div>\n </div>\n )\n}\n\n/** A settings page's scrolling body, with the header sticky at the top. */\nexport function SettingsPage(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"settings-page\"\n class={cn('flex min-h-0 flex-1 flex-col overflow-y-auto', local.class)}\n {...rest}\n />\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"settings.js","names":["ComponentProps","JSX","createUniqueId","Show","splitProps","createFormFieldContext","FormFieldContext","cn","Heading","SettingsSection","props","title","description","action","Element","bodyLayout","local","rest","_el$","_tmpl$3","_el$2","firstChild","_el$3","_el$6","nextSibling","_$spread","_$mergeProps","class","_$insert","_$createComponent","as","size","children","when","_el$4","_tmpl$","_el$5","_tmpl$2","_$effect","_$className","SettingsRow","label","orientation","bare","flush","rowId","labelId","descriptionId","field","defaultControlId","hint","error","undefined","group","Provider","value","_el$7","_tmpl$4","_el$8","_el$9","_el$1","_$setAttribute","_el$0","SettingsField","htmlFor","_el$10","_tmpl$5","_el$11","_el$12","_el$14","_el$13","SettingsPage","_el$15","_tmpl$6","_$mergeProps","_$createComponent","_$className","_$setAttribute"],"sources":["../../../../src/components/composites/settings/settings.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { createUniqueId, Show, splitProps } from 'solid-js'\nimport { createFormFieldContext, FormFieldContext } from '#lib/form-field'\nimport { cn } from '#lib/utils'\nimport { Heading } from '../../ui/typography'\n\n/**\n * SettingsSection and SettingsRow.\n *\n * A settings page is the most repetitive surface in any application, and the\n * one where drift is most visible: label sizes, control widths and description\n * placement all wander unless something fixes them.\n *\n * The row puts the label and description at the start and the control at the\n * end (stacked on a narrow window), so controls line up down the page's end\n * edge regardless of how long the labels are. `SettingsRow` also\n * exposes its label and description through the shared form-field context to\n * the first control inside it. `SettingsField` is the visual stacked layout;\n * use `FormField` when the control needs label, help, or validation wiring.\n */\nexport function SettingsSection(\n props: ComponentProps<'section'> & {\n title: string\n description?: string\n /** A control for the section as a whole, e.g. a master toggle. */\n action?: JSX.Element\n /** Use a spaced content stack for fields, alerts, and cards instead of divided rows. */\n bodyLayout?: 'rows' | 'content'\n }\n) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'title',\n 'description',\n 'action',\n 'bodyLayout',\n 'children',\n ])\n\n return (\n <section\n data-slot=\"settings-section\"\n class={cn('flex flex-col gap-4 px-5 py-5', local.class)}\n {...rest}\n >\n <div class=\"flex items-start justify-between gap-4\">\n <div class=\"flex min-w-0 flex-col gap-0.5\">\n <Heading as=\"h2\" size=\"card\">\n {local.title}\n </Heading>\n <Show when={local.description}>\n <p class=\"max-w-prose text-sm text-muted-foreground text-pretty\">{local.description}</p>\n </Show>\n </div>\n <Show when={local.action}>\n <div class=\"flex shrink-0 items-center gap-2\">{local.action}</div>\n </Show>\n </div>\n <div\n data-slot=\"settings-section-body\"\n class={cn(\n local.bodyLayout === 'content'\n ? 'flex flex-col gap-4'\n : 'divide-y divide-border rounded-xl border border-border [&>[data-slot=empty-description]]:p-4'\n )}\n >\n {local.children}\n </div>\n </section>\n )\n}\n\n/**\n * One setting: a label and description on the leading side, a control on the\n * trailing side.\n *\n * The label and description are linked to a shared control through field\n * context. An explicit `aria-label` or `aria-labelledby` on the control keeps\n * precedence; otherwise the visible row label names it.\n */\nexport function SettingsRow(\n props: ComponentProps<'div'> & {\n label: string\n description?: string\n /** Render a vertical stack when the control needs the full width. */\n orientation?: 'horizontal' | 'vertical'\n /** Hide the divider this row would otherwise contribute. */\n bare?: boolean\n /**\n * Drop the row's own 16px padding so its label and control sit on the same\n * edges as the fields around it. For a row placed loose in a\n * `bodyLayout=\"content\"` section, where nothing encloses it and the section's\n * gap already spaces it from its neighbours. Leave it off inside a divided\n * rows body or a `Card`, whose edge the padding is there to clear.\n */\n flush?: boolean\n }\n) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'label',\n 'description',\n 'orientation',\n 'bare',\n 'flush',\n 'children',\n ])\n const rowId = createUniqueId()\n const labelId = `${rowId}-label`\n const descriptionId = `${rowId}-description`\n const field = createFormFieldContext({\n defaultControlId: rowId,\n labelId,\n descriptionId,\n hint: () => local.description,\n error: () => undefined,\n group: () => false,\n })\n\n return (\n <FormFieldContext.Provider value={field}>\n <div\n data-slot=\"settings-row\"\n class={cn(\n 'flex gap-4',\n local.flush ? 'p-0' : 'p-4',\n local.orientation === 'vertical'\n ? 'flex-col'\n : 'flex-col sm:flex-row sm:items-center sm:justify-between',\n local.class\n )}\n {...rest}\n >\n <div class=\"flex min-w-0 flex-col gap-0.5\">\n <div id={labelId} data-slot=\"settings-row-label\" class=\"text-sm font-medium\">\n {local.label}\n </div>\n <Show when={local.description}>\n <p id={descriptionId} class=\"max-w-prose text-sm text-muted-foreground text-pretty\">\n {local.description}\n </p>\n </Show>\n </div>\n <div\n data-slot=\"settings-row-control\"\n class={cn('shrink-0', local.orientation === 'vertical' && 'w-full')}\n >\n {local.children}\n </div>\n </div>\n </FormFieldContext.Provider>\n )\n}\n\n/** A stacked label-and-control pair, for a control too wide for a row. */\nexport function SettingsField(\n props: ComponentProps<'div'> & { label: string; description?: string; htmlFor?: string }\n) {\n const [local, rest] = splitProps(props, ['class', 'label', 'description', 'htmlFor', 'children'])\n\n return (\n <div data-slot=\"settings-field\" class={cn('flex flex-col gap-2 p-4', local.class)} {...rest}>\n <div class=\"flex flex-col gap-0.5\">\n <label for={local.htmlFor} class=\"text-sm font-medium\">\n {local.label}\n </label>\n <Show when={local.description}>\n <p class=\"max-w-prose text-sm text-muted-foreground text-pretty\">{local.description}</p>\n </Show>\n </div>\n <div>{local.children}</div>\n </div>\n )\n}\n\n/** A settings page's scrolling body, with the header sticky at the top. */\nexport function SettingsPage(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"settings-page\"\n class={cn('flex min-h-0 flex-1 flex-col overflow-y-auto', local.class)}\n {...rest}\n />\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { ComponentProps, JSX } from 'solid-js';
|
|
2
|
-
|
|
2
|
+
type EmptyStateSecondaryAction = {
|
|
3
|
+
secondaryAction?: undefined;
|
|
4
|
+
secondaryActionLabel?: undefined;
|
|
5
|
+
secondaryActionTooltip?: never;
|
|
6
|
+
} | {
|
|
7
|
+
/** A second, quieter way out beside `action`: "Open settings" next to "Retry". */
|
|
8
|
+
secondaryAction: () => void;
|
|
9
|
+
/** Required: there is no sensible default name for an arbitrary second action. */
|
|
10
|
+
secondaryActionLabel: string;
|
|
11
|
+
secondaryActionTooltip?: string;
|
|
12
|
+
};
|
|
13
|
+
export type EmptyStateProps = Omit<ComponentProps<'div'>, 'children' | 'role' | 'aria-live'> & EmptyStateSecondaryAction & {
|
|
3
14
|
title: string;
|
|
4
15
|
detail: string;
|
|
5
16
|
busy?: boolean;
|
|
@@ -10,6 +21,14 @@ export type EmptyStateProps = Omit<ComponentProps<'div'>, 'children' | 'role' |
|
|
|
10
21
|
actionLabel?: string;
|
|
11
22
|
actionTooltip?: string;
|
|
12
23
|
};
|
|
13
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* A semantic empty, loading, or error state built from the shared empty parts.
|
|
26
|
+
*
|
|
27
|
+
* `action` is the primary way forward. `secondaryAction` adds one quieter
|
|
28
|
+
* alternative after it, in a `secondary` button, so the primary stays first in
|
|
29
|
+
* the tab order. Two actions side by side is the limit: a state that needs more
|
|
30
|
+
* should compose the `Empty*` parts directly.
|
|
31
|
+
*/
|
|
14
32
|
export declare function EmptyState(props: EmptyStateProps): JSX.Element;
|
|
33
|
+
export {};
|
|
15
34
|
//# sourceMappingURL=empty-state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/empty/empty-state.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/empty/empty-state.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAOnD,KAAK,yBAAyB,GAC1B;IACE,eAAe,CAAC,EAAE,SAAS,CAAA;IAC3B,oBAAoB,CAAC,EAAE,SAAS,CAAA;IAChC,sBAAsB,CAAC,EAAE,KAAK,CAAA;CAC/B,GACD;IACE,kFAAkF;IAClF,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B,kFAAkF;IAClF,oBAAoB,EAAE,MAAM,CAAA;IAC5B,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC,CAAA;AAEL,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,WAAW,CAAC,GAC1F,yBAAyB,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC/B,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACpC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAEH;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,eAiEhD"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cn } from "../../../lib/utils.js";
|
|
1
2
|
import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "./empty.js";
|
|
2
3
|
import { Spinner } from "../spinner/spinner.js";
|
|
3
4
|
import { ActionButton } from "../../composites/action-button/action-button.js";
|
|
@@ -5,7 +6,14 @@ import { createComponent, memo, mergeProps } from "solid-js/web";
|
|
|
5
6
|
import { Search } from "lucide-solid";
|
|
6
7
|
import { Show, splitProps } from "solid-js";
|
|
7
8
|
//#region src/components/ui/empty/empty-state.tsx
|
|
8
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* A semantic empty, loading, or error state built from the shared empty parts.
|
|
11
|
+
*
|
|
12
|
+
* `action` is the primary way forward. `secondaryAction` adds one quieter
|
|
13
|
+
* alternative after it, in a `secondary` button, so the primary stays first in
|
|
14
|
+
* the tab order. Two actions side by side is the limit: a state that needs more
|
|
15
|
+
* should compose the `Empty*` parts directly.
|
|
16
|
+
*/
|
|
9
17
|
function EmptyState(props) {
|
|
10
18
|
const [local, rest] = splitProps(props, [
|
|
11
19
|
"title",
|
|
@@ -17,6 +25,9 @@ function EmptyState(props) {
|
|
|
17
25
|
"action",
|
|
18
26
|
"actionLabel",
|
|
19
27
|
"actionTooltip",
|
|
28
|
+
"secondaryAction",
|
|
29
|
+
"secondaryActionLabel",
|
|
30
|
+
"secondaryActionTooltip",
|
|
20
31
|
"class"
|
|
21
32
|
]);
|
|
22
33
|
return createComponent(Empty, mergeProps(rest, {
|
|
@@ -66,25 +77,58 @@ function EmptyState(props) {
|
|
|
66
77
|
];
|
|
67
78
|
} }), createComponent(Show, {
|
|
68
79
|
get when() {
|
|
69
|
-
return local.action;
|
|
80
|
+
return local.action || local.secondaryAction;
|
|
70
81
|
},
|
|
71
82
|
get children() {
|
|
72
|
-
return createComponent(EmptyContent, {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
return createComponent(EmptyContent, {
|
|
84
|
+
get ["class"]() {
|
|
85
|
+
return cn({ "flex-row flex-wrap justify-center": !!local.secondaryAction });
|
|
86
|
+
},
|
|
87
|
+
get children() {
|
|
88
|
+
return [createComponent(Show, {
|
|
89
|
+
get when() {
|
|
90
|
+
return local.action;
|
|
91
|
+
},
|
|
92
|
+
get children() {
|
|
93
|
+
return createComponent(ActionButton, {
|
|
94
|
+
get tooltip() {
|
|
95
|
+
return local.actionTooltip ?? local.actionLabel ?? "Try again";
|
|
96
|
+
},
|
|
97
|
+
get ["aria-label"]() {
|
|
98
|
+
return local.actionLabel ?? "Try again";
|
|
99
|
+
},
|
|
100
|
+
get onClick() {
|
|
101
|
+
return local.action;
|
|
102
|
+
},
|
|
103
|
+
get children() {
|
|
104
|
+
return local.actionLabel ?? "Try again";
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}), createComponent(Show, {
|
|
109
|
+
get when() {
|
|
110
|
+
return local.secondaryAction;
|
|
111
|
+
},
|
|
112
|
+
get children() {
|
|
113
|
+
return createComponent(ActionButton, {
|
|
114
|
+
variant: "secondary",
|
|
115
|
+
get tooltip() {
|
|
116
|
+
return local.secondaryActionTooltip ?? local.secondaryActionLabel;
|
|
117
|
+
},
|
|
118
|
+
get ["aria-label"]() {
|
|
119
|
+
return local.secondaryActionLabel;
|
|
120
|
+
},
|
|
121
|
+
get onClick() {
|
|
122
|
+
return local.secondaryAction;
|
|
123
|
+
},
|
|
124
|
+
get children() {
|
|
125
|
+
return local.secondaryActionLabel;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
})];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
88
132
|
}
|
|
89
133
|
})];
|
|
90
134
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"empty-state.js","names":["Search","ComponentProps","JSX","Show","splitProps","ActionButton","Spinner","Empty","EmptyContent","EmptyDescription","EmptyHeader","EmptyMedia","EmptyTitle","EmptyStateProps","Omit","title","detail","busy","icon","Element","announceAs","headingLevel","action","actionLabel","actionTooltip","EmptyState","props","local","rest","_$createComponent","_$mergeProps","class","role","aria-live","undefined","aria-busy","children","when","variant","_$memo","label","aria-level","tooltip","aria-label","onClick","_$createComponent","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/empty/empty-state.tsx"],"sourcesContent":["import { Search } from 'lucide-solid'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { ActionButton } from '../../composites/action-button'\nimport { Spinner } from '../spinner'\nimport { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from './empty'\n\nexport type EmptyStateProps = Omit<ComponentProps<'div'>, 'children' | 'role' | 'aria-live'> & {\n
|
|
1
|
+
{"version":3,"file":"empty-state.js","names":["Search","ComponentProps","JSX","Show","splitProps","ActionButton","cn","Spinner","Empty","EmptyContent","EmptyDescription","EmptyHeader","EmptyMedia","EmptyTitle","EmptyStateSecondaryAction","secondaryAction","secondaryActionLabel","secondaryActionTooltip","EmptyStateProps","Omit","title","detail","busy","icon","Element","announceAs","headingLevel","action","actionLabel","actionTooltip","EmptyState","props","local","rest","_$createComponent","_$mergeProps","class","role","aria-live","undefined","aria-busy","children","when","variant","_$memo","label","aria-level","tooltip","aria-label","onClick","_$createComponent","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/empty/empty-state.tsx"],"sourcesContent":["import { Search } from 'lucide-solid'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport { Show, splitProps } from 'solid-js'\nimport { ActionButton } from '../../composites/action-button'\nimport { cn } from '#lib/utils'\nimport { Spinner } from '../spinner'\nimport { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from './empty'\n\ntype EmptyStateSecondaryAction =\n | {\n secondaryAction?: undefined\n secondaryActionLabel?: undefined\n secondaryActionTooltip?: never\n }\n | {\n /** A second, quieter way out beside `action`: \"Open settings\" next to \"Retry\". */\n secondaryAction: () => void\n /** Required: there is no sensible default name for an arbitrary second action. */\n secondaryActionLabel: string\n secondaryActionTooltip?: string\n }\n\nexport type EmptyStateProps = Omit<ComponentProps<'div'>, 'children' | 'role' | 'aria-live'> &\n EmptyStateSecondaryAction & {\n title: string\n detail: string\n busy?: boolean\n icon?: JSX.Element\n announceAs?: 'alert' | 'status'\n headingLevel?: 1 | 2 | 3 | 4 | 5 | 6\n action?: () => void\n actionLabel?: string\n actionTooltip?: string\n }\n\n/**\n * A semantic empty, loading, or error state built from the shared empty parts.\n *\n * `action` is the primary way forward. `secondaryAction` adds one quieter\n * alternative after it, in a `secondary` button, so the primary stays first in\n * the tab order. Two actions side by side is the limit: a state that needs more\n * should compose the `Empty*` parts directly.\n */\nexport function EmptyState(props: EmptyStateProps) {\n const [local, rest] = splitProps(props, [\n 'title',\n 'detail',\n 'busy',\n 'icon',\n 'announceAs',\n 'headingLevel',\n 'action',\n 'actionLabel',\n 'actionTooltip',\n 'secondaryAction',\n 'secondaryActionLabel',\n 'secondaryActionTooltip',\n 'class',\n ])\n\n return (\n <Empty\n {...rest}\n class={local.class}\n role={local.announceAs}\n aria-live={local.announceAs === 'status' ? 'polite' : undefined}\n aria-busy={local.busy || undefined}\n >\n <EmptyHeader>\n <Show when={local.busy || local.icon}>\n <EmptyMedia variant=\"icon\">\n {local.busy ? (\n <Spinner label={false} aria-hidden=\"true\" />\n ) : (\n (local.icon ?? <Search aria-hidden=\"true\" />)\n )}\n </EmptyMedia>\n </Show>\n <EmptyTitle role=\"heading\" aria-level={local.headingLevel ?? 1}>\n {local.title}\n </EmptyTitle>\n <EmptyDescription>{local.detail}</EmptyDescription>\n </EmptyHeader>\n <Show when={local.action || local.secondaryAction}>\n <EmptyContent class={cn({ 'flex-row flex-wrap justify-center': !!local.secondaryAction })}>\n <Show when={local.action}>\n <ActionButton\n tooltip={local.actionTooltip ?? local.actionLabel ?? 'Try again'}\n aria-label={local.actionLabel ?? 'Try again'}\n onClick={local.action}\n >\n {local.actionLabel ?? 'Try again'}\n </ActionButton>\n </Show>\n <Show when={local.secondaryAction}>\n <ActionButton\n variant=\"secondary\"\n tooltip={local.secondaryActionTooltip ?? local.secondaryActionLabel}\n aria-label={local.secondaryActionLabel}\n onClick={local.secondaryAction}\n >\n {local.secondaryActionLabel}\n </ActionButton>\n </Show>\n </EmptyContent>\n </Show>\n </Empty>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA2CA,SAAgB8B,WAAWC,OAAwB;CACjD,MAAM,CAACC,OAAOC,QAAQ7B,WAAW2B,OAAO;EACtC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAO,CACR;CAED,OAAAG,gBACG1B,OAAK2B,WACAF,MAAI;EAAA,KAAA,WAAA;GAAA,OACDD,MAAMI;EAAK;EAAA,IAClBC,OAAI;GAAA,OAAEL,MAAMP;EAAU;EAAA,KAAA,eAAA;GAAA,OACXO,MAAMP,eAAe,WAAW,WAAWc,KAAAA;EAAS;EAAA,KAAA,eAAA;GAAA,OACpDP,MAAMV,QAAQiB,KAAAA;EAAS;EAAA,IAAAE,WAAA;GAAA,OAAA,CAAAP,gBAEjCvB,aAAW,EAAA,IAAA8B,WAAA;IAAA,OAAA;KAAAP,gBACT/B,MAAI;MAAA,IAACuC,OAAI;OAAA,OAAEV,MAAMV,QAAQU,MAAMT;MAAI;MAAA,IAAAkB,WAAA;OAAA,OAAAP,gBACjCtB,YAAU;QAAC+B,SAAO;QAAA,IAAAF,WAAA;SAAA,OAChBG,WAAA,CAAA,CAAAZ,MAAMV,IAAI,CAAA,CAAA,IAAAY,gBACR3B,SAAO;UAACsC,OAAO;UAAK,eAAA;SAAA,CAAA,IAEpBb,MAAMT,QAAIW,gBAAKlC,QAAM,EAAA,eAAA,OAAA,CAAA;QACvB;OAAA,CAAA;MAAA;KAAA,CAAA;KAAAkC,gBAGJrB,YAAU;MAACwB,MAAI;MAAA,KAAA,gBAAA;OAAA,OAAuBL,MAAMN,gBAAgB;MAAC;MAAA,IAAAe,WAAA;OAAA,OAC3DT,MAAMZ;MAAK;KAAA,CAAA;KAAAc,gBAEbxB,kBAAgB,EAAA,IAAA+B,WAAA;MAAA,OAAET,MAAMX;KAAM,EAAA,CAAA;IAAA;GAAA,EAAA,CAAA,GAAAa,gBAEhC/B,MAAI;IAAA,IAACuC,OAAI;KAAA,OAAEV,MAAML,UAAUK,MAAMjB;IAAe;IAAA,IAAA0B,WAAA;KAAA,OAAAP,gBAC9CzB,cAAY;MAAA,KAAA,WAAA;OAAA,OAAQH,GAAG,EAAE,qCAAqC,CAAC,CAAC0B,MAAMjB,gBAAgB,CAAC;MAAC;MAAA,IAAA0B,WAAA;OAAA,OAAA,CAAAP,gBACtF/B,MAAI;QAAA,IAACuC,OAAI;SAAA,OAAEV,MAAML;QAAM;QAAA,IAAAc,WAAA;SAAA,OAAAP,gBACrB7B,cAAY;UAAA,IACX0C,UAAO;WAAA,OAAEf,MAAMH,iBAAiBG,MAAMJ,eAAe;UAAW;UAAA,KAAA,gBAAA;WAAA,OACpDI,MAAMJ,eAAe;UAAW;UAAA,IAC5CqB,UAAO;WAAA,OAAEjB,MAAML;UAAM;UAAA,IAAAc,WAAA;WAAA,OAEpBT,MAAMJ,eAAe;UAAW;SAAA,CAAA;QAAA;OAAA,CAAA,GAAAM,gBAGpC/B,MAAI;QAAA,IAACuC,OAAI;SAAA,OAAEV,MAAMjB;QAAe;QAAA,IAAA0B,WAAA;SAAA,OAAAP,gBAC9B7B,cAAY;UACXsC,SAAO;UAAA,IACPI,UAAO;WAAA,OAAEf,MAAMf,0BAA0Be,MAAMhB;UAAoB;UAAA,KAAA,gBAAA;WAAA,OACvDgB,MAAMhB;UAAoB;UAAA,IACtCiC,UAAO;WAAA,OAAEjB,MAAMjB;UAAe;UAAA,IAAA0B,WAAA;WAAA,OAE7BT,MAAMhB;UAAoB;SAAA,CAAA;QAAA;OAAA,CAAA,CAAA;MAAA;KAAA,CAAA;IAAA;GAAA,CAAA,CAAA;EAAA;CAAA,CAAA,CAAA;AAOzC"}
|
|
@@ -56,8 +56,12 @@ export type FieldGroupProps = ComponentProps<'div'> & {
|
|
|
56
56
|
* that needs the full width says `class="col-span-full"`. Below `sm` it is
|
|
57
57
|
* one column again, because two inputs side by side on a phone are each too
|
|
58
58
|
* narrow to read.
|
|
59
|
+
*
|
|
60
|
+
* `3` is the same grid with three columns from `sm`, for a row of short values
|
|
61
|
+
* (a trio of limits, a day count and two thresholds). Each column is a third of
|
|
62
|
+
* the group, so reach for `2` when a field holds a path, a URL or a sentence.
|
|
59
63
|
*/
|
|
60
|
-
columns?: 1 | 2;
|
|
64
|
+
columns?: 1 | 2 | 3;
|
|
61
65
|
};
|
|
62
66
|
/** A visual stack for related controls that does not imply fieldset semantics. */
|
|
63
67
|
export declare function FieldGroup(props: FieldGroupProps): JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/field/field.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAOnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,eAGnE;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC,GAAG;IAC7E,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,eAkE9C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,eAK9E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,WAAW,CAAC,eAQ1F;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,YAAY,CAAC,eAKrF;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,eAiB9E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,eAiBpF;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,eAGzD;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG;IACpD
|
|
1
|
+
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/field/field.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAOnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,eAGnE;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC,GAAG;IAC7E,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;CACtB,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,eAkE9C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,eAK9E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,WAAW,CAAC,eAQ1F;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,YAAY,CAAC,eAKrF;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,KAAK,CAAC,eAiB9E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,eAiBpF;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,eAGzD;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG;IACpD;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CACpB,CAAA;AAED,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,eAgBhD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;CAAE,eAY7F;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAA;CAC9C,eAYA"}
|
|
@@ -192,7 +192,11 @@ function FieldGroup(props) {
|
|
|
192
192
|
return (() => {
|
|
193
193
|
var _el$5 = _tmpl$5();
|
|
194
194
|
spread(_el$5, mergeProps({ get ["class"]() {
|
|
195
|
-
return cn(
|
|
195
|
+
return cn({
|
|
196
|
+
"grid gap-4 sm:grid-cols-2": local.columns === 2,
|
|
197
|
+
"grid gap-4 sm:grid-cols-3": local.columns === 3,
|
|
198
|
+
"flex flex-col gap-4": local.columns !== 2 && local.columns !== 3
|
|
199
|
+
}, local.class);
|
|
196
200
|
} }, rest), false, false);
|
|
197
201
|
return _el$5;
|
|
198
202
|
})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.js","names":["TextField","KobalteTextField","ComponentProps","JSX","createUniqueId","Show","splitProps","Label","createFormFieldContext","FormFieldContext","cn","headingVariants","Field","props","local","rest","_$createComponent","_$mergeProps","class","FormFieldProps","Omit","label","hint","error","controlId","group","children","Element","FormField","fieldId","labelId","descriptionId","errorId","field","defaultControlId","help","when","_el$","_tmpl$","_$setAttribute","_$insert","_el$2","_tmpl$2","Provider","value","_el$3","_tmpl$3","_$spread","_c$","_$memo","FieldSet","aria-describedby","describedBy","aria-invalid","invalid","undefined","FieldLegend","id","variant","for","FieldLabel","FieldDescription","Description","FieldError","ErrorMessage","FieldInput","Input","FieldTextArea","TextArea","_el$4","_tmpl$4","FieldGroupProps","columns","FieldGroup","_el$5","_tmpl$5","_el$6","_tmpl$6","size","FieldSeparator","_el$7","_tmpl$8","_el$8","firstChild","_el$0","nextSibling","_el$9","_tmpl$7","_$createComponent","KobalteTextField","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/field/field.tsx"],"sourcesContent":["import { TextField as KobalteTextField } from '@kobalte/core/text-field'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport { createUniqueId, Show, splitProps } from 'solid-js'\nimport { Label } from '../label/label'\nimport { createFormFieldContext, FormFieldContext } from '#lib/form-field'\nimport { cn } from '#lib/utils'\nimport { headingVariants } from '../typography'\n\n/**\n * Field.\n *\n * The wrapper that makes a form control describable and validatable: a label,\n * a description, an error message, and the ARIA relationships between them.\n *\n * This Kobalte TextField composition is for its own `FieldLabel`, `FieldInput`\n * and `FieldTextArea` parts. Use `FormField` to wire the standalone shared\n * controls, including checkboxes, switches and comboboxes.\n *\n * It is built on Kobalte's TextField specifically so `aria-describedby`,\n * `aria-invalid` and `aria-errormessage` are wired by construction. Those three\n * attributes are the difference between \"this field is required and empty\" and\n * a red border that only a sighted user can perceive — and they are also the\n * first thing a hand-rolled form drops.\n *\n * `Field` owns the description and the error slot, so its controls line up and\n * its messages land in the same place regardless of which TextField part is used.\n */\nexport function Field(props: ComponentProps<typeof KobalteTextField>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteTextField class={cn('flex flex-col gap-1.5', local.class)} {...rest} />\n}\n\nexport type FormFieldProps = Omit<ComponentProps<'div'>, 'children' | 'ref'> & {\n label: string\n hint?: string\n error?: string\n controlId?: string\n group?: boolean\n children: JSX.Element\n}\n\n/**\n * FormField.\n *\n * A shared label, help and validation wrapper for any one shared control. Its\n * context is consumed by Input, Textarea, NativeSelect, Checkbox, Switch,\n * RadioGroup and ComboboxInput, so the actual focusable element receives the\n * generated ID and description relationships. Set `group` when the label names\n * a set of controls; the wrapper then uses fieldset and legend semantics.\n */\nexport function FormField(props: FormFieldProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'label',\n 'hint',\n 'error',\n 'controlId',\n 'group',\n 'children',\n ])\n const fieldId = createUniqueId()\n const labelId = `${fieldId}-label`\n const descriptionId = `${fieldId}-description`\n const errorId = `${fieldId}-error`\n const field = createFormFieldContext({\n controlId: local.controlId,\n defaultControlId: fieldId,\n labelId,\n descriptionId,\n errorId,\n hint: () => local.hint,\n error: () => local.error,\n group: () => local.group ?? false,\n })\n const help = () => (\n <>\n <Show when={local.hint}>\n <p id={descriptionId} class=\"text-muted-foreground text-sm\">\n {local.hint}\n </p>\n </Show>\n <Show when={local.error}>\n <p id={errorId} role=\"alert\" class=\"text-foreground text-sm\">\n {local.error}\n </p>\n </Show>\n </>\n )\n\n return (\n <FormFieldContext.Provider value={field}>\n <div class={cn('flex flex-col gap-1.5', local.class)} {...rest}>\n {local.group ? (\n <FieldSet\n class=\"flex flex-col gap-1.5\"\n aria-describedby={field.describedBy()}\n aria-invalid={field.invalid() || undefined}\n >\n <FieldLegend id={labelId} variant=\"label\">\n {local.label}\n </FieldLegend>\n {local.children}\n {help()}\n </FieldSet>\n ) : (\n <>\n <Label id={labelId} for={field.controlId()}>\n {local.label}\n </Label>\n {local.children}\n {help()}\n </>\n )}\n </div>\n </FormFieldContext.Provider>\n )\n}\n\nexport function FieldLabel(props: ComponentProps<typeof KobalteTextField.Label>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteTextField.Label class={cn('text-sm leading-none font-medium', local.class)} {...rest} />\n )\n}\n\nexport function FieldDescription(props: ComponentProps<typeof KobalteTextField.Description>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteTextField.Description\n class={cn('text-muted-foreground text-sm', local.class)}\n {...rest}\n />\n )\n}\n\nexport function FieldError(props: ComponentProps<typeof KobalteTextField.ErrorMessage>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteTextField.ErrorMessage class={cn('text-foreground text-sm', local.class)} {...rest} />\n )\n}\n\nexport function FieldInput(props: ComponentProps<typeof KobalteTextField.Input>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <KobalteTextField.Input\n class={cn(\n 'h-control-md w-full min-w-0 rounded-md border border-input bg-transparent px-control-md py-1 text-sm',\n 'transition-[color,box-shadow,border-color] ease-out outline-none',\n 'placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive-subtle',\n 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function FieldTextArea(props: ComponentProps<typeof KobalteTextField.TextArea>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <KobalteTextField.TextArea\n class={cn(\n 'flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-control-md py-2 text-sm',\n 'transition-[color,box-shadow,border-color] ease-out outline-none resize-y',\n 'placeholder:text-muted-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive-subtle',\n 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/**\n * A labelled group of fields with a single legend, for a real `<fieldset>`.\n * Grouping is what lets a screen reader announce \"Shipping address, group\"\n * before reading the four fields inside it.\n */\nexport function FieldSet(props: ComponentProps<'fieldset'>) {\n const [local, rest] = splitProps(props, ['class'])\n return <fieldset class={cn('flex flex-col gap-4', local.class)} {...rest} />\n}\n\nexport type FieldGroupProps = ComponentProps<'div'> & {\n /**\n * `2` lays the fields out in two columns from the `sm` breakpoint up — a\n * short form of paired values (host and port, a name and a model). A field\n * that needs the full width says `class=\"col-span-full\"`. Below `sm` it is\n * one column again, because two inputs side by side on a phone are each too\n * narrow to read.\n */\n columns?: 1 | 2\n}\n\n/** A visual stack for related controls that does not imply fieldset semantics. */\nexport function FieldGroup(props: FieldGroupProps) {\n const [local, rest] = splitProps(props, ['class', 'columns'])\n return (\n <div\n data-slot=\"field-group\"\n class={cn(\n local.columns === 2 ? 'grid gap-4 sm:grid-cols-2' : 'flex flex-col gap-4',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function FieldLegend(props: ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {\n const [local, rest] = splitProps(props, ['class', 'variant'])\n return (\n <legend\n class={cn(\n 'mb-1',\n local.variant === 'label' ? 'text-sm font-medium' : headingVariants({ size: 'card' }),\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** A horizontal rule with a word in it, for \"or continue with\" separators. */\nexport function FieldSeparator(props: {\n class?: string\n children?: ComponentProps<'span'>['children']\n}) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n\n return (\n <div class={cn('relative flex items-center gap-3 py-1', local.class)} {...rest}>\n <span class=\"bg-border h-px flex-1\" />\n <Show when={local.children}>\n <span class=\"text-muted-foreground text-2xs tracking-wide uppercase\">{local.children}</span>\n </Show>\n <span class=\"bg-border h-px flex-1\" />\n </div>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"field.js","names":["TextField","KobalteTextField","ComponentProps","JSX","createUniqueId","Show","splitProps","Label","createFormFieldContext","FormFieldContext","cn","headingVariants","Field","props","local","rest","_$createComponent","_$mergeProps","class","FormFieldProps","Omit","label","hint","error","controlId","group","children","Element","FormField","fieldId","labelId","descriptionId","errorId","field","defaultControlId","help","when","_el$","_tmpl$","_$setAttribute","_$insert","_el$2","_tmpl$2","Provider","value","_el$3","_tmpl$3","_$spread","_c$","_$memo","FieldSet","aria-describedby","describedBy","aria-invalid","invalid","undefined","FieldLegend","id","variant","for","FieldLabel","FieldDescription","Description","FieldError","ErrorMessage","FieldInput","Input","FieldTextArea","TextArea","_el$4","_tmpl$4","FieldGroupProps","columns","FieldGroup","_el$5","_tmpl$5","_el$6","_tmpl$6","size","FieldSeparator","_el$7","_tmpl$8","_el$8","firstChild","_el$0","nextSibling","_el$9","_tmpl$7","_$createComponent","KobalteTextField","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/field/field.tsx"],"sourcesContent":["import { TextField as KobalteTextField } from '@kobalte/core/text-field'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport { createUniqueId, Show, splitProps } from 'solid-js'\nimport { Label } from '../label/label'\nimport { createFormFieldContext, FormFieldContext } from '#lib/form-field'\nimport { cn } from '#lib/utils'\nimport { headingVariants } from '../typography'\n\n/**\n * Field.\n *\n * The wrapper that makes a form control describable and validatable: a label,\n * a description, an error message, and the ARIA relationships between them.\n *\n * This Kobalte TextField composition is for its own `FieldLabel`, `FieldInput`\n * and `FieldTextArea` parts. Use `FormField` to wire the standalone shared\n * controls, including checkboxes, switches and comboboxes.\n *\n * It is built on Kobalte's TextField specifically so `aria-describedby`,\n * `aria-invalid` and `aria-errormessage` are wired by construction. Those three\n * attributes are the difference between \"this field is required and empty\" and\n * a red border that only a sighted user can perceive — and they are also the\n * first thing a hand-rolled form drops.\n *\n * `Field` owns the description and the error slot, so its controls line up and\n * its messages land in the same place regardless of which TextField part is used.\n */\nexport function Field(props: ComponentProps<typeof KobalteTextField>) {\n const [local, rest] = splitProps(props, ['class'])\n return <KobalteTextField class={cn('flex flex-col gap-1.5', local.class)} {...rest} />\n}\n\nexport type FormFieldProps = Omit<ComponentProps<'div'>, 'children' | 'ref'> & {\n label: string\n hint?: string\n error?: string\n controlId?: string\n group?: boolean\n children: JSX.Element\n}\n\n/**\n * FormField.\n *\n * A shared label, help and validation wrapper for any one shared control. Its\n * context is consumed by Input, Textarea, NativeSelect, Checkbox, Switch,\n * RadioGroup and ComboboxInput, so the actual focusable element receives the\n * generated ID and description relationships. Set `group` when the label names\n * a set of controls; the wrapper then uses fieldset and legend semantics.\n */\nexport function FormField(props: FormFieldProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'label',\n 'hint',\n 'error',\n 'controlId',\n 'group',\n 'children',\n ])\n const fieldId = createUniqueId()\n const labelId = `${fieldId}-label`\n const descriptionId = `${fieldId}-description`\n const errorId = `${fieldId}-error`\n const field = createFormFieldContext({\n controlId: local.controlId,\n defaultControlId: fieldId,\n labelId,\n descriptionId,\n errorId,\n hint: () => local.hint,\n error: () => local.error,\n group: () => local.group ?? false,\n })\n const help = () => (\n <>\n <Show when={local.hint}>\n <p id={descriptionId} class=\"text-muted-foreground text-sm\">\n {local.hint}\n </p>\n </Show>\n <Show when={local.error}>\n <p id={errorId} role=\"alert\" class=\"text-foreground text-sm\">\n {local.error}\n </p>\n </Show>\n </>\n )\n\n return (\n <FormFieldContext.Provider value={field}>\n <div class={cn('flex flex-col gap-1.5', local.class)} {...rest}>\n {local.group ? (\n <FieldSet\n class=\"flex flex-col gap-1.5\"\n aria-describedby={field.describedBy()}\n aria-invalid={field.invalid() || undefined}\n >\n <FieldLegend id={labelId} variant=\"label\">\n {local.label}\n </FieldLegend>\n {local.children}\n {help()}\n </FieldSet>\n ) : (\n <>\n <Label id={labelId} for={field.controlId()}>\n {local.label}\n </Label>\n {local.children}\n {help()}\n </>\n )}\n </div>\n </FormFieldContext.Provider>\n )\n}\n\nexport function FieldLabel(props: ComponentProps<typeof KobalteTextField.Label>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteTextField.Label class={cn('text-sm leading-none font-medium', local.class)} {...rest} />\n )\n}\n\nexport function FieldDescription(props: ComponentProps<typeof KobalteTextField.Description>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteTextField.Description\n class={cn('text-muted-foreground text-sm', local.class)}\n {...rest}\n />\n )\n}\n\nexport function FieldError(props: ComponentProps<typeof KobalteTextField.ErrorMessage>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <KobalteTextField.ErrorMessage class={cn('text-foreground text-sm', local.class)} {...rest} />\n )\n}\n\nexport function FieldInput(props: ComponentProps<typeof KobalteTextField.Input>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <KobalteTextField.Input\n class={cn(\n 'h-control-md w-full min-w-0 rounded-md border border-input bg-transparent px-control-md py-1 text-sm',\n 'transition-[color,box-shadow,border-color] ease-out outline-none',\n 'placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive-subtle',\n 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function FieldTextArea(props: ComponentProps<typeof KobalteTextField.TextArea>) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <KobalteTextField.TextArea\n class={cn(\n 'flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-control-md py-2 text-sm',\n 'transition-[color,box-shadow,border-color] ease-out outline-none resize-y',\n 'placeholder:text-muted-foreground',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n 'aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive-subtle',\n 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/**\n * A labelled group of fields with a single legend, for a real `<fieldset>`.\n * Grouping is what lets a screen reader announce \"Shipping address, group\"\n * before reading the four fields inside it.\n */\nexport function FieldSet(props: ComponentProps<'fieldset'>) {\n const [local, rest] = splitProps(props, ['class'])\n return <fieldset class={cn('flex flex-col gap-4', local.class)} {...rest} />\n}\n\nexport type FieldGroupProps = ComponentProps<'div'> & {\n /**\n * `2` lays the fields out in two columns from the `sm` breakpoint up — a\n * short form of paired values (host and port, a name and a model). A field\n * that needs the full width says `class=\"col-span-full\"`. Below `sm` it is\n * one column again, because two inputs side by side on a phone are each too\n * narrow to read.\n *\n * `3` is the same grid with three columns from `sm`, for a row of short values\n * (a trio of limits, a day count and two thresholds). Each column is a third of\n * the group, so reach for `2` when a field holds a path, a URL or a sentence.\n */\n columns?: 1 | 2 | 3\n}\n\n/** A visual stack for related controls that does not imply fieldset semantics. */\nexport function FieldGroup(props: FieldGroupProps) {\n const [local, rest] = splitProps(props, ['class', 'columns'])\n return (\n <div\n data-slot=\"field-group\"\n class={cn(\n {\n 'grid gap-4 sm:grid-cols-2': local.columns === 2,\n 'grid gap-4 sm:grid-cols-3': local.columns === 3,\n 'flex flex-col gap-4': local.columns !== 2 && local.columns !== 3,\n },\n local.class\n )}\n {...rest}\n />\n )\n}\n\nexport function FieldLegend(props: ComponentProps<'legend'> & { variant?: 'legend' | 'label' }) {\n const [local, rest] = splitProps(props, ['class', 'variant'])\n return (\n <legend\n class={cn(\n 'mb-1',\n local.variant === 'label' ? 'text-sm font-medium' : headingVariants({ size: 'card' }),\n local.class\n )}\n {...rest}\n />\n )\n}\n\n/** A horizontal rule with a word in it, for \"or continue with\" separators. */\nexport function FieldSeparator(props: {\n class?: string\n children?: ComponentProps<'span'>['children']\n}) {\n const [local, rest] = splitProps(props, ['class', 'children'])\n\n return (\n <div class={cn('relative flex items-center gap-3 py-1', local.class)} {...rest}>\n <span class=\"bg-border h-px flex-1\" />\n <Show when={local.children}>\n <span class=\"text-muted-foreground text-2xs tracking-wide uppercase\">{local.children}</span>\n </Show>\n <span class=\"bg-border h-px flex-1\" />\n </div>\n )\n}\n"],"mappings":"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"}
|
|
@@ -5,6 +5,20 @@ export type NumberFieldProps = {
|
|
|
5
5
|
value: number;
|
|
6
6
|
min: number;
|
|
7
7
|
max: number;
|
|
8
|
+
/**
|
|
9
|
+
* The increment of the spinner and the arrow keys, and the grid a typed value
|
|
10
|
+
* must sit on: `min` plus a whole number of steps. Use it for stepped or
|
|
11
|
+
* fractional values (`0.05` for a 0-1 score, `5` for a percentage in fives).
|
|
12
|
+
* Without it a field steps by 1, or by `any` when `integer` is `false`, which
|
|
13
|
+
* accepts every decimal but leaves the spinner moving in whole numbers.
|
|
14
|
+
*/
|
|
15
|
+
step?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Whether only whole numbers are valid. It defaults to `true`, or, when a
|
|
18
|
+
* `step` is given, to whether both the step and its base `min` are whole
|
|
19
|
+
* numbers, so `step={0.05}` accepts decimals without also saying
|
|
20
|
+
* `integer={false}`, and `min={0.5} step={1}` accepts 0.5, 1.5, 2.5.
|
|
21
|
+
*/
|
|
8
22
|
integer?: boolean;
|
|
9
23
|
onChange: (value: number) => void;
|
|
10
24
|
class?: string;
|
|
@@ -12,8 +26,10 @@ export type NumberFieldProps = {
|
|
|
12
26
|
};
|
|
13
27
|
/**
|
|
14
28
|
* A controlled numeric field that keeps an editable draft while validating
|
|
15
|
-
* range and
|
|
16
|
-
* to the latest controlled value when focus leaves the input
|
|
29
|
+
* range, integer and step constraints. Invalid drafts are announced and restored
|
|
30
|
+
* to the latest controlled value when focus leaves the input, so `onChange`
|
|
31
|
+
* only ever receives a value the field accepts — a caller never needs a
|
|
32
|
+
* `Number(value) || fallback` of its own.
|
|
17
33
|
*/
|
|
18
34
|
export declare function NumberField(props: NumberFieldProps): JSX.Element;
|
|
19
35
|
//# sourceMappingURL=number-field.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number-field.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/field/number-field.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAI/D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAA;CACxD,CAAA;AAED
|
|
1
|
+
{"version":3,"file":"number-field.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/field/number-field.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAI/D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAA;CACxD,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,eAgElD"}
|
|
@@ -5,13 +5,15 @@ import { createEffect, createSignal } from "solid-js";
|
|
|
5
5
|
//#region src/components/ui/field/number-field.tsx
|
|
6
6
|
/**
|
|
7
7
|
* A controlled numeric field that keeps an editable draft while validating
|
|
8
|
-
* range and
|
|
9
|
-
* to the latest controlled value when focus leaves the input
|
|
8
|
+
* range, integer and step constraints. Invalid drafts are announced and restored
|
|
9
|
+
* to the latest controlled value when focus leaves the input, so `onChange`
|
|
10
|
+
* only ever receives a value the field accepts — a caller never needs a
|
|
11
|
+
* `Number(value) || fallback` of its own.
|
|
10
12
|
*/
|
|
11
13
|
function NumberField(props) {
|
|
12
14
|
const [draft, setDraft] = createSignal(String(props.value));
|
|
13
15
|
const [error, setError] = createSignal("");
|
|
14
|
-
const integer = () => props.integer ??
|
|
16
|
+
const integer = () => props.integer ?? (props.step === void 0 || Number.isInteger(props.step) && Number.isInteger(props.min));
|
|
15
17
|
createEffect(() => {
|
|
16
18
|
setDraft(String(props.value));
|
|
17
19
|
});
|
|
@@ -21,6 +23,10 @@ function NumberField(props) {
|
|
|
21
23
|
if (!Number.isFinite(next)) return `${props.label} must be a valid number.`;
|
|
22
24
|
if (integer() && !Number.isInteger(next)) return `${props.label} must be a whole number.`;
|
|
23
25
|
if (next < props.min || next > props.max) return `${props.label} must be between ${props.min} and ${props.max}.`;
|
|
26
|
+
if (props.step !== void 0 && props.step > 0) {
|
|
27
|
+
const steps = (next - props.min) / props.step;
|
|
28
|
+
if (Math.abs(steps - Math.round(steps)) > 1e-9) return props.min === 0 ? `${props.label} must be a multiple of ${props.step}.` : `${props.label} must be ${props.min} plus a multiple of ${props.step}.`;
|
|
29
|
+
}
|
|
24
30
|
return "";
|
|
25
31
|
};
|
|
26
32
|
return createComponent(FormField, {
|
|
@@ -49,7 +55,7 @@ function NumberField(props) {
|
|
|
49
55
|
return props.max;
|
|
50
56
|
},
|
|
51
57
|
get step() {
|
|
52
|
-
return integer() ? 1 : "any";
|
|
58
|
+
return props.step ?? (integer() ? 1 : "any");
|
|
53
59
|
},
|
|
54
60
|
required: true,
|
|
55
61
|
onInput: (event) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number-field.js","names":["createEffect","createSignal","JSX","FormField","Input","NumberFieldProps","label","hint","value","min","max","integer","onChange","class","onBlur","EventHandler","HTMLInputElement","FocusEvent","NumberField","props","draft","setDraft","String","error","setError","validate","raw","next","
|
|
1
|
+
{"version":3,"file":"number-field.js","names":["createEffect","createSignal","JSX","FormField","Input","NumberFieldProps","label","hint","value","min","max","step","integer","onChange","class","onBlur","EventHandler","HTMLInputElement","FocusEvent","NumberField","props","draft","setDraft","String","error","setError","undefined","Number","isInteger","validate","raw","next","isFinite","steps","Math","abs","round","_$createComponent","children","type","required","onInput","event","currentTarget","nextError","_$createComponent"],"sources":["../../../../src/components/ui/field/number-field.tsx"],"sourcesContent":["import { createEffect, createSignal, type JSX } from 'solid-js'\nimport { FormField } from './field'\nimport { Input } from '../input/input'\n\nexport type NumberFieldProps = {\n label: string\n hint?: string\n value: number\n min: number\n max: number\n /**\n * The increment of the spinner and the arrow keys, and the grid a typed value\n * must sit on: `min` plus a whole number of steps. Use it for stepped or\n * fractional values (`0.05` for a 0-1 score, `5` for a percentage in fives).\n * Without it a field steps by 1, or by `any` when `integer` is `false`, which\n * accepts every decimal but leaves the spinner moving in whole numbers.\n */\n step?: number\n /**\n * Whether only whole numbers are valid. It defaults to `true`, or, when a\n * `step` is given, to whether both the step and its base `min` are whole\n * numbers, so `step={0.05}` accepts decimals without also saying\n * `integer={false}`, and `min={0.5} step={1}` accepts 0.5, 1.5, 2.5.\n */\n integer?: boolean\n onChange: (value: number) => void\n class?: string\n onBlur?: JSX.EventHandler<HTMLInputElement, FocusEvent>\n}\n\n/**\n * A controlled numeric field that keeps an editable draft while validating\n * range, integer and step constraints. Invalid drafts are announced and restored\n * to the latest controlled value when focus leaves the input, so `onChange`\n * only ever receives a value the field accepts — a caller never needs a\n * `Number(value) || fallback` of its own.\n */\nexport function NumberField(props: NumberFieldProps) {\n const [draft, setDraft] = createSignal(String(props.value))\n const [error, setError] = createSignal('')\n // Whole numbers only when nothing on the grid is fractional: a whole step from\n // a fractional `min` (0.5, 1.5, 2.5) puts the spinner's own values off the\n // integers, so inference needs the step and its base to both be whole.\n const integer = () =>\n props.integer ??\n (props.step === undefined || (Number.isInteger(props.step) && Number.isInteger(props.min)))\n\n createEffect(() => {\n setDraft(String(props.value))\n })\n\n const validate = (raw: string) => {\n if (!raw) return `${props.label} is required.`\n const next = Number(raw)\n if (!Number.isFinite(next)) return `${props.label} must be a valid number.`\n if (integer() && !Number.isInteger(next)) {\n return `${props.label} must be a whole number.`\n }\n if (next < props.min || next > props.max) {\n return `${props.label} must be between ${props.min} and ${props.max}.`\n }\n if (props.step !== undefined && props.step > 0) {\n // Compare in whole steps with a tolerance: 0.15 / 0.05 is 3.0000000000000004,\n // and rejecting it would make the spinner's own values invalid.\n const steps = (next - props.min) / props.step\n if (Math.abs(steps - Math.round(steps)) > 1e-9) {\n return props.min === 0\n ? `${props.label} must be a multiple of ${props.step}.`\n : `${props.label} must be ${props.min} plus a multiple of ${props.step}.`\n }\n }\n return ''\n }\n\n return (\n <FormField label={props.label} hint={props.hint} error={error()} class={props.class}>\n <Input\n type=\"number\"\n value={draft()}\n min={props.min}\n max={props.max}\n step={props.step ?? (integer() ? 1 : 'any')}\n required\n onInput={(event) => {\n const raw = event.currentTarget.value\n setDraft(raw)\n const nextError = validate(raw)\n setError(nextError)\n if (!nextError) props.onChange(Number(raw))\n }}\n onBlur={(event) => {\n const nextError = validate(draft())\n if (nextError) {\n setDraft(String(props.value))\n setError('')\n }\n props.onBlur?.(event)\n }}\n />\n </FormField>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAqCA,SAAgBmB,YAAYC,OAAyB;CACnD,MAAM,CAACC,OAAOC,YAAYrB,aAAasB,OAAOH,MAAMZ,KAAK,CAAC;CAC1D,MAAM,CAACgB,OAAOC,YAAYxB,aAAa,EAAE;CAIzC,MAAMW,gBACJQ,MAAMR,YACLQ,MAAMT,SAASe,KAAAA,KAAcC,OAAOC,UAAUR,MAAMT,IAAI,KAAKgB,OAAOC,UAAUR,MAAMX,GAAG;CAE1FT,mBAAmB;EACjBsB,SAASC,OAAOH,MAAMZ,KAAK,CAAC;CAC9B,CAAC;CAED,MAAMqB,YAAYC,QAAgB;EAChC,IAAI,CAACA,KAAK,OAAO,GAAGV,MAAMd,MAAK;EAC/B,MAAMyB,OAAOJ,OAAOG,GAAG;EACvB,IAAI,CAACH,OAAOK,SAASD,IAAI,GAAG,OAAO,GAAGX,MAAMd,MAAK;EACjD,IAAIM,QAAQ,KAAK,CAACe,OAAOC,UAAUG,IAAI,GACrC,OAAO,GAAGX,MAAMd,MAAK;EAEvB,IAAIyB,OAAOX,MAAMX,OAAOsB,OAAOX,MAAMV,KACnC,OAAO,GAAGU,MAAMd,MAAK,mBAAoBc,MAAMX,IAAG,OAAQW,MAAMV,IAAG;EAErE,IAAIU,MAAMT,SAASe,KAAAA,KAAaN,MAAMT,OAAO,GAAG;GAG9C,MAAMsB,SAASF,OAAOX,MAAMX,OAAOW,MAAMT;GACzC,IAAIuB,KAAKC,IAAIF,QAAQC,KAAKE,MAAMH,KAAK,CAAC,IAAI,MACxC,OAAOb,MAAMX,QAAQ,IACjB,GAAGW,MAAMd,MAAK,yBAA0Bc,MAAMT,KAAI,KAClD,GAAGS,MAAMd,MAAK,WAAYc,MAAMX,IAAG,sBAAuBW,MAAMT,KAAI;EAE5E;EACA,OAAO;CACT;CAEA,OAAA0B,gBACGlC,WAAS;EAAA,IAACG,QAAK;GAAA,OAAEc,MAAMd;EAAK;EAAA,IAAEC,OAAI;GAAA,OAAEa,MAAMb;EAAI;EAAA,IAAEiB,QAAK;GAAA,OAAEA,MAAM;EAAC;EAAA,KAAA,WAAA;GAAA,OAASJ,MAAMN;EAAK;EAAA,IAAAwB,WAAA;GAAA,OAAAD,gBAChFjC,OAAK;IACJmC,MAAI;IAAA,IACJ/B,QAAK;KAAA,OAAEa,MAAM;IAAC;IAAA,IACdZ,MAAG;KAAA,OAAEW,MAAMX;IAAG;IAAA,IACdC,MAAG;KAAA,OAAEU,MAAMV;IAAG;IAAA,IACdC,OAAI;KAAA,OAAES,MAAMT,SAASC,QAAQ,IAAI,IAAI;IAAM;IAC3C4B,UAAQ;IACRC,UAAUC,UAAU;KAClB,MAAMZ,MAAMY,MAAMC,cAAcnC;KAChCc,SAASQ,GAAG;KACZ,MAAMc,YAAYf,SAASC,GAAG;KAC9BL,SAASmB,SAAS;KAClB,IAAI,CAACA,WAAWxB,MAAMP,SAASc,OAAOG,GAAG,CAAC;IAC5C;IACAf,SAAS2B,UAAU;KAEjB,IADkBb,SAASR,MAAM,CAC7BuB,GAAW;MACbtB,SAASC,OAAOH,MAAMZ,KAAK,CAAC;MAC5BiB,SAAS,EAAE;KACb;KACAL,MAAML,SAAS2B,KAAK;IACtB;GAAC,CAAA;EAAA;CAAA,CAAA;AAIT"}
|