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/src/utils.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { getOwner } from '@ember/owner';
|
|
2
|
+
|
|
3
|
+
import type Owner from '@ember/owner';
|
|
4
|
+
|
|
5
|
+
// this is copy pasted from https://github.com/emberjs/ember.js/blob/60d2e0cddb353aea0d6e36a72fda971010d92355/packages/%40ember/-internals/glimmer/lib/helpers/unique-id.ts
|
|
6
|
+
// Unfortunately due to https://github.com/emberjs/ember.js/issues/20165 we cannot use the built-in version in template tags
|
|
7
|
+
export function uniqueId(): string {
|
|
8
|
+
// @ts-expect-error this one-liner abuses weird JavaScript semantics that
|
|
9
|
+
// TypeScript (legitimately) doesn't like, but they're nonetheless valid and
|
|
10
|
+
// specced.
|
|
11
|
+
// 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
|
|
12
|
+
return ([3e7] + -1e3 + -4e3 + -2e3 + -1e11).replace(/[0-3]/g, (a) =>
|
|
13
|
+
((a * 4) ^ ((Math.random() * 16) >> (a & 2))).toString(16)
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isNewable(x: any): x is new (...args: unknown[]) => NonNullable<object> {
|
|
18
|
+
// TypeScript has really bad prototype support -- they don't really
|
|
19
|
+
// want folks using this sort of stuff -- but it's handy for perf and all that.
|
|
20
|
+
//
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
22
|
+
return x.prototype?.constructor === x;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Loose check for an "ownerish" API.
|
|
27
|
+
* only the ".lookup" method is required.
|
|
28
|
+
*
|
|
29
|
+
* The requirements for what an "owner" is are sort of undefined,
|
|
30
|
+
* as the actual owner in ember applications has too much on it,
|
|
31
|
+
* and the long term purpose of the owner will be questioned once we
|
|
32
|
+
* eliminate the need to have a registry (what lookup looks in to),
|
|
33
|
+
* but we'll still need "Something" to represent the lifetime of the application.
|
|
34
|
+
*
|
|
35
|
+
* Technically, the owner could be any object, including `{}`
|
|
36
|
+
*/
|
|
37
|
+
export function isOwner(x: unknown): x is Owner {
|
|
38
|
+
if (!isNonNullableObject(x)) return false;
|
|
39
|
+
|
|
40
|
+
return 'lookup' in x && typeof x.lookup === 'function';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function isNonNullableObject(x: unknown): x is NonNullable<object> {
|
|
44
|
+
if (typeof x !== 'object') return false;
|
|
45
|
+
if (x === null) return false;
|
|
46
|
+
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Can receive the class instance or the owner itself, and will always return return the owner.
|
|
52
|
+
*
|
|
53
|
+
* undefined will be returned if the Owner does not exist on the passed object
|
|
54
|
+
*
|
|
55
|
+
* Can be useful when combined with `createStore` to then create "services",
|
|
56
|
+
* which don't require string lookup.
|
|
57
|
+
*/
|
|
58
|
+
export function findOwner(contextOrOwner: unknown): Owner | undefined {
|
|
59
|
+
if (isOwner(contextOrOwner)) return contextOrOwner;
|
|
60
|
+
|
|
61
|
+
// _ENSURE_ that we have an object, else getOwner makes no sense to call
|
|
62
|
+
if (!isNonNullableObject(contextOrOwner)) return;
|
|
63
|
+
|
|
64
|
+
const maybeOwner = getOwner(contextOrOwner);
|
|
65
|
+
|
|
66
|
+
if (isOwner(maybeOwner)) return maybeOwner;
|
|
67
|
+
|
|
68
|
+
if ('owner' in contextOrOwner) {
|
|
69
|
+
const maybeOwner = contextOrOwner.owner;
|
|
70
|
+
|
|
71
|
+
if (isOwner(maybeOwner)) return maybeOwner;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import Component from "@glimmer/component";
|
|
2
|
+
import { tracked } from "@glimmer/tracking";
|
|
3
|
+
import { assert } from "@ember/debug";
|
|
4
|
+
|
|
5
|
+
import { element } from "ember-element-helper";
|
|
6
|
+
import { modifier } from "ember-modifier";
|
|
7
|
+
|
|
8
|
+
import { viewport } from "./viewport.ts";
|
|
9
|
+
|
|
10
|
+
export type InViewportMode = "replace" | "contain";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Configuration for the InViewport component
|
|
14
|
+
*/
|
|
15
|
+
export interface InViewportSignature {
|
|
16
|
+
Element: HTMLElement;
|
|
17
|
+
Args: {
|
|
18
|
+
/**
|
|
19
|
+
* The tag name for the placeholder element.
|
|
20
|
+
* Can be any valid HTML tag name.
|
|
21
|
+
* Default: 'div'
|
|
22
|
+
*/
|
|
23
|
+
tagName?: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The mode determines how yielded content is rendered:
|
|
27
|
+
* - 'replace': yielded content replaces the placeholder element
|
|
28
|
+
* - 'contain': yielded content is rendered within the placeholder
|
|
29
|
+
* Default: 'contain'
|
|
30
|
+
*/
|
|
31
|
+
mode?: InViewportMode;
|
|
32
|
+
};
|
|
33
|
+
Blocks: {
|
|
34
|
+
/**
|
|
35
|
+
* Default block - rendered when the element is in the viewport
|
|
36
|
+
*/
|
|
37
|
+
default: [];
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A component that only renders its content when the element is near the viewport.
|
|
43
|
+
*
|
|
44
|
+
* This is useful for deferring the rendering of heavy components until they're
|
|
45
|
+
* actually needed, improving performance for pages with many components.
|
|
46
|
+
*
|
|
47
|
+
* Example usage:
|
|
48
|
+
* ```gjs
|
|
49
|
+
* import { InViewport } from 'ember-primitives';
|
|
50
|
+
*
|
|
51
|
+
* <template>
|
|
52
|
+
* <InViewport>
|
|
53
|
+
* <ExpensiveComponent />
|
|
54
|
+
* </InViewport>
|
|
55
|
+
* </template>
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* The component uses the Intersection Observer API to detect when the element
|
|
59
|
+
* is near the viewport. Once detected, the observer is destroyed and the content
|
|
60
|
+
* is rendered permanently.
|
|
61
|
+
*/
|
|
62
|
+
export class InViewport extends Component<InViewportSignature> {
|
|
63
|
+
/**
|
|
64
|
+
* Whether the element has been detected as in/near the viewport
|
|
65
|
+
*/
|
|
66
|
+
@tracked hasIntersected = false;
|
|
67
|
+
|
|
68
|
+
get #viewport() {
|
|
69
|
+
return viewport(this);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
setupObserver = modifier((element: Element) => {
|
|
73
|
+
if (this.hasIntersected) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.#viewport.observe(element, this.handle);
|
|
78
|
+
|
|
79
|
+
return () => this.#viewport.unobserve(element, this.handle);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
handle = (entry: IntersectionObserverEntry) => {
|
|
83
|
+
if (entry?.isIntersecting) {
|
|
84
|
+
this.hasIntersected = true;
|
|
85
|
+
|
|
86
|
+
this.#viewport.unobserve(entry.target, this.handle);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
get mode(): InViewportMode {
|
|
91
|
+
assert(
|
|
92
|
+
'InViewport mode must be either "replace" or "contain"',
|
|
93
|
+
!this.args.mode || this.args.mode === "replace" || this.args.mode === "contain",
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
return this.args.mode ?? "contain";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get tagName(): string {
|
|
100
|
+
return this.args.tagName ?? "div";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get hasReachedViewport(): boolean {
|
|
104
|
+
return this.hasIntersected;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get isReplacing(): boolean {
|
|
108
|
+
return this.mode === "replace";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
<template>
|
|
112
|
+
{{#let (element this.tagName) as |El|}}
|
|
113
|
+
{{#if this.isReplacing}}
|
|
114
|
+
{{#if this.hasReachedViewport}}
|
|
115
|
+
{{yield}}
|
|
116
|
+
{{else}}
|
|
117
|
+
<El {{this.setupObserver}} ...attributes />
|
|
118
|
+
{{/if}}
|
|
119
|
+
{{else}}
|
|
120
|
+
<El {{this.setupObserver}} ...attributes>
|
|
121
|
+
{{#if this.hasReachedViewport}}
|
|
122
|
+
{{yield}}
|
|
123
|
+
{{/if}}
|
|
124
|
+
</El>
|
|
125
|
+
{{/if}}
|
|
126
|
+
{{/let}}
|
|
127
|
+
</template>
|
|
128
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { registerDestructor } from '@ember/destroyable';
|
|
2
|
+
|
|
3
|
+
import { createService } from '../service.ts';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates or returns the ViewportObserverManager.
|
|
7
|
+
*
|
|
8
|
+
* Only one of these will exist per owner.
|
|
9
|
+
*
|
|
10
|
+
* Has only two methods:
|
|
11
|
+
* - observe(element, callback: (intersectionObserverEntry) => void, options?)
|
|
12
|
+
* - unobserve(element, callback: (intersectionObserverEntry) => void)
|
|
13
|
+
*
|
|
14
|
+
* Like with the underlying IntersectionObserver API (and all event listeners),
|
|
15
|
+
* the callback passed to unobserve must be the same reference as the one
|
|
16
|
+
* passed to observe.
|
|
17
|
+
*/
|
|
18
|
+
export function viewport(context: object) {
|
|
19
|
+
return createService(context, ViewportObserverManager);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ViewportOptions {
|
|
23
|
+
/**
|
|
24
|
+
* A margin around the root. Can have values similar to the CSS margin property.
|
|
25
|
+
* The values can be percentages. This set of values serves to grow or shrink each
|
|
26
|
+
* side of the root element's bounding box before computing intersections.
|
|
27
|
+
* Defaults to all zeros.
|
|
28
|
+
*/
|
|
29
|
+
rootMargin?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Either a single number or an array of numbers which indicate at what percentage
|
|
32
|
+
* of the target's visibility the observer's callback should be executed. If you only
|
|
33
|
+
* want to detect when visibility passes the 50% mark, you can use a value of 0.5.
|
|
34
|
+
* If you want the callback to run every time visibility passes another 25%, you would
|
|
35
|
+
* specify the array [0, 0.25, 0.5, 0.75, 1]. The default is 0 (meaning as soon as
|
|
36
|
+
* even one pixel is visible, the callback will be run).
|
|
37
|
+
*/
|
|
38
|
+
threshold?: number | number[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class ViewportObserverManager {
|
|
42
|
+
#callbacks = new WeakMap<Element, Set<(entries: IntersectionObserverEntry) => unknown>>();
|
|
43
|
+
|
|
44
|
+
#handleIntersection = (entries: IntersectionObserverEntry[]) => {
|
|
45
|
+
for (const entry of entries) {
|
|
46
|
+
const callbacks = this.#callbacks.get(entry.target);
|
|
47
|
+
|
|
48
|
+
if (callbacks) {
|
|
49
|
+
for (const callback of callbacks) {
|
|
50
|
+
callback(entry);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
#observer = new IntersectionObserver(this.#handleIntersection, {
|
|
57
|
+
/**
|
|
58
|
+
* NOTE: clipping is unaffected by rootMargin if the intersection is with anything
|
|
59
|
+
* other than the specified "root".
|
|
60
|
+
* And since we don't specify the "root", this effectively means the window viewport.
|
|
61
|
+
* (hence the utility name: "viewport")
|
|
62
|
+
*/
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
constructor() {
|
|
66
|
+
registerDestructor(this, () => {
|
|
67
|
+
this.#observer?.disconnect();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Initiate the observing of the `element` or add an additional `callback`
|
|
73
|
+
* if the `element` is already observed.
|
|
74
|
+
*
|
|
75
|
+
* @param {object} element
|
|
76
|
+
* @param {function} callback The `callback` is called whenever the `element`
|
|
77
|
+
* intersects with the viewport. It is called with an `IntersectionObserverEntry`
|
|
78
|
+
* object for the particular `element`.
|
|
79
|
+
*/
|
|
80
|
+
observe(element: Element, callback: (entry: IntersectionObserverEntry) => unknown) {
|
|
81
|
+
const callbacks = this.#callbacks.get(element);
|
|
82
|
+
|
|
83
|
+
if (callbacks) {
|
|
84
|
+
callbacks.add(callback);
|
|
85
|
+
} else {
|
|
86
|
+
this.#callbacks.set(element, new Set([callback]));
|
|
87
|
+
this.#observer.observe(element);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* End the observing of the `element` or just remove the provided `callback`.
|
|
93
|
+
*
|
|
94
|
+
* It will unobserve the `element` if the `callback` is not provided
|
|
95
|
+
* or there are no more callbacks left for this `element`.
|
|
96
|
+
*
|
|
97
|
+
* @param {Element | undefined | null} element
|
|
98
|
+
* @param {function?} callback - The `callback` to remove from the listeners
|
|
99
|
+
* of the `element` intersection changes.
|
|
100
|
+
*/
|
|
101
|
+
unobserve(
|
|
102
|
+
element: Element | undefined | null,
|
|
103
|
+
callback: (entry: IntersectionObserverEntry) => unknown
|
|
104
|
+
) {
|
|
105
|
+
if (!element) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const callbacks = this.#callbacks.get(element);
|
|
110
|
+
|
|
111
|
+
if (!callbacks) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
callbacks.delete(callback);
|
|
116
|
+
|
|
117
|
+
if (!callback || !callbacks.size) {
|
|
118
|
+
this.#callbacks.delete(element);
|
|
119
|
+
this.#observer.unobserve(element);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
package/src/viewport.ts
ADDED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"component-Bs3N-G9z.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-DKE67I8L.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/dist/otp-C6hCCXKx.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"otp-C6hCCXKx.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/dist/rating-D052JWRa.js
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import Component from '@glimmer/component';
|
|
3
|
-
import { hash } from '@ember/helper';
|
|
4
|
-
import { on } from '@ember/modifier';
|
|
5
|
-
import { uniqueId } from './utils.js';
|
|
6
|
-
import { precompileTemplate } from '@ember/template-compilation';
|
|
7
|
-
import { setComponentTemplate } from '@ember/component';
|
|
8
|
-
import templateOnly from '@ember/component/template-only';
|
|
9
|
-
import { cached } from '@glimmer/tracking';
|
|
10
|
-
import { assert } from '@ember/debug';
|
|
11
|
-
import { localCopy } from 'tracked-toolbox';
|
|
12
|
-
import { g, i, n } from 'decorator-transforms/runtime';
|
|
13
|
-
|
|
14
|
-
const RatingRange = setComponentTemplate(precompileTemplate("\n <input ...attributes name={{@name}} type=\"range\" max={{@max}} value={{@value}} {{on \"change\" @handleChange}} />\n", {
|
|
15
|
-
strictMode: true,
|
|
16
|
-
scope: () => ({
|
|
17
|
-
on
|
|
18
|
-
})
|
|
19
|
-
}), templateOnly());
|
|
20
|
-
|
|
21
|
-
function isString(x) {
|
|
22
|
-
return typeof x === 'string';
|
|
23
|
-
}
|
|
24
|
-
function lte(a, b) {
|
|
25
|
-
return a <= b;
|
|
26
|
-
}
|
|
27
|
-
function percentSelected(a, b) {
|
|
28
|
-
const diff = b + 1 - a;
|
|
29
|
-
if (diff < 0) return 0;
|
|
30
|
-
if (diff > 1) return 100;
|
|
31
|
-
if (a === b) return 100;
|
|
32
|
-
const percent = diff * 100;
|
|
33
|
-
return percent;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const Stars = setComponentTemplate(precompileTemplate("\n <div class=\"ember-primitives__rating__items\">\n {{#each @stars as |star|}}\n {{#let (uniqueId) as |id|}}\n <span class=\"ember-primitives__rating__item\" data-number={{star}} data-percent-selected={{percentSelected star @currentValue}} data-selected={{lte star @currentValue}} data-readonly={{@isReadonly}}>\n <label for=\"input-{{id}}\">\n <span visually-hidden>{{star}} star</span>\n <span aria-hidden=\"true\">\n {{#if (isString @icon)}}\n {{@icon}}\n {{else}}\n <@icon @value={{star}} @isSelected={{lte star @currentValue}} @percentSelected={{percentSelected star @currentValue}} @readonly={{@isReadonly}} />\n {{/if}}\n </span>\n </label>\n\n <input id=\"input-{{id}}\" type=\"radio\" name={{@name}} value={{star}} readonly={{@isReadonly}} checked={{lte star @currentValue}} />\n </span>\n {{/let}}\n {{/each}}\n </div>\n", {
|
|
37
|
-
strictMode: true,
|
|
38
|
-
scope: () => ({
|
|
39
|
-
uniqueId,
|
|
40
|
-
percentSelected,
|
|
41
|
-
lte,
|
|
42
|
-
isString
|
|
43
|
-
})
|
|
44
|
-
}), templateOnly());
|
|
45
|
-
|
|
46
|
-
class RatingState extends Component {
|
|
47
|
-
static {
|
|
48
|
-
g(this.prototype, "_value", [localCopy("args.value")]);
|
|
49
|
-
}
|
|
50
|
-
#_value = (i(this, "_value"), void 0); // eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
51
|
-
get value() {
|
|
52
|
-
return this._value ?? 0;
|
|
53
|
-
}
|
|
54
|
-
get stars() {
|
|
55
|
-
return Array.from({
|
|
56
|
-
length: this.args.max ?? 5
|
|
57
|
-
}, (_, index) => index + 1);
|
|
58
|
-
}
|
|
59
|
-
static {
|
|
60
|
-
n(this.prototype, "stars", [cached]);
|
|
61
|
-
}
|
|
62
|
-
setRating = value => {
|
|
63
|
-
if (this.args.readonly) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
if (value === this._value) {
|
|
67
|
-
this._value = 0;
|
|
68
|
-
} else {
|
|
69
|
-
this._value = value;
|
|
70
|
-
}
|
|
71
|
-
this.args.onChange?.(value);
|
|
72
|
-
};
|
|
73
|
-
setFromString = value => {
|
|
74
|
-
assert("[BUG]: value from input must be a string.", typeof value === "string");
|
|
75
|
-
const num = parseFloat(value);
|
|
76
|
-
if (isNaN(num)) {
|
|
77
|
-
// something went wrong.
|
|
78
|
-
// Since we're using event delegation,
|
|
79
|
-
// this could be from an unrelated input
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
this.setRating(num);
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* Click events are captured by
|
|
86
|
-
* - radio changes (mouse and keyboard)
|
|
87
|
-
* - but only range clicks
|
|
88
|
-
*/
|
|
89
|
-
handleClick = event => {
|
|
90
|
-
// Since we're doing event delegation on a click, we want to make sure
|
|
91
|
-
// we don't do anything on other elements
|
|
92
|
-
const isValid = event.target instanceof HTMLInputElement && event.target.name === this.args.name && event.target.type === "radio";
|
|
93
|
-
if (!isValid) return;
|
|
94
|
-
const selected = event.target?.value;
|
|
95
|
-
this.setFromString(selected);
|
|
96
|
-
};
|
|
97
|
-
/**
|
|
98
|
-
* Only attached to a range element, if present.
|
|
99
|
-
* Range elements don't fire click events on keyboard usage, like radios do
|
|
100
|
-
*/
|
|
101
|
-
handleChange = event => {
|
|
102
|
-
const isValid = event.target !== null && "value" in event.target;
|
|
103
|
-
if (!isValid) return;
|
|
104
|
-
this.setFromString(event.target.value);
|
|
105
|
-
};
|
|
106
|
-
static {
|
|
107
|
-
setComponentTemplate(precompileTemplate("\n {{yield (hash stars=this.stars total=this.stars.length handleClick=this.handleClick handleChange=this.handleChange setRating=this.setRating value=this.value) (hash total=this.stars.length value=this.value)}}\n ", {
|
|
108
|
-
strictMode: true,
|
|
109
|
-
scope: () => ({
|
|
110
|
-
hash
|
|
111
|
-
})
|
|
112
|
-
}), this);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
class Rating extends Component {
|
|
117
|
-
name = `rating-${uniqueId()}`;
|
|
118
|
-
get icon() {
|
|
119
|
-
return this.args.icon ?? "★";
|
|
120
|
-
}
|
|
121
|
-
get isInteractive() {
|
|
122
|
-
return this.args.interactive ?? true;
|
|
123
|
-
}
|
|
124
|
-
get isChangeable() {
|
|
125
|
-
const readonly = this.args.readonly ?? false;
|
|
126
|
-
return !readonly && this.isInteractive;
|
|
127
|
-
}
|
|
128
|
-
get isReadonly() {
|
|
129
|
-
return !this.isChangeable;
|
|
130
|
-
}
|
|
131
|
-
get needsDescription() {
|
|
132
|
-
return !this.isInteractive;
|
|
133
|
-
}
|
|
134
|
-
static {
|
|
135
|
-
setComponentTemplate(precompileTemplate("\n <RatingState @max={{@max}} @value={{@value}} @name={{this.name}} @readonly={{this.isReadonly}} @onChange={{@onChange}} as |r publicState|>\n <fieldset class=\"ember-primitives__rating\" data-total={{r.total}} data-value={{r.value}} data-readonly={{this.isReadonly}} {{!-- We use event delegation, this isn't a primary interactive -- we're capturing events from inputs --}} {{!-- template-lint-disable no-invalid-interactive --}} {{on \"click\" r.handleClick}} ...attributes>\n {{#let (component Stars stars=r.stars icon=this.icon isReadonly=this.isReadonly name=this.name total=r.total currentValue=r.value) as |RatingStars|}}\n\n {{#if (has-block)}}\n {{yield (hash max=r.total total=r.total value=r.value name=this.name isReadonly=this.isReadonly isChangeable=this.isChangeable Stars=RatingStars Range=(component RatingRange max=r.total value=r.value name=this.name handleChange=r.handleChange))}}\n {{else}}\n {{#if this.needsDescription}}\n {{#if (has-block \"label\")}}\n {{yield publicState to=\"label\"}}\n {{else}}\n <span visually-hidden class=\"ember-primitives__rating__label\">Rated\n {{r.value}}\n out of\n {{r.total}}</span>\n {{/if}}\n {{else}}\n {{#if (has-block \"label\")}}\n <legend>\n {{yield publicState to=\"label\"}}\n </legend>\n {{/if}}\n {{/if}}\n\n <RatingStars />\n {{/if}}\n {{/let}}\n\n </fieldset>\n </RatingState>\n ", {
|
|
136
|
-
strictMode: true,
|
|
137
|
-
scope: () => ({
|
|
138
|
-
RatingState,
|
|
139
|
-
on,
|
|
140
|
-
Stars,
|
|
141
|
-
hash,
|
|
142
|
-
RatingRange
|
|
143
|
-
})
|
|
144
|
-
}), this);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export { Rating as R };
|
|
149
|
-
//# sourceMappingURL=rating-D052JWRa.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rating-D052JWRa.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils-C5796IKA.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|