vultus-core 0.4.0 → 0.5.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/README.md +304 -6
- package/dist/ArgStoreContext.d.ts +10 -0
- package/dist/ArgStoreContext.d.ts.map +1 -0
- package/dist/ArgStoreContext.js +15 -0
- package/dist/ArgStoreContext.js.map +1 -0
- package/dist/FieldContext.d.ts +38 -0
- package/dist/FieldContext.d.ts.map +1 -0
- package/dist/FieldContext.js +82 -0
- package/dist/FieldContext.js.map +1 -0
- package/dist/argStore.d.ts +26 -0
- package/dist/argStore.d.ts.map +1 -0
- package/dist/argStore.js +27 -0
- package/dist/argStore.js.map +1 -0
- package/dist/choices.d.ts +43 -0
- package/dist/choices.d.ts.map +1 -0
- package/dist/choices.js +20 -0
- package/dist/choices.js.map +1 -0
- package/dist/field.d.ts +42 -15
- package/dist/field.d.ts.map +1 -1
- package/dist/field.js +20 -7
- package/dist/field.js.map +1 -1
- package/dist/index.d.ts +21 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -3
- package/dist/index.js.map +1 -1
- package/dist/kinds.d.ts +51 -0
- package/dist/kinds.d.ts.map +1 -0
- package/dist/kinds.js +143 -0
- package/dist/kinds.js.map +1 -0
- package/dist/localStorageStore.d.ts +16 -0
- package/dist/localStorageStore.d.ts.map +1 -0
- package/dist/localStorageStore.js +72 -0
- package/dist/localStorageStore.js.map +1 -0
- package/dist/normalizeText.d.ts +6 -0
- package/dist/normalizeText.d.ts.map +1 -0
- package/dist/normalizeText.js +8 -0
- package/dist/normalizeText.js.map +1 -0
- package/dist/numeric.d.ts +38 -0
- package/dist/numeric.d.ts.map +1 -0
- package/dist/numeric.js +43 -0
- package/dist/numeric.js.map +1 -0
- package/dist/resolve.d.ts +13 -0
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +25 -0
- package/dist/resolve.js.map +1 -1
- package/dist/tree.d.ts +69 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +151 -0
- package/dist/tree.js.map +1 -0
- package/dist/types.d.ts +15 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/useArg.d.ts +45 -0
- package/dist/useArg.d.ts.map +1 -0
- package/dist/useArg.js +83 -0
- package/dist/useArg.js.map +1 -0
- package/dist/useBoolField.d.ts +8 -3
- package/dist/useBoolField.d.ts.map +1 -1
- package/dist/useBoolField.js +9 -1
- package/dist/useBoolField.js.map +1 -1
- package/dist/useManyOfField.d.ts +35 -0
- package/dist/useManyOfField.d.ts.map +1 -0
- package/dist/useManyOfField.js +74 -0
- package/dist/useManyOfField.js.map +1 -0
- package/dist/useMixedBoolField.d.ts +8 -3
- package/dist/useMixedBoolField.d.ts.map +1 -1
- package/dist/useMixedBoolField.js +9 -1
- package/dist/useMixedBoolField.js.map +1 -1
- package/dist/useNumericField.d.ts +25 -0
- package/dist/useNumericField.d.ts.map +1 -0
- package/dist/useNumericField.js +52 -0
- package/dist/useNumericField.js.map +1 -0
- package/dist/useOneOfField.d.ts +18 -34
- package/dist/useOneOfField.d.ts.map +1 -1
- package/dist/useOneOfField.js +18 -18
- package/dist/useOneOfField.js.map +1 -1
- package/dist/useRangeField.d.ts +34 -0
- package/dist/useRangeField.d.ts.map +1 -0
- package/dist/useRangeField.js +63 -0
- package/dist/useRangeField.js.map +1 -0
- package/dist/useStoredField.d.ts +61 -0
- package/dist/useStoredField.d.ts.map +1 -0
- package/dist/useStoredField.js +151 -0
- package/dist/useStoredField.js.map +1 -0
- package/dist/useTextField.d.ts +22 -0
- package/dist/useTextField.d.ts.map +1 -0
- package/dist/useTextField.js +21 -0
- package/dist/useTextField.js.map +1 -0
- package/dist/useTreeField.d.ts +39 -0
- package/dist/useTreeField.d.ts.map +1 -0
- package/dist/useTreeField.js +66 -0
- package/dist/useTreeField.js.map +1 -0
- package/dist/valueTypes.d.ts +28 -0
- package/dist/valueTypes.d.ts.map +1 -0
- package/dist/valueTypes.js +65 -0
- package/dist/valueTypes.js.map +1 -0
- package/package.json +1 -1
- package/src/ArgStoreContext.tsx +16 -0
- package/src/FieldContext.tsx +98 -0
- package/src/argStore.ts +49 -0
- package/src/choices.ts +62 -0
- package/src/field.ts +64 -25
- package/src/index.ts +50 -4
- package/src/kinds.ts +197 -0
- package/src/localStorageStore.ts +68 -0
- package/src/normalizeText.ts +7 -0
- package/src/numeric.ts +68 -0
- package/src/resolve.ts +23 -0
- package/src/tree.ts +175 -0
- package/src/types.ts +28 -7
- package/src/useArg.ts +121 -0
- package/src/useBoolField.ts +19 -6
- package/src/useManyOfField.ts +107 -0
- package/src/useMixedBoolField.ts +19 -6
- package/src/useNumericField.ts +69 -0
- package/src/useOneOfField.ts +38 -58
- package/src/useRangeField.ts +86 -0
- package/src/useStoredField.ts +205 -0
- package/src/useTextField.ts +39 -0
- package/src/useTreeField.ts +108 -0
- package/src/valueTypes.ts +77 -0
package/dist/useBoolField.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type FieldControls, type FieldOptions } from './field.js';
|
|
2
|
-
import type
|
|
3
|
-
|
|
2
|
+
import { type FieldCtx } from './FieldContext.js';
|
|
3
|
+
import type { ErrorRoutesRegistry, ValueOrFn } from './types.js';
|
|
4
|
+
export type BoolFieldOptions<RouteId extends string = string, Ctx = any> = FieldOptions<boolean, boolean, RouteId, Ctx>;
|
|
4
5
|
export interface BoolFieldControls extends FieldControls<boolean, boolean> {
|
|
5
6
|
/**
|
|
6
7
|
* Request the opposite value. Programmatic use; widgets obtain the field's
|
|
@@ -8,10 +9,14 @@ export interface BoolFieldControls extends FieldControls<boolean, boolean> {
|
|
|
8
9
|
*/
|
|
9
10
|
toggle(): void;
|
|
10
11
|
}
|
|
12
|
+
/** The implicit initial value for a boolean field: `initialValue` resolved, else false. */
|
|
13
|
+
export declare function boolInitialValue(opts: {
|
|
14
|
+
initialValue?: ValueOrFn<boolean>;
|
|
15
|
+
}, ctx: FieldCtx, id: string): boolean;
|
|
11
16
|
/**
|
|
12
17
|
* A boolean field (moxb's Bool, the sidedao boolean field). Rendered by
|
|
13
18
|
* vultus-antd's BoolCheckbox and BoolSwitch, which take the same controls.
|
|
14
19
|
* Inside the field the value starts at `initialValue` (default false).
|
|
15
20
|
*/
|
|
16
|
-
export declare function useBoolField<RouteId extends string = string>(opts: BoolFieldOptions<RouteId>, registry?: ErrorRoutesRegistry<RouteId>): BoolFieldControls;
|
|
21
|
+
export declare function useBoolField<RouteId extends string = string, Ctx = any>(opts: BoolFieldOptions<RouteId, Ctx>, registry?: ErrorRoutesRegistry<RouteId>): BoolFieldControls;
|
|
17
22
|
//# sourceMappingURL=useBoolField.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBoolField.d.ts","sourceRoot":"","sources":["../src/useBoolField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"useBoolField.d.ts","sourceRoot":"","sources":["../src/useBoolField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,MAAM,gBAAgB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,IAAI,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;AAExH,MAAM,WAAW,iBAAkB,SAAQ,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC;IACxE;;;OAGG;IACH,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE;IAAE,YAAY,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;CAAE,EAC3C,GAAG,EAAE,QAAQ,EACb,EAAE,EAAE,MAAM,GACT,OAAO,CAET;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,EACrE,IAAI,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC,EACpC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,GACtC,iBAAiB,CAUnB"}
|
package/dist/useBoolField.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { useFieldCore } from './field.js';
|
|
2
|
+
import { useFieldContext } from './FieldContext.js';
|
|
3
|
+
import { resolveIn } from './resolve.js';
|
|
4
|
+
/** The implicit initial value for a boolean field: `initialValue` resolved, else false. */
|
|
5
|
+
export function boolInitialValue(opts, ctx, id) {
|
|
6
|
+
return resolveIn(opts.initialValue, false, ctx, `Field '${id}': option 'initialValue'`);
|
|
7
|
+
}
|
|
2
8
|
/**
|
|
3
9
|
* A boolean field (moxb's Bool, the sidedao boolean field). Rendered by
|
|
4
10
|
* vultus-antd's BoolCheckbox and BoolSwitch, which take the same controls.
|
|
5
11
|
* Inside the field the value starts at `initialValue` (default false).
|
|
6
12
|
*/
|
|
7
13
|
export function useBoolField(opts, registry) {
|
|
14
|
+
const ctx = useFieldContext();
|
|
8
15
|
const inside = !opts.onChange && !opts.commit;
|
|
9
|
-
const
|
|
16
|
+
const initialValue = () => boolInitialValue(opts, ctx, opts.id);
|
|
17
|
+
const field = useFieldCore('boolean', inside ? { ...opts, initialValue } : opts, registry);
|
|
10
18
|
return { ...field, toggle: () => field.setValue(!field.value) };
|
|
11
19
|
}
|
|
12
20
|
//# sourceMappingURL=useBoolField.js.map
|
package/dist/useBoolField.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBoolField.js","sourceRoot":"","sources":["../src/useBoolField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"useBoolField.js","sourceRoot":"","sources":["../src/useBoolField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyC,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,eAAe,EAAiB,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAazC,2FAA2F;AAC3F,MAAM,UAAU,gBAAgB,CAC9B,IAA2C,EAC3C,GAAa,EACb,EAAU;IAEV,OAAO,SAAS,CAAU,IAAI,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,0BAA0B,CAAC,CAAC;AACnG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAoC,EACpC,QAAuC;IAEvC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC9C,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,YAAY,CACxB,SAAS,EACT,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,EACzC,QAAQ,CACT,CAAC;IACF,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type FieldControls, type FieldOptions } from './field.js';
|
|
2
|
+
import { type OneOfChoice, type OneOfChoiceControls } from './choices.js';
|
|
3
|
+
import { type FieldCtx } from './FieldContext.js';
|
|
4
|
+
import type { ErrorRoutesRegistry, ValueOrFn } from './types.js';
|
|
5
|
+
export type ManyOfOwnOptions<T extends string = string, Ctx = any> = {
|
|
6
|
+
/** The choices, in order; static or derived (a function, of the field context if it declares a parameter). */
|
|
7
|
+
choices: ValueOrFn<OneOfChoice<T>[], Ctx>;
|
|
8
|
+
};
|
|
9
|
+
export type ManyOfFieldOptions<T extends string = string, RouteId extends string = string, Ctx = any> = FieldOptions<T[], T[], RouteId, Ctx> & ManyOfOwnOptions<T, Ctx>;
|
|
10
|
+
export interface ManyOfChoiceControls<T extends string = string> extends OneOfChoiceControls<T> {
|
|
11
|
+
selected: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface ManyOfFieldControls<T extends string = string> extends FieldControls<T[], T[]> {
|
|
14
|
+
choices: ManyOfChoiceControls<T>[];
|
|
15
|
+
isSelected(value: T): boolean;
|
|
16
|
+
/** Flips a choice's membership in the value; ignored (with a warning) for an unknown or disabled choice. */
|
|
17
|
+
toggle(value: T): void;
|
|
18
|
+
}
|
|
19
|
+
/** The implicit initial value for a many-of field: `initialValue` resolved, else the empty list. */
|
|
20
|
+
export declare function manyOfInitialValue<T extends string>(opts: {
|
|
21
|
+
initialValue?: ValueOrFn<T[]>;
|
|
22
|
+
}, ctx: FieldCtx, id: string): T[];
|
|
23
|
+
/**
|
|
24
|
+
* A field whose value is a set of choices (moxb's ManyOf). A request (to
|
|
25
|
+
* `setValue` or `toggle`) is normalized to the known choices in their order,
|
|
26
|
+
* without duplicates, followed by the values the field already holds that are
|
|
27
|
+
* no longer among the choices and that the request keeps (in their current
|
|
28
|
+
* order: `toggle` keeps them, so a stored value naming a choice that was
|
|
29
|
+
* removed is not silently dropped, while `setValue([])` clears it). A request
|
|
30
|
+
* naming a value that is neither a choice nor already held, or that changes a
|
|
31
|
+
* disabled choice's membership, is ignored with a warning — as useOneOfField
|
|
32
|
+
* refuses a disabled or unknown choice.
|
|
33
|
+
*/
|
|
34
|
+
export declare function useManyOfField<T extends string = string, RouteId extends string = string, Ctx = any>(opts: ManyOfFieldOptions<T, RouteId, Ctx>, registry?: ErrorRoutesRegistry<RouteId>): ManyOfFieldControls<T>;
|
|
35
|
+
//# sourceMappingURL=useManyOfField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useManyOfField.d.ts","sourceRoot":"","sources":["../src/useManyOfField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAiB,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACzF,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,IAAI;IACnE,8GAA8G;IAC9G,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,IAClG,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,gBAAgB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAElE,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,mBAAmB,CAAC,CAAC,CAAC;IAC7F,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAC7F,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC;IACnC,UAAU,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IAC9B,4GAA4G;IAC5G,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;CACxB;AAED,oGAAoG;AACpG,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,EACjD,IAAI,EAAE;IAAE,YAAY,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAA;CAAE,EACvC,GAAG,EAAE,QAAQ,EACb,EAAE,EAAE,MAAM,GACT,CAAC,EAAE,CAEL;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,EAClG,IAAI,EAAE,kBAAkB,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,EACzC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,GACtC,mBAAmB,CAAC,CAAC,CAAC,CA0DxB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useFieldCore } from './field.js';
|
|
2
|
+
import { resolveChoice } from './choices.js';
|
|
3
|
+
import { useFieldContext } from './FieldContext.js';
|
|
4
|
+
import { resolveIn } from './resolve.js';
|
|
5
|
+
/** The implicit initial value for a many-of field: `initialValue` resolved, else the empty list. */
|
|
6
|
+
export function manyOfInitialValue(opts, ctx, id) {
|
|
7
|
+
return resolveIn(opts.initialValue, [], ctx, `Field '${id}': option 'initialValue'`);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A field whose value is a set of choices (moxb's ManyOf). A request (to
|
|
11
|
+
* `setValue` or `toggle`) is normalized to the known choices in their order,
|
|
12
|
+
* without duplicates, followed by the values the field already holds that are
|
|
13
|
+
* no longer among the choices and that the request keeps (in their current
|
|
14
|
+
* order: `toggle` keeps them, so a stored value naming a choice that was
|
|
15
|
+
* removed is not silently dropped, while `setValue([])` clears it). A request
|
|
16
|
+
* naming a value that is neither a choice nor already held, or that changes a
|
|
17
|
+
* disabled choice's membership, is ignored with a warning — as useOneOfField
|
|
18
|
+
* refuses a disabled or unknown choice.
|
|
19
|
+
*/
|
|
20
|
+
export function useManyOfField(opts, registry) {
|
|
21
|
+
const ctx = useFieldContext();
|
|
22
|
+
const resolvedChoices = resolveIn(opts.choices, [], ctx, `Field '${opts.id}': option 'choices'`)
|
|
23
|
+
.map((c) => resolveChoice(opts.id, c));
|
|
24
|
+
const byValue = new Map(resolvedChoices.map((c) => [c.value, c]));
|
|
25
|
+
const choiceOrder = resolvedChoices.map((c) => c.value);
|
|
26
|
+
const inside = !opts.onChange && !opts.commit;
|
|
27
|
+
const initialValue = () => manyOfInitialValue(opts, ctx, opts.id);
|
|
28
|
+
const field = useFieldCore('manyOf', inside ? { ...opts, initialValue } : opts, registry);
|
|
29
|
+
/** The normalized list a request becomes, or undefined when the request is refused (with a warning already issued). */
|
|
30
|
+
const normalize = (request, current) => {
|
|
31
|
+
const requestSet = new Set(request);
|
|
32
|
+
const currentSet = new Set(current);
|
|
33
|
+
const heldUnknown = current.filter((v) => !byValue.has(v));
|
|
34
|
+
const heldUnknownSet = new Set(heldUnknown);
|
|
35
|
+
for (const v of request) {
|
|
36
|
+
if (!byValue.has(v) && !heldUnknownSet.has(v)) {
|
|
37
|
+
console.warn(`Field '${opts.id}': '${v}' is not one of its choices`);
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const choice of resolvedChoices) {
|
|
42
|
+
if (choice.enabled)
|
|
43
|
+
continue;
|
|
44
|
+
if (currentSet.has(choice.value) !== requestSet.has(choice.value)) {
|
|
45
|
+
console.warn(`Field '${opts.id}': choice '${choice.value}' is disabled — ${choice.whyDisabled ?? '(no reason)'}`);
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return [...choiceOrder.filter((v) => requestSet.has(v)), ...heldUnknown.filter((v) => requestSet.has(v))];
|
|
50
|
+
};
|
|
51
|
+
const setValue = (next) => {
|
|
52
|
+
const normalized = normalize(next, field.value);
|
|
53
|
+
if (normalized === undefined)
|
|
54
|
+
return;
|
|
55
|
+
field.setValue(normalized);
|
|
56
|
+
};
|
|
57
|
+
const isSelected = (value) => field.value.includes(value);
|
|
58
|
+
const toggle = (value) => {
|
|
59
|
+
const choice = byValue.get(value);
|
|
60
|
+
if (!choice) {
|
|
61
|
+
console.warn(`Field '${opts.id}': '${value}' is not one of its choices`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!choice.enabled) {
|
|
65
|
+
console.warn(`Field '${opts.id}': choice '${value}' is disabled — ${choice.whyDisabled ?? '(no reason)'}`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const current = field.value;
|
|
69
|
+
setValue(current.includes(value) ? current.filter((v) => v !== value) : [...current, value]);
|
|
70
|
+
};
|
|
71
|
+
const choices = resolvedChoices.map((c) => ({ ...c, selected: field.value.includes(c.value) }));
|
|
72
|
+
return { ...field, setValue, choices, isSelected, toggle };
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=useManyOfField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useManyOfField.js","sourceRoot":"","sources":["../src/useManyOfField.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { type FieldControls, type FieldOptions } from './field.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type FieldCtx } from './FieldContext.js';
|
|
3
|
+
import type { ErrorRoutesRegistry, ValueOrFn } from './types.js';
|
|
3
4
|
/** What a mixed boolean field shows: on, off, or some of its items on and some off. */
|
|
4
5
|
export type MixedBool = boolean | 'mixed';
|
|
5
|
-
export type MixedBoolFieldOptions<RouteId extends string = string> = FieldOptions<MixedBool, boolean, RouteId>;
|
|
6
|
+
export type MixedBoolFieldOptions<RouteId extends string = string, Ctx = any> = FieldOptions<MixedBool, boolean, RouteId, Ctx>;
|
|
6
7
|
export interface MixedBoolFieldControls extends FieldControls<MixedBool, boolean> {
|
|
7
8
|
/** Request the opposite: off when on, on when off or mixed. Programmatic use, as in BoolFieldControls. */
|
|
8
9
|
toggle(): void;
|
|
9
10
|
}
|
|
11
|
+
/** The implicit initial value for a mixed-boolean field: `initialValue` resolved, else false. */
|
|
12
|
+
export declare function mixedBoolInitialValue(opts: {
|
|
13
|
+
initialValue?: ValueOrFn<MixedBool>;
|
|
14
|
+
}, ctx: FieldCtx, id: string): MixedBool;
|
|
10
15
|
/**
|
|
11
16
|
* A boolean field over an aggregate (moxb's indeterminate Bool, ARIA's
|
|
12
17
|
* "mixed"): it shows true, false or 'mixed', and can be asked for true or
|
|
@@ -14,7 +19,7 @@ export interface MixedBoolFieldControls extends FieldControls<MixedBool, boolean
|
|
|
14
19
|
* its knob in the middle, BoolCheckbox is indeterminate. Derive the value with
|
|
15
20
|
* `aggregateBool`; with no items at all, disable the field with a reason.
|
|
16
21
|
*/
|
|
17
|
-
export declare function useMixedBoolField<RouteId extends string = string>(opts: MixedBoolFieldOptions<RouteId>, registry?: ErrorRoutesRegistry<RouteId>): MixedBoolFieldControls;
|
|
22
|
+
export declare function useMixedBoolField<RouteId extends string = string, Ctx = any>(opts: MixedBoolFieldOptions<RouteId, Ctx>, registry?: ErrorRoutesRegistry<RouteId>): MixedBoolFieldControls;
|
|
18
23
|
/**
|
|
19
24
|
* The aggregate of several booleans: true when all are on, false when none is,
|
|
20
25
|
* 'mixed' otherwise; `undefined` when there are none (a case for disabling the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMixedBoolField.d.ts","sourceRoot":"","sources":["../src/useMixedBoolField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"useMixedBoolField.d.ts","sourceRoot":"","sources":["../src/useMixedBoolField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjE,uFAAuF;AACvF,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE1C,MAAM,MAAM,qBAAqB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,IAAI,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;AAE/H,MAAM,WAAW,sBAAuB,SAAQ,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC;IAC/E,0GAA0G;IAC1G,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,iGAAiG;AACjG,wBAAgB,qBAAqB,CACnC,IAAI,EAAE;IAAE,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;CAAE,EAC7C,GAAG,EAAE,QAAQ,EACb,EAAE,EAAE,MAAM,GACT,SAAS,CAEX;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,EAC1E,IAAI,EAAE,qBAAqB,CAAC,OAAO,EAAE,GAAG,CAAC,EACzC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,GACtC,sBAAsB,CAUxB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,GAAG,SAAS,CAI/E"}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { useFieldCore } from './field.js';
|
|
2
|
+
import { useFieldContext } from './FieldContext.js';
|
|
3
|
+
import { resolveIn } from './resolve.js';
|
|
4
|
+
/** The implicit initial value for a mixed-boolean field: `initialValue` resolved, else false. */
|
|
5
|
+
export function mixedBoolInitialValue(opts, ctx, id) {
|
|
6
|
+
return resolveIn(opts.initialValue, false, ctx, `Field '${id}': option 'initialValue'`);
|
|
7
|
+
}
|
|
2
8
|
/**
|
|
3
9
|
* A boolean field over an aggregate (moxb's indeterminate Bool, ARIA's
|
|
4
10
|
* "mixed"): it shows true, false or 'mixed', and can be asked for true or
|
|
@@ -7,8 +13,10 @@ import { useFieldCore } from './field.js';
|
|
|
7
13
|
* `aggregateBool`; with no items at all, disable the field with a reason.
|
|
8
14
|
*/
|
|
9
15
|
export function useMixedBoolField(opts, registry) {
|
|
16
|
+
const ctx = useFieldContext();
|
|
10
17
|
const inside = !opts.onChange && !opts.commit;
|
|
11
|
-
const
|
|
18
|
+
const initialValue = () => mixedBoolInitialValue(opts, ctx, opts.id);
|
|
19
|
+
const field = useFieldCore('mixed-boolean', inside ? { ...opts, initialValue } : opts, registry);
|
|
12
20
|
return { ...field, toggle: () => field.setValue(field.value !== true) };
|
|
13
21
|
}
|
|
14
22
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMixedBoolField.js","sourceRoot":"","sources":["../src/useMixedBoolField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"useMixedBoolField.js","sourceRoot":"","sources":["../src/useMixedBoolField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyC,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,eAAe,EAAiB,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAazC,iGAAiG;AACjG,MAAM,UAAU,qBAAqB,CACnC,IAA6C,EAC7C,GAAa,EACb,EAAU;IAEV,OAAO,SAAS,CAAY,IAAI,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,0BAA0B,CAAC,CAAC;AACrG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAyC,EACzC,QAAuC;IAEvC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC9C,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,YAAY,CACxB,eAAe,EACf,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,EACzC,QAAQ,CACT,CAAC;IACF,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,EAAE,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAA0B;IACtD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type FieldControls, type FieldOptions } from './field.js';
|
|
2
|
+
import { type FieldCtx } from './FieldContext.js';
|
|
3
|
+
import { type NumericBounds, type ResolvedNumeric } from './numeric.js';
|
|
4
|
+
import type { ErrorRoutesRegistry } from './types.js';
|
|
5
|
+
export type NumericOwnOptions<Ctx = any> = NumericBounds<Ctx>;
|
|
6
|
+
export type NumericFieldOptions<RouteId extends string = string, Ctx = any> = FieldOptions<number, number, RouteId, Ctx> & NumericOwnOptions<Ctx>;
|
|
7
|
+
export interface NumericFieldControls extends FieldControls<number, number>, ResolvedNumeric {
|
|
8
|
+
/** The value, formatted (default: the number and the unit; `format` overrides it). */
|
|
9
|
+
valueText: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The implicit initial value for a numeric field: `initialValue` resolved, else `min` (or 0),
|
|
13
|
+
* clamped into the bounds. Only those options are resolved, not `format`, so a `format` of the
|
|
14
|
+
* field context needs no provider here.
|
|
15
|
+
*/
|
|
16
|
+
export declare function numericInitialValue(opts: NumericFieldOptions, ctx: FieldCtx, id: string): number;
|
|
17
|
+
/**
|
|
18
|
+
* A field whose value is a single number (moxb's Numeric). The shown value is always clamped
|
|
19
|
+
* into the bounds, then rounded when `integer`, since a value from outside (a stored or
|
|
20
|
+
* passed-in one) may fall outside them or be fractional even when every request this hook makes
|
|
21
|
+
* fits. A request is clamped and rounded the same way; a non-finite request (e.g. a widget
|
|
22
|
+
* parsing `''`) is refused with a warning, as a disabled field refuses any request.
|
|
23
|
+
*/
|
|
24
|
+
export declare function useNumericField<RouteId extends string = string, Ctx = any>(opts: NumericFieldOptions<RouteId, Ctx>, registry?: ErrorRoutesRegistry<RouteId>): NumericFieldControls;
|
|
25
|
+
//# sourceMappingURL=useNumericField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNumericField.d.ts","sourceRoot":"","sources":["../src/useNumericField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAyB,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,MAAM,iBAAiB,CAAC,GAAG,GAAG,GAAG,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;AAE9D,MAAM,MAAM,mBAAmB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,IACxE,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;AAEtE,MAAM,WAAW,oBAAqB,SAAQ,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe;IAC1F,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,mBAAmB,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAMhG;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,EACxE,IAAI,EAAE,mBAAmB,CAAC,OAAO,EAAE,GAAG,CAAC,EACvC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,GACtC,oBAAoB,CA6BtB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useFieldCore } from './field.js';
|
|
2
|
+
import { useFieldContext } from './FieldContext.js';
|
|
3
|
+
import { resolveIn } from './resolve.js';
|
|
4
|
+
import { clamp, resolveNumeric } from './numeric.js';
|
|
5
|
+
/**
|
|
6
|
+
* The implicit initial value for a numeric field: `initialValue` resolved, else `min` (or 0),
|
|
7
|
+
* clamped into the bounds. Only those options are resolved, not `format`, so a `format` of the
|
|
8
|
+
* field context needs no provider here.
|
|
9
|
+
*/
|
|
10
|
+
export function numericInitialValue(opts, ctx, id) {
|
|
11
|
+
const resolved = resolveIn(opts.initialValue, undefined, ctx, `Field '${id}': option 'initialValue'`);
|
|
12
|
+
if (resolved !== undefined)
|
|
13
|
+
return resolved;
|
|
14
|
+
const min = resolveIn(opts.min, undefined, ctx, `Field '${id}': option 'min'`);
|
|
15
|
+
const max = resolveIn(opts.max, undefined, ctx, `Field '${id}': option 'max'`);
|
|
16
|
+
return clamp(min ?? 0, min, max);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A field whose value is a single number (moxb's Numeric). The shown value is always clamped
|
|
20
|
+
* into the bounds, then rounded when `integer`, since a value from outside (a stored or
|
|
21
|
+
* passed-in one) may fall outside them or be fractional even when every request this hook makes
|
|
22
|
+
* fits. A request is clamped and rounded the same way; a non-finite request (e.g. a widget
|
|
23
|
+
* parsing `''`) is refused with a warning, as a disabled field refuses any request.
|
|
24
|
+
*/
|
|
25
|
+
export function useNumericField(opts, registry) {
|
|
26
|
+
const ctx = useFieldContext();
|
|
27
|
+
const resolved = resolveNumeric(opts.id, opts, ctx);
|
|
28
|
+
const inside = !opts.onChange && !opts.commit;
|
|
29
|
+
const initialValue = () => numericInitialValue(opts, ctx, opts.id);
|
|
30
|
+
const field = useFieldCore('numeric', inside ? { ...opts, initialValue } : opts, registry);
|
|
31
|
+
/** A number clamped into the bounds, then rounded when `integer`. */
|
|
32
|
+
const fit = (n) => {
|
|
33
|
+
const clamped = clamp(n, resolved.min, resolved.max);
|
|
34
|
+
return resolved.integer ? Math.round(clamped) : clamped;
|
|
35
|
+
};
|
|
36
|
+
const value = fit(field.value);
|
|
37
|
+
const setValue = (next) => {
|
|
38
|
+
if (!Number.isFinite(next)) {
|
|
39
|
+
console.warn(`Field '${opts.id}': '${next}' is not a finite number`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
field.setValue(fit(next));
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
...field,
|
|
46
|
+
...resolved,
|
|
47
|
+
value,
|
|
48
|
+
setValue,
|
|
49
|
+
valueText: resolved.format(value),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=useNumericField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNumericField.js","sourceRoot":"","sources":["../src/useNumericField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyC,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,eAAe,EAAiB,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,cAAc,EAA4C,MAAM,cAAc,CAAC;AAa/F;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAyB,EAAE,GAAa,EAAE,EAAU;IACtF,MAAM,QAAQ,GAAG,SAAS,CAAqB,IAAI,CAAC,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,0BAA0B,CAAC,CAAC;IAC1H,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAC5C,MAAM,GAAG,GAAG,SAAS,CAAqB,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC;IACnG,MAAM,GAAG,GAAG,SAAS,CAAqB,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC;IACnG,OAAO,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAuC,EACvC,QAAuC;IAEvC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC9C,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,mBAAmB,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,YAAY,CAA+B,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAEzH,qEAAqE;IACrE,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QACrD,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC1D,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE/B,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE;QAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE,OAAO,IAAI,0BAA0B,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5B,CAAC,CAAC;IAEF,OAAO;QACL,GAAG,KAAK;QACR,GAAG,QAAQ;QACX,KAAK;QACL,QAAQ;QACR,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;KAClC,CAAC;AACJ,CAAC"}
|
package/dist/useOneOfField.d.ts
CHANGED
|
@@ -1,38 +1,22 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
1
|
import { type FieldControls, type FieldOptions } from './field.js';
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
description?: string;
|
|
11
|
-
/** Shown before the label (or instead of it, for an icon-only widget), like an action's icon. */
|
|
12
|
-
icon?: ReactNode;
|
|
13
|
-
/** Choosable? Default true, optionally with a reason. Use `enabled` or `disabled`, not contradicting each other. */
|
|
14
|
-
enabled?: Decision;
|
|
15
|
-
disabled?: Decision;
|
|
16
|
-
/** Shown as the main or a dangerous choice, like an action's variant. Default 'default'. */
|
|
17
|
-
variant?: 'default' | 'primary' | 'danger';
|
|
18
|
-
/** A heading the choice is listed under, after the choices without one (OneOfSelect); default none. */
|
|
19
|
-
group?: string;
|
|
20
|
-
}
|
|
21
|
-
/** A choice as the widgets get it. */
|
|
22
|
-
export interface OneOfChoiceControls<T extends string = string> {
|
|
23
|
-
value: T;
|
|
24
|
-
label: string;
|
|
25
|
-
description: string | undefined;
|
|
26
|
-
icon: ReactNode | undefined;
|
|
27
|
-
enabled: boolean;
|
|
28
|
-
whyDisabled: string | undefined;
|
|
29
|
-
variant: 'default' | 'primary' | 'danger';
|
|
30
|
-
group: string | undefined;
|
|
31
|
-
}
|
|
32
|
-
export type OneOfFieldOptions<T extends string = string, RouteId extends string = string> = FieldOptions<T, T, RouteId> & {
|
|
33
|
-
/** The choices, in order; static or derived. */
|
|
34
|
-
choices: ValueOrFn<OneOfChoice<T>[]>;
|
|
2
|
+
import { type OneOfChoice, type OneOfChoiceControls } from './choices.js';
|
|
3
|
+
import { type FieldCtx } from './FieldContext.js';
|
|
4
|
+
import type { ErrorRoutesRegistry, ValueOrFn } from './types.js';
|
|
5
|
+
export type { OneOfChoice, OneOfChoiceControls };
|
|
6
|
+
export type OneOfOwnOptions<T extends string = string, Ctx = any> = {
|
|
7
|
+
/** The choices, in order; static or derived (a function, of the field context if it declares a parameter). */
|
|
8
|
+
choices: ValueOrFn<OneOfChoice<T>[], Ctx>;
|
|
35
9
|
};
|
|
10
|
+
export type OneOfFieldOptions<T extends string = string, RouteId extends string = string, Ctx = any> = FieldOptions<T, T, RouteId, Ctx> & OneOfOwnOptions<T, Ctx>;
|
|
11
|
+
/**
|
|
12
|
+
* The implicit initial value for a one-of field: `initialValue` resolved through the field
|
|
13
|
+
* context, else the first enabled choice. Resolving first (rather than `opts.initialValue ??
|
|
14
|
+
* ...`) matters when `initialValue` is a context function that returns undefined: `??` would
|
|
15
|
+
* see the function, not its result, and never fall back.
|
|
16
|
+
*/
|
|
17
|
+
export declare function oneOfInitialValue<T extends string>(opts: {
|
|
18
|
+
initialValue?: ValueOrFn<T>;
|
|
19
|
+
}, ctx: FieldCtx, id: string, choices: OneOfChoiceControls<T>[]): T | undefined;
|
|
36
20
|
export interface OneOfFieldControls<T extends string = string> extends FieldControls<T, T> {
|
|
37
21
|
choices: OneOfChoiceControls<T>[];
|
|
38
22
|
/** The choice the value is, if it is one of them. */
|
|
@@ -47,5 +31,5 @@ export interface OneOfFieldControls<T extends string = string> extends FieldCont
|
|
|
47
31
|
* warning, as a disabled field ignores any request. Inside the field the value
|
|
48
32
|
* starts at `initialValue`, else at the first enabled choice.
|
|
49
33
|
*/
|
|
50
|
-
export declare function useOneOfField<T extends string = string, RouteId extends string = string>(opts: OneOfFieldOptions<T, RouteId>, registry?: ErrorRoutesRegistry<RouteId>): OneOfFieldControls<T>;
|
|
34
|
+
export declare function useOneOfField<T extends string = string, RouteId extends string = string, Ctx = any>(opts: OneOfFieldOptions<T, RouteId, Ctx>, registry?: ErrorRoutesRegistry<RouteId>): OneOfFieldControls<T>;
|
|
51
35
|
//# sourceMappingURL=useOneOfField.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOneOfField.d.ts","sourceRoot":"","sources":["../src/useOneOfField.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"useOneOfField.d.ts","sourceRoot":"","sources":["../src/useOneOfField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAiB,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACzF,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIjE,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC;AAEjD,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,IAAI;IAClE,8GAA8G;IAC9G,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,IACjG,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAE7D;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAChD,IAAI,EAAE;IAAE,YAAY,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;CAAE,EACrC,GAAG,EAAE,QAAQ,EACb,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAAE,GAChC,CAAC,GAAG,SAAS,CAGf;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC;IACxF,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;IAClC,qDAAqD;IACrD,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;CAC7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,EACjG,IAAI,EAAE,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,EACxC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,GACtC,kBAAkB,CAAC,CAAC,CAAC,CA8BvB"}
|
package/dist/useOneOfField.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
variant: choice.variant ?? 'default',
|
|
15
|
-
group: choice.group,
|
|
16
|
-
};
|
|
1
|
+
import { useFieldCore } from './field.js';
|
|
2
|
+
import { resolveChoice } from './choices.js';
|
|
3
|
+
import { useFieldContext } from './FieldContext.js';
|
|
4
|
+
import { resolveIn } from './resolve.js';
|
|
5
|
+
/**
|
|
6
|
+
* The implicit initial value for a one-of field: `initialValue` resolved through the field
|
|
7
|
+
* context, else the first enabled choice. Resolving first (rather than `opts.initialValue ??
|
|
8
|
+
* ...`) matters when `initialValue` is a context function that returns undefined: `??` would
|
|
9
|
+
* see the function, not its result, and never fall back.
|
|
10
|
+
*/
|
|
11
|
+
export function oneOfInitialValue(opts, ctx, id, choices) {
|
|
12
|
+
const resolved = resolveIn(opts.initialValue, undefined, ctx, `Field '${id}': option 'initialValue'`);
|
|
13
|
+
return resolved ?? choices.find((c) => c.enabled)?.value;
|
|
17
14
|
}
|
|
18
15
|
/**
|
|
19
16
|
* A field whose value is one of a list of choices (moxb's OneOf). Rendered by
|
|
@@ -25,9 +22,12 @@ function resolveChoice(fieldId, choice) {
|
|
|
25
22
|
* starts at `initialValue`, else at the first enabled choice.
|
|
26
23
|
*/
|
|
27
24
|
export function useOneOfField(opts, registry) {
|
|
28
|
-
const
|
|
25
|
+
const ctx = useFieldContext();
|
|
26
|
+
const choices = resolveIn(opts.choices, [], ctx, `Field '${opts.id}': option 'choices'`)
|
|
27
|
+
.map((c) => resolveChoice(opts.id, c));
|
|
29
28
|
const inside = !opts.onChange && !opts.commit;
|
|
30
|
-
|
|
29
|
+
// Undefined when no choice is enabled, and then so is the value.
|
|
30
|
+
const initialValue = () => oneOfInitialValue(opts, ctx, opts.id, choices);
|
|
31
31
|
const field = useFieldCore('oneOf', inside ? { ...opts, initialValue } : opts, registry);
|
|
32
32
|
const current = choices.find((c) => c.value === field.value);
|
|
33
33
|
const setValue = (next) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOneOfField.js","sourceRoot":"","sources":["../src/useOneOfField.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useOneOfField.js","sourceRoot":"","sources":["../src/useOneOfField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyC,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,aAAa,EAA8C,MAAM,cAAc,CAAC;AACzF,OAAO,EAAE,eAAe,EAAiB,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAezC;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAqC,EACrC,GAAa,EACb,EAAU,EACV,OAAiC;IAEjC,MAAM,QAAQ,GAAG,SAAS,CAAgB,IAAI,CAAC,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,0BAA0B,CAAC,CAAC;IACrH,OAAO,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC;AAC3D,CAAC;AAQD;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAwC,EACxC,QAAuC;IAEvC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,SAAS,CAAmB,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,UAAU,IAAI,CAAC,EAAE,qBAAqB,CAAC;SACvG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC9C,iEAAiE;IACjE,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,CAAM,CAAC;IAC/E,MAAM,KAAK,GAAG,YAAY,CAAqB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7G,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7D,MAAM,QAAQ,GAAG,CAAC,IAAO,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE,OAAO,IAAI,6BAA6B,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE,cAAc,IAAI,mBAAmB,MAAM,CAAC,WAAW,IAAI,aAAa,EAAE,CAAC,CAAC;YAC1G,OAAO;QACT,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC,CAAC;IAEF,OAAO;QACL,GAAG,KAAK;QACR,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,IAAI,OAAO,EAAE,WAAW;QAChE,QAAQ;QACR,OAAO;QACP,OAAO;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type FieldControls, type FieldOptions } from './field.js';
|
|
2
|
+
import { type FieldCtx } from './FieldContext.js';
|
|
3
|
+
import { type NumericBounds, type ResolvedNumeric } from './numeric.js';
|
|
4
|
+
import type { ErrorRoutesRegistry, ValueOrFn } from './types.js';
|
|
5
|
+
/** A `[from, to]` pair, `from <= to`. Not named `Range`, which would shadow the DOM's global type. */
|
|
6
|
+
export type NumberRange = [number, number];
|
|
7
|
+
export type RangeOwnOptions<Ctx = any> = NumericBounds<Ctx> & {
|
|
8
|
+
min: ValueOrFn<number, Ctx>;
|
|
9
|
+
max: ValueOrFn<number, Ctx>;
|
|
10
|
+
};
|
|
11
|
+
export type RangeFieldOptions<RouteId extends string = string, Ctx = any> = FieldOptions<NumberRange, NumberRange, RouteId, Ctx> & RangeOwnOptions<Ctx>;
|
|
12
|
+
export interface RangeFieldControls extends FieldControls<NumberRange, NumberRange>, ResolvedNumeric {
|
|
13
|
+
min: number;
|
|
14
|
+
max: number;
|
|
15
|
+
/** The value, formatted (default: each end's number, joined by an en dash). */
|
|
16
|
+
valueText: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The implicit initial value for a range field: `initialValue` resolved, else `[min, max]`. Only
|
|
20
|
+
* those options are resolved, not `format`, so a `format` of the field context needs no
|
|
21
|
+
* provider here.
|
|
22
|
+
*/
|
|
23
|
+
export declare function rangeInitialValue(opts: RangeFieldOptions, ctx: FieldCtx, id: string): NumberRange;
|
|
24
|
+
/**
|
|
25
|
+
* A field whose value is a `[from, to]` number range (Praeceptor's school-years filter),
|
|
26
|
+
* reusing numeric's bounds and formatting; `min` and `max` are required here, and `step`
|
|
27
|
+
* defaults to 1. The shown value is each end clamped into the bounds and rounded when
|
|
28
|
+
* `integer`, then ordered, since a value from outside (a stored or passed-in one) may fall
|
|
29
|
+
* outside them, be fractional or be out of order even when every request this hook makes fits.
|
|
30
|
+
* A request is clamped, rounded and ordered the same way; a non-finite end refuses the request
|
|
31
|
+
* with a warning, as a disabled field refuses any request.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useRangeField<RouteId extends string = string, Ctx = any>(opts: RangeFieldOptions<RouteId, Ctx>, registry?: ErrorRoutesRegistry<RouteId>): RangeFieldControls;
|
|
34
|
+
//# sourceMappingURL=useRangeField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRangeField.d.ts","sourceRoot":"","sources":["../src/useRangeField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,EAAyB,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/F,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjE,sGAAsG;AACtG,MAAM,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE3C,MAAM,MAAM,eAAe,CAAC,GAAG,GAAG,GAAG,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG;IAAE,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAAC,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC;AAE3H,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,IACtE,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;AAE9E,MAAM,WAAW,kBAAmB,SAAQ,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,eAAe;IAClG,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CAMjG;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,EACtE,IAAI,EAAE,iBAAiB,CAAC,OAAO,EAAE,GAAG,CAAC,EACrC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,GACtC,kBAAkB,CAmCpB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useFieldCore } from './field.js';
|
|
2
|
+
import { useFieldContext } from './FieldContext.js';
|
|
3
|
+
import { resolveIn } from './resolve.js';
|
|
4
|
+
import { clamp, resolveNumeric } from './numeric.js';
|
|
5
|
+
function order([from, to]) {
|
|
6
|
+
return from <= to ? [from, to] : [to, from];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The implicit initial value for a range field: `initialValue` resolved, else `[min, max]`. Only
|
|
10
|
+
* those options are resolved, not `format`, so a `format` of the field context needs no
|
|
11
|
+
* provider here.
|
|
12
|
+
*/
|
|
13
|
+
export function rangeInitialValue(opts, ctx, id) {
|
|
14
|
+
const resolved = resolveIn(opts.initialValue, undefined, ctx, `Field '${id}': option 'initialValue'`);
|
|
15
|
+
if (resolved !== undefined)
|
|
16
|
+
return resolved;
|
|
17
|
+
const min = resolveIn(opts.min, undefined, ctx, `Field '${id}': option 'min'`);
|
|
18
|
+
const max = resolveIn(opts.max, undefined, ctx, `Field '${id}': option 'max'`);
|
|
19
|
+
return [min, max];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A field whose value is a `[from, to]` number range (Praeceptor's school-years filter),
|
|
23
|
+
* reusing numeric's bounds and formatting; `min` and `max` are required here, and `step`
|
|
24
|
+
* defaults to 1. The shown value is each end clamped into the bounds and rounded when
|
|
25
|
+
* `integer`, then ordered, since a value from outside (a stored or passed-in one) may fall
|
|
26
|
+
* outside them, be fractional or be out of order even when every request this hook makes fits.
|
|
27
|
+
* A request is clamped, rounded and ordered the same way; a non-finite end refuses the request
|
|
28
|
+
* with a warning, as a disabled field refuses any request.
|
|
29
|
+
*/
|
|
30
|
+
export function useRangeField(opts, registry) {
|
|
31
|
+
const ctx = useFieldContext();
|
|
32
|
+
const resolved = resolveNumeric(opts.id, opts, ctx);
|
|
33
|
+
const min = resolved.min;
|
|
34
|
+
const max = resolved.max;
|
|
35
|
+
const step = resolved.step ?? 1;
|
|
36
|
+
const inside = !opts.onChange && !opts.commit;
|
|
37
|
+
const initialValue = () => rangeInitialValue(opts, ctx, opts.id);
|
|
38
|
+
const field = useFieldCore('range', inside ? { ...opts, initialValue } : opts, registry);
|
|
39
|
+
/** An end clamped into the bounds, then rounded when `integer`. */
|
|
40
|
+
const fit = (n) => {
|
|
41
|
+
const clamped = clamp(n, min, max);
|
|
42
|
+
return resolved.integer ? Math.round(clamped) : clamped;
|
|
43
|
+
};
|
|
44
|
+
const value = order([fit(field.value[0]), fit(field.value[1])]);
|
|
45
|
+
const setValue = (next) => {
|
|
46
|
+
if (!Number.isFinite(next[0]) || !Number.isFinite(next[1])) {
|
|
47
|
+
console.warn(`Field '${opts.id}': '${next}' is not a finite number range`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
field.setValue(order([fit(next[0]), fit(next[1])]));
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
...field,
|
|
54
|
+
...resolved,
|
|
55
|
+
min,
|
|
56
|
+
max,
|
|
57
|
+
step,
|
|
58
|
+
value,
|
|
59
|
+
setValue,
|
|
60
|
+
valueText: `${resolved.format(value[0])}–${resolved.format(value[1])}`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=useRangeField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRangeField.js","sourceRoot":"","sources":["../src/useRangeField.ts"],"names":[],"mappings":"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"}
|