ember-container-query 2.1.0 → 3.0.0-alpha.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 @@
1
+ [{"/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/navigation-menu.css":"1","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/styles/album.css":"2","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/styles/app.css":"3","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/styles/dashboard.css":"4","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/styles/form.css":"5","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/styles/index.css":"6","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/styles/application.css":"7","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/styles/not-found.css":"8","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-4.css":"9","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/ui/page.css":"10","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/tracks/table.css":"11","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/ui/form.css":"12","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-1.css":"13","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/tracks/list.css":"14","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-5.css":"15","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-2.css":"16","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-3.css":"17","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/ui/form/checkbox.css":"18","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-1/item.css":"19","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/ui/form/field.css":"20","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/ui/form/textarea.css":"21","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-2/stacked-chart.css":"22","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-3/tour-schedule.css":"23","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/ui/form/information.css":"24","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-4/memo.css":"25","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/ui/form/input.css":"26","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-2/captions.css":"27","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-3/tour-schedule/responsive-image.css":"28","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-4/memo/body.css":"29","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-4/memo/actions.css":"30","/Users/isaaclee/Documents/GitHub/ember-container-query/tests/dummy/app/components/widgets/widget-4/memo/header.css":"31"},{"size":323,"mtime":1656746523373,"hashOfConfig":"32"},{"size":892,"mtime":1656746523421,"hashOfConfig":"32"},{"size":1494,"mtime":1670927594478,"hashOfConfig":"32"},{"size":1846,"mtime":1656746523430,"hashOfConfig":"32"},{"size":82,"mtime":1656746523432,"hashOfConfig":"32"},{"size":36,"mtime":1670927594479,"hashOfConfig":"32"},{"size":980,"mtime":1656746523427,"hashOfConfig":"32"},{"size":1299,"mtime":1656746523434,"hashOfConfig":"32"},{"size":400,"mtime":1656746523408,"hashOfConfig":"32"},{"size":306,"mtime":1656746523386,"hashOfConfig":"32"},{"size":106,"mtime":1656746523378,"hashOfConfig":"32"},{"size":324,"mtime":1656746523380,"hashOfConfig":"32"},{"size":797,"mtime":1656746523388,"hashOfConfig":"32"},{"size":323,"mtime":1656746523376,"hashOfConfig":"32"},{"size":657,"mtime":1656746523418,"hashOfConfig":"32"},{"size":439,"mtime":1656746523393,"hashOfConfig":"32"},{"size":268,"mtime":1656746523400,"hashOfConfig":"32"},{"size":566,"mtime":1653552800391,"hashOfConfig":"32"},{"size":243,"mtime":1656746523391,"hashOfConfig":"32"},{"size":1630,"mtime":1656746523382,"hashOfConfig":"32"},{"size":375,"mtime":1653552800412,"hashOfConfig":"32"},{"size":267,"mtime":1656746523397,"hashOfConfig":"32"},{"size":1570,"mtime":1656746523403,"hashOfConfig":"32"},{"size":225,"mtime":1656746523384,"hashOfConfig":"32"},{"size":937,"mtime":1656746523410,"hashOfConfig":"32"},{"size":360,"mtime":1653552800408,"hashOfConfig":"32"},{"size":2101,"mtime":1656746523395,"hashOfConfig":"32"},{"size":159,"mtime":1656746523405,"hashOfConfig":"32"},{"size":493,"mtime":1656746523414,"hashOfConfig":"32"},{"size":701,"mtime":1656746523412,"hashOfConfig":"32"},{"size":888,"mtime":1656746523416,"hashOfConfig":"32"},"187t81u"]
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+
3
+ /* eslint-disable-next-line n/no-unpublished-require */
4
+ const { browsers } = require('./tests/dummy/config/targets');
5
+
6
+ module.exports = {
7
+ extends: ['stylelint-config-standard'],
8
+ plugins: ['stylelint-no-unsupported-browser-features', 'stylelint-order'],
9
+ rules: {
10
+ /*
11
+ Customize plugins
12
+ */
13
+ 'order/properties-order': [
14
+ [
15
+ // Defined by ember-css-modules
16
+ 'composes',
17
+ ],
18
+ {
19
+ unspecified: 'bottomAlphabetical',
20
+ },
21
+ ],
22
+
23
+ 'plugin/no-unsupported-browser-features': [
24
+ true,
25
+ {
26
+ browsers,
27
+ ignore: [
28
+ // grid-template-columns falsely identified as multicolumn
29
+ 'multicolumn',
30
+ ],
31
+ },
32
+ ],
33
+
34
+ /*
35
+ Customize rules
36
+ */
37
+ 'declaration-block-no-redundant-longhand-properties': [
38
+ true,
39
+ {
40
+ ignoreShorthands: ['grid-gap', 'grid-template'],
41
+ },
42
+ ],
43
+
44
+ 'property-no-unknown': [
45
+ true,
46
+ {
47
+ ignoreProperties: [
48
+ // Defined by ember-css-modules
49
+ 'composes',
50
+ ],
51
+ },
52
+ ],
53
+
54
+ 'selector-pseudo-class-no-unknown': [
55
+ true,
56
+ {
57
+ ignorePseudoClasses: [
58
+ // Defined by ember-css-modules
59
+ 'global',
60
+ ],
61
+ },
62
+ ],
63
+ },
64
+ };
package/CHANGELOG.md CHANGED
@@ -1,3 +1,44 @@
1
+ ## 3.0.0-alpha.0 (2022-12-13)
2
+
3
+ ### Breaking Change
4
+ * [#135](https://github.com/ijlee2/ember-container-query/pull/135) Documented {{container-query}} modifier. Dropped support for Node 12 and Ember 3.24. ([@ijlee2](https://github.com/ijlee2))
5
+
6
+ ### Internal
7
+ * [#138](https://github.com/ijlee2/ember-container-query/pull/138) Updated development dependencies ([@ijlee2](https://github.com/ijlee2))
8
+ * [#137](https://github.com/ijlee2/ember-container-query/pull/137) Updated demo app ([@ijlee2](https://github.com/ijlee2))
9
+ * [#136](https://github.com/ijlee2/ember-container-query/pull/136) Reinstalled ember-cli-typescript ([@ijlee2](https://github.com/ijlee2))
10
+ * [#135](https://github.com/ijlee2/ember-container-query/pull/135) Documented {{container-query}} modifier. Dropped support for Node 12 and Ember 3.24. ([@ijlee2](https://github.com/ijlee2))
11
+ * [#131](https://github.com/ijlee2/ember-container-query/pull/131) Remove ember-cli-typescript. Enable enableTypeScriptTransform instead. ([@ijlee2](https://github.com/ijlee2))
12
+
13
+ ### Documentation
14
+ * [#137](https://github.com/ijlee2/ember-container-query/pull/137) Updated demo app ([@ijlee2](https://github.com/ijlee2))
15
+ * [#135](https://github.com/ijlee2/ember-container-query/pull/135) Documented {{container-query}} modifier. Dropped support for Node 12 and Ember 3.24. ([@ijlee2](https://github.com/ijlee2))
16
+ * [#134](https://github.com/ijlee2/ember-container-query/pull/134) Refactor tests ([@ijlee2](https://github.com/ijlee2))
17
+
18
+ ### Committers: 1
19
+ - Isaac Lee ([@ijlee2](https://github.com/ijlee2))
20
+
21
+
22
+ ## 2.1.1 (2022-12-02)
23
+
24
+ ### Bug Fix
25
+ * [#128](https://github.com/ijlee2/ember-container-query/pull/128) Replaced @ember/render-modifiers with ember-modifier ([@ijlee2](https://github.com/ijlee2))
26
+ * [#126](https://github.com/ijlee2/ember-container-query/pull/126) Listed ember-test-selectors as a dependency ([@ijlee2](https://github.com/ijlee2))
27
+
28
+ ### Enhancement
29
+ * [#128](https://github.com/ijlee2/ember-container-query/pull/128) Replaced @ember/render-modifiers with ember-modifier ([@ijlee2](https://github.com/ijlee2))
30
+
31
+ ### Internal
32
+ * [#133](https://github.com/ijlee2/ember-container-query/pull/133) Addressed ember-modifier deprecations ([@ijlee2](https://github.com/ijlee2))
33
+ * [#132](https://github.com/ijlee2/ember-container-query/pull/132) Updated dependencies to their latest version ([@ijlee2](https://github.com/ijlee2))
34
+ * [#128](https://github.com/ijlee2/ember-container-query/pull/128) Replaced @ember/render-modifiers with ember-modifier ([@ijlee2](https://github.com/ijlee2))
35
+ * [#125](https://github.com/ijlee2/ember-container-query/pull/125) Updated dependencies to their latest version ([@ijlee2](https://github.com/ijlee2))
36
+ * [#124](https://github.com/ijlee2/ember-container-query/pull/124) Installed stylelint to help with maintaining the demo app ([@ijlee2](https://github.com/ijlee2))
37
+
38
+ ### Committers: 1
39
+ - Isaac Lee ([@ijlee2](https://github.com/ijlee2))
40
+
41
+
1
42
  ## 2.1.0 (2022-06-03)
2
43
 
3
44
  ### Enhancement
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2022
3
+ Copyright (c) 2023 Isaac J. Lee
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
6
 
package/README.md CHANGED
@@ -14,37 +14,10 @@ Open the [demo app](https://ember-container-query.netlify.app/) to see `ember-co
14
14
  Installation
15
15
  ------------------------------------------------------------------------------
16
16
 
17
- ```
17
+ ```sh
18
18
  ember install ember-container-query
19
19
  ```
20
20
 
21
- <details>
22
- <summary>Use FastBoot? ⚠️</summary>
23
-
24
- This addon uses nullish coalescing operator `??`. If you use [FastBoot](https://github.com/ember-fastboot/ember-cli-fastboot) (with `Node < v14.0`) and only support [browsers that natively support `??`](https://v8.dev/features/nullish-coalescing#support), you will run into a build error:
25
-
26
- ```bash
27
- /var/folders/2z/93zyyhx13rs879qr8rzyxrb40000gn/T/broccoli-689520dxo26a682Mz/out-529-broccoli_merge_trees/assets/vendor.js:121232
28
- return this.args.features ?? {};
29
- ^
30
- SyntaxError: Unexpected token '?'
31
- ```
32
-
33
- To prevent this, please make sure to add `node: 'current'` to your `config/targets.js` file.
34
-
35
- ```javascript
36
- 'use strict';
37
-
38
- const browsers = [ ... ];
39
-
40
- module.exports = {
41
- browsers,
42
- node: 'current'
43
- };
44
- ```
45
-
46
- </details>
47
-
48
21
 
49
22
  Applications
50
23
  ------------------------------------------------------------------------------
@@ -137,6 +110,12 @@ The addon provides 1 Glimmer component and 3 helpers:
137
110
  - `{{cq-height}}`
138
111
  - `{{cq-width}}`
139
112
 
113
+ Starting `v2.1.1`, the addon extracts the core logic into a modifier. This lets you opt out of using the provided component.
114
+
115
+ - `{{container-query}}`
116
+
117
+ Expand the items below to learn more about the API.
118
+
140
119
 
141
120
  <details>
142
121
  <summary><code>&lt;ContainerQuery&gt;</code></summary>
@@ -199,6 +178,30 @@ All helpers accept these arguments:
199
178
  </details>
200
179
 
201
180
 
181
+ <details>
182
+ <summary><code>{{container-query}}</code></summary>
183
+
184
+ ### Arguments
185
+
186
+ You can pass these arguments to the modifier.
187
+
188
+ - `@dataAttributePrefix`
189
+ - `@debounce`
190
+ - `@features`
191
+
192
+ For more information, refer to [the arguments of `<ContainerQuery>` component](#arguments).
193
+
194
+
195
+ ### Outputs
196
+
197
+ The outputs are similar to [those of `<ContainerQuery>` component](#outputs).
198
+
199
+ Data attributes are automatically applied to the HTML element. To get `dimensions` and `features`, you will need to pass the argument `@onQuery` (a function) to the modifier.
200
+
201
+
202
+ </details>
203
+
204
+
202
205
  Example
203
206
  ------------------------------------------------------------------------------
204
207
 
@@ -207,7 +210,7 @@ Let's look at the code that created the video demo above.
207
210
  <details>
208
211
  <summary><code>app/templates/album.hbs</code></summary>
209
212
 
210
- ```handlebars
213
+ ```hbs
211
214
  <ContainerQuery
212
215
  @features={{hash
213
216
  large=(cq-width min=960)
@@ -248,7 +251,7 @@ Let's look at the code that created the video demo above.
248
251
  <details>
249
252
  <summary><code>app/components/tracks.hbs</code></summary>
250
253
 
251
- ```handlebars
254
+ ```hbs
252
255
  <ContainerQuery
253
256
  @features={{hash
254
257
  small=(cq-width max=480)
@@ -286,12 +289,9 @@ For more examples, I encourage you to check out the code for my demo app. It is
286
289
  Compatibility
287
290
  ------------------------------------------------------------------------------
288
291
 
289
- * Ember.js v3.24 or above<sup>1</sup>
290
- * Ember CLI v3.24 or above
291
- * Node.js v12 or above
292
- * Modern browsers<sup>1</sup> (IE 11 won't be supported)
293
-
294
- <sup>1. Until you can adopt Ember Octane and drop support for IE 11, I recommend using [`ember-fill-up`](https://github.com/chadian/ember-fill-up) to do container queries. The APIs are similar so your migration should be smooth. Chad Carbert and I will ensure that the addons are maintained side-by-side for some time.</sup>
292
+ * Ember.js v3.28 or above
293
+ * Ember CLI v3.28 or above
294
+ * Node.js v14 or above
295
295
 
296
296
 
297
297
  Contributing
@@ -2,17 +2,19 @@
2
2
  <Tag
3
3
  class="container-query"
4
4
  data-test-container-query
5
- {{did-insert this.queryContainer}}
6
- {{on-resize this.onResize}}
5
+ {{container-query
6
+ dataAttributePrefix=@dataAttributePrefix
7
+ debounce=@debounce
8
+ features=@features
9
+ onQuery=this.updateState
10
+ }}
7
11
  ...attributes
8
12
  >
9
- {{yield (hash
10
- features=this.queryResults
11
- dimensions=(hash
12
- aspectRatio=this.aspectRatio
13
- height=this.height
14
- width=this.width
13
+ {{yield
14
+ (hash
15
+ dimensions=this.dimensions
16
+ features=this.queryResults
15
17
  )
16
- )}}
18
+ }}
17
19
  </Tag>
18
20
  {{/let}}
@@ -1,21 +1,11 @@
1
1
  import { action } from '@ember/object';
2
2
  import Component from '@glimmer/component';
3
3
  import { tracked } from '@glimmer/tracking';
4
- import { debounce } from '@ember/runloop';
5
-
6
- type Metadata = {
7
- dimension: 'aspectRatio' | 'height' | 'width';
8
- max: number;
9
- min: number;
10
- };
11
-
12
- type Features = {
13
- [featureName: string]: Metadata;
14
- };
15
-
16
- type QueryResults = {
17
- [featureName: string]: boolean;
18
- };
4
+ import type {
5
+ Dimensions,
6
+ Features,
7
+ QueryResults,
8
+ } from 'ember-container-query/modifiers/container-query';
19
9
 
20
10
  interface ContainerQueryComponentArgs {
21
11
  dataAttributePrefix?: string;
@@ -25,81 +15,20 @@ interface ContainerQueryComponentArgs {
25
15
  }
26
16
 
27
17
  export default class ContainerQueryComponent extends Component<ContainerQueryComponentArgs> {
28
- @tracked queryResults = {} as QueryResults;
29
- @tracked aspectRatio?: number;
30
- @tracked height?: number;
31
- @tracked width?: number;
32
-
33
- get features(): Features {
34
- return this.args.features ?? {};
35
- }
36
-
37
- get dataAttributePrefix(): string {
38
- return this.args.dataAttributePrefix ?? 'container-query';
39
- }
40
-
41
- get debounce(): number {
42
- return this.args.debounce ?? 0;
43
- }
18
+ @tracked dimensions?: Dimensions;
19
+ @tracked queryResults?: QueryResults;
44
20
 
45
21
  // The dynamic tag is restricted to be immutable
46
22
  tagName = this.args.tagName ?? 'div';
47
23
 
48
- @action onResize(resizeObserverEntry: ResizeObserverEntry): void {
49
- const element = resizeObserverEntry.target;
50
-
51
- if (this.debounce > 0) {
52
- debounce(this, this.queryContainer, element, this.debounce);
53
- return;
54
- }
55
-
56
- this.queryContainer(element);
57
- }
58
-
59
- @action queryContainer(element: Element): void {
60
- this.measureDimensions(element);
61
- this.evaluateQueries();
62
- this.setDataAttributes(element);
63
- }
64
-
65
- measureDimensions(element: Element): void {
66
- this.height = element.clientHeight;
67
- this.width = element.clientWidth;
68
- this.aspectRatio = this.width / this.height;
69
- }
70
-
71
- evaluateQueries(): void {
72
- const queryResults = {} as QueryResults;
73
-
74
- for (const [featureName, metadata] of Object.entries(this.features)) {
75
- const { dimension, min, max } = metadata;
76
- const value = this[dimension]!;
77
-
78
- queryResults[featureName] = min <= value && value < max;
79
- }
80
-
24
+ @action updateState({
25
+ dimensions,
26
+ queryResults,
27
+ }: {
28
+ dimensions: Dimensions;
29
+ queryResults: QueryResults;
30
+ }): void {
31
+ this.dimensions = dimensions;
81
32
  this.queryResults = queryResults;
82
33
  }
83
-
84
- setDataAttributes(element: Element): void {
85
- const prefix = this.dataAttributePrefix;
86
-
87
- for (const [featureName, meetsFeature] of Object.entries(
88
- this.queryResults
89
- )) {
90
- let attributeName;
91
-
92
- if (prefix) {
93
- attributeName = `data-${prefix}-${featureName}`;
94
- } else {
95
- attributeName = `data-${featureName}`;
96
- }
97
-
98
- if (meetsFeature) {
99
- element.setAttribute(attributeName, '');
100
- } else {
101
- element.removeAttribute(attributeName);
102
- }
103
- }
104
- }
105
34
  }
@@ -1,10 +1,5 @@
1
1
  import { helper } from '@ember/component/helper';
2
-
3
- type Metadata = {
4
- dimension: 'aspectRatio' | 'height' | 'width';
5
- max: number;
6
- min: number;
7
- };
2
+ import type { Metadata } from 'ember-container-query/modifiers/container-query';
8
3
 
9
4
  function cqAspectRatio(
10
5
  positional: unknown[],
@@ -1,10 +1,5 @@
1
1
  import { helper } from '@ember/component/helper';
2
-
3
- type Metadata = {
4
- dimension: 'aspectRatio' | 'height' | 'width';
5
- max: number;
6
- min: number;
7
- };
2
+ import type { Metadata } from 'ember-container-query/modifiers/container-query';
8
3
 
9
4
  function cqHeight(
10
5
  positional: unknown[],
@@ -1,10 +1,5 @@
1
1
  import { helper } from '@ember/component/helper';
2
-
3
- type Metadata = {
4
- dimension: 'aspectRatio' | 'height' | 'width';
5
- max: number;
6
- min: number;
7
- };
2
+ import type { Metadata } from 'ember-container-query/modifiers/container-query';
8
3
 
9
4
  function cqWidth(
10
5
  positional: unknown[],
@@ -0,0 +1,168 @@
1
+ import { registerDestructor } from '@ember/destroyable';
2
+ import { action } from '@ember/object';
3
+ import { debounce as _debounce } from '@ember/runloop';
4
+ import { inject as service } from '@ember/service';
5
+ import Modifier, { ArgsFor, NamedArgs, PositionalArgs } from 'ember-modifier';
6
+
7
+ export type Metadata = {
8
+ dimension: 'aspectRatio' | 'height' | 'width';
9
+ max: number;
10
+ min: number;
11
+ };
12
+
13
+ export type Features = {
14
+ [featureName: string]: Metadata;
15
+ };
16
+
17
+ export type Dimensions = {
18
+ aspectRatio: number;
19
+ height: number;
20
+ width: number;
21
+ };
22
+
23
+ export type QueryResults = {
24
+ [featureName: string]: boolean;
25
+ };
26
+
27
+ interface ContainerQueryModifierSignature {
28
+ Args: {
29
+ Named: {
30
+ dataAttributePrefix?: string;
31
+ debounce?: number;
32
+ features?: Features;
33
+ onQuery?: ({
34
+ dimensions,
35
+ queryResults,
36
+ }: {
37
+ dimensions: Dimensions;
38
+ queryResults: QueryResults;
39
+ }) => void;
40
+ };
41
+ Positional: [];
42
+ };
43
+ Element: Element;
44
+ }
45
+
46
+ export default class ContainerQueryModifier extends Modifier<ContainerQueryModifierSignature> {
47
+ @service private declare readonly resizeObserver;
48
+
49
+ dimensions!: Dimensions;
50
+ queryResults!: QueryResults;
51
+
52
+ private _dataAttributes: string[] = [];
53
+ private _element?: Element;
54
+ private _named!: NamedArgs<ContainerQueryModifierSignature>;
55
+
56
+ get dataAttributePrefix(): string {
57
+ return this._named.dataAttributePrefix ?? 'container-query';
58
+ }
59
+
60
+ get debounce(): number {
61
+ return this._named.debounce ?? 0;
62
+ }
63
+
64
+ get features(): Features {
65
+ return this._named.features ?? {};
66
+ }
67
+
68
+ constructor(owner: unknown, args: ArgsFor<ContainerQueryModifierSignature>) {
69
+ super(owner, args);
70
+
71
+ registerDestructor(this, () => {
72
+ this.resizeObserver.unobserve(this._element, this.onResize);
73
+ });
74
+ }
75
+
76
+ modify(
77
+ element: Element,
78
+ _positional: PositionalArgs<ContainerQueryModifierSignature>,
79
+ named: NamedArgs<ContainerQueryModifierSignature>
80
+ ): void {
81
+ this._named = named;
82
+
83
+ this.registerResizeObserver(element);
84
+ this.queryContainer(element);
85
+ }
86
+
87
+ @action private onResize(resizeObserverEntry: ResizeObserverEntry): void {
88
+ const element = resizeObserverEntry.target;
89
+
90
+ if (this.debounce > 0) {
91
+ _debounce(this, this.queryContainer, element, this.debounce);
92
+ return;
93
+ }
94
+
95
+ this.queryContainer(element);
96
+ }
97
+
98
+ private registerResizeObserver(element: Element): void {
99
+ this.resizeObserver.unobserve(this._element, this.onResize);
100
+
101
+ this._element = element;
102
+ this.resizeObserver.observe(this._element, this.onResize);
103
+ }
104
+
105
+ private queryContainer(element: Element): void {
106
+ this.measureDimensions(element);
107
+ this.evaluateQueries();
108
+ this.resetDataAttributes(element);
109
+ this.setDataAttributes(element);
110
+
111
+ this._named.onQuery?.({
112
+ dimensions: this.dimensions,
113
+ queryResults: this.queryResults,
114
+ });
115
+ }
116
+
117
+ private measureDimensions(element: Element): void {
118
+ const height = element.clientHeight;
119
+ const width = element.clientWidth;
120
+
121
+ this.dimensions = {
122
+ aspectRatio: width / height,
123
+ height,
124
+ width,
125
+ };
126
+ }
127
+
128
+ private evaluateQueries(): void {
129
+ const queryResults = {} as QueryResults;
130
+
131
+ for (const [featureName, metadata] of Object.entries(this.features)) {
132
+ const { dimension, min, max } = metadata;
133
+ const value = this.dimensions[dimension];
134
+
135
+ queryResults[featureName] = min <= value && value < max;
136
+ }
137
+
138
+ this.queryResults = queryResults;
139
+ }
140
+
141
+ private resetDataAttributes(element: Element): void {
142
+ this._dataAttributes.forEach((dataAttribute) => {
143
+ element.removeAttribute(dataAttribute);
144
+ });
145
+
146
+ this._dataAttributes = [];
147
+ }
148
+
149
+ private setDataAttributes(element: Element): void {
150
+ const prefix = this.dataAttributePrefix;
151
+
152
+ for (const [featureName, meetsFeature] of Object.entries(
153
+ this.queryResults
154
+ )) {
155
+ if (!meetsFeature) {
156
+ continue;
157
+ }
158
+
159
+ const dataAttribute = prefix
160
+ ? `data-${prefix}-${featureName}`
161
+ : `data-${featureName}`;
162
+
163
+ element.setAttribute(dataAttribute, '');
164
+
165
+ this._dataAttributes.push(dataAttribute);
166
+ }
167
+ }
168
+ }
@@ -0,0 +1 @@
1
+ export { default } from 'ember-container-query/modifiers/container-query';
@@ -1,15 +1,5 @@
1
1
  import Component from '@glimmer/component';
2
- declare type Metadata = {
3
- dimension: 'aspectRatio' | 'height' | 'width';
4
- max: number;
5
- min: number;
6
- };
7
- declare type Features = {
8
- [featureName: string]: Metadata;
9
- };
10
- declare type QueryResults = {
11
- [featureName: string]: boolean;
12
- };
2
+ import type { Dimensions, Features, QueryResults } from 'ember-container-query/modifiers/container-query';
13
3
  interface ContainerQueryComponentArgs {
14
4
  dataAttributePrefix?: string;
15
5
  debounce?: number;
@@ -17,19 +7,13 @@ interface ContainerQueryComponentArgs {
17
7
  tagName?: string;
18
8
  }
19
9
  export default class ContainerQueryComponent extends Component<ContainerQueryComponentArgs> {
20
- queryResults: QueryResults;
21
- aspectRatio?: number;
22
- height?: number;
23
- width?: number;
24
- get features(): Features;
25
- get dataAttributePrefix(): string;
26
- get debounce(): number;
10
+ dimensions?: Dimensions;
11
+ queryResults?: QueryResults;
27
12
  tagName: string;
28
- onResize(resizeObserverEntry: ResizeObserverEntry): void;
29
- queryContainer(element: Element): void;
30
- measureDimensions(element: Element): void;
31
- evaluateQueries(): void;
32
- setDataAttributes(element: Element): void;
13
+ updateState({ dimensions, queryResults, }: {
14
+ dimensions: Dimensions;
15
+ queryResults: QueryResults;
16
+ }): void;
33
17
  }
34
18
  export {};
35
19
  //# sourceMappingURL=container-query.d.ts.map
@@ -1,8 +1,4 @@
1
- declare type Metadata = {
2
- dimension: 'aspectRatio' | 'height' | 'width';
3
- max: number;
4
- min: number;
5
- };
1
+ import type { Metadata } from 'ember-container-query/modifiers/container-query';
6
2
  declare const _default: import("@ember/component/helper").FunctionBasedHelper<{
7
3
  Args: {
8
4
  Positional: unknown[];
@@ -1,8 +1,4 @@
1
- declare type Metadata = {
2
- dimension: 'aspectRatio' | 'height' | 'width';
3
- max: number;
4
- min: number;
5
- };
1
+ import type { Metadata } from 'ember-container-query/modifiers/container-query';
6
2
  declare const _default: import("@ember/component/helper").FunctionBasedHelper<{
7
3
  Args: {
8
4
  Positional: unknown[];
@@ -1,8 +1,4 @@
1
- declare type Metadata = {
2
- dimension: 'aspectRatio' | 'height' | 'width';
3
- max: number;
4
- min: number;
5
- };
1
+ import type { Metadata } from 'ember-container-query/modifiers/container-query';
6
2
  declare const _default: import("@ember/component/helper").FunctionBasedHelper<{
7
3
  Args: {
8
4
  Positional: unknown[];
@@ -0,0 +1,54 @@
1
+ import Modifier, { ArgsFor, NamedArgs, PositionalArgs } from 'ember-modifier';
2
+ export type Metadata = {
3
+ dimension: 'aspectRatio' | 'height' | 'width';
4
+ max: number;
5
+ min: number;
6
+ };
7
+ export type Features = {
8
+ [featureName: string]: Metadata;
9
+ };
10
+ export type Dimensions = {
11
+ aspectRatio: number;
12
+ height: number;
13
+ width: number;
14
+ };
15
+ export type QueryResults = {
16
+ [featureName: string]: boolean;
17
+ };
18
+ interface ContainerQueryModifierSignature {
19
+ Args: {
20
+ Named: {
21
+ dataAttributePrefix?: string;
22
+ debounce?: number;
23
+ features?: Features;
24
+ onQuery?: ({ dimensions, queryResults, }: {
25
+ dimensions: Dimensions;
26
+ queryResults: QueryResults;
27
+ }) => void;
28
+ };
29
+ Positional: [];
30
+ };
31
+ Element: Element;
32
+ }
33
+ export default class ContainerQueryModifier extends Modifier<ContainerQueryModifierSignature> {
34
+ private readonly resizeObserver;
35
+ dimensions: Dimensions;
36
+ queryResults: QueryResults;
37
+ private _dataAttributes;
38
+ private _element?;
39
+ private _named;
40
+ get dataAttributePrefix(): string;
41
+ get debounce(): number;
42
+ get features(): Features;
43
+ constructor(owner: unknown, args: ArgsFor<ContainerQueryModifierSignature>);
44
+ modify(element: Element, _positional: PositionalArgs<ContainerQueryModifierSignature>, named: NamedArgs<ContainerQueryModifierSignature>): void;
45
+ private onResize;
46
+ private registerResizeObserver;
47
+ private queryContainer;
48
+ private measureDimensions;
49
+ private evaluateQueries;
50
+ private resetDataAttributes;
51
+ private setDataAttributes;
52
+ }
53
+ export {};
54
+ //# sourceMappingURL=container-query.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-container-query",
3
- "version": "2.1.0",
3
+ "version": "3.0.0-alpha.0",
4
4
  "description": "Container queries using Ember modifiers",
5
5
  "keywords": [
6
6
  "container-queries",
@@ -26,9 +26,11 @@
26
26
  "build": "ember build --environment=production",
27
27
  "build:test": "ember build --environment=test",
28
28
  "changelog": "lerna-changelog",
29
- "lint": "npm-run-all --aggregate-output --continue-on-error --parallel \"lint:!(fix)\"",
29
+ "lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
30
+ "lint:css": "stylelint \"tests/dummy/app/**/*.css\" --cache",
31
+ "lint:css:fix": "stylelint \"tests/dummy/app/**/*.css\" --fix",
30
32
  "lint:dependency": "ember dependency-lint",
31
- "lint:fix": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*:fix",
33
+ "lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
32
34
  "lint:hbs": "ember-template-lint .",
33
35
  "lint:hbs:fix": "ember-template-lint . --fix",
34
36
  "lint:js": "eslint . --cache --ext=.js,.ts",
@@ -52,55 +54,59 @@
52
54
  }
53
55
  },
54
56
  "dependencies": {
55
- "@ember/render-modifiers": "^2.0.4",
56
57
  "ember-cli-babel": "^7.26.11",
57
- "ember-cli-htmlbars": "^6.0.1",
58
- "ember-cli-typescript": "^5.1.0",
58
+ "ember-cli-htmlbars": "^6.1.1",
59
+ "ember-cli-typescript": "^5.2.1",
59
60
  "ember-element-helper": "^0.6.1",
60
- "ember-on-resize-modifier": "^1.1.0"
61
+ "ember-modifier": "^3.2.7",
62
+ "ember-resize-observer-service": "^1.1.0",
63
+ "ember-test-selectors": "^6.0.0"
61
64
  },
62
65
  "devDependencies": {
63
66
  "@ember/optional-features": "^2.0.0",
64
67
  "@ember/test-helpers": "^2.8.1",
65
- "@embroider/test-setup": "^1.7.1",
68
+ "@embroider/test-setup": "^2.0.2",
66
69
  "@glimmer/component": "^1.1.2",
67
70
  "@glimmer/tracking": "^1.1.2",
68
- "@percy/cli": "^1.2.1",
69
- "@percy/ember": "^3.0.0",
70
- "@types/ember-qunit": "^5.0.0",
71
- "@types/ember-resolver": "^5.0.11",
72
- "@types/ember__application": "^4.0.0",
73
- "@types/ember__array": "^4.0.1",
74
- "@types/ember__component": "^4.0.8",
75
- "@types/ember__controller": "^4.0.0",
76
- "@types/ember__debug": "^4.0.1",
77
- "@types/ember__engine": "^4.0.0",
78
- "@types/ember__error": "^4.0.0",
79
- "@types/ember__object": "^4.0.2",
80
- "@types/ember__polyfills": "^4.0.0",
81
- "@types/ember__routing": "^4.0.7",
82
- "@types/ember__runloop": "^4.0.1",
83
- "@types/ember__service": "^4.0.0",
84
- "@types/ember__string": "^3.0.9",
85
- "@types/ember__template": "^4.0.0",
86
- "@types/ember__test": "^4.0.0",
87
- "@types/ember__test-helpers": "^2.6.1",
88
- "@types/ember__utils": "^4.0.0",
71
+ "@percy/cli": "^1.16.0",
72
+ "@percy/ember": "^4.0.0",
73
+ "@tsconfig/ember": "^1.1.0",
74
+ "@types/ember-qunit": "^5.0.2",
75
+ "@types/ember-resolver": "^5.0.13",
76
+ "@types/ember__application": "^4.0.5",
77
+ "@types/ember__array": "^4.0.3",
78
+ "@types/ember__component": "^4.0.11",
79
+ "@types/ember__controller": "^4.0.4",
80
+ "@types/ember__debug": "^4.0.3",
81
+ "@types/ember__destroyable": "^4.0.1",
82
+ "@types/ember__engine": "^4.0.4",
83
+ "@types/ember__error": "^4.0.2",
84
+ "@types/ember__object": "^4.0.5",
85
+ "@types/ember__polyfills": "^4.0.1",
86
+ "@types/ember__routing": "^4.0.12",
87
+ "@types/ember__runloop": "^4.0.2",
88
+ "@types/ember__service": "^4.0.1",
89
+ "@types/ember__string": "^3.0.10",
90
+ "@types/ember__template": "^4.0.1",
91
+ "@types/ember__test": "^4.0.1",
92
+ "@types/ember__test-helpers": "^2.8.2",
93
+ "@types/ember__utils": "^4.0.2",
89
94
  "@types/htmlbars-inline-precompile": "^3.0.0",
90
- "@types/qunit": "^2.19.0",
95
+ "@types/qunit": "^2.19.3",
91
96
  "@types/rsvp": "^4.0.4",
92
- "@typescript-eslint/eslint-plugin": "^5.27.0",
93
- "@typescript-eslint/parser": "^5.27.0",
97
+ "@typescript-eslint/eslint-plugin": "^5.46.1",
98
+ "@typescript-eslint/parser": "^5.46.1",
94
99
  "broccoli-asset-rev": "^3.0.0",
95
- "d3-array": "^3.1.6",
100
+ "concurrently": "^7.6.0",
101
+ "d3-array": "^3.2.1",
96
102
  "d3-axis": "^3.0.0",
97
103
  "d3-scale": "^4.0.2",
98
104
  "d3-selection": "^3.0.0",
99
105
  "d3-shape": "^3.1.0",
100
- "ember-a11y-refocus": "^2.3.0",
101
- "ember-a11y-testing": "^5.0.0",
102
- "ember-auto-import": "^2.4.2",
103
- "ember-cli": "~4.4.0",
106
+ "ember-a11y-refocus": "^3.0.2",
107
+ "ember-a11y-testing": "^5.1.0",
108
+ "ember-auto-import": "^2.5.0",
109
+ "ember-cli": "~4.9.2",
104
110
  "ember-cli-dependency-checker": "^3.3.1",
105
111
  "ember-cli-dependency-lint": "^2.0.1",
106
112
  "ember-cli-inject-live-reload": "^2.1.0",
@@ -108,36 +114,39 @@
108
114
  "ember-cli-sri": "^2.1.1",
109
115
  "ember-cli-terser": "^4.0.2",
110
116
  "ember-css-modules": "^2.0.1",
111
- "ember-disable-prototype-extensions": "^1.1.3",
112
- "ember-export-application-global": "^2.0.1",
113
117
  "ember-load-initializers": "^2.1.2",
114
118
  "ember-named-blocks-polyfill": "^0.2.5",
115
119
  "ember-page-title": "^7.0.0",
116
- "ember-qunit": "^5.1.5",
120
+ "ember-qunit": "^6.0.0",
117
121
  "ember-resolver": "^8.0.3",
118
- "ember-source": "~4.4.0",
122
+ "ember-source": "~4.9.2",
119
123
  "ember-source-channel-url": "^3.0.0",
120
- "ember-svg-jar": "^2.3.4",
121
- "ember-template-lint": "^4.10.0",
122
- "ember-test-selectors": "^6.0.0",
123
- "ember-truth-helpers": "^3.0.0",
124
+ "ember-svg-jar": "^2.4.2",
125
+ "ember-template-lint": "^5.2.0",
126
+ "ember-template-lint-plugin-prettier": "^4.1.0",
127
+ "ember-truth-helpers": "^3.1.1",
124
128
  "ember-try": "^2.0.0",
125
- "eslint": "^8.16.0",
129
+ "eslint": "^8.29.0",
126
130
  "eslint-config-prettier": "^8.5.0",
127
- "eslint-plugin-ember": "^10.6.1",
128
- "eslint-plugin-node": "^11.1.0",
129
- "eslint-plugin-prettier": "^4.0.0",
131
+ "eslint-plugin-ember": "^11.2.1",
132
+ "eslint-plugin-n": "^15.6.0",
133
+ "eslint-plugin-prettier": "^4.2.1",
134
+ "eslint-plugin-qunit": "^7.3.4",
135
+ "eslint-plugin-simple-import-sort": "^8.0.0",
130
136
  "lerna-changelog": "^2.2.0",
131
137
  "loader.js": "^4.7.0",
132
- "npm-run-all": "^4.1.5",
133
- "prettier": "^2.6.2",
134
- "qunit": "^2.19.1",
138
+ "prettier": "^2.8.1",
139
+ "qunit": "^2.19.3",
135
140
  "qunit-dom": "^2.0.0",
136
- "typescript": "^4.7.2",
137
- "webpack": "^5.73.0"
141
+ "stylelint": "^14.16.0",
142
+ "stylelint-config-standard": "^29.0.0",
143
+ "stylelint-no-unsupported-browser-features": "^6.0.1",
144
+ "stylelint-order": "^5.0.0",
145
+ "typescript": "^4.9.4",
146
+ "webpack": "^5.75.0"
138
147
  },
139
148
  "engines": {
140
- "node": "12.* || 14.* || >= 16"
149
+ "node": "14.* || 16.* || >= 18"
141
150
  },
142
151
  "ember": {
143
152
  "edition": "octane"
package/tsconfig.json CHANGED
@@ -1,69 +1,9 @@
1
1
  {
2
+ "extends": "@tsconfig/ember/tsconfig.json",
2
3
  "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ES2020",
5
- "moduleResolution": "node",
6
-
7
- // Trying to check Ember apps and addons with `allowJs: true` is a recipe
8
- // for many unresolveable type errors, because with *considerable* extra
9
- // configuration it ends up including many files which are *not* valid and
10
- // cannot be: they *appear* to be resolve-able to TS, but are in fact not in
11
- // valid Node-resolveable locations and may not have TS-ready types. This
12
- // will likely improve over time
13
- "allowJs": false,
14
-
15
4
  // Don't check the types of dependencies
16
5
  "skipLibCheck": true,
17
6
 
18
- // --- TS for SemVer Types compatibility
19
- // Strictness settings -- you should *not* change these: Ember code is not
20
- // guaranteed to type check with these set to looser values.
21
- "strict": true,
22
- "noUncheckedIndexedAccess": true,
23
-
24
- // Interop: these are viral and will require anyone downstream of your
25
- // package to *also* set them to true. If you *must* enable them to consume
26
- // an upstream package, you should document that for downstream consumers to
27
- // be aware of.
28
- //
29
- // These *are* safe for apps to enable, since they do not *have* downstream
30
- // consumers; but leaving them off is still preferred when possible, since
31
- // it makes it easier to switch between apps and addons and have the same
32
- // rules for what can be imported and how.
33
- "allowSyntheticDefaultImports": false,
34
- "esModuleInterop": false,
35
-
36
- // --- Lint-style rules
37
-
38
- // TypeScript also supplies some lint-style checks; nearly all of them are
39
- // better handled by ESLint with the `@typescript-eslint`. This one is more
40
- // like a safety check, though, so we leave it on.
41
- "noPropertyAccessFromIndexSignature": true,
42
-
43
- // --- Compilation/integration settings
44
- // Setting `noEmitOnError` here allows ember-cli-typescript to catch errors
45
- // and inject them into Ember CLI's build error reporting, which provides
46
- // nice feedback for when
47
- "noEmitOnError": false,
48
-
49
- // We use Babel for emitting runtime code, because it's very important that
50
- // we always and only use the same transpiler for non-stable features, in
51
- // particular decorators. If you were to change this to `true`, it could
52
- // lead to accidentally generating code with `tsc` instead of Babel, and
53
- // could thereby result in broken code at runtime.
54
- "noEmit": true,
55
-
56
- // Ember makes heavy use of decorators; TS does not support them at all
57
- // without this flag.
58
- "experimentalDecorators": true,
59
-
60
- // Support generation of source maps. Note: you must *also* enable source
61
- // maps in your `ember-cli-babel` config and/or `babel.config.js`.
62
- "declaration": true,
63
- "declarationMap": true,
64
- "inlineSourceMap": true,
65
- "inlineSources": true,
66
-
67
7
  // The combination of `baseUrl` with `paths` allows Ember's classic package
68
8
  // layout, which is not resolveable with the Node resolution algorithm, to
69
9
  // work with TypeScript.
@@ -1,5 +0,0 @@
1
- 'use strict';
2
-
3
- module.exports = function (/* environment, appConfig */) {
4
- return {};
5
- };