ember-primitives 0.61.1 → 0.63.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/README.md +8 -1
- package/declarations/components/accordion/content.d.ts +2 -1
- package/declarations/components/accordion/content.d.ts.map +1 -1
- package/declarations/components/accordion/header.d.ts +2 -1
- package/declarations/components/accordion/header.d.ts.map +1 -1
- package/declarations/components/accordion/item.d.ts +7 -0
- package/declarations/components/accordion/item.d.ts.map +1 -1
- package/declarations/components/accordion/public.d.ts +3 -3
- package/declarations/components/accordion/public.d.ts.map +1 -1
- package/declarations/components/accordion/trigger.d.ts +2 -1
- package/declarations/components/accordion/trigger.d.ts.map +1 -1
- package/declarations/components/command-palette.d.ts +329 -0
- package/declarations/components/command-palette.d.ts.map +1 -0
- package/declarations/components/dialog.d.ts +65 -7
- package/declarations/components/dialog.d.ts.map +1 -1
- package/declarations/components/drawer.d.ts +14 -6
- package/declarations/components/drawer.d.ts.map +1 -1
- package/declarations/components/link.d.ts.map +1 -1
- package/declarations/components/menu.d.ts.map +1 -1
- package/declarations/components/one-time-password/otp.d.ts +1 -1
- package/declarations/components/one-time-password/utils.d.ts.map +1 -1
- package/declarations/components/rating/range.d.ts +1 -0
- package/declarations/components/rating/range.d.ts.map +1 -1
- package/declarations/components/rating/rating.d.ts +1 -1
- package/declarations/components/rating/rating.d.ts.map +1 -1
- package/declarations/components/rating/stars.d.ts.map +1 -1
- package/declarations/components/rating/state.d.ts +1 -0
- package/declarations/components/rating/state.d.ts.map +1 -1
- package/declarations/components/slider.d.ts +2 -0
- package/declarations/components/slider.d.ts.map +1 -1
- package/declarations/components/switch.d.ts +5 -1
- package/declarations/components/switch.d.ts.map +1 -1
- package/declarations/components/tabs.d.ts +30 -1
- package/declarations/components/tabs.d.ts.map +1 -1
- package/declarations/components/zoetrope/index.d.ts.map +1 -1
- package/declarations/index.d.ts +2 -1
- package/declarations/index.d.ts.map +1 -1
- package/dist/components/accordion.js +12 -4
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/command-palette.js +370 -0
- package/dist/components/command-palette.js.map +1 -0
- package/dist/components/dialog.js +59 -3
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/drawer.js +9 -2
- package/dist/components/drawer.js.map +1 -1
- package/dist/components/link.js +1 -1
- package/dist/components/link.js.map +1 -1
- package/dist/components/menu.js +5 -1
- package/dist/components/menu.js.map +1 -1
- package/dist/components/one-time-password.js +1 -1
- package/dist/components/rating.js +1 -1
- package/dist/components/slider.js +6 -1
- package/dist/components/switch.js +1 -1
- package/dist/components/switch.js.map +1 -1
- package/dist/components/tabs.js +18 -5
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/zoetrope/styles.css +6 -1
- package/dist/components/zoetrope.js +1 -1
- package/dist/{index-gRO4Cvlf.js → index-B-yrfUe9.js} +10 -3
- package/dist/index-B-yrfUe9.js.map +1 -0
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/{otp-H5a4B4yu.js → otp-C8c1EIw6.js} +27 -15
- package/dist/otp-C8c1EIw6.js.map +1 -0
- package/dist/{rating-BrIiwDLw.js → rating-CKWhrr-L.js} +9 -5
- package/dist/rating-CKWhrr-L.js.map +1 -0
- package/package.json +2 -1
- package/src/components/accordion/content.gts +4 -2
- package/src/components/accordion/header.gts +8 -2
- package/src/components/accordion/item.gts +18 -2
- package/src/components/accordion/public.ts +12 -3
- package/src/components/accordion/trigger.gts +5 -3
- package/src/components/command-palette.gts +741 -0
- package/src/components/dialog.gts +86 -4
- package/src/components/drawer.gts +15 -3
- package/src/components/link.gts +1 -0
- package/src/components/menu.gts +7 -0
- package/src/components/one-time-password/input.gts +1 -1
- package/src/components/one-time-password/otp.gts +1 -1
- package/src/components/one-time-password/utils.ts +26 -13
- package/src/components/rating/range.gts +3 -0
- package/src/components/rating/rating.gts +7 -2
- package/src/components/rating/stars.gts +0 -1
- package/src/components/rating/state.gts +9 -0
- package/src/components/slider.gts +8 -0
- package/src/components/switch.gts +5 -2
- package/src/components/tabs.gts +35 -4
- package/src/components/zoetrope/index.gts +12 -3
- package/src/components/zoetrope/styles.css +6 -1
- package/src/index.ts +2 -1
- package/dist/index-gRO4Cvlf.js.map +0 -1
- package/dist/otp-H5a4B4yu.js.map +0 -1
- package/dist/rating-BrIiwDLw.js.map +0 -1
|
@@ -14,6 +14,11 @@ import { localCopy } from "tracked-toolbox";
|
|
|
14
14
|
import type { TOC } from "@ember/component/template-only";
|
|
15
15
|
import type { ModifierLike, WithBoundArgs } from "@glint/template";
|
|
16
16
|
|
|
17
|
+
interface RegisterSignature {
|
|
18
|
+
Element: HTMLDialogElement;
|
|
19
|
+
Args: { Named: { open: boolean | undefined } };
|
|
20
|
+
}
|
|
21
|
+
|
|
17
22
|
const DialogElement: TOC<{
|
|
18
23
|
Element: HTMLDialogElement;
|
|
19
24
|
Args: {
|
|
@@ -29,11 +34,11 @@ const DialogElement: TOC<{
|
|
|
29
34
|
/**
|
|
30
35
|
* @internal
|
|
31
36
|
*/
|
|
32
|
-
register: ModifierLike<
|
|
37
|
+
register: ModifierLike<RegisterSignature>;
|
|
33
38
|
};
|
|
34
39
|
Blocks: { default: [] };
|
|
35
40
|
}> = <template>
|
|
36
|
-
<dialog ...attributes
|
|
41
|
+
<dialog ...attributes {{on "close" @onClose}} {{@register open=@open}}>
|
|
37
42
|
{{yield}}
|
|
38
43
|
</dialog>
|
|
39
44
|
</template>;
|
|
@@ -144,7 +149,14 @@ class ModalDialog extends Component<Signature> {
|
|
|
144
149
|
|
|
145
150
|
@tracked declare dialogElement: HTMLDialogElement | undefined;
|
|
146
151
|
|
|
147
|
-
register = eModifier((element
|
|
152
|
+
register = eModifier<RegisterSignature>((element, _, { open }) => {
|
|
153
|
+
/** The `open` attribute shows a non-modal dialog, only `showModal` is modal. */
|
|
154
|
+
if (open && !element.open) {
|
|
155
|
+
element.showModal();
|
|
156
|
+
} else if (open === false && element.open) {
|
|
157
|
+
element.close();
|
|
158
|
+
}
|
|
159
|
+
|
|
148
160
|
/**
|
|
149
161
|
* This is very sad.
|
|
150
162
|
*
|
|
@@ -228,7 +240,77 @@ class ModalDialog extends Component<Signature> {
|
|
|
228
240
|
};
|
|
229
241
|
}
|
|
230
242
|
|
|
243
|
+
export interface SimpleSignature {
|
|
244
|
+
Element: HTMLDialogElement;
|
|
245
|
+
Blocks: {
|
|
246
|
+
default: [
|
|
247
|
+
{
|
|
248
|
+
/**
|
|
249
|
+
* Opens the dialog, modally.
|
|
250
|
+
*/
|
|
251
|
+
open: () => void;
|
|
252
|
+
/**
|
|
253
|
+
* Closes the dialog.
|
|
254
|
+
*/
|
|
255
|
+
close: () => void;
|
|
256
|
+
},
|
|
257
|
+
];
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* A modal `<dialog>` around whatever you put in it, and the two things needed
|
|
263
|
+
* to drive it.
|
|
264
|
+
*
|
|
265
|
+
* ```gjs
|
|
266
|
+
* <Dialog as |d|>
|
|
267
|
+
* <CommandPalette @onSelect={{d.close}} @onOpen={{d.open}} @hotkey="mod+k" />
|
|
268
|
+
* </Dialog>
|
|
269
|
+
* ```
|
|
270
|
+
*
|
|
271
|
+
* The element is here, so a trigger cannot be: whatever opens this either
|
|
272
|
+
* lives inside it, or is a key combination. For a dialog opened by a button
|
|
273
|
+
* beside it, use `<Modal>`, which hands you the element to place.
|
|
274
|
+
*
|
|
275
|
+
* <kbd>Escape</kbd> closes it and focus returns to whatever opened it, which
|
|
276
|
+
* is the `<dialog>` element's own behaviour. Set `closedby` to change which
|
|
277
|
+
* actions dismiss it.
|
|
278
|
+
*/
|
|
279
|
+
export class Dialog extends Component<SimpleSignature> {
|
|
280
|
+
/**
|
|
281
|
+
* A plain field rather than tracked state: it is read when somebody calls
|
|
282
|
+
* `open` or `close`, never while rendering, so nothing has to settle in a
|
|
283
|
+
* second pass.
|
|
284
|
+
*/
|
|
285
|
+
#element: HTMLDialogElement | undefined;
|
|
286
|
+
|
|
287
|
+
register = eModifier((element: HTMLDialogElement) => {
|
|
288
|
+
this.#element = element;
|
|
289
|
+
|
|
290
|
+
return () => {
|
|
291
|
+
this.#element = undefined;
|
|
292
|
+
};
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* `showModal` on an open dialog, and `close` on a closed one, are both
|
|
297
|
+
* no-ops per spec, so neither needs guarding here.
|
|
298
|
+
*/
|
|
299
|
+
open = () => {
|
|
300
|
+
this.#element?.showModal();
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
close = () => {
|
|
304
|
+
this.#element?.close();
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
<template>
|
|
308
|
+
<dialog {{this.register}} ...attributes>
|
|
309
|
+
{{yield (hash open=this.open close=this.close)}}
|
|
310
|
+
</dialog>
|
|
311
|
+
</template>
|
|
312
|
+
}
|
|
313
|
+
|
|
231
314
|
export const Modal = ModalDialog;
|
|
232
|
-
export const Dialog = ModalDialog;
|
|
233
315
|
|
|
234
316
|
export default ModalDialog;
|
|
@@ -14,6 +14,11 @@ import { localCopy } from "tracked-toolbox";
|
|
|
14
14
|
import type { TOC } from "@ember/component/template-only";
|
|
15
15
|
import type { ModifierLike, WithBoundArgs } from "@glint/template";
|
|
16
16
|
|
|
17
|
+
interface RegisterSignature {
|
|
18
|
+
Element: HTMLDialogElement;
|
|
19
|
+
Args: { Named: { open: boolean | undefined } };
|
|
20
|
+
}
|
|
21
|
+
|
|
17
22
|
const DrawerElement: TOC<{
|
|
18
23
|
Element: HTMLDialogElement;
|
|
19
24
|
Args: {
|
|
@@ -29,11 +34,11 @@ const DrawerElement: TOC<{
|
|
|
29
34
|
/**
|
|
30
35
|
* @internal
|
|
31
36
|
*/
|
|
32
|
-
register: ModifierLike<
|
|
37
|
+
register: ModifierLike<RegisterSignature>;
|
|
33
38
|
};
|
|
34
39
|
Blocks: { default: [] };
|
|
35
40
|
}> = <template>
|
|
36
|
-
<dialog ...attributes
|
|
41
|
+
<dialog ...attributes {{on "close" @onClose}} {{@register open=@open}}>
|
|
37
42
|
{{yield}}
|
|
38
43
|
</dialog>
|
|
39
44
|
</template>;
|
|
@@ -144,7 +149,14 @@ class DrawerDialog extends Component<Signature> {
|
|
|
144
149
|
|
|
145
150
|
@tracked declare drawerElement: HTMLDialogElement | undefined;
|
|
146
151
|
|
|
147
|
-
register = eModifier((element
|
|
152
|
+
register = eModifier<RegisterSignature>((element, _, { open }) => {
|
|
153
|
+
/** The `open` attribute shows a non-modal drawer, only `showModal` is modal. */
|
|
154
|
+
if (open && !element.open) {
|
|
155
|
+
element.showModal();
|
|
156
|
+
} else if (open === false && element.open) {
|
|
157
|
+
element.close();
|
|
158
|
+
}
|
|
159
|
+
|
|
148
160
|
/**
|
|
149
161
|
* This is very sad.
|
|
150
162
|
*
|
package/src/components/link.gts
CHANGED
|
@@ -159,6 +159,7 @@ export const Link: TOC<Signature> = <template>
|
|
|
159
159
|
{{else}}
|
|
160
160
|
<a
|
|
161
161
|
data-active={{l.isActive}}
|
|
162
|
+
aria-current={{if l.isActive (if @activeOnSubPaths "true" "page")}}
|
|
162
163
|
href={{if @href @href "##missing##"}}
|
|
163
164
|
{{on "click" l.handleClick}}
|
|
164
165
|
...attributes
|
package/src/components/menu.gts
CHANGED
|
@@ -183,6 +183,8 @@ const installContent = eModifier<{
|
|
|
183
183
|
// listen for the escape key
|
|
184
184
|
function onDocumentKeydown(e: KeyboardEvent) {
|
|
185
185
|
if (isOpen.current && e.key === "Escape") {
|
|
186
|
+
/** Otherwise the same key press also closes a `<dialog>` around the menu. */
|
|
187
|
+
e.preventDefault();
|
|
186
188
|
isOpen.current = false;
|
|
187
189
|
}
|
|
188
190
|
}
|
|
@@ -226,6 +228,7 @@ const Content: TOC<PrivateContentSignature> = <template>
|
|
|
226
228
|
<@PopoverContent
|
|
227
229
|
id={{@contentId}}
|
|
228
230
|
role="menu"
|
|
231
|
+
aria-labelledby={{@triggerElement.current.id}}
|
|
229
232
|
data-tabster={{TABSTER_CONFIG_CONTENT}}
|
|
230
233
|
tabindex="0"
|
|
231
234
|
{{installContent isOpen=@isOpen triggerElement=@triggerElement}}
|
|
@@ -292,6 +295,10 @@ const trigger = eModifier<PrivateTriggerModifierSignature>(
|
|
|
292
295
|
|
|
293
296
|
element.addEventListener("click", onTriggerClick);
|
|
294
297
|
|
|
298
|
+
if (!element.id) {
|
|
299
|
+
element.id = `${contentId}__trigger`;
|
|
300
|
+
}
|
|
301
|
+
|
|
295
302
|
triggerElement.current = element;
|
|
296
303
|
|
|
297
304
|
setReference(element);
|
|
@@ -44,13 +44,21 @@ export function handlePaste(event: Event) {
|
|
|
44
44
|
// multiple text fields
|
|
45
45
|
event.preventDefault();
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
fillFrom(target, clipboardData.getData('Text'));
|
|
48
|
+
|
|
49
|
+
// Selected again, so that another paste gives the same result.
|
|
50
|
+
target.select();
|
|
51
|
+
|
|
52
|
+
// A cancelled paste fires no input event, and @onChange listens for that event.
|
|
53
|
+
target.dispatchEvent(new InputEvent('input', { bubbles: true, inputType: 'insertFromPaste' }));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function fillFrom(target: HTMLInputElement, code: string) {
|
|
49
57
|
let i = 0;
|
|
50
58
|
let currElement: HTMLInputElement | null = target;
|
|
51
59
|
|
|
52
60
|
while (currElement) {
|
|
53
|
-
currElement.value =
|
|
61
|
+
currElement.value = code[i++] || '';
|
|
54
62
|
|
|
55
63
|
const next = nextInput(currElement);
|
|
56
64
|
|
|
@@ -60,11 +68,6 @@ export function handlePaste(event: Event) {
|
|
|
60
68
|
break;
|
|
61
69
|
}
|
|
62
70
|
}
|
|
63
|
-
|
|
64
|
-
// We want to select the first field again
|
|
65
|
-
// so that if someone holds paste, or
|
|
66
|
-
// pastes again, they get the same result.
|
|
67
|
-
target.select();
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
export function handleNavigation(event: KeyboardEvent) {
|
|
@@ -143,17 +146,27 @@ export const autoAdvance = (event: Event) => {
|
|
|
143
146
|
event.target instanceof HTMLInputElement
|
|
144
147
|
);
|
|
145
148
|
|
|
149
|
+
if ('inputType' in event && event.inputType === 'insertFromPaste') return;
|
|
150
|
+
|
|
146
151
|
const value = event.target.value;
|
|
147
152
|
|
|
148
153
|
if (value.length === 0) return;
|
|
149
154
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
155
|
+
const data = 'data' in event && typeof event.data === 'string' ? event.data : '';
|
|
156
|
+
|
|
157
|
+
// Browser autofill puts the whole code in to the first field.
|
|
158
|
+
if (data.length > 1 || (!data && value.length > 1)) {
|
|
159
|
+
fillFrom(event.target, data || value);
|
|
160
|
+
event.target.select();
|
|
154
161
|
|
|
155
|
-
return
|
|
162
|
+
return;
|
|
156
163
|
}
|
|
164
|
+
|
|
165
|
+
if (data) {
|
|
166
|
+
event.target.value = data;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return focusRight(event);
|
|
157
170
|
};
|
|
158
171
|
|
|
159
172
|
export function getCollectiveValue(elementTarget: EventTarget | null, length: number) {
|
|
@@ -6,12 +6,15 @@ export const RatingRange: TOC<{
|
|
|
6
6
|
Element: HTMLInputElement;
|
|
7
7
|
Args: {
|
|
8
8
|
name: string;
|
|
9
|
+
step: number;
|
|
9
10
|
max: number;
|
|
10
11
|
value: number;
|
|
11
12
|
handleChange: (event: Event) => void;
|
|
12
13
|
};
|
|
13
14
|
}> = <template>
|
|
14
15
|
<input
|
|
16
|
+
min="0"
|
|
17
|
+
step={{@step}}
|
|
15
18
|
...attributes
|
|
16
19
|
name={{@name}}
|
|
17
20
|
type="range"
|
|
@@ -103,7 +103,10 @@ export interface Signature {
|
|
|
103
103
|
/**
|
|
104
104
|
* Input range for adjusting the rating via fractional means
|
|
105
105
|
*/
|
|
106
|
-
Range: WithBoundArgs<
|
|
106
|
+
Range: WithBoundArgs<
|
|
107
|
+
typeof RatingRange,
|
|
108
|
+
"step" | "max" | "value" | "name" | "handleChange"
|
|
109
|
+
>;
|
|
107
110
|
},
|
|
108
111
|
];
|
|
109
112
|
label: [
|
|
@@ -159,6 +162,8 @@ export class Rating extends Component<Signature> {
|
|
|
159
162
|
>
|
|
160
163
|
<fieldset
|
|
161
164
|
class="ember-primitives__rating"
|
|
165
|
+
role="radiogroup"
|
|
166
|
+
aria-readonly={{if this.isReadonly "true"}}
|
|
162
167
|
data-total={{r.total}}
|
|
163
168
|
data-value={{r.value}}
|
|
164
169
|
data-readonly={{this.isReadonly}}
|
|
@@ -193,7 +198,7 @@ export class Rating extends Component<Signature> {
|
|
|
193
198
|
Range=(component
|
|
194
199
|
RatingRange
|
|
195
200
|
step=r.step
|
|
196
|
-
max=r.
|
|
201
|
+
max=r.max
|
|
197
202
|
value=r.value
|
|
198
203
|
name=this.name
|
|
199
204
|
handleChange=r.handleChange
|
|
@@ -22,6 +22,7 @@ export class RatingState extends Component<{
|
|
|
22
22
|
stars: number[];
|
|
23
23
|
step: number;
|
|
24
24
|
value: number;
|
|
25
|
+
max: number;
|
|
25
26
|
total: number;
|
|
26
27
|
handleClick: (event: Event) => void;
|
|
27
28
|
handleChange: (event: Event) => void;
|
|
@@ -110,6 +111,13 @@ export class RatingState extends Component<{
|
|
|
110
111
|
|
|
111
112
|
if (!isValid) return;
|
|
112
113
|
|
|
114
|
+
if (this.args.readonly) {
|
|
115
|
+
/** `readonly` has no effect on a radio, cancelling is what restores the checked one. */
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
113
121
|
const selected = event.target?.value;
|
|
114
122
|
|
|
115
123
|
this.setFromString(selected);
|
|
@@ -131,6 +139,7 @@ export class RatingState extends Component<{
|
|
|
131
139
|
{{yield
|
|
132
140
|
(hash
|
|
133
141
|
stars=this.stars
|
|
142
|
+
max=this.max
|
|
134
143
|
total=this.stars.length
|
|
135
144
|
handleClick=this.handleClick
|
|
136
145
|
handleChange=this.handleChange
|
|
@@ -160,6 +160,13 @@ class ThumbComponent extends Component<{
|
|
|
160
160
|
return this.args.thumb?.inputValue ?? this.args.value ?? this.args.store.internalMin;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
/** With tick values the input holds an index, which means nothing when read aloud. */
|
|
164
|
+
get valueText(): string | undefined {
|
|
165
|
+
const tick = this.args.store.tickValues?.[this.value];
|
|
166
|
+
|
|
167
|
+
return tick === undefined ? undefined : String(tick);
|
|
168
|
+
}
|
|
169
|
+
|
|
163
170
|
get isActive(): boolean {
|
|
164
171
|
return this.args.store.activeThumbIndex === this.index;
|
|
165
172
|
}
|
|
@@ -205,6 +212,7 @@ class ThumbComponent extends Component<{
|
|
|
205
212
|
|
|
206
213
|
<template>
|
|
207
214
|
<input
|
|
215
|
+
aria-valuetext={{this.valueText}}
|
|
208
216
|
...attributes
|
|
209
217
|
class="ember-primitives__slider__thumb-input"
|
|
210
218
|
type="range"
|
|
@@ -11,7 +11,11 @@ import type { TOC } from "@ember/component/template-only";
|
|
|
11
11
|
import type { WithBoundArgs } from "@glint/template";
|
|
12
12
|
|
|
13
13
|
export interface Signature {
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The wrapping element.
|
|
16
|
+
* An accessible name belongs on `Control`, or comes from `Label`.
|
|
17
|
+
*/
|
|
18
|
+
Element: HTMLDivElement;
|
|
15
19
|
Args: {
|
|
16
20
|
/**
|
|
17
21
|
* The initial checked value of the Switch.
|
|
@@ -103,7 +107,6 @@ class Checkbox extends Component<ControlSignature> {
|
|
|
103
107
|
type="checkbox"
|
|
104
108
|
role="switch"
|
|
105
109
|
checked={{@checked.current}}
|
|
106
|
-
aria-checked={{@checked.current}}
|
|
107
110
|
data-state={{if @checked.current "on" "off"}}
|
|
108
111
|
{{on "click" this.handleClick}}
|
|
109
112
|
...attributes
|
package/src/components/tabs.gts
CHANGED
|
@@ -30,6 +30,7 @@ const TABSTER_CONFIG = getTabsterAttribute(
|
|
|
30
30
|
mover: {
|
|
31
31
|
direction: MoverDirections.Both,
|
|
32
32
|
cyclic: true,
|
|
33
|
+
hasDefault: true,
|
|
33
34
|
memorizeCurrent: true,
|
|
34
35
|
},
|
|
35
36
|
deloser: {},
|
|
@@ -37,6 +38,12 @@ const TABSTER_CONFIG = getTabsterAttribute(
|
|
|
37
38
|
true,
|
|
38
39
|
);
|
|
39
40
|
|
|
41
|
+
const TABSTER_SELECTED_TAB = getTabsterAttribute({ focusable: { isDefault: true } }, true);
|
|
42
|
+
|
|
43
|
+
function tabsterFor(isSelected: boolean) {
|
|
44
|
+
return isSelected ? TABSTER_SELECTED_TAB : undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
const TabLink: TOC<{
|
|
41
48
|
Element: HTMLAnchorElement;
|
|
42
49
|
Args: {
|
|
@@ -50,10 +57,28 @@ const TabLink: TOC<{
|
|
|
50
57
|
* for linking of aria
|
|
51
58
|
*/
|
|
52
59
|
panelId: string;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @internal
|
|
63
|
+
* for managing state
|
|
64
|
+
*/
|
|
65
|
+
value: string | undefined;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @internal
|
|
69
|
+
*/
|
|
70
|
+
state: TabState;
|
|
53
71
|
};
|
|
54
72
|
Blocks: { default: [] };
|
|
55
73
|
}> = <template>
|
|
56
|
-
<a
|
|
74
|
+
<a
|
|
75
|
+
href="##missing##"
|
|
76
|
+
...attributes
|
|
77
|
+
role="tab"
|
|
78
|
+
aria-controls={{@panelId}}
|
|
79
|
+
aria-selected={{String (@state.isActive @id @value)}}
|
|
80
|
+
id={{@id}}
|
|
81
|
+
>
|
|
57
82
|
{{yield}}
|
|
58
83
|
</a>
|
|
59
84
|
</template>;
|
|
@@ -107,6 +132,7 @@ const TabButton: TOC<{
|
|
|
107
132
|
type="button"
|
|
108
133
|
aria-controls={{@panelId}}
|
|
109
134
|
aria-selected={{String (@state.isActive @id @value)}}
|
|
135
|
+
data-tabster={{tabsterFor (@state.isActive @id @value)}}
|
|
110
136
|
id={{@id}}
|
|
111
137
|
{{on "click" @handleClick}}
|
|
112
138
|
{{! The Types for modifier are wrong }}
|
|
@@ -152,7 +178,7 @@ const TabContent: TOC<{
|
|
|
152
178
|
}> = <template>
|
|
153
179
|
<Portal @to="#{{@state.tabpanelId}}" @append={{true}}>
|
|
154
180
|
{{#if (@state.isActive @tabId)}}
|
|
155
|
-
<div ...attributes role="tabpanel" aria-labelledby={{@tabId}} id={{@id}}>
|
|
181
|
+
<div tabindex="0" ...attributes role="tabpanel" aria-labelledby={{@tabId}} id={{@id}}>
|
|
156
182
|
{{yield}}
|
|
157
183
|
</div>
|
|
158
184
|
{{/if}}
|
|
@@ -223,7 +249,12 @@ class TabContainer extends Component<{
|
|
|
223
249
|
};
|
|
224
250
|
Blocks: {
|
|
225
251
|
default: [
|
|
226
|
-
Label: WithBoundArgs<
|
|
252
|
+
Label: WithBoundArgs<
|
|
253
|
+
typeof TabButton,
|
|
254
|
+
"state" | "id" | "panelId" | "handleClick" | "value"
|
|
255
|
+
> & {
|
|
256
|
+
Link: WithBoundArgs<typeof TabLink, "state" | "value" | "id" | "panelId">;
|
|
257
|
+
},
|
|
227
258
|
Content: WithBoundArgs<typeof TabContent, "state" | "id" | "tabId">,
|
|
228
259
|
];
|
|
229
260
|
};
|
|
@@ -280,7 +311,7 @@ class TabContainer extends Component<{
|
|
|
280
311
|
panelId=this.panelId
|
|
281
312
|
handleClick=(fn @state.handleChange this.tabId @value)
|
|
282
313
|
)
|
|
283
|
-
(component TabLink state=@state id=this.tabId panelId=this.panelId)
|
|
314
|
+
(component TabLink state=@state value=@value id=this.tabId panelId=this.panelId)
|
|
284
315
|
)
|
|
285
316
|
(component TabContent state=@state id=this.panelId tabId=this.tabId)
|
|
286
317
|
}}
|
|
@@ -78,8 +78,6 @@ export class Zoetrope extends Component<Signature> {
|
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
event.preventDefault();
|
|
82
|
-
|
|
83
81
|
let newTarget: HTMLElement | null = null;
|
|
84
82
|
|
|
85
83
|
if (shiftKey) {
|
|
@@ -92,7 +90,14 @@ export class Zoetrope extends Component<Signature> {
|
|
|
92
90
|
return;
|
|
93
91
|
}
|
|
94
92
|
|
|
95
|
-
newTarget
|
|
93
|
+
newTarget.focus({ preventScroll: true });
|
|
94
|
+
|
|
95
|
+
/** Cancelling Tab when the sibling cannot take focus traps the keyboard. */
|
|
96
|
+
if ((target.getRootNode() as Document | ShadowRoot).activeElement !== newTarget) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
event.preventDefault();
|
|
96
101
|
|
|
97
102
|
const rect = getRelativeBoundingClientRect(newTarget, this.scrollerElement);
|
|
98
103
|
|
|
@@ -131,6 +136,10 @@ export class Zoetrope extends Component<Signature> {
|
|
|
131
136
|
return "instant";
|
|
132
137
|
}
|
|
133
138
|
|
|
139
|
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
140
|
+
return "instant";
|
|
141
|
+
}
|
|
142
|
+
|
|
134
143
|
return this.args.scrollBehavior || "smooth";
|
|
135
144
|
}
|
|
136
145
|
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
gap: var(--zoetrope-gap, 8px);
|
|
27
27
|
overflow: scroll visible;
|
|
28
28
|
padding: 8px var(--zoetrope-offset, 0);
|
|
29
|
-
scroll-behavior: smooth;
|
|
30
29
|
scroll-padding-left: var(--zoetrope-offset, 0);
|
|
31
30
|
scroll-snap-type: x mandatory;
|
|
32
31
|
scrollbar-color: transparent transparent;
|
|
@@ -38,3 +37,9 @@
|
|
|
38
37
|
scroll-snap-align: start;
|
|
39
38
|
}
|
|
40
39
|
}
|
|
40
|
+
|
|
41
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
42
|
+
.ember-primitives__zoetrope__scroller {
|
|
43
|
+
scroll-behavior: smooth;
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -20,7 +20,8 @@ export type {
|
|
|
20
20
|
} from './components/accordion/public.ts';
|
|
21
21
|
export { Avatar } from './components/avatar.gts';
|
|
22
22
|
export { Breadcrumb } from './components/breadcrumb.gts';
|
|
23
|
-
export {
|
|
23
|
+
export { CommandPalette } from './components/command-palette.gts';
|
|
24
|
+
export { Dialog, Modal } from './components/dialog.gts';
|
|
24
25
|
export { Drawer } from './components/drawer.gts';
|
|
25
26
|
export { ExternalLink } from './components/external-link.gts';
|
|
26
27
|
export { Form } from './components/form.gts';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-gRO4Cvlf.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/dist/otp-H5a4B4yu.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"otp-H5a4B4yu.js","sources":["../src/components/one-time-password/utils.ts","../src/components/one-time-password/input.gts","../src/components/one-time-password/buttons.gts","../src/components/one-time-password/otp.gts"],"sourcesContent":["import { assert } from '@ember/debug';\n\nfunction getInputs(current: HTMLInputElement) {\n const fieldset = current.closest('fieldset');\n\n assert('[BUG]: fieldset went missing', fieldset);\n\n return [...fieldset.querySelectorAll('input')];\n}\n\nfunction nextInput(current: HTMLInputElement) {\n const inputs = getInputs(current);\n const currentIndex = inputs.indexOf(current);\n\n return inputs[currentIndex + 1];\n}\n\nexport function selectAll(event: Event) {\n const target = event.target;\n\n assert(`selectAll is only meant for use with input elements`, target instanceof HTMLInputElement);\n\n target.select();\n}\n\nexport function handlePaste(event: Event) {\n const target = event.target;\n\n assert(\n `handlePaste is only meant for use with input elements`,\n target instanceof HTMLInputElement\n );\n\n const clipboardData = (event as ClipboardEvent).clipboardData;\n\n assert(\n `Could not get clipboardData while handling the paste event on OTP. Please report this issue on the ember-primitives repo with a reproduction. Thanks!`,\n clipboardData\n );\n\n // This is typically not good to prevent paste.\n // But because of the UX we're implementing,\n // we want to split the pasted value across\n // multiple text fields\n event.preventDefault();\n\n const value = clipboardData.getData('Text');\n const digits = value;\n let i = 0;\n let currElement: HTMLInputElement | null = target;\n\n while (currElement) {\n currElement.value = digits[i++] || '';\n\n const next = nextInput(currElement);\n\n if (next instanceof HTMLInputElement) {\n currElement = next;\n } else {\n break;\n }\n }\n\n // We want to select the first field again\n // so that if someone holds paste, or\n // pastes again, they get the same result.\n target.select();\n}\n\nexport function handleNavigation(event: KeyboardEvent) {\n switch (event.key) {\n case 'Backspace':\n return handleBackspace(event);\n case 'ArrowLeft':\n return focusLeft(event);\n case 'ArrowRight':\n return focusRight(event);\n }\n}\n\nfunction focusLeft(event: Pick<Event, 'target'>) {\n const target = event.target;\n\n assert(`only allowed on input elements`, target instanceof HTMLInputElement);\n\n const input = previousInput(target);\n\n input?.focus();\n requestAnimationFrame(() => {\n input?.select();\n });\n}\n\nfunction focusRight(event: Pick<Event, 'target'>) {\n const target = event.target;\n\n assert(`only allowed on input elements`, target instanceof HTMLInputElement);\n\n const input = nextInput(target);\n\n input?.focus();\n requestAnimationFrame(() => {\n input?.select();\n });\n}\n\nconst syntheticEvent = new InputEvent('input');\n\nfunction handleBackspace(event: KeyboardEvent) {\n if (event.key !== 'Backspace') return;\n\n /**\n * We have to prevent default because we\n * - want to clear the whole field\n * - have the focus behavior keep up with the key-repeat\n * speed of the user's computer\n */\n event.preventDefault();\n\n const target = event.target;\n\n if (target && 'value' in target) {\n if (target.value === '') {\n focusLeft({ target });\n } else {\n target.value = '';\n }\n }\n\n target?.dispatchEvent(syntheticEvent);\n}\n\nfunction previousInput(current: HTMLInputElement) {\n const inputs = getInputs(current);\n const currentIndex = inputs.indexOf(current);\n\n return inputs[currentIndex - 1];\n}\n\nexport const autoAdvance = (event: Event) => {\n assert(\n '[BUG]: autoAdvance called on non-input element',\n event.target instanceof HTMLInputElement\n );\n\n const value = event.target.value;\n\n if (value.length === 0) return;\n\n if (value.length > 0) {\n if ('data' in event && event.data && typeof event.data === 'string') {\n event.target.value = event.data;\n }\n\n return focusRight(event);\n }\n};\n\nexport function getCollectiveValue(elementTarget: EventTarget | null, length: number) {\n if (!elementTarget) return;\n\n assert(\n `[BUG]: somehow the element target is not HTMLElement`,\n elementTarget instanceof HTMLElement\n );\n\n let parent: null | HTMLElement | ShadowRoot;\n\n // TODO: should this logic be extracted?\n // why is getting the target element within a shadow root hard?\n if (!(elementTarget instanceof HTMLInputElement)) {\n if (elementTarget.shadowRoot) {\n parent = elementTarget.shadowRoot;\n } else {\n parent = elementTarget.closest('fieldset');\n }\n } else {\n parent = elementTarget.closest('fieldset');\n }\n\n assert(`[BUG]: somehow the input fields were rendered without a parent element`, parent);\n\n const elements = parent.querySelectorAll('input');\n\n let value = '';\n\n assert(\n `found elements (${elements.length}) do not match length (${length}). Was the same OTP input rendered more than once?`,\n elements.length === length\n );\n\n for (const element of elements) {\n assert(\n '[BUG]: how did the queried elements become a non-input element?',\n element instanceof HTMLInputElement\n );\n value += element.value;\n }\n\n return value;\n}\n","import Component from \"@glimmer/component\";\nimport { warn } from \"@ember/debug\";\nimport { isDestroyed, isDestroying } from \"@ember/destroyable\";\nimport { on } from \"@ember/modifier\";\nimport { buildWaiter } from \"@ember/test-waiters\";\n\nimport {\n autoAdvance,\n getCollectiveValue,\n handleNavigation,\n handlePaste,\n selectAll,\n} from \"./utils.ts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\nconst DEFAULT_LENGTH = 6;\n\nfunction labelFor(inputIndex: number, labelFn: undefined | ((index: number) => string)) {\n if (labelFn) {\n return labelFn(inputIndex);\n }\n\n return `Please enter OTP character ${inputIndex + 1}`;\n}\n\nconst waiter = buildWaiter(\"ember-primitives:OTPInput:handleChange\");\n\nconst Fields: TOC<{\n /**\n * Any attributes passed to this component will be applied to each input.\n */\n Element: HTMLInputElement;\n Args: {\n fields: unknown[];\n labelFn: (index: number) => string;\n handleChange: (event: Event) => void;\n };\n}> = <template>\n {{#each @fields as |_field i|}}\n <label>\n <span class=\"ember-primitives__sr-only\">{{labelFor i @labelFn}}</span>\n <input\n name=\"code{{i}}\"\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n ...attributes\n {{on \"click\" selectAll}}\n {{on \"paste\" handlePaste}}\n {{on \"input\" autoAdvance}}\n {{on \"input\" @handleChange}}\n {{on \"keydown\" handleNavigation}}\n />\n </label>\n {{/each}}\n</template>;\n\nexport class OTPInput extends Component<{\n /**\n * The collection of individual OTP inputs are contained by a fieldset.\n * Applying the `disabled` attribute to this fieldset will disable\n * all of the inputs, if that's desired.\n */\n Element: HTMLFieldSetElement;\n Args: {\n /**\n * How many characters the one-time-password field should be\n * Defaults to 6\n */\n length?: number;\n\n /**\n * To Customize the label of the input fields, you may pass a function.\n * By default, this is `Please enter OTP character ${index + 1}`.\n */\n labelFn?: (index: number) => string;\n\n /**\n * If passed, this function will be called when the <Input> changes.\n * All fields are considered one input.\n */\n onChange?: (\n data: {\n /**\n * The text from the collective `<Input>`\n *\n * `code` _may_ be shorter than `length`\n * if the user has not finished typing / pasting their code\n */\n code: string;\n /**\n * will be `true` if `code`'s length matches the passed `@length` or the default of 6\n */\n complete: boolean;\n },\n /**\n * The last input event received\n */\n event: Event,\n ) => void;\n };\n Blocks: {\n /**\n * Optionally, you may control how the Fields are rendered, with proceeding text,\n * additional attributes added, etc.\n *\n * This is how you can add custom validation to each input field.\n */\n default?: [fields: WithBoundArgs<typeof Fields, \"fields\" | \"handleChange\" | \"labelFn\">];\n };\n}> {\n /**\n * This is debounced, because we bind to each input,\n * but only want to emit one change event if someone pastes\n * multiple characters\n */\n handleChange = (event: Event) => {\n if (!this.args.onChange) return;\n\n if (!this.#token) {\n this.#token = waiter.beginAsync();\n }\n\n if (this.#frame) {\n cancelAnimationFrame(this.#frame);\n }\n\n // We use requestAnimationFrame to be friendly to rendering.\n // We don't know if onChange is going to want to cause paints\n // (it's also how we debounce, under the assumption that \"paste\" behavior\n // would be fast enough to be quicker than individual frames\n // (see logic in autoAdvance)\n // )\n this.#frame = requestAnimationFrame(() => {\n waiter.endAsync(this.#token);\n\n if (isDestroyed(this) || isDestroying(this)) return;\n if (!this.args.onChange) return;\n\n const value = getCollectiveValue(event.target, this.length);\n\n if (value === undefined) {\n warn(`Value could not be determined for the OTP field. was it removed from the DOM?`, {\n id: \"ember-primitives.OTPInput.missing-value\",\n });\n\n return;\n }\n\n this.args.onChange({ code: value, complete: value.length === this.length }, event);\n });\n };\n\n #token: unknown;\n #frame: number | undefined;\n\n get length() {\n return this.args.length ?? DEFAULT_LENGTH;\n }\n\n get fields() {\n // We only need to iterate a number of times,\n // so we don't care about the actual value or\n // referential integrity here\n return new Array<undefined>(this.length);\n }\n\n <template>\n <fieldset ...attributes>\n {{#let\n (component Fields fields=this.fields handleChange=this.handleChange labelFn=@labelFn)\n as |CurriedFields|\n }}\n {{#if (has-block)}}\n {{yield CurriedFields}}\n {{else}}\n <CurriedFields />\n {{/if}}\n {{/let}}\n\n <style>\n .ember-primitives__sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n }\n </style>\n </fieldset>\n </template>\n}\n","import { assert } from \"@ember/debug\";\nimport { on } from \"@ember/modifier\";\n\nimport type { TOC } from \"@ember/component/template-only\";\n\nconst reset = (event: Event) => {\n assert(\"[BUG]: reset called without an event.target\", event.target instanceof HTMLElement);\n\n const form = event.target.closest(\"form\");\n\n assert(\n \"Form is missing. Cannot use <Reset> without being contained within a <form>\",\n form instanceof HTMLFormElement,\n );\n\n form.reset();\n};\n\nexport const Submit: TOC<{\n Element: HTMLButtonElement;\n Blocks: { default: [] };\n}> = <template>\n <button type=\"submit\" ...attributes>Submit</button>\n</template>;\n\nexport const Reset: TOC<{\n Element: HTMLButtonElement;\n Blocks: { default: [] };\n}> = <template>\n <button type=\"button\" {{on \"click\" reset}} ...attributes>{{yield}}</button>\n</template>;\n","import { assert } from \"@ember/debug\";\nimport { fn, hash } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\nimport { buildWaiter } from \"@ember/test-waiters\";\n\nimport { Reset, Submit } from \"./buttons.gts\";\nimport { OTPInput } from \"./input.gts\";\n\nimport type { TOC } from \"@ember/component/template-only\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\nconst waiter = buildWaiter(\"ember-primitives:OTP:handleAutoSubmitAttempt\");\n\nconst handleFormSubmit = (submit: (data: { code: string }) => void, event: SubmitEvent) => {\n event.preventDefault();\n\n assert(\n \"[BUG]: handleFormSubmit was not attached to a form. Please open an issue.\",\n event.currentTarget instanceof HTMLFormElement,\n );\n\n const formData = new FormData(event.currentTarget);\n\n let code = \"\";\n\n for (const [key, value] of formData.entries()) {\n if (key.startsWith(\"code\")) {\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands, @typescript-eslint/no-base-to-string\n code += value;\n }\n }\n\n submit({\n code,\n });\n};\n\nfunction handleChange(\n autoSubmit: boolean | undefined,\n data: { code: string; complete: boolean },\n event: Event,\n) {\n if (!autoSubmit) return;\n if (!data.complete) return;\n\n assert(\n \"[BUG]: event target is not a known element type\",\n event.target instanceof HTMLElement || event.target instanceof SVGElement,\n );\n\n const form = event.target.closest(\"form\");\n\n assert(\"[BUG]: Cannot handle event when <OTP> Inputs are not rendered within their <form>\", form);\n\n const token = waiter.beginAsync();\n const finished = () => {\n waiter.endAsync(token);\n form.removeEventListener(\"submit\", finished);\n };\n\n form.addEventListener(\"submit\", finished);\n\n // NOTE: when calling .submit() the submit event handlers are not run\n form.requestSubmit();\n}\n\nexport const OTP: TOC<{\n /**\n * The overall OTP Input is in its own form.\n * Modern UI/UX Patterns usually have this sort of field\n * as its own page, thus within its own form.\n *\n * By default, only the 'submit' event is bound, and is\n * what calls the `@onSubmit` argument.\n */\n Element: HTMLFormElement;\n Args: {\n /**\n * How many characters the one-time-password field should be\n * Defaults to 6\n */\n length?: number;\n\n /**\n * The on submit callback will give you the entered\n * one-time-password code.\n *\n * It will be called when the user manually clicks the 'submit'\n * button or when the full code is pasted and meats the validation\n * criteria.\n */\n onSubmit: (data: { code: string }) => void;\n\n /**\n * Whether or not to auto-submit after the code has been pasted\n * in to the collective \"field\". Default is true\n */\n autoSubmit?: boolean;\n };\n Blocks: {\n default: [\n {\n /**\n * The collective input field that the OTP code will be typed/pasted in to\n */\n Input: WithBoundArgs<typeof OTPInput, \"length\" | \"onChange\">;\n /**\n * Button with `type=\"submit\"` to submit the form\n */\n Submit: typeof Submit;\n /**\n * Pre-wired button to reset the form\n */\n Reset: typeof Reset;\n },\n ];\n };\n}> = <template>\n <form {{on \"submit\" (fn handleFormSubmit @onSubmit)}} ...attributes>\n {{yield\n (hash\n Input=(component\n OTPInput length=@length onChange=(if @autoSubmit (fn handleChange @autoSubmit))\n )\n Submit=Submit\n Reset=Reset\n )\n }}\n </form>\n</template>;\n"],"names":["getInputs","current","fieldset","closest","assert","querySelectorAll","nextInput","inputs","currentIndex","indexOf","selectAll","event","target","HTMLInputElement","select","handlePaste","clipboardData","preventDefault","value","getData","digits","i","currElement","next","handleNavigation","key","handleBackspace","focusLeft","focusRight","input","previousInput","focus","requestAnimationFrame","syntheticEvent","InputEvent","dispatchEvent","autoAdvance","length","data","getCollectiveValue","elementTarget","HTMLElement","parent","shadowRoot","elements","element","DEFAULT_LENGTH","labelFor","inputIndex","labelFn","waiter","buildWaiter","Fields","setComponentTemplate","precompileTemplate","strictMode","scope","on","templateOnly","OTPInput","Component","handleChange","args","onChange","beginAsync","cancelAnimationFrame","endAsync","isDestroyed","isDestroying","undefined","warn","id","code","complete","fields","Array","reset","form","HTMLFormElement","Submit","Reset","handleFormSubmit","submit","currentTarget","formData","FormData","entries","startsWith","autoSubmit","SVGElement","token","finished","removeEventListener","addEventListener","requestSubmit","OTP","fn","hash"],"mappings":"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"}
|