ember-primitives 0.25.0 → 0.26.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.
@@ -0,0 +1,81 @@
1
+ import './styles.css';
2
+ import Component from '@glimmer/component';
3
+ type ScrollBehavior = 'auto' | 'smooth' | 'instant';
4
+ export interface Signature {
5
+ Args: {
6
+ /**
7
+ * The distance in pixels between each item in the slider.
8
+ */
9
+ gap?: number;
10
+ /**
11
+ * The distance from the edge of the container to the first and last item, this allows
12
+ * the contents to visually overflow the container
13
+ */
14
+ offset?: number;
15
+ /**
16
+ * The scroll behavior to use when scrolling the slider. Defaults to smooth.
17
+ */
18
+ scrollBehavior?: ScrollBehavior;
19
+ };
20
+ Blocks: {
21
+ /**
22
+ * The header block is where the header content is placed.
23
+ */
24
+ header: [];
25
+ /**
26
+ * The content block is where the items that will be scrolled are placed.
27
+ */
28
+ content: [];
29
+ /**
30
+ * The controls block is where the left and right buttons are placed.
31
+ */
32
+ controls: [
33
+ {
34
+ /**
35
+ * Whether the slider can scroll.
36
+ */
37
+ canScroll: boolean;
38
+ /**
39
+ * Whether the slider cannot scroll left.
40
+ */
41
+ cannotScrollLeft: boolean;
42
+ /**
43
+ * Whether the slider cannot scroll right.
44
+ */
45
+ cannotScrollRight: boolean;
46
+ /**
47
+ * The function to scroll the slider left.
48
+ */
49
+ scrollLeft: () => void;
50
+ /**
51
+ * The function to scroll the slider right.
52
+ */
53
+ scrollRight: () => void;
54
+ }
55
+ ];
56
+ };
57
+ Element: HTMLElement;
58
+ }
59
+ export declare class Zoetrope extends Component<Signature> {
60
+ scrollerElement: HTMLElement | null;
61
+ currentlyScrolled: number;
62
+ scrollWidth: number;
63
+ offsetWidth: number;
64
+ private setCSSVariables;
65
+ scrollerWaiter: unknown;
66
+ noScrollWaiter: () => void;
67
+ private configureScroller;
68
+ private tabListener;
69
+ private scrollListener;
70
+ get offset(): number;
71
+ get gap(): number;
72
+ get canScroll(): boolean;
73
+ get cannotScrollLeft(): boolean;
74
+ get cannotScrollRight(): boolean;
75
+ get scrollBehavior(): ScrollBehavior;
76
+ scrollLeft: () => void;
77
+ scrollRight: () => void;
78
+ private findOverflowingElement;
79
+ }
80
+ export default Zoetrope;
81
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/zoetrope/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAEtB,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAS3C,KAAK,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEpD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE;QACJ;;WAEG;QACH,GAAG,CAAC,EAAE,MAAM,CAAC;QAEb;;;WAGG;QACH,MAAM,CAAC,EAAE,MAAM,CAAC;QAEhB;;WAEG;QACH,cAAc,CAAC,EAAE,cAAc,CAAC;KACjC,CAAC;IACF,MAAM,EAAE;QACN;;WAEG;QACH,MAAM,EAAE,EAAE,CAAC;QAEX;;WAEG;QACH,OAAO,EAAE,EAAE,CAAC;QAEZ;;WAEG;QACH,QAAQ,EAAE;YACR;gBACE;;mBAEG;gBACH,SAAS,EAAE,OAAO,CAAC;gBAEnB;;mBAEG;gBACH,gBAAgB,EAAE,OAAO,CAAC;gBAE1B;;mBAEG;gBACH,iBAAiB,EAAE,OAAO,CAAC;gBAE3B;;mBAEG;gBACH,UAAU,EAAE,MAAM,IAAI,CAAC;gBAEvB;;mBAEG;gBACH,WAAW,EAAE,MAAM,IAAI,CAAC;aACzB;SACF,CAAC;KACH,CAAC;IACF,OAAO,EAAE,WAAW,CAAC;CACtB;AAMD,qBAAa,QAAS,SAAQ,SAAS,CAAC,SAAS,CAAC;IACvC,eAAe,EAAE,WAAW,GAAG,IAAI,CAAQ;IAC3C,iBAAiB,SAAK;IACtB,WAAW,SAAK;IAChB,WAAW,SAAK;IAEzB,OAAO,CAAC,eAAe,CAKrB;IAEF,cAAc,UAA2B;IACzC,cAAc,aAEZ;IAEF,OAAO,CAAC,iBAAiB,CAwBtB;IAEH,OAAO,CAAC,WAAW,CAyCjB;IAEF,OAAO,CAAC,cAAc,CAEpB;IAEF,IAAI,MAAM,WAET;IAED,IAAI,GAAG,WAEN;IAED,IAAI,SAAS,YAEZ;IAED,IAAI,gBAAgB,YAEnB;IAED,IAAI,iBAAiB,YAEpB;IAED,IAAI,cAAc,IAAI,cAAc,CAMnC;IAED,UAAU,aA0CR;IAEF,WAAW,aAgCT;IAEF,OAAO,CAAC,sBAAsB;CA0H/B;AAED,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { Zoetrope } from "./zoetrope/index";
2
+ //# sourceMappingURL=zoetrope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zoetrope.d.ts","sourceRoot":"","sources":["../../src/components/zoetrope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC"}
@@ -18,6 +18,7 @@ export { Shadowed } from "./components/shadowed";
18
18
  export { Switch } from "./components/switch";
19
19
  export { Toggle } from "./components/toggle";
20
20
  export { ToggleGroup } from "./components/toggle-group";
21
+ export { Zoetrope } from "./components/zoetrope/index";
21
22
  export * from './helpers.ts';
22
23
  export type { default as SetupService } from './services/ember-primitives/setup.ts';
23
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,YAAY,EACV,iCAAiC,EACjC,gCAAgC,EAChC,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,cAAc,cAAc,CAAC;AAC7B,YAAY,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,sCAAsC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,YAAY,EACV,iCAAiC,EACjC,gCAAgC,EAChC,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAC3D,cAAc,cAAc,CAAC;AAC7B,YAAY,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,sCAAsC,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export { fillOTP } from './otp.ts';
2
2
  export { getRouter, setupRouting } from './routing.ts';
3
+ export { ZoetropeHelper } from './zoetrope.ts';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-support/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-support/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare class ZoetropeHelper {
2
+ parentSelector: string;
3
+ constructor(parentSelector?: string);
4
+ scrollLeft(): Promise<void>;
5
+ scrollRight(): Promise<void>;
6
+ visibleItems(): Element[];
7
+ visibleItemCount(): number;
8
+ }
9
+ //# sourceMappingURL=zoetrope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zoetrope.d.ts","sourceRoot":"","sources":["../../src/test-support/zoetrope.ts"],"names":[],"mappings":"AAGA,qBAAa,cAAc;IACzB,cAAc,SAAiC;gBAEnC,cAAc,CAAC,EAAE,MAAM;IAM7B,UAAU;IAIV,WAAW;IAIjB,YAAY;IA2BZ,gBAAgB;CAGjB"}
@@ -0,0 +1,267 @@
1
+ import './styles.css';
2
+ import Component from '@glimmer/component';
3
+ import { tracked } from '@glimmer/tracking';
4
+ import { hash } from '@ember/helper';
5
+ import { on } from '@ember/modifier';
6
+ import { buildWaiter, waitForPromise } from '@ember/test-waiters';
7
+ import { macroCondition, isTesting } from '@embroider/macros';
8
+ import { modifier } from 'ember-modifier';
9
+ import { precompileTemplate } from '@ember/template-compilation';
10
+ import { setComponentTemplate } from '@ember/component';
11
+ import { g, i } from 'decorator-transforms/runtime';
12
+
13
+ const testWaiter = buildWaiter('ember-primitive:zoetrope-waiter');
14
+ const DEFAULT_GAP = 8;
15
+ const DEFAULT_OFFSET = 0;
16
+ class Zoetrope extends Component {
17
+ static {
18
+ g(this.prototype, "scrollerElement", [tracked], function () {
19
+ return null;
20
+ });
21
+ }
22
+ #scrollerElement = (i(this, "scrollerElement"), void 0);
23
+ static {
24
+ g(this.prototype, "currentlyScrolled", [tracked], function () {
25
+ return 0;
26
+ });
27
+ }
28
+ #currentlyScrolled = (i(this, "currentlyScrolled"), void 0);
29
+ static {
30
+ g(this.prototype, "scrollWidth", [tracked], function () {
31
+ return 0;
32
+ });
33
+ }
34
+ #scrollWidth = (i(this, "scrollWidth"), void 0);
35
+ static {
36
+ g(this.prototype, "offsetWidth", [tracked], function () {
37
+ return 0;
38
+ });
39
+ }
40
+ #offsetWidth = (i(this, "offsetWidth"), void 0);
41
+ setCSSVariables = modifier((element1, _1, {
42
+ gap: gap1,
43
+ offset: offset1
44
+ }) => {
45
+ if (gap1) element1.style.setProperty('--zoetrope-gap', `${gap1}px`);
46
+ if (offset1) element1.style.setProperty('--zoetrope-offset', `${offset1}px`);
47
+ });
48
+ scrollerWaiter = testWaiter.beginAsync();
49
+ noScrollWaiter = () => {
50
+ testWaiter.endAsync(this.scrollerWaiter);
51
+ };
52
+ configureScroller = modifier(element1 => {
53
+ this.scrollerElement = element1;
54
+ this.currentlyScrolled = element1.scrollLeft;
55
+ const zoetropeResizeObserver1 = new ResizeObserver(() => {
56
+ this.scrollWidth = element1.scrollWidth;
57
+ this.offsetWidth = element1.offsetWidth;
58
+ });
59
+ zoetropeResizeObserver1.observe(element1);
60
+ element1.addEventListener('scroll', this.scrollListener, {
61
+ passive: true
62
+ });
63
+ element1.addEventListener('keydown', this.tabListener);
64
+ requestAnimationFrame(() => {
65
+ testWaiter.endAsync(this.scrollerWaiter);
66
+ });
67
+ return () => {
68
+ element1.removeEventListener('scroll', this.scrollListener);
69
+ element1.removeEventListener('keydown', this.tabListener);
70
+ zoetropeResizeObserver1.unobserve(element1);
71
+ };
72
+ });
73
+ tabListener = event1 => {
74
+ const target1 = event1.target;
75
+ const {
76
+ key: key1,
77
+ shiftKey: shiftKey1
78
+ } = event1;
79
+ if (!this.scrollerElement || this.scrollerElement === target1) {
80
+ return;
81
+ }
82
+ if (key1 !== 'Tab') {
83
+ return;
84
+ }
85
+ const nextElement1 = target1.nextElementSibling;
86
+ const previousElement1 = target1.previousElementSibling;
87
+ if (!shiftKey1 && !nextElement1 || shiftKey1 && !previousElement1) {
88
+ return;
89
+ }
90
+ event1.preventDefault();
91
+ let newTarget1 = null;
92
+ if (shiftKey1) {
93
+ newTarget1 = previousElement1;
94
+ } else {
95
+ newTarget1 = nextElement1;
96
+ }
97
+ if (!newTarget1) {
98
+ return;
99
+ }
100
+ newTarget1?.focus({
101
+ preventScroll: true
102
+ });
103
+ const rect1 = getRelativeBoundingClientRect(newTarget1, this.scrollerElement);
104
+ this.scrollerElement?.scrollBy({
105
+ left: rect1.left,
106
+ behavior: this.scrollBehavior
107
+ });
108
+ };
109
+ scrollListener = () => {
110
+ this.currentlyScrolled = this.scrollerElement?.scrollLeft || 0;
111
+ };
112
+ get offset() {
113
+ return this.args.offset ?? DEFAULT_OFFSET;
114
+ }
115
+ get gap() {
116
+ return this.args.gap ?? DEFAULT_GAP;
117
+ }
118
+ get canScroll() {
119
+ return this.scrollWidth > this.offsetWidth + this.offset;
120
+ }
121
+ get cannotScrollLeft() {
122
+ return this.currentlyScrolled <= this.offset;
123
+ }
124
+ get cannotScrollRight() {
125
+ return this.scrollWidth - this.offsetWidth - this.offset < this.currentlyScrolled;
126
+ }
127
+ get scrollBehavior() {
128
+ if (macroCondition(isTesting())) {
129
+ return 'instant';
130
+ }
131
+ return this.args.scrollBehavior || 'smooth';
132
+ }
133
+ scrollLeft = () => {
134
+ if (!(this.scrollerElement instanceof HTMLElement)) {
135
+ return;
136
+ }
137
+ const {
138
+ firstChild: firstChild1
139
+ } = this.findOverflowingElement();
140
+ if (!firstChild1) {
141
+ return;
142
+ }
143
+ const children1 = [...this.scrollerElement.children];
144
+ const firstChildIndex1 = children1.indexOf(firstChild1);
145
+ let targetElement1 = firstChild1;
146
+ let accumalatedWidth1 = 0;
147
+ for (let i1 = firstChildIndex1; i1 >= 0; i1--) {
148
+ const child1 = children1[i1];
149
+ if (!(child1 instanceof HTMLElement)) {
150
+ continue;
151
+ }
152
+ accumalatedWidth1 += child1.offsetWidth + this.gap;
153
+ if (accumalatedWidth1 >= this.offsetWidth) {
154
+ break;
155
+ }
156
+ targetElement1 = child1;
157
+ }
158
+ const rect1 = getRelativeBoundingClientRect(targetElement1, this.scrollerElement);
159
+ this.scrollerElement.scrollBy({
160
+ left: rect1.left,
161
+ behavior: this.scrollBehavior
162
+ });
163
+ waitForPromise(new Promise(requestAnimationFrame));
164
+ };
165
+ scrollRight = () => {
166
+ if (!(this.scrollerElement instanceof HTMLElement)) {
167
+ return;
168
+ }
169
+ const {
170
+ activeSlide: activeSlide1,
171
+ lastChild: lastChild1
172
+ } = this.findOverflowingElement();
173
+ if (!lastChild1) {
174
+ return;
175
+ }
176
+ let rect1 = getRelativeBoundingClientRect(lastChild1, this.scrollerElement);
177
+ // If the card is larger than the container then skip to the next card
178
+ if (rect1.width > this.offsetWidth && activeSlide1 === lastChild1) {
179
+ const children1 = [...this.scrollerElement.children];
180
+ const lastChildIndex1 = children1.indexOf(lastChild1);
181
+ const targetElement1 = children1[lastChildIndex1 + 1];
182
+ if (!targetElement1) {
183
+ return;
184
+ }
185
+ rect1 = getRelativeBoundingClientRect(targetElement1, this.scrollerElement);
186
+ }
187
+ this.scrollerElement?.scrollBy({
188
+ left: rect1.left,
189
+ behavior: this.scrollBehavior
190
+ });
191
+ waitForPromise(new Promise(requestAnimationFrame));
192
+ };
193
+ findOverflowingElement() {
194
+ const returnObj1 = {
195
+ firstChild: undefined,
196
+ lastChild: undefined,
197
+ activeSlide: undefined
198
+ };
199
+ if (!this.scrollerElement) {
200
+ return returnObj1;
201
+ }
202
+ const parentElement1 = this.scrollerElement.parentElement;
203
+ if (!parentElement1) {
204
+ return returnObj1;
205
+ }
206
+ const containerRect1 = getRelativeBoundingClientRect(this.scrollerElement, parentElement1);
207
+ const children1 = [...this.scrollerElement.children];
208
+ // Find the first child that is overflowing the left edge of the container
209
+ // and the last child that is overflowing the right edge of the container
210
+ for (const child1 of children1) {
211
+ const rect1 = getRelativeBoundingClientRect(child1, this.scrollerElement);
212
+ if (rect1.right + this.gap >= containerRect1.left && !returnObj1.firstChild) {
213
+ returnObj1.firstChild = child1;
214
+ }
215
+ if (rect1.left >= this.offset && !returnObj1.activeSlide) {
216
+ returnObj1.activeSlide = child1;
217
+ }
218
+ if (rect1.right >= containerRect1.width && !returnObj1.lastChild) {
219
+ returnObj1.lastChild = child1;
220
+ break;
221
+ }
222
+ }
223
+ if (!returnObj1.firstChild) {
224
+ returnObj1.firstChild = children1[0];
225
+ }
226
+ if (!returnObj1.lastChild) {
227
+ returnObj1.lastChild = children1[children1.length - 1];
228
+ }
229
+ return returnObj1;
230
+ }
231
+ static {
232
+ setComponentTemplate(precompileTemplate("\n <section class=\"ember-primitives__zoetrope\" {{this.setCSSVariables gap=this.gap offset=this.offset}} ...attributes>\n {{#if (has-block \"header\")}}\n <div class=\"ember-primitives__zoetrope__header\">\n {{yield to=\"header\"}}\n </div>\n {{/if}}\n\n {{#if (has-block \"controls\")}}\n {{yield (hash cannotScrollLeft=this.cannotScrollLeft cannotScrollRight=this.cannotScrollRight canScroll=this.canScroll scrollLeft=this.scrollLeft scrollRight=this.scrollRight) to=\"controls\"}}\n {{else}}\n {{#if this.canScroll}}\n <div class=\"ember-primitives__zoetrope__controls\">\n <button type=\"button\" {{on \"click\" this.scrollLeft}} disabled={{this.cannotScrollLeft}}>Left</button>\n\n <button type=\"button\" {{on \"click\" this.scrollRight}} disabled={{this.cannotScrollRight}}>Right</button>\n </div>\n {{/if}}\n {{/if}}\n {{#if (has-block \"content\")}}\n <div class=\"ember-primitives__zoetrope__scroller\" {{this.configureScroller}}>\n {{yield to=\"content\"}}\n </div>\n {{else}}\n {{(this.noScrollWaiter)}}\n {{/if}}\n </section>\n ", {
233
+ strictMode: true,
234
+ scope: () => ({
235
+ hash,
236
+ on
237
+ })
238
+ }), this);
239
+ }
240
+ }
241
+ function getRelativeBoundingClientRect(childElement1, parentElement1) {
242
+ if (!childElement1 || !parentElement1) {
243
+ throw new Error('Both childElement and parentElement must be provided');
244
+ }
245
+ // Get the bounding rect of the child and parent elements
246
+ const childRect1 = childElement1.getBoundingClientRect();
247
+ const parentRect1 = parentElement1.getBoundingClientRect();
248
+ // Get computed styles of the parent element
249
+ const parentStyles1 = window.getComputedStyle(parentElement1);
250
+ // Extract and parse parent's padding, and border, for all sides
251
+ const parentPaddingTop1 = parseFloat(parentStyles1.paddingTop);
252
+ const parentPaddingLeft1 = parseFloat(parentStyles1.paddingLeft);
253
+ const parentBorderTopWidth1 = parseFloat(parentStyles1.borderTopWidth);
254
+ const parentBorderLeftWidth1 = parseFloat(parentStyles1.borderLeftWidth);
255
+ // Calculate child's position relative to parent's content area (including padding and borders)
256
+ return {
257
+ width: childRect1.width,
258
+ height: childRect1.height,
259
+ top: childRect1.top - parentRect1.top - parentBorderTopWidth1 - parentPaddingTop1,
260
+ left: childRect1.left - parentRect1.left - parentBorderLeftWidth1 - parentPaddingLeft1,
261
+ bottom: childRect1.top - parentRect1.top - parentBorderTopWidth1 - parentPaddingTop1 + childRect1.height,
262
+ right: childRect1.left - parentRect1.left - parentBorderLeftWidth1 - parentPaddingLeft1 + childRect1.width
263
+ };
264
+ }
265
+
266
+ export { Zoetrope, Zoetrope as default };
267
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,45 @@
1
+ .ember-primitives__zoetrope {
2
+ display: flex;
3
+ flex-wrap: wrap;
4
+ position: relative;
5
+ width: 100%;
6
+ }
7
+
8
+ .ember-primitives__zoetrope__header {
9
+ align-items: center;
10
+ display: flex;
11
+ flex: 1;
12
+ justify-content: space-between;
13
+ padding-left: var(--zoetrope-offset, 0);
14
+ }
15
+
16
+ .ember-primitives__zoetrope__controls {
17
+ align-items: center;
18
+ display: flex;
19
+ padding-right: var(--zoetrope-offset, 0);
20
+ gap: 4px;
21
+ }
22
+
23
+ .ember-primitives__zoetrope__scroller {
24
+ display: flex;
25
+ flex-flow: row nowrap;
26
+ gap: var(--zoetrope-gap, 8px);
27
+ overflow: scroll visible;
28
+ padding: 8px var(--zoetrope-offset, 0);
29
+ scroll-behavior: smooth;
30
+ scroll-padding-left: var(--zoetrope-offset, 0);
31
+ scroll-snap-type: x mandatory;
32
+ scrollbar-color: transparent transparent;
33
+ scrollbar-width: none;
34
+ width: 100%;
35
+
36
+ & > * {
37
+ flex-shrink: 0;
38
+ scroll-snap-align: start;
39
+ }
40
+
41
+ &:focus {
42
+ outline: 1px dotted var(--ekto-colors-focus);
43
+ outline-offset: -1px;
44
+ }
45
+ }
@@ -0,0 +1,2 @@
1
+ export { Zoetrope } from './zoetrope/index.js';
2
+ //# sourceMappingURL=zoetrope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zoetrope.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -18,6 +18,7 @@ export { Shadowed } from './components/shadowed.js';
18
18
  export { Switch } from './components/switch.js';
19
19
  export { Toggle } from './components/toggle.js';
20
20
  export { ToggleGroup } from './components/toggle-group.js';
21
+ export { Zoetrope } from './components/zoetrope/index.js';
21
22
  export { link } from './helpers/link.js';
22
23
  export { service } from './helpers/service.js';
23
24
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * DANGER: this is a *barrel file*\n *\n * It forces the whole library to be loaded and all dependencies.\n *\n * If you have a small app, you probably don't want to import from here -- instead import from each sub-path.\n */\nimport { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';\n\nif (macroCondition(isDevelopingApp())) {\n importSync('./components/violations.css');\n}\n\nexport { Accordion } from './components/accordion.gts';\nexport type {\n AccordionContentExternalSignature,\n AccordionHeaderExternalSignature,\n AccordionItemExternalSignature,\n AccordionTriggerExternalSignature,\n} from './components/accordion/public.ts';\nexport { Avatar } from './components/avatar.gts';\nexport { Dialog, Dialog as Modal } from './components/dialog.gts';\nexport { ExternalLink } from './components/external-link.gts';\nexport { Form } from './components/form.gts';\nexport { StickyFooter } from './components/layout/sticky-footer.gts';\nexport { Link } from './components/link.gts';\nexport { Menu } from './components/menu.gts';\nexport { OTP, OTPInput } from './components/one-time-password/index.gts';\nexport { Popover } from './components/popover.gts';\nexport { Portal } from './components/portal.gts';\nexport { PortalTargets } from './components/portal-targets.gts';\nexport { TARGETS as PORTALS } from './components/portal-targets.gts';\nexport { Progress } from './components/progress.gts';\nexport { Scroller } from './components/scroller.gts';\nexport { Shadowed } from './components/shadowed.gts';\nexport { Switch } from './components/switch.gts';\nexport { Toggle } from './components/toggle.gts';\nexport { ToggleGroup } from './components/toggle-group.gts';\nexport * from './helpers.ts';\nexport type { default as SetupService } from './services/ember-primitives/setup.ts';\n"],"names":["macroCondition","isDevelopingApp","importSync"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,IAAIA,cAAc,CAACC,eAAe,EAAE,CAAC,EAAE;EACrCC,UAAU,CAAC,6BAA6B,CAAC,CAAA;AAC3C"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * DANGER: this is a *barrel file*\n *\n * It forces the whole library to be loaded and all dependencies.\n *\n * If you have a small app, you probably don't want to import from here -- instead import from each sub-path.\n */\nimport { importSync, isDevelopingApp, macroCondition } from '@embroider/macros';\n\nif (macroCondition(isDevelopingApp())) {\n importSync('./components/violations.css');\n}\n\nexport { Accordion } from './components/accordion.gts';\nexport type {\n AccordionContentExternalSignature,\n AccordionHeaderExternalSignature,\n AccordionItemExternalSignature,\n AccordionTriggerExternalSignature,\n} from './components/accordion/public.ts';\nexport { Avatar } from './components/avatar.gts';\nexport { Dialog, Dialog as Modal } from './components/dialog.gts';\nexport { ExternalLink } from './components/external-link.gts';\nexport { Form } from './components/form.gts';\nexport { StickyFooter } from './components/layout/sticky-footer.gts';\nexport { Link } from './components/link.gts';\nexport { Menu } from './components/menu.gts';\nexport { OTP, OTPInput } from './components/one-time-password/index.gts';\nexport { Popover } from './components/popover.gts';\nexport { Portal } from './components/portal.gts';\nexport { PortalTargets } from './components/portal-targets.gts';\nexport { TARGETS as PORTALS } from './components/portal-targets.gts';\nexport { Progress } from './components/progress.gts';\nexport { Scroller } from './components/scroller.gts';\nexport { Shadowed } from './components/shadowed.gts';\nexport { Switch } from './components/switch.gts';\nexport { Toggle } from './components/toggle.gts';\nexport { ToggleGroup } from './components/toggle-group.gts';\nexport { Zoetrope } from './components/zoetrope/index.gts';\nexport * from './helpers.ts';\nexport type { default as SetupService } from './services/ember-primitives/setup.ts';\n"],"names":["macroCondition","isDevelopingApp","importSync"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA,IAAIA,cAAc,CAACC,eAAe,EAAE,CAAC,EAAE;EACrCC,UAAU,CAAC,6BAA6B,CAAC,CAAA;AAC3C"}
@@ -1,3 +1,4 @@
1
1
  export { fillOTP } from './otp.js';
2
2
  export { getRouter, setupRouting } from './routing.js';
3
+ export { ZoetropeHelper } from './zoetrope.js';
3
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,42 @@
1
+ import { click } from '@ember/test-helpers';
2
+
3
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
4
+ class ZoetropeHelper {
5
+ parentSelector = '.ember-primitives__zoetrope';
6
+ constructor(parentSelector) {
7
+ if (parentSelector) {
8
+ this.parentSelector = parentSelector;
9
+ }
10
+ }
11
+ async scrollLeft() {
12
+ await click(`${this.parentSelector} .ember-primitives__zoetrope__controls button:first-child`);
13
+ }
14
+ async scrollRight() {
15
+ await click(`${this.parentSelector} .ember-primitives__zoetrope__controls button:last-child`);
16
+ }
17
+ visibleItems() {
18
+ const zoetropeContent = document.querySelectorAll(`${this.parentSelector} .ember-primitives__zoetrope__scroller > *`);
19
+ let firstVisibleItemIndex = -1;
20
+ let lastVisibleItemIndex = -1;
21
+ for (let i = 0; i < zoetropeContent.length; i++) {
22
+ const item = zoetropeContent[i];
23
+ const rect = item.getBoundingClientRect();
24
+ const parentRect = item.parentElement.getBoundingClientRect();
25
+ if (rect.right >= parentRect?.left && rect.left <= parentRect?.right) {
26
+ if (firstVisibleItemIndex === -1) {
27
+ firstVisibleItemIndex = i;
28
+ }
29
+ lastVisibleItemIndex = i;
30
+ } else if (firstVisibleItemIndex !== -1) {
31
+ break;
32
+ }
33
+ }
34
+ return Array.from(zoetropeContent).slice(firstVisibleItemIndex, lastVisibleItemIndex + 1);
35
+ }
36
+ visibleItemCount() {
37
+ return this.visibleItems().length;
38
+ }
39
+ }
40
+
41
+ export { ZoetropeHelper };
42
+ //# sourceMappingURL=zoetrope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zoetrope.js","sources":["../../src/test-support/zoetrope.ts"],"sourcesContent":["/* 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":["ZoetropeHelper","parentSelector","constructor","scrollLeft","click","scrollRight","visibleItems","zoetropeContent","document","querySelectorAll","firstVisibleItemIndex","lastVisibleItemIndex","i","length","item","rect","getBoundingClientRect","parentRect","parentElement","right","left","Array","from","slice","visibleItemCount"],"mappings":";;AAAA;AAGO,MAAMA,cAAc,CAAC;AAC1BC,EAAAA,cAAc,GAAG,6BAA6B,CAAA;EAE9CC,WAAWA,CAACD,cAAuB,EAAE;AACnC,IAAA,IAAIA,cAAc,EAAE;MAClB,IAAI,CAACA,cAAc,GAAGA,cAAc,CAAA;AACtC,KAAA;AACF,GAAA;EAEA,MAAME,UAAUA,GAAG;AACjB,IAAA,MAAMC,KAAK,CAAC,CAAA,EAAG,IAAI,CAACH,cAAc,2DAA2D,CAAC,CAAA;AAChG,GAAA;EAEA,MAAMI,WAAWA,GAAG;AAClB,IAAA,MAAMD,KAAK,CAAC,CAAA,EAAG,IAAI,CAACH,cAAc,0DAA0D,CAAC,CAAA;AAC/F,GAAA;AAEAK,EAAAA,YAAYA,GAAG;IACb,MAAMC,eAAe,GAAGC,QAAQ,CAACC,gBAAgB,CAC/C,CAAA,EAAG,IAAI,CAACR,cAAc,CAAA,0CAAA,CACxB,CAAC,CAAA;IAED,IAAIS,qBAAqB,GAAG,CAAC,CAAC,CAAA;IAC9B,IAAIC,oBAAoB,GAAG,CAAC,CAAC,CAAA;AAE7B,IAAA,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGL,eAAe,CAACM,MAAM,EAAED,CAAC,EAAE,EAAE;AAC/C,MAAA,MAAME,IAAI,GAAGP,eAAe,CAACK,CAAC,CAAE,CAAA;AAChC,MAAA,MAAMG,IAAI,GAAGD,IAAI,CAACE,qBAAqB,EAAE,CAAA;MACzC,MAAMC,UAAU,GAAGH,IAAI,CAACI,aAAa,CAAEF,qBAAqB,EAAE,CAAA;AAE9D,MAAA,IAAID,IAAI,CAACI,KAAK,IAAIF,UAAU,EAAEG,IAAI,IAAIL,IAAI,CAACK,IAAI,IAAIH,UAAU,EAAEE,KAAK,EAAE;AACpE,QAAA,IAAIT,qBAAqB,KAAK,CAAC,CAAC,EAAE;AAChCA,UAAAA,qBAAqB,GAAGE,CAAC,CAAA;AAC3B,SAAA;AAEAD,QAAAA,oBAAoB,GAAGC,CAAC,CAAA;AAC1B,OAAC,MAAM,IAAIF,qBAAqB,KAAK,CAAC,CAAC,EAAE;AACvC,QAAA,MAAA;AACF,OAAA;AACF,KAAA;AAEA,IAAA,OAAOW,KAAK,CAACC,IAAI,CAACf,eAAe,CAAC,CAACgB,KAAK,CAACb,qBAAqB,EAAEC,oBAAoB,GAAG,CAAC,CAAC,CAAA;AAC3F,GAAA;AAEAa,EAAAA,gBAAgBA,GAAG;AACjB,IAAA,OAAO,IAAI,CAAClB,YAAY,EAAE,CAACO,MAAM,CAAA;AACnC,GAAA;AACF;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-primitives",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Making apps easier to build",
5
5
  "sideEffects": [
6
6
  "*.css"