ember-primitives 0.43.1 → 0.45.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 (99) hide show
  1. package/declarations/components/heading.d.ts +14 -0
  2. package/declarations/components/heading.d.ts.map +1 -0
  3. package/declarations/components/one-time-password.d.ts +3 -0
  4. package/declarations/components/one-time-password.d.ts.map +1 -0
  5. package/declarations/components/shadowed.d.ts +33 -3
  6. package/declarations/components/shadowed.d.ts.map +1 -1
  7. package/declarations/index.d.ts +1 -1
  8. package/declarations/index.d.ts.map +1 -1
  9. package/declarations/test-support/dom.d.ts +14 -0
  10. package/declarations/test-support/dom.d.ts.map +1 -0
  11. package/declarations/test-support.d.ts +7 -0
  12. package/declarations/test-support.d.ts.map +1 -0
  13. package/dist/{floating-ui/modifier.js → component-Bs3N-G9z.js} +72 -4
  14. package/dist/component-Bs3N-G9z.js.map +1 -0
  15. package/dist/components/accordion.js +60 -1
  16. package/dist/components/heading.js +109 -0
  17. package/dist/components/heading.js.map +1 -0
  18. package/dist/components/one-time-password.js +3 -0
  19. package/dist/components/one-time-password.js.map +1 -0
  20. package/dist/components/popover.js +1 -2
  21. package/dist/components/rating.js +1 -1
  22. package/dist/components/shadowed.js +47 -35
  23. package/dist/components/switch.js +8 -2
  24. package/dist/components/toggle.js +1 -1
  25. package/dist/components/zoetrope.js +1 -1
  26. package/dist/floating-ui.js +1 -2
  27. package/dist/index-D052JWRa.js +149 -0
  28. package/dist/index-D052JWRa.js.map +1 -0
  29. package/dist/{components/zoetrope/index.js → index-DKE67I8L.js} +3 -3
  30. package/dist/index-DKE67I8L.js.map +1 -0
  31. package/dist/index.js +3 -4
  32. package/dist/otp-C6hCCXKx.js +291 -0
  33. package/dist/otp-C6hCCXKx.js.map +1 -0
  34. package/dist/test-support.js +255 -0
  35. package/dist/test-support.js.map +1 -0
  36. package/dist/{components/-private/utils.js → utils-C5796IKA.js} +2 -2
  37. package/dist/utils-C5796IKA.js.map +1 -0
  38. package/package.json +1 -9
  39. package/declarations/components/one-time-password/index.d.ts +0 -3
  40. package/declarations/components/one-time-password/index.d.ts.map +0 -1
  41. package/declarations/test-support/index.d.ts +0 -6
  42. package/declarations/test-support/index.d.ts.map +0 -1
  43. package/dist/components/-private/typed-elements.js +0 -14
  44. package/dist/components/-private/typed-elements.js.map +0 -1
  45. package/dist/components/-private/utils.js.map +0 -1
  46. package/dist/components/accordion/content.js +0 -6
  47. package/dist/components/accordion/content.js.map +0 -1
  48. package/dist/components/accordion/header.js +0 -7
  49. package/dist/components/accordion/header.js.map +0 -1
  50. package/dist/components/accordion/item.js +0 -7
  51. package/dist/components/accordion/item.js.map +0 -1
  52. package/dist/components/accordion/public.js +0 -2
  53. package/dist/components/accordion/public.js.map +0 -1
  54. package/dist/components/accordion/trigger.js +0 -7
  55. package/dist/components/accordion/trigger.js.map +0 -1
  56. package/dist/components/one-time-password/buttons.js +0 -26
  57. package/dist/components/one-time-password/buttons.js.map +0 -1
  58. package/dist/components/one-time-password/index.js +0 -4
  59. package/dist/components/one-time-password/index.js.map +0 -1
  60. package/dist/components/one-time-password/input.js +0 -90
  61. package/dist/components/one-time-password/input.js.map +0 -1
  62. package/dist/components/one-time-password/otp.js +0 -58
  63. package/dist/components/one-time-password/otp.js.map +0 -1
  64. package/dist/components/one-time-password/utils.js +0 -144
  65. package/dist/components/one-time-password/utils.js.map +0 -1
  66. package/dist/components/rating/index.js +0 -45
  67. package/dist/components/rating/index.js.map +0 -1
  68. package/dist/components/rating/public-types.js +0 -2
  69. package/dist/components/rating/public-types.js.map +0 -1
  70. package/dist/components/rating/range.js +0 -15
  71. package/dist/components/rating/range.js.map +0 -1
  72. package/dist/components/rating/stars.js +0 -19
  73. package/dist/components/rating/stars.js.map +0 -1
  74. package/dist/components/rating/state.js +0 -82
  75. package/dist/components/rating/state.js.map +0 -1
  76. package/dist/components/rating/utils.js +0 -18
  77. package/dist/components/rating/utils.js.map +0 -1
  78. package/dist/components/zoetrope/index.js.map +0 -1
  79. package/dist/components/zoetrope/types.js +0 -2
  80. package/dist/components/zoetrope/types.js.map +0 -1
  81. package/dist/floating-ui/component.js +0 -63
  82. package/dist/floating-ui/component.js.map +0 -1
  83. package/dist/floating-ui/middleware.js +0 -15
  84. package/dist/floating-ui/middleware.js.map +0 -1
  85. package/dist/floating-ui/modifier.js.map +0 -1
  86. package/dist/item-CwIzoqlC.js +0 -68
  87. package/dist/item-CwIzoqlC.js.map +0 -1
  88. package/dist/test-support/a11y.js +0 -24
  89. package/dist/test-support/a11y.js.map +0 -1
  90. package/dist/test-support/index.js +0 -7
  91. package/dist/test-support/index.js.map +0 -1
  92. package/dist/test-support/otp.js +0 -34
  93. package/dist/test-support/otp.js.map +0 -1
  94. package/dist/test-support/rating.js +0 -92
  95. package/dist/test-support/rating.js.map +0 -1
  96. package/dist/test-support/routing.js +0 -54
  97. package/dist/test-support/routing.js.map +0 -1
  98. package/dist/test-support/zoetrope.js +0 -43
  99. package/dist/test-support/zoetrope.js.map +0 -1
@@ -0,0 +1,149 @@
1
+
2
+ import Component from '@glimmer/component';
3
+ import { hash } from '@ember/helper';
4
+ import { on } from '@ember/modifier';
5
+ import { uniqueId } from './utils.js';
6
+ import { precompileTemplate } from '@ember/template-compilation';
7
+ import { setComponentTemplate } from '@ember/component';
8
+ import templateOnly from '@ember/component/template-only';
9
+ import { cached } from '@glimmer/tracking';
10
+ import { assert } from '@ember/debug';
11
+ import { localCopy } from 'tracked-toolbox';
12
+ import { g, i, n } from 'decorator-transforms/runtime';
13
+
14
+ const RatingRange = setComponentTemplate(precompileTemplate("\n <input ...attributes name={{@name}} type=\"range\" max={{@max}} value={{@value}} {{on \"change\" @handleChange}} />\n", {
15
+ strictMode: true,
16
+ scope: () => ({
17
+ on
18
+ })
19
+ }), templateOnly());
20
+
21
+ function isString(x) {
22
+ return typeof x === 'string';
23
+ }
24
+ function lte(a, b) {
25
+ return a <= b;
26
+ }
27
+ function percentSelected(a, b) {
28
+ const diff = b + 1 - a;
29
+ if (diff < 0) return 0;
30
+ if (diff > 1) return 100;
31
+ if (a === b) return 100;
32
+ const percent = diff * 100;
33
+ return percent;
34
+ }
35
+
36
+ const Stars = setComponentTemplate(precompileTemplate("\n <div class=\"ember-primitives__rating__items\">\n {{#each @stars as |star|}}\n {{#let (uniqueId) as |id|}}\n <span class=\"ember-primitives__rating__item\" data-number={{star}} data-percent-selected={{percentSelected star @currentValue}} data-selected={{lte star @currentValue}} data-readonly={{@isReadonly}}>\n <label for=\"input-{{id}}\">\n <span visually-hidden>{{star}} star</span>\n <span aria-hidden=\"true\">\n {{#if (isString @icon)}}\n {{@icon}}\n {{else}}\n <@icon @value={{star}} @isSelected={{lte star @currentValue}} @percentSelected={{percentSelected star @currentValue}} @readonly={{@isReadonly}} />\n {{/if}}\n </span>\n </label>\n\n <input id=\"input-{{id}}\" type=\"radio\" name={{@name}} value={{star}} readonly={{@isReadonly}} checked={{lte star @currentValue}} />\n </span>\n {{/let}}\n {{/each}}\n </div>\n", {
37
+ strictMode: true,
38
+ scope: () => ({
39
+ uniqueId,
40
+ percentSelected,
41
+ lte,
42
+ isString
43
+ })
44
+ }), templateOnly());
45
+
46
+ class RatingState extends Component {
47
+ static {
48
+ g(this.prototype, "_value", [localCopy("args.value")]);
49
+ }
50
+ #_value = (i(this, "_value"), void 0); // eslint-disable-next-line @typescript-eslint/no-unsafe-call
51
+ get value() {
52
+ return this._value ?? 0;
53
+ }
54
+ get stars() {
55
+ return Array.from({
56
+ length: this.args.max ?? 5
57
+ }, (_, index) => index + 1);
58
+ }
59
+ static {
60
+ n(this.prototype, "stars", [cached]);
61
+ }
62
+ setRating = value => {
63
+ if (this.args.readonly) {
64
+ return;
65
+ }
66
+ if (value === this._value) {
67
+ this._value = 0;
68
+ } else {
69
+ this._value = value;
70
+ }
71
+ this.args.onChange?.(value);
72
+ };
73
+ setFromString = value => {
74
+ assert("[BUG]: value from input must be a string.", typeof value === "string");
75
+ const num = parseFloat(value);
76
+ if (isNaN(num)) {
77
+ // something went wrong.
78
+ // Since we're using event delegation,
79
+ // this could be from an unrelated input
80
+ return;
81
+ }
82
+ this.setRating(num);
83
+ };
84
+ /**
85
+ * Click events are captured by
86
+ * - radio changes (mouse and keyboard)
87
+ * - but only range clicks
88
+ */
89
+ handleClick = event => {
90
+ // Since we're doing event delegation on a click, we want to make sure
91
+ // we don't do anything on other elements
92
+ const isValid = event.target instanceof HTMLInputElement && event.target.name === this.args.name && event.target.type === "radio";
93
+ if (!isValid) return;
94
+ const selected = event.target?.value;
95
+ this.setFromString(selected);
96
+ };
97
+ /**
98
+ * Only attached to a range element, if present.
99
+ * Range elements don't fire click events on keyboard usage, like radios do
100
+ */
101
+ handleChange = event => {
102
+ const isValid = event.target !== null && "value" in event.target;
103
+ if (!isValid) return;
104
+ this.setFromString(event.target.value);
105
+ };
106
+ static {
107
+ setComponentTemplate(precompileTemplate("\n {{yield (hash stars=this.stars total=this.stars.length handleClick=this.handleClick handleChange=this.handleChange setRating=this.setRating value=this.value) (hash total=this.stars.length value=this.value)}}\n ", {
108
+ strictMode: true,
109
+ scope: () => ({
110
+ hash
111
+ })
112
+ }), this);
113
+ }
114
+ }
115
+
116
+ class Rating extends Component {
117
+ name = `rating-${uniqueId()}`;
118
+ get icon() {
119
+ return this.args.icon ?? "★";
120
+ }
121
+ get isInteractive() {
122
+ return this.args.interactive ?? true;
123
+ }
124
+ get isChangeable() {
125
+ const readonly = this.args.readonly ?? false;
126
+ return !readonly && this.isInteractive;
127
+ }
128
+ get isReadonly() {
129
+ return !this.isChangeable;
130
+ }
131
+ get needsDescription() {
132
+ return !this.isInteractive;
133
+ }
134
+ static {
135
+ setComponentTemplate(precompileTemplate("\n <RatingState @max={{@max}} @value={{@value}} @name={{this.name}} @readonly={{this.isReadonly}} @onChange={{@onChange}} as |r publicState|>\n <fieldset class=\"ember-primitives__rating\" data-total={{r.total}} data-value={{r.value}} data-readonly={{this.isReadonly}} {{!-- We use event delegation, this isn't a primary interactive -- we're capturing events from inputs --}} {{!-- template-lint-disable no-invalid-interactive --}} {{on \"click\" r.handleClick}} ...attributes>\n {{#let (component Stars stars=r.stars icon=this.icon isReadonly=this.isReadonly name=this.name total=r.total currentValue=r.value) as |RatingStars|}}\n\n {{#if (has-block)}}\n {{yield (hash max=r.total total=r.total value=r.value name=this.name isReadonly=this.isReadonly isChangeable=this.isChangeable Stars=RatingStars Range=(component RatingRange max=r.total value=r.value name=this.name handleChange=r.handleChange))}}\n {{else}}\n {{#if this.needsDescription}}\n {{#if (has-block \"label\")}}\n {{yield publicState to=\"label\"}}\n {{else}}\n <span visually-hidden class=\"ember-primitives__rating__label\">Rated\n {{r.value}}\n out of\n {{r.total}}</span>\n {{/if}}\n {{else}}\n {{#if (has-block \"label\")}}\n <legend>\n {{yield publicState to=\"label\"}}\n </legend>\n {{/if}}\n {{/if}}\n\n <RatingStars />\n {{/if}}\n {{/let}}\n\n </fieldset>\n </RatingState>\n ", {
136
+ strictMode: true,
137
+ scope: () => ({
138
+ RatingState,
139
+ on,
140
+ Stars,
141
+ hash,
142
+ RatingRange
143
+ })
144
+ }), this);
145
+ }
146
+ }
147
+
148
+ export { Rating as R };
149
+ //# sourceMappingURL=index-D052JWRa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-D052JWRa.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -1,4 +1,4 @@
1
- import "./styles.css"
1
+ import "./components/zoetrope/styles.css"
2
2
  import Component from '@glimmer/component';
3
3
  import { tracked } from '@glimmer/tracking';
4
4
  import { hash } from '@ember/helper';
@@ -265,5 +265,5 @@ function getRelativeBoundingClientRect(childElement, parentElement) {
265
265
  };
266
266
  }
267
267
 
268
- export { Zoetrope, Zoetrope as default };
269
- //# sourceMappingURL=index.js.map
268
+ export { Zoetrope as Z };
269
+ //# sourceMappingURL=index-DKE67I8L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DKE67I8L.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -9,20 +9,19 @@ export { Key, KeyCombo } from './components/keys.js';
9
9
  export { StickyFooter } from './components/layout/sticky-footer.js';
10
10
  export { Link } from './components/link.js';
11
11
  export { Menu } from './components/menu.js';
12
- export { OTPInput } from './components/one-time-password/input.js';
13
- export { OTP } from './components/one-time-password/otp.js';
12
+ export { a as OTP, O as OTPInput } from './otp-C6hCCXKx.js';
14
13
  export { Popover } from './components/popover.js';
15
14
  export { Portal } from './components/portal.js';
16
15
  export { TARGETS as PORTALS, PortalTargets } from './components/portal-targets.js';
17
16
  export { Progress } from './components/progress.js';
18
- export { Rating } from './components/rating/index.js';
17
+ export { R as Rating } from './index-D052JWRa.js';
19
18
  export { Scroller } from './components/scroller.js';
20
19
  export { Shadowed } from './components/shadowed.js';
21
20
  export { Switch } from './components/switch.js';
22
21
  export { Toggle } from './components/toggle.js';
23
22
  export { ToggleGroup } from './components/toggle-group.js';
24
23
  export { VisuallyHidden } from './components/visually-hidden.js';
25
- export { Zoetrope } from './components/zoetrope/index.js';
24
+ export { Z as Zoetrope } from './index-DKE67I8L.js';
26
25
  export { link } from './helpers/link.js';
27
26
  export { service } from './helpers/service.js';
28
27
 
@@ -0,0 +1,291 @@
1
+
2
+ import { assert, warn } from '@ember/debug';
3
+ import { hash, fn } from '@ember/helper';
4
+ import { on } from '@ember/modifier';
5
+ import { buildWaiter } from '@ember/test-waiters';
6
+ import { precompileTemplate } from '@ember/template-compilation';
7
+ import { setComponentTemplate } from '@ember/component';
8
+ import templateOnly from '@ember/component/template-only';
9
+ import Component from '@glimmer/component';
10
+ import { isDestroyed, isDestroying } from '@ember/destroyable';
11
+
12
+ function getInputs(current) {
13
+ const fieldset = current.closest('fieldset');
14
+ assert('[BUG]: fieldset went missing', fieldset);
15
+ return [...fieldset.querySelectorAll('input')];
16
+ }
17
+ function nextInput(current) {
18
+ const inputs = getInputs(current);
19
+ const currentIndex = inputs.indexOf(current);
20
+ return inputs[currentIndex + 1];
21
+ }
22
+ function selectAll(event) {
23
+ const target = event.target;
24
+ assert(`selectAll is only meant for use with input elements`, target instanceof HTMLInputElement);
25
+ target.select();
26
+ }
27
+ function handlePaste(event) {
28
+ const target = event.target;
29
+ assert(`handlePaste is only meant for use with input elements`, target instanceof HTMLInputElement);
30
+ const clipboardData = event.clipboardData;
31
+ assert(`Could not get clipboardData while handling the paste event on OTP. Please report this issue on the ember-primitives repo with a reproduction. Thanks!`, clipboardData);
32
+
33
+ // This is typically not good to prevent paste.
34
+ // But because of the UX we're implementing,
35
+ // we want to split the pasted value across
36
+ // multiple text fields
37
+ event.preventDefault();
38
+ const value = clipboardData.getData('Text');
39
+ const digits = value;
40
+ let i = 0;
41
+ let currElement = target;
42
+ while (currElement) {
43
+ currElement.value = digits[i++] || '';
44
+ const next = nextInput(currElement);
45
+ if (next instanceof HTMLInputElement) {
46
+ currElement = next;
47
+ } else {
48
+ break;
49
+ }
50
+ }
51
+
52
+ // We want to select the first field again
53
+ // so that if someone holds paste, or
54
+ // pastes again, they get the same result.
55
+ target.select();
56
+ }
57
+ function handleNavigation(event) {
58
+ switch (event.key) {
59
+ case 'Backspace':
60
+ return handleBackspace(event);
61
+ case 'ArrowLeft':
62
+ return focusLeft(event);
63
+ case 'ArrowRight':
64
+ return focusRight(event);
65
+ }
66
+ }
67
+ function focusLeft(event) {
68
+ const target = event.target;
69
+ assert(`only allowed on input elements`, target instanceof HTMLInputElement);
70
+ const input = previousInput(target);
71
+ input?.focus();
72
+ requestAnimationFrame(() => {
73
+ input?.select();
74
+ });
75
+ }
76
+ function focusRight(event) {
77
+ const target = event.target;
78
+ assert(`only allowed on input elements`, target instanceof HTMLInputElement);
79
+ const input = nextInput(target);
80
+ input?.focus();
81
+ requestAnimationFrame(() => {
82
+ input?.select();
83
+ });
84
+ }
85
+ const syntheticEvent = new InputEvent('input');
86
+ function handleBackspace(event) {
87
+ if (event.key !== 'Backspace') return;
88
+
89
+ /**
90
+ * We have to prevent default because we
91
+ * - want to clear the whole field
92
+ * - have the focus behavior keep up with the key-repeat
93
+ * speed of the user's computer
94
+ */
95
+ event.preventDefault();
96
+ const target = event.target;
97
+ if (target && 'value' in target) {
98
+ if (target.value === '') {
99
+ focusLeft({
100
+ target
101
+ });
102
+ } else {
103
+ target.value = '';
104
+ }
105
+ }
106
+ target?.dispatchEvent(syntheticEvent);
107
+ }
108
+ function previousInput(current) {
109
+ const inputs = getInputs(current);
110
+ const currentIndex = inputs.indexOf(current);
111
+ return inputs[currentIndex - 1];
112
+ }
113
+ const autoAdvance = event => {
114
+ assert('[BUG]: autoAdvance called on non-input element', event.target instanceof HTMLInputElement);
115
+ const value = event.target.value;
116
+ if (value.length === 0) return;
117
+ if (value.length > 0) {
118
+ if ('data' in event && event.data && typeof event.data === 'string') {
119
+ event.target.value = event.data;
120
+ }
121
+ return focusRight(event);
122
+ }
123
+ };
124
+ function getCollectiveValue(elementTarget, length) {
125
+ if (!elementTarget) return;
126
+ assert(`[BUG]: somehow the element target is not HTMLElement`, elementTarget instanceof HTMLElement);
127
+ let parent;
128
+
129
+ // TODO: should this logic be extracted?
130
+ // why is getting the target element within a shadow root hard?
131
+ if (!(elementTarget instanceof HTMLInputElement)) {
132
+ if (elementTarget.shadowRoot) {
133
+ parent = elementTarget.shadowRoot;
134
+ } else {
135
+ parent = elementTarget.closest('fieldset');
136
+ }
137
+ } else {
138
+ parent = elementTarget.closest('fieldset');
139
+ }
140
+ assert(`[BUG]: somehow the input fields were rendered without a parent element`, parent);
141
+ const elements = parent.querySelectorAll('input');
142
+ let value = '';
143
+ assert(`found elements (${elements.length}) do not match length (${length}). Was the same OTP input rendered more than once?`, elements.length === length);
144
+ for (const element of elements) {
145
+ assert('[BUG]: how did the queried elements become a non-input element?', element instanceof HTMLInputElement);
146
+ value += element.value;
147
+ }
148
+ return value;
149
+ }
150
+
151
+ const DEFAULT_LENGTH = 6;
152
+ function labelFor(inputIndex, labelFn) {
153
+ if (labelFn) {
154
+ return labelFn(inputIndex);
155
+ }
156
+ return `Please enter OTP character ${inputIndex + 1}`;
157
+ }
158
+ const waiter$1 = buildWaiter("ember-primitives:OTPInput:handleChange");
159
+ const Fields = setComponentTemplate(precompileTemplate("\n {{#each @fields as |_field i|}}\n <label>\n <span class=\"ember-primitives__sr-only\">{{labelFor i @labelFn}}</span>\n <input name=\"code{{i}}\" type=\"text\" inputmode=\"numeric\" autocomplete=\"off\" ...attributes {{on \"click\" selectAll}} {{on \"paste\" handlePaste}} {{on \"input\" autoAdvance}} {{on \"input\" @handleChange}} {{on \"keydown\" handleNavigation}} />\n </label>\n {{/each}}\n", {
160
+ strictMode: true,
161
+ scope: () => ({
162
+ labelFor,
163
+ on,
164
+ selectAll,
165
+ handlePaste,
166
+ autoAdvance,
167
+ handleNavigation
168
+ })
169
+ }), templateOnly());
170
+ class OTPInput extends Component {
171
+ /**
172
+ * This is debounced, because we bind to each input,
173
+ * but only want to emit one change event if someone pastes
174
+ * multiple characters
175
+ */
176
+ handleChange = event => {
177
+ if (!this.args.onChange) return;
178
+ if (!this.#token) {
179
+ this.#token = waiter$1.beginAsync();
180
+ }
181
+ if (this.#frame) {
182
+ cancelAnimationFrame(this.#frame);
183
+ }
184
+ // We use requestAnimationFrame to be friendly to rendering.
185
+ // We don't know if onChange is going to want to cause paints
186
+ // (it's also how we debounce, under the assumption that "paste" behavior
187
+ // would be fast enough to be quicker than individual frames
188
+ // (see logic in autoAdvance)
189
+ // )
190
+ this.#frame = requestAnimationFrame(() => {
191
+ waiter$1.endAsync(this.#token);
192
+ if (isDestroyed(this) || isDestroying(this)) return;
193
+ if (!this.args.onChange) return;
194
+ const value = getCollectiveValue(event.target, this.length);
195
+ if (value === undefined) {
196
+ warn(`Value could not be determined for the OTP field. was it removed from the DOM?`, {
197
+ id: "ember-primitives.OTPInput.missing-value"
198
+ });
199
+ return;
200
+ }
201
+ this.args.onChange({
202
+ code: value,
203
+ complete: value.length === this.length
204
+ }, event);
205
+ });
206
+ };
207
+ #token;
208
+ #frame;
209
+ get length() {
210
+ return this.args.length ?? DEFAULT_LENGTH;
211
+ }
212
+ get fields() {
213
+ // We only need to iterate a number of times,
214
+ // so we don't care about the actual value or
215
+ // referential integrity here
216
+ return new Array(this.length);
217
+ }
218
+ static {
219
+ setComponentTemplate(precompileTemplate("\n <fieldset ...attributes>\n {{#let (component Fields fields=this.fields handleChange=this.handleChange labelFn=@labelFn) as |CurriedFields|}}\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 ", {
220
+ strictMode: true,
221
+ scope: () => ({
222
+ Fields
223
+ })
224
+ }), this);
225
+ }
226
+ }
227
+
228
+ const reset = event => {
229
+ assert("[BUG]: reset called without an event.target", event.target instanceof HTMLElement);
230
+ const form = event.target.closest("form");
231
+ assert("Form is missing. Cannot use <Reset> without being contained within a <form>", form instanceof HTMLFormElement);
232
+ form.reset();
233
+ };
234
+ const Submit = setComponentTemplate(precompileTemplate("\n <button type=\"submit\" ...attributes>Submit</button>\n", {
235
+ strictMode: true
236
+ }), templateOnly());
237
+ const Reset = setComponentTemplate(precompileTemplate("\n <button type=\"button\" {{on \"click\" reset}} ...attributes>{{yield}}</button>\n", {
238
+ strictMode: true,
239
+ scope: () => ({
240
+ on,
241
+ reset
242
+ })
243
+ }), templateOnly());
244
+
245
+ const waiter = buildWaiter("ember-primitives:OTP:handleAutoSubmitAttempt");
246
+ const handleFormSubmit = (submit, event) => {
247
+ event.preventDefault();
248
+ assert("[BUG]: handleFormSubmit was not attached to a form. Please open an issue.", event.currentTarget instanceof HTMLFormElement);
249
+ const formData = new FormData(event.currentTarget);
250
+ let code = "";
251
+ for (const [key, value] of formData.entries()) {
252
+ if (key.startsWith("code")) {
253
+ // eslint-disable-next-line @typescript-eslint/restrict-plus-operands, @typescript-eslint/no-base-to-string
254
+ code += value;
255
+ }
256
+ }
257
+ submit({
258
+ code
259
+ });
260
+ };
261
+ function handleChange(autoSubmit, data, event) {
262
+ if (!autoSubmit) return;
263
+ if (!data.complete) return;
264
+ assert("[BUG]: event target is not a known element type", event.target instanceof HTMLElement || event.target instanceof SVGElement);
265
+ const form = event.target.closest("form");
266
+ assert("[BUG]: Cannot handle event when <OTP> Inputs are not rendered within their <form>", form);
267
+ const token = waiter.beginAsync();
268
+ const finished = () => {
269
+ waiter.endAsync(token);
270
+ form.removeEventListener("submit", finished);
271
+ };
272
+ form.addEventListener("submit", finished);
273
+ // NOTE: when calling .submit() the submit event handlers are not run
274
+ form.requestSubmit();
275
+ }
276
+ const OTP = setComponentTemplate(precompileTemplate("\n <form {{on \"submit\" (fn handleFormSubmit @onSubmit)}} ...attributes>\n {{yield (hash Input=(component OTPInput length=@length onChange=(if @autoSubmit (fn handleChange @autoSubmit))) Submit=Submit Reset=Reset)}}\n </form>\n", {
277
+ strictMode: true,
278
+ scope: () => ({
279
+ on,
280
+ fn,
281
+ handleFormSubmit,
282
+ hash,
283
+ OTPInput,
284
+ handleChange,
285
+ Submit,
286
+ Reset
287
+ })
288
+ }), templateOnly());
289
+
290
+ export { OTPInput as O, OTP as a };
291
+ //# sourceMappingURL=otp-C6hCCXKx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otp-C6hCCXKx.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}