@fusion.dev/helix-headless 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +234 -234
- package/dist/accordion/item/accordion-item.js +0 -108
- package/dist/accordion/root/accordion-root.js +0 -33
- package/dist/announcement/root/announcement-root.js +1 -76
- package/dist/app-header/root/app-header-root.js +0 -84
- package/dist/avatar/group/avatar-group.js +0 -77
- package/dist/avatar/root/avatar-root.js +0 -72
- package/dist/badge/root/badge-root.js +0 -67
- package/dist/bar-chart/root/bar-chart-root.js +3 -263
- package/dist/blockquote/root/blockquote-root.js +0 -46
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +0 -72
- package/dist/breadcrumbs/root/breadcrumbs-root.js +0 -52
- package/dist/button/root/button-root.js +0 -215
- package/dist/button-group/root/button-group-root.js +0 -30
- package/dist/callout/root/callout-root.js +0 -52
- package/dist/card/root/card-root.js +0 -41
- package/dist/carousel/root/carousel-root.d.ts +2 -2
- package/dist/carousel/root/carousel-root.js +2 -362
- package/dist/chat/composer/chat-composer.js +0 -131
- package/dist/chat/message/chat-message.js +0 -137
- package/dist/chat/root/chat-root.js +0 -193
- package/dist/checkbox/root/checkbox-root.js +0 -113
- package/dist/checkbox-group/root/checkbox-group-root.js +1 -157
- package/dist/code/root/code-root.js +0 -26
- package/dist/code-block/root/code-block-root.js +0 -100
- package/dist/color-input/root/color-input-root.js +0 -217
- package/dist/color-picker/color.js +0 -69
- package/dist/color-picker/root/color-picker-root.js +0 -272
- package/dist/combobox/root/combobox-root.js +0 -428
- package/dist/command/root/command-root.js +0 -177
- package/dist/copy-button/root/copy-button-root.js +0 -134
- package/dist/data-table/root/data-table-root.js +0 -336
- package/dist/data-table/root/order.js +0 -100
- package/dist/date-input/root/date-input-root.js +1 -398
- package/dist/date-picker/root/date-picker-root.js +0 -358
- package/dist/dialog/root/dialog-root.js +0 -189
- package/dist/divider/root/divider-root.js +0 -71
- package/dist/donut-chart/root/donut-chart-root.js +0 -214
- package/dist/drawer/root/drawer-root.js +0 -116
- package/dist/drilldown/item/drilldown-item.js +0 -82
- package/dist/drilldown/root/drilldown-root.js +0 -91
- package/dist/element-events.generated.js +0 -5
- package/dist/empty/root/empty-root.js +0 -35
- package/dist/file-input/root/file-input-root.js +0 -232
- package/dist/format-date/root/format-date-root.js +0 -95
- package/dist/heatmap/root/buckets.js +0 -57
- package/dist/heatmap/root/heatmap-root.js +0 -313
- package/dist/icon/root/icon-root.js +0 -48
- package/dist/icon-button/root/icon-button-root.js +0 -30
- package/dist/image/root/image-root.js +0 -174
- package/dist/index.js +0 -9
- package/dist/input/root/input-root.js +0 -228
- package/dist/kbd/root/kbd-root.js +0 -117
- package/dist/legend/root/legend-root.js +0 -73
- package/dist/line-chart/root/line-chart-root.js +0 -172
- package/dist/list/item/list-item.js +0 -92
- package/dist/list/root/list-root.js +0 -26
- package/dist/listbox/root/listbox-root.js +2 -429
- package/dist/loader/root/loader-root.js +0 -40
- package/dist/megamenu/root/megamenu-root.js +0 -284
- package/dist/menu/item/menu-item.js +1 -221
- package/dist/menu/root/menu-root.js +1 -171
- package/dist/meter/root/meter-root.js +1 -152
- package/dist/navigation/root/navigation-root.js +0 -56
- package/dist/notifications/notification/notification.js +0 -159
- package/dist/notifications/root/notifications-root.js +0 -148
- package/dist/number-input/root/number-input-root.js +1 -263
- package/dist/option/group/option-group.js +0 -26
- package/dist/option/root/option-root.js +0 -157
- package/dist/outline/root/outline-root.js +0 -292
- package/dist/pagination/root/pagination-root.js +0 -361
- package/dist/pagination/size/pagination-size.js +0 -104
- package/dist/pagination/summary/pagination-summary.js +0 -90
- package/dist/pin-input/root/pin-input-root.js +0 -276
- package/dist/popover/root/popover-root.js +0 -103
- package/dist/progress/root/progress-root.js +1 -133
- package/dist/qr-code/root/qr-code-root.js +0 -96
- package/dist/quote/root/quote-root.js +0 -25
- package/dist/radio/group/radio-group.js +0 -81
- package/dist/radio/root/radio-root.js +0 -85
- package/dist/rating/root/rating-root.js +0 -220
- package/dist/scroll-area/root/scroll-area-root.js +0 -100
- package/dist/select/root/select-root.js +2 -218
- package/dist/skeleton/root/skeleton-root.js +0 -20
- package/dist/slider/root/slider-root.js +1 -267
- package/dist/sparkline/root/sparkline-root.js +3 -164
- package/dist/speed-dial/item/speed-dial-item.js +0 -52
- package/dist/speed-dial/root/speed-dial-root.js +1 -116
- package/dist/splitter/root/splitter-root.js +0 -489
- package/dist/stat/group/stat-group.js +0 -18
- package/dist/stat/root/stat-root.js +0 -23
- package/dist/steps/root/steps-root.js +0 -62
- package/dist/steps/step/step.js +0 -131
- package/dist/switch/root/switch-root.js +0 -80
- package/dist/table/cell/table-cell.js +0 -23
- package/dist/table/column/table-column.js +0 -158
- package/dist/table/root/table-root.js +0 -82
- package/dist/table/row/table-row.js +0 -21
- package/dist/tabs/panel/tab-panel.js +0 -49
- package/dist/tabs/root/tabs-root.js +0 -98
- package/dist/tabs/tab/tab.js +0 -59
- package/dist/tag/root/tag-root.js +0 -31
- package/dist/textarea/root/textarea-root.js +0 -162
- package/dist/time-input/root/time-input-root.js +0 -283
- package/dist/time-picker/root/time-picker-root.js +0 -326
- package/dist/timeline/item/timeline-item.js +0 -66
- package/dist/timeline/root/timeline-root.js +0 -41
- package/dist/toast/item/toast-item.js +0 -165
- package/dist/toast/root/toast-root.js +0 -51
- package/dist/toggle/group/toggle-group.js +0 -150
- package/dist/toggle/root/toggle-root.js +0 -78
- package/dist/toolbar/root/toolbar-root.js +0 -116
- package/dist/tooltip/root/tooltip-root.js +0 -427
- package/dist/tour/root/tour-root.js +0 -130
- package/dist/tour/stop/tour-stop.js +1 -127
- package/dist/tree/item/tree-item.js +0 -198
- package/dist/tree/root/tree-root.js +0 -97
- package/dist/trend/root/trend-root.js +0 -53
- package/dist/video/root/video-root.d.ts +8 -12
- package/dist/video/root/video-root.js +5 -756
- package/dist/video-playlist/item/video-playlist-item.js +1 -90
- package/dist/video-playlist/menu/video-playlist-menu.js +1 -132
- package/dist/video-playlist/root/video-playlist-root.js +0 -113
- package/dist/virtual-list/root/virtual-list-root.js +0 -105
- package/jsx.d.ts +1408 -2576
- package/package.json +6 -6
- package/vue.d.ts +1 -1
|
@@ -9,197 +9,26 @@ import { eyedropper } from '@fusion.dev/helix-icons';
|
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
import { html } from 'lit/static-html.js';
|
|
12
|
-
/* Side-effect import, because this renders a slider in its own shadow root and
|
|
13
|
-
a custom element registers on import. The path is relative, so this registers
|
|
14
|
-
the base slider and the styled file's identical import registers the styled
|
|
15
|
-
one; `tier` picks which name the template asks for. */
|
|
16
12
|
import '../../button/index.js';
|
|
17
13
|
import '../../button-group/index.js';
|
|
18
14
|
import '../../slider/index.js';
|
|
19
15
|
import { formatColor, parseColor, splitColors, toCss, } from '../color.js';
|
|
20
|
-
/** The formats the toggle walks through, in the order it walks them. */
|
|
21
16
|
const FORMATS = ['hex', 'rgb', 'hsl'];
|
|
22
|
-
/**
|
|
23
|
-
* Where a picker starts when there is nothing to start from.
|
|
24
|
-
*
|
|
25
|
-
* Not black, which is what `<input type="color">` opens on. Black is
|
|
26
|
-
* `brightness: 0`, and from there the hue ramp moves nothing and the square is
|
|
27
|
-
* one flat color: the whole thing is dead until the reader happens to raise
|
|
28
|
-
* brightness first. Pure red is the nearest color where everything answers the
|
|
29
|
-
* first thing touched.
|
|
30
|
-
*/
|
|
31
17
|
const START = { alpha: 100, brightness: 100, hue: 0, saturation: 100 };
|
|
32
|
-
/**
|
|
33
|
-
* @summary Picks a color, from a square and two ramps.
|
|
34
|
-
*
|
|
35
|
-
* @description
|
|
36
|
-
* **The picker itself, with no field around it.** Color Input is this element in
|
|
37
|
-
* a panel behind a text field, the same way Date Input is `helix-date-picker` in a
|
|
38
|
-
* panel: a form wants a field, and a settings pane or a toolbar wants the picker
|
|
39
|
-
* sitting flat on the page with nothing to open. Neither should be the other one
|
|
40
|
-
* with parts hidden.
|
|
41
|
-
*
|
|
42
|
-
* **The square is two real range inputs.** Saturation and brightness are each an
|
|
43
|
-
* `<input type="range">`, laid over the square and made invisible, and the
|
|
44
|
-
* handle is drawn from their values. The pointer gets the square; the keyboard
|
|
45
|
-
* gets the arrow keys, Home, End and the page keys; a screen reader gets two
|
|
46
|
-
* sliders that announce a name and a number. All of it is the platform's, and
|
|
47
|
-
* nothing here implements a key handler. There is no `role="application"`, which
|
|
48
|
-
* is the usual way this control is built and amounts to asking a screen reader
|
|
49
|
-
* to stop helping.
|
|
50
|
-
*
|
|
51
|
-
* **The working model is HSB, and the value is derived from it.** The reverse
|
|
52
|
-
* loses colors: black is `brightness: 0`, whose hue and saturation are both
|
|
53
|
-
* undefined, so a reader who drags to the bottom of the square and back would
|
|
54
|
-
* get gray where they had red. Holding the model means a color survives a trip
|
|
55
|
-
* through one that has no hue. A value arriving from outside is read into the
|
|
56
|
-
* model once, which is the only moment the conversion runs in that direction.
|
|
57
|
-
*
|
|
58
|
-
* **Every syntax is read; the one `format` names is written.** `#f00`,
|
|
59
|
-
* `#ff0000`, `rgb(255 0 0)`, `rgba(255,0,0,.5)` and `hsl(0 100% 50%)` are all
|
|
60
|
-
* colors. Named colors are the exception, and deliberately: resolving
|
|
61
|
-
* `rebeccapurple` means shipping a table of a hundred and forty or asking the
|
|
62
|
-
* browser, and there is no browser during a server render.
|
|
63
|
-
*
|
|
64
|
-
* The properties below are written by this component and read by whoever draws
|
|
65
|
-
* it. A consumer sets none of them: they carry a number this element computed
|
|
66
|
-
* and CSS cannot, which is what lets a stylesheet on this tier draw the thing
|
|
67
|
-
* without measuring anything itself.
|
|
68
|
-
*
|
|
69
|
-
* @since 0.1.0
|
|
70
|
-
* @status experimental
|
|
71
|
-
* @category forms
|
|
72
|
-
* @aliases Color, ColorArea, Swatch picker
|
|
73
|
-
* @documentation https://helix.fusion.dev/components/color-picker
|
|
74
|
-
*
|
|
75
|
-
* @slot eyedropper-icon - The glyph on the screen-sampling control, usually a dropper.
|
|
76
|
-
*
|
|
77
|
-
* @event {Event} change - Announced once the value has moved.
|
|
78
|
-
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the color changes. Cancelable: refusing it takes the decision and nothing moves.
|
|
79
|
-
* @event {HelixCopyEvent} helix-copy - Fired when the color is put on the clipboard.
|
|
80
|
-
* @event {HelixSampleEndEvent} helix-sample-end - The eyedropper has closed, whether or not a color was taken.
|
|
81
|
-
* @event {HelixSampleStartEvent} helix-sample-start - The eyedropper is opening, so anything covering the page should get out of the way.
|
|
82
|
-
* @event {Event} input - Announced once the value has moved.
|
|
83
|
-
*
|
|
84
|
-
* @csspart actions - The group holding the eyedropper and the syntax toggle.
|
|
85
|
-
* @csspart channel - One ramp.
|
|
86
|
-
* @csspart channel-control - The range input.
|
|
87
|
-
* @csspart channel-feedback - What is wrong with it.
|
|
88
|
-
* @csspart channel-field - The row: the control and its readout.
|
|
89
|
-
* @csspart channel-hint - Help under the track, while nothing is wrong.
|
|
90
|
-
* @csspart channel-label - The question, over the track.
|
|
91
|
-
* @csspart channel-marker - One mark.
|
|
92
|
-
* @csspart channel-marker-label - The value a mark stands at, when `marker-labels` is set.
|
|
93
|
-
* @csspart channel-markers - The row of marks along the track.
|
|
94
|
-
* @csspart channel-output - The current value, shown beside it.
|
|
95
|
-
* @csspart channels - The ramps beside it.
|
|
96
|
-
* @csspart controls - The row under the square.
|
|
97
|
-
* @csspart eyedropper - The control that samples a color from the screen.
|
|
98
|
-
* @csspart eyedropper-button - The inner control.
|
|
99
|
-
* @csspart footer - The row holding the value and the tools.
|
|
100
|
-
* @csspart format - The control that changes the syntax the value is written in.
|
|
101
|
-
* @csspart format-button - The inner control.
|
|
102
|
-
* @csspart grid - The saturation and brightness square.
|
|
103
|
-
* @csspart grid-brightness - The range input for its vertical axis.
|
|
104
|
-
* @csspart grid-handle - The mark showing where in the square the color sits.
|
|
105
|
-
* @csspart grid-saturation - The range input for the square's horizontal axis.
|
|
106
|
-
* @csspart sample - The chip of the current color, which copies it when pressed.
|
|
107
|
-
* @csspart swatch - One preset.
|
|
108
|
-
* @csspart swatches - The row of presets.
|
|
109
|
-
* @csspart value - The color as text, which can be typed or pasted.
|
|
110
|
-
*
|
|
111
|
-
* @cssproperty --color-picker-brightness - The chosen brightness, 0 to 100, as a percentage.
|
|
112
|
-
* @cssproperty --color-picker-hue - The chosen hue, 0 to 360, unitless.
|
|
113
|
-
* @cssproperty --color-picker-saturation - The chosen saturation, 0 to 100, as a percentage.
|
|
114
|
-
* @cssproperty --color-picker-swatch - A color to paint: the current one on the sample, a preset's on each preset.
|
|
115
|
-
*/
|
|
116
18
|
let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinControllerValue(HelixFormElement) {
|
|
117
19
|
constructor() {
|
|
118
20
|
super(...arguments);
|
|
119
|
-
/**
|
|
120
|
-
* Whether the color carries an alpha channel.
|
|
121
|
-
*
|
|
122
|
-
* Off by default, because it widens every value written, and a consumer who
|
|
123
|
-
* did not ask for transparency should not have to strip a byte off each one.
|
|
124
|
-
*/
|
|
125
21
|
this.alpha = false;
|
|
126
|
-
/**
|
|
127
|
-
* What the browser may autofill in the text field, as a platform token.
|
|
128
|
-
*
|
|
129
|
-
* **Defaults to `off`, which is not the platform's default and is the
|
|
130
|
-
* point.** The field holds a color, so a browser offering to fill it with a
|
|
131
|
-
* saved address is competing for the same keystrokes as the square and the
|
|
132
|
-
* ramps. A consumer who wants autofill can still ask.
|
|
133
|
-
*/
|
|
134
22
|
this.autocomplete = 'off';
|
|
135
|
-
/**
|
|
136
|
-
* Whether the current selection fails validation.
|
|
137
|
-
*
|
|
138
|
-
* A flag rather than a message, the split Date Picker also draws. A flat
|
|
139
|
-
* picker has no room of its own for a sentence: the field that wraps one owns
|
|
140
|
-
* the label, the hint and the feedback, and a second message inside the panel
|
|
141
|
-
* would be the same error said twice. What is left for the picker is the one
|
|
142
|
-
* thing the field cannot draw from outside, the mark on the answer itself.
|
|
143
|
-
*/
|
|
144
23
|
this.invalid = false;
|
|
145
|
-
/**
|
|
146
|
-
* Whether the eyedropper is offered where the browser has one.
|
|
147
|
-
*/
|
|
148
24
|
this.noEyedropper = false;
|
|
149
|
-
/**
|
|
150
|
-
* Whether the reader may change the format.
|
|
151
|
-
*/
|
|
152
25
|
this.noFormat = false;
|
|
153
|
-
/**
|
|
154
|
-
* Whether to leave the value out, for a picker whose value is stated elsewhere.
|
|
155
|
-
*
|
|
156
|
-
* The row reads the color as text and lets it be typed or pasted, which is
|
|
157
|
-
* what makes this element complete standing on a page: a square and two ramps
|
|
158
|
-
* can build a color and cannot state one, and a reader who has a hex already
|
|
159
|
-
* should not have to find it by dragging.
|
|
160
|
-
*
|
|
161
|
-
* Color Input sets this, because its field is that input. Two editable fields
|
|
162
|
-
* for one value is the outcome worth avoiding: two places to type, and no
|
|
163
|
-
* answer to which one is authoritative or which has the caret. Do not close it
|
|
164
|
-
* the other way round, with Color Input dropping its own field: the value
|
|
165
|
-
* would then be unreadable and unpasteable without opening a panel.
|
|
166
|
-
*/
|
|
167
26
|
this.noValue = false;
|
|
168
|
-
/**
|
|
169
|
-
* Colors offered under the picker, as a comma-separated list.
|
|
170
|
-
*/
|
|
171
27
|
this.swatches = '';
|
|
172
|
-
/**
|
|
173
|
-
* Whether this browser can sample a color off the screen.
|
|
174
|
-
*
|
|
175
|
-
* Settled after the first render rather than at construction, because there is
|
|
176
|
-
* no `window` on the server, and a button that ships in the markup and does
|
|
177
|
-
* nothing in Firefox is worse than one that is never offered.
|
|
178
|
-
*/
|
|
179
28
|
this.sampling = false;
|
|
180
|
-
/**
|
|
181
|
-
* Whether the value on this element was produced here.
|
|
182
|
-
*
|
|
183
|
-
* The one bit that keeps the model from being overwritten by the value it just
|
|
184
|
-
* produced. Without it, dragging to the bottom of the square writes black,
|
|
185
|
-
* which reads back as hue 0 and saturation 0, and the next drag starts gray.
|
|
186
|
-
*/
|
|
187
29
|
this.owned = false;
|
|
188
|
-
/**
|
|
189
|
-
* The last value that was a color.
|
|
190
|
-
*
|
|
191
|
-
* Half-typed input reaches the row on every keystroke and most of it is not a
|
|
192
|
-
* color, so the square is given the last thing that was one. Typing `#00ff00`
|
|
193
|
-
* a character at a time goes `#`, `#0`, `#00`, `#00f`, `#00ff`, `#00ff0`,
|
|
194
|
-
* `#00ff00`: two of those are colors and the ones between are not, so without
|
|
195
|
-
* this the square walks red, blue, red, green. Color Input keeps the same
|
|
196
|
-
* guard for its own field, each local to the input it protects.
|
|
197
|
-
*/
|
|
198
30
|
this.settled = '';
|
|
199
|
-
/** Takes what was typed, and lets the square follow only a whole color. */
|
|
200
31
|
this.handleValueInput = (event) => {
|
|
201
|
-
// Stopped for the reason `Input.handleInput` gives: the inner control's own
|
|
202
|
-
// `input` is composed and would reach a consumer beside this element's.
|
|
203
32
|
event.stopPropagation();
|
|
204
33
|
const typed = event.target.value;
|
|
205
34
|
const parsed = parseColor(typed);
|
|
@@ -209,49 +38,24 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
209
38
|
}
|
|
210
39
|
this.requestValue(typed);
|
|
211
40
|
};
|
|
212
|
-
/** Moves part of the model and announces the value that follows from it. */
|
|
213
41
|
this.move = (next) => {
|
|
214
42
|
this.moved = { ...this.color, ...next };
|
|
215
43
|
this.owned = true;
|
|
216
44
|
this.requestValue(formatColor(this.moved, this.format ?? 'hex', this.alpha));
|
|
217
45
|
};
|
|
218
|
-
/**
|
|
219
|
-
* Copying the value, which is the one thing here worth taking away.
|
|
220
|
-
*
|
|
221
|
-
* A reader who has just built a color wants it in a stylesheet, and the
|
|
222
|
-
* alternative is selecting text out of a field that may not be on screen. The
|
|
223
|
-
* chip is the obvious target: it is the color, at the size of a control.
|
|
224
|
-
*
|
|
225
|
-
* The controller rather than four lines here, because Copy Button shares
|
|
226
|
-
* everything about this that is easy to get wrong: the write, the
|
|
227
|
-
* confirmation, the timer that ends it, the event, and a failure that is
|
|
228
|
-
* correctly silent.
|
|
229
|
-
*/
|
|
230
46
|
this.copier = new CopyController(this);
|
|
231
|
-
/** Takes a preset, in this picker's syntax rather than as the preset spelled it. */
|
|
232
47
|
this.handleSwatch = (preset) => {
|
|
233
48
|
const parsed = parseColor(preset);
|
|
234
49
|
if (parsed) {
|
|
235
50
|
this.move(parsed);
|
|
236
51
|
}
|
|
237
52
|
};
|
|
238
|
-
/** Walks the format on, and rewrites the value in it. */
|
|
239
53
|
this.handleFormat = () => {
|
|
240
54
|
this.format = FORMATS[(FORMATS.indexOf(this.format ?? 'hex') + 1) % FORMATS.length] ?? 'hex';
|
|
241
55
|
if (this.value !== '') {
|
|
242
56
|
this.move({});
|
|
243
57
|
}
|
|
244
58
|
};
|
|
245
|
-
/**
|
|
246
|
-
* Samples a color from anywhere on the screen.
|
|
247
|
-
*
|
|
248
|
-
* `helix-sample-start` and `helix-sample-end` bracket it, because whatever is
|
|
249
|
-
* holding this picker may need to get out of the way: `EyeDropper` takes the
|
|
250
|
-
* pointer over, and a floating panel left up during it is one the reader
|
|
251
|
-
* cannot dismiss and may well be trying to sample from underneath. This
|
|
252
|
-
* element cannot know it is in a panel, so it says what it is doing and lets
|
|
253
|
-
* whatever does know decide.
|
|
254
|
-
*/
|
|
255
59
|
this.handleEyeDropper = async () => {
|
|
256
60
|
const Dropper = globalThis.EyeDropper;
|
|
257
61
|
if (!Dropper) {
|
|
@@ -262,29 +66,17 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
262
66
|
const { sRGBHex } = await new Dropper().open();
|
|
263
67
|
const parsed = parseColor(sRGBHex);
|
|
264
68
|
if (parsed) {
|
|
265
|
-
// A sample carries no alpha, so whatever was set is kept.
|
|
266
69
|
this.move({ ...parsed, alpha: this.color.alpha });
|
|
267
70
|
}
|
|
268
71
|
}
|
|
269
72
|
catch {
|
|
270
|
-
/* Canceling is how this is normally left, and the platform reports it as
|
|
271
|
-
a rejection. There is nothing to recover from and nothing to say. */
|
|
272
73
|
}
|
|
273
74
|
this.dispatchEvent(new HelixSampleEndEvent());
|
|
274
75
|
};
|
|
275
|
-
/**
|
|
276
|
-
* Dragging in the square.
|
|
277
|
-
*
|
|
278
|
-
* The two ranges are the state, so this reads a point and writes to them
|
|
279
|
-
* rather than keeping a position of its own. Pointer capture, so a drag that
|
|
280
|
-
* leaves the square keeps going: leaving and coming back is how a reader
|
|
281
|
-
* reaches a corner, and without it the handle stops wherever the pointer left.
|
|
282
|
-
*/
|
|
283
76
|
this.handleGridPointer = (event) => {
|
|
284
77
|
const grid = event.currentTarget;
|
|
285
78
|
if (event.type === 'pointerdown') {
|
|
286
79
|
capturePointer(grid, event.pointerId);
|
|
287
|
-
// So the keyboard carries on from where the pointer left off.
|
|
288
80
|
this.renderRoot?.querySelector('[part="grid-saturation"]')?.focus();
|
|
289
81
|
}
|
|
290
82
|
else if (!grid.hasPointerCapture(event.pointerId)) {
|
|
@@ -300,25 +92,12 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
300
92
|
this.move({ brightness: Math.round((1 - down) * 100), saturation: Math.round(across * 100) });
|
|
301
93
|
};
|
|
302
94
|
}
|
|
303
|
-
/** Where the picker stands: what was moved, or what the value says, or the start. */
|
|
304
95
|
get color() {
|
|
305
|
-
/* `settled` between the value and the start, so a half-typed value leaves
|
|
306
|
-
the square where the last whole one put it rather than throwing it back to
|
|
307
|
-
red. Only reached where the value itself is not a color. */
|
|
308
96
|
return this.moved ?? parseColor(this.value) ?? parseColor(this.settled) ?? START;
|
|
309
97
|
}
|
|
310
|
-
/**
|
|
311
|
-
* Whether the tools row holds anything at all.
|
|
312
|
-
*
|
|
313
|
-
* The group is withheld rather than rendered empty, because it is an element
|
|
314
|
-
* with a role and a name: an empty group labeled "Color tools" announces
|
|
315
|
-
* nothing, and the footer cannot tell it is empty either, so the row kept its
|
|
316
|
-
* padding with nothing in it.
|
|
317
|
-
*/
|
|
318
98
|
get tools() {
|
|
319
99
|
return (this.sampling && !this.noEyedropper) || !this.noFormat;
|
|
320
100
|
}
|
|
321
|
-
/** The presets, as written, with anything that is not a color dropped. */
|
|
322
101
|
get presets() {
|
|
323
102
|
return splitColors(this.swatches).filter((one) => parseColor(one) !== null);
|
|
324
103
|
}
|
|
@@ -332,9 +111,6 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
332
111
|
if (parseColor(this.value)) {
|
|
333
112
|
this.settled = this.value;
|
|
334
113
|
}
|
|
335
|
-
/* Let go only where the value came from somewhere else, so the getter
|
|
336
|
-
reads that value instead. `owned` is cleared here rather than where it
|
|
337
|
-
is set, so it covers exactly the one update this element caused. */
|
|
338
114
|
if (this.owned) {
|
|
339
115
|
this.owned = false;
|
|
340
116
|
}
|
|
@@ -343,16 +119,9 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
343
119
|
}
|
|
344
120
|
}
|
|
345
121
|
}
|
|
346
|
-
/** Puts the keyboard on the square, which is the control a reader wants. */
|
|
347
122
|
focus(options) {
|
|
348
123
|
this.renderRoot?.querySelector('[part="grid-saturation"]')?.focus(options);
|
|
349
124
|
}
|
|
350
|
-
/**
|
|
351
|
-
* One of the ramps under the square.
|
|
352
|
-
*
|
|
353
|
-
* `protected` rather than `private`, the method being the seam a tier above
|
|
354
|
-
* renders its own ramp through.
|
|
355
|
-
*/
|
|
356
125
|
renderChannel(channel, label, max, value) {
|
|
357
126
|
return html `<${this.tag('slider')}
|
|
358
127
|
part="channel"
|
|
@@ -369,61 +138,20 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
369
138
|
@change=${(event) => this.takeChannel(channel, event)}
|
|
370
139
|
></${this.tag('slider')}>`;
|
|
371
140
|
}
|
|
372
|
-
/**
|
|
373
|
-
* One axis of the area, taken the way `takeChannel` takes a rail.
|
|
374
|
-
*
|
|
375
|
-
* **Named rather than inline because of the first line.** The `<input
|
|
376
|
-
* type="range">` behind each axis sends its own composed `input`, which
|
|
377
|
-
* reaches a consumer listening on this element beside this element's own
|
|
378
|
-
* unless it is stopped: a consumer dragging the area receives the range's
|
|
379
|
-
* event and not this component's.
|
|
380
|
-
*/
|
|
381
141
|
takeArea(axis, event) {
|
|
382
142
|
event.stopPropagation();
|
|
383
143
|
const { value } = event.target;
|
|
384
144
|
this.move({ [axis]: Number(value) });
|
|
385
145
|
}
|
|
386
|
-
/**
|
|
387
|
-
* A channel's new value, read off the slider that just applied it.
|
|
388
|
-
*
|
|
389
|
-
* **Both native events, because a slider sends both and at different
|
|
390
|
-
* moments.** It is one of the controls a reader edits continuously, so it
|
|
391
|
-
* announces `input` all the way through a drag and `change` when the drag
|
|
392
|
-
* ends. Listening only for the commit leaves the picker deaf while a handle
|
|
393
|
-
* moves, and the hue and alpha handles do not move at all.
|
|
394
|
-
*
|
|
395
|
-
* **Read off the target rather than out of a detail.** Do not bind
|
|
396
|
-
* `helix-input` and `helix-change` and take the proposed value out of the
|
|
397
|
-
* event: those are requests, announcing what the slider is *about* to do,
|
|
398
|
-
* before anything has moved and while a listener may still refuse it. The
|
|
399
|
-
* native pair fires after the slider applied, so the value is on the element
|
|
400
|
-
* and cannot disagree with it.
|
|
401
|
-
*
|
|
402
|
-
* Idempotent, so taking both costs nothing: the same value applied twice is
|
|
403
|
-
* the same color.
|
|
404
|
-
*/
|
|
405
146
|
takeChannel(channel, event) {
|
|
406
147
|
event.stopPropagation();
|
|
407
148
|
const { value } = event.target;
|
|
408
149
|
this.move({ [channel]: Number(value) });
|
|
409
150
|
}
|
|
410
|
-
/* `ariaInvalid` on the host through `ElementInternals`, the same route
|
|
411
|
-
Date Picker takes and for the reason the whole library records: a `role` or a
|
|
412
|
-
state written onto the host as an attribute is one a React consumer's
|
|
413
|
-
server markup never had. */
|
|
414
151
|
willUpdate(changed) {
|
|
415
152
|
super.willUpdate(changed);
|
|
416
153
|
this.internals.ariaInvalid = this.invalid ? 'true' : null;
|
|
417
154
|
}
|
|
418
|
-
/**
|
|
419
|
-
* The eyedropper and the swatch tools, which are a group of buttons, behind a seam the styled tier can move.
|
|
420
|
-
*
|
|
421
|
-
* A method rather than a fragment inline, so a tier above can render its own,
|
|
422
|
-
* wrap this one, pass it a property the base does not know about, or leave it
|
|
423
|
-
* out, without reimplementing the whole template. The tag is interpolated
|
|
424
|
-
* rather than written, so `tier` resolves it and one template serves both
|
|
425
|
-
* tiers.
|
|
426
|
-
*/
|
|
427
155
|
renderTools() {
|
|
428
156
|
return html `<${this.tag('button-group')} part="actions" label="Color tools">
|
|
429
157
|
${this.sampling && !this.noEyedropper
|