@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,170 @@
1
+ import { dispatch } from '../../core/dom.js';
2
+ import { FormControlElement } from '../../core/form-control.js';
3
+ import { stepUnit } from '../shared/step.js';
4
+ import { sliderBigStep, sliderDef, sliderStyle, sliderValue } from './slider.def.js';
5
+ export class NeuSlider extends FormControlElement {
6
+ static def = sliderDef;
7
+ static extraProperties = ['defaultValue', 'valueFormatter'];
8
+ current;
9
+ dirty = false;
10
+ dragging = false;
11
+ startValue = 0;
12
+ formatter;
13
+ constructor() {
14
+ super();
15
+ this.internals.role = 'slider';
16
+ this.internals.ariaOrientation = 'horizontal';
17
+ this.current = this.snap(this.props.value);
18
+ this.addEventListener('keydown', (event) => this.onKey(event));
19
+ this.addEventListener('pointerdown', (event) => this.onDown(event));
20
+ this.addEventListener('pointermove', (event) => this.onMove(event));
21
+ this.addEventListener('pointerup', () => this.endDrag());
22
+ this.addEventListener('pointercancel', () => this.endDrag());
23
+ // Capture lost without a pointerup reaching us (the browser took it back, say): the drag is over.
24
+ this.addEventListener('lostpointercapture', () => this.endDrag());
25
+ }
26
+ disconnected() {
27
+ super.disconnected();
28
+ // A drag cut short by removal does not resume when the slider is put back.
29
+ this.dragging = false;
30
+ }
31
+ get value() {
32
+ return this.current;
33
+ }
34
+ set value(next) {
35
+ this.dirty = true;
36
+ this.setCurrent(this.snap(Number(next)));
37
+ }
38
+ get defaultValue() {
39
+ return this.snap(this.props.value);
40
+ }
41
+ set defaultValue(next) {
42
+ this.setAttribute('value', String(next));
43
+ }
44
+ get valueFormatter() {
45
+ return this.formatter;
46
+ }
47
+ set valueFormatter(next) {
48
+ this.formatter = typeof next === 'function' ? next : undefined;
49
+ this.sync();
50
+ }
51
+ snap(raw) {
52
+ return sliderValue(raw, this.props.min, this.props.max, this.props.step);
53
+ }
54
+ /** Pushes the value to ARIA and the thumb, without touching the form. */
55
+ sync() {
56
+ const { min, max } = this.props;
57
+ const internals = this.internals;
58
+ internals.ariaLabel = this.props.label === '' ? null : String(this.props.label);
59
+ internals.ariaValueMin = String(min);
60
+ internals.ariaValueMax = String(Math.max(min, max));
61
+ internals.ariaValueNow = String(this.current);
62
+ internals.ariaValueText = this.formatter ? this.formatter(this.current) : null;
63
+ // The template writes the same string, so a server-rendered root is left alone.
64
+ const base = this.ref('base');
65
+ const style = sliderStyle(this.current, min, max);
66
+ if (base && base.getAttribute('style') !== style)
67
+ base.setAttribute('style', style);
68
+ }
69
+ setCurrent(next) {
70
+ this.current = next;
71
+ this.sync();
72
+ this.commit();
73
+ }
74
+ /** The value as a user change: marks the form interaction and fires input. Returns false if nothing changed. */
75
+ userSet(next) {
76
+ if (next === this.current)
77
+ return false;
78
+ this.markInteracted();
79
+ this.setCurrent(next);
80
+ dispatch(this, 'input');
81
+ return true;
82
+ }
83
+ onKey(event) {
84
+ if (this.isDisabled || event.altKey || event.ctrlKey || event.metaKey)
85
+ return;
86
+ const { min, max } = this.props;
87
+ const step = stepUnit(this.props.step);
88
+ const direction = this.matches(':dir(rtl)') ? -1 : 1;
89
+ const big = sliderBigStep(min, max, step);
90
+ const wanted = {
91
+ ArrowRight: this.current + step * direction,
92
+ ArrowLeft: this.current - step * direction,
93
+ ArrowUp: this.current + step,
94
+ ArrowDown: this.current - step,
95
+ PageUp: this.current + big,
96
+ PageDown: this.current - big,
97
+ Home: Number.NEGATIVE_INFINITY,
98
+ End: Number.POSITIVE_INFINITY,
99
+ };
100
+ const raw = wanted[event.key];
101
+ if (raw === undefined)
102
+ return;
103
+ event.preventDefault();
104
+ if (this.userSet(this.snap(raw)))
105
+ dispatch(this, 'change');
106
+ }
107
+ onDown(event) {
108
+ if (this.isDisabled || event.button !== 0)
109
+ return;
110
+ this.dragging = true;
111
+ this.startValue = this.current;
112
+ this.focus();
113
+ try {
114
+ this.setPointerCapture(event.pointerId);
115
+ }
116
+ catch {
117
+ // A pointer the browser does not know (synthetic events): the drag is tracked by the flag.
118
+ }
119
+ this.moveTo(event);
120
+ }
121
+ onMove(event) {
122
+ if (this.dragging)
123
+ this.moveTo(event);
124
+ }
125
+ moveTo(event) {
126
+ const track = this.ref('track');
127
+ if (!track)
128
+ return;
129
+ const rect = track.getBoundingClientRect();
130
+ let fraction = rect.width > 0 ? (event.clientX - rect.left) / rect.width : 0;
131
+ if (this.matches(':dir(rtl)'))
132
+ fraction = 1 - fraction;
133
+ const { min, max } = this.props;
134
+ const clamped = Math.min(1, Math.max(0, fraction));
135
+ this.userSet(this.snap(min + clamped * (Math.max(min, max) - min)));
136
+ }
137
+ endDrag() {
138
+ if (!this.dragging)
139
+ return;
140
+ this.dragging = false;
141
+ if (this.current !== this.startValue)
142
+ dispatch(this, 'change');
143
+ }
144
+ willUpdate(changed) {
145
+ if (changed.has('value') || changed.has('min') || changed.has('max') || changed.has('step')) {
146
+ // Until the user or a script sets one, the value is the attribute's; a new range re-snaps it.
147
+ this.current = this.snap(this.dirty ? this.current : this.props.value);
148
+ }
149
+ }
150
+ update(changed) {
151
+ if (changed.has('disabled'))
152
+ this.syncDisabledState();
153
+ this.sync();
154
+ this.commit();
155
+ }
156
+ formValue() {
157
+ return String(this.current);
158
+ }
159
+ validate() {
160
+ this.internals.setValidity({});
161
+ }
162
+ resetToDefault() {
163
+ this.dirty = false;
164
+ this.setCurrent(this.snap(this.props.value));
165
+ }
166
+ restoreState(state) {
167
+ this.dirty = true;
168
+ this.setCurrent(this.snap(Number(state)));
169
+ }
170
+ }
@@ -0,0 +1 @@
1
+ export declare const sliderStyles = "\n:host {\n --_neu-bg: var(--neu-bg, #e0e5ec);\n --_neu-accent-c: var(--neu-accent, #6d5dfc);\n --_neu-d: var(--neu-distance, 6px);\n --_neu-k: var(--neu-intensity, 1);\n --_neu-r: var(--neu-radius, 12px);\n --_neu-danger: var(--neu-danger, #e5484d);\n --_neu-dur: var(--neu-duration, 150ms);\n --_neu-sd: var(--neu-shadow-dark, color-mix(in oklab, var(--_neu-bg), black min(100%, calc(var(--_neu-shade, 18%) * var(--_neu-k)))));\n --_neu-sl: var(--neu-shadow-light, color-mix(in oklab, var(--_neu-bg), white min(100%, calc(var(--_neu-light, 100%) * var(--_neu-k)))));\n --_neu-fg: var(--neu-fg, color-mix(in oklab, var(--_neu-bg), var(--_neu-ink, black) var(--_neu-fg-mix, 32%)));\n --_neu-fg-muted: var(--neu-fg-muted, color-mix(in oklab, var(--_neu-bg), var(--_neu-ink, black) var(--_neu-fg-muted-mix, 18%)));\n --_neu-accent-soft: color-mix(in oklab, var(--_neu-accent-c) 25%, var(--_neu-bg));\n --_neu-focus: 0 0 0 3px color-mix(in oklab, var(--_neu-accent-c) 45%, transparent);\n --_neu-raised: var(--_neu-d) var(--_neu-d) calc(var(--_neu-d) * 2) var(--_neu-sd), calc(var(--_neu-d) * -1) calc(var(--_neu-d) * -1) calc(var(--_neu-d) * 2) var(--_neu-sl);\n --_neu-raised-sm: calc(var(--_neu-d) * 0.5) calc(var(--_neu-d) * 0.5) var(--_neu-d) var(--_neu-sd), calc(var(--_neu-d) * -0.5) calc(var(--_neu-d) * -0.5) var(--_neu-d) var(--_neu-sl);\n --_neu-inset: inset var(--_neu-d) var(--_neu-d) calc(var(--_neu-d) * 2) var(--_neu-sd), inset calc(var(--_neu-d) * -1) calc(var(--_neu-d) * -1) calc(var(--_neu-d) * 2) var(--_neu-sl);\n --_neu-inset-sm: inset calc(var(--_neu-d) * 0.5) calc(var(--_neu-d) * 0.5) var(--_neu-d) var(--_neu-sd), inset calc(var(--_neu-d) * -0.5) calc(var(--_neu-d) * -0.5) var(--_neu-d) var(--_neu-sl);\n font-family: var(--neu-font);\n color: var(--_neu-fg);\n -webkit-tap-highlight-color: transparent;\n}\n:host(:not(:defined)) { visibility: inherit !important; min-block-size: auto !important; }\n:host([hidden]) { display: none !important; }\n:host(:focus) { outline: none; }\n*, *::before, *::after { box-sizing: border-box; }\n\n:host { display: block; min-block-size: 1.25rem; touch-action: pan-y; cursor: pointer; user-select: none; }\n:host(:disabled), :host([disabled]) { cursor: not-allowed; }\n.base { position: relative; display: flex; align-items: center; block-size: 1.25rem; padding-inline: 0.625rem; }\n.track { position: relative; flex: 1; block-size: 0.5rem; border-radius: 999px; background: var(--_neu-bg); box-shadow: var(--_neu-inset-sm); }\n.fill { position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: calc(var(--_neu-pos) * 100%); border-radius: inherit; background: var(--_neu-accent-soft); }\n.thumb {\n position: absolute; inset-block-start: 50%; inset-inline-start: calc(var(--_neu-pos) * 100%);\n inline-size: 1.25rem; block-size: 1.25rem; margin-block-start: -0.625rem; margin-inline-start: -0.625rem;\n border-radius: 50%; background: var(--_neu-bg); box-shadow: var(--_neu-raised-sm);\n transition: box-shadow var(--_neu-dur) ease;\n}\n:host(:focus-visible) .thumb { box-shadow: var(--_neu-raised-sm), var(--_neu-focus); }\n:host(:disabled) .base, :host([disabled]) .base { opacity: 0.55; }\n";
@@ -0,0 +1,16 @@
1
+ import { hostTheme } from '../../core/styles.js';
2
+ export const sliderStyles = `${hostTheme}
3
+ :host { display: block; min-block-size: 1.25rem; touch-action: pan-y; cursor: pointer; user-select: none; }
4
+ :host(:disabled), :host([disabled]) { cursor: not-allowed; }
5
+ .base { position: relative; display: flex; align-items: center; block-size: 1.25rem; padding-inline: 0.625rem; }
6
+ .track { position: relative; flex: 1; block-size: 0.5rem; border-radius: 999px; background: var(--_neu-bg); box-shadow: var(--_neu-inset-sm); }
7
+ .fill { position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: calc(var(--_neu-pos) * 100%); border-radius: inherit; background: var(--_neu-accent-soft); }
8
+ .thumb {
9
+ position: absolute; inset-block-start: 50%; inset-inline-start: calc(var(--_neu-pos) * 100%);
10
+ inline-size: 1.25rem; block-size: 1.25rem; margin-block-start: -0.625rem; margin-inline-start: -0.625rem;
11
+ border-radius: 50%; background: var(--_neu-bg); box-shadow: var(--_neu-raised-sm);
12
+ transition: box-shadow var(--_neu-dur) ease;
13
+ }
14
+ :host(:focus-visible) .thumb { box-shadow: var(--_neu-raised-sm), var(--_neu-focus); }
15
+ :host(:disabled) .base, :host([disabled]) .base { opacity: 0.55; }
16
+ `;
@@ -9,7 +9,6 @@ export declare class NeuSpinner extends NeuElement {
9
9
  readonly type: "string";
10
10
  readonly default: "md";
11
11
  readonly values: readonly ["sm", "md", "lg"];
12
- readonly reflect: true;
13
12
  };
14
13
  }>;
15
14
  label: string;
@@ -7,6 +7,5 @@ export declare const spinnerDef: import("../../core/define.js").ComponentDef<{
7
7
  readonly type: "string";
8
8
  readonly default: "md";
9
9
  readonly values: readonly ["sm", "md", "lg"];
10
- readonly reflect: true;
11
10
  };
12
11
  }>;
@@ -1,25 +1,13 @@
1
1
  import { defineComponent } from '../../core/define.js';
2
2
  import { html } from '../../core/html.js';
3
- import { themeCssProperties } from '../../core/styles.js';
4
3
  import { spinnerStyles } from './spinner.styles.js';
5
4
  export const spinnerDef = defineComponent({
6
5
  tag: 'neu-spinner',
7
6
  props: {
8
7
  label: { type: 'string', default: 'Loading' },
9
- size: { type: 'string', default: 'md', values: ['sm', 'md', 'lg'], reflect: true },
8
+ size: { type: 'string', default: 'md', values: ['sm', 'md', 'lg'] },
10
9
  },
11
10
  styles: spinnerStyles,
12
11
  // The label is also visually hidden text: a live region announces content, not its name.
13
12
  template: (p) => html `<span part="base" class="base"><span part="track" class="track"></span><span part="indicator" class="indicator"></span><span class="label" data-ref="label">${p.label}</span></span>`,
14
- docs: {
15
- summary: 'A rotating indicator for work in progress.',
16
- events: [],
17
- slots: [],
18
- parts: [
19
- { name: 'base', description: 'The sized wrapper.' },
20
- { name: 'track', description: 'The inset ring behind the indicator.' },
21
- { name: 'indicator', description: 'The rotating arc.' },
22
- ],
23
- cssProperties: themeCssProperties,
24
- },
25
13
  });
@@ -0,0 +1,2 @@
1
+ import type { ComponentDocs } from '../../core/define.js';
2
+ export declare const spinnerDocs: ComponentDocs;
@@ -0,0 +1,17 @@
1
+ import { themeCssProperties } from '../theme-docs.js';
2
+ export const spinnerDocs = {
3
+ summary: 'A rotating indicator for work in progress.',
4
+ descriptions: {
5
+ label: 'Accessible name announced for the spinner; defaults to "Loading".',
6
+ size: 'The spinner size.',
7
+ },
8
+ events: [],
9
+ slots: [],
10
+ parts: [
11
+ { name: 'base', description: 'The sized wrapper.' },
12
+ { name: 'track', description: 'The inset ring behind the indicator.' },
13
+ { name: 'indicator', description: 'The rotating arc.' },
14
+ ],
15
+ cssProperties: themeCssProperties,
16
+ keyboard: [],
17
+ };
@@ -5,25 +5,21 @@ export declare class NeuSurface extends NeuElement {
5
5
  readonly type: "string";
6
6
  readonly default: "raised";
7
7
  readonly values: readonly ["raised", "inset", "flat", "convex", "concave"];
8
- readonly reflect: true;
9
8
  };
10
9
  readonly elevation: {
11
10
  readonly type: "string";
12
11
  readonly default: "md";
13
12
  readonly values: readonly ["sm", "md", "lg"];
14
- readonly reflect: true;
15
13
  };
16
14
  readonly radius: {
17
15
  readonly type: "string";
18
16
  readonly default: "md";
19
17
  readonly values: readonly ["sm", "md", "lg", "full"];
20
- readonly reflect: true;
21
18
  };
22
19
  readonly padding: {
23
20
  readonly type: "string";
24
21
  readonly default: "md";
25
22
  readonly values: readonly ["none", "sm", "md", "lg"];
26
- readonly reflect: true;
27
23
  };
28
24
  }>;
29
25
  shape: 'raised' | 'inset' | 'flat' | 'convex' | 'concave';
@@ -3,24 +3,20 @@ export declare const surfaceDef: import("../../core/define.js").ComponentDef<{
3
3
  readonly type: "string";
4
4
  readonly default: "raised";
5
5
  readonly values: readonly ["raised", "inset", "flat", "convex", "concave"];
6
- readonly reflect: true;
7
6
  };
8
7
  readonly elevation: {
9
8
  readonly type: "string";
10
9
  readonly default: "md";
11
10
  readonly values: readonly ["sm", "md", "lg"];
12
- readonly reflect: true;
13
11
  };
14
12
  readonly radius: {
15
13
  readonly type: "string";
16
14
  readonly default: "md";
17
15
  readonly values: readonly ["sm", "md", "lg", "full"];
18
- readonly reflect: true;
19
16
  };
20
17
  readonly padding: {
21
18
  readonly type: "string";
22
19
  readonly default: "md";
23
20
  readonly values: readonly ["none", "sm", "md", "lg"];
24
- readonly reflect: true;
25
21
  };
26
22
  }>;
@@ -1,6 +1,5 @@
1
1
  import { defineComponent } from '../../core/define.js';
2
2
  import { html } from '../../core/html.js';
3
- import { themeCssProperties } from '../../core/styles.js';
4
3
  import { surfaceStyles } from './surface.styles.js';
5
4
  export const surfaceDef = defineComponent({
6
5
  tag: 'neu-surface',
@@ -9,19 +8,11 @@ export const surfaceDef = defineComponent({
9
8
  type: 'string',
10
9
  default: 'raised',
11
10
  values: ['raised', 'inset', 'flat', 'convex', 'concave'],
12
- reflect: true,
13
11
  },
14
- elevation: { type: 'string', default: 'md', values: ['sm', 'md', 'lg'], reflect: true },
15
- radius: { type: 'string', default: 'md', values: ['sm', 'md', 'lg', 'full'], reflect: true },
16
- padding: { type: 'string', default: 'md', values: ['none', 'sm', 'md', 'lg'], reflect: true },
12
+ elevation: { type: 'string', default: 'md', values: ['sm', 'md', 'lg'] },
13
+ radius: { type: 'string', default: 'md', values: ['sm', 'md', 'lg', 'full'] },
14
+ padding: { type: 'string', default: 'md', values: ['none', 'sm', 'md', 'lg'] },
17
15
  },
18
16
  styles: surfaceStyles,
19
17
  template: () => html `<div part="base" class="base"><slot></slot></div>`,
20
- docs: {
21
- summary: 'A neumorphic container with its own shape, elevation, radius and padding.',
22
- events: [],
23
- slots: [{ name: '', description: 'The content of the surface.' }],
24
- parts: [{ name: 'base', description: 'The surface itself.' }],
25
- cssProperties: themeCssProperties,
26
- },
27
18
  });
@@ -0,0 +1,2 @@
1
+ import type { ComponentDocs } from '../../core/define.js';
2
+ export declare const surfaceDocs: ComponentDocs;
@@ -0,0 +1,15 @@
1
+ import { themeCssProperties } from '../theme-docs.js';
2
+ export const surfaceDocs = {
3
+ summary: 'A neumorphic container with its own shape, elevation, radius and padding.',
4
+ descriptions: {
5
+ shape: 'How the surface is lit and curved.',
6
+ elevation: 'How far the surface appears to lift off its background.',
7
+ radius: 'How rounded the corners are.',
8
+ padding: 'The space between the edge and the content.',
9
+ },
10
+ events: [],
11
+ slots: [{ name: '', description: 'The content of the surface.' }],
12
+ parts: [{ name: 'base', description: 'The surface itself.' }],
13
+ cssProperties: themeCssProperties,
14
+ keyboard: [],
15
+ };
@@ -1,60 +1,29 @@
1
- import { FormControlElement } from '../../core/form-control.js';
2
- export declare class NeuSwitch extends FormControlElement {
1
+ import { CheckableElement } from '../shared/checkable.js';
2
+ export declare class NeuSwitch extends CheckableElement {
3
3
  static def: import("../../ssr.js").ComponentDef<{
4
4
  readonly checked: {
5
5
  readonly type: "boolean";
6
6
  };
7
7
  readonly name: {
8
8
  readonly type: "string";
9
- readonly reflect: true;
10
9
  };
11
10
  readonly value: {
12
11
  readonly type: "string";
13
12
  readonly default: "on";
14
- readonly reflect: true;
15
13
  };
16
14
  readonly disabled: {
17
15
  readonly type: "boolean";
18
- readonly reflect: true;
19
16
  };
20
17
  readonly required: {
21
18
  readonly type: "boolean";
22
- readonly reflect: true;
23
19
  };
24
20
  readonly size: {
25
21
  readonly type: "string";
26
22
  readonly default: "md";
27
23
  readonly values: readonly ["sm", "md", "lg"];
28
- readonly reflect: true;
29
24
  };
30
25
  }>;
31
- static extraProperties: string[];
32
- name: string;
33
- value: string;
34
- disabled: boolean;
35
- required: boolean;
36
- size: 'sm' | 'md' | 'lg';
37
- private current;
38
- private dirty;
26
+ protected readonly anchor = "track";
39
27
  constructor();
40
- get checked(): boolean;
41
- set checked(value: boolean);
42
- get defaultChecked(): boolean;
43
- set defaultChecked(value: boolean);
44
- /**
45
- * Native checkbox order: flip now, let click listeners see it, then input + change once the
46
- * click has finished dispatching (within it, unless propagation was stopped before window).
47
- */
48
- private onClick;
49
- private onKeyDown;
50
- /** Like a native checkbox, Space toggles on keyup only after its own keydown. */
51
- private onKeyUp;
52
- private setCurrent;
53
- protected willUpdate(changed: ReadonlySet<string>): void;
54
- protected update(changed: ReadonlySet<string>): void;
55
- protected formValue(): string | null;
56
- protected formState(): string;
57
- protected validate(): void;
58
- protected resetToDefault(): void;
59
- protected restoreState(state: string): void;
28
+ protected paint(): void;
60
29
  }
@@ -4,25 +4,20 @@ export declare const switchDef: import("../../core/define.js").ComponentDef<{
4
4
  };
5
5
  readonly name: {
6
6
  readonly type: "string";
7
- readonly reflect: true;
8
7
  };
9
8
  readonly value: {
10
9
  readonly type: "string";
11
10
  readonly default: "on";
12
- readonly reflect: true;
13
11
  };
14
12
  readonly disabled: {
15
13
  readonly type: "boolean";
16
- readonly reflect: true;
17
14
  };
18
15
  readonly required: {
19
16
  readonly type: "boolean";
20
- readonly reflect: true;
21
17
  };
22
18
  readonly size: {
23
19
  readonly type: "string";
24
20
  readonly default: "md";
25
21
  readonly values: readonly ["sm", "md", "lg"];
26
- readonly reflect: true;
27
22
  };
28
23
  }>;
@@ -1,33 +1,17 @@
1
1
  import { defineComponent } from '../../core/define.js';
2
2
  import { html } from '../../core/html.js';
3
- import { themeCssProperties } from '../../core/styles.js';
4
3
  import { switchStyles } from './switch.styles.js';
5
4
  export const switchDef = defineComponent({
6
5
  tag: 'neu-switch',
7
6
  props: {
8
7
  checked: { type: 'boolean' },
9
- name: { type: 'string', reflect: true },
10
- value: { type: 'string', default: 'on', reflect: true },
11
- disabled: { type: 'boolean', reflect: true },
12
- required: { type: 'boolean', reflect: true },
13
- size: { type: 'string', default: 'md', values: ['sm', 'md', 'lg'], reflect: true },
8
+ name: { type: 'string' },
9
+ value: { type: 'string', default: 'on' },
10
+ disabled: { type: 'boolean' },
11
+ required: { type: 'boolean' },
12
+ size: { type: 'string', default: 'md', values: ['sm', 'md', 'lg'] },
14
13
  },
15
14
  form: { valueProp: 'checked' },
16
15
  styles: switchStyles,
17
16
  template: (p) => html `<span part="base" class="base"><span part="track" class="track${p.checked ? ' on' : ''}" data-ref="track"><span part="thumb" class="thumb"></span></span><span part="label" class="label"><slot></slot></span></span>`,
18
- docs: {
19
- summary: 'An on/off switch. The checked attribute is the default state.',
20
- events: [
21
- { name: 'input', description: 'Fired when the user toggles the switch.' },
22
- { name: 'change', description: 'Fired after input when the user toggles the switch.' },
23
- ],
24
- slots: [{ name: '', description: 'Label; also the accessible name.' }],
25
- parts: [
26
- { name: 'base', description: 'Wrapper around track and label.' },
27
- { name: 'track', description: 'The inset track.' },
28
- { name: 'thumb', description: 'The raised thumb.' },
29
- { name: 'label', description: 'Wrapper around the default slot.' },
30
- ],
31
- cssProperties: themeCssProperties,
32
- },
33
17
  });
@@ -0,0 +1,2 @@
1
+ import type { ComponentDocs } from '../../core/define.js';
2
+ export declare const switchDocs: ComponentDocs;
@@ -0,0 +1,26 @@
1
+ import { themeCssProperties } from '../theme-docs.js';
2
+ export const switchDocs = {
3
+ summary: 'An on/off switch. The checked attribute is the default state.',
4
+ descriptions: {
5
+ checked: 'Whether the switch is currently on.',
6
+ name: 'The name under which the value is submitted with a form.',
7
+ value: 'The value submitted with the form while the switch is on; defaults to "on".',
8
+ disabled: 'Prevents interaction and leaves the switch out of form submission.',
9
+ required: 'Makes the form invalid until the switch is on.',
10
+ size: 'The switch size.',
11
+ defaultChecked: 'Whether the switch starts on, which a form reset restores; set by the checked attribute.',
12
+ },
13
+ events: [
14
+ { name: 'input', description: 'Fired when the user toggles the switch.' },
15
+ { name: 'change', description: 'Fired after input when the user toggles the switch.' },
16
+ ],
17
+ slots: [{ name: '', description: 'Label; also the accessible name.' }],
18
+ parts: [
19
+ { name: 'base', description: 'Wrapper around track and label.' },
20
+ { name: 'track', description: 'The inset track.' },
21
+ { name: 'thumb', description: 'The raised thumb.' },
22
+ { name: 'label', description: 'Wrapper around the default slot.' },
23
+ ],
24
+ cssProperties: themeCssProperties,
25
+ keyboard: [{ name: 'Space / Enter', description: 'Toggles the switch.' }],
26
+ };
@@ -1,125 +1,13 @@
1
- import { afterDispatch, dispatch, isActiveInRoot } from '../../core/dom.js';
2
- import { FormControlElement } from '../../core/form-control.js';
3
- import { requiredCheckboxMessage } from '../../core/validation.js';
1
+ import { CheckableElement } from '../shared/checkable.js';
4
2
  import { switchDef } from './switch.def.js';
5
- export class NeuSwitch extends FormControlElement {
3
+ export class NeuSwitch extends CheckableElement {
6
4
  static def = switchDef;
7
- static extraProperties = ['defaultChecked'];
8
- current;
9
- dirty = false;
5
+ anchor = 'track';
10
6
  constructor() {
11
7
  super();
12
- this.current = this.props.checked === true;
13
8
  this.internals.role = 'switch';
14
- this.addEventListener('click', (event) => this.onClick(event));
15
- this.addEventListener('keydown', (event) => this.onKeyDown(event));
16
- this.addEventListener('keyup', (event) => this.onKeyUp(event));
17
- // Disarm when focus moves away, not when only the window loses focus.
18
- this.addEventListener('blur', () => {
19
- if (!isActiveInRoot(this))
20
- this.toggleState('pressed', false);
21
- });
22
- // Focus coming back means Space may have been released while it was away.
23
- this.addEventListener('focus', () => this.toggleState('pressed', false));
24
9
  }
25
- get checked() {
26
- return this.current;
27
- }
28
- set checked(value) {
29
- this.dirty = true;
30
- this.setCurrent(Boolean(value));
31
- }
32
- get defaultChecked() {
33
- return this.props.checked === true;
34
- }
35
- set defaultChecked(value) {
36
- this.toggleAttribute('checked', Boolean(value));
37
- }
38
- /**
39
- * Native checkbox order: flip now, let click listeners see it, then input + change once the
40
- * click has finished dispatching (within it, unless propagation was stopped before window).
41
- */
42
- onClick(event) {
43
- const before = this.current;
44
- this.dirty = true;
45
- this.setCurrent(!before);
46
- afterDispatch(event, () => {
47
- if (event.defaultPrevented) {
48
- this.setCurrent(before);
49
- }
50
- else if (this.isConnected && this.current === !before) {
51
- this.markInteracted();
52
- dispatch(this, 'input');
53
- dispatch(this, 'change');
54
- }
55
- });
56
- }
57
- onKeyDown(event) {
58
- if (event.key === ' ') {
59
- if (event.defaultPrevented)
60
- return;
61
- // Cancelled at once: deferred, an ancestor that stops propagation would let the page scroll.
62
- // An ancestor claims Space in the capture phase, or by cancelling the keyup.
63
- event.preventDefault();
64
- this.toggleState('pressed', true);
65
- }
66
- else if (event.key === 'Enter' && !event.repeat) {
67
- // Not cancelled here, so a handler further up can still cancel the toggle.
68
- afterDispatch(event, () => {
69
- if (!event.defaultPrevented)
70
- this.click();
71
- });
72
- }
73
- }
74
- /** Like a native checkbox, Space toggles on keyup only after its own keydown. */
75
- onKeyUp(event) {
76
- if (event.key !== ' ' || !this.internals.states.has('pressed'))
77
- return;
78
- this.toggleState('pressed', false);
79
- afterDispatch(event, () => {
80
- if (!event.defaultPrevented)
81
- this.click();
82
- });
83
- }
84
- setCurrent(value) {
85
- this.current = value;
86
- this.toggleState('checked', value);
87
- this.internals.ariaChecked = value ? 'true' : 'false';
88
- this.ref('track')?.classList.toggle('on', value);
89
- this.commit();
90
- }
91
- willUpdate(changed) {
92
- if (changed.has('checked') && !this.dirty)
93
- this.current = this.props.checked === true;
94
- }
95
- update(changed) {
96
- if (changed.has('disabled'))
97
- this.syncDisabledState();
98
- if (changed.has('checked'))
99
- this.setCurrent(this.current);
100
- else if (changed.has('required') || changed.has('value'))
101
- this.commit();
102
- }
103
- formValue() {
104
- return this.current ? String(this.props.value) : null;
105
- }
106
- formState() {
107
- return this.current ? 'checked' : 'unchecked';
108
- }
109
- validate() {
110
- if (this.props.required === true && !this.current) {
111
- this.internals.setValidity({ valueMissing: true }, requiredCheckboxMessage(), this.ref('track') ?? undefined);
112
- }
113
- else {
114
- this.internals.setValidity({});
115
- }
116
- }
117
- resetToDefault() {
118
- this.dirty = false;
119
- this.setCurrent(this.props.checked === true);
120
- }
121
- restoreState(state) {
122
- this.dirty = true;
123
- this.setCurrent(state === 'checked');
10
+ paint() {
11
+ this.ref('track')?.classList.toggle('on', this.checked);
124
12
  }
125
13
  }