ember-primitives 0.49.0 → 0.50.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.
Files changed (103) hide show
  1. package/bin/index.mjs +271 -0
  2. package/declarations/components/rating/public-types.d.ts +0 -4
  3. package/declarations/components/rating/public-types.d.ts.map +1 -1
  4. package/declarations/components/rating/rating.d.ts +9 -1
  5. package/declarations/components/rating/rating.d.ts.map +1 -1
  6. package/declarations/components/rating/stars.d.ts.map +1 -1
  7. package/declarations/components/rating/state.d.ts +4 -0
  8. package/declarations/components/rating/state.d.ts.map +1 -1
  9. package/declarations/components/rating/utils.d.ts +0 -1
  10. package/declarations/components/rating/utils.d.ts.map +1 -1
  11. package/dist/components/rating.js +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/{rating-CjBVsX6q.js → rating-BrIiwDLw.js} +21 -17
  14. package/dist/rating-BrIiwDLw.js.map +1 -0
  15. package/package.json +6 -2
  16. package/src/-private.ts +4 -0
  17. package/src/color-scheme.ts +165 -0
  18. package/src/components/-private/typed-elements.gts +13 -0
  19. package/src/components/-private/utils.ts +16 -0
  20. package/src/components/accordion/content.gts +34 -0
  21. package/src/components/accordion/header.gts +36 -0
  22. package/src/components/accordion/item.gts +55 -0
  23. package/src/components/accordion/public.ts +64 -0
  24. package/src/components/accordion/trigger.gts +32 -0
  25. package/src/components/accordion.gts +195 -0
  26. package/src/components/avatar.gts +108 -0
  27. package/src/components/dialog.gts +234 -0
  28. package/src/components/external-link.gts +14 -0
  29. package/src/components/form.gts +75 -0
  30. package/src/components/heading.gts +36 -0
  31. package/src/components/keys.gts +53 -0
  32. package/src/components/layout/hero.css +5 -0
  33. package/src/components/layout/hero.gts +17 -0
  34. package/src/components/layout/sticky-footer.css +9 -0
  35. package/src/components/layout/sticky-footer.gts +40 -0
  36. package/src/components/link.gts +172 -0
  37. package/src/components/menu.gts +373 -0
  38. package/src/components/one-time-password/buttons.gts +31 -0
  39. package/src/components/one-time-password/input.gts +198 -0
  40. package/src/components/one-time-password/otp.gts +130 -0
  41. package/src/components/one-time-password/utils.ts +201 -0
  42. package/src/components/one-time-password.gts +2 -0
  43. package/src/components/popover.gts +248 -0
  44. package/src/components/portal-targets.gts +136 -0
  45. package/src/components/portal.gts +194 -0
  46. package/src/components/progress.gts +154 -0
  47. package/src/components/rating/public-types.ts +44 -0
  48. package/src/components/rating/range.gts +22 -0
  49. package/src/components/rating/rating.gts +228 -0
  50. package/src/components/rating/stars.gts +60 -0
  51. package/src/components/rating/state.gts +144 -0
  52. package/src/components/rating/utils.ts +7 -0
  53. package/src/components/rating.gts +5 -0
  54. package/src/components/scroller.gts +179 -0
  55. package/src/components/shadowed.gts +110 -0
  56. package/src/components/switch.gts +103 -0
  57. package/src/components/tabs.gts +519 -0
  58. package/src/components/toggle-group.gts +265 -0
  59. package/src/components/toggle.gts +81 -0
  60. package/src/components/violations.css +105 -0
  61. package/src/components/violations.css.ts +1 -0
  62. package/src/components/visually-hidden.css +14 -0
  63. package/src/components/visually-hidden.gts +15 -0
  64. package/src/components/zoetrope/index.gts +358 -0
  65. package/src/components/zoetrope/styles.css +40 -0
  66. package/src/components/zoetrope/types.ts +65 -0
  67. package/src/components/zoetrope.ts +3 -0
  68. package/src/dom-context.gts +245 -0
  69. package/src/floating-ui/component.gts +186 -0
  70. package/src/floating-ui/middleware.ts +13 -0
  71. package/src/floating-ui/modifier.ts +183 -0
  72. package/src/floating-ui.ts +2 -0
  73. package/src/head.gts +37 -0
  74. package/src/helpers/body-class.ts +94 -0
  75. package/src/helpers/link.ts +125 -0
  76. package/src/helpers/service.ts +25 -0
  77. package/src/helpers.ts +2 -0
  78. package/src/iframe.ts +31 -0
  79. package/src/index.ts +43 -0
  80. package/src/load.gts +77 -0
  81. package/src/narrowing.ts +7 -0
  82. package/src/on-resize.ts +64 -0
  83. package/src/proper-links.ts +140 -0
  84. package/src/qp.ts +107 -0
  85. package/src/resize-observer.ts +132 -0
  86. package/src/service.ts +103 -0
  87. package/src/store.ts +72 -0
  88. package/src/styles.css.ts +5 -0
  89. package/src/tabster.ts +54 -0
  90. package/src/template-registry.ts +44 -0
  91. package/src/test-support/a11y.ts +50 -0
  92. package/src/test-support/dom.ts +112 -0
  93. package/src/test-support/otp.ts +64 -0
  94. package/src/test-support/rating.ts +144 -0
  95. package/src/test-support/routing.ts +62 -0
  96. package/src/test-support/zoetrope.ts +51 -0
  97. package/src/test-support.gts +6 -0
  98. package/src/type-utils.ts +1 -0
  99. package/src/utils.ts +75 -0
  100. package/src/viewport/in-viewport.gts +128 -0
  101. package/src/viewport/viewport.ts +122 -0
  102. package/src/viewport.ts +2 -0
  103. package/dist/rating-CjBVsX6q.js.map +0 -1
@@ -0,0 +1,172 @@
1
+ /**
2
+ * TODO: make template-only component,
3
+ * and use class-based modifier?
4
+ *
5
+ * This would require that modifiers could run pre-render
6
+ */
7
+ import { hash } from '@ember/helper';
8
+ import { on } from '@ember/modifier';
9
+
10
+ import { link } from '../helpers/link.ts';
11
+ import { ExternalLink } from './external-link.gts';
12
+
13
+ import type { TOC } from '@ember/component/template-only';
14
+
15
+ export interface Signature {
16
+ Element: HTMLAnchorElement;
17
+ Args: {
18
+ /**
19
+ * the `href` string value to set on the anchor element.
20
+ */
21
+ href: string;
22
+ /**
23
+ * When calculating the "active" state of the link, you may decide
24
+ * whether or not you want to _require_ that all query params be considered (true)
25
+ * or specify individual query params, ignoring anything not specified.
26
+ *
27
+ * For example:
28
+ *
29
+ * ```gjs live preview
30
+ * import { Link } from 'ember-primitives';
31
+ *
32
+ * <template>
33
+ * <Link @href="/" @includeActiveQueryParams={{true}} as |a|>
34
+ * ...
35
+ * </Link>
36
+ * </template>
37
+ * ```
38
+ *
39
+ * the data-active state here will only be "true" on
40
+ * - `/`
41
+ * - `/?foo=2`
42
+ * - `/?foo=&bar=`
43
+ *
44
+ */
45
+ includeActiveQueryParams?: true | string[];
46
+ /**
47
+ * When calculating the "active" state of the link, you may decide
48
+ * whether or not you want to consider sub paths to be active when
49
+ * child routes/urls are active.
50
+ *
51
+ * For example:
52
+ *
53
+ * ```gjs live preview
54
+ * import { Link } from 'ember-primitives';
55
+ *
56
+ * <template>
57
+ * <Link @href="/forum/1" @activeOnSubPaths={{true}} as |a|>
58
+ * ...
59
+ * </Link>
60
+ * </template>
61
+ * ```
62
+ *
63
+ * the data-active state here will be "true" on
64
+ * - `/forum/1`
65
+ * - `/forum/1/posts`
66
+ * - `/forum/1/posts/comments`
67
+ * - `/forum/1/*etc*`
68
+ *
69
+ * if `@activeOnSubPaths` is set to false or left off
70
+ * the data-active state here will only be "true" on
71
+ * - `/forum/1`
72
+ *
73
+ */
74
+ activeOnSubPaths?: true;
75
+ };
76
+ Blocks: {
77
+ default: [
78
+ {
79
+ /**
80
+ * Indicates if the passed `href` is pointing to an external site.
81
+ * Useful if you want your links to have additional context for when
82
+ * a user is about to leave your site.
83
+ *
84
+ * For example:
85
+ *
86
+ * ```gjs live preview
87
+ * import { Link } from 'ember-primitives';
88
+ *
89
+ * const MyLink = <template>
90
+ * <Link @href={{@href}} as |a|>
91
+ * {{yield}}
92
+ * {{#if a.isExternal}}
93
+ * ➚
94
+ * {{/if}}
95
+ * </Link>
96
+ * </template>;
97
+ *
98
+ * <template>
99
+ * <MyLink @href="https://developer.mozilla.org">MDN</MyLink> &nbsp;&nbsp;
100
+ * <MyLink @href="/">Home</MyLink>
101
+ * </template>
102
+ * ```
103
+ */
104
+ isExternal: boolean;
105
+ /**
106
+ * Indicates if the passed `href` is *active*, or the user is on the same basepath.
107
+ * This allows consumers to style their link if they wish or style their text.
108
+ * The active state will also be present on a `data-active` attribute on the generated anchor tag.
109
+ *
110
+ *
111
+ * For example
112
+ * ```gjs
113
+ * import { Link, service } from 'ember-primitives';
114
+ *
115
+ * const MyLink = <template>
116
+ * <Link @href="..."> as |a|>
117
+ * <span class="{{if a.isActive 'underline'}}">
118
+ * {{yield}}
119
+ * </span>
120
+ * </Link>
121
+ * </template>
122
+ *
123
+ * <template>
124
+ * {{#let (service 'router') as |router|}}
125
+ * <MyLink @href={{router.currentURL}}>Ths page</MyLink> &nbsp;&nbsp;
126
+ * <MyLink @href="/">Home</MyLink>
127
+ * {{/let}}
128
+ * </template>
129
+ * ```
130
+ *
131
+ * By default, the query params are omitted from `isActive` calculation, but you may
132
+ * configure the query params to be included if you wish
133
+ * See: `@includeActiveQueryParams`
134
+ *
135
+ * By default, only the exact route/url is considered for the `isActive` calculation,
136
+ * but you may configure sub routes/paths to also be considered active
137
+ * See: `@activeOnSubPaths`
138
+ *
139
+ * Note that external links are never active.
140
+ */
141
+ isActive: boolean;
142
+ },
143
+ ];
144
+ };
145
+ }
146
+
147
+ /**
148
+ * A light wrapper around the [Anchor element][mdn-a], which will appropriately make your link an external link if the passed `@href` is not on the same domain.
149
+ *
150
+ *
151
+ * [mdn-a]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a
152
+ */
153
+ export const Link: TOC<Signature> = <template>
154
+ {{#let (link @href includeActiveQueryParams=@includeActiveQueryParams activeOnSubPaths=@activeOnSubPaths) as |l|}}
155
+ {{#if l.isExternal}}
156
+ <ExternalLink href={{@href}} ...attributes>
157
+ {{yield (hash isExternal=true isActive=false)}}
158
+ </ExternalLink>
159
+ {{else}}
160
+ <a
161
+ data-active={{l.isActive}}
162
+ href={{if @href @href "##missing##"}}
163
+ {{on "click" l.handleClick}}
164
+ ...attributes
165
+ >
166
+ {{yield (hash isExternal=false isActive=l.isActive)}}
167
+ </a>
168
+ {{/if}}
169
+ {{/let}}
170
+ </template>;
171
+
172
+ export default Link;
@@ -0,0 +1,373 @@
1
+ import Component from "@glimmer/component";
2
+ import { hash } from "@ember/helper";
3
+ import { on } from "@ember/modifier";
4
+ import { guidFor } from "@ember/object/internals";
5
+
6
+ import { modifier as eModifier } from "ember-modifier";
7
+ import { cell } from "ember-resources";
8
+ import { getTabster, getTabsterAttribute, MoverDirections, setTabsterAttribute } from "tabster";
9
+
10
+ import { Link, type Signature as LinkSignature } from "./link.gts";
11
+ import { Popover, type Signature as PopoverSignature } from "./popover.gts";
12
+
13
+ import type { TOC } from "@ember/component/template-only";
14
+ import type { WithBoundArgs } from "@glint/template";
15
+
16
+ type Cell<V> = ReturnType<typeof cell<V>>;
17
+ type LinkArgs = LinkSignature["Args"];
18
+ type PopoverArgs = PopoverSignature["Args"];
19
+ type PopoverBlockParams = PopoverSignature["Blocks"]["default"][0];
20
+
21
+ const TABSTER_CONFIG_CONTENT = getTabsterAttribute(
22
+ {
23
+ mover: {
24
+ direction: MoverDirections.Both,
25
+ cyclic: true,
26
+ },
27
+ deloser: {},
28
+ },
29
+ true,
30
+ );
31
+
32
+ const TABSTER_CONFIG_TRIGGER = {
33
+ deloser: {},
34
+ };
35
+
36
+ export interface Signature {
37
+ Args: PopoverArgs;
38
+ Blocks: {
39
+ default: [
40
+ {
41
+ arrow: PopoverBlockParams["arrow"];
42
+ trigger: WithBoundArgs<
43
+ typeof trigger,
44
+ "triggerElement" | "contentId" | "isOpen" | "setReference"
45
+ >;
46
+ Trigger: WithBoundArgs<typeof Trigger, "triggerModifier">;
47
+ Content: WithBoundArgs<
48
+ typeof Content,
49
+ "triggerElement" | "contentId" | "isOpen" | "PopoverContent"
50
+ >;
51
+ isOpen: boolean;
52
+ },
53
+ ];
54
+ };
55
+ }
56
+
57
+ export interface SeparatorSignature {
58
+ Element: HTMLDivElement;
59
+ Blocks: { default: [] };
60
+ }
61
+
62
+ const Separator: TOC<SeparatorSignature> = <template>
63
+ <div role="separator" ...attributes>
64
+ {{yield}}
65
+ </div>
66
+ </template>;
67
+
68
+ /**
69
+ * We focus items on `pointerMove` to achieve the following:
70
+ *
71
+ * - Mouse over an item (it focuses)
72
+ * - Leave mouse where it is and use keyboard to focus a different item
73
+ * - Wiggle mouse without it leaving previously focused item
74
+ * - Previously focused item should re-focus
75
+ *
76
+ * If we used `mouseOver`/`mouseEnter` it would not re-focus when the mouse
77
+ * wiggles. This is to match native menu implementation.
78
+ */
79
+ function focusOnHover(e: PointerEvent) {
80
+ const item = e.currentTarget;
81
+
82
+ if (item instanceof HTMLElement) {
83
+ item?.focus();
84
+ }
85
+ }
86
+
87
+ interface PrivateItemSignature {
88
+ Element: HTMLButtonElement;
89
+ Args: { onSelect?: (event: Event) => void; toggle: () => void };
90
+ Blocks: { default: [] };
91
+ }
92
+
93
+ export interface ItemSignature {
94
+ Element: PrivateItemSignature["Element"];
95
+ Args: Omit<PrivateItemSignature["Args"], "toggle">;
96
+ Blocks: PrivateItemSignature["Blocks"];
97
+ }
98
+
99
+ const Item: TOC<PrivateItemSignature> = <template>
100
+ {{! @glint-expect-error }}
101
+ {{#let (if @onSelect (modifier on "click" @onSelect)) as |maybeClick|}}
102
+ <button
103
+ type="button"
104
+ role="menuitem"
105
+ {{! @glint-expect-error }}
106
+ {{maybeClick}}
107
+ {{on "click" @toggle}}
108
+ {{on "pointermove" focusOnHover}}
109
+ ...attributes
110
+ >
111
+ {{yield}}
112
+ </button>
113
+ {{/let}}
114
+ </template>;
115
+
116
+ interface LinkItemArgs extends LinkArgs {
117
+ toggle: () => void;
118
+ }
119
+
120
+ interface PrivateLinkItemSignature {
121
+ Element: HTMLAnchorElement;
122
+ Args: LinkItemArgs;
123
+ Blocks: { default: [] };
124
+ }
125
+
126
+ export interface LinkItemSignature {
127
+ Element: PrivateLinkItemSignature["Element"];
128
+ Args: LinkArgs;
129
+ Blocks: PrivateLinkItemSignature["Blocks"];
130
+ }
131
+
132
+ const LinkItem: TOC<PrivateLinkItemSignature> = <template>
133
+ <Link
134
+ role="menuitem"
135
+ @href={{@href}}
136
+ @includeActiveQueryParams={{@includeActiveQueryParams}}
137
+ @activeOnSubPaths={{@activeOnSubPaths}}
138
+ {{on "click" @toggle}}
139
+ {{on "pointermove" focusOnHover}}
140
+ ...attributes
141
+ >
142
+ {{yield}}
143
+ </Link>
144
+ </template>;
145
+
146
+ const installContent = eModifier<{
147
+ Element: HTMLElement;
148
+ Args: {
149
+ Named: {
150
+ isOpen: Cell<boolean>;
151
+ triggerElement: Cell<HTMLElement>;
152
+ };
153
+ };
154
+ }>((element, _: [], { isOpen, triggerElement }) => {
155
+ // focus first focusable element on the content
156
+ const tabster = getTabster(window);
157
+ const firstFocusable = tabster?.focusable.findFirst({
158
+ container: element,
159
+ });
160
+
161
+ firstFocusable?.focus();
162
+
163
+ // listen for "outside" clicks
164
+ function onDocumentClick(e: MouseEvent) {
165
+ if (
166
+ isOpen.current &&
167
+ e.target &&
168
+ !element.contains(e.target as HTMLElement) &&
169
+ !triggerElement.current?.contains(e.target as HTMLElement)
170
+ ) {
171
+ isOpen.current = false;
172
+ }
173
+ }
174
+
175
+ // listen for the escape key
176
+ function onDocumentKeydown(e: KeyboardEvent) {
177
+ if (isOpen.current && e.key === "Escape") {
178
+ isOpen.current = false;
179
+ }
180
+ }
181
+
182
+ document.addEventListener("click", onDocumentClick);
183
+ document.addEventListener("keydown", onDocumentKeydown);
184
+
185
+ return () => {
186
+ document.removeEventListener("click", onDocumentClick);
187
+ document.removeEventListener("keydown", onDocumentKeydown);
188
+ };
189
+ });
190
+
191
+ interface PrivateContentSignature {
192
+ Element: HTMLDivElement;
193
+ Args: {
194
+ triggerElement: Cell<HTMLElement>;
195
+ contentId: string;
196
+ isOpen: Cell<boolean>;
197
+ PopoverContent: PopoverBlockParams["Content"];
198
+ };
199
+ Blocks: {
200
+ default: [
201
+ {
202
+ Item: WithBoundArgs<typeof Item, "toggle">;
203
+ LinkItem: WithBoundArgs<typeof LinkItem, "toggle">;
204
+ Separator: typeof Separator;
205
+ },
206
+ ];
207
+ };
208
+ }
209
+
210
+ export interface ContentSignature {
211
+ Element: PrivateContentSignature["Element"];
212
+ Blocks: PrivateContentSignature["Blocks"];
213
+ }
214
+
215
+ const Content: TOC<PrivateContentSignature> = <template>
216
+ {{#if @isOpen.current}}
217
+ <@PopoverContent
218
+ id={{@contentId}}
219
+ role="menu"
220
+ data-tabster={{TABSTER_CONFIG_CONTENT}}
221
+ tabindex="0"
222
+ {{installContent isOpen=@isOpen triggerElement=@triggerElement}}
223
+ ...attributes
224
+ >
225
+ {{yield
226
+ (hash
227
+ Item=(component Item toggle=@isOpen.toggle)
228
+ LinkItem=(component LinkItem toggle=@isOpen.toggle)
229
+ Separator=Separator
230
+ )
231
+ }}
232
+ </@PopoverContent>
233
+ {{/if}}
234
+ </template>;
235
+
236
+ interface PrivateTriggerModifierSignature {
237
+ Element: HTMLElement;
238
+ Args: {
239
+ Named: {
240
+ triggerElement: Cell<HTMLElement>;
241
+ isOpen: Cell<boolean>;
242
+ contentId: string;
243
+ setReference: PopoverBlockParams["setReference"];
244
+ stopPropagation?: boolean;
245
+ preventDefault?: boolean;
246
+ };
247
+ };
248
+ }
249
+
250
+ export interface TriggerModifierSignature {
251
+ Element: PrivateTriggerModifierSignature["Element"];
252
+ }
253
+
254
+ const trigger = eModifier<PrivateTriggerModifierSignature>(
255
+ (
256
+ element,
257
+ _: [],
258
+ { triggerElement, isOpen, contentId, setReference, stopPropagation, preventDefault },
259
+ ) => {
260
+ element.setAttribute("aria-haspopup", "menu");
261
+
262
+ if (isOpen.current) {
263
+ element.setAttribute("aria-controls", contentId);
264
+ element.setAttribute("aria-expanded", "true");
265
+ } else {
266
+ element.removeAttribute("aria-controls");
267
+ element.setAttribute("aria-expanded", "false");
268
+ }
269
+
270
+ setTabsterAttribute(element, TABSTER_CONFIG_TRIGGER);
271
+
272
+ const onTriggerClick = (event: MouseEvent) => {
273
+ if (stopPropagation) {
274
+ event.stopPropagation();
275
+ }
276
+
277
+ if (preventDefault) {
278
+ event.preventDefault();
279
+ }
280
+
281
+ isOpen.toggle();
282
+ };
283
+
284
+ element.addEventListener("click", onTriggerClick);
285
+
286
+ triggerElement.current = element;
287
+
288
+ setReference(element);
289
+
290
+ return () => {
291
+ element.removeEventListener("click", onTriggerClick);
292
+ };
293
+ },
294
+ );
295
+
296
+ interface PrivateTriggerSignature {
297
+ Element: HTMLButtonElement;
298
+ Args: {
299
+ triggerModifier: WithBoundArgs<
300
+ typeof trigger,
301
+ "triggerElement" | "contentId" | "isOpen" | "setReference"
302
+ >;
303
+ stopPropagation?: boolean;
304
+ preventDefault?: boolean;
305
+ };
306
+ Blocks: { default: [] };
307
+ }
308
+
309
+ export interface TriggerSignature {
310
+ Element: PrivateTriggerSignature["Element"];
311
+ Blocks: PrivateTriggerSignature["Blocks"];
312
+ }
313
+
314
+ const Trigger: TOC<PrivateTriggerSignature> = <template>
315
+ <button
316
+ type="button"
317
+ {{@triggerModifier stopPropagation=@stopPropagation preventDefault=@preventDefault}}
318
+ ...attributes
319
+ >
320
+ {{yield}}
321
+ </button>
322
+ </template>;
323
+
324
+ const IsOpen = () => cell<boolean>(false);
325
+ const TriggerElement = () => cell<HTMLElement>();
326
+
327
+ export class Menu extends Component<Signature> {
328
+ contentId = guidFor(this);
329
+
330
+ <template>
331
+ {{#let (IsOpen) (TriggerElement) as |isOpen triggerEl|}}
332
+ <Popover
333
+ @flipOptions={{@flipOptions}}
334
+ @middleware={{@middleware}}
335
+ @offsetOptions={{@offsetOptions}}
336
+ @placement={{@placement}}
337
+ @shiftOptions={{@shiftOptions}}
338
+ @strategy={{@strategy}}
339
+ @inline={{@inline}}
340
+ as |p|
341
+ >
342
+ {{#let
343
+ (modifier
344
+ trigger
345
+ triggerElement=triggerEl
346
+ isOpen=isOpen
347
+ contentId=this.contentId
348
+ setReference=p.setReference
349
+ )
350
+ as |triggerModifier|
351
+ }}
352
+ {{yield
353
+ (hash
354
+ trigger=triggerModifier
355
+ Trigger=(component Trigger triggerModifier=triggerModifier)
356
+ Content=(component
357
+ Content
358
+ PopoverContent=p.Content
359
+ isOpen=isOpen
360
+ triggerElement=triggerEl
361
+ contentId=this.contentId
362
+ )
363
+ arrow=p.arrow
364
+ isOpen=isOpen.current
365
+ )
366
+ }}
367
+ {{/let}}
368
+ </Popover>
369
+ {{/let}}
370
+ </template>
371
+ }
372
+
373
+ export default Menu;
@@ -0,0 +1,31 @@
1
+ import { assert } from "@ember/debug";
2
+ import { on } from "@ember/modifier";
3
+
4
+ import type { TOC } from "@ember/component/template-only";
5
+
6
+ const reset = (event: Event) => {
7
+ assert("[BUG]: reset called without an event.target", event.target instanceof HTMLElement);
8
+
9
+ const form = event.target.closest("form");
10
+
11
+ assert(
12
+ "Form is missing. Cannot use <Reset> without being contained within a <form>",
13
+ form instanceof HTMLFormElement,
14
+ );
15
+
16
+ form.reset();
17
+ };
18
+
19
+ export const Submit: TOC<{
20
+ Element: HTMLButtonElement;
21
+ Blocks: { default: [] };
22
+ }> = <template>
23
+ <button type="submit" ...attributes>Submit</button>
24
+ </template>;
25
+
26
+ export const Reset: TOC<{
27
+ Element: HTMLButtonElement;
28
+ Blocks: { default: [] };
29
+ }> = <template>
30
+ <button type="button" {{on "click" reset}} ...attributes>{{yield}}</button>
31
+ </template>;