@neumorphism-ui/elements 1.0.0-next.1 → 1.0.0-next.3

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.
Files changed (183) hide show
  1. package/README.md +12 -1
  2. package/cdn/neu.min.js +176 -51
  3. package/custom-elements.json +2555 -358
  4. package/dist/all.d.ts +8 -0
  5. package/dist/all.js +8 -0
  6. package/dist/checkbox.d.ts +3 -0
  7. package/dist/checkbox.js +4 -0
  8. package/dist/components/avatar/avatar.d.ts +0 -3
  9. package/dist/components/avatar/avatar.def.d.ts +0 -3
  10. package/dist/components/avatar/avatar.def.js +4 -18
  11. package/dist/components/avatar/avatar.docs.d.ts +2 -0
  12. package/dist/components/avatar/avatar.docs.js +22 -0
  13. package/dist/components/avatar/avatar.js +7 -1
  14. package/dist/components/badge/badge.d.ts +0 -2
  15. package/dist/components/badge/badge.def.d.ts +0 -2
  16. package/dist/components/badge/badge.def.js +1 -14
  17. package/dist/components/badge/badge.docs.d.ts +2 -0
  18. package/dist/components/badge/badge.docs.js +17 -0
  19. package/dist/components/button/button.d.ts +0 -2
  20. package/dist/components/button/button.def.d.ts +0 -5
  21. package/dist/components/button/button.def.js +3 -25
  22. package/dist/components/button/button.docs.d.ts +2 -0
  23. package/dist/components/button/button.docs.js +29 -0
  24. package/dist/components/button/button.js +3 -36
  25. package/dist/components/button-group/button-group.d.ts +0 -2
  26. package/dist/components/button-group/button-group.def.d.ts +0 -2
  27. package/dist/components/button-group/button-group.def.js +1 -10
  28. package/dist/components/button-group/button-group.docs.d.ts +2 -0
  29. package/dist/components/button-group/button-group.docs.js +13 -0
  30. package/dist/components/checkbox/checkbox.d.ts +40 -0
  31. package/dist/components/checkbox/checkbox.def.d.ts +27 -0
  32. package/dist/components/checkbox/checkbox.def.js +21 -0
  33. package/dist/components/checkbox/checkbox.docs.d.ts +2 -0
  34. package/dist/components/checkbox/checkbox.docs.js +27 -0
  35. package/dist/components/checkbox/checkbox.js +40 -0
  36. package/dist/components/checkbox/checkbox.styles.d.ts +1 -0
  37. package/dist/components/checkbox/checkbox.styles.js +28 -0
  38. package/dist/components/divider/divider.d.ts +0 -1
  39. package/dist/components/divider/divider.def.d.ts +0 -1
  40. package/dist/components/divider/divider.def.js +0 -9
  41. package/dist/components/divider/divider.docs.d.ts +2 -0
  42. package/dist/components/divider/divider.docs.js +12 -0
  43. package/dist/components/icon/icon.d.ts +0 -3
  44. package/dist/components/icon/icon.def.d.ts +0 -3
  45. package/dist/components/icon/icon.def.js +3 -10
  46. package/dist/components/icon/icon.docs.d.ts +2 -0
  47. package/dist/components/icon/icon.docs.js +13 -0
  48. package/dist/components/icon/system-icons.d.ts +10 -0
  49. package/dist/components/icon/system-icons.js +22 -11
  50. package/dist/components/icon-button/icon-button.d.ts +0 -5
  51. package/dist/components/icon-button/icon-button.def.d.ts +0 -5
  52. package/dist/components/icon-button/icon-button.def.js +3 -17
  53. package/dist/components/icon-button/icon-button.docs.d.ts +2 -0
  54. package/dist/components/icon-button/icon-button.docs.js +26 -0
  55. package/dist/components/number-field/number-field.d.ts +79 -0
  56. package/dist/components/number-field/number-field.def.d.ts +115 -0
  57. package/dist/components/number-field/number-field.def.js +40 -0
  58. package/dist/components/number-field/number-field.docs.d.ts +2 -0
  59. package/dist/components/number-field/number-field.docs.js +45 -0
  60. package/dist/components/number-field/number-field.js +121 -0
  61. package/dist/components/number-field/number-field.styles.d.ts +1 -0
  62. package/dist/components/number-field/number-field.styles.js +15 -0
  63. package/dist/components/option/option-data.d.ts +8 -0
  64. package/dist/components/option/option-data.js +12 -0
  65. package/dist/components/option/option.d.ts +17 -0
  66. package/dist/components/option/option.def.d.ts +8 -0
  67. package/dist/components/option/option.def.js +12 -0
  68. package/dist/components/option/option.docs.d.ts +2 -0
  69. package/dist/components/option/option.docs.js +12 -0
  70. package/dist/components/option/option.js +17 -0
  71. package/dist/components/option/option.styles.d.ts +2 -0
  72. package/dist/components/option/option.styles.js +5 -0
  73. package/dist/components/radio/radio-link.d.ts +11 -0
  74. package/dist/components/radio/radio-link.js +5 -0
  75. package/dist/components/radio/radio.d.ts +27 -0
  76. package/dist/components/radio/radio.def.d.ts +9 -0
  77. package/dist/components/radio/radio.def.js +12 -0
  78. package/dist/components/radio/radio.docs.d.ts +2 -0
  79. package/dist/components/radio/radio.docs.js +18 -0
  80. package/dist/components/radio/radio.js +43 -0
  81. package/dist/components/radio/radio.styles.d.ts +1 -0
  82. package/dist/components/radio/radio.styles.js +21 -0
  83. package/dist/components/radio-group/radio-group.d.ts +76 -0
  84. package/dist/components/radio-group/radio-group.def.d.ts +36 -0
  85. package/dist/components/radio-group/radio-group.def.js +40 -0
  86. package/dist/components/radio-group/radio-group.docs.d.ts +2 -0
  87. package/dist/components/radio-group/radio-group.docs.js +37 -0
  88. package/dist/components/radio-group/radio-group.js +208 -0
  89. package/dist/components/radio-group/radio-group.styles.d.ts +1 -0
  90. package/dist/components/radio-group/radio-group.styles.js +13 -0
  91. package/dist/components/select/select.d.ts +115 -0
  92. package/dist/components/select/select.def.d.ts +34 -0
  93. package/dist/components/select/select.def.js +35 -0
  94. package/dist/components/select/select.docs.d.ts +2 -0
  95. package/dist/components/select/select.docs.js +65 -0
  96. package/dist/components/select/select.js +391 -0
  97. package/dist/components/select/select.styles.d.ts +1 -0
  98. package/dist/components/select/select.styles.js +35 -0
  99. package/dist/components/shared/checkable.d.ts +45 -0
  100. package/dist/components/shared/checkable.js +108 -0
  101. package/dist/components/shared/field.styles.d.ts +1 -0
  102. package/dist/components/shared/field.styles.js +34 -0
  103. package/dist/components/shared/press.d.ts +7 -0
  104. package/dist/components/shared/press.js +42 -0
  105. package/dist/components/shared/step.d.ts +2 -0
  106. package/dist/components/shared/step.js +2 -0
  107. package/dist/components/shared/text-control.d.ts +72 -0
  108. package/dist/components/shared/text-control.js +191 -0
  109. package/dist/components/slider/slider.d.ts +67 -0
  110. package/dist/components/slider/slider.def.d.ts +37 -0
  111. package/dist/components/slider/slider.def.js +54 -0
  112. package/dist/components/slider/slider.docs.d.ts +2 -0
  113. package/dist/components/slider/slider.docs.js +45 -0
  114. package/dist/components/slider/slider.js +170 -0
  115. package/dist/components/slider/slider.styles.d.ts +1 -0
  116. package/dist/components/slider/slider.styles.js +16 -0
  117. package/dist/components/spinner/spinner.d.ts +0 -1
  118. package/dist/components/spinner/spinner.def.d.ts +0 -1
  119. package/dist/components/spinner/spinner.def.js +1 -13
  120. package/dist/components/spinner/spinner.docs.d.ts +2 -0
  121. package/dist/components/spinner/spinner.docs.js +17 -0
  122. package/dist/components/surface/surface.d.ts +0 -4
  123. package/dist/components/surface/surface.def.d.ts +0 -4
  124. package/dist/components/surface/surface.def.js +3 -12
  125. package/dist/components/surface/surface.docs.d.ts +2 -0
  126. package/dist/components/surface/surface.docs.js +15 -0
  127. package/dist/components/switch/switch.d.ts +4 -35
  128. package/dist/components/switch/switch.def.d.ts +0 -5
  129. package/dist/components/switch/switch.def.js +5 -21
  130. package/dist/components/switch/switch.docs.d.ts +2 -0
  131. package/dist/components/switch/switch.docs.js +26 -0
  132. package/dist/components/switch/switch.js +5 -117
  133. package/dist/components/text-field/implicit-submit.d.ts +5 -0
  134. package/dist/components/text-field/implicit-submit.js +8 -3
  135. package/dist/components/text-field/text-field.d.ts +9 -42
  136. package/dist/components/text-field/text-field.def.d.ts +0 -12
  137. package/dist/components/text-field/text-field.def.js +5 -30
  138. package/dist/components/text-field/text-field.docs.d.ts +2 -0
  139. package/dist/components/text-field/text-field.docs.js +45 -0
  140. package/dist/components/text-field/text-field.js +21 -178
  141. package/dist/components/text-field/text-field.styles.d.ts +1 -1
  142. package/dist/components/text-field/text-field.styles.js +2 -35
  143. package/dist/components/textarea/textarea.d.ts +92 -0
  144. package/dist/components/textarea/textarea.def.d.ts +127 -0
  145. package/dist/components/textarea/textarea.def.js +44 -0
  146. package/dist/components/textarea/textarea.docs.d.ts +2 -0
  147. package/dist/components/textarea/textarea.docs.js +40 -0
  148. package/dist/components/textarea/textarea.js +101 -0
  149. package/dist/components/textarea/textarea.styles.d.ts +1 -0
  150. package/dist/components/textarea/textarea.styles.js +9 -0
  151. package/dist/components/theme-docs.d.ts +3 -0
  152. package/dist/components/theme-docs.js +8 -0
  153. package/dist/core/define.d.ts +20 -2
  154. package/dist/core/dom.d.ts +4 -0
  155. package/dist/core/dom.js +7 -0
  156. package/dist/core/form-control.js +6 -1
  157. package/dist/core/neu-element.d.ts +2 -2
  158. package/dist/core/neu-element.js +10 -7
  159. package/dist/core/props.d.ts +13 -1
  160. package/dist/core/props.js +13 -3
  161. package/dist/core/styles.d.ts +0 -2
  162. package/dist/core/styles.js +0 -7
  163. package/dist/core/validation.d.ts +6 -2
  164. package/dist/core/validation.js +15 -8
  165. package/dist/docs.d.ts +3 -0
  166. package/dist/docs.js +41 -0
  167. package/dist/number-field.d.ts +3 -0
  168. package/dist/number-field.js +4 -0
  169. package/dist/option.d.ts +3 -0
  170. package/dist/option.js +4 -0
  171. package/dist/radio-group.d.ts +4 -0
  172. package/dist/radio-group.js +6 -0
  173. package/dist/radio.d.ts +3 -0
  174. package/dist/radio.js +4 -0
  175. package/dist/select.d.ts +3 -0
  176. package/dist/select.js +4 -0
  177. package/dist/slider.d.ts +3 -0
  178. package/dist/slider.js +4 -0
  179. package/dist/ssr.d.ts +10 -6
  180. package/dist/ssr.js +26 -6
  181. package/dist/textarea.d.ts +3 -0
  182. package/dist/textarea.js +4 -0
  183. package/package.json +45 -1
@@ -0,0 +1,42 @@
1
+ import { afterDispatch, isActiveInRoot } from '../../core/dom.js';
2
+ /**
3
+ * Native-like keyboard activation shared by button, switch and checkbox: Space arms on keydown and
4
+ * clicks on keyup, Enter clicks on keydown. `inactive` blocks both arming and clicking.
5
+ */
6
+ export function pressable(host, states, enter, inactive) {
7
+ const press = (on) => (on ? states.add('pressed') : states.delete('pressed'));
8
+ // Not cancelled at the keydown/keyup itself, so a handler further up can still cancel the click.
9
+ const clickUnlessCancelled = (event) => afterDispatch(event, () => {
10
+ if (!event.defaultPrevented && !inactive())
11
+ host.click();
12
+ });
13
+ host.addEventListener('keydown', (event) => {
14
+ if (inactive())
15
+ return;
16
+ if (event.key === ' ') {
17
+ if (event.defaultPrevented)
18
+ return;
19
+ // Cancelled at once: deferred, an ancestor that stops propagation would let the page scroll.
20
+ // An ancestor claims Space in the capture phase, or by cancelling the keyup.
21
+ event.preventDefault();
22
+ press(true);
23
+ }
24
+ else if (event.key === 'Enter' &&
25
+ (enter === 'repeat' || (enter === 'once' && !event.repeat))) {
26
+ clickUnlessCancelled(event);
27
+ }
28
+ });
29
+ host.addEventListener('keyup', (event) => {
30
+ if (event.key !== ' ' || !states.has('pressed'))
31
+ return;
32
+ press(false);
33
+ clickUnlessCancelled(event);
34
+ });
35
+ // Disarm when focus moves away, not when only the window loses focus.
36
+ host.addEventListener('blur', () => {
37
+ if (!isActiveInRoot(host))
38
+ press(false);
39
+ });
40
+ // Focus coming back means Space may have been released while it was away.
41
+ host.addEventListener('focus', () => press(false));
42
+ }
@@ -0,0 +1,2 @@
1
+ /** A step a native input would accept; anything at or below zero means the default of 1. */
2
+ export declare const stepUnit: (step: number) => number;
@@ -0,0 +1,2 @@
1
+ /** A step a native input would accept; anything at or below zero means the default of 1. */
2
+ export const stepUnit = (step) => (step > 0 ? step : 1);
@@ -0,0 +1,72 @@
1
+ import { FormControlElement } from '../../core/form-control.js';
2
+ type TextControl = HTMLInputElement | HTMLTextAreaElement;
3
+ /** The props every text control shares; a subclass's def may leave some out. */
4
+ interface TextControlProps {
5
+ value: string;
6
+ placeholder: string;
7
+ required: boolean;
8
+ readOnly: boolean;
9
+ minLength: number;
10
+ maxLength: number;
11
+ autocomplete: string;
12
+ errorText: string;
13
+ label: string;
14
+ helpText: string;
15
+ enterKeyHint: string;
16
+ }
17
+ /** The props that can change the form value, its restore state or its validity in every text control. */
18
+ export declare const baseCommitProps: readonly ["value", "required", "disabled", "readOnly", "minLength", "maxLength", "errorText", "autocomplete"];
19
+ /**
20
+ * The behaviour text-field, textarea and number-field share: a native control in the shadow root
21
+ * (`data-ref="input"`) holds the value, and the host mirrors its form value, restore state and
22
+ * validity. update() touches a prop only when it is in `changed`, so props a def does not declare
23
+ * never reach it.
24
+ */
25
+ export declare abstract class TextControlElement extends FormControlElement {
26
+ name: string;
27
+ label: string;
28
+ placeholder: string;
29
+ helpText: string;
30
+ errorText: string;
31
+ required: boolean;
32
+ disabled: boolean;
33
+ readOnly: boolean;
34
+ autocomplete: string;
35
+ /** True once the value was edited or set as a property; the default then stops applying. */
36
+ protected dirty: boolean;
37
+ /** A value set before the shadow root exists. */
38
+ protected pendingValue: string | null;
39
+ /** Props that can change the form value, its restore state or its validity. */
40
+ protected abstract readonly commitProps: readonly string[];
41
+ /** A detached control holding `value`, sanitized and constrained the way the real one is. */
42
+ protected abstract probe(value: string): TextControl;
43
+ get value(): string;
44
+ set value(next: string);
45
+ get defaultValue(): string;
46
+ set defaultValue(next: string);
47
+ /** Focuses the inner control directly, so the caret stays where it was (no select-all). */
48
+ focus(options?: FocusOptions): void;
49
+ select(): void;
50
+ setSelectionRange(start: number, end: number, direction?: 'forward' | 'backward' | 'none'): void;
51
+ protected get p(): TextControlProps;
52
+ protected get input(): TextControl | null;
53
+ /** Hook for keys pressed in the inner control. */
54
+ protected controlKeyDown(_event: KeyboardEvent): void;
55
+ private needsCommit;
56
+ /** Stands in for the inner control until it exists, so validity is right from the start. */
57
+ private validityProbe;
58
+ protected rendered(): void;
59
+ protected update(changed: ReadonlySet<string>): void;
60
+ /** update() only runs once connected; before that, keep the value and validity current here. */
61
+ protected willUpdate(changed: ReadonlySet<string>): void;
62
+ protected formValue(): string;
63
+ /**
64
+ * Like a native control, one with autocomplete=off is never saved for restore, nor is one
65
+ * that sets none of its own inside a form with autocomplete=off.
66
+ */
67
+ protected formState(): string | null;
68
+ protected validate(): void;
69
+ protected resetToDefault(): void;
70
+ protected restoreState(state: string): void;
71
+ }
72
+ export {};
@@ -0,0 +1,191 @@
1
+ import { dispatch, setOptionalAttribute, setText } from '../../core/dom.js';
2
+ import { FormControlElement } from '../../core/form-control.js';
3
+ import { copyValidity } from '../../core/validation.js';
4
+ /** The props that can change the form value, its restore state or its validity in every text control. */
5
+ export const baseCommitProps = [
6
+ 'value',
7
+ 'required',
8
+ 'disabled',
9
+ 'readOnly',
10
+ 'minLength',
11
+ 'maxLength',
12
+ 'errorText',
13
+ 'autocomplete',
14
+ ];
15
+ function autocompleteOff(value) {
16
+ return (value ?? '').trim().toLowerCase() === 'off';
17
+ }
18
+ /**
19
+ * The behaviour text-field, textarea and number-field share: a native control in the shadow root
20
+ * (`data-ref="input"`) holds the value, and the host mirrors its form value, restore state and
21
+ * validity. update() touches a prop only when it is in `changed`, so props a def does not declare
22
+ * never reach it.
23
+ */
24
+ export class TextControlElement extends FormControlElement {
25
+ /** True once the value was edited or set as a property; the default then stops applying. */
26
+ dirty = false;
27
+ /** A value set before the shadow root exists. */
28
+ pendingValue = null;
29
+ get value() {
30
+ return this.input?.value ?? this.pendingValue ?? this.p.value;
31
+ }
32
+ set value(next) {
33
+ const text = next === null || next === undefined ? '' : String(next);
34
+ this.dirty = true;
35
+ const input = this.input;
36
+ if (input)
37
+ input.value = text;
38
+ else
39
+ this.pendingValue = text;
40
+ this.commit();
41
+ }
42
+ get defaultValue() {
43
+ return this.p.value;
44
+ }
45
+ set defaultValue(next) {
46
+ this.setAttribute('value', String(next));
47
+ }
48
+ /** Focuses the inner control directly, so the caret stays where it was (no select-all). */
49
+ focus(options) {
50
+ const input = this.input;
51
+ if (input)
52
+ input.focus(options);
53
+ else
54
+ super.focus(options);
55
+ }
56
+ select() {
57
+ this.input?.select();
58
+ }
59
+ setSelectionRange(start, end, direction) {
60
+ this.input?.setSelectionRange(start, end, direction);
61
+ }
62
+ get p() {
63
+ return this.props;
64
+ }
65
+ get input() {
66
+ return this.ref('input');
67
+ }
68
+ /** Hook for keys pressed in the inner control. */
69
+ controlKeyDown(_event) { }
70
+ needsCommit(changed) {
71
+ return this.commitProps.some((key) => changed.has(key));
72
+ }
73
+ /** Stands in for the inner control until it exists, so validity is right from the start. */
74
+ validityProbe() {
75
+ const p = this.p;
76
+ const probe = this.probe(this.value);
77
+ probe.required = p.required;
78
+ probe.readOnly = p.readOnly;
79
+ probe.disabled = this.isDisabled;
80
+ if (p.minLength >= 0)
81
+ probe.setAttribute('minlength', String(p.minLength));
82
+ if (p.maxLength >= 0)
83
+ probe.setAttribute('maxlength', String(p.maxLength));
84
+ return probe;
85
+ }
86
+ rendered() {
87
+ const input = this.input;
88
+ // A declarative root adopted without its control (cut short by the parser): nothing to wire up.
89
+ if (!input)
90
+ return;
91
+ // An SSR'd control works before JS loads; keep whatever was typed or autofilled meanwhile.
92
+ // Compare with the sanitized default: the browser trims or strips some values by itself.
93
+ if (input.value !== this.probe(this.p.value).value)
94
+ this.dirty = true;
95
+ if (this.pendingValue !== null) {
96
+ input.value = this.pendingValue;
97
+ this.pendingValue = null;
98
+ }
99
+ input.addEventListener('input', () => {
100
+ this.dirty = true;
101
+ this.commit();
102
+ });
103
+ input.addEventListener('change', () => {
104
+ this.markInteracted();
105
+ dispatch(this, 'change');
106
+ });
107
+ input.addEventListener('keydown', (event) => this.controlKeyDown(event));
108
+ }
109
+ update(changed) {
110
+ const p = this.p;
111
+ const input = this.input;
112
+ if (input) {
113
+ if (changed.has('value')) {
114
+ if (input.defaultValue !== p.value)
115
+ input.defaultValue = p.value;
116
+ if (!this.dirty)
117
+ input.value = p.value;
118
+ }
119
+ if (changed.has('placeholder'))
120
+ setOptionalAttribute(input, 'placeholder', p.placeholder);
121
+ if (changed.has('required'))
122
+ input.required = p.required;
123
+ if (changed.has('disabled'))
124
+ input.disabled = this.isDisabled;
125
+ if (changed.has('readOnly'))
126
+ input.readOnly = p.readOnly;
127
+ if (changed.has('minLength')) {
128
+ setOptionalAttribute(input, 'minlength', p.minLength >= 0 ? String(p.minLength) : '');
129
+ }
130
+ if (changed.has('maxLength')) {
131
+ setOptionalAttribute(input, 'maxlength', p.maxLength >= 0 ? String(p.maxLength) : '');
132
+ }
133
+ if (changed.has('autocomplete'))
134
+ setOptionalAttribute(input, 'autocomplete', p.autocomplete);
135
+ if (changed.has('enterKeyHint'))
136
+ setOptionalAttribute(input, 'enterkeyhint', p.enterKeyHint);
137
+ }
138
+ if (changed.has('label'))
139
+ setText(this.ref('label-text'), p.label);
140
+ if (changed.has('helpText'))
141
+ setText(this.ref('help-text'), p.helpText);
142
+ if (this.needsCommit(changed))
143
+ this.commit();
144
+ }
145
+ /** update() only runs once connected; before that, keep the value and validity current here. */
146
+ willUpdate(changed) {
147
+ if (!this.isConnected && !this.input && this.needsCommit(changed))
148
+ this.commit();
149
+ }
150
+ formValue() {
151
+ return this.value;
152
+ }
153
+ /**
154
+ * Like a native control, one with autocomplete=off is never saved for restore, nor is one
155
+ * that sets none of its own inside a form with autocomplete=off.
156
+ */
157
+ formState() {
158
+ const own = this.p.autocomplete?.trim();
159
+ const off = own
160
+ ? autocompleteOff(own)
161
+ : autocompleteOff(this.internals.form?.getAttribute('autocomplete'));
162
+ return off ? null : this.value;
163
+ }
164
+ validate() {
165
+ const input = this.input;
166
+ const source = input ?? this.validityProbe();
167
+ // A disabled or readonly control still sets flags such as typeMismatch, but is barred from
168
+ // validation and has no message; setValidity() would throw on flags without a message.
169
+ if (!source.willValidate || source.validity.valid)
170
+ this.internals.setValidity({});
171
+ else {
172
+ this.internals.setValidity(copyValidity(source.validity), source.validationMessage, input ?? undefined);
173
+ }
174
+ setText(this.ref('error-text'), this.p.errorText || input?.validationMessage || '');
175
+ }
176
+ resetToDefault() {
177
+ this.dirty = false;
178
+ this.pendingValue = null;
179
+ const input = this.input;
180
+ if (input)
181
+ input.value = this.p.value;
182
+ }
183
+ restoreState(state) {
184
+ this.dirty = true;
185
+ const input = this.input;
186
+ if (input)
187
+ input.value = state;
188
+ else
189
+ this.pendingValue = state;
190
+ }
191
+ }
@@ -0,0 +1,67 @@
1
+ import { FormControlElement } from '../../core/form-control.js';
2
+ export declare class NeuSlider extends FormControlElement {
3
+ static def: import("../../ssr.js").ComponentDef<{
4
+ readonly value: {
5
+ readonly type: "number";
6
+ readonly default: number;
7
+ };
8
+ readonly min: {
9
+ readonly type: "number";
10
+ readonly default: 0;
11
+ };
12
+ readonly max: {
13
+ readonly type: "number";
14
+ readonly default: 100;
15
+ };
16
+ readonly step: {
17
+ readonly type: "number";
18
+ readonly default: 1;
19
+ };
20
+ readonly name: {
21
+ readonly type: "string";
22
+ };
23
+ readonly label: {
24
+ readonly type: "string";
25
+ };
26
+ readonly disabled: {
27
+ readonly type: "boolean";
28
+ };
29
+ }>;
30
+ static extraProperties: string[];
31
+ name: string;
32
+ label: string;
33
+ min: number;
34
+ max: number;
35
+ step: number;
36
+ disabled: boolean;
37
+ private current;
38
+ private dirty;
39
+ private dragging;
40
+ private startValue;
41
+ private formatter;
42
+ constructor();
43
+ protected disconnected(): void;
44
+ get value(): number;
45
+ set value(next: number);
46
+ get defaultValue(): number;
47
+ set defaultValue(next: number);
48
+ get valueFormatter(): ((value: number) => string) | undefined;
49
+ set valueFormatter(next: ((value: number) => string) | undefined);
50
+ private snap;
51
+ /** Pushes the value to ARIA and the thumb, without touching the form. */
52
+ private sync;
53
+ private setCurrent;
54
+ /** The value as a user change: marks the form interaction and fires input. Returns false if nothing changed. */
55
+ private userSet;
56
+ private onKey;
57
+ private onDown;
58
+ private onMove;
59
+ private moveTo;
60
+ private endDrag;
61
+ protected willUpdate(changed: ReadonlySet<string>): void;
62
+ protected update(changed: ReadonlySet<string>): void;
63
+ protected formValue(): string;
64
+ protected validate(): void;
65
+ protected resetToDefault(): void;
66
+ protected restoreState(state: string): void;
67
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The value `raw` becomes on a slider: the nearest step counted from min, inside [min, max]
3
+ * (plan decision 9). max < min counts as max = min, a step of 0 or less as 1, NaN as the midpoint.
4
+ * Rounded to the decimals of step and min, so 0.1 + 0.2 on a 0.1 step is 0.3.
5
+ */
6
+ export declare function sliderValue(raw: number, min: number, max: number, step: number): number;
7
+ /** What PageUp and PageDown move by: a tenth of the range in whole steps, at least one step. */
8
+ export declare function sliderBigStep(min: number, max: number, step: number): number;
9
+ /** The `style` of `.base`: where the thumb sits, 0 to 1. Template and update() write the same bytes. */
10
+ export declare function sliderStyle(value: number, min: number, max: number): string;
11
+ export declare const sliderDef: import("../../core/define.js").ComponentDef<{
12
+ readonly value: {
13
+ readonly type: "number";
14
+ readonly default: number;
15
+ };
16
+ readonly min: {
17
+ readonly type: "number";
18
+ readonly default: 0;
19
+ };
20
+ readonly max: {
21
+ readonly type: "number";
22
+ readonly default: 100;
23
+ };
24
+ readonly step: {
25
+ readonly type: "number";
26
+ readonly default: 1;
27
+ };
28
+ readonly name: {
29
+ readonly type: "string";
30
+ };
31
+ readonly label: {
32
+ readonly type: "string";
33
+ };
34
+ readonly disabled: {
35
+ readonly type: "boolean";
36
+ };
37
+ }>;
@@ -0,0 +1,54 @@
1
+ import { defineComponent } from '../../core/define.js';
2
+ import { html } from '../../core/html.js';
3
+ import { stepUnit } from '../shared/step.js';
4
+ import { sliderStyles } from './slider.styles.js';
5
+ /** Decimal places of a number as written, exponent notation included. */
6
+ function decimals(n) {
7
+ const [, fraction = '', exponent = '0'] = /(?:\.(\d+))?(?:e([+-]\d+))?$/.exec(String(n)) ?? [];
8
+ return Math.min(100, Math.max(0, fraction.length - Number(exponent)));
9
+ }
10
+ /**
11
+ * The value `raw` becomes on a slider: the nearest step counted from min, inside [min, max]
12
+ * (plan decision 9). max < min counts as max = min, a step of 0 or less as 1, NaN as the midpoint.
13
+ * Rounded to the decimals of step and min, so 0.1 + 0.2 on a 0.1 step is 0.3.
14
+ */
15
+ export function sliderValue(raw, min, max, step) {
16
+ const hi = Math.max(min, max);
17
+ const unit = stepUnit(step);
18
+ const wanted = Number.isNaN(raw) ? min + (hi - min) / 2 : raw;
19
+ let steps = Math.round((wanted - min) / unit);
20
+ // Rounding up may pass max: the largest step that fits is the answer. The epsilon absorbs
21
+ // float noise such as (0.3 - 0) / 0.1 = 2.9999999999999996.
22
+ if (min + steps * unit > hi)
23
+ steps = Math.floor((hi - min) / unit + 1e-9);
24
+ const value = min + Math.max(0, steps) * unit;
25
+ return Number(Math.min(value, hi).toFixed(Math.max(decimals(unit), decimals(min))));
26
+ }
27
+ /** What PageUp and PageDown move by: a tenth of the range in whole steps, at least one step. */
28
+ export function sliderBigStep(min, max, step) {
29
+ const unit = stepUnit(step);
30
+ const tenth = Math.round((Math.max(min, max) - min) / 10 / unit) * unit;
31
+ return Number(Math.max(unit, tenth).toFixed(decimals(unit)));
32
+ }
33
+ /** The `style` of `.base`: where the thumb sits, 0 to 1. Template and update() write the same bytes. */
34
+ export function sliderStyle(value, min, max) {
35
+ const range = Math.max(min, max) - min;
36
+ const pos = range > 0 ? Math.round(((value - min) / range) * 1e4) / 1e4 : 0;
37
+ return `--_neu-pos:${pos}`;
38
+ }
39
+ export const sliderDef = defineComponent({
40
+ tag: 'neu-slider',
41
+ props: {
42
+ value: { type: 'number', default: Number.NaN },
43
+ min: { type: 'number', default: 0 },
44
+ max: { type: 'number', default: 100 },
45
+ step: { type: 'number', default: 1 },
46
+ name: { type: 'string' },
47
+ label: { type: 'string' },
48
+ disabled: { type: 'boolean' },
49
+ },
50
+ form: { valueProp: 'value' },
51
+ properties: { valueFormatter: '(value: number) => string' },
52
+ styles: sliderStyles,
53
+ template: (p) => html `<span part="base" class="base" data-ref="base" style="${sliderStyle(sliderValue(p.value, p.min, p.max, p.step), p.min, p.max)}"><span part="track" class="track" data-ref="track"><span part="fill" class="fill"></span><span part="thumb" class="thumb"></span></span></span>`,
54
+ });
@@ -0,0 +1,2 @@
1
+ import type { ComponentDocs } from '../../core/define.js';
2
+ export declare const sliderDocs: ComponentDocs;
@@ -0,0 +1,45 @@
1
+ import { themeCssProperties } from '../theme-docs.js';
2
+ export const sliderDocs = {
3
+ summary: 'A horizontal slider for a number. The value attribute is the default; the value property is the current value. The valueFormatter property turns the value into the text a screen reader announces.',
4
+ descriptions: {
5
+ value: 'The current number, snapped to the nearest step within the range.',
6
+ min: 'The lowest value of the range.',
7
+ max: 'The highest value of the range.',
8
+ step: 'The distance between allowed values.',
9
+ name: 'The name under which the value is submitted with a form.',
10
+ label: 'Accessible name of the slider.',
11
+ disabled: 'Prevents interaction and leaves the slider out of form submission.',
12
+ defaultValue: 'The value the slider starts with, which a form reset restores; set by the value attribute.',
13
+ valueFormatter: 'Function that turns the value into the text a screen reader announces.',
14
+ },
15
+ events: [
16
+ {
17
+ name: 'input',
18
+ description: 'Fired on every change while the user drags or presses a key.',
19
+ },
20
+ {
21
+ name: 'change',
22
+ description: 'Fired after the user commits a change: on release, or per key.',
23
+ },
24
+ ],
25
+ slots: [],
26
+ parts: [
27
+ { name: 'base', description: 'Wrapper around the track.' },
28
+ { name: 'track', description: 'The inset groove.' },
29
+ { name: 'fill', description: 'The part of the track up to the thumb.' },
30
+ { name: 'thumb', description: 'The raised handle.' },
31
+ ],
32
+ cssProperties: themeCssProperties,
33
+ keyboard: [
34
+ {
35
+ name: 'ArrowRight / ArrowUp',
36
+ description: 'Increases the value by step; left and right swap in right-to-left text.',
37
+ },
38
+ { name: 'ArrowLeft / ArrowDown', description: 'Decreases the value by step.' },
39
+ {
40
+ name: 'PageUp / PageDown',
41
+ description: 'Changes the value by a large step: the larger of step and a tenth of the range.',
42
+ },
43
+ { name: 'Home / End', description: 'Sets the value to min or max.' },
44
+ ],
45
+ };