@zeyos/zx 2.1.0 → 2.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/CHANGELOG.md +51 -0
- package/README.md +15 -0
- package/dist/types/compat/base.d.ts +156 -0
- package/dist/types/compat/globals.d.ts +20 -0
- package/dist/types/compat/index.d.ts +128 -0
- package/dist/types/compat/map/basic.d.ts +175 -0
- package/dist/types/compat/map/data.d.ts +102 -0
- package/dist/types/compat/map/date-time.d.ts +80 -0
- package/dist/types/compat/map/factory.d.ts +9 -0
- package/dist/types/compat/map/form.d.ts +98 -0
- package/dist/types/compat/map/helpers.d.ts +12 -0
- package/dist/types/compat/map/http.d.ts +36 -0
- package/dist/types/compat/map/layout.d.ts +106 -0
- package/dist/types/compat/map/options.d.ts +80 -0
- package/dist/types/compat/map/select.d.ts +95 -0
- package/dist/types/compat/map/stubs.d.ts +32 -0
- package/dist/types/compat/map/utilities.d.ts +37 -0
- package/dist/types/compat-entry.d.ts +5 -0
- package/dist/types/components/badge/badge.d.ts +46 -0
- package/dist/types/components/breadcrumb/breadcrumb.d.ts +200 -0
- package/dist/types/components/button/button.d.ts +42 -0
- package/dist/types/components/check-button/check-button.d.ts +98 -0
- package/dist/types/components/checklist/checklist.d.ts +143 -0
- package/dist/types/components/checklist/field-adapter.d.ts +5 -0
- package/dist/types/components/context-menu/context-menu.d.ts +130 -0
- package/dist/types/components/copy/copy-button.d.ts +48 -0
- package/dist/types/components/copy/copy-input.d.ts +91 -0
- package/dist/types/components/data-filter/data-filter.d.ts +250 -0
- package/dist/types/components/data-filter/filter-core.d.ts +52 -0
- package/dist/types/components/date-picker/date-picker.d.ts +137 -0
- package/dist/types/components/date-picker/date-range-picker.d.ts +350 -0
- package/dist/types/components/date-picker/field-adapter.d.ts +6 -0
- package/dist/types/components/date-picker/month-picker.d.ts +75 -0
- package/dist/types/components/date-picker/range-field-adapter.d.ts +7 -0
- package/dist/types/components/date-picker/time-picker.d.ts +127 -0
- package/dist/types/components/datebox/date-range-box.d.ts +218 -0
- package/dist/types/components/datebox/datebox.d.ts +160 -0
- package/dist/types/components/datebox/field-adapter.d.ts +5 -0
- package/dist/types/components/dialog/dialog.d.ts +284 -0
- package/dist/types/components/dropdown/dropdown.d.ts +118 -0
- package/dist/types/components/empty-state/empty-state.d.ts +38 -0
- package/dist/types/components/field/field.d.ts +231 -0
- package/dist/types/components/field-upload/field-adapter.d.ts +5 -0
- package/dist/types/components/field-upload/field-upload.d.ts +213 -0
- package/dist/types/components/fieldset/fieldset.d.ts +125 -0
- package/dist/types/components/finder/finder.d.ts +252 -0
- package/dist/types/components/form/form.d.ts +194 -0
- package/dist/types/components/groupbox/groupbox.d.ts +89 -0
- package/dist/types/components/layout/layout.d.ts +132 -0
- package/dist/types/components/loading/inline-loading.d.ts +86 -0
- package/dist/types/components/loading/progress-bar.d.ts +168 -0
- package/dist/types/components/loading/spinner.d.ts +34 -0
- package/dist/types/components/master-panel/master-panel.d.ts +112 -0
- package/dist/types/components/menu-button/menu-button.d.ts +142 -0
- package/dist/types/components/message/message.d.ts +212 -0
- package/dist/types/components/modal/modal.d.ts +105 -0
- package/dist/types/components/multi-value-editor/field-adapter.d.ts +5 -0
- package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +66 -0
- package/dist/types/components/navigation-bar/navigation-bar.d.ts +229 -0
- package/dist/types/components/number-field/field-adapter.d.ts +5 -0
- package/dist/types/components/number-field/number-field.d.ts +292 -0
- package/dist/types/components/pagination/pagination.d.ts +267 -0
- package/dist/types/components/panel/panel.d.ts +194 -0
- package/dist/types/components/permission/permission.d.ts +93 -0
- package/dist/types/components/rating/field-adapter.d.ts +5 -0
- package/dist/types/components/rating/rating.d.ts +213 -0
- package/dist/types/components/search/search.d.ts +98 -0
- package/dist/types/components/select/field-adapter.d.ts +5 -0
- package/dist/types/components/select/filter.d.ts +11 -0
- package/dist/types/components/select/select.d.ts +235 -0
- package/dist/types/components/skeleton/skeleton.d.ts +97 -0
- package/dist/types/components/slider/field-adapter.d.ts +5 -0
- package/dist/types/components/slider/slider.d.ts +216 -0
- package/dist/types/components/split-view/split-view.d.ts +335 -0
- package/dist/types/components/stepper/stepper.d.ts +314 -0
- package/dist/types/components/stepper/steps.d.ts +131 -0
- package/dist/types/components/tabbox/tabbox.d.ts +230 -0
- package/dist/types/components/table/sort.d.ts +49 -0
- package/dist/types/components/table/table.d.ts +872 -0
- package/dist/types/components/tag-picker/field-adapter.d.ts +5 -0
- package/dist/types/components/tag-picker/tag-picker.d.ts +375 -0
- package/dist/types/components/timebox/field-adapter.d.ts +5 -0
- package/dist/types/components/timebox/timebox.d.ts +121 -0
- package/dist/types/components/toggle/field-adapter.d.ts +5 -0
- package/dist/types/components/toggle/toggle.d.ts +94 -0
- package/dist/types/components/toolbar/toolbar.d.ts +230 -0
- package/dist/types/components/tooltip/tooltip.d.ts +183 -0
- package/dist/types/components/tree/hierarchy.d.ts +113 -0
- package/dist/types/components/tree/tree.d.ts +383 -0
- package/dist/types/components/truncate/truncate.d.ts +61 -0
- package/dist/types/components/value-list/field-adapter.d.ts +5 -0
- package/dist/types/components/value-list/value-list.d.ts +143 -0
- package/dist/types/core/breakpoint.d.ts +68 -0
- package/dist/types/core/component.d.ts +115 -0
- package/dist/types/core/date.d.ts +50 -0
- package/dist/types/core/dom.d.ts +86 -0
- package/dist/types/core/export.d.ts +70 -0
- package/dist/types/core/fontawesome.d.ts +107 -0
- package/dist/types/core/format.d.ts +107 -0
- package/dist/types/core/http.d.ts +122 -0
- package/dist/types/core/i18n.d.ts +35 -0
- package/dist/types/core/icons.d.ts +137 -0
- package/dist/types/core/keyboard.d.ts +72 -0
- package/dist/types/core/position.d.ts +45 -0
- package/dist/types/core/storage.d.ts +46 -0
- package/dist/types/core/util.d.ts +117 -0
- package/dist/types/elements/define.d.ts +73 -0
- package/dist/types/elements/reflect.d.ts +27 -0
- package/dist/types/index.d.ts +79 -0
- package/dist/types/zeyos/connect.d.ts +65 -0
- package/dist/types/zeyos/form.d.ts +140 -0
- package/dist/types/zeyos/icons.d.ts +104 -0
- package/dist/types/zeyos/index.d.ts +12 -0
- package/dist/types/zeyos/modules.d.ts +110 -0
- package/dist/types/zeyos/query.d.ts +157 -0
- package/dist/types/zeyos/schema.d.ts +79 -0
- package/dist/types/zeyos/select.d.ts +167 -0
- package/dist/types/zeyos/table.d.ts +205 -0
- package/dist/zx-compat.esm.js +375 -39
- package/dist/zx-compat.esm.min.js +1 -1
- package/dist/zx-compat.global.js +372 -73
- package/dist/zx-compat.global.min.js +3 -3
- package/dist/zx-zeyos.esm.js +355 -49
- package/dist/zx-zeyos.esm.min.js +1 -1
- package/dist/zx.css +68 -6
- package/dist/zx.esm.js +359 -73
- package/dist/zx.esm.min.js +3 -3
- package/dist/zx.global.js +359 -73
- package/dist/zx.global.min.js +3 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +48 -2
- package/docs/llms.md +31 -0
- package/package.json +37 -9
- package/src/compat/base.js +291 -0
- package/src/compat/globals.js +165 -0
- package/src/compat/index.js +84 -0
- package/src/compat/map/basic.js +464 -0
- package/src/compat/map/data.js +232 -0
- package/src/compat/map/date-time.js +177 -0
- package/src/compat/map/factory.js +45 -0
- package/src/compat/map/form.js +330 -0
- package/src/compat/map/helpers.js +46 -0
- package/src/compat/map/http.js +117 -0
- package/src/compat/map/layout.js +256 -0
- package/src/compat/map/options.js +267 -0
- package/src/compat/map/select.js +198 -0
- package/src/compat/map/stubs.js +26 -0
- package/src/compat/map/utilities.js +113 -0
- package/src/compat-entry.js +11 -0
- package/src/components/badge/badge.css +147 -0
- package/src/components/badge/badge.js +92 -0
- package/src/components/breadcrumb/breadcrumb.css +105 -0
- package/src/components/breadcrumb/breadcrumb.js +331 -0
- package/src/components/button/button.css +104 -0
- package/src/components/button/button.js +76 -0
- package/src/components/check-button/check-button.css +66 -0
- package/src/components/check-button/check-button.js +167 -0
- package/src/components/checklist/checklist.css +65 -0
- package/src/components/checklist/checklist.js +282 -0
- package/src/components/checklist/field-adapter.js +46 -0
- package/src/components/context-menu/context-menu.css +54 -0
- package/src/components/context-menu/context-menu.js +334 -0
- package/src/components/copy/copy-button.css +27 -0
- package/src/components/copy/copy-button.js +78 -0
- package/src/components/copy/copy-input.css +59 -0
- package/src/components/copy/copy-input.js +123 -0
- package/src/components/data-filter/data-filter.css +53 -0
- package/src/components/data-filter/data-filter.js +400 -0
- package/src/components/data-filter/filter-core.js +128 -0
- package/src/components/date-picker/date-picker.css +181 -0
- package/src/components/date-picker/date-picker.js +500 -0
- package/src/components/date-picker/date-range-picker.css +264 -0
- package/src/components/date-picker/date-range-picker.js +990 -0
- package/src/components/date-picker/field-adapter.js +36 -0
- package/src/components/date-picker/month-picker.js +223 -0
- package/src/components/date-picker/range-field-adapter.js +31 -0
- package/src/components/date-picker/time-picker.css +191 -0
- package/src/components/date-picker/time-picker.js +406 -0
- package/src/components/datebox/date-range-box.css +128 -0
- package/src/components/datebox/date-range-box.js +492 -0
- package/src/components/datebox/datebox.css +108 -0
- package/src/components/datebox/datebox.js +358 -0
- package/src/components/datebox/field-adapter.js +34 -0
- package/src/components/dialog/dialog.css +74 -0
- package/src/components/dialog/dialog.js +450 -0
- package/src/components/dropdown/dropdown.css +24 -0
- package/src/components/dropdown/dropdown.js +288 -0
- package/src/components/empty-state/empty-state.css +80 -0
- package/src/components/empty-state/empty-state.js +92 -0
- package/src/components/field/field.css +127 -0
- package/src/components/field/field.js +605 -0
- package/src/components/field-upload/field-adapter.js +21 -0
- package/src/components/field-upload/field-upload.css +108 -0
- package/src/components/field-upload/field-upload.js +475 -0
- package/src/components/fieldset/fieldset.css +37 -0
- package/src/components/fieldset/fieldset.js +307 -0
- package/src/components/finder/finder.css +98 -0
- package/src/components/finder/finder.js +509 -0
- package/src/components/form/form.css +32 -0
- package/src/components/form/form.js +302 -0
- package/src/components/groupbox/groupbox.css +51 -0
- package/src/components/groupbox/groupbox.js +199 -0
- package/src/components/layout/layout.css +117 -0
- package/src/components/layout/layout.js +136 -0
- package/src/components/loading/inline-loading.css +34 -0
- package/src/components/loading/inline-loading.js +140 -0
- package/src/components/loading/progress-bar.css +115 -0
- package/src/components/loading/progress-bar.js +259 -0
- package/src/components/loading/spinner.css +58 -0
- package/src/components/loading/spinner.js +57 -0
- package/src/components/master-panel/master-panel.css +51 -0
- package/src/components/master-panel/master-panel.js +203 -0
- package/src/components/menu-button/menu-button.css +49 -0
- package/src/components/menu-button/menu-button.js +294 -0
- package/src/components/message/message.css +122 -0
- package/src/components/message/message.js +499 -0
- package/src/components/modal/modal.css +47 -0
- package/src/components/modal/modal.js +203 -0
- package/src/components/multi-value-editor/field-adapter.js +44 -0
- package/src/components/multi-value-editor/multi-value-editor.css +56 -0
- package/src/components/multi-value-editor/multi-value-editor.js +170 -0
- package/src/components/navigation-bar/navigation-bar.css +130 -0
- package/src/components/navigation-bar/navigation-bar.js +450 -0
- package/src/components/number-field/field-adapter.js +40 -0
- package/src/components/number-field/number-field.css +77 -0
- package/src/components/number-field/number-field.js +545 -0
- package/src/components/pagination/pagination.css +95 -0
- package/src/components/pagination/pagination.js +481 -0
- package/src/components/panel/panel.css +123 -0
- package/src/components/panel/panel.js +336 -0
- package/src/components/permission/permission.css +47 -0
- package/src/components/permission/permission.js +198 -0
- package/src/components/rating/field-adapter.js +34 -0
- package/src/components/rating/rating.css +97 -0
- package/src/components/rating/rating.js +395 -0
- package/src/components/search/search.css +70 -0
- package/src/components/search/search.js +193 -0
- package/src/components/select/field-adapter.js +24 -0
- package/src/components/select/filter.js +39 -0
- package/src/components/select/select.css +180 -0
- package/src/components/select/select.js +663 -0
- package/src/components/skeleton/skeleton.css +76 -0
- package/src/components/skeleton/skeleton.js +139 -0
- package/src/components/slider/field-adapter.js +36 -0
- package/src/components/slider/slider.css +181 -0
- package/src/components/slider/slider.js +399 -0
- package/src/components/split-view/split-view.css +139 -0
- package/src/components/split-view/split-view.js +806 -0
- package/src/components/stepper/stepper.css +234 -0
- package/src/components/stepper/stepper.js +459 -0
- package/src/components/stepper/steps.js +131 -0
- package/src/components/tabbox/tabbox.css +281 -0
- package/src/components/tabbox/tabbox.js +484 -0
- package/src/components/table/sort.js +85 -0
- package/src/components/table/table.css +364 -0
- package/src/components/table/table.js +1711 -0
- package/src/components/tag-picker/field-adapter.js +35 -0
- package/src/components/tag-picker/tag-picker.css +169 -0
- package/src/components/tag-picker/tag-picker.js +837 -0
- package/src/components/timebox/field-adapter.js +24 -0
- package/src/components/timebox/timebox.css +51 -0
- package/src/components/timebox/timebox.js +276 -0
- package/src/components/toggle/field-adapter.js +24 -0
- package/src/components/toggle/toggle.css +66 -0
- package/src/components/toggle/toggle.js +150 -0
- package/src/components/toolbar/toolbar.css +81 -0
- package/src/components/toolbar/toolbar.js +511 -0
- package/src/components/tooltip/tooltip.css +36 -0
- package/src/components/tooltip/tooltip.js +420 -0
- package/src/components/tree/hierarchy.js +151 -0
- package/src/components/tree/tree.css +99 -0
- package/src/components/tree/tree.js +784 -0
- package/src/components/truncate/truncate.css +20 -0
- package/src/components/truncate/truncate.js +92 -0
- package/src/components/value-list/field-adapter.js +24 -0
- package/src/components/value-list/value-list.css +108 -0
- package/src/components/value-list/value-list.js +336 -0
- package/src/core/breakpoint.js +150 -0
- package/src/core/component.js +292 -0
- package/src/core/date.js +216 -0
- package/src/core/dom.js +260 -0
- package/src/core/export.js +204 -0
- package/src/core/fontawesome.js +177 -0
- package/src/core/format.js +283 -0
- package/src/core/http.js +246 -0
- package/src/core/i18n.js +83 -0
- package/src/core/icons.js +283 -0
- package/src/core/keyboard.js +240 -0
- package/src/core/position.js +177 -0
- package/src/core/storage.js +175 -0
- package/src/core/util.js +336 -0
- package/src/elements/define.js +715 -0
- package/src/elements/reflect.js +79 -0
- package/src/index.js +131 -0
- package/src/zeyos/connect.js +142 -0
- package/src/zeyos/form.js +254 -0
- package/src/zeyos/icons.js +92 -0
- package/src/zeyos/index.js +21 -0
- package/src/zeyos/modules.js +269 -0
- package/src/zeyos/query.js +199 -0
- package/src/zeyos/schema.js +474 -0
- package/src/zeyos/select.js +175 -0
- package/src/zeyos/table.js +272 -0
- package/styles/base.css +124 -0
- package/styles/icons.css +34 -0
- package/styles/tokens/dark.css +84 -0
- package/styles/tokens/density.css +9 -0
- package/styles/tokens/global.css +80 -0
- package/styles/tokens/modules.css +109 -0
- package/styles/tokens/semantic.css +49 -0
- package/styles/zx.css +61 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { Component } from '../../core/component.js';
|
|
2
|
+
import { h, restoreTarget, snapshotTarget } from '../../core/dom.js';
|
|
3
|
+
import { clamp, uid } from '../../core/util.js';
|
|
4
|
+
import { snapNumber } from '../number-field/number-field.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} SliderMark
|
|
8
|
+
* @property {number} value Position on the scale.
|
|
9
|
+
* @property {string} [label] Text drawn under the tick; the value is used when omitted.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {Object} SliderOptions
|
|
14
|
+
* @property {number} [value=0] Initial value, clamped to the range and snapped to `step`.
|
|
15
|
+
* @property {number} [min=0] Lowest selectable value.
|
|
16
|
+
* @property {number} [max=100] Highest selectable value.
|
|
17
|
+
* @property {number} [step=1] Increment between selectable values.
|
|
18
|
+
* @property {string} [label=''] Visible name of the control.
|
|
19
|
+
* @property {boolean} [hideLabel=false] Whether the label is kept for assistive technology only.
|
|
20
|
+
* @property {boolean} [showValue=true] Whether the current value is drawn opposite the label.
|
|
21
|
+
* @property {boolean} [showBounds=false] Whether `min` and `max` are drawn either side of the track.
|
|
22
|
+
* @property {boolean} [showInput=false] Whether a number box is drawn beside the track, for
|
|
23
|
+
* entering a value precisely rather than dragging to it.
|
|
24
|
+
* @property {string} [unit=''] Suffix appended to the readout.
|
|
25
|
+
* @property {Array<number|SliderMark>|null} [marks=null] Labelled positions under the track.
|
|
26
|
+
* @property {boolean} [disabled=false] Whether the control is disabled.
|
|
27
|
+
* @property {boolean} [readonly=false] Whether the value is displayed but cannot be changed.
|
|
28
|
+
* @property {'md'|'sm'} [size='md'] Control size.
|
|
29
|
+
* @property {((value: number) => string)|null} [formatValue=null] Replaces the default readout.
|
|
30
|
+
* @property {(event: CustomEvent<{value: number}>) => void} [onchange] Committed-value listener.
|
|
31
|
+
* @property {(event: CustomEvent<{value: number}>) => void} [oninput] Listener called while dragging.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Range control for a bounded numeric value — a discount rate, a threshold, a weighting.
|
|
36
|
+
*
|
|
37
|
+
* Built on a native `<input type="range">`, which is where the whole keyboard map comes from:
|
|
38
|
+
* arrows step, Page Up/Page Down jump, Home and End go to the bounds, and the value is announced
|
|
39
|
+
* as a slider without a line of ARIA. Everything Zx adds is chrome around it — the filled track,
|
|
40
|
+
* the readout, optional ticks, and an optional number box for entering a value exactly.
|
|
41
|
+
*
|
|
42
|
+
* @fires Slider#change
|
|
43
|
+
* @fires Slider#input
|
|
44
|
+
* @extends {Component<SliderOptions>}
|
|
45
|
+
*/
|
|
46
|
+
export class Slider extends Component {
|
|
47
|
+
static cssName = 'slider';
|
|
48
|
+
|
|
49
|
+
/** @type {SliderOptions} */
|
|
50
|
+
static defaults = {
|
|
51
|
+
value: 0,
|
|
52
|
+
min: 0,
|
|
53
|
+
max: 100,
|
|
54
|
+
step: 1,
|
|
55
|
+
label: '',
|
|
56
|
+
hideLabel: false,
|
|
57
|
+
showValue: true,
|
|
58
|
+
showBounds: false,
|
|
59
|
+
showInput: false,
|
|
60
|
+
unit: '',
|
|
61
|
+
marks: null,
|
|
62
|
+
disabled: false,
|
|
63
|
+
readonly: false,
|
|
64
|
+
size: 'md',
|
|
65
|
+
formatValue: null
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/** @returns {HTMLElement} */
|
|
69
|
+
render() {
|
|
70
|
+
// render() runs inside the base constructor, before class-field initializers would run.
|
|
71
|
+
this._value = 0;
|
|
72
|
+
this._readonly = Boolean(this.options.readonly);
|
|
73
|
+
this._createdRoot = this.el === null;
|
|
74
|
+
this._snapshot = this._createdRoot ? null : snapshotTarget(this.el);
|
|
75
|
+
|
|
76
|
+
const root = /** @type {HTMLElement} */ (this.el ?? h('div'));
|
|
77
|
+
this.el = root;
|
|
78
|
+
|
|
79
|
+
this._min = Number(this.options.min) || 0;
|
|
80
|
+
this._max = Number(this.options.max);
|
|
81
|
+
if (!Number.isFinite(this._max) || this._max <= this._min) this._max = this._min + 100;
|
|
82
|
+
this._step = Math.abs(Number(this.options.step)) || 1;
|
|
83
|
+
this._id = uid('zx-slider');
|
|
84
|
+
|
|
85
|
+
const input = /** @type {HTMLInputElement} */ (h('input', {
|
|
86
|
+
ref: 'input',
|
|
87
|
+
class: 'zx-slider__input',
|
|
88
|
+
type: 'range',
|
|
89
|
+
id: this._id,
|
|
90
|
+
min: String(this._min),
|
|
91
|
+
max: String(this._max),
|
|
92
|
+
step: String(this._step),
|
|
93
|
+
disabled: Boolean(this.options.disabled)
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
const track = h('div', { class: 'zx-slider__track' }, input, this._marks());
|
|
97
|
+
const control = h('div', { class: 'zx-slider__control' });
|
|
98
|
+
if (this.options.showBounds) {
|
|
99
|
+
control.append(h('span', { class: 'zx-slider__bound', ariaHidden: 'true' },
|
|
100
|
+
this._format(this._min)));
|
|
101
|
+
}
|
|
102
|
+
control.append(track);
|
|
103
|
+
if (this.options.showBounds) {
|
|
104
|
+
control.append(h('span', { class: 'zx-slider__bound', ariaHidden: 'true' },
|
|
105
|
+
this._format(this._max)));
|
|
106
|
+
}
|
|
107
|
+
if (this.options.showInput) control.append(this._numberBox());
|
|
108
|
+
|
|
109
|
+
root.replaceChildren(
|
|
110
|
+
h('div', { class: 'zx-slider__head' },
|
|
111
|
+
h('label', { ref: 'label', class: 'zx-slider__label', for: this._id },
|
|
112
|
+
String(this.options.label ?? '')),
|
|
113
|
+
h('span', { ref: 'output', class: 'zx-slider__value', ariaHidden: 'true' })
|
|
114
|
+
),
|
|
115
|
+
control
|
|
116
|
+
);
|
|
117
|
+
root.dataset.size = this.options.size === 'sm' ? 'sm' : 'md';
|
|
118
|
+
root.toggleAttribute('data-hide-label', Boolean(this.options.hideLabel));
|
|
119
|
+
|
|
120
|
+
this.listen(input, 'input', () => this._onInput());
|
|
121
|
+
this.listen(input, 'change', () => this._onCommit());
|
|
122
|
+
// A range input has no readonly state of its own, so an edit is taken and put straight back.
|
|
123
|
+
this.listen(input, 'keydown', (event) => {
|
|
124
|
+
if (this._readonly && CHANGE_KEYS.has(/** @type {KeyboardEvent} */ (event).key)) {
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
this.set(this.options.value, { silent: true });
|
|
130
|
+
this._syncState();
|
|
131
|
+
return root;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Current value. @returns {number} */
|
|
135
|
+
get value() {
|
|
136
|
+
return this._value;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** @param {number} next Next value. */
|
|
140
|
+
set value(next) {
|
|
141
|
+
this.set(next);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Returns the current value.
|
|
146
|
+
* @returns {number}
|
|
147
|
+
*/
|
|
148
|
+
get() {
|
|
149
|
+
return this._value;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Sets the value, snapped to `step` and clamped to the range.
|
|
154
|
+
* @param {number} next Next value.
|
|
155
|
+
* @param {{silent?: boolean}} [options={}] Set `silent` to suppress `change`.
|
|
156
|
+
* @returns {this}
|
|
157
|
+
* @fires Slider#change
|
|
158
|
+
*/
|
|
159
|
+
set(next, { silent = false } = {}) {
|
|
160
|
+
const value = this._snap(next);
|
|
161
|
+
const changed = value !== this._value;
|
|
162
|
+
this._value = value;
|
|
163
|
+
this._paint();
|
|
164
|
+
if (changed && !silent) this.emit('change', { value });
|
|
165
|
+
return this;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Replaces the range, re-snapping the current value into it.
|
|
170
|
+
* @param {number} min Lowest selectable value.
|
|
171
|
+
* @param {number} max Highest selectable value.
|
|
172
|
+
* @param {number} [step] Increment; the current one is kept when omitted.
|
|
173
|
+
* @returns {this}
|
|
174
|
+
*/
|
|
175
|
+
setRange(min, max, step) {
|
|
176
|
+
const low = Number(min);
|
|
177
|
+
const high = Number(max);
|
|
178
|
+
if (!Number.isFinite(low) || !Number.isFinite(high) || high <= low) {
|
|
179
|
+
throw new RangeError('Slider range requires min < max');
|
|
180
|
+
}
|
|
181
|
+
this._min = low;
|
|
182
|
+
this._max = high;
|
|
183
|
+
if (step !== undefined) this._step = Math.abs(Number(step)) || 1;
|
|
184
|
+
const { input } = this.refs;
|
|
185
|
+
input.min = String(this._min);
|
|
186
|
+
input.max = String(this._max);
|
|
187
|
+
input.step = String(this._step);
|
|
188
|
+
for (const [index, bound] of [...this.el.querySelectorAll('.zx-slider__bound')].entries()) {
|
|
189
|
+
bound.textContent = this._format(index === 0 ? this._min : this._max);
|
|
190
|
+
}
|
|
191
|
+
return this.set(this._value, { silent: true });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Focuses the track. @returns {this} */
|
|
195
|
+
focus() {
|
|
196
|
+
this.refs.input.focus();
|
|
197
|
+
return this;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Enables user interaction. @returns {this} */
|
|
201
|
+
enable() {
|
|
202
|
+
this.refs.input.disabled = false;
|
|
203
|
+
if (this.refs.number) this.refs.number.disabled = false;
|
|
204
|
+
this._syncState();
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Disables user interaction. @returns {this} */
|
|
209
|
+
disable() {
|
|
210
|
+
this.refs.input.disabled = true;
|
|
211
|
+
if (this.refs.number) this.refs.number.disabled = true;
|
|
212
|
+
this._syncState();
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Sets the read-only state: the value stays focusable and announced, but cannot be changed.
|
|
218
|
+
* @param {boolean} readonly Whether the value is fixed.
|
|
219
|
+
* @returns {this}
|
|
220
|
+
*/
|
|
221
|
+
setReadonly(readonly) {
|
|
222
|
+
this._readonly = Boolean(readonly);
|
|
223
|
+
if (this.refs.number) this.refs.number.readOnly = this._readonly;
|
|
224
|
+
this._syncState();
|
|
225
|
+
return this;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Replaces the visible label.
|
|
230
|
+
* @param {string} label Control name.
|
|
231
|
+
* @returns {this}
|
|
232
|
+
*/
|
|
233
|
+
setLabel(label) {
|
|
234
|
+
this.refs.label.textContent = String(label ?? '');
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** @returns {HTMLInputElement} */
|
|
239
|
+
_numberBox() {
|
|
240
|
+
const number = /** @type {HTMLInputElement} */ (h('input', {
|
|
241
|
+
ref: 'number',
|
|
242
|
+
class: 'zx-slider__number',
|
|
243
|
+
type: 'number',
|
|
244
|
+
min: String(this._min),
|
|
245
|
+
max: String(this._max),
|
|
246
|
+
step: String(this._step),
|
|
247
|
+
disabled: Boolean(this.options.disabled),
|
|
248
|
+
readOnly: this._readonly,
|
|
249
|
+
ariaLabel: String(this.options.label ?? 'Value')
|
|
250
|
+
}));
|
|
251
|
+
this.listen(number, 'input', () => {
|
|
252
|
+
if (this._readonly) return;
|
|
253
|
+
const raw = Number(number.value);
|
|
254
|
+
if (number.value === '' || !Number.isFinite(raw)) return;
|
|
255
|
+
this._value = this._snap(raw);
|
|
256
|
+
this.refs.input.value = String(this._value);
|
|
257
|
+
this._paintTrack();
|
|
258
|
+
this.emit('input', { value: this._value });
|
|
259
|
+
});
|
|
260
|
+
// Snapping on the way out, so typing "5" on the way to "50" is not rewritten mid-keystroke.
|
|
261
|
+
this.listen(number, 'change', () => {
|
|
262
|
+
if (this._readonly) {
|
|
263
|
+
number.value = String(this._value);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
this.set(number.value === '' ? this._min : Number(number.value));
|
|
267
|
+
});
|
|
268
|
+
return number;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** @returns {HTMLElement|null} */
|
|
272
|
+
_marks() {
|
|
273
|
+
const marks = this.options.marks;
|
|
274
|
+
if (!Array.isArray(marks) || marks.length === 0) return null;
|
|
275
|
+
const element = h('div', { class: 'zx-slider__marks', ariaHidden: 'true' });
|
|
276
|
+
for (const mark of marks) {
|
|
277
|
+
const value = typeof mark === 'number' ? mark : Number(mark?.value);
|
|
278
|
+
if (!Number.isFinite(value)) continue;
|
|
279
|
+
const label = typeof mark === 'number' ? this._format(value) : String(mark.label ?? this._format(value));
|
|
280
|
+
element.append(h('span', {
|
|
281
|
+
class: 'zx-slider__mark',
|
|
282
|
+
style: { '--zx-slider-mark': `${this._ratio(value) * 100}%` }
|
|
283
|
+
}, label));
|
|
284
|
+
}
|
|
285
|
+
return element;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** @returns {void} */
|
|
289
|
+
_onInput() {
|
|
290
|
+
if (this._readonly) {
|
|
291
|
+
this.refs.input.value = String(this._value);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
this._value = this._snap(this.refs.input.value);
|
|
295
|
+
this._paintTrack();
|
|
296
|
+
if (this.refs.number) this.refs.number.value = String(this._value);
|
|
297
|
+
this.emit('input', { value: this._value });
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** @returns {void} */
|
|
301
|
+
_onCommit() {
|
|
302
|
+
if (this._readonly) {
|
|
303
|
+
this.refs.input.value = String(this._value);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
this.emit('change', { value: this._value });
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Writes the value into the input, the readout, and the fill. @returns {void} */
|
|
310
|
+
_paint() {
|
|
311
|
+
this.refs.input.value = String(this._value);
|
|
312
|
+
if (this.refs.number) this.refs.number.value = String(this._value);
|
|
313
|
+
this._paintTrack();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** @returns {void} */
|
|
317
|
+
_paintTrack() {
|
|
318
|
+
this.el.style.setProperty('--zx-slider-fill', `${this._ratio(this._value) * 100}%`);
|
|
319
|
+
const { output } = this.refs;
|
|
320
|
+
output.textContent = this.options.showValue ? this._format(this._value) : '';
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/** @returns {void} */
|
|
324
|
+
_syncState() {
|
|
325
|
+
const disabled = this.refs.input.disabled;
|
|
326
|
+
this.el.toggleAttribute('data-disabled', disabled);
|
|
327
|
+
this.el.toggleAttribute('data-readonly', this._readonly);
|
|
328
|
+
this.refs.input.setAttribute('aria-readonly', String(this._readonly));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Snaps a raw value onto the step grid and clamps it to the range.
|
|
333
|
+
* @param {unknown} raw Value to snap.
|
|
334
|
+
* @returns {number}
|
|
335
|
+
*/
|
|
336
|
+
_snap(raw) {
|
|
337
|
+
const value = Number(raw);
|
|
338
|
+
if (!Number.isFinite(value)) return this._min;
|
|
339
|
+
return snapNumber(value, {
|
|
340
|
+
min: this._min,
|
|
341
|
+
max: this._max,
|
|
342
|
+
step: this._step,
|
|
343
|
+
precision: stepPrecision(this._step)
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/** @param {number} value @returns {number} */
|
|
348
|
+
_ratio(value) {
|
|
349
|
+
return clamp((value - this._min) / (this._max - this._min), 0, 1);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** @param {number} value @returns {string} */
|
|
353
|
+
_format(value) {
|
|
354
|
+
const formatter = this.options.formatValue;
|
|
355
|
+
if (typeof formatter === 'function') return String(formatter(value));
|
|
356
|
+
return `${trimFloat(value)}${this.options.unit ?? ''}`;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** Restores an enhanced target to the markup it had before the takeover. @returns {void} */
|
|
360
|
+
destroy() {
|
|
361
|
+
const root = this.el;
|
|
362
|
+
super.destroy();
|
|
363
|
+
if (!this._createdRoot && root) restoreTarget(root, this._snapshot);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Value committed — the pointer was released, or the keyboard moved the thumb.
|
|
369
|
+
* @event Slider#change
|
|
370
|
+
* @type {CustomEvent<{value: number}>}
|
|
371
|
+
*/
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Value while dragging, before it is committed.
|
|
375
|
+
* @event Slider#input
|
|
376
|
+
* @type {CustomEvent<{value: number}>}
|
|
377
|
+
*/
|
|
378
|
+
|
|
379
|
+
/** Keys a range input would act on, blocked while the slider is read-only. */
|
|
380
|
+
const CHANGE_KEYS = new Set([
|
|
381
|
+
'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'PageUp', 'PageDown', 'Home', 'End'
|
|
382
|
+
]);
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Decimal places a step carries, so a 0.1 step snaps to 0.3 rather than 0.30000000000000004.
|
|
386
|
+
* @param {number} step Step size.
|
|
387
|
+
* @returns {number}
|
|
388
|
+
*/
|
|
389
|
+
export function stepPrecision(step) {
|
|
390
|
+
const text = String(step);
|
|
391
|
+
const exponent = /e-(\d+)$/i.exec(text);
|
|
392
|
+
if (exponent) return Number(exponent[1]);
|
|
393
|
+
return (text.split('.')[1] ?? '').length;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** @param {number} value @returns {string} */
|
|
397
|
+
function trimFloat(value) {
|
|
398
|
+
return String(Number(value.toFixed(6)));
|
|
399
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* One grid, three tracks, one variable: `--zx-split-size` sizes the start pane, the divider takes
|
|
3
|
+
* its intrinsic thickness, and the end pane takes the rest. A drag therefore writes a single
|
|
4
|
+
* custom property per frame instead of two widths.
|
|
5
|
+
*
|
|
6
|
+
* The root has no height of its own — give it one (a grid row, `block-size: 100%`, a flex child)
|
|
7
|
+
* when the panes should fill a shell rather than grow with their content.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
.zx-split-view {
|
|
11
|
+
--zx-split-view-divider-size: var(--zx-space-2);
|
|
12
|
+
--zx-split-view-divider-line: 1px;
|
|
13
|
+
display: grid;
|
|
14
|
+
min-inline-size: 0;
|
|
15
|
+
min-block-size: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.zx-split-view[data-orientation="horizontal"] {
|
|
19
|
+
grid-template-columns: var(--zx-split-size, 38%) auto minmax(0, 1fr);
|
|
20
|
+
grid-template-rows: minmax(0, 1fr);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.zx-split-view[data-orientation="vertical"] {
|
|
24
|
+
grid-template-columns: minmax(0, 1fr);
|
|
25
|
+
grid-template-rows: var(--zx-split-size, 38%) auto minmax(0, 1fr);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* A collapsed pane keeps its grid slot at zero so the divider never changes track. */
|
|
29
|
+
.zx-split-view[data-orientation="horizontal"][data-collapsed="start"] {
|
|
30
|
+
grid-template-columns: 0 auto minmax(0, 1fr);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.zx-split-view[data-orientation="horizontal"][data-collapsed="end"] {
|
|
34
|
+
grid-template-columns: minmax(0, 1fr) auto 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.zx-split-view[data-orientation="vertical"][data-collapsed="start"] {
|
|
38
|
+
grid-template-rows: 0 auto minmax(0, 1fr);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.zx-split-view[data-orientation="vertical"][data-collapsed="end"] {
|
|
42
|
+
grid-template-rows: minmax(0, 1fr) auto 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.zx-split-view__pane {
|
|
46
|
+
overflow: auto;
|
|
47
|
+
/* Grid items refuse to shrink below min-content without this, which would blow the track. */
|
|
48
|
+
min-inline-size: 0;
|
|
49
|
+
min-block-size: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Hidden rather than clipped: a zero-width pane would still hand its buttons to the tab order. */
|
|
53
|
+
.zx-split-view[data-collapsed="start"] > .zx-split-view__pane[data-pane="start"],
|
|
54
|
+
.zx-split-view[data-collapsed="end"] > .zx-split-view__pane[data-pane="end"] {
|
|
55
|
+
visibility: hidden;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.zx-split-view__divider {
|
|
59
|
+
position: relative;
|
|
60
|
+
/* The hit area is wider than the line it draws, and never scrolls or zooms under a drag. */
|
|
61
|
+
touch-action: none;
|
|
62
|
+
/* A press that starts on a non-selectable element never begins a text selection, which is why
|
|
63
|
+
the component can leave `pointerdown` uncancelled and keep its double-click reset. */
|
|
64
|
+
user-select: none;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.zx-split-view__divider::before {
|
|
68
|
+
content: "";
|
|
69
|
+
position: absolute;
|
|
70
|
+
background: var(--zx-color-border);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.zx-split-view[data-orientation="horizontal"] > .zx-split-view__divider {
|
|
74
|
+
inline-size: var(--zx-split-view-divider-size);
|
|
75
|
+
cursor: col-resize;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.zx-split-view[data-orientation="horizontal"] > .zx-split-view__divider::before {
|
|
79
|
+
inset-block: 0;
|
|
80
|
+
inset-inline-start: calc(50% - (var(--zx-split-view-divider-line) / 2));
|
|
81
|
+
inline-size: var(--zx-split-view-divider-line);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.zx-split-view[data-orientation="vertical"] > .zx-split-view__divider {
|
|
85
|
+
block-size: var(--zx-split-view-divider-size);
|
|
86
|
+
cursor: row-resize;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.zx-split-view[data-orientation="vertical"] > .zx-split-view__divider::before {
|
|
90
|
+
inset-inline: 0;
|
|
91
|
+
inset-block-start: calc(50% - (var(--zx-split-view-divider-line) / 2));
|
|
92
|
+
block-size: var(--zx-split-view-divider-line);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.zx-split-view__divider:hover::before,
|
|
96
|
+
.zx-split-view[data-dragging="true"] > .zx-split-view__divider::before {
|
|
97
|
+
--zx-split-view-divider-line: 2px;
|
|
98
|
+
background: var(--zx-color-accent);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.zx-split-view__divider:focus-visible {
|
|
102
|
+
outline: 0;
|
|
103
|
+
box-shadow: var(--zx-focus-ring);
|
|
104
|
+
/* The ring sits outside an 8px-wide element, so it must draw over both panes. */
|
|
105
|
+
z-index: 1;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.zx-split-view__divider:focus-visible::before {
|
|
109
|
+
background: var(--zx-color-accent);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.zx-split-view__divider[aria-disabled="true"] {
|
|
113
|
+
cursor: default;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.zx-split-view__divider[aria-disabled="true"]:hover::before {
|
|
117
|
+
--zx-split-view-divider-line: 1px;
|
|
118
|
+
background: var(--zx-color-border);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* While dragging, the pointer owns the whole shell: no text selection, no cursor flicker as it
|
|
122
|
+
crosses out of the divider's own box. */
|
|
123
|
+
.zx-split-view[data-dragging="true"] {
|
|
124
|
+
user-select: none;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.zx-split-view[data-orientation="horizontal"][data-dragging="true"] {
|
|
128
|
+
cursor: col-resize;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.zx-split-view[data-orientation="vertical"][data-dragging="true"] {
|
|
132
|
+
cursor: row-resize;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
136
|
+
.zx-split-view__divider::before {
|
|
137
|
+
transition: background-color var(--zx-dur-fast) var(--zx-ease);
|
|
138
|
+
}
|
|
139
|
+
}
|