ember-primitives 0.48.1 → 0.49.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 +9 -2
- package/declarations/components/menu.d.ts +26 -10
- package/declarations/components/menu.d.ts.map +1 -1
- package/declarations/components/portal.d.ts.map +1 -1
- package/declarations/tabster.d.ts.map +1 -1
- package/declarations/utils.d.ts.map +1 -1
- package/declarations/viewport/in-viewport.d.ts +70 -0
- package/declarations/viewport/in-viewport.d.ts.map +1 -0
- package/declarations/viewport/viewport.d.ts +59 -0
- package/declarations/viewport/viewport.d.ts.map +1 -0
- package/declarations/viewport.d.ts +3 -0
- package/declarations/viewport.d.ts.map +1 -0
- package/dist/-private.js +0 -1
- package/dist/-private.js.map +1 -1
- package/dist/color-scheme.js +0 -1
- package/dist/color-scheme.js.map +1 -1
- package/dist/{component-Bs3N-G9z.js → component-BXy_iafw.js} +2 -3
- package/dist/component-BXy_iafw.js.map +1 -0
- package/dist/components/accordion.js +5 -6
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/avatar.js +3 -4
- package/dist/components/avatar.js.map +1 -1
- package/dist/components/dialog.js +2 -3
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/external-link.js +1 -2
- package/dist/components/external-link.js.map +1 -1
- package/dist/components/form.js +1 -2
- package/dist/components/form.js.map +1 -1
- package/dist/components/heading.js +1 -2
- package/dist/components/heading.js.map +1 -1
- package/dist/components/keys.js +2 -3
- package/dist/components/keys.js.map +1 -1
- package/dist/components/layout/hero.js +1 -1
- package/dist/components/layout/sticky-footer.js +1 -1
- package/dist/components/link.js +1 -2
- package/dist/components/link.js.map +1 -1
- package/dist/components/menu.js +6 -9
- package/dist/components/menu.js.map +1 -1
- package/dist/components/one-time-password.js +1 -2
- package/dist/components/popover.js +3 -4
- package/dist/components/popover.js.map +1 -1
- package/dist/components/portal-targets.js +2 -3
- package/dist/components/portal-targets.js.map +1 -1
- package/dist/components/portal.js +3 -7
- package/dist/components/portal.js.map +1 -1
- package/dist/components/progress.js +2 -3
- package/dist/components/progress.js.map +1 -1
- package/dist/components/rating.js +1 -2
- package/dist/components/scroller.js +1 -2
- package/dist/components/scroller.js.map +1 -1
- package/dist/components/shadowed.js +2 -3
- package/dist/components/shadowed.js.map +1 -1
- package/dist/components/switch.js +5 -6
- package/dist/components/switch.js.map +1 -1
- package/dist/components/tabs.js +6 -7
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/toggle-group.js +3 -4
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle.js +2 -3
- package/dist/components/toggle.js.map +1 -1
- package/dist/components/visually-hidden.js +1 -2
- package/dist/components/visually-hidden.js.map +1 -1
- package/dist/components/zoetrope.js +1 -2
- package/dist/dom-context.js +2 -3
- package/dist/dom-context.js.map +1 -1
- package/dist/floating-ui.js +1 -2
- package/dist/head.js +1 -2
- package/dist/head.js.map +1 -1
- package/dist/helpers/body-class.js +0 -1
- package/dist/helpers/body-class.js.map +1 -1
- package/dist/helpers/link.js +0 -1
- package/dist/helpers/link.js.map +1 -1
- package/dist/helpers/service.js +0 -1
- package/dist/helpers/service.js.map +1 -1
- package/dist/helpers.js +0 -1
- package/dist/helpers.js.map +1 -1
- package/dist/iframe.js +0 -1
- package/dist/iframe.js.map +1 -1
- package/dist/{index-DKE67I8L.js → index-gRO4Cvlf.js} +2 -2
- package/dist/index-gRO4Cvlf.js.map +1 -0
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/load.js +0 -1
- package/dist/load.js.map +1 -1
- package/dist/narrowing.js +0 -1
- package/dist/narrowing.js.map +1 -1
- package/dist/on-resize.js +0 -1
- package/dist/on-resize.js.map +1 -1
- package/dist/{otp-C6hCCXKx.js → otp-7rz1PWP0.js} +6 -7
- package/dist/otp-7rz1PWP0.js.map +1 -0
- package/dist/proper-links.js +0 -1
- package/dist/proper-links.js.map +1 -1
- package/dist/qp.js +0 -1
- package/dist/qp.js.map +1 -1
- package/dist/{rating-D052JWRa.js → rating-CjBVsX6q.js} +5 -6
- package/dist/rating-CjBVsX6q.js.map +1 -0
- package/dist/resize-observer.js +0 -1
- package/dist/resize-observer.js.map +1 -1
- package/dist/service.js +0 -1
- package/dist/service.js.map +1 -1
- package/dist/store.js +0 -1
- package/dist/store.js.map +1 -1
- package/dist/styles.css.js +0 -1
- package/dist/tabster.js +0 -1
- package/dist/tabster.js.map +1 -1
- package/dist/test-support.js +0 -1
- package/dist/test-support.js.map +1 -1
- package/dist/{utils-C5796IKA.js → utils-D0v9WKmV.js} +1 -2
- package/dist/utils-D0v9WKmV.js.map +1 -0
- package/dist/utils.js +4 -1
- package/dist/utils.js.map +1 -1
- package/dist/viewport/in-viewport.js +82 -0
- package/dist/viewport/in-viewport.js.map +1 -0
- package/dist/viewport/viewport.js +92 -0
- package/dist/viewport/viewport.js.map +1 -0
- package/dist/viewport.js +3 -0
- package/dist/viewport.js.map +1 -0
- package/package.json +20 -20
- package/dist/component-Bs3N-G9z.js.map +0 -1
- package/dist/index-DKE67I8L.js.map +0 -1
- package/dist/otp-C6hCCXKx.js.map +0 -1
- package/dist/rating-D052JWRa.js.map +0 -1
- package/dist/utils-C5796IKA.js.map +0 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import { assert, warn } from '@ember/debug';
|
|
3
2
|
import { hash, fn } from '@ember/helper';
|
|
4
3
|
import { on } from '@ember/modifier';
|
|
@@ -156,7 +155,7 @@ function labelFor(inputIndex, labelFn) {
|
|
|
156
155
|
return `Please enter OTP character ${inputIndex + 1}`;
|
|
157
156
|
}
|
|
158
157
|
const waiter$1 = buildWaiter("ember-primitives:OTPInput:handleChange");
|
|
159
|
-
const Fields = setComponentTemplate(precompileTemplate("
|
|
158
|
+
const Fields = setComponentTemplate(precompileTemplate("{{#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}}", {
|
|
160
159
|
strictMode: true,
|
|
161
160
|
scope: () => ({
|
|
162
161
|
labelFor,
|
|
@@ -216,7 +215,7 @@ class OTPInput extends Component {
|
|
|
216
215
|
return new Array(this.length);
|
|
217
216
|
}
|
|
218
217
|
static {
|
|
219
|
-
setComponentTemplate(precompileTemplate("
|
|
218
|
+
setComponentTemplate(precompileTemplate("<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>", {
|
|
220
219
|
strictMode: true,
|
|
221
220
|
scope: () => ({
|
|
222
221
|
Fields
|
|
@@ -231,10 +230,10 @@ const reset = event => {
|
|
|
231
230
|
assert("Form is missing. Cannot use <Reset> without being contained within a <form>", form instanceof HTMLFormElement);
|
|
232
231
|
form.reset();
|
|
233
232
|
};
|
|
234
|
-
const Submit = setComponentTemplate(precompileTemplate("
|
|
233
|
+
const Submit = setComponentTemplate(precompileTemplate("<button type=\"submit\" ...attributes>Submit</button>", {
|
|
235
234
|
strictMode: true
|
|
236
235
|
}), templateOnly());
|
|
237
|
-
const Reset = setComponentTemplate(precompileTemplate("
|
|
236
|
+
const Reset = setComponentTemplate(precompileTemplate("<button type=\"button\" {{on \"click\" reset}} ...attributes>{{yield}}</button>", {
|
|
238
237
|
strictMode: true,
|
|
239
238
|
scope: () => ({
|
|
240
239
|
on,
|
|
@@ -273,7 +272,7 @@ function handleChange(autoSubmit, data, event) {
|
|
|
273
272
|
// NOTE: when calling .submit() the submit event handlers are not run
|
|
274
273
|
form.requestSubmit();
|
|
275
274
|
}
|
|
276
|
-
const OTP = setComponentTemplate(precompileTemplate("
|
|
275
|
+
const OTP = setComponentTemplate(precompileTemplate("<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>", {
|
|
277
276
|
strictMode: true,
|
|
278
277
|
scope: () => ({
|
|
279
278
|
on,
|
|
@@ -288,4 +287,4 @@ const OTP = setComponentTemplate(precompileTemplate("\n <form {{on \"submit\" (
|
|
|
288
287
|
}), templateOnly());
|
|
289
288
|
|
|
290
289
|
export { OTPInput as O, OTP as a };
|
|
291
|
-
//# sourceMappingURL=otp-
|
|
290
|
+
//# sourceMappingURL=otp-7rz1PWP0.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otp-7rz1PWP0.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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"}
|
package/dist/proper-links.js
CHANGED
package/dist/proper-links.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proper-links.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"proper-links.js","sources":["../src/proper-links.ts"],"sourcesContent":["import { assert } from '@ember/debug';\nimport { registerDestructor } from '@ember/destroyable';\nimport { getOwner } from '@ember/owner';\n\nimport { getAnchor, shouldHandle } from 'should-handle-link';\n\nimport type { Newable } from './type-utils.ts';\nimport type EmberRouter from '@ember/routing/router';\nimport type RouterService from '@ember/routing/router-service';\n\nexport { shouldHandle } from 'should-handle-link';\n\nexport interface Options {\n ignore?: string[];\n}\n\nexport function properLinks(\n options: Options\n): <Instance extends object, Klass = { new (...args: any[]): Instance }>(klass: Klass) => Klass;\n\nexport function properLinks<Instance extends object, Klass = { new (...args: any[]): Instance }>(\n klass: Klass\n): Klass;\n/**\n * @internal\n */\nexport function properLinks<Instance extends object, Klass = { new (...args: any[]): Instance }>(\n options: Options,\n klass: Klass\n): Klass;\n\nexport function properLinks<Instance extends object, Klass = { new (...args: any[]): Instance }>(\n ...args: [Options] | [Klass] | [Options, Klass]\n): Klass | ((klass: Klass) => Klass) {\n let options: Options = {};\n\n let klass: undefined | Klass = undefined;\n\n if (args.length === 2) {\n options = args[0];\n klass = args[1];\n } else if (args.length === 1) {\n if (typeof args[0] === 'object') {\n // TODO: how to get first arg type correct?\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n return (klass: Klass) => properLinks(args[0] as any, klass);\n } else {\n klass = args[0];\n }\n }\n\n const ignore = options.ignore || [];\n\n assert(`klass was not defined. possibile incorrect arity given to properLinks`, klass);\n\n return class RouterWithProperLinks extends (klass as unknown as Newable<EmberRouter>) {\n // SAFETY: we literally do not care about the args' type here,\n // because we just call super\n constructor(...args: any[]) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n super(...args);\n\n setup(this, ignore);\n }\n } as unknown as Klass;\n}\n\n/**\n * Setup proper links without a decorator.\n * This function only requires that a framework object with an owner is passed.\n */\nexport function setup(parent: object, ignore?: string[]) {\n const handler = (event: MouseEvent) => {\n /**\n * event.target may not be an anchor,\n * it may be a span, svg, img, or any number of elements nested in <a>...</a>\n */\n const interactive = getAnchor(event);\n\n if (!interactive) return;\n\n const owner = getOwner(parent);\n\n assert('owner is not present', owner);\n\n const routerService = owner.lookup('service:router');\n\n handle(routerService, interactive, ignore ?? [], event);\n };\n\n document.body.addEventListener('click', handler, false);\n\n registerDestructor(parent, () => document.body.removeEventListener('click', handler));\n}\n\nexport function handle(\n router: RouterService,\n element: HTMLAnchorElement,\n ignore: string[],\n event: MouseEvent\n) {\n if (!shouldHandle(location.href, element, event, ignore)) {\n return;\n }\n\n const url = new URL(element.href);\n\n const fullHref = `${url.pathname}${url.search}${url.hash}`;\n\n const rootURL = router.rootURL;\n\n let withoutRootURL = fullHref.slice(rootURL.length);\n\n // re-add the \"root\" sigil\n // we removed it when we chopped off the rootURL,\n // because the rootURL often has this attached to it as well\n if (!withoutRootURL.startsWith('/')) {\n withoutRootURL = `/${withoutRootURL}`;\n }\n\n try {\n const routeInfo = router.recognize(fullHref);\n\n if (routeInfo) {\n event.preventDefault();\n event.stopImmediatePropagation();\n event.stopPropagation();\n\n router.transitionTo(withoutRootURL);\n\n return false;\n }\n } catch (e) {\n if (e instanceof Error && e.name === 'UnrecognizedURLError') {\n return;\n }\n\n throw e;\n }\n}\n"],"names":["properLinks","args","options","klass","undefined","length","ignore","assert","RouterWithProperLinks","constructor","setup","parent","handler","event","interactive","getAnchor","owner","getOwner","routerService","lookup","handle","document","body","addEventListener","registerDestructor","removeEventListener","router","element","shouldHandle","location","href","url","URL","fullHref","pathname","search","hash","rootURL","withoutRootURL","slice","startsWith","routeInfo","recognize","preventDefault","stopImmediatePropagation","stopPropagation","transitionTo","e","Error","name"],"mappings":"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"}
|
package/dist/qp.js
CHANGED
package/dist/qp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qp.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"qp.js","sources":["../src/qp.ts"],"sourcesContent":["import Helper from '@ember/component/helper';\nimport { assert } from '@ember/debug';\nimport { service } from '@ember/service';\n\nimport type RouterService from '@ember/routing/router-service';\n\ninterface Signature {\n Args: {\n Positional: [string];\n };\n Return: string | undefined;\n}\n\n/**\n * Grabs a query-param off the current route from the router service.\n *\n * ```gjs\n * import { qp } from 'ember-primitives/qp';\n *\n * <template>\n * {{qp \"query-param\"}}\n * </template>\n * ```\n */\nexport class qp extends Helper<Signature> {\n @service declare router: RouterService;\n\n compute([name]: [string]): string | undefined {\n assert('A queryParam name is required', name);\n\n return this.router.currentRoute?.queryParams?.[name] as string | undefined;\n }\n}\n\n/**\n * Returns a string for use as an `href` on `<a>` tags, updated with the passed query param\n *\n * ```gjs\n * import { withQP } from 'ember-primitives/qp';\n *\n * <template>\n * <a href={{withQP \"foo\" \"2\"}}>\n * ...\n * </a>\n * </template>\n * ```\n */\nexport class withQP extends Helper<{ Args: { Positional: [string, string] }; Return: string }> {\n @service declare router: RouterService;\n\n compute([qpName, nextValue]: [string, string]) {\n const existing = this.router.currentURL;\n\n assert('A queryParam name is required', qpName);\n assert('There is no currentURL', existing);\n\n const url = new URL(existing, location.origin);\n\n url.searchParams.set(qpName, nextValue);\n\n return url.href;\n }\n}\n\n/**\n * Cast a query-param string value to a boolean\n *\n * ```gjs\n * import { castToBoolean, qp } from 'ember-primitives/qp';\n *\n * <template>\n * {{#if (castToBoolean (qp 'the-qp'))}}\n * ...\n * {{/if}}\n * </template>\n * ```\n *\n * The following values are considered \"false\"\n * - undefined\n * - \"\"\n * - \"0\"\n * - false\n * - \"f\"\n * - \"off\"\n * - \"no\"\n * - \"null\"\n * - \"undefined\"\n *\n * All other values are considered truthy\n */\nexport function castToBoolean(x: string | undefined) {\n if (!x) return false;\n\n const isFalsey =\n x === '0' ||\n x === 'false' ||\n x === 'f' ||\n x === 'null' ||\n x === 'off' ||\n x === 'undefined' ||\n x === 'no';\n\n if (isFalsey) return false;\n\n // All other values are considered truthy\n return true;\n}\n"],"names":["qp","Helper","g","prototype","service","i","compute","name","assert","router","currentRoute","queryParams","withQP","qpName","nextValue","existing","currentURL","url","URL","location","origin","searchParams","set","href","castToBoolean","x","isFalsey"],"mappings":";;;;;AAaA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,EAAE,SAASC,MAAM,CAAY;AAAA,EAAA;IAAAC,CAAA,CAAA,IAAA,CAAAC,SAAA,EAAA,QAAA,EAAA,CACvCC,OAAO,CAAA,CAAA;AAAA;EAAA,OAAA,IAAAC,CAAA,CAAA,IAAA,EAAA,QAAA,CAAA,EAAA,MAAA;AAERC,EAAAA,OAAOA,CAAC,CAACC,IAAI,CAAW,EAAsB;AAC5CC,IAAAA,MAAM,CAAC,+BAA+B,EAAED,IAAI,CAAC;IAE7C,OAAO,IAAI,CAACE,MAAM,CAACC,YAAY,EAAEC,WAAW,GAAGJ,IAAI,CAAC;AACtD,EAAA;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMK,MAAM,SAASX,MAAM,CAA6D;AAAA,EAAA;IAAAC,CAAA,CAAA,IAAA,CAAAC,SAAA,EAAA,QAAA,EAAA,CAC5FC,OAAO,CAAA,CAAA;AAAA;EAAA,OAAA,IAAAC,CAAA,CAAA,IAAA,EAAA,QAAA,CAAA,EAAA,MAAA;AAERC,EAAAA,OAAOA,CAAC,CAACO,MAAM,EAAEC,SAAS,CAAmB,EAAE;AAC7C,IAAA,MAAMC,QAAQ,GAAG,IAAI,CAACN,MAAM,CAACO,UAAU;AAEvCR,IAAAA,MAAM,CAAC,+BAA+B,EAAEK,MAAM,CAAC;AAC/CL,IAAAA,MAAM,CAAC,wBAAwB,EAAEO,QAAQ,CAAC;IAE1C,MAAME,GAAG,GAAG,IAAIC,GAAG,CAACH,QAAQ,EAAEI,QAAQ,CAACC,MAAM,CAAC;IAE9CH,GAAG,CAACI,YAAY,CAACC,GAAG,CAACT,MAAM,EAAEC,SAAS,CAAC;IAEvC,OAAOG,GAAG,CAACM,IAAI;AACjB,EAAA;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,aAAaA,CAACC,CAAqB,EAAE;AACnD,EAAA,IAAI,CAACA,CAAC,EAAE,OAAO,KAAK;AAEpB,EAAA,MAAMC,QAAQ,GACZD,CAAC,KAAK,GAAG,IACTA,CAAC,KAAK,OAAO,IACbA,CAAC,KAAK,GAAG,IACTA,CAAC,KAAK,MAAM,IACZA,CAAC,KAAK,KAAK,IACXA,CAAC,KAAK,WAAW,IACjBA,CAAC,KAAK,IAAI;EAEZ,IAAIC,QAAQ,EAAE,OAAO,KAAK;;AAE1B;AACA,EAAA,OAAO,IAAI;AACb;;;;"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import Component from '@glimmer/component';
|
|
3
2
|
import { hash } from '@ember/helper';
|
|
4
3
|
import { on } from '@ember/modifier';
|
|
@@ -11,7 +10,7 @@ import { assert } from '@ember/debug';
|
|
|
11
10
|
import { localCopy } from 'tracked-toolbox';
|
|
12
11
|
import { g, i, n } from 'decorator-transforms/runtime';
|
|
13
12
|
|
|
14
|
-
const RatingRange = setComponentTemplate(precompileTemplate("
|
|
13
|
+
const RatingRange = setComponentTemplate(precompileTemplate("<input ...attributes name={{@name}} type=\"range\" max={{@max}} value={{@value}} {{on \"change\" @handleChange}} />", {
|
|
15
14
|
strictMode: true,
|
|
16
15
|
scope: () => ({
|
|
17
16
|
on
|
|
@@ -33,7 +32,7 @@ function percentSelected(a, b) {
|
|
|
33
32
|
return percent;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
const Stars = setComponentTemplate(precompileTemplate("
|
|
35
|
+
const Stars = setComponentTemplate(precompileTemplate("<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>", {
|
|
37
36
|
strictMode: true,
|
|
38
37
|
scope: () => ({
|
|
39
38
|
uniqueId,
|
|
@@ -104,7 +103,7 @@ class RatingState extends Component {
|
|
|
104
103
|
this.setFromString(event.target.value);
|
|
105
104
|
};
|
|
106
105
|
static {
|
|
107
|
-
setComponentTemplate(precompileTemplate("
|
|
106
|
+
setComponentTemplate(precompileTemplate("{{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)}}", {
|
|
108
107
|
strictMode: true,
|
|
109
108
|
scope: () => ({
|
|
110
109
|
hash
|
|
@@ -132,7 +131,7 @@ class Rating extends Component {
|
|
|
132
131
|
return !this.isInteractive;
|
|
133
132
|
}
|
|
134
133
|
static {
|
|
135
|
-
setComponentTemplate(precompileTemplate("
|
|
134
|
+
setComponentTemplate(precompileTemplate("<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>", {
|
|
136
135
|
strictMode: true,
|
|
137
136
|
scope: () => ({
|
|
138
137
|
RatingState,
|
|
@@ -146,4 +145,4 @@ class Rating extends Component {
|
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
export { Rating as R };
|
|
149
|
-
//# sourceMappingURL=rating-
|
|
148
|
+
//# sourceMappingURL=rating-CjBVsX6q.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rating-CjBVsX6q.js","sources":["../src/components/rating/range.gts","../src/components/rating/utils.ts","../src/components/rating/stars.gts","../src/components/rating/state.gts","../src/components/rating/rating.gts"],"sourcesContent":["import { on } from \"@ember/modifier\";\n\nimport type { TOC } from \"@ember/component/template-only\";\n\nexport const RatingRange: TOC<{\n Element: HTMLInputElement;\n Args: {\n name: string;\n max: number;\n value: number;\n handleChange: (event: Event) => void;\n };\n}> = <template>\n <input\n ...attributes\n name={{@name}}\n type=\"range\"\n max={{@max}}\n value={{@value}}\n {{on \"change\" @handleChange}}\n />\n</template>;\n","export function isString(x: unknown) {\n return typeof x === 'string';\n}\n\nexport function lte(a: number, b: number) {\n return a <= b;\n}\n\nexport function percentSelected(a: number, b: number) {\n const diff = b + 1 - a;\n\n if (diff < 0) return 0;\n if (diff > 1) return 100;\n if (a === b) return 100;\n\n const percent = diff * 100;\n\n return percent;\n}\n","import { uniqueId } from \"../../utils.ts\";\nimport { isString, lte, percentSelected } from \"./utils.ts\";\n\nimport type { ComponentIcons, StringIcons } from \"./public-types.ts\";\nimport type { TOC } from \"@ember/component/template-only\";\n\nexport const Stars: TOC<{\n Args: {\n // Configuration\n stars: number[];\n icon: StringIcons[\"icon\"] | ComponentIcons[\"icon\"];\n isReadonly: boolean;\n\n // HTML Boilerplate\n name: string;\n\n // State\n currentValue: number;\n total: number;\n };\n}> = <template>\n <div class=\"ember-primitives__rating__items\">\n {{#each @stars as |star|}}\n {{#let (uniqueId) as |id|}}\n <span\n class=\"ember-primitives__rating__item\"\n data-number={{star}}\n data-percent-selected={{percentSelected star @currentValue}}\n data-selected={{lte star @currentValue}}\n data-readonly={{@isReadonly}}\n >\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\n @value={{star}}\n @isSelected={{lte star @currentValue}}\n @percentSelected={{percentSelected star @currentValue}}\n @readonly={{@isReadonly}}\n />\n {{/if}}\n </span>\n </label>\n\n <input\n id=\"input-{{id}}\"\n type=\"radio\"\n name={{@name}}\n value={{star}}\n readonly={{@isReadonly}}\n checked={{lte star @currentValue}}\n />\n </span>\n {{/let}}\n {{/each}}\n </div>\n</template>;\n","import Component from \"@glimmer/component\";\nimport { cached } from \"@glimmer/tracking\";\nimport { assert } from \"@ember/debug\";\nimport { hash } from \"@ember/helper\";\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-expect-error\nimport { localCopy } from \"tracked-toolbox\";\n\nexport class RatingState extends Component<{\n Args: {\n max: number | undefined;\n value: number | undefined;\n readonly: boolean | undefined;\n name: string;\n onChange?: (value: number) => void;\n };\n Blocks: {\n default: [\n internalApi: {\n stars: number[];\n value: number;\n total: number;\n handleClick: (event: Event) => void;\n handleChange: (event: Event) => void;\n setRating: (num: number) => void;\n },\n publicApi: {\n value: number;\n total: number;\n },\n ];\n };\n}> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n @localCopy(\"args.value\") declare _value: number;\n\n get value() {\n return this._value ?? 0;\n }\n\n @cached\n get stars() {\n return Array.from({ length: this.args.max ?? 5 }, (_, index) => index + 1);\n }\n\n setRating = (value: number) => {\n if (this.args.readonly) {\n return;\n }\n\n if (value === this._value) {\n this._value = 0;\n } else {\n this._value = value;\n }\n\n this.args.onChange?.(value);\n };\n\n setFromString = (value: unknown) => {\n assert(\"[BUG]: value from input must be a string.\", typeof value === \"string\");\n\n const num = parseFloat(value);\n\n if (isNaN(num)) {\n // something went wrong.\n // Since we're using event delegation,\n // this could be from an unrelated input\n return;\n }\n\n this.setRating(num);\n };\n\n /**\n * Click events are captured by\n * - radio changes (mouse and keyboard)\n * - but only range clicks\n */\n handleClick = (event: Event) => {\n // Since we're doing event delegation on a click, we want to make sure\n // we don't do anything on other elements\n const isValid =\n event.target instanceof HTMLInputElement &&\n event.target.name === this.args.name &&\n event.target.type === \"radio\";\n\n if (!isValid) return;\n\n const selected = event.target?.value;\n\n this.setFromString(selected);\n };\n\n /**\n * Only attached to a range element, if present.\n * Range elements don't fire click events on keyboard usage, like radios do\n */\n handleChange = (event: Event) => {\n const isValid = event.target !== null && \"value\" in event.target;\n\n if (!isValid) return;\n\n this.setFromString(event.target.value);\n };\n\n <template>\n {{yield\n (hash\n stars=this.stars\n total=this.stars.length\n handleClick=this.handleClick\n handleChange=this.handleChange\n setRating=this.setRating\n value=this.value\n )\n (hash total=this.stars.length value=this.value)\n }}\n </template>\n}\n","import Component from \"@glimmer/component\";\nimport { hash } from \"@ember/helper\";\nimport { on } from \"@ember/modifier\";\n\nimport { uniqueId } from \"../../utils.ts\";\nimport { RatingRange } from \"./range.gts\";\nimport { Stars } from \"./stars.gts\";\nimport { RatingState } from \"./state.gts\";\n\nimport type { ComponentIcons, StringIcons } from \"./public-types.ts\";\nimport type { WithBoundArgs } from \"@glint/template\";\n\nexport interface Signature {\n /*\n * The element all passed attributes / modifiers are applied to.\n *\n * This is a `<fieldset>`, becaues the rating elements are\n * powered by a group of radio buttons.\n */\n Element: HTMLFieldSetElement;\n Args: (ComponentIcons | StringIcons) & {\n /**\n * The number of stars/whichever-icon to show\n *\n * Defaults to 5\n */\n max?: number;\n\n /**\n * The current number of stars/whichever-icon to show as selected\n *\n * Defaults to 0\n */\n value?: number;\n\n /**\n * Prevents click events on the icons and sets aria-readonly.\n *\n * Also sets data-readonly=true on the wrapping element\n */\n readonly?: boolean;\n\n /**\n * Toggles the ability to interact with the rating component.\n * When `true` (the default), the Rating component can be as a form input\n * to gather user feedback.\n *\n * When false, only the `@value` will be shown, and it cannot be changed.\n */\n interactive?: boolean;\n\n /**\n * Callback when the selected rating changes.\n * Can include half-ratings if the iconHalf argument is passed.\n */\n onChange?: (value: number) => void;\n };\n\n Blocks: {\n default: [\n rating: {\n /**\n * The maximum rating\n */\n max: number;\n /**\n * The maxium rating\n */\n total: number;\n /**\n * The current rating\n */\n value: number;\n /**\n * The name shared by the field group\n */\n name: string;\n /**\n * If the rating can be changed\n */\n isReadonly: boolean;\n /**\n * If the rating can be changed\n */\n isChangeable: boolean;\n /**\n * The stars / items radio group\n */\n Stars: WithBoundArgs<\n typeof Stars,\n \"stars\" | \"icon\" | \"isReadonly\" | \"name\" | \"total\" | \"currentValue\"\n >;\n /**\n * Input range for adjusting the rating via fractional means\n */\n Range: WithBoundArgs<typeof RatingRange, \"max\" | \"value\" | \"name\" | \"handleChange\">;\n },\n ];\n label: [\n state: {\n /**\n * The current rating\n */\n value: number;\n\n /**\n * The maximum rating\n */\n total: number;\n },\n ];\n };\n}\n\nexport class Rating extends Component<Signature> {\n name = `rating-${uniqueId()}`;\n\n get icon() {\n return this.args.icon ?? \"★\";\n }\n\n get isInteractive() {\n return this.args.interactive ?? true;\n }\n\n get isChangeable() {\n const readonly = this.args.readonly ?? false;\n\n return !readonly && this.isInteractive;\n }\n\n get isReadonly() {\n return !this.isChangeable;\n }\n\n get needsDescription() {\n return !this.isInteractive;\n }\n\n <template>\n <RatingState\n @max={{@max}}\n @value={{@value}}\n @name={{this.name}}\n @readonly={{this.isReadonly}}\n @onChange={{@onChange}}\n as |r publicState|\n >\n <fieldset\n class=\"ember-primitives__rating\"\n data-total={{r.total}}\n data-value={{r.value}}\n data-readonly={{this.isReadonly}}\n {{! We use event delegation, this isn't a primary interactive -- we're capturing events from inputs }}\n {{! template-lint-disable no-invalid-interactive }}\n {{on \"click\" r.handleClick}}\n ...attributes\n >\n {{#let\n (component\n Stars\n stars=r.stars\n icon=this.icon\n isReadonly=this.isReadonly\n name=this.name\n total=r.total\n currentValue=r.value\n )\n as |RatingStars|\n }}\n\n {{#if (has-block)}}\n {{yield\n (hash\n max=r.total\n total=r.total\n value=r.value\n name=this.name\n isReadonly=this.isReadonly\n isChangeable=this.isChangeable\n Stars=RatingStars\n Range=(component\n RatingRange max=r.total value=r.value name=this.name handleChange=r.handleChange\n )\n )\n }}\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 </template>\n}\n"],"names":["RatingRange","setComponentTemplate","precompileTemplate","strictMode","scope","on","templateOnly","isString","x","lte","a","b","percentSelected","diff","percent","Stars","uniqueId","RatingState","Component","localCopy","i","value","_value","stars","Array","from","length","args","max","_","index","n","prototype","cached","setRating","readonly","onChange","setFromString","assert","num","parseFloat","isNaN","handleClick","event","isValid","target","HTMLInputElement","name","type","selected","handleChange","hash","Rating","icon","isInteractive","interactive","isChangeable","isReadonly","needsDescription"],"mappings":"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"}
|
package/dist/resize-observer.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resize-observer.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"resize-observer.js","sources":["../src/resize-observer.ts"],"sourcesContent":["import { assert } from '@ember/debug';\nimport { registerDestructor } from '@ember/destroyable';\n\nimport { createStore } from './store.ts';\nimport { findOwner } from './utils.ts';\n\n/**\n * Creates or returns the ResizeObserverManager.\n *\n * Only one of these will exist per owner.\n *\n * Has only two methods:\n * - observe(element, callback: (resizeObserverEntry) => void)\n * - unobserve(element, callback: (resizeObserverEntry) => void)\n *\n * Like with the underlying ResizeObserver API (and all event listeners),\n * the callback passed to unobserved must be the same reference as the one\n * passed to observe.\n */\nexport function resizeObserver(context: object) {\n const owner = findOwner(context);\n\n assert(\n `Could not find owner on the passed context (to resizeObserver). resizeObserver can only be used on an object whos lifetime is in someone entangled with the application (which incidentally has an \"owner\").`,\n owner\n );\n\n return createStore(owner, ResizeObserverManager);\n}\n\nclass ResizeObserverManager {\n #callbacks = new WeakMap<Element, Set<(entry: ResizeObserverEntry) => unknown>>();\n\n #handleResize = (entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const callbacks = this.#callbacks.get(entry.target);\n\n if (callbacks) {\n for (const callback of callbacks) {\n callback(entry);\n }\n }\n }\n };\n #observer = new ResizeObserver(this.#handleResize);\n\n constructor() {\n ignoreROError();\n\n registerDestructor(this, () => {\n this.#observer?.disconnect();\n });\n }\n\n /**\n * Initiate the observing of the `element` or add an additional `callback`\n * if the `element` is already observed.\n *\n * @param {object} element\n * @param {function} callback The `callback` is called whenever the size of\n * the `element` changes. It is called with `ResizeObserverEntry` object\n * for the particular `element`.\n */\n observe(element: Element, callback: (entry: ResizeObserverEntry) => unknown) {\n const callbacks = this.#callbacks.get(element);\n\n if (callbacks) {\n callbacks.add(callback);\n } else {\n this.#callbacks.set(element, new Set([callback]));\n this.#observer.observe(element);\n }\n }\n\n /**\n * End the observing of the `element` or just remove the provided `callback`.\n *\n * It will unobserve the `element` if the `callback` is not provided\n * or there are no more callbacks left for this `element`.\n *\n * @param {object} element\n * @param {function?} callback - The `callback` to remove from the listeners\n * of the `element` size changes.\n */\n unobserve(element: Element, callback: (entry: ResizeObserverEntry) => unknown) {\n const callbacks = this.#callbacks.get(element);\n\n if (!callbacks) {\n return;\n }\n\n callbacks.delete(callback);\n\n if (!callback || !callbacks.size) {\n this.#callbacks.delete(element);\n this.#observer.unobserve(element);\n }\n }\n}\n\nconst errorMessages = [\n 'ResizeObserver loop limit exceeded',\n 'ResizeObserver loop completed with undelivered notifications.',\n];\n\n/**\n * Ignores \"ResizeObserver loop limit exceeded\" error in Ember tests.\n *\n * This \"error\" is safe to ignore as it is just a warning message,\n * telling that the \"looping\" observation will be skipped in the current frame,\n * and will be delivered in the next one.\n *\n * For some reason, it is fired as an `error` event at `window` failing Ember\n * tests and exploding Sentry with errors that must be ignored.\n */\nexport function ignoreROError() {\n if (typeof window.onerror !== 'function') {\n return;\n }\n\n const onError = window.onerror;\n\n window.onerror = (...args) => {\n const [message] = args;\n\n if (typeof message === 'string') {\n if (errorMessages.includes(message)) return true;\n }\n\n onError(...args);\n };\n}\n"],"names":["resizeObserver","context","owner","findOwner","assert","createStore","ResizeObserverManager","WeakMap","entries","entry","callbacks","get","target","callback","ResizeObserver","constructor","ignoreROError","registerDestructor","disconnect","observe","element","add","set","Set","unobserve","delete","size","errorMessages","window","onerror","onError","args","message","includes"],"mappings":";;;;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,cAAcA,CAACC,OAAe,EAAE;AAC9C,EAAA,MAAMC,KAAK,GAAGC,SAAS,CAACF,OAAO,CAAC;AAEhCG,EAAAA,MAAM,CACJ,CAAA,4MAAA,CAA8M,EAC9MF,KACF,CAAC;AAED,EAAA,OAAOG,WAAW,CAACH,KAAK,EAAEI,qBAAqB,CAAC;AAClD;AAEA,MAAMA,qBAAqB,CAAC;AAC1B,EAAA,UAAU,GAAG,IAAIC,OAAO,EAAyD;EAEjF,aAAa,GAAIC,OAA8B,IAAK;AAClD,IAAA,KAAK,MAAMC,KAAK,IAAID,OAAO,EAAE;AAC3B,MAAA,MAAME,SAAS,GAAG,IAAI,CAAC,UAAU,CAACC,GAAG,CAACF,KAAK,CAACG,MAAM,CAAC;AAEnD,MAAA,IAAIF,SAAS,EAAE;AACb,QAAA,KAAK,MAAMG,QAAQ,IAAIH,SAAS,EAAE;UAChCG,QAAQ,CAACJ,KAAK,CAAC;AACjB,QAAA;AACF,MAAA;AACF,IAAA;EACF,CAAC;EACD,SAAS,GAAG,IAAIK,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC;AAElDC,EAAAA,WAAWA,GAAG;AACZC,IAAAA,aAAa,EAAE;IAEfC,kBAAkB,CAAC,IAAI,EAAE,MAAM;AAC7B,MAAA,IAAI,CAAC,SAAS,EAAEC,UAAU,EAAE;AAC9B,IAAA,CAAC,CAAC;AACJ,EAAA;;AAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACEC,EAAAA,OAAOA,CAACC,OAAgB,EAAEP,QAAiD,EAAE;IAC3E,MAAMH,SAAS,GAAG,IAAI,CAAC,UAAU,CAACC,GAAG,CAACS,OAAO,CAAC;AAE9C,IAAA,IAAIV,SAAS,EAAE;AACbA,MAAAA,SAAS,CAACW,GAAG,CAACR,QAAQ,CAAC;AACzB,IAAA,CAAC,MAAM;AACL,MAAA,IAAI,CAAC,UAAU,CAACS,GAAG,CAACF,OAAO,EAAE,IAAIG,GAAG,CAAC,CAACV,QAAQ,CAAC,CAAC,CAAC;AACjD,MAAA,IAAI,CAAC,SAAS,CAACM,OAAO,CAACC,OAAO,CAAC;AACjC,IAAA;AACF,EAAA;;AAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACEI,EAAAA,SAASA,CAACJ,OAAgB,EAAEP,QAAiD,EAAE;IAC7E,MAAMH,SAAS,GAAG,IAAI,CAAC,UAAU,CAACC,GAAG,CAACS,OAAO,CAAC;IAE9C,IAAI,CAACV,SAAS,EAAE;AACd,MAAA;AACF,IAAA;AAEAA,IAAAA,SAAS,CAACe,MAAM,CAACZ,QAAQ,CAAC;AAE1B,IAAA,IAAI,CAACA,QAAQ,IAAI,CAACH,SAAS,CAACgB,IAAI,EAAE;AAChC,MAAA,IAAI,CAAC,UAAU,CAACD,MAAM,CAACL,OAAO,CAAC;AAC/B,MAAA,IAAI,CAAC,SAAS,CAACI,SAAS,CAACJ,OAAO,CAAC;AACnC,IAAA;AACF,EAAA;AACF;AAEA,MAAMO,aAAa,GAAG,CACpB,oCAAoC,EACpC,+DAA+D,CAChE;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASX,aAAaA,GAAG;AAC9B,EAAA,IAAI,OAAOY,MAAM,CAACC,OAAO,KAAK,UAAU,EAAE;AACxC,IAAA;AACF,EAAA;AAEA,EAAA,MAAMC,OAAO,GAAGF,MAAM,CAACC,OAAO;AAE9BD,EAAAA,MAAM,CAACC,OAAO,GAAG,CAAC,GAAGE,IAAI,KAAK;AAC5B,IAAA,MAAM,CAACC,OAAO,CAAC,GAAGD,IAAI;AAEtB,IAAA,IAAI,OAAOC,OAAO,KAAK,QAAQ,EAAE;MAC/B,IAAIL,aAAa,CAACM,QAAQ,CAACD,OAAO,CAAC,EAAE,OAAO,IAAI;AAClD,IAAA;IAEAF,OAAO,CAAC,GAAGC,IAAI,CAAC;EAClB,CAAC;AACH;;;;"}
|
package/dist/service.js
CHANGED
package/dist/service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"service.js","sources":["../src/service.ts"],"sourcesContent":["import { assert } from '@ember/debug';\n\nimport { getPromiseState } from 'reactiveweb/get-promise-state';\n\nimport { createStore } from './store.ts';\nimport { findOwner } from './utils.ts';\n\nimport type { Newable } from './type-utils.ts';\n\n/*\nimport type { Newable } from './type-utils.ts';\nimport type { Registry } from '@ember/service';\nimport type Service from '@ember/service';\n\ntype Decorator = ReturnType<typeof emberService>;\n\n// export function service<Key extends keyof Registry>(\n// context: object,\n// serviceName: Key\n// ): Registry[Key] & Service;\nexport function service<Class extends object>(\n context: object,\n serviceDefinition: Newable<Class>\n): Class;\nexport function service<Class extends object>(serviceDefinition: Newable<Class>): Decorator;\nexport function service<Key extends keyof Registry>(serviceName: Key): Decorator;\nexport function service(prototype: object, name: string | symbol, descriptor: unknown): void;\nexport function service<Value, Result>(\n context: object,\n fn: Parameters<typeof getPromiseState<Value, Result>>[0]\n): ReturnType<typeof getPromiseState<Value, Result>>;\nexport function service<Value, Result>(\n fn: Parameters<typeof getPromiseState<Value, Result>>[0]\n): Decorator;\n*/\n\n/**\n * Instantiates a class once per application instance.\n *\n *\n */\nexport function createService<Instance extends object>(\n context: object,\n theClass: Newable<Instance> | (() => Instance)\n): Instance {\n const owner = findOwner(context);\n\n assert(\n `Could not find owner / application instance. Cannot create a instance tied to the application lifetime without the application`,\n owner\n );\n\n return createStore(owner, theClass);\n}\n\nconst promiseCache = new WeakMap<() => any, unknown>();\n\n/**\n * Lazily instantiate a service.\n *\n * This is a replacement / alternative API for ember's `@service` decorator from `@ember/service`.\n *\n * For example\n * ```js\n * import { service } from 'ember-primitives/service';\n *\n * const loader = () => {\n * let module = await import('./foo/file/with/class.js');\n * return () => new module.MyState();\n * }\n *\n * class Demo extends Component {\n * state = createAsyncService(this, loader);\n * }\n * ```\n *\n * The important thing is for repeat usage of `createAsyncService` the second parameter,\n * (loader in this case), must be shared between all usages.\n *\n * This is an alternative to using `createStore` inside an await'd component,\n * or a component rendered with [`getPromiseState`](https://reactive.nullvoxpopuli.com/functions/get-promise-state.getPromiseState.html)\n * ```\n */\nexport function createAsyncService<Instance extends object>(\n context: object,\n theClass: () => Promise<Newable<Instance> | (() => Instance)>\n): ReturnType<typeof getPromiseState<unknown, Instance>> {\n let existing = promiseCache.get(theClass);\n\n if (!existing) {\n existing = async () => {\n const result = await theClass();\n\n // Pay no attention to the lies, I don't know what the right type is here\n return createStore(context, result as Newable<Instance>);\n };\n\n promiseCache.set(theClass, existing);\n }\n\n // Pay no attention to the TS inference crime here\n return getPromiseState<unknown, Instance>(existing);\n}\n"],"names":["createService","context","theClass","owner","findOwner","assert","createStore","promiseCache","WeakMap","createAsyncService","existing","get","result","set","getPromiseState"],"mappings":";;;;;AASA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACO,SAASA,aAAaA,CAC3BC,OAAe,EACfC,QAA8C,EACpC;AACV,EAAA,MAAMC,KAAK,GAAGC,SAAS,CAACH,OAAO,CAAC;AAEhCI,EAAAA,MAAM,CACJ,CAAA,8HAAA,CAAgI,EAChIF,KACF,CAAC;AAED,EAAA,OAAOG,WAAW,CAACH,KAAK,EAAED,QAAQ,CAAC;AACrC;AAEA,MAAMK,YAAY,GAAG,IAAIC,OAAO,EAAsB;;AAEtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,kBAAkBA,CAChCR,OAAe,EACfC,QAA6D,EACN;AACvD,EAAA,IAAIQ,QAAQ,GAAGH,YAAY,CAACI,GAAG,CAACT,QAAQ,CAAC;EAEzC,IAAI,CAACQ,QAAQ,EAAE;IACbA,QAAQ,GAAG,YAAY;AACrB,MAAA,MAAME,MAAM,GAAG,MAAMV,QAAQ,EAAE;;AAE/B;AACA,MAAA,OAAOI,WAAW,CAACL,OAAO,EAAEW,MAA2B,CAAC;IAC1D,CAAC;AAEDL,IAAAA,YAAY,CAACM,GAAG,CAACX,QAAQ,EAAEQ,QAAQ,CAAC;AACtC,EAAA;;AAEA;EACA,OAAOI,eAAe,CAAoBJ,QAAQ,CAAC;AACrD;;;;"}
|
package/dist/store.js
CHANGED
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"store.js","sources":["../src/store.ts"],"sourcesContent":["import { link } from 'reactiveweb/link';\n\nimport { isNewable } from './utils.ts';\n\nimport type { Newable } from './type-utils.ts';\n\n/**\n * context => { class => instance }\n */\nconst contextCache = new WeakMap<object, Map<object, object>>();\n\n/**\n * Creates a singleton for the given context and links the lifetime of the created class to the passed context\n *\n * Note that this function is _not_ lazy. Calling `createStore` will create an instance of the passed class.\n * When combined with a getter though, creation becomes lazy.\n *\n * In this example, `MyState` is created once per instance of the component.\n * repeat accesses to `this.foo` return a stable reference _as if_ `@cached` were used.\n * ```js\n * class MyState {}\n *\n * class Demo extends Component {\n * // this is a stable reference\n * get foo() {\n * return createStore(this, MyState);\n * }\n *\n * // or\n * bar = createStore(this, MyState);\n *\n * // or\n * three = createStore(this, () => new MyState(1, 2));\n * }\n * ```\n *\n * If arguments need to be configured during construction, the second argument may also be a function\n * ```js\n * class MyState {}\n *\n * class Demo extends Component {\n * // this is a stable reference\n * get foo() {\n * return createStore(this, MyState);\n * }\n * }\n * ```\n */\nexport function createStore<Instance extends object>(\n context: object,\n theClass: Newable<Instance> | (() => Instance)\n): Instance {\n let cache = contextCache.get(context);\n\n if (!cache) {\n cache = new Map();\n contextCache.set(context, cache);\n }\n\n let existing = cache.get(theClass);\n\n if (!existing) {\n const instance = isNewable(theClass) ? new theClass() : theClass();\n\n link(instance, context);\n\n cache.set(theClass, instance);\n existing = instance;\n }\n\n return existing as Instance;\n}\n"],"names":["contextCache","WeakMap","createStore","context","theClass","cache","get","Map","set","existing","instance","isNewable","link"],"mappings":";;;AAMA;AACA;AACA;AACA,MAAMA,YAAY,GAAG,IAAIC,OAAO,EAA+B;;AAE/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,WAAWA,CACzBC,OAAe,EACfC,QAA8C,EACpC;AACV,EAAA,IAAIC,KAAK,GAAGL,YAAY,CAACM,GAAG,CAACH,OAAO,CAAC;EAErC,IAAI,CAACE,KAAK,EAAE;AACVA,IAAAA,KAAK,GAAG,IAAIE,GAAG,EAAE;AACjBP,IAAAA,YAAY,CAACQ,GAAG,CAACL,OAAO,EAAEE,KAAK,CAAC;AAClC,EAAA;AAEA,EAAA,IAAII,QAAQ,GAAGJ,KAAK,CAACC,GAAG,CAACF,QAAQ,CAAC;EAElC,IAAI,CAACK,QAAQ,EAAE;AACb,IAAA,MAAMC,QAAQ,GAAGC,SAAS,CAACP,QAAQ,CAAC,GAAG,IAAIA,QAAQ,EAAE,GAAGA,QAAQ,EAAE;AAElEQ,IAAAA,IAAI,CAACF,QAAQ,EAAEP,OAAO,CAAC;AAEvBE,IAAAA,KAAK,CAACG,GAAG,CAACJ,QAAQ,EAAEM,QAAQ,CAAC;AAC7BD,IAAAA,QAAQ,GAAGC,QAAQ;AACrB,EAAA;AAEA,EAAA,OAAOD,QAAQ;AACjB;;;;"}
|
package/dist/styles.css.js
CHANGED
package/dist/tabster.js
CHANGED
package/dist/tabster.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabster.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"tabster.js","sources":["../src/tabster.ts"],"sourcesContent":["import { registerDestructor } from '@ember/destroyable';\n\nexport async function setupTabster(\n /**\n * A destroyable object.\n * This is needed so that when the app (or tests) or unmounted or ending,\n * the tabster instance can be disposed of.\n */\n context: object,\n {\n tabster,\n setTabsterRoot,\n }: {\n /**\n * Let this setup function initalize tabster.\n * https://tabster.io/docs/core\n *\n * This should be done only once per application as we don't want\n * focus managers fighting with each other.\n *\n * Defaults to `true`,\n *\n * Will fallback to an existing tabster instance automatically if `getTabster` returns a value.\n *\n * If `false` is explicitly passed here, you'll also be in charge of teardown.\n */\n tabster?: boolean;\n setTabsterRoot?: boolean;\n } = {}\n) {\n const { createTabster, getDeloser, getMover, getTabster, disposeTabster } =\n await import('tabster');\n\n tabster ??= true;\n setTabsterRoot ??= true;\n\n if (!tabster) {\n return;\n }\n\n const existing = getTabster(window);\n const primitivesTabster = existing ?? createTabster(window);\n\n getMover(primitivesTabster);\n getDeloser(primitivesTabster);\n\n if (setTabsterRoot) {\n document.body.setAttribute('data-tabster', '{ \"root\": {} }');\n }\n\n registerDestructor(context, () => {\n disposeTabster(primitivesTabster);\n });\n}\n"],"names":["setupTabster","context","tabster","setTabsterRoot","createTabster","getDeloser","getMover","getTabster","disposeTabster","existing","window","primitivesTabster","document","body","setAttribute","registerDestructor"],"mappings":";;AAEO,eAAeA,YAAYA;AAChC;AACF;AACA;AACA;AACA;AACEC,OAAe,EACf;EACEC,OAAO;AACPC,EAAAA;AAiBF,CAAC,GAAG,EAAE,EACN;EACA,MAAM;IAAEC,aAAa;IAAEC,UAAU;IAAEC,QAAQ;IAAEC,UAAU;AAAEC,IAAAA;AAAe,GAAC,GACvE,MAAM,OAAO,SAAS,CAAC;AAEzBN,EAAAA,OAAO,KAAK,IAAI;AAChBC,EAAAA,cAAc,KAAK,IAAI;EAEvB,IAAI,CAACD,OAAO,EAAE;AACZ,IAAA;AACF,EAAA;AAEA,EAAA,MAAMO,QAAQ,GAAGF,UAAU,CAACG,MAAM,CAAC;AACnC,EAAA,MAAMC,iBAAiB,GAAGF,QAAQ,IAAIL,aAAa,CAACM,MAAM,CAAC;EAE3DJ,QAAQ,CAACK,iBAAiB,CAAC;EAC3BN,UAAU,CAACM,iBAAiB,CAAC;AAE7B,EAAA,IAAIR,cAAc,EAAE;IAClBS,QAAQ,CAACC,IAAI,CAACC,YAAY,CAAC,cAAc,EAAE,gBAAgB,CAAC;AAC9D,EAAA;EAEAC,kBAAkB,CAACd,OAAO,EAAE,MAAM;IAChCO,cAAc,CAACG,iBAAiB,CAAC;AACnC,EAAA,CAAC,CAAC;AACJ;;;;"}
|
package/dist/test-support.js
CHANGED
package/dist/test-support.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-support.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"test-support.js","sources":["../src/test-support/a11y.ts","../src/test-support/dom.ts","../src/test-support/otp.ts","../src/test-support/rating.ts","../src/test-support/routing.ts","../src/test-support/zoetrope.ts"],"sourcesContent":["import { assert } from '@ember/debug';\n\nimport { setupTabster as _setupTabster } from '../tabster.ts';\n\nimport type Owner from '@ember/owner';\n\n/**\n * Sets up all support utilities for primitive components.\n * Including the tabster root.\n */\nasync function setup(owner: Owner) {\n await _setupTabster(owner, { setTabsterRoot: false });\n\n document.querySelector('#ember-testing')?.setAttribute('data-tabster', '{ \"root\": {} }');\n}\n\n/**\n * A QUnit test utility for setting up the tabbing utility that a few of the components in ember-primitive use for providing enhanced keyboard support.\n *\n * ```gjs\n * import { module, test } from 'qunit';\n * import { setupRenderingTest } from 'ember-qunit';\n * import { setupTabster } from 'ember-primitives/test-support';\n *\n * module('your suite', function (hooks) {\n * setupRenderingTest(hooks);\n * setupTabster(hooks);\n *\n * test('your test', async function (assert) {\n * // ...\n * });\n * });\n * ```\n *\n * This utility takes no options.\n */\nexport function setupTabster(hooks: {\n beforeEach: (callback: () => void | Promise<void>) => unknown;\n}) {\n hooks.beforeEach(async function (this: { owner: object }) {\n const owner = this.owner;\n\n assert(\n `Test does not have an owner, be sure to use setupRenderingTest, setupTest, or setupApplicationTest (from ember-qunit (or similar))`,\n owner\n );\n\n await setup(this.owner as Owner);\n });\n}\n","import { assert } from '@ember/debug';\nimport { find } from '@ember/test-helpers';\n\ntype Findable = Parameters<typeof find>[0] | Element;\n\n/**\n * Find an element within a given element that has a shadow-root.\n *\n * If the `root` can't be found, or if there actually is no shadow root,\n * nothing will be returned.\n *\n * ```gjs\n * import { findInShadow } from 'ember-primitives/test-support';\n *\n * // ...\n *\n * test('...', async function (assert) {\n * // ...\n * const root = find('div.with-shadowdom');\n * assert.dom(findInShadow(root, 'h1')).containsText('welcome');\n * });\n * ```\n */\nexport function findInShadow(root: Findable, query: string) {\n const rootElement = root instanceof Element ? root : find(root);\n\n return rootElement?.shadowRoot?.querySelector(query);\n}\n\n/**\n * Does the element have a shadow root?\n *\n * Using this utility function will only save a few characters over using its implementation directly.\n *\n * ```gjs\n * import { hasShadowRoot } from 'ember-primitives/test-support';\n *\n * // ...\n *\n * test('...', async function (assert) {\n * // ...\n * const el = find('div.with-shadowdom');\n * assert.ok(hasShadowRoot(el), 'expecting el to have a shadow root');\n * });\n * ```\n */\nexport function hasShadowRoot(el: Element) {\n return Boolean(el.shadowRoot);\n}\n\n/**\n * Find an element within `root`, that has a shadow root.\n * The `root` param is optional, and if not provided, all of `#ember-testing` will be searched.\n *\n * This only returns the first-found shadow, so if you want a specifc shadow root,\n * you'll need to narrow down the search by specifying a `root`.\n *\n * ```gjs\n * import { findShadow } from 'ember-primitives/test-support';\n *\n * // ...\n *\n * test('...', async function (assert) {\n * // ...\n * const el = findShadow('div.with-shadowdom');\n * // ...\n * });\n * ```\n */\nexport function findShadow(root?: Findable) {\n const rootElement = root\n ? root instanceof Element\n ? root\n : find(root)\n : document.getElementById('ember-testing');\n\n if (!rootElement) return;\n\n for (const element of rootElement.querySelectorAll('*')) {\n if (element.shadowRoot) {\n return element;\n }\n }\n}\n\n/**\n * For the first available shadow root on the page, query in to it, like you would with `querySelector`.\n *\n *\n * ```gjs\n * import { findInFirstShadow } from 'ember-primitives/test-support';\n *\n * // ...\n *\n * test('...', async function (assert) {\n * // ...\n * assert.dom(findInFirstShadow('h1')).containsText('welcome');\n * });\n * ```\n *\n * If there are multiple shadow roots on the page / test-render,\n * this is not the utility for you.\n *\n * For querying in specific shadow roots, you'll want to use `findInShadow`\n */\nexport function findInFirstShadow(query: string) {\n const host = findShadow();\n\n assert(`No element with a shadow root could be found`, host);\n\n return findInShadow(host, query);\n}\n","import { assert } from '@ember/debug';\nimport { fillIn, find, settled } from '@ember/test-helpers';\n\n/**\n * Fill the OTP input\n *\n * ```gjs\n * import { fillOTP } from 'ember-primitives/test-support';\n *\n * test('...', async function(assert) {\n * // ...\n * await fillOTP('123456');\n * // ...\n * })\n *\n * ```\n *\n * @param {string} code the code to fill the input(s) with.\n * @param {string} [ selector ] if there are multiple OTP components on a page, this can be used to select one of them.\n */\nexport async function fillOTP(code: string, selector?: string) {\n const ancestor = selector ? find(selector) : document;\n\n assert(\n `Could not find ancestor element, does your selector match an existing element?`,\n ancestor\n );\n\n const fieldset =\n ancestor instanceof HTMLFieldSetElement ? ancestor : ancestor.querySelector('fieldset');\n\n assert(\n `Could not find containing fieldset element (this holds the OTP Input fields). Was the OTP component rendered?`,\n fieldset\n );\n\n const inputs = fieldset.querySelectorAll('input');\n\n assert(\n `code cannot be longer than the available inputs. code is of length ${code.length} but there are ${inputs.length}`,\n code.length <= inputs.length\n );\n\n const chars = code.split('');\n\n assert(`OTP Input for index 0 is missing!`, inputs[0]);\n assert(`Character at index 0 is missing`, chars[0]);\n\n for (let i = 0; i < chars.length; i++) {\n const input = inputs[i];\n const char = chars[i];\n\n assert(`Input at index ${i} is missing`, input);\n assert(`Character at index ${i} is missing`, char);\n\n input.value = char;\n }\n\n await fillIn(inputs[0], chars[0]);\n\n // Account for out-of-settled-system delay due to RAF debounce.\n await new Promise((resolve) => requestAnimationFrame(resolve));\n await settled();\n}\n","import { assert } from '@ember/debug';\nimport { click, fillIn, find, findAll } from '@ember/test-helpers';\n\nconst selectors = {\n root: '.ember-primitives__rating',\n item: '.ember-primitives__rating__item',\n label: '.ember-primitives__rating__label',\n\n rootData: {\n total: '[data-total]',\n value: '[data-value]',\n },\n\n itemData: {\n number: '[data-number]',\n readonly: '[data-readonly]',\n selected: '[data-selected]',\n itemPercent: '[data-percent-selected]',\n },\n};\n\nconst stars = {\n selected: '★',\n unselected: '☆',\n};\n\n/**\n * Test utility for interacting with the\n * Rating component.\n *\n * Simulates user behavior and provides high level functions so you don't need to worry about the DOM.\n *\n * Actual elements are not exposed, as the elements are private API.\n * Even as you build a design system, the DOM should not be exposed to your consumers.\n */\nexport function rating(selector?: string) {\n const root = `${selector ?? ''}${selectors.root}`;\n\n return new RatingPageObject(root);\n}\n\nclass RatingPageObject {\n #root: string;\n\n constructor(root: string) {\n this.#root = root;\n }\n\n get #rootElement() {\n const element = find(this.#root);\n\n assert(\n `Could not find the root element for the <Rating> component. Used the selector \\`${this.#root}\\`. Was it rendered?`,\n element\n );\n\n return element;\n }\n\n get #labelElement() {\n const element = find(`${this.#root} ${selectors.label}`);\n\n assert(`Could not find the label for the <Rating> component. Was it rendered?`, element);\n\n return element;\n }\n\n get label() {\n return this.#labelElement.textContent?.replaceAll(/\\s+/g, ' ').trim();\n }\n\n get #starElements() {\n const elements = findAll(`${this.#root} ${selectors.item}`);\n\n assert(\n `There are no stars/items. Is the <Rating> component misconfigured?`,\n elements.length > 0\n );\n\n return elements as HTMLElement[];\n }\n\n get stars() {\n const elements = this.#starElements;\n\n return elements\n .map((x) => (x.hasAttribute('data-selected') ? stars.selected : stars.unselected))\n .join(' ');\n }\n\n get starTexts() {\n const elements = this.#starElements;\n\n return elements.map((x) => x.querySelector('[aria-hidden]')?.textContent?.trim()).join(' ');\n }\n\n get value() {\n const value = this.#rootElement.getAttribute(`data-value`);\n\n assert(`data-value attribute is missing on element '${this.#root}'`, value);\n\n const number = parseFloat(value);\n\n return number;\n }\n\n get isReadonly() {\n return this.#starElements.every((x) => x.hasAttribute('data-readonly'));\n }\n\n async select(stars: number) {\n const root = this.#rootElement;\n\n const star = root.querySelector(`[data-number=\"${stars}\"] input`);\n\n if (star) {\n await click(star);\n\n return;\n }\n\n /**\n * When we don't have an input, we require an input --\n * which is also the only way we can choose non-integer values.\n *\n * Should be able to be a number input or range input.\n */\n const input = root.querySelector('input[type=\"number\"], input[type=\"range\"]');\n\n if (input) {\n await fillIn(input, `${stars}`);\n\n return;\n }\n\n const available = [...root.querySelectorAll('[data-number]')].map((x) =>\n x.getAttribute('data-number')\n );\n\n assert(\n `Could not find item/star in <Rating> with value '${stars}' (or a number or range input with the same \"name\" value). Is the number (${stars}) correct and in-range for this component? The found available values are ${available.join(', ')}.`\n );\n }\n}\n","import { assert } from '@ember/debug';\nimport Router from '@ember/routing/router';\n\nimport { properLinks } from '../proper-links.ts';\n\nimport type Owner from '@ember/owner';\nimport type { DSLCallback } from '@ember/routing/lib/dsl';\nimport type RouterService from '@ember/routing/router-service';\n\n/**\n * Allows setting up routes in tests without the need to scaffold routes in the actual app,\n * allowing for iterating on many different routing scenario / configurations rapidly.\n *\n * Example:\n * ```js\n * import { setupRouting } from 'ember-primitives/test-support';\n *\n * ...\n *\n * test('my test', async function (assert) {\n * setupRouting(this.owner, function () {\n * this.route('foo');\n * this.route('bar', function () {\n * this.route('a');\n * this.route('b');\n * })\n * });\n *\n * await visit('/bar/b');\n * });\n * ```\n *\n */\nexport function setupRouting(owner: Owner, map: DSLCallback, options?: { rootURL: string }) {\n if (options?.rootURL) {\n assert('rootURL must begin with a forward slash (\"/\")', options?.rootURL?.startsWith('/'));\n }\n\n @properLinks\n class TestRouter extends Router {\n rootURL = options?.rootURL ?? '/';\n }\n\n TestRouter.map(map);\n\n owner.register('router:main', TestRouter);\n\n // eslint-disable-next-line ember/no-private-routing-service\n const iKnowWhatIMDoing = owner.lookup('router:main');\n\n // We need a public testing API for this sort of stuff\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n (iKnowWhatIMDoing as any).setupRouter();\n}\n\n/**\n * A small utility that only gives you a _typed_ router service.\n */\nexport function getRouter(owner: Owner): RouterService {\n return owner.lookup('service:router');\n}\n","/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { click } from '@ember/test-helpers';\n\nexport class ZoetropeHelper {\n parentSelector = '.ember-primitives__zoetrope';\n\n constructor(parentSelector?: string) {\n if (parentSelector) {\n this.parentSelector = parentSelector;\n }\n }\n\n async scrollLeft() {\n await click(`${this.parentSelector} .ember-primitives__zoetrope__controls button:first-child`);\n }\n\n async scrollRight() {\n await click(`${this.parentSelector} .ember-primitives__zoetrope__controls button:last-child`);\n }\n\n visibleItems() {\n const zoetropeContent = document.querySelectorAll(\n `${this.parentSelector} .ember-primitives__zoetrope__scroller > *`\n );\n\n let firstVisibleItemIndex = -1;\n let lastVisibleItemIndex = -1;\n\n for (let i = 0; i < zoetropeContent.length; i++) {\n const item = zoetropeContent[i]!;\n const rect = item.getBoundingClientRect();\n const parentRect = item.parentElement!.getBoundingClientRect();\n\n if (rect.right >= parentRect?.left && rect.left <= parentRect?.right) {\n if (firstVisibleItemIndex === -1) {\n firstVisibleItemIndex = i;\n }\n\n lastVisibleItemIndex = i;\n } else if (firstVisibleItemIndex !== -1) {\n break;\n }\n }\n\n return Array.from(zoetropeContent).slice(firstVisibleItemIndex, lastVisibleItemIndex + 1);\n }\n\n visibleItemCount() {\n return this.visibleItems().length;\n }\n}\n"],"names":["setup","owner","_setupTabster","setTabsterRoot","document","querySelector","setAttribute","setupTabster","hooks","beforeEach","assert","findInShadow","root","query","rootElement","Element","find","shadowRoot","hasShadowRoot","el","Boolean","findShadow","getElementById","element","querySelectorAll","findInFirstShadow","host","fillOTP","code","selector","ancestor","fieldset","HTMLFieldSetElement","inputs","length","chars","split","i","input","char","value","fillIn","Promise","resolve","requestAnimationFrame","settled","selectors","item","label","stars","selected","unselected","rating","RatingPageObject","constructor","#rootElement","#labelElement","textContent","replaceAll","trim","#starElements","elements","findAll","map","x","hasAttribute","join","starTexts","getAttribute","number","parseFloat","isReadonly","every","select","star","click","available","setupRouting","options","rootURL","startsWith","TestRouter","c","Router","properLinks","register","iKnowWhatIMDoing","lookup","setupRouter","getRouter","ZoetropeHelper","parentSelector","scrollLeft","scrollRight","visibleItems","zoetropeContent","firstVisibleItemIndex","lastVisibleItemIndex","rect","getBoundingClientRect","parentRect","parentElement","right","left","Array","from","slice","visibleItemCount"],"mappings":"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"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
3
2
|
* If the user provides an onChange or similar function, use that,
|
|
4
3
|
* otherwise fallback to the uncontrolled toggle
|
|
@@ -11,4 +10,4 @@ function toggleWithFallback(uncontrolledToggle, controlledToggle, ...args) {
|
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
export { toggleWithFallback as t };
|
|
14
|
-
//# sourceMappingURL=utils-
|
|
13
|
+
//# sourceMappingURL=utils-D0v9WKmV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-D0v9WKmV.js","sources":["../src/components/-private/utils.ts"],"sourcesContent":["/**\n * If the user provides an onChange or similar function, use that,\n * otherwise fallback to the uncontrolled toggle\n */\nexport function toggleWithFallback(\n uncontrolledToggle: (...args: unknown[]) => void,\n\n controlledToggle?: (...args: any[]) => void,\n ...args: unknown[]\n) {\n if (controlledToggle) {\n return controlledToggle(...args);\n }\n\n uncontrolledToggle(...args);\n}\n"],"names":["toggleWithFallback","uncontrolledToggle","controlledToggle","args"],"mappings":"AAAA;AACA;AACA;AACA;AACO,SAASA,kBAAkBA,CAChCC,kBAAgD,EAEhDC,gBAA2C,EAC3C,GAAGC,IAAe,EAClB;AACA,EAAA,IAAID,gBAAgB,EAAE;AACpB,IAAA,OAAOA,gBAAgB,CAAC,GAAGC,IAAI,CAAC;AAClC,EAAA;EAEAF,kBAAkB,CAAC,GAAGE,IAAI,CAAC;AAC7B;;;;"}
|
package/dist/utils.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import { getOwner } from '@ember/owner';
|
|
3
2
|
|
|
4
3
|
// this is copy pasted from https://github.com/emberjs/ember.js/blob/60d2e0cddb353aea0d6e36a72fda971010d92355/packages/%40ember/-internals/glimmer/lib/helpers/unique-id.ts
|
|
@@ -55,6 +54,10 @@ function findOwner(contextOrOwner) {
|
|
|
55
54
|
if (!isNonNullableObject(contextOrOwner)) return;
|
|
56
55
|
const maybeOwner = getOwner(contextOrOwner);
|
|
57
56
|
if (isOwner(maybeOwner)) return maybeOwner;
|
|
57
|
+
if ('owner' in contextOrOwner) {
|
|
58
|
+
const maybeOwner = contextOrOwner.owner;
|
|
59
|
+
if (isOwner(maybeOwner)) return maybeOwner;
|
|
60
|
+
}
|
|
58
61
|
return;
|
|
59
62
|
}
|
|
60
63
|
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import { getOwner } from '@ember/owner';\n\nimport type Owner from '@ember/owner';\n\n// this is copy pasted from https://github.com/emberjs/ember.js/blob/60d2e0cddb353aea0d6e36a72fda971010d92355/packages/%40ember/-internals/glimmer/lib/helpers/unique-id.ts\n// Unfortunately due to https://github.com/emberjs/ember.js/issues/20165 we cannot use the built-in version in template tags\nexport function uniqueId(): string {\n // @ts-expect-error this one-liner abuses weird JavaScript semantics that\n // TypeScript (legitimately) doesn't like, but they're nonetheless valid and\n // specced.\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/restrict-plus-operands, @typescript-eslint/no-unsafe-member-access\n return ([3e7] + -1e3 + -4e3 + -2e3 + -1e11).replace(/[0-3]/g, (a) =>\n ((a * 4) ^ ((Math.random() * 16) >> (a & 2))).toString(16)\n );\n}\n\nexport function isNewable(x: any): x is new (...args: unknown[]) => NonNullable<object> {\n // TypeScript has really bad prototype support -- they don't really\n // want folks using this sort of stuff -- but it's handy for perf and all that.\n //\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return x.prototype?.constructor === x;\n}\n\n/**\n * Loose check for an \"ownerish\" API.\n * only the \".lookup\" method is required.\n *\n * The requirements for what an \"owner\" is are sort of undefined,\n * as the actual owner in ember applications has too much on it,\n * and the long term purpose of the owner will be questioned once we\n * eliminate the need to have a registry (what lookup looks in to),\n * but we'll still need \"Something\" to represent the lifetime of the application.\n *\n * Technically, the owner could be any object, including `{}`\n */\nexport function isOwner(x: unknown): x is Owner {\n if (!isNonNullableObject(x)) return false;\n\n return 'lookup' in x && typeof x.lookup === 'function';\n}\n\nexport function isNonNullableObject(x: unknown): x is NonNullable<object> {\n if (typeof x !== 'object') return false;\n if (x === null) return false;\n\n return true;\n}\n\n/**\n * Can receive the class instance or the owner itself, and will always return return the owner.\n *\n * undefined will be returned if the Owner does not exist on the passed object\n *\n * Can be useful when combined with `createStore` to then create \"services\",\n * which don't require string lookup.\n */\nexport function findOwner(contextOrOwner: unknown): Owner | undefined {\n if (isOwner(contextOrOwner)) return contextOrOwner;\n\n // _ENSURE_ that we have an object, else getOwner makes no sense to call\n if (!isNonNullableObject(contextOrOwner)) return;\n\n const maybeOwner = getOwner(contextOrOwner);\n\n if (isOwner(maybeOwner)) return maybeOwner;\n\n if ('owner' in contextOrOwner) {\n const maybeOwner = contextOrOwner.owner;\n\n if (isOwner(maybeOwner)) return maybeOwner;\n }\n\n return;\n}\n"],"names":["uniqueId","replace","a","Math","random","toString","isNewable","x","prototype","constructor","isOwner","isNonNullableObject","lookup","findOwner","contextOrOwner","maybeOwner","getOwner","owner"],"mappings":";;AAIA;AACA;AACO,SAASA,QAAQA,GAAW;AACjC;AACA;AACA;AACA;EACA,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAEC,OAAO,CAAC,QAAQ,EAAGC,CAAC,IAC9D,CAAEA,CAAC,GAAG,CAAC,GAAMC,IAAI,CAACC,MAAM,EAAE,GAAG,EAAE,KAAMF,CAAC,GAAG,CAAC,CAAE,EAAEG,QAAQ,CAAC,EAAE,CAC3D,CAAC;AACH;AAEO,SAASC,SAASA,CAACC,CAAM,EAAwD;AACtF;AACA;AACA;AACA;AACA,EAAA,OAAOA,CAAC,CAACC,SAAS,EAAEC,WAAW,KAAKF,CAAC;AACvC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,OAAOA,CAACH,CAAU,EAAc;AAC9C,EAAA,IAAI,CAACI,mBAAmB,CAACJ,CAAC,CAAC,EAAE,OAAO,KAAK;EAEzC,OAAO,QAAQ,IAAIA,CAAC,IAAI,OAAOA,CAAC,CAACK,MAAM,KAAK,UAAU;AACxD;AAEO,SAASD,mBAAmBA,CAACJ,CAAU,EAA4B;AACxE,EAAA,IAAI,OAAOA,CAAC,KAAK,QAAQ,EAAE,OAAO,KAAK;AACvC,EAAA,IAAIA,CAAC,KAAK,IAAI,EAAE,OAAO,KAAK;AAE5B,EAAA,OAAO,IAAI;AACb;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASM,SAASA,CAACC,cAAuB,EAAqB;AACpE,EAAA,IAAIJ,OAAO,CAACI,cAAc,CAAC,EAAE,OAAOA,cAAc;;AAElD;AACA,EAAA,IAAI,CAACH,mBAAmB,CAACG,cAAc,CAAC,EAAE;AAE1C,EAAA,MAAMC,UAAU,GAAGC,QAAQ,CAACF,cAAc,CAAC;AAE3C,EAAA,IAAIJ,OAAO,CAACK,UAAU,CAAC,EAAE,OAAOA,UAAU;EAE1C,IAAI,OAAO,IAAID,cAAc,EAAE;AAC7B,IAAA,MAAMC,UAAU,GAAGD,cAAc,CAACG,KAAK;AAEvC,IAAA,IAAIP,OAAO,CAACK,UAAU,CAAC,EAAE,OAAOA,UAAU;AAC5C,EAAA;AAEA,EAAA;AACF;;;;"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import Component from '@glimmer/component';
|
|
2
|
+
import { tracked } from '@glimmer/tracking';
|
|
3
|
+
import { assert } from '@ember/debug';
|
|
4
|
+
import { element } from 'ember-element-helper';
|
|
5
|
+
import { modifier } from 'ember-modifier';
|
|
6
|
+
import { viewport } from './viewport.js';
|
|
7
|
+
import { precompileTemplate } from '@ember/template-compilation';
|
|
8
|
+
import { setComponentTemplate } from '@ember/component';
|
|
9
|
+
import { g, i } from 'decorator-transforms/runtime';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A component that only renders its content when the element is near the viewport.
|
|
13
|
+
*
|
|
14
|
+
* This is useful for deferring the rendering of heavy components until they're
|
|
15
|
+
* actually needed, improving performance for pages with many components.
|
|
16
|
+
*
|
|
17
|
+
* Example usage:
|
|
18
|
+
* ```gjs
|
|
19
|
+
* import { InViewport } from 'ember-primitives';
|
|
20
|
+
*
|
|
21
|
+
* <template>
|
|
22
|
+
* <InViewport>
|
|
23
|
+
* <ExpensiveComponent />
|
|
24
|
+
* </InViewport>
|
|
25
|
+
* </template>
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* The component uses the Intersection Observer API to detect when the element
|
|
29
|
+
* is near the viewport. Once detected, the observer is destroyed and the content
|
|
30
|
+
* is rendered permanently.
|
|
31
|
+
*/
|
|
32
|
+
class InViewport extends Component {
|
|
33
|
+
static {
|
|
34
|
+
g(this.prototype, "hasIntersected", [tracked], function () {
|
|
35
|
+
return false;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
#hasIntersected = (i(this, "hasIntersected"), void 0);
|
|
39
|
+
/**
|
|
40
|
+
* Whether the element has been detected as in/near the viewport
|
|
41
|
+
*/
|
|
42
|
+
get #viewport() {
|
|
43
|
+
return viewport(this);
|
|
44
|
+
}
|
|
45
|
+
setupObserver = modifier(element => {
|
|
46
|
+
if (this.hasIntersected) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.#viewport.observe(element, this.handle);
|
|
50
|
+
return () => this.#viewport.unobserve(element, this.handle);
|
|
51
|
+
});
|
|
52
|
+
handle = entry => {
|
|
53
|
+
if (entry?.isIntersecting) {
|
|
54
|
+
this.hasIntersected = true;
|
|
55
|
+
this.#viewport.unobserve(entry.target, this.handle);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
get mode() {
|
|
59
|
+
assert('InViewport mode must be either "replace" or "contain"', !this.args.mode || this.args.mode === "replace" || this.args.mode === "contain");
|
|
60
|
+
return this.args.mode ?? "contain";
|
|
61
|
+
}
|
|
62
|
+
get tagName() {
|
|
63
|
+
return this.args.tagName ?? "div";
|
|
64
|
+
}
|
|
65
|
+
get hasReachedViewport() {
|
|
66
|
+
return this.hasIntersected;
|
|
67
|
+
}
|
|
68
|
+
get isReplacing() {
|
|
69
|
+
return this.mode === "replace";
|
|
70
|
+
}
|
|
71
|
+
static {
|
|
72
|
+
setComponentTemplate(precompileTemplate("{{#let (element this.tagName) as |El|}}\n {{#if this.isReplacing}}\n {{#if this.hasReachedViewport}}\n {{yield}}\n {{else}}\n <El {{this.setupObserver}} ...attributes />\n {{/if}}\n {{else}}\n <El {{this.setupObserver}} ...attributes>\n {{#if this.hasReachedViewport}}\n {{yield}}\n {{/if}}\n </El>\n {{/if}}\n{{/let}}", {
|
|
73
|
+
strictMode: true,
|
|
74
|
+
scope: () => ({
|
|
75
|
+
element
|
|
76
|
+
})
|
|
77
|
+
}), this);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { InViewport };
|
|
82
|
+
//# sourceMappingURL=in-viewport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-viewport.js","sources":["../../src/viewport/in-viewport.gts"],"sourcesContent":["import Component from \"@glimmer/component\";\nimport { tracked } from \"@glimmer/tracking\";\nimport { assert } from \"@ember/debug\";\n\nimport { element } from \"ember-element-helper\";\nimport { modifier } from \"ember-modifier\";\n\nimport { viewport } from \"./viewport.ts\";\n\nexport type InViewportMode = \"replace\" | \"contain\";\n\n/**\n * Configuration for the InViewport component\n */\nexport interface InViewportSignature {\n Element: HTMLElement;\n Args: {\n /**\n * The tag name for the placeholder element.\n * Can be any valid HTML tag name.\n * Default: 'div'\n */\n tagName?: string;\n\n /**\n * The mode determines how yielded content is rendered:\n * - 'replace': yielded content replaces the placeholder element\n * - 'contain': yielded content is rendered within the placeholder\n * Default: 'contain'\n */\n mode?: InViewportMode;\n };\n Blocks: {\n /**\n * Default block - rendered when the element is in the viewport\n */\n default: [];\n };\n}\n\n/**\n * A component that only renders its content when the element is near the viewport.\n *\n * This is useful for deferring the rendering of heavy components until they're\n * actually needed, improving performance for pages with many components.\n *\n * Example usage:\n * ```gjs\n * import { InViewport } from 'ember-primitives';\n *\n * <template>\n * <InViewport>\n * <ExpensiveComponent />\n * </InViewport>\n * </template>\n * ```\n *\n * The component uses the Intersection Observer API to detect when the element\n * is near the viewport. Once detected, the observer is destroyed and the content\n * is rendered permanently.\n */\nexport class InViewport extends Component<InViewportSignature> {\n /**\n * Whether the element has been detected as in/near the viewport\n */\n @tracked hasIntersected = false;\n\n get #viewport() {\n return viewport(this);\n }\n\n setupObserver = modifier((element: Element) => {\n if (this.hasIntersected) {\n return;\n }\n\n this.#viewport.observe(element, this.handle);\n\n return () => this.#viewport.unobserve(element, this.handle);\n });\n\n handle = (entry: IntersectionObserverEntry) => {\n if (entry?.isIntersecting) {\n this.hasIntersected = true;\n\n this.#viewport.unobserve(entry.target, this.handle);\n }\n };\n\n get mode(): InViewportMode {\n assert(\n 'InViewport mode must be either \"replace\" or \"contain\"',\n !this.args.mode || this.args.mode === \"replace\" || this.args.mode === \"contain\",\n );\n\n return this.args.mode ?? \"contain\";\n }\n\n get tagName(): string {\n return this.args.tagName ?? \"div\";\n }\n\n get hasReachedViewport(): boolean {\n return this.hasIntersected;\n }\n\n get isReplacing(): boolean {\n return this.mode === \"replace\";\n }\n\n <template>\n {{#let (element this.tagName) as |El|}}\n {{#if this.isReplacing}}\n {{#if this.hasReachedViewport}}\n {{yield}}\n {{else}}\n <El {{this.setupObserver}} ...attributes />\n {{/if}}\n {{else}}\n <El {{this.setupObserver}} ...attributes>\n {{#if this.hasReachedViewport}}\n {{yield}}\n {{/if}}\n </El>\n {{/if}}\n {{/let}}\n </template>\n}\n"],"names":["InViewport","Component","g","prototype","tracked","i","#viewport","viewport","setupObserver","modifier","element","hasIntersected","observe","handle","unobserve","entry","isIntersecting","target","mode","assert","args","tagName","hasReachedViewport","isReplacing","setComponentTemplate","precompileTemplate","strictMode","scope"],"mappings":";;;;;;;;;;AAwCA;;;;;;;;;;;;;;;;;;;;;AAqBO,MAAMA,UAAA,SAAmBC,SAAA,CAAU;AAAA,EAAA;IAAAC,CAAA,CAAA,IAAA,CAAAC,SAAA,EAAA,gBAAA,EAAA,CAIvCC,OAAA,CAAA,EAAA,YAAA;AAAA,MAAA,OAAyB,KAAA;AAAA,IAAA,CAAA,CAAA;AAAA;EAAA,eAAA,IAAAC,CAAA,CAAA,IAAA,EAAA,gBAAA,CAAA,EAAA,MAAA;AAH1B;;AAEC;EAGD,IAAI,SAASC,GAAA;IACX,OAAOC,SAAS,IAAI,CAAA;AACtB,EAAA;AAEAC,EAAAA,aAAA,GAAgBC,QAAA,CAAUC,OAAS,IAAA;IACjC,IAAI,IAAI,CAACC,cAAc,EAAE;AACvB,MAAA;AACF,IAAA;IAEA,IAAI,CAAC,SAAS,CAACC,OAAO,CAACF,OAAA,EAAS,IAAI,CAACG,MAAM,CAAA;AAE3C,IAAA,OAAO,MAAM,IAAI,CAAC,SAAS,CAACC,SAAS,CAACJ,OAAA,EAAS,IAAI,CAACG,MAAM,CAAA;AAC5D,EAAA,CAAA,CAAA;EAEAA,MAAA,GAAUE,KAAO,IAAA;IACf,IAAIA,OAAOC,cAAA,EAAgB;MACzB,IAAI,CAACL,cAAc,GAAG,IAAA;AAEtB,MAAA,IAAI,CAAC,SAAS,CAACG,SAAS,CAACC,KAAA,CAAME,MAAM,EAAE,IAAI,CAACJ,MAAM,CAAA;AACpD,IAAA;EACF,CAAA;EAEA,IAAIK,OAAuB;IACzBC,MAAA,CACE,uDAAA,EACA,CAAC,IAAI,CAACC,IAAI,CAACF,IAAI,IAAI,IAAI,CAACE,IAAI,CAACF,IAAI,KAAK,SAAA,IAAa,IAAI,CAACE,IAAI,CAACF,IAAI,KAAK,SAAA,CAAA;AAGxE,IAAA,OAAO,IAAI,CAACE,IAAI,CAACF,IAAI,IAAI,SAAA;AAC3B,EAAA;EAEA,IAAIG,OAAAA,GAAkB;AACpB,IAAA,OAAO,IAAI,CAACD,IAAI,CAACC,OAAO,IAAI,KAAA;AAC9B,EAAA;EAEA,IAAIC,kBAAAA,GAA8B;IAChC,OAAO,IAAI,CAACX,cAAc;AAC5B,EAAA;EAEA,IAAIY,WAAAA,GAAuB;AACzB,IAAA,OAAO,IAAI,CAACL,IAAI,KAAK,SAAA;AACvB,EAAA;AAEA,EAAA;IAAAM,oBAAA,CAAAC,kBAAA,CAAA,6WAAA,EAgBA;MAAAC,UAAA,EAAA,IAAA;AAAAC,MAAAA,KAAA,EAAAA,OAAA;AAAAjB,QAAAA;AAAA,OAAA;KAAU,CAAA,EAAV,IAAW,CAAA;AAAD;AACZ;;;;"}
|