ember-primitives 0.48.2 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.mjs +271 -0
- package/declarations/components/portal.d.ts.map +1 -1
- package/declarations/components/rating/public-types.d.ts +0 -4
- package/declarations/components/rating/public-types.d.ts.map +1 -1
- package/declarations/components/rating/rating.d.ts +9 -1
- package/declarations/components/rating/rating.d.ts.map +1 -1
- package/declarations/components/rating/stars.d.ts.map +1 -1
- package/declarations/components/rating/state.d.ts +4 -0
- package/declarations/components/rating/state.d.ts.map +1 -1
- package/declarations/components/rating/utils.d.ts +0 -1
- package/declarations/components/rating/utils.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 -8
- 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-BrIiwDLw.js +152 -0
- package/dist/rating-BrIiwDLw.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 +24 -20
- package/src/-private.ts +4 -0
- package/src/color-scheme.ts +165 -0
- package/src/components/-private/typed-elements.gts +13 -0
- package/src/components/-private/utils.ts +16 -0
- package/src/components/accordion/content.gts +34 -0
- package/src/components/accordion/header.gts +36 -0
- package/src/components/accordion/item.gts +55 -0
- package/src/components/accordion/public.ts +64 -0
- package/src/components/accordion/trigger.gts +32 -0
- package/src/components/accordion.gts +195 -0
- package/src/components/avatar.gts +108 -0
- package/src/components/dialog.gts +234 -0
- package/src/components/external-link.gts +14 -0
- package/src/components/form.gts +75 -0
- package/src/components/heading.gts +36 -0
- package/src/components/keys.gts +53 -0
- package/src/components/layout/hero.css +5 -0
- package/src/components/layout/hero.gts +17 -0
- package/src/components/layout/sticky-footer.css +9 -0
- package/src/components/layout/sticky-footer.gts +40 -0
- package/src/components/link.gts +172 -0
- package/src/components/menu.gts +373 -0
- package/src/components/one-time-password/buttons.gts +31 -0
- package/src/components/one-time-password/input.gts +198 -0
- package/src/components/one-time-password/otp.gts +130 -0
- package/src/components/one-time-password/utils.ts +201 -0
- package/src/components/one-time-password.gts +2 -0
- package/src/components/popover.gts +248 -0
- package/src/components/portal-targets.gts +136 -0
- package/src/components/portal.gts +194 -0
- package/src/components/progress.gts +154 -0
- package/src/components/rating/public-types.ts +44 -0
- package/src/components/rating/range.gts +22 -0
- package/src/components/rating/rating.gts +228 -0
- package/src/components/rating/stars.gts +60 -0
- package/src/components/rating/state.gts +144 -0
- package/src/components/rating/utils.ts +7 -0
- package/src/components/rating.gts +5 -0
- package/src/components/scroller.gts +179 -0
- package/src/components/shadowed.gts +110 -0
- package/src/components/switch.gts +103 -0
- package/src/components/tabs.gts +519 -0
- package/src/components/toggle-group.gts +265 -0
- package/src/components/toggle.gts +81 -0
- package/src/components/violations.css +105 -0
- package/src/components/violations.css.ts +1 -0
- package/src/components/visually-hidden.css +14 -0
- package/src/components/visually-hidden.gts +15 -0
- package/src/components/zoetrope/index.gts +358 -0
- package/src/components/zoetrope/styles.css +40 -0
- package/src/components/zoetrope/types.ts +65 -0
- package/src/components/zoetrope.ts +3 -0
- package/src/dom-context.gts +245 -0
- package/src/floating-ui/component.gts +186 -0
- package/src/floating-ui/middleware.ts +13 -0
- package/src/floating-ui/modifier.ts +183 -0
- package/src/floating-ui.ts +2 -0
- package/src/head.gts +37 -0
- package/src/helpers/body-class.ts +94 -0
- package/src/helpers/link.ts +125 -0
- package/src/helpers/service.ts +25 -0
- package/src/helpers.ts +2 -0
- package/src/iframe.ts +31 -0
- package/src/index.ts +43 -0
- package/src/load.gts +77 -0
- package/src/narrowing.ts +7 -0
- package/src/on-resize.ts +64 -0
- package/src/proper-links.ts +140 -0
- package/src/qp.ts +107 -0
- package/src/resize-observer.ts +132 -0
- package/src/service.ts +103 -0
- package/src/store.ts +72 -0
- package/src/styles.css.ts +5 -0
- package/src/tabster.ts +54 -0
- package/src/template-registry.ts +44 -0
- package/src/test-support/a11y.ts +50 -0
- package/src/test-support/dom.ts +112 -0
- package/src/test-support/otp.ts +64 -0
- package/src/test-support/rating.ts +144 -0
- package/src/test-support/routing.ts +62 -0
- package/src/test-support/zoetrope.ts +51 -0
- package/src/test-support.gts +6 -0
- package/src/type-utils.ts +1 -0
- package/src/utils.ts +75 -0
- package/src/viewport/in-viewport.gts +128 -0
- package/src/viewport/viewport.ts +122 -0
- package/src/viewport.ts +2 -0
- 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 +0 -149
- package/dist/rating-D052JWRa.js.map +0 -1
- package/dist/utils-C5796IKA.js.map +0 -1
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;;;;"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { registerDestructor } from '@ember/destroyable';
|
|
2
|
+
import { createService } from '../service.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates or returns the ViewportObserverManager.
|
|
6
|
+
*
|
|
7
|
+
* Only one of these will exist per owner.
|
|
8
|
+
*
|
|
9
|
+
* Has only two methods:
|
|
10
|
+
* - observe(element, callback: (intersectionObserverEntry) => void, options?)
|
|
11
|
+
* - unobserve(element, callback: (intersectionObserverEntry) => void)
|
|
12
|
+
*
|
|
13
|
+
* Like with the underlying IntersectionObserver API (and all event listeners),
|
|
14
|
+
* the callback passed to unobserve must be the same reference as the one
|
|
15
|
+
* passed to observe.
|
|
16
|
+
*/
|
|
17
|
+
function viewport(context) {
|
|
18
|
+
return createService(context, ViewportObserverManager);
|
|
19
|
+
}
|
|
20
|
+
class ViewportObserverManager {
|
|
21
|
+
#callbacks = new WeakMap();
|
|
22
|
+
#handleIntersection = entries => {
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
const callbacks = this.#callbacks.get(entry.target);
|
|
25
|
+
if (callbacks) {
|
|
26
|
+
for (const callback of callbacks) {
|
|
27
|
+
callback(entry);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
#observer = new IntersectionObserver(this.#handleIntersection, {
|
|
33
|
+
/**
|
|
34
|
+
* NOTE: clipping is unaffected by rootMargin if the intersection is with anything
|
|
35
|
+
* other than the specified "root".
|
|
36
|
+
* And since we don't specify the "root", this effectively means the window viewport.
|
|
37
|
+
* (hence the utility name: "viewport")
|
|
38
|
+
*/
|
|
39
|
+
});
|
|
40
|
+
constructor() {
|
|
41
|
+
registerDestructor(this, () => {
|
|
42
|
+
this.#observer?.disconnect();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Initiate the observing of the `element` or add an additional `callback`
|
|
48
|
+
* if the `element` is already observed.
|
|
49
|
+
*
|
|
50
|
+
* @param {object} element
|
|
51
|
+
* @param {function} callback The `callback` is called whenever the `element`
|
|
52
|
+
* intersects with the viewport. It is called with an `IntersectionObserverEntry`
|
|
53
|
+
* object for the particular `element`.
|
|
54
|
+
*/
|
|
55
|
+
observe(element, callback) {
|
|
56
|
+
const callbacks = this.#callbacks.get(element);
|
|
57
|
+
if (callbacks) {
|
|
58
|
+
callbacks.add(callback);
|
|
59
|
+
} else {
|
|
60
|
+
this.#callbacks.set(element, new Set([callback]));
|
|
61
|
+
this.#observer.observe(element);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* End the observing of the `element` or just remove the provided `callback`.
|
|
67
|
+
*
|
|
68
|
+
* It will unobserve the `element` if the `callback` is not provided
|
|
69
|
+
* or there are no more callbacks left for this `element`.
|
|
70
|
+
*
|
|
71
|
+
* @param {Element | undefined | null} element
|
|
72
|
+
* @param {function?} callback - The `callback` to remove from the listeners
|
|
73
|
+
* of the `element` intersection changes.
|
|
74
|
+
*/
|
|
75
|
+
unobserve(element, callback) {
|
|
76
|
+
if (!element) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const callbacks = this.#callbacks.get(element);
|
|
80
|
+
if (!callbacks) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
callbacks.delete(callback);
|
|
84
|
+
if (!callback || !callbacks.size) {
|
|
85
|
+
this.#callbacks.delete(element);
|
|
86
|
+
this.#observer.unobserve(element);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { viewport };
|
|
92
|
+
//# sourceMappingURL=viewport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport.js","sources":["../../src/viewport/viewport.ts"],"sourcesContent":["import { registerDestructor } from '@ember/destroyable';\n\nimport { createService } from '../service.ts';\n\n/**\n * Creates or returns the ViewportObserverManager.\n *\n * Only one of these will exist per owner.\n *\n * Has only two methods:\n * - observe(element, callback: (intersectionObserverEntry) => void, options?)\n * - unobserve(element, callback: (intersectionObserverEntry) => void)\n *\n * Like with the underlying IntersectionObserver API (and all event listeners),\n * the callback passed to unobserve must be the same reference as the one\n * passed to observe.\n */\nexport function viewport(context: object) {\n return createService(context, ViewportObserverManager);\n}\n\nexport interface ViewportOptions {\n /**\n * A margin around the root. Can have values similar to the CSS margin property.\n * The values can be percentages. This set of values serves to grow or shrink each\n * side of the root element's bounding box before computing intersections.\n * Defaults to all zeros.\n */\n rootMargin?: string;\n /**\n * Either a single number or an array of numbers which indicate at what percentage\n * of the target's visibility the observer's callback should be executed. If you only\n * want to detect when visibility passes the 50% mark, you can use a value of 0.5.\n * If you want the callback to run every time visibility passes another 25%, you would\n * specify the array [0, 0.25, 0.5, 0.75, 1]. The default is 0 (meaning as soon as\n * even one pixel is visible, the callback will be run).\n */\n threshold?: number | number[];\n}\n\nclass ViewportObserverManager {\n #callbacks = new WeakMap<Element, Set<(entries: IntersectionObserverEntry) => unknown>>();\n\n #handleIntersection = (entries: IntersectionObserverEntry[]) => {\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\n #observer = new IntersectionObserver(this.#handleIntersection, {\n /**\n * NOTE: clipping is unaffected by rootMargin if the intersection is with anything\n * other than the specified \"root\".\n * And since we don't specify the \"root\", this effectively means the window viewport.\n * (hence the utility name: \"viewport\")\n */\n });\n\n constructor() {\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 `element`\n * intersects with the viewport. It is called with an `IntersectionObserverEntry`\n * object for the particular `element`.\n */\n observe(element: Element, callback: (entry: IntersectionObserverEntry) => 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 {Element | undefined | null} element\n * @param {function?} callback - The `callback` to remove from the listeners\n * of the `element` intersection changes.\n */\n unobserve(\n element: Element | undefined | null,\n callback: (entry: IntersectionObserverEntry) => unknown\n ) {\n if (!element) {\n return;\n }\n\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"],"names":["viewport","context","createService","ViewportObserverManager","WeakMap","entries","entry","callbacks","get","target","callback","IntersectionObserver","constructor","registerDestructor","disconnect","observe","element","add","set","Set","unobserve","delete","size"],"mappings":";;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,QAAQA,CAACC,OAAe,EAAE;AACxC,EAAA,OAAOC,aAAa,CAACD,OAAO,EAAEE,uBAAuB,CAAC;AACxD;AAqBA,MAAMA,uBAAuB,CAAC;AAC5B,EAAA,UAAU,GAAG,IAAIC,OAAO,EAAiE;EAEzF,mBAAmB,GAAIC,OAAoC,IAAK;AAC9D,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;EAED,SAAS,GAAG,IAAIK,oBAAoB,CAAC,IAAI,CAAC,mBAAmB,EAAE;AAC7D;AACJ;AACA;AACA;AACA;AACA;AALI,GAMD,CAAC;AAEFC,EAAAA,WAAWA,GAAG;IACZC,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,EAAEN,QAAuD,EAAE;IACjF,MAAMH,SAAS,GAAG,IAAI,CAAC,UAAU,CAACC,GAAG,CAACQ,OAAO,CAAC;AAE9C,IAAA,IAAIT,SAAS,EAAE;AACbA,MAAAA,SAAS,CAACU,GAAG,CAACP,QAAQ,CAAC;AACzB,IAAA,CAAC,MAAM;AACL,MAAA,IAAI,CAAC,UAAU,CAACQ,GAAG,CAACF,OAAO,EAAE,IAAIG,GAAG,CAAC,CAACT,QAAQ,CAAC,CAAC,CAAC;AACjD,MAAA,IAAI,CAAC,SAAS,CAACK,OAAO,CAACC,OAAO,CAAC;AACjC,IAAA;AACF,EAAA;;AAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACEI,EAAAA,SAASA,CACPJ,OAAmC,EACnCN,QAAuD,EACvD;IACA,IAAI,CAACM,OAAO,EAAE;AACZ,MAAA;AACF,IAAA;IAEA,MAAMT,SAAS,GAAG,IAAI,CAAC,UAAU,CAACC,GAAG,CAACQ,OAAO,CAAC;IAE9C,IAAI,CAACT,SAAS,EAAE;AACd,MAAA;AACF,IAAA;AAEAA,IAAAA,SAAS,CAACc,MAAM,CAACX,QAAQ,CAAC;AAE1B,IAAA,IAAI,CAACA,QAAQ,IAAI,CAACH,SAAS,CAACe,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;;;;"}
|
package/dist/viewport.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember-primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "Making apps easier to build",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ember-addon"
|
|
@@ -11,22 +11,25 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"addon-main.cjs",
|
|
13
13
|
"dist",
|
|
14
|
+
"src",
|
|
15
|
+
"bin",
|
|
14
16
|
"declarations"
|
|
15
17
|
],
|
|
18
|
+
"bin": "./bin/index.mjs",
|
|
16
19
|
"dependencies": {
|
|
17
20
|
"@babel/runtime": "^7.27.1",
|
|
18
21
|
"@embroider/addon-shim": "^1.10.0",
|
|
19
|
-
"@embroider/macros": "^1.19.
|
|
22
|
+
"@embroider/macros": "^1.19.6",
|
|
20
23
|
"@floating-ui/dom": "^1.7.0",
|
|
21
24
|
"decorator-transforms": "^2.3.0",
|
|
22
25
|
"ember-element-helper": ">= 0.8.6",
|
|
23
26
|
"form-data-utils": "^0.6.0",
|
|
24
27
|
"reactiveweb": "^1.8.0",
|
|
25
28
|
"should-handle-link": "^1.2.2",
|
|
26
|
-
"tabster": "^8.
|
|
27
|
-
"tracked-built-ins": "^4.
|
|
29
|
+
"tabster": "^8.7.0",
|
|
30
|
+
"tracked-built-ins": "^4.1.0",
|
|
28
31
|
"tracked-toolbox": "^2.0.0",
|
|
29
|
-
"which-heading-do-i-need": "0.2.
|
|
32
|
+
"which-heading-do-i-need": "0.2.3"
|
|
30
33
|
},
|
|
31
34
|
"devDependencies": {
|
|
32
35
|
"@arethetypeswrong/cli": "^0.18.0",
|
|
@@ -37,32 +40,33 @@
|
|
|
37
40
|
"@babel/plugin-syntax-decorators": "^7.27.1",
|
|
38
41
|
"@babel/plugin-transform-class-static-block": "^7.27.1",
|
|
39
42
|
"@babel/plugin-transform-private-methods": "^7.27.1",
|
|
43
|
+
"@babel/plugin-transform-typescript": "^7.28.5",
|
|
40
44
|
"@babel/preset-typescript": "^7.28.5",
|
|
41
|
-
"@ember/library-tsconfig": "^
|
|
42
|
-
"@ember/test-helpers": "^5.4.
|
|
45
|
+
"@ember/library-tsconfig": "^2.0.0",
|
|
46
|
+
"@ember/test-helpers": "^5.4.1",
|
|
43
47
|
"@ember/test-waiters": "^4.1.0",
|
|
44
|
-
"@embroider/addon-dev": "^8.
|
|
48
|
+
"@embroider/addon-dev": "^8.2.0",
|
|
45
49
|
"@glimmer/component": "^2.0.0",
|
|
46
50
|
"@glimmer/tracking": "^1.1.2",
|
|
47
|
-
"@glint/ember-tsc": "^1.0.
|
|
48
|
-
"@glint/template": "^1.7.
|
|
49
|
-
"@glint/tsserver-plugin": "^2.0.
|
|
50
|
-
"@nullvoxpopuli/eslint-configs": "^5.
|
|
51
|
+
"@glint/ember-tsc": "^1.0.8",
|
|
52
|
+
"@glint/template": "^1.7.3",
|
|
53
|
+
"@glint/tsserver-plugin": "^2.0.8",
|
|
54
|
+
"@nullvoxpopuli/eslint-configs": "^5.5.0",
|
|
51
55
|
"@rollup/plugin-babel": "^6.1.0",
|
|
52
|
-
"@tsconfig/ember": "^3.0.
|
|
53
|
-
"babel-plugin-ember-template-compilation": "^
|
|
56
|
+
"@tsconfig/ember": "^3.0.12",
|
|
57
|
+
"babel-plugin-ember-template-compilation": "^3.0.1",
|
|
54
58
|
"concurrently": "^9.2.1",
|
|
55
59
|
"ember-modifier": "^4.2.2",
|
|
56
60
|
"ember-resources": "^7.0.7",
|
|
57
|
-
"ember-source": "6.
|
|
61
|
+
"ember-source": "6.9.0",
|
|
58
62
|
"ember-template-lint": "^7.9.3",
|
|
59
|
-
"eslint": "^9.39.
|
|
63
|
+
"eslint": "^9.39.2",
|
|
60
64
|
"execa": "^9.6.0",
|
|
61
65
|
"fix-bad-declaration-output": "^1.1.5",
|
|
62
|
-
"prettier": "^3.
|
|
63
|
-
"prettier-plugin-ember-template-tag": "^2.
|
|
64
|
-
"publint": "^0.3.
|
|
65
|
-
"rollup": "~4.
|
|
66
|
+
"prettier": "^3.7.4",
|
|
67
|
+
"prettier-plugin-ember-template-tag": "^2.1.2",
|
|
68
|
+
"publint": "^0.3.16",
|
|
69
|
+
"rollup": "~4.54.0",
|
|
66
70
|
"rollup-plugin-copy": "^3.5.0",
|
|
67
71
|
"typescript": "^5.9.3"
|
|
68
72
|
},
|
package/src/-private.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { waitForPromise } from '@ember/test-waiters';
|
|
2
|
+
|
|
3
|
+
import { cell } from 'ember-resources';
|
|
4
|
+
|
|
5
|
+
const _colorScheme = cell<string | undefined>();
|
|
6
|
+
|
|
7
|
+
let callbacks: Set<(colorScheme: string) => void> = new Set();
|
|
8
|
+
|
|
9
|
+
async function runCallbacks(theme: string) {
|
|
10
|
+
await Promise.resolve();
|
|
11
|
+
|
|
12
|
+
for (const callback of callbacks.values()) {
|
|
13
|
+
callback(theme);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Object for managing the color scheme
|
|
19
|
+
*/
|
|
20
|
+
export const colorScheme = {
|
|
21
|
+
/**
|
|
22
|
+
* Set's the current color scheme to the passed value
|
|
23
|
+
*/
|
|
24
|
+
update: (value: string) => {
|
|
25
|
+
colorScheme.current = value;
|
|
26
|
+
|
|
27
|
+
void waitForPromise(runCallbacks(value));
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
on: {
|
|
31
|
+
/**
|
|
32
|
+
* register a function to be called when the color scheme changes.
|
|
33
|
+
*/
|
|
34
|
+
update: (callback: (colorScheme: string) => void) => {
|
|
35
|
+
callbacks.add(callback);
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
off: {
|
|
39
|
+
/**
|
|
40
|
+
* unregister a function that would have been called when the color scheme changes.
|
|
41
|
+
*/
|
|
42
|
+
update: (callback: (colorScheme: string) => void) => {
|
|
43
|
+
callbacks.delete(callback);
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* the current valuel of the "color scheme"
|
|
49
|
+
*/
|
|
50
|
+
get current(): string | undefined {
|
|
51
|
+
return _colorScheme.current;
|
|
52
|
+
},
|
|
53
|
+
set current(value: string | undefined) {
|
|
54
|
+
_colorScheme.current = value;
|
|
55
|
+
|
|
56
|
+
if (!value) {
|
|
57
|
+
localPreference.delete();
|
|
58
|
+
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
localPreference.update(value);
|
|
63
|
+
setColorScheme(value);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Synchronizes state of `colorScheme` with the users preferences as well as reconciles with previously set theme in local storage.
|
|
69
|
+
*
|
|
70
|
+
* This may only be called once per app.
|
|
71
|
+
*/
|
|
72
|
+
export function sync() {
|
|
73
|
+
/**
|
|
74
|
+
* reset the callbacks
|
|
75
|
+
*/
|
|
76
|
+
callbacks = new Set();
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* If local prefs are set, then we don't care what prefers-color-scheme is
|
|
80
|
+
*/
|
|
81
|
+
const userPreference = localPreference.read();
|
|
82
|
+
|
|
83
|
+
if (userPreference) {
|
|
84
|
+
setColorScheme(userPreference);
|
|
85
|
+
_colorScheme.current = userPreference;
|
|
86
|
+
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (prefers.dark()) {
|
|
91
|
+
setColorScheme('dark');
|
|
92
|
+
_colorScheme.current = 'dark';
|
|
93
|
+
} else if (prefers.light()) {
|
|
94
|
+
setColorScheme('light');
|
|
95
|
+
_colorScheme.current = 'light';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Helper methods to determining what the user's preferred color scheme is
|
|
101
|
+
* based on the system preferences rather than the users explicit preference.
|
|
102
|
+
*/
|
|
103
|
+
export const prefers = {
|
|
104
|
+
dark: () => window.matchMedia('(prefers-color-scheme: dark)').matches,
|
|
105
|
+
light: () => window.matchMedia('(prefers-color-scheme: light)').matches,
|
|
106
|
+
custom: (name: string) => window.matchMedia(`(prefers-color-scheme: ${name})`).matches,
|
|
107
|
+
none: () => window.matchMedia('(prefers-color-scheme: no-preference)').matches,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const LOCAL_PREF_KEY = 'ember-primitives/color-scheme#local-preference';
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Helper methods for working with the color scheme preference in local storage
|
|
114
|
+
*/
|
|
115
|
+
export const localPreference = {
|
|
116
|
+
isSet: () => Boolean(localPreference.read()),
|
|
117
|
+
read: () => localStorage.getItem(LOCAL_PREF_KEY),
|
|
118
|
+
update: (value: string) => localStorage.setItem(LOCAL_PREF_KEY, value),
|
|
119
|
+
delete: () => localStorage.removeItem(LOCAL_PREF_KEY),
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* For the given element, returns the `color-scheme` of that element.
|
|
124
|
+
*/
|
|
125
|
+
export function getColorScheme(element?: HTMLElement) {
|
|
126
|
+
const style = styleOf(element);
|
|
127
|
+
|
|
128
|
+
return style.getPropertyValue('color-scheme');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function setColorScheme(element: HTMLElement, value: string): void;
|
|
132
|
+
export function setColorScheme(value: string): void;
|
|
133
|
+
|
|
134
|
+
export function setColorScheme(...args: [string] | [HTMLElement, string]): void {
|
|
135
|
+
if (typeof args[0] === 'string') {
|
|
136
|
+
styleOf().setProperty('color-scheme', args[0]);
|
|
137
|
+
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (typeof args[1] === 'string') {
|
|
142
|
+
styleOf(args[0]).setProperty('color-scheme', args[1]);
|
|
143
|
+
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
throw new Error(`Invalid arity, expected up to 2 args, received ${args.length}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Removes the `color-scheme` from the given element
|
|
152
|
+
*/
|
|
153
|
+
export function removeColorScheme(element?: HTMLElement) {
|
|
154
|
+
const style = styleOf(element);
|
|
155
|
+
|
|
156
|
+
style.removeProperty('color-scheme');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function styleOf(element?: HTMLElement) {
|
|
160
|
+
if (element) {
|
|
161
|
+
return element.style;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return document.documentElement.style;
|
|
165
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TOC } from "@ember/component/template-only";
|
|
2
|
+
|
|
3
|
+
export const Div: TOC<{ Element: HTMLDivElement; Blocks: { default: [] } }> = <template>
|
|
4
|
+
<div ...attributes>{{yield}}</div>
|
|
5
|
+
</template>;
|
|
6
|
+
|
|
7
|
+
export const Label: TOC<{
|
|
8
|
+
Element: HTMLLabelElement;
|
|
9
|
+
Args: { for: string };
|
|
10
|
+
Blocks: { default: [] };
|
|
11
|
+
}> = <template>
|
|
12
|
+
<label for={{@for}} ...attributes>{{yield}}</label>
|
|
13
|
+
</template>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* If the user provides an onChange or similar function, use that,
|
|
3
|
+
* otherwise fallback to the uncontrolled toggle
|
|
4
|
+
*/
|
|
5
|
+
export function toggleWithFallback(
|
|
6
|
+
uncontrolledToggle: (...args: unknown[]) => void,
|
|
7
|
+
|
|
8
|
+
controlledToggle?: (...args: any[]) => void,
|
|
9
|
+
...args: unknown[]
|
|
10
|
+
) {
|
|
11
|
+
if (controlledToggle) {
|
|
12
|
+
return controlledToggle(...args);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
uncontrolledToggle(...args);
|
|
16
|
+
}
|