@sectile/core 0.2.0 → 0.2.1
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/accordion.d.ts +44 -0
- package/dist/accordion.d.ts.map +1 -0
- package/dist/accordion.js +87 -0
- package/dist/accordion.js.map +1 -0
- package/dist/alert-dialog.d.ts +19 -0
- package/dist/alert-dialog.d.ts.map +1 -0
- package/dist/alert-dialog.js +10 -0
- package/dist/alert-dialog.js.map +1 -0
- package/dist/calendar.d.ts +3 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +3 -0
- package/dist/calendar.js.map +1 -0
- package/dist/carousel.d.ts +41 -0
- package/dist/carousel.d.ts.map +1 -0
- package/dist/carousel.js +55 -0
- package/dist/carousel.js.map +1 -0
- package/dist/cascade-select.d.ts +48 -0
- package/dist/cascade-select.d.ts.map +1 -0
- package/dist/cascade-select.js +148 -0
- package/dist/cascade-select.js.map +1 -0
- package/dist/checkbox-group.d.ts +13 -0
- package/dist/checkbox-group.d.ts.map +1 -0
- package/dist/checkbox-group.js +16 -0
- package/dist/checkbox-group.js.map +1 -0
- package/dist/checkbox.d.ts +3 -0
- package/dist/checkbox.d.ts.map +1 -0
- package/dist/checkbox.js +3 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/collection-window.d.ts +51 -0
- package/dist/collection-window.d.ts.map +1 -0
- package/dist/collection-window.js +111 -0
- package/dist/collection-window.js.map +1 -0
- package/dist/color-picker.d.ts +101 -0
- package/dist/color-picker.d.ts.map +1 -0
- package/dist/color-picker.js +503 -0
- package/dist/color-picker.js.map +1 -0
- package/dist/combobox.d.ts +17 -0
- package/dist/combobox.d.ts.map +1 -0
- package/dist/combobox.js +46 -0
- package/dist/combobox.js.map +1 -0
- package/dist/date-field.d.ts +62 -0
- package/dist/date-field.d.ts.map +1 -0
- package/dist/date-field.js +245 -0
- package/dist/date-field.js.map +1 -0
- package/dist/date-picker.d.ts +76 -0
- package/dist/date-picker.d.ts.map +1 -0
- package/dist/date-picker.js +261 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/date-range-field.d.ts +47 -0
- package/dist/date-range-field.d.ts.map +1 -0
- package/dist/date-range-field.js +66 -0
- package/dist/date-range-field.js.map +1 -0
- package/dist/date-range-picker.d.ts +29 -0
- package/dist/date-range-picker.d.ts.map +1 -0
- package/dist/date-range-picker.js +89 -0
- package/dist/date-range-picker.js.map +1 -0
- package/dist/date-time-field.d.ts +57 -0
- package/dist/date-time-field.d.ts.map +1 -0
- package/dist/date-time-field.js +267 -0
- package/dist/date-time-field.js.map +1 -0
- package/dist/date-time-picker.d.ts +71 -0
- package/dist/date-time-picker.d.ts.map +1 -0
- package/dist/date-time-picker.js +156 -0
- package/dist/date-time-picker.js.map +1 -0
- package/dist/date-time-range-picker.d.ts +87 -0
- package/dist/date-time-range-picker.d.ts.map +1 -0
- package/dist/date-time-range-picker.js +252 -0
- package/dist/date-time-range-picker.js.map +1 -0
- package/dist/dialog.d.ts +17 -0
- package/dist/dialog.d.ts.map +1 -0
- package/dist/dialog.js +6 -0
- package/dist/dialog.js.map +1 -0
- package/dist/disclosure.d.ts +3 -0
- package/dist/disclosure.d.ts.map +1 -0
- package/dist/disclosure.js +3 -0
- package/dist/disclosure.js.map +1 -0
- package/dist/editable.d.ts +29 -0
- package/dist/editable.d.ts.map +1 -0
- package/dist/editable.js +34 -0
- package/dist/editable.js.map +1 -0
- package/dist/feed.d.ts +49 -0
- package/dist/feed.d.ts.map +1 -0
- package/dist/feed.js +124 -0
- package/dist/feed.js.map +1 -0
- package/dist/form.d.ts +135 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +627 -0
- package/dist/form.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction.d.ts +15 -0
- package/dist/interaction.d.ts.map +1 -0
- package/dist/interaction.js +42 -0
- package/dist/interaction.js.map +1 -0
- package/dist/internal/composites/calendar.d.ts +36 -0
- package/dist/internal/composites/calendar.d.ts.map +1 -0
- package/dist/internal/composites/calendar.js +143 -0
- package/dist/internal/composites/calendar.js.map +1 -0
- package/dist/internal/composites/combobox.d.ts +42 -0
- package/dist/internal/composites/combobox.d.ts.map +1 -0
- package/dist/internal/composites/combobox.js +188 -0
- package/dist/internal/composites/combobox.js.map +1 -0
- package/dist/internal/composites/grid-control.d.ts +37 -0
- package/dist/internal/composites/grid-control.d.ts.map +1 -0
- package/dist/internal/composites/grid-control.js +90 -0
- package/dist/internal/composites/grid-control.js.map +1 -0
- package/dist/internal/composites/linear-action.d.ts +36 -0
- package/dist/internal/composites/linear-action.d.ts.map +1 -0
- package/dist/internal/composites/linear-action.js +96 -0
- package/dist/internal/composites/linear-action.js.map +1 -0
- package/dist/internal/composites/linear-choice.d.ts +41 -0
- package/dist/internal/composites/linear-choice.d.ts.map +1 -0
- package/dist/internal/composites/linear-choice.js +139 -0
- package/dist/internal/composites/linear-choice.js.map +1 -0
- package/dist/internal/composites/listbox.d.ts +52 -0
- package/dist/internal/composites/listbox.d.ts.map +1 -0
- package/dist/internal/composites/listbox.js +251 -0
- package/dist/internal/composites/listbox.js.map +1 -0
- package/dist/internal/composites/menu.d.ts +29 -0
- package/dist/internal/composites/menu.d.ts.map +1 -0
- package/dist/internal/composites/menu.js +76 -0
- package/dist/internal/composites/menu.js.map +1 -0
- package/dist/internal/composites/popup.d.ts +21 -0
- package/dist/internal/composites/popup.d.ts.map +1 -0
- package/dist/internal/composites/popup.js +10 -0
- package/dist/internal/composites/popup.js.map +1 -0
- package/dist/internal/composites/slider.d.ts +21 -0
- package/dist/internal/composites/slider.d.ts.map +1 -0
- package/dist/internal/composites/slider.js +73 -0
- package/dist/internal/composites/slider.js.map +1 -0
- package/dist/internal/composites/tree-grid.d.ts +67 -0
- package/dist/internal/composites/tree-grid.d.ts.map +1 -0
- package/dist/internal/composites/tree-grid.js +281 -0
- package/dist/internal/composites/tree-grid.js.map +1 -0
- package/dist/internal/composites/tree-view.d.ts +42 -0
- package/dist/internal/composites/tree-view.d.ts.map +1 -0
- package/dist/internal/composites/tree-view.js +196 -0
- package/dist/internal/composites/tree-view.js.map +1 -0
- package/dist/internal/editing/text.d.ts +66 -0
- package/dist/internal/editing/text.d.ts.map +1 -0
- package/dist/internal/editing/text.js +248 -0
- package/dist/internal/editing/text.js.map +1 -0
- package/dist/internal/kernel/decimal.d.ts +22 -0
- package/dist/internal/kernel/decimal.d.ts.map +1 -0
- package/dist/internal/kernel/decimal.js +137 -0
- package/dist/internal/kernel/decimal.js.map +1 -0
- package/dist/internal/kernel/foundation.d.ts +12 -0
- package/dist/internal/kernel/foundation.d.ts.map +1 -0
- package/dist/internal/kernel/foundation.js +132 -0
- package/dist/internal/kernel/foundation.js.map +1 -0
- package/dist/internal/kernel/indexed-sequence.d.ts +26 -0
- package/dist/internal/kernel/indexed-sequence.d.ts.map +1 -0
- package/dist/internal/kernel/indexed-sequence.js +117 -0
- package/dist/internal/kernel/indexed-sequence.js.map +1 -0
- package/dist/internal/kernel/machine.d.ts +8 -0
- package/dist/internal/kernel/machine.d.ts.map +1 -0
- package/dist/internal/kernel/machine.js +6 -0
- package/dist/internal/kernel/machine.js.map +1 -0
- package/dist/internal/runtime/revision.d.ts +23 -0
- package/dist/internal/runtime/revision.d.ts.map +1 -0
- package/dist/internal/runtime/revision.js +76 -0
- package/dist/internal/runtime/revision.js.map +1 -0
- package/dist/internal/state/checked.d.ts +22 -0
- package/dist/internal/state/checked.d.ts.map +1 -0
- package/dist/internal/state/checked.js +33 -0
- package/dist/internal/state/checked.js.map +1 -0
- package/dist/internal/state/cursor.d.ts +13 -0
- package/dist/internal/state/cursor.d.ts.map +1 -0
- package/dist/internal/state/cursor.js +24 -0
- package/dist/internal/state/cursor.js.map +1 -0
- package/dist/internal/state/expansion.d.ts +8 -0
- package/dist/internal/state/expansion.d.ts.map +1 -0
- package/dist/internal/state/expansion.js +23 -0
- package/dist/internal/state/expansion.js.map +1 -0
- package/dist/internal/state/open-state.d.ts +17 -0
- package/dist/internal/state/open-state.d.ts.map +1 -0
- package/dist/internal/state/open-state.js +29 -0
- package/dist/internal/state/open-state.js.map +1 -0
- package/dist/internal/state/selection.d.ts +23 -0
- package/dist/internal/state/selection.d.ts.map +1 -0
- package/dist/internal/state/selection.js +110 -0
- package/dist/internal/state/selection.js.map +1 -0
- package/dist/layer-stack.d.ts +47 -0
- package/dist/layer-stack.d.ts.map +1 -0
- package/dist/layer-stack.js +115 -0
- package/dist/layer-stack.js.map +1 -0
- package/dist/listbox.d.ts +3 -0
- package/dist/listbox.d.ts.map +1 -0
- package/dist/listbox.js +3 -0
- package/dist/listbox.js.map +1 -0
- package/dist/menu-button.d.ts +5 -0
- package/dist/menu-button.d.ts.map +1 -0
- package/dist/menu-button.js +5 -0
- package/dist/menu-button.js.map +1 -0
- package/dist/menu.d.ts +10 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +9 -0
- package/dist/menu.js.map +1 -0
- package/dist/menubar.d.ts +5 -0
- package/dist/menubar.d.ts.map +1 -0
- package/dist/menubar.js +5 -0
- package/dist/menubar.js.map +1 -0
- package/dist/month-picker.d.ts +5 -0
- package/dist/month-picker.d.ts.map +1 -0
- package/dist/month-picker.js +4 -0
- package/dist/month-picker.js.map +1 -0
- package/dist/month-range-picker.d.ts +6 -0
- package/dist/month-range-picker.d.ts.map +1 -0
- package/dist/month-range-picker.js +5 -0
- package/dist/month-range-picker.js.map +1 -0
- package/dist/multi-thumb-slider.d.ts +36 -0
- package/dist/multi-thumb-slider.d.ts.map +1 -0
- package/dist/multi-thumb-slider.js +72 -0
- package/dist/multi-thumb-slider.js.map +1 -0
- package/dist/navigation-menu.d.ts +6 -0
- package/dist/navigation-menu.d.ts.map +1 -0
- package/dist/navigation-menu.js +5 -0
- package/dist/navigation-menu.js.map +1 -0
- package/dist/number-field.d.ts +51 -0
- package/dist/number-field.d.ts.map +1 -0
- package/dist/number-field.js +461 -0
- package/dist/number-field.js.map +1 -0
- package/dist/pagination.d.ts +65 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +197 -0
- package/dist/pagination.js.map +1 -0
- package/dist/pin-input.d.ts +31 -0
- package/dist/pin-input.d.ts.map +1 -0
- package/dist/pin-input.js +53 -0
- package/dist/pin-input.js.map +1 -0
- package/dist/popover.d.ts +17 -0
- package/dist/popover.d.ts.map +1 -0
- package/dist/popover.js +6 -0
- package/dist/popover.js.map +1 -0
- package/dist/quantity-field.d.ts +59 -0
- package/dist/quantity-field.d.ts.map +1 -0
- package/dist/quantity-field.js +254 -0
- package/dist/quantity-field.js.map +1 -0
- package/dist/radio-group.d.ts +23 -0
- package/dist/radio-group.d.ts.map +1 -0
- package/dist/radio-group.js +20 -0
- package/dist/radio-group.js.map +1 -0
- package/dist/range-calendar.d.ts +6 -0
- package/dist/range-calendar.d.ts.map +1 -0
- package/dist/range-calendar.js +5 -0
- package/dist/range-calendar.js.map +1 -0
- package/dist/rating.d.ts +18 -0
- package/dist/rating.d.ts.map +1 -0
- package/dist/rating.js +19 -0
- package/dist/rating.js.map +1 -0
- package/dist/reorder.d.ts +47 -0
- package/dist/reorder.d.ts.map +1 -0
- package/dist/reorder.js +110 -0
- package/dist/reorder.js.map +1 -0
- package/dist/result.d.ts +10 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +19 -0
- package/dist/result.js.map +1 -0
- package/dist/revision.d.ts +3 -0
- package/dist/revision.d.ts.map +1 -0
- package/dist/revision.js +3 -0
- package/dist/revision.js.map +1 -0
- package/dist/select.d.ts +31 -0
- package/dist/select.d.ts.map +1 -0
- package/dist/select.js +32 -0
- package/dist/select.js.map +1 -0
- package/dist/shared.d.ts +43 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +3 -0
- package/dist/shared.js.map +1 -0
- package/dist/slider.d.ts +3 -0
- package/dist/slider.d.ts.map +1 -0
- package/dist/slider.js +3 -0
- package/dist/slider.js.map +1 -0
- package/dist/spin-button.d.ts +31 -0
- package/dist/spin-button.d.ts.map +1 -0
- package/dist/spin-button.js +65 -0
- package/dist/spin-button.js.map +1 -0
- package/dist/stepper.d.ts +18 -0
- package/dist/stepper.d.ts.map +1 -0
- package/dist/stepper.js +16 -0
- package/dist/stepper.js.map +1 -0
- package/dist/structures/grid.d.ts +29 -0
- package/dist/structures/grid.d.ts.map +1 -0
- package/dist/structures/grid.js +202 -0
- package/dist/structures/grid.js.map +1 -0
- package/dist/structures/range.d.ts +41 -0
- package/dist/structures/range.d.ts.map +1 -0
- package/dist/structures/range.js +249 -0
- package/dist/structures/range.js.map +1 -0
- package/dist/structures/sequence.d.ts +19 -0
- package/dist/structures/sequence.d.ts.map +1 -0
- package/dist/structures/sequence.js +28 -0
- package/dist/structures/sequence.js.map +1 -0
- package/dist/structures/tree.d.ts +33 -0
- package/dist/structures/tree.d.ts.map +1 -0
- package/dist/structures/tree.js +238 -0
- package/dist/structures/tree.js.map +1 -0
- package/dist/switch.d.ts +21 -0
- package/dist/switch.d.ts.map +1 -0
- package/dist/switch.js +8 -0
- package/dist/switch.js.map +1 -0
- package/dist/tabs.d.ts +16 -0
- package/dist/tabs.d.ts.map +1 -0
- package/dist/tabs.js +27 -0
- package/dist/tabs.js.map +1 -0
- package/dist/tags-input.d.ts +43 -0
- package/dist/tags-input.d.ts.map +1 -0
- package/dist/tags-input.js +48 -0
- package/dist/tags-input.js.map +1 -0
- package/dist/text.d.ts +4 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +4 -0
- package/dist/text.js.map +1 -0
- package/dist/time-field.d.ts +48 -0
- package/dist/time-field.d.ts.map +1 -0
- package/dist/time-field.js +157 -0
- package/dist/time-field.js.map +1 -0
- package/dist/time-range-field.d.ts +53 -0
- package/dist/time-range-field.d.ts.map +1 -0
- package/dist/time-range-field.js +75 -0
- package/dist/time-range-field.js.map +1 -0
- package/dist/timer.d.ts +37 -0
- package/dist/timer.d.ts.map +1 -0
- package/dist/timer.js +84 -0
- package/dist/timer.js.map +1 -0
- package/dist/toast.d.ts +56 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +87 -0
- package/dist/toast.js.map +1 -0
- package/dist/toggle-button.d.ts +20 -0
- package/dist/toggle-button.d.ts.map +1 -0
- package/dist/toggle-button.js +20 -0
- package/dist/toggle-button.js.map +1 -0
- package/dist/toggle-group.d.ts +25 -0
- package/dist/toggle-group.d.ts.map +1 -0
- package/dist/toggle-group.js +30 -0
- package/dist/toggle-group.js.map +1 -0
- package/dist/toolbar.d.ts +3 -0
- package/dist/toolbar.d.ts.map +1 -0
- package/dist/toolbar.js +3 -0
- package/dist/toolbar.js.map +1 -0
- package/dist/tooltip.d.ts +3 -0
- package/dist/tooltip.d.ts.map +1 -0
- package/dist/tooltip.js +3 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/tree-grid.d.ts +13 -0
- package/dist/tree-grid.d.ts.map +1 -0
- package/dist/tree-grid.js +20 -0
- package/dist/tree-grid.js.map +1 -0
- package/dist/tree-view.d.ts +3 -0
- package/dist/tree-view.d.ts.map +1 -0
- package/dist/tree-view.js +3 -0
- package/dist/tree-view.js.map +1 -0
- package/dist/units.d.ts +77 -0
- package/dist/units.d.ts.map +1 -0
- package/dist/units.js +512 -0
- package/dist/units.js.map +1 -0
- package/dist/window-splitter.d.ts +3 -0
- package/dist/window-splitter.d.ts.map +1 -0
- package/dist/window-splitter.js +3 -0
- package/dist/window-splitter.js.map +1 -0
- package/dist/year-picker.d.ts +10 -0
- package/dist/year-picker.d.ts.map +1 -0
- package/dist/year-picker.js +27 -0
- package/dist/year-picker.js.map +1 -0
- package/dist/year-range-picker.d.ts +6 -0
- package/dist/year-range-picker.d.ts.map +1 -0
- package/dist/year-range-picker.js +5 -0
- package/dist/year-range-picker.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { unwrap } from './result.js';
|
|
2
|
+
import { fail, ok } from './internal/kernel/foundation.js';
|
|
3
|
+
import { createMachineUpdate } from './internal/kernel/machine.js';
|
|
4
|
+
import { createCursorState } from './internal/state/cursor.js';
|
|
5
|
+
export function createMultiThumbSliderState(thumbs, range, ticks, current = null, policies = {}) {
|
|
6
|
+
return unwrap(tryCreateMultiThumbSliderState(thumbs, range, ticks, current, policies));
|
|
7
|
+
}
|
|
8
|
+
export function tryCreateMultiThumbSliderState(thumbs, range, ticks, current = null, policies = {}) {
|
|
9
|
+
if (ticks.length !== thumbs.size)
|
|
10
|
+
return fail('construction', 'thumb-value-count-mismatch', 'Every thumb requires one tick.');
|
|
11
|
+
if (current !== null && !thumbs.contains(current))
|
|
12
|
+
return fail('construction', 'multi-thumb-cursor-outside-domain', 'Active thumb must exist.');
|
|
13
|
+
const gap = policies.minGap ?? 0;
|
|
14
|
+
if (!Number.isSafeInteger(gap) || gap < 0)
|
|
15
|
+
return fail('construction', 'invalid-thumb-gap', 'minGap must be a non-negative safe integer.');
|
|
16
|
+
for (let index = 0; index < ticks.length; index += 1) {
|
|
17
|
+
const tick = ticks[index];
|
|
18
|
+
if (tick === undefined || !Number.isSafeInteger(tick) || tick < 0 || tick > range.count)
|
|
19
|
+
return fail('construction', 'thumb-tick-outside-range', 'Every thumb tick must be inside the range.');
|
|
20
|
+
if (!policies.allowCross && index > 0 && ticks[index - 1] + gap > tick)
|
|
21
|
+
return fail('construction', 'thumb-order-violation', 'Thumb ticks must preserve order and minimum gap.');
|
|
22
|
+
}
|
|
23
|
+
return ok(Object.freeze({ cursor: createCursorState(current), ticks: Object.freeze([...ticks]) }));
|
|
24
|
+
}
|
|
25
|
+
export function applyMultiThumbSliderEvent(thumbs, range, state, event, policies = {}) {
|
|
26
|
+
const valid = tryCreateMultiThumbSliderState(thumbs, range, state.ticks, state.cursor.current, policies);
|
|
27
|
+
if (!valid.ok)
|
|
28
|
+
return { ok: false, error: { ...valid.error, class: 'transition-rejection' } };
|
|
29
|
+
if (event === 'next-thumb' || event === 'previous-thumb') {
|
|
30
|
+
if (thumbs.size === 0)
|
|
31
|
+
return createMachineUpdate(state);
|
|
32
|
+
const current = state.cursor.current;
|
|
33
|
+
let id;
|
|
34
|
+
if (current === null)
|
|
35
|
+
id = thumbs.at(event === 'next-thumb' ? 0 : thumbs.size - 1);
|
|
36
|
+
else {
|
|
37
|
+
const target = thumbs.move(current, event === 'next-thumb' ? 1 : -1, 'wrap');
|
|
38
|
+
id = target.kind === 'found' ? target.id : null;
|
|
39
|
+
}
|
|
40
|
+
if (id === null)
|
|
41
|
+
return createMachineUpdate(state);
|
|
42
|
+
return createMachineUpdate(Object.freeze({ cursor: createCursorState(id), ticks: state.ticks }), [{ type: 'focus', id }]);
|
|
43
|
+
}
|
|
44
|
+
const id = typeof event === 'object' ? event.id : state.cursor.current;
|
|
45
|
+
if (id === null)
|
|
46
|
+
return fail('transition-rejection', 'no-cursor', 'Multi-thumb change requires an active thumb.');
|
|
47
|
+
const index = thumbs.indexOf(id);
|
|
48
|
+
if (index === null)
|
|
49
|
+
return fail('transition-rejection', 'multi-thumb-target-unavailable', 'Thumb target must exist.');
|
|
50
|
+
if (typeof event === 'object' && event.type === 'focus')
|
|
51
|
+
return createMachineUpdate(Object.freeze({ cursor: createCursorState(id), ticks: state.ticks }), [{ type: 'focus', id }]);
|
|
52
|
+
const current = state.ticks[index];
|
|
53
|
+
let tick = typeof event === 'object' ? event.tick : event === 'increment' ? current + 1 : event === 'decrement' ? current - 1 : event === 'home' ? 0 : range.count;
|
|
54
|
+
tick = Math.max(0, Math.min(range.count, tick));
|
|
55
|
+
if (!policies.allowCross) {
|
|
56
|
+
const gap = policies.minGap ?? 0;
|
|
57
|
+
const lower = index === 0 ? 0 : state.ticks[index - 1] + gap;
|
|
58
|
+
const upper = index === state.ticks.length - 1 ? range.count : state.ticks[index + 1] - gap;
|
|
59
|
+
tick = Math.max(lower, Math.min(upper, tick));
|
|
60
|
+
}
|
|
61
|
+
if (!Number.isSafeInteger(tick))
|
|
62
|
+
return fail('transition-rejection', 'thumb-tick-outside-range', 'Thumb tick must be a safe range tick.');
|
|
63
|
+
const ticks = [...state.ticks];
|
|
64
|
+
ticks[index] = tick;
|
|
65
|
+
const commands = [];
|
|
66
|
+
if (state.cursor.current !== id)
|
|
67
|
+
commands.push({ type: 'focus', id });
|
|
68
|
+
if (current !== tick)
|
|
69
|
+
commands.push({ type: 'announce-tick', id, tick });
|
|
70
|
+
return createMachineUpdate(Object.freeze({ cursor: createCursorState(id), ticks: Object.freeze(ticks) }), commands);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=multi-thumb-slider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-thumb-slider.js","sourceRoot":"","sources":["../src/multi-thumb-slider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { applyMenuEvent as applyNavigationMenuEvent, createMenuState as createNavigationMenuState, type MenuCommand as NavigationMenuCommand, type MenuEvent as NavigationMenuEvent, type MenuPolicies as NavigationMenuPolicies, type MenuState as NavigationMenuState, type MenuUpdate as NavigationMenuUpdate, } from './internal/composites/menu.js';
|
|
2
|
+
export { createMenuModel as createNavigationMenuModel, type MenuModel as NavigationMenuModel, } from './menu.js';
|
|
3
|
+
export type { TreeNodeInput as NavigationMenuItemDefinition } from './structures/tree.js';
|
|
4
|
+
export { tryCreateMenuModel as tryCreateNavigationMenuModel } from './menu.js';
|
|
5
|
+
export { tryCreateMenuState as tryCreateNavigationMenuState } from './internal/composites/menu.js';
|
|
6
|
+
//# sourceMappingURL=navigation-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-menu.d.ts","sourceRoot":"","sources":["../src/navigation-menu.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,IAAI,wBAAwB,EAC1C,eAAe,IAAI,yBAAyB,EAC5C,KAAK,WAAW,IAAI,qBAAqB,EACzC,KAAK,SAAS,IAAI,mBAAmB,EACrC,KAAK,YAAY,IAAI,sBAAsB,EAC3C,KAAK,SAAS,IAAI,mBAAmB,EACrC,KAAK,UAAU,IAAI,oBAAoB,GACxC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,eAAe,IAAI,yBAAyB,EAC5C,KAAK,SAAS,IAAI,mBAAmB,GACtC,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,aAAa,IAAI,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAE1F,OAAO,EAAE,kBAAkB,IAAI,4BAA4B,EAAE,MAAM,WAAW,CAAC;AAC/E,OAAO,EAAE,kBAAkB,IAAI,4BAA4B,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { applyMenuEvent as applyNavigationMenuEvent, createMenuState as createNavigationMenuState, } from './internal/composites/menu.js';
|
|
2
|
+
export { createMenuModel as createNavigationMenuModel, } from './menu.js';
|
|
3
|
+
export { tryCreateMenuModel as tryCreateNavigationMenuModel } from './menu.js';
|
|
4
|
+
export { tryCreateMenuState as tryCreateNavigationMenuState } from './internal/composites/menu.js';
|
|
5
|
+
//# sourceMappingURL=navigation-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-menu.js","sourceRoot":"","sources":["../src/navigation-menu.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,IAAI,wBAAwB,EAC1C,eAAe,IAAI,yBAAyB,GAM7C,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,eAAe,IAAI,yBAAyB,GAE7C,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,kBAAkB,IAAI,4BAA4B,EAAE,MAAM,WAAW,CAAC;AAC/E,OAAO,EAAE,kBAAkB,IAAI,4BAA4B,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Result } from './shared.js';
|
|
2
|
+
import { type DecimalRounding } from './internal/kernel/decimal.js';
|
|
3
|
+
import { type TextEditingState, type TextEvent } from './text.js';
|
|
4
|
+
export interface NumericExpressionResult {
|
|
5
|
+
readonly expression: string;
|
|
6
|
+
readonly value: string;
|
|
7
|
+
}
|
|
8
|
+
export interface NumericExpressionEvaluator {
|
|
9
|
+
evaluate(expression: string): Result<NumericExpressionResult>;
|
|
10
|
+
}
|
|
11
|
+
export interface CalculatorExpressionOptions {
|
|
12
|
+
readonly precision?: number;
|
|
13
|
+
readonly rounding?: DecimalRounding;
|
|
14
|
+
readonly maxCodeUnits?: number;
|
|
15
|
+
readonly maxTokens?: number;
|
|
16
|
+
readonly maxDepth?: number;
|
|
17
|
+
readonly maxOperations?: number;
|
|
18
|
+
readonly maxExponent?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface NumberFieldState {
|
|
21
|
+
readonly value: string | null;
|
|
22
|
+
readonly inputState: TextEditingState;
|
|
23
|
+
}
|
|
24
|
+
export type NumberFieldEvent = {
|
|
25
|
+
readonly type: 'text';
|
|
26
|
+
readonly event: TextEvent;
|
|
27
|
+
} | 'commit' | 'cancel';
|
|
28
|
+
export type NumberFieldCommand = {
|
|
29
|
+
readonly type: 'input-state-changed';
|
|
30
|
+
readonly value: TextEditingState;
|
|
31
|
+
} | {
|
|
32
|
+
readonly type: 'value-committed';
|
|
33
|
+
readonly value: string | null;
|
|
34
|
+
readonly expression: string;
|
|
35
|
+
};
|
|
36
|
+
export interface NumberFieldPolicies {
|
|
37
|
+
readonly evaluator?: NumericExpressionEvaluator;
|
|
38
|
+
readonly min?: string;
|
|
39
|
+
readonly max?: string;
|
|
40
|
+
readonly required?: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface NumberFieldUpdate {
|
|
43
|
+
readonly state: NumberFieldState;
|
|
44
|
+
readonly commands: readonly NumberFieldCommand[];
|
|
45
|
+
}
|
|
46
|
+
export declare function createCalculatorExpression(options?: CalculatorExpressionOptions): NumericExpressionEvaluator;
|
|
47
|
+
export declare function tryCreateCalculatorExpression(options?: CalculatorExpressionOptions): Result<NumericExpressionEvaluator>;
|
|
48
|
+
export declare function createNumberFieldState(value?: string | null, inputState?: TextEditingState): NumberFieldState;
|
|
49
|
+
export declare function tryCreateNumberFieldState(value?: string | null, inputState?: TextEditingState): Result<NumberFieldState>;
|
|
50
|
+
export declare function applyNumberFieldEvent(state: NumberFieldState, event: NumberFieldEvent, policies?: NumberFieldPolicies): Result<NumberFieldUpdate>;
|
|
51
|
+
//# sourceMappingURL=number-field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-field.d.ts","sourceRoot":"","sources":["../src/number-field.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EASL,KAAK,eAAe,EAErB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,SAAS,EAEf,MAAM,WAAW,CAAC;AAEnB,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;CACvC;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GACpD,QAAQ,GACR,QAAQ,CAAC;AAEb,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,GAC1E;IAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAErG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,0BAA0B,CAAC;IAChD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAClD;AAyBD,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,2BAAgC,GACxC,0BAA0B,CAE5B;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,2BAAgC,GACxC,MAAM,CAAC,0BAA0B,CAAC,CAQpC;AAED,wBAAgB,sBAAsB,CACpC,KAAK,GAAE,MAAM,GAAG,IAAW,EAC3B,UAAU,CAAC,EAAE,gBAAgB,GAC5B,gBAAgB,CAElB;AAED,wBAAgB,yBAAyB,CACvC,KAAK,GAAE,MAAM,GAAG,IAAW,EAC3B,UAAU,CAAC,EAAE,gBAAgB,GAC5B,MAAM,CAAC,gBAAgB,CAAC,CAiB1B;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,GAAE,mBAAwB,GACjC,MAAM,CAAC,iBAAiB,CAAC,CAoE3B"}
|
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import { unwrap } from './result.js';
|
|
2
|
+
import { addDecimal, compareDecimal, decimalToString, divideDecimal, multiplyDecimal, negateDecimal, parseDecimal, subtractDecimal, } from './internal/kernel/decimal.js';
|
|
3
|
+
import { fail, ok, validateSafeCeiling } from './internal/kernel/foundation.js';
|
|
4
|
+
import { createMachineUpdate } from './internal/kernel/machine.js';
|
|
5
|
+
import { applyTextEvent, createTextEditingState, normalizeTextEditingState, tryCreateTextEditingState, } from './text.js';
|
|
6
|
+
export function createCalculatorExpression(options = {}) {
|
|
7
|
+
return unwrap(tryCreateCalculatorExpression(options));
|
|
8
|
+
}
|
|
9
|
+
export function tryCreateCalculatorExpression(options = {}) {
|
|
10
|
+
const limits = normalizeCalculatorLimits(options);
|
|
11
|
+
if (!limits.ok)
|
|
12
|
+
return limits;
|
|
13
|
+
return ok(Object.freeze({
|
|
14
|
+
evaluate(expression) {
|
|
15
|
+
return evaluateCalculator(expression, limits.value);
|
|
16
|
+
},
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
export function createNumberFieldState(value = null, inputState) {
|
|
20
|
+
return unwrap(tryCreateNumberFieldState(value, inputState));
|
|
21
|
+
}
|
|
22
|
+
export function tryCreateNumberFieldState(value = null, inputState) {
|
|
23
|
+
if (value !== null && typeof value !== 'string') {
|
|
24
|
+
return fail('construction', 'invalid-number-field-value', 'Number field value must be decimal text or null.');
|
|
25
|
+
}
|
|
26
|
+
const parsed = value === null ? null : parseDecimal(value);
|
|
27
|
+
if (value !== null && parsed === null) {
|
|
28
|
+
return fail('construction', 'invalid-number-field-value', 'Number field value must be finite decimal text.', { value });
|
|
29
|
+
}
|
|
30
|
+
const canonicalValue = parsed === null ? null : decimalToString(parsed);
|
|
31
|
+
const input = inputState === undefined
|
|
32
|
+
? createCommittedInput(canonicalValue)
|
|
33
|
+
: normalizeTextEditingState(inputState);
|
|
34
|
+
if (!input.ok)
|
|
35
|
+
return input;
|
|
36
|
+
return ok(Object.freeze({
|
|
37
|
+
value: canonicalValue,
|
|
38
|
+
inputState: input.value,
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
export function applyNumberFieldEvent(state, event, policies = {}) {
|
|
42
|
+
const valid = tryCreateNumberFieldState(state.value, state.inputState);
|
|
43
|
+
if (!valid.ok)
|
|
44
|
+
return { ok: false, error: { ...valid.error, class: 'transition-rejection' } };
|
|
45
|
+
const bounds = normalizeBounds(policies);
|
|
46
|
+
if (!bounds.ok)
|
|
47
|
+
return bounds;
|
|
48
|
+
if (typeof event === 'object') {
|
|
49
|
+
if (event.type !== 'text' || typeof event.event !== 'object' || event.event === null) {
|
|
50
|
+
return fail('transition-rejection', 'invalid-number-field-text-event', 'Number field input must be a semantic text event.');
|
|
51
|
+
}
|
|
52
|
+
const edited = applyTextEvent(valid.value.inputState, event.event);
|
|
53
|
+
if (!edited.ok)
|
|
54
|
+
return edited;
|
|
55
|
+
return createMachineUpdate(Object.freeze({ value: valid.value.value, inputState: edited.value.state }), [{ type: 'input-state-changed', value: edited.value.state }]);
|
|
56
|
+
}
|
|
57
|
+
if (event === 'cancel') {
|
|
58
|
+
const restored = createCommittedInput(valid.value.value);
|
|
59
|
+
if (!restored.ok)
|
|
60
|
+
return restored;
|
|
61
|
+
if (sameTextState(restored.value, valid.value.inputState))
|
|
62
|
+
return createMachineUpdate(valid.value);
|
|
63
|
+
return createMachineUpdate(Object.freeze({ value: valid.value.value, inputState: restored.value }), [{ type: 'input-state-changed', value: restored.value }]);
|
|
64
|
+
}
|
|
65
|
+
if (event !== 'commit') {
|
|
66
|
+
return fail('transition-rejection', 'unsupported-number-field-event', 'Number field event is unsupported.');
|
|
67
|
+
}
|
|
68
|
+
if (valid.value.inputState.composition !== null) {
|
|
69
|
+
return fail('transition-rejection', 'number-field-composition-active', 'Number field cannot commit while text composition is active.');
|
|
70
|
+
}
|
|
71
|
+
const expression = valid.value.inputState.snapshot.text.trim();
|
|
72
|
+
if (expression.length === 0) {
|
|
73
|
+
if (policies.required === true) {
|
|
74
|
+
return fail('transition-rejection', 'number-field-value-required', 'Number field requires a value.');
|
|
75
|
+
}
|
|
76
|
+
const input = createCommittedInput(null);
|
|
77
|
+
if (!input.ok)
|
|
78
|
+
return input;
|
|
79
|
+
return createMachineUpdate(Object.freeze({ value: null, inputState: input.value }), [
|
|
80
|
+
{ type: 'input-state-changed', value: input.value },
|
|
81
|
+
{ type: 'value-committed', value: null, expression },
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
const evaluated = safelyEvaluate(policies.evaluator ?? literalEvaluator, expression);
|
|
85
|
+
if (!evaluated.ok)
|
|
86
|
+
return evaluated;
|
|
87
|
+
const parsed = parseDecimal(evaluated.value.value);
|
|
88
|
+
if (parsed === null) {
|
|
89
|
+
return fail('transition-rejection', 'invalid-number-field-evaluation', 'Number evaluator must return finite decimal text.');
|
|
90
|
+
}
|
|
91
|
+
if (bounds.value.min !== null && compareDecimal(parsed, bounds.value.min) < 0) {
|
|
92
|
+
return fail('transition-rejection', 'number-field-value-below-minimum', 'Number field value is below its minimum.', { value: evaluated.value.value, min: policies.min });
|
|
93
|
+
}
|
|
94
|
+
if (bounds.value.max !== null && compareDecimal(parsed, bounds.value.max) > 0) {
|
|
95
|
+
return fail('transition-rejection', 'number-field-value-above-maximum', 'Number field value is above its maximum.', { value: evaluated.value.value, max: policies.max });
|
|
96
|
+
}
|
|
97
|
+
const value = decimalToString(parsed);
|
|
98
|
+
const input = createCommittedInput(value);
|
|
99
|
+
if (!input.ok)
|
|
100
|
+
return input;
|
|
101
|
+
return createMachineUpdate(Object.freeze({ value, inputState: input.value }), [
|
|
102
|
+
{ type: 'input-state-changed', value: input.value },
|
|
103
|
+
{ type: 'value-committed', value, expression: evaluated.value.expression },
|
|
104
|
+
]);
|
|
105
|
+
}
|
|
106
|
+
function createCommittedInput(value) {
|
|
107
|
+
const text = value ?? '';
|
|
108
|
+
return tryCreateTextEditingState(text, {
|
|
109
|
+
anchorCodeUnitOffset: text.length,
|
|
110
|
+
focusCodeUnitOffset: text.length,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function sameTextState(left, right) {
|
|
114
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
115
|
+
}
|
|
116
|
+
const literalEvaluator = Object.freeze({
|
|
117
|
+
evaluate(expression) {
|
|
118
|
+
const value = parseDecimal(expression);
|
|
119
|
+
return value === null
|
|
120
|
+
? fail('transition-rejection', 'invalid-number-literal', 'Number field draft must be a finite decimal literal.', { expression })
|
|
121
|
+
: ok(Object.freeze({ expression, value: decimalToString(value) }));
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
function safelyEvaluate(evaluator, expression) {
|
|
125
|
+
if (typeof evaluator !== 'object' || evaluator === null || typeof evaluator.evaluate !== 'function') {
|
|
126
|
+
return fail('construction', 'invalid-number-evaluator', 'Number field evaluator must expose evaluate(expression).');
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
return evaluator.evaluate(expression);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
return fail('transition-rejection', 'number-evaluator-threw', 'Number field evaluator threw while evaluating its draft.', { cause: error instanceof Error ? error.message : String(error) });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function normalizeBounds(policies) {
|
|
136
|
+
const min = policies.min === undefined ? null : parseDecimal(policies.min);
|
|
137
|
+
const max = policies.max === undefined ? null : parseDecimal(policies.max);
|
|
138
|
+
if (policies.min !== undefined && min === null)
|
|
139
|
+
return fail('construction', 'invalid-number-field-minimum', 'Number field minimum must be finite decimal text.');
|
|
140
|
+
if (policies.max !== undefined && max === null)
|
|
141
|
+
return fail('construction', 'invalid-number-field-maximum', 'Number field maximum must be finite decimal text.');
|
|
142
|
+
if (min !== null && max !== null && compareDecimal(min, max) > 0)
|
|
143
|
+
return fail('construction', 'inverted-number-field-bounds', 'Number field minimum must not exceed its maximum.');
|
|
144
|
+
return ok(Object.freeze({ min, max }));
|
|
145
|
+
}
|
|
146
|
+
function normalizeCalculatorLimits(options) {
|
|
147
|
+
const values = {
|
|
148
|
+
precision: options.precision ?? 12,
|
|
149
|
+
maxCodeUnits: options.maxCodeUnits ?? 1_024,
|
|
150
|
+
maxTokens: options.maxTokens ?? 256,
|
|
151
|
+
maxDepth: options.maxDepth ?? 32,
|
|
152
|
+
maxOperations: options.maxOperations ?? 256,
|
|
153
|
+
maxExponent: options.maxExponent ?? 1_000,
|
|
154
|
+
};
|
|
155
|
+
for (const [name, value, minimum] of [
|
|
156
|
+
['precision', values.precision, 0],
|
|
157
|
+
['maxCodeUnits', values.maxCodeUnits, 1],
|
|
158
|
+
['maxTokens', values.maxTokens, 1],
|
|
159
|
+
['maxDepth', values.maxDepth, 1],
|
|
160
|
+
['maxOperations', values.maxOperations, 1],
|
|
161
|
+
['maxExponent', values.maxExponent, 0],
|
|
162
|
+
]) {
|
|
163
|
+
const error = validateSafeCeiling(value, name, minimum);
|
|
164
|
+
if (error !== null)
|
|
165
|
+
return { ok: false, error };
|
|
166
|
+
}
|
|
167
|
+
const rounding = options.rounding ?? 'half-even';
|
|
168
|
+
if (rounding !== 'half-even' && rounding !== 'half-up' && rounding !== 'toward-zero') {
|
|
169
|
+
return fail('construction', 'invalid-decimal-rounding', 'Calculator rounding must be half-even, half-up, or toward-zero.');
|
|
170
|
+
}
|
|
171
|
+
return ok(Object.freeze({ ...values, rounding }));
|
|
172
|
+
}
|
|
173
|
+
function evaluateCalculator(expression, limits) {
|
|
174
|
+
if (typeof expression !== 'string') {
|
|
175
|
+
return fail('transition-rejection', 'invalid-calculator-expression', 'Calculator expression must be text.');
|
|
176
|
+
}
|
|
177
|
+
if (expression.length === 0) {
|
|
178
|
+
return fail('transition-rejection', 'empty-calculator-expression', 'Calculator expression must not be empty.');
|
|
179
|
+
}
|
|
180
|
+
if (expression.length > limits.maxCodeUnits) {
|
|
181
|
+
return fail('resource-rejection', 'calculator-code-unit-ceiling-exceeded', 'Calculator expression exceeds maxCodeUnits.', { codeUnits: expression.length, maxCodeUnits: limits.maxCodeUnits });
|
|
182
|
+
}
|
|
183
|
+
const tokens = tokenize(expression, limits.maxTokens);
|
|
184
|
+
if (!tokens.ok)
|
|
185
|
+
return tokens;
|
|
186
|
+
const parser = new ExpressionParser(tokens.value, limits);
|
|
187
|
+
const parsed = parser.parse();
|
|
188
|
+
if (!parsed.ok)
|
|
189
|
+
return parsed;
|
|
190
|
+
const evaluated = evaluateNode(parsed.value, limits, { operations: 0 });
|
|
191
|
+
if (!evaluated.ok)
|
|
192
|
+
return evaluated;
|
|
193
|
+
const value = decimalToString(evaluated.value);
|
|
194
|
+
if (value.length > limits.maxCodeUnits) {
|
|
195
|
+
return fail('resource-rejection', 'calculator-result-ceiling-exceeded', 'Calculator result exceeds maxCodeUnits.', { codeUnits: value.length, maxCodeUnits: limits.maxCodeUnits });
|
|
196
|
+
}
|
|
197
|
+
return ok(Object.freeze({ expression, value }));
|
|
198
|
+
}
|
|
199
|
+
function tokenize(expression, maxTokens) {
|
|
200
|
+
const tokens = [];
|
|
201
|
+
let offset = 0;
|
|
202
|
+
while (offset < expression.length) {
|
|
203
|
+
const character = expression[offset] ?? '';
|
|
204
|
+
if (/\s/u.test(character)) {
|
|
205
|
+
offset += 1;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (/\d|\./u.test(character)) {
|
|
209
|
+
const start = offset;
|
|
210
|
+
let dots = 0;
|
|
211
|
+
while (offset < expression.length && /\d|\./u.test(expression[offset] ?? '')) {
|
|
212
|
+
if (expression[offset] === '.')
|
|
213
|
+
dots += 1;
|
|
214
|
+
offset += 1;
|
|
215
|
+
}
|
|
216
|
+
const text = expression.slice(start, offset);
|
|
217
|
+
if (dots > 1 || parseDecimal(text) === null) {
|
|
218
|
+
return fail('transition-rejection', 'invalid-calculator-number', 'Calculator expression contains an invalid number.', { text, offset: start });
|
|
219
|
+
}
|
|
220
|
+
tokens.push(Object.freeze({ type: 'number', text, offset: start }));
|
|
221
|
+
}
|
|
222
|
+
else if ('+-*/^'.includes(character) || character === '×' || character === '÷' || character === '−') {
|
|
223
|
+
const operator = character === '×' ? '*' : character === '÷' ? '/' : character === '−' ? '-' : character;
|
|
224
|
+
tokens.push(Object.freeze({ type: 'operator', operator, offset }));
|
|
225
|
+
offset += 1;
|
|
226
|
+
}
|
|
227
|
+
else if (character === '%') {
|
|
228
|
+
tokens.push(Object.freeze({ type: 'percent', offset }));
|
|
229
|
+
offset += 1;
|
|
230
|
+
}
|
|
231
|
+
else if (character === '(') {
|
|
232
|
+
tokens.push(Object.freeze({ type: 'left', offset }));
|
|
233
|
+
offset += 1;
|
|
234
|
+
}
|
|
235
|
+
else if (character === ')') {
|
|
236
|
+
tokens.push(Object.freeze({ type: 'right', offset }));
|
|
237
|
+
offset += 1;
|
|
238
|
+
}
|
|
239
|
+
else
|
|
240
|
+
return fail('transition-rejection', 'unsupported-calculator-token', 'Calculator expression contains an unsupported token.', { character, offset });
|
|
241
|
+
if (tokens.length > maxTokens)
|
|
242
|
+
return fail('resource-rejection', 'calculator-token-ceiling-exceeded', 'Calculator expression exceeds maxTokens.', { maxTokens });
|
|
243
|
+
}
|
|
244
|
+
tokens.push(Object.freeze({ type: 'end', offset }));
|
|
245
|
+
return ok(Object.freeze(tokens));
|
|
246
|
+
}
|
|
247
|
+
class ExpressionParser {
|
|
248
|
+
#tokens;
|
|
249
|
+
#limits;
|
|
250
|
+
#index = 0;
|
|
251
|
+
#depth = 0;
|
|
252
|
+
#operations = 0;
|
|
253
|
+
constructor(tokens, limits) {
|
|
254
|
+
this.#tokens = tokens;
|
|
255
|
+
this.#limits = limits;
|
|
256
|
+
}
|
|
257
|
+
parse() {
|
|
258
|
+
const expression = this.#parseAdditive();
|
|
259
|
+
if (!expression.ok)
|
|
260
|
+
return expression;
|
|
261
|
+
const token = this.#current();
|
|
262
|
+
return token.type === 'end'
|
|
263
|
+
? expression
|
|
264
|
+
: fail('transition-rejection', 'unexpected-calculator-token', 'Calculator expression has an unexpected trailing token.', { offset: token.offset });
|
|
265
|
+
}
|
|
266
|
+
#parseAdditive() {
|
|
267
|
+
let left = this.#parseMultiplicative();
|
|
268
|
+
if (!left.ok)
|
|
269
|
+
return left;
|
|
270
|
+
while (this.#operator('+') || this.#operator('-')) {
|
|
271
|
+
const operator = this.#take().operator;
|
|
272
|
+
const right = this.#parseMultiplicative();
|
|
273
|
+
if (!right.ok)
|
|
274
|
+
return right;
|
|
275
|
+
const combined = this.#binary(operator, left.value, right.value);
|
|
276
|
+
if (!combined.ok)
|
|
277
|
+
return combined;
|
|
278
|
+
left = combined;
|
|
279
|
+
}
|
|
280
|
+
return left;
|
|
281
|
+
}
|
|
282
|
+
#parseMultiplicative() {
|
|
283
|
+
let left = this.#parseUnary();
|
|
284
|
+
if (!left.ok)
|
|
285
|
+
return left;
|
|
286
|
+
while (this.#operator('*') || this.#operator('/')) {
|
|
287
|
+
const operator = this.#take().operator;
|
|
288
|
+
const right = this.#parseUnary();
|
|
289
|
+
if (!right.ok)
|
|
290
|
+
return right;
|
|
291
|
+
const combined = this.#binary(operator, left.value, right.value);
|
|
292
|
+
if (!combined.ok)
|
|
293
|
+
return combined;
|
|
294
|
+
left = combined;
|
|
295
|
+
}
|
|
296
|
+
return left;
|
|
297
|
+
}
|
|
298
|
+
#parseUnary() {
|
|
299
|
+
if (this.#operator('+') || this.#operator('-')) {
|
|
300
|
+
const operator = this.#take().operator;
|
|
301
|
+
const operand = this.#parseUnary();
|
|
302
|
+
if (!operand.ok)
|
|
303
|
+
return operand;
|
|
304
|
+
const operation = this.#countOperation();
|
|
305
|
+
return operation.ok ? ok(Object.freeze({ type: 'unary', operator, operand: operand.value })) : operation;
|
|
306
|
+
}
|
|
307
|
+
return this.#parsePower();
|
|
308
|
+
}
|
|
309
|
+
#parsePower() {
|
|
310
|
+
const left = this.#parsePostfix();
|
|
311
|
+
if (!left.ok || !this.#operator('^'))
|
|
312
|
+
return left;
|
|
313
|
+
this.#take();
|
|
314
|
+
const right = this.#parseUnary();
|
|
315
|
+
if (!right.ok)
|
|
316
|
+
return right;
|
|
317
|
+
return this.#binary('^', left.value, right.value);
|
|
318
|
+
}
|
|
319
|
+
#parsePostfix() {
|
|
320
|
+
const primary = this.#parsePrimary();
|
|
321
|
+
if (!primary.ok)
|
|
322
|
+
return primary;
|
|
323
|
+
let operand = primary.value;
|
|
324
|
+
while (this.#current().type === 'percent') {
|
|
325
|
+
this.#take();
|
|
326
|
+
const operation = this.#countOperation();
|
|
327
|
+
if (!operation.ok)
|
|
328
|
+
return operation;
|
|
329
|
+
operand = Object.freeze({ type: 'percent', operand });
|
|
330
|
+
}
|
|
331
|
+
return ok(operand);
|
|
332
|
+
}
|
|
333
|
+
#parsePrimary() {
|
|
334
|
+
const token = this.#current();
|
|
335
|
+
if (token.type === 'number') {
|
|
336
|
+
this.#take();
|
|
337
|
+
return ok(Object.freeze({ type: 'number', value: parseDecimal(token.text) }));
|
|
338
|
+
}
|
|
339
|
+
if (token.type !== 'left') {
|
|
340
|
+
return fail('transition-rejection', 'calculator-operand-expected', 'Calculator expression requires a number or parenthesized expression.', { offset: token.offset });
|
|
341
|
+
}
|
|
342
|
+
this.#take();
|
|
343
|
+
this.#depth += 1;
|
|
344
|
+
if (this.#depth > this.#limits.maxDepth) {
|
|
345
|
+
return fail('resource-rejection', 'calculator-depth-ceiling-exceeded', 'Calculator expression exceeds maxDepth.', { maxDepth: this.#limits.maxDepth });
|
|
346
|
+
}
|
|
347
|
+
const expression = this.#parseAdditive();
|
|
348
|
+
this.#depth -= 1;
|
|
349
|
+
if (!expression.ok)
|
|
350
|
+
return expression;
|
|
351
|
+
const closing = this.#current();
|
|
352
|
+
if (closing.type !== 'right') {
|
|
353
|
+
return fail('transition-rejection', 'calculator-closing-parenthesis-expected', 'Calculator expression is missing a closing parenthesis.', { offset: closing.offset });
|
|
354
|
+
}
|
|
355
|
+
this.#take();
|
|
356
|
+
return expression;
|
|
357
|
+
}
|
|
358
|
+
#binary(operator, left, right) {
|
|
359
|
+
const operation = this.#countOperation();
|
|
360
|
+
return operation.ok ? ok(Object.freeze({ type: 'binary', operator, left, right })) : operation;
|
|
361
|
+
}
|
|
362
|
+
#countOperation() {
|
|
363
|
+
this.#operations += 1;
|
|
364
|
+
return this.#operations > this.#limits.maxOperations
|
|
365
|
+
? fail('resource-rejection', 'calculator-operation-ceiling-exceeded', 'Calculator expression exceeds maxOperations.', { maxOperations: this.#limits.maxOperations })
|
|
366
|
+
: ok(true);
|
|
367
|
+
}
|
|
368
|
+
#operator(operator) {
|
|
369
|
+
const token = this.#current();
|
|
370
|
+
return token.type === 'operator' && token.operator === operator;
|
|
371
|
+
}
|
|
372
|
+
#current() { return this.#tokens[this.#index]; }
|
|
373
|
+
#take() { const token = this.#current(); this.#index += 1; return token; }
|
|
374
|
+
}
|
|
375
|
+
function evaluateNode(node, limits, budget) {
|
|
376
|
+
if (node.type === 'number')
|
|
377
|
+
return ok(node.value);
|
|
378
|
+
budget.operations += 1;
|
|
379
|
+
if (budget.operations > limits.maxOperations) {
|
|
380
|
+
return fail('resource-rejection', 'calculator-operation-ceiling-exceeded', 'Calculator evaluation exceeds maxOperations.', { maxOperations: limits.maxOperations });
|
|
381
|
+
}
|
|
382
|
+
if (node.type === 'unary') {
|
|
383
|
+
const operand = evaluateNode(node.operand, limits, budget);
|
|
384
|
+
return operand.ok ? ok(node.operator === '-' ? negateDecimal(operand.value) : operand.value) : operand;
|
|
385
|
+
}
|
|
386
|
+
if (node.type === 'percent') {
|
|
387
|
+
const operand = evaluateNode(node.operand, limits, budget);
|
|
388
|
+
if (!operand.ok)
|
|
389
|
+
return operand;
|
|
390
|
+
return divide(operand.value, { coefficient: 100n, scale: 0 }, limits);
|
|
391
|
+
}
|
|
392
|
+
const left = evaluateNode(node.left, limits, budget);
|
|
393
|
+
if (!left.ok)
|
|
394
|
+
return left;
|
|
395
|
+
if ((node.operator === '+' || node.operator === '-') && node.right.type === 'percent') {
|
|
396
|
+
const percentage = evaluateNode(node.right.operand, limits, budget);
|
|
397
|
+
if (!percentage.ok)
|
|
398
|
+
return percentage;
|
|
399
|
+
const ratio = divide(percentage.value, { coefficient: 100n, scale: 0 }, limits);
|
|
400
|
+
if (!ratio.ok)
|
|
401
|
+
return ratio;
|
|
402
|
+
const delta = multiplyDecimal(left.value, ratio.value);
|
|
403
|
+
return checkedDecimal(node.operator === '+' ? addDecimal(left.value, delta) : subtractDecimal(left.value, delta), limits);
|
|
404
|
+
}
|
|
405
|
+
const right = evaluateNode(node.right, limits, budget);
|
|
406
|
+
if (!right.ok)
|
|
407
|
+
return right;
|
|
408
|
+
if (node.operator === '+')
|
|
409
|
+
return checkedDecimal(addDecimal(left.value, right.value), limits);
|
|
410
|
+
if (node.operator === '-')
|
|
411
|
+
return checkedDecimal(subtractDecimal(left.value, right.value), limits);
|
|
412
|
+
if (node.operator === '*')
|
|
413
|
+
return checkedDecimal(multiplyDecimal(left.value, right.value), limits);
|
|
414
|
+
if (node.operator === '/')
|
|
415
|
+
return divide(left.value, right.value, limits);
|
|
416
|
+
return power(left.value, right.value, limits);
|
|
417
|
+
}
|
|
418
|
+
function divide(numerator, denominator, limits) {
|
|
419
|
+
const value = divideDecimal(numerator, denominator, limits.precision, limits.rounding);
|
|
420
|
+
return value === null
|
|
421
|
+
? fail('transition-rejection', 'calculator-division-by-zero', 'Calculator expression cannot divide by zero.')
|
|
422
|
+
: checkedDecimal(value, limits);
|
|
423
|
+
}
|
|
424
|
+
function power(base, exponent, limits) {
|
|
425
|
+
if (exponent.scale !== 0) {
|
|
426
|
+
return fail('transition-rejection', 'calculator-fractional-exponent', 'Calculator exponent must be an integer.', { exponent: decimalToString(exponent) });
|
|
427
|
+
}
|
|
428
|
+
const maximum = BigInt(limits.maxExponent);
|
|
429
|
+
const absolute = exponent.coefficient < 0n ? -exponent.coefficient : exponent.coefficient;
|
|
430
|
+
if (absolute > maximum) {
|
|
431
|
+
return fail('resource-rejection', 'calculator-exponent-ceiling-exceeded', 'Calculator exponent exceeds maxExponent.', { exponent: exponent.coefficient.toString(), maxExponent: limits.maxExponent });
|
|
432
|
+
}
|
|
433
|
+
let result = { coefficient: 1n, scale: 0 };
|
|
434
|
+
let factor = base;
|
|
435
|
+
let remaining = absolute;
|
|
436
|
+
while (remaining > 0n) {
|
|
437
|
+
if (remaining % 2n === 1n) {
|
|
438
|
+
result = multiplyDecimal(result, factor);
|
|
439
|
+
const checked = checkedDecimal(result, limits);
|
|
440
|
+
if (!checked.ok)
|
|
441
|
+
return checked;
|
|
442
|
+
}
|
|
443
|
+
remaining /= 2n;
|
|
444
|
+
if (remaining > 0n) {
|
|
445
|
+
factor = multiplyDecimal(factor, factor);
|
|
446
|
+
const checked = checkedDecimal(factor, limits);
|
|
447
|
+
if (!checked.ok)
|
|
448
|
+
return checked;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return exponent.coefficient < 0n
|
|
452
|
+
? divide({ coefficient: 1n, scale: 0 }, result, limits)
|
|
453
|
+
: checkedDecimal(result, limits);
|
|
454
|
+
}
|
|
455
|
+
function checkedDecimal(value, limits) {
|
|
456
|
+
const text = decimalToString(value);
|
|
457
|
+
return text.length > limits.maxCodeUnits
|
|
458
|
+
? fail('resource-rejection', 'calculator-result-ceiling-exceeded', 'Calculator intermediate result exceeds maxCodeUnits.', { codeUnits: text.length, maxCodeUnits: limits.maxCodeUnits })
|
|
459
|
+
: ok(value);
|
|
460
|
+
}
|
|
461
|
+
//# sourceMappingURL=number-field.js.map
|