@tylertech/forge-core 2.0.0 → 2.2.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/esm/index.js CHANGED
@@ -7,7 +7,9 @@ export * from './a11y';
7
7
  export * from './constants';
8
8
  export * from './custom-elements';
9
9
  export * from './events';
10
+ export * from './media-observer';
10
11
  export * from './message-list';
12
+ export * from './resize';
11
13
  export * from './scroll';
12
14
  export * from './services';
13
15
  export * from './utils';
@@ -0,0 +1,3 @@
1
+ export * from './media-observer';
2
+ export * from './media-observer-utils';
3
+ export * from './types';
@@ -0,0 +1,57 @@
1
+ import { ALL_MEDIA_FEATURES } from './types';
2
+ /** Returns the names of all queries that match. Used for range media features. */
3
+ export function getMatchingValues(namedQueries) {
4
+ const values = [];
5
+ for (const namedQuery of namedQueries) {
6
+ const queryList = window.matchMedia(namedQuery.query);
7
+ if (queryList.matches) {
8
+ values.push(namedQuery.name);
9
+ }
10
+ }
11
+ return values;
12
+ }
13
+ /** Returns the name of one query that matches. Used for discrete media features. */
14
+ export function getMatchingValue(namedQueries) {
15
+ for (const namedQuery of namedQueries) {
16
+ const queryList = window.matchMedia(namedQuery.query);
17
+ if (queryList.matches) {
18
+ return namedQuery.name;
19
+ }
20
+ }
21
+ // We can assume that at least one query will match, this fallback is mostly to satisfy TypeScript
22
+ console.warn(`No media query returned a match, falling back to ${namedQueries[0].name}.`);
23
+ return namedQueries[0].name;
24
+ }
25
+ /** Returns whether a query matches. */
26
+ export function getBooleanValue(query) {
27
+ return window.matchMedia(query.query).matches;
28
+ }
29
+ /** Returns a CSS media query string from a range. */
30
+ export function getRangeQuery(feature, range) {
31
+ if (range.equals !== undefined) {
32
+ return `(${feature}: ${range.equals})`;
33
+ }
34
+ const rules = [];
35
+ if (range.min !== undefined) {
36
+ rules.push(`(min-${feature}: ${range.min})`);
37
+ }
38
+ if (range.max !== undefined) {
39
+ rules.push(`(max-${feature}: ${range.max})`);
40
+ }
41
+ return rules.join(' and ');
42
+ }
43
+ /** Whether a string is the name of a media feature. */
44
+ export function isMediaFeature(value) {
45
+ return ALL_MEDIA_FEATURES.includes(value);
46
+ }
47
+ /** Return `undefined` if the name is a reserved media feature. */
48
+ export function validateName(name) {
49
+ if (!name) {
50
+ return undefined;
51
+ }
52
+ if (isMediaFeature(name)) {
53
+ console.error(`${name} is a disallowed media observer name.`);
54
+ return undefined;
55
+ }
56
+ return name;
57
+ }
@@ -0,0 +1,214 @@
1
+ import { Subject } from '../observable';
2
+ import { getBooleanValue, getMatchingValue, getMatchingValues, getRangeQuery, validateName } from './media-observer-utils';
3
+ import { mediaFeatureValues } from './types';
4
+ /**
5
+ * A Subject that tracks the value of a media feature and exposes it synchronously and
6
+ * asynchronously.
7
+ */
8
+ export class MediaObserver extends Subject {
9
+ // eslint-disable-next-line @tylertech-eslint/require-private-modifier
10
+ constructor(name, namedQueries, value, track = true) {
11
+ super(value);
12
+ this._queries = [];
13
+ this._name = name;
14
+ this._queries = this._attachMediaQueries(namedQueries);
15
+ if (track) {
16
+ MediaObserver._observers[name] = this;
17
+ }
18
+ }
19
+ /**
20
+ * Returns a new media observer tracking a discrete feature.
21
+ * @param feature The name of a discrete media feature.
22
+ * @param options An options object with the following properties:
23
+ * - `name`: The name to track the observer by. The feature name is used if unsupplied.
24
+ * - `track`: Whether to make the observer available globally.
25
+ * @returns A `DiscreteMediaObserver` tracking the given feature.
26
+ */
27
+ static observeDiscrete(feature, options) {
28
+ var _a;
29
+ const name = (_a = validateName(options === null || options === void 0 ? void 0 : options.name)) !== null && _a !== void 0 ? _a : feature;
30
+ const existing = MediaObserver._getObserver(name);
31
+ if (existing && (options === null || options === void 0 ? void 0 : options.track) !== false) {
32
+ return existing;
33
+ }
34
+ return DiscreteMediaObserver.create(feature);
35
+ }
36
+ /** Returns a media oberserver tracking a range feature. */
37
+ /**
38
+ * Returns a new media observer tracking a range feature.
39
+ * @param feature The name of a range media feature.
40
+ * @param constraints One or more ranges to track. A range includes the following properties:
41
+ * - `name`: A label for the range used to set the observer's value.
42
+ * - `min`: The lowest value in the range (optional).
43
+ * - `max`: The highest value in the range (optional).
44
+ * - `equals`: A single value to match, supersedes `min` and `max` (optional).
45
+ * @param options An options object with the following properties:
46
+ * - `name`: The name to track the observer by. The feature name is used if unsupplied.
47
+ * - `track`: Whether to make the observer available globally.
48
+ * @returns A `RangeMediaObserver` tracking the given feature.
49
+ */
50
+ static observeRange(feature, constraints, options) {
51
+ var _a;
52
+ const name = (_a = validateName(options === null || options === void 0 ? void 0 : options.name)) !== null && _a !== void 0 ? _a : feature;
53
+ const existing = MediaObserver._getObserver(name);
54
+ if (existing && (options === null || options === void 0 ? void 0 : options.track) !== false) {
55
+ return existing;
56
+ }
57
+ return RangeMediaObserver.create(feature, Array.isArray(constraints) ? constraints : [constraints], options);
58
+ }
59
+ /**
60
+ * Returns a media observer tracking a feature that evaluates to a boolean value.
61
+ * @param feature The name of a media feature that can be expressed as a boolean.
62
+ * @param options An options object with the following properties:
63
+ * - `name`: The name to track the observer by. The feature name plus '-bool' is used if unsupplied.
64
+ * - `track`: Whether to make the observer available globally.
65
+ * @returns A `BooleanMediaObserver` tracking the given feature.
66
+ */
67
+ static observeBoolean(feature, options) {
68
+ var _a;
69
+ const name = (_a = validateName(options === null || options === void 0 ? void 0 : options.name)) !== null && _a !== void 0 ? _a : `${feature}-bool`;
70
+ const existing = MediaObserver._getObserver(name);
71
+ if (existing && (options === null || options === void 0 ? void 0 : options.track) !== false) {
72
+ return existing;
73
+ }
74
+ return BooleanMediaObserver.create(feature, options);
75
+ }
76
+ /** Returns a media observer tracking any media query. */
77
+ /**
78
+ * Returns a media observer tracking any media query.
79
+ * @param query Any media query.
80
+ * @param options An options object with the following properties:
81
+ * - `name`: The name to track the observer by. The entire query string is used if unsupplied.
82
+ * - `track`: Whether to make the observer available globally.
83
+ * @returns A `CustomMediaObserver` tracking the given query.
84
+ */
85
+ static observeCustom(query, options) {
86
+ var _a;
87
+ const name = (_a = validateName(options === null || options === void 0 ? void 0 : options.name)) !== null && _a !== void 0 ? _a : query;
88
+ const existing = MediaObserver._getObserver(name);
89
+ if (existing && (options === null || options === void 0 ? void 0 : options.track) !== false) {
90
+ return existing;
91
+ }
92
+ return CustomMediaObserver.create(query, options);
93
+ }
94
+ static _getObserver(name) {
95
+ const existing = MediaObserver._observers[name];
96
+ if (existing) {
97
+ return existing;
98
+ }
99
+ return undefined;
100
+ }
101
+ get name() {
102
+ return this._name;
103
+ }
104
+ /** Removes the `MediaObserver` and all created event listeners. */
105
+ destroy() {
106
+ for (const query of this._queries) {
107
+ query.queryList.removeEventListener('change', query.handler);
108
+ }
109
+ this._queries = [];
110
+ delete MediaObserver._observers[this.name];
111
+ }
112
+ _attachMediaQueries(namedQueries) {
113
+ return namedQueries.map(({ name, query }) => {
114
+ const queryList = window.matchMedia(query);
115
+ const handler = (event) => this.setValue(event, name);
116
+ handler(queryList);
117
+ queryList.addEventListener('change', handler);
118
+ return { queryList, handler };
119
+ });
120
+ }
121
+ }
122
+ /**
123
+ * STATIC MEMBERS
124
+ */
125
+ /** A collection of all managed media observers. */
126
+ MediaObserver._observers = {};
127
+ /**
128
+ * A media observer that tracks one feature with multiple discrete keyword values.
129
+ */
130
+ export class DiscreteMediaObserver extends MediaObserver {
131
+ static create(feature, options) {
132
+ var _a;
133
+ const namedQueries = mediaFeatureValues[feature].map(featureValue => ({ name: featureValue.toString(), query: `(${feature}: ${featureValue})` }));
134
+ const value = getMatchingValue(namedQueries);
135
+ const name = (_a = validateName(options === null || options === void 0 ? void 0 : options.name)) !== null && _a !== void 0 ? _a : feature;
136
+ return new DiscreteMediaObserver(name, namedQueries, value, (options === null || options === void 0 ? void 0 : options.track) !== false);
137
+ }
138
+ // eslint-disable-next-line @tylertech-eslint/require-private-modifier
139
+ setValue(value, name) {
140
+ if (!value.matches) {
141
+ return;
142
+ }
143
+ this.next(name);
144
+ }
145
+ }
146
+ /**
147
+ * A media observer that tracks one feature with comparable range values.
148
+ */
149
+ export class RangeMediaObserver extends MediaObserver {
150
+ // eslint-disable-next-line @tylertech-eslint/require-private-modifier
151
+ constructor(name, namedQueries, value, track = true) {
152
+ super(name, namedQueries, value, track);
153
+ this._isAwaitingQueries = false;
154
+ this._valueQueue = [];
155
+ this._isInitialized = true;
156
+ }
157
+ static create(feature, constraints, options) {
158
+ var _a;
159
+ const namedQueries = constraints.map(constraint => ({ query: getRangeQuery(feature, constraint), name: constraint.name }));
160
+ const value = getMatchingValues(namedQueries);
161
+ const name = (_a = validateName(options === null || options === void 0 ? void 0 : options.name)) !== null && _a !== void 0 ? _a : feature;
162
+ return new RangeMediaObserver(name, namedQueries, value, (options === null || options === void 0 ? void 0 : options.track) !== false);
163
+ }
164
+ // eslint-disable-next-line @tylertech-eslint/require-private-modifier
165
+ setValue(value, name) {
166
+ if (!this._isInitialized) {
167
+ return;
168
+ }
169
+ if (value.matches) {
170
+ this._valueQueue.push(name);
171
+ }
172
+ if (!this._isAwaitingQueries) {
173
+ setTimeout(() => {
174
+ this.next([...this._valueQueue]);
175
+ this._valueQueue = [];
176
+ this._isAwaitingQueries = false;
177
+ });
178
+ this._isAwaitingQueries = true;
179
+ }
180
+ }
181
+ }
182
+ /**
183
+ * A media observer that tracks one feature that can be coerced to a boolean value. `none` and 0
184
+ * values evaluate to `true`.
185
+ */
186
+ export class BooleanMediaObserver extends MediaObserver {
187
+ static create(feature, options) {
188
+ var _a;
189
+ const namedQuery = [{ query: `(${feature})`, name: '' }];
190
+ const value = getBooleanValue(namedQuery[0]);
191
+ const name = (_a = validateName(options === null || options === void 0 ? void 0 : options.name)) !== null && _a !== void 0 ? _a : `${feature}-bool`;
192
+ return new BooleanMediaObserver(name, namedQuery, value, (options === null || options === void 0 ? void 0 : options.track) !== false);
193
+ }
194
+ // eslint-disable-next-line @tylertech-eslint/require-private-modifier
195
+ setValue(value, _) {
196
+ this.next(value.matches);
197
+ }
198
+ }
199
+ /**
200
+ * A media observer that tracks any query.
201
+ */
202
+ export class CustomMediaObserver extends MediaObserver {
203
+ static create(query, options) {
204
+ var _a;
205
+ const namedQuery = [{ query, name: '' }];
206
+ const value = window.matchMedia(query);
207
+ const name = (_a = validateName(options === null || options === void 0 ? void 0 : options.name)) !== null && _a !== void 0 ? _a : query;
208
+ return new CustomMediaObserver(name, namedQuery, value, (options === null || options === void 0 ? void 0 : options.track) !== false);
209
+ }
210
+ // eslint-disable-next-line @tylertech-eslint/require-private-modifier
211
+ setValue(value, _) {
212
+ this.next(value);
213
+ }
214
+ }
@@ -0,0 +1,87 @@
1
+ export const DISCRETE_MEDIA_FEATURES = [
2
+ 'any-hover',
3
+ 'any-pointer',
4
+ 'color-gamut',
5
+ 'display-mode',
6
+ 'dynamic-range',
7
+ 'forced-colors',
8
+ 'grid',
9
+ 'hover',
10
+ 'inverted-colors',
11
+ 'orientation',
12
+ 'overflow-block',
13
+ 'overflow-inline',
14
+ 'pointer',
15
+ 'prefers-contrast',
16
+ 'prefers-color-scheme',
17
+ 'prefers-reduced-motion',
18
+ 'scripting',
19
+ 'update',
20
+ 'video-dynamic-range'
21
+ ];
22
+ export const RANGE_MEDIA_FEATURES = [
23
+ 'aspect-ratio',
24
+ 'color',
25
+ 'color-index',
26
+ 'height',
27
+ 'monochrome',
28
+ 'resolution',
29
+ 'width'
30
+ ];
31
+ export const ALL_MEDIA_FEATURES = [...DISCRETE_MEDIA_FEATURES, ...RANGE_MEDIA_FEATURES];
32
+ export const BOOLEAN_MEDIA_FEATURES = [
33
+ 'any-hover',
34
+ 'any-pointer',
35
+ 'color',
36
+ 'color-index',
37
+ 'forced-colors',
38
+ 'grid',
39
+ 'height',
40
+ 'hover',
41
+ 'inverted-colors',
42
+ 'monochrome',
43
+ 'overflow-block',
44
+ 'overflow-inline',
45
+ 'pointer',
46
+ 'scripting',
47
+ 'update',
48
+ 'width'
49
+ ];
50
+ export const colorGamutValues = ['srbg', 'p3', 'rec2020'];
51
+ export const displayModeValues = ['fullscreen', 'standalone', 'minimal-ui', 'browser', 'window-controls-overlay'];
52
+ export const dynamicRangeValues = ['standard', 'high'];
53
+ export const forcedColorsValues = ['none', 'active'];
54
+ export const gridValues = [0, 1];
55
+ export const hoverValues = ['none', 'hover'];
56
+ export const invertedColorsValues = ['none', 'inverted'];
57
+ export const orientationValues = ['portrait', 'landscape'];
58
+ export const overflowBlockValues = ['none', 'scroll', 'optional-paged', 'paged'];
59
+ export const overflowInlineValues = ['none', 'scroll'];
60
+ export const pointerValues = ['none', 'coarse', 'fine'];
61
+ export const prefersContrastValues = ['no-preference', 'more', 'less', 'custom'];
62
+ export const prefersColorSchemeValues = ['light', 'dark'];
63
+ export const prefersReducedMotionValues = ['no-preference', 'reduce'];
64
+ export const scriptingValues = ['none', 'initial-only', 'enabled'];
65
+ export const updateValues = ['none', 'slow', 'fast'];
66
+ export const videoDynamicRangeValues = ['standard', 'high'];
67
+ export const mediaFeatureValues = {
68
+ 'any-hover': Array.from(hoverValues.values()),
69
+ 'any-pointer': Array.from(pointerValues.values()),
70
+ 'color-gamut': Array.from(colorGamutValues.values()),
71
+ 'display-mode': Array.from(displayModeValues.values()),
72
+ 'dynamic-range': Array.from(dynamicRangeValues.values()),
73
+ 'forced-colors': Array.from(forcedColorsValues.values()),
74
+ 'grid': Array.from(gridValues.values()),
75
+ 'hover': Array.from(hoverValues.values()),
76
+ 'inverted-colors': Array.from(invertedColorsValues.values()),
77
+ 'orientation': Array.from(orientationValues.values()),
78
+ 'overflow-block': Array.from(overflowBlockValues.values()),
79
+ 'overflow-inline': Array.from(overflowInlineValues.values()),
80
+ 'pointer': Array.from(pointerValues.values()),
81
+ 'prefers-contrast': Array.from(prefersContrastValues.values()),
82
+ 'prefers-color-scheme': Array.from(prefersColorSchemeValues.values()),
83
+ 'prefers-reduced-motion': Array.from(prefersReducedMotionValues.values()),
84
+ 'scripting': Array.from(scriptingValues.values()),
85
+ 'update': Array.from(updateValues.values()),
86
+ 'video-dynamic-range': Array.from(videoDynamicRangeValues.values())
87
+ };
@@ -0,0 +1,2 @@
1
+ export * from './observable';
2
+ export * from './types';
@@ -0,0 +1,51 @@
1
+ export class Subject {
2
+ constructor(value) {
3
+ this.subscribers = [];
4
+ this.source = value;
5
+ }
6
+ get value() {
7
+ return this.source;
8
+ }
9
+ subscribe(observer) {
10
+ const subscription = new Subscription(this.subscribers, observer);
11
+ this.subscribers.push(subscription);
12
+ observer === null || observer === void 0 ? void 0 : observer(this.source);
13
+ return subscription;
14
+ }
15
+ // eslint-disable-next-line @tylertech-eslint/require-private-modifier
16
+ next(value) {
17
+ var _a;
18
+ this.source = value;
19
+ for (const subscriber of this.subscribers) {
20
+ // eslint-disable-next-line @typescript-eslint/dot-notation
21
+ (_a = subscriber.observer) === null || _a === void 0 ? void 0 : _a.call(subscriber, value);
22
+ }
23
+ }
24
+ // eslint-disable-next-line @tylertech-eslint/require-private-modifier
25
+ complete() {
26
+ this.subscribers = [];
27
+ }
28
+ }
29
+ export class Subscription {
30
+ constructor(parent, observer) {
31
+ this._closed = false;
32
+ this.observer = observer;
33
+ this._parent = parent;
34
+ }
35
+ get closed() {
36
+ return this._closed;
37
+ }
38
+ ;
39
+ unsubscribe() {
40
+ if (this._closed) {
41
+ return;
42
+ }
43
+ const index = this._parent.findIndex(subscription => subscription === this);
44
+ if (index > -1) {
45
+ this._parent.splice(index, 1);
46
+ this._closed = true;
47
+ return;
48
+ }
49
+ console.error('Subscription is not present in parent array.', { subscription: this, parent: this._parent });
50
+ }
51
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './resize-observer';
2
+ export * from './resize-types';
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Provides a set of methods for observing and responding to resizing of elements.
3
+ */
4
+ export class ForgeResizeObserver {
5
+ /**
6
+ * Initiates the observing of a specified `Element`. Calling with an already observed `Element`
7
+ * overwrites the exisiting observation. It is expected that the consumer will eventually
8
+ * {@link unobserve} the `Element` to avoid memory leaks.
9
+ *
10
+ * @param target An `Element` reference.
11
+ * @param callback A function that accepts a `ResizeObserverEntry` for the `Element`.
12
+ * @param options An options object allowing you to set options for the observation.
13
+ */
14
+ static observe(target, callback, options) {
15
+ var _a, _b;
16
+ if (ForgeResizeObserver._targets.has(target)) {
17
+ (_a = ForgeResizeObserver._observer) === null || _a === void 0 ? void 0 : _a.unobserve(target);
18
+ }
19
+ ForgeResizeObserver._targets.set(target, callback);
20
+ ForgeResizeObserver._countTargets();
21
+ (_b = ForgeResizeObserver._observer) === null || _b === void 0 ? void 0 : _b.observe(target, options);
22
+ }
23
+ /**
24
+ * Ends the observing of a specified `Element`.
25
+ *
26
+ * @param target An `Element` reference.
27
+ */
28
+ static unobserve(target) {
29
+ var _a;
30
+ ForgeResizeObserver._targets.delete(target);
31
+ (_a = ForgeResizeObserver._observer) === null || _a === void 0 ? void 0 : _a.unobserve(target);
32
+ ForgeResizeObserver._countTargets();
33
+ }
34
+ /**
35
+ * Creates or destroys the `ResizeObserver` based on whether targets exist.
36
+ */
37
+ static _countTargets() {
38
+ if (ForgeResizeObserver._observer) {
39
+ // If there are no targets destroy the observer
40
+ if (ForgeResizeObserver._targets.size < 1) {
41
+ ForgeResizeObserver._observer = undefined;
42
+ }
43
+ }
44
+ else {
45
+ // If there are targets create the observer
46
+ if (ForgeResizeObserver._targets.size) {
47
+ ForgeResizeObserver._observer = new ResizeObserver(ForgeResizeObserver._handleResize);
48
+ }
49
+ }
50
+ }
51
+ }
52
+ ForgeResizeObserver._targets = new Map();
53
+ /**
54
+ * Runs the callback function of targets when they are resized.
55
+ *
56
+ * @param entries An array of `ResizeObserverEntry`s.
57
+ */
58
+ ForgeResizeObserver._handleResize = entries => {
59
+ entries.forEach(entry => {
60
+ var _a;
61
+ (_a = ForgeResizeObserver._targets.get(entry.target)) === null || _a === void 0 ? void 0 : _a(entry);
62
+ });
63
+ };
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tylertech/forge-core",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "A library of core web utilities that support Forge Web Component libraries.",
5
5
  "author": "Tyler Technologies, Inc.",
6
6
  "license": "Apache-2.0",
@@ -7,7 +7,9 @@ export * from './a11y';
7
7
  export * from './constants';
8
8
  export * from './custom-elements';
9
9
  export * from './events';
10
+ export * from './media-observer';
10
11
  export * from './message-list';
12
+ export * from './resize';
11
13
  export * from './scroll';
12
14
  export * from './services';
13
15
  export * from './utils';
@@ -0,0 +1,3 @@
1
+ export * from './media-observer';
2
+ export * from './media-observer-utils';
3
+ export * from './types';
@@ -0,0 +1,13 @@
1
+ import { IMediaRange, MediaFeature, NamedMediaQuery, RangeMediaFeature } from './types';
2
+ /** Returns the names of all queries that match. Used for range media features. */
3
+ export declare function getMatchingValues(namedQueries: NamedMediaQuery[]): string[];
4
+ /** Returns the name of one query that matches. Used for discrete media features. */
5
+ export declare function getMatchingValue(namedQueries: NamedMediaQuery[]): string;
6
+ /** Returns whether a query matches. */
7
+ export declare function getBooleanValue(query: NamedMediaQuery): boolean;
8
+ /** Returns a CSS media query string from a range. */
9
+ export declare function getRangeQuery(feature: RangeMediaFeature, range: IMediaRange): string;
10
+ /** Whether a string is the name of a media feature. */
11
+ export declare function isMediaFeature(value: string): value is MediaFeature;
12
+ /** Return `undefined` if the name is a reserved media feature. */
13
+ export declare function validateName(name?: string): string | undefined;
@@ -0,0 +1,101 @@
1
+ import { Subject } from '../observable';
2
+ import { BooleanMediaFeature, IMediaObserverOptions, IMediaRange, MediaFeature as DiscreteMediaFeature, NamedMediaQuery, RangeMediaFeature } from './types';
3
+ /**
4
+ * A Subject that tracks the value of a media feature and exposes it synchronously and
5
+ * asynchronously.
6
+ */
7
+ export declare abstract class MediaObserver<T> extends Subject<T> {
8
+ /**
9
+ * STATIC MEMBERS
10
+ */
11
+ /** A collection of all managed media observers. */
12
+ private static _observers;
13
+ /**
14
+ * Returns a new media observer tracking a discrete feature.
15
+ * @param feature The name of a discrete media feature.
16
+ * @param options An options object with the following properties:
17
+ * - `name`: The name to track the observer by. The feature name is used if unsupplied.
18
+ * - `track`: Whether to make the observer available globally.
19
+ * @returns A `DiscreteMediaObserver` tracking the given feature.
20
+ */
21
+ static observeDiscrete(feature: DiscreteMediaFeature, options?: IMediaObserverOptions): DiscreteMediaObserver;
22
+ /** Returns a media oberserver tracking a range feature. */
23
+ /**
24
+ * Returns a new media observer tracking a range feature.
25
+ * @param feature The name of a range media feature.
26
+ * @param constraints One or more ranges to track. A range includes the following properties:
27
+ * - `name`: A label for the range used to set the observer's value.
28
+ * - `min`: The lowest value in the range (optional).
29
+ * - `max`: The highest value in the range (optional).
30
+ * - `equals`: A single value to match, supersedes `min` and `max` (optional).
31
+ * @param options An options object with the following properties:
32
+ * - `name`: The name to track the observer by. The feature name is used if unsupplied.
33
+ * - `track`: Whether to make the observer available globally.
34
+ * @returns A `RangeMediaObserver` tracking the given feature.
35
+ */
36
+ static observeRange(feature: RangeMediaFeature, constraints: IMediaRange | IMediaRange[], options?: IMediaObserverOptions): RangeMediaObserver;
37
+ /**
38
+ * Returns a media observer tracking a feature that evaluates to a boolean value.
39
+ * @param feature The name of a media feature that can be expressed as a boolean.
40
+ * @param options An options object with the following properties:
41
+ * - `name`: The name to track the observer by. The feature name plus '-bool' is used if unsupplied.
42
+ * - `track`: Whether to make the observer available globally.
43
+ * @returns A `BooleanMediaObserver` tracking the given feature.
44
+ */
45
+ static observeBoolean(feature: BooleanMediaFeature, options?: IMediaObserverOptions): BooleanMediaObserver;
46
+ /** Returns a media observer tracking any media query. */
47
+ /**
48
+ * Returns a media observer tracking any media query.
49
+ * @param query Any media query.
50
+ * @param options An options object with the following properties:
51
+ * - `name`: The name to track the observer by. The entire query string is used if unsupplied.
52
+ * - `track`: Whether to make the observer available globally.
53
+ * @returns A `CustomMediaObserver` tracking the given query.
54
+ */
55
+ static observeCustom(query: string, options?: IMediaObserverOptions): CustomMediaObserver;
56
+ private static _getObserver;
57
+ /**
58
+ * INSTANCE MEMBERS
59
+ */
60
+ private _name;
61
+ get name(): string;
62
+ private _queries;
63
+ protected constructor(name: string, namedQueries: NamedMediaQuery[], value: T, track?: boolean);
64
+ /** Removes the `MediaObserver` and all created event listeners. */
65
+ destroy(): void;
66
+ private _attachMediaQueries;
67
+ protected abstract setValue(value: MediaQueryList | MediaQueryListEvent, name: string): void;
68
+ }
69
+ /**
70
+ * A media observer that tracks one feature with multiple discrete keyword values.
71
+ */
72
+ export declare class DiscreteMediaObserver extends MediaObserver<string> {
73
+ static create(feature: DiscreteMediaFeature, options?: IMediaObserverOptions): DiscreteMediaObserver;
74
+ protected setValue(value: MediaQueryList | MediaQueryListEvent, name: string): void;
75
+ }
76
+ /**
77
+ * A media observer that tracks one feature with comparable range values.
78
+ */
79
+ export declare class RangeMediaObserver extends MediaObserver<string[]> {
80
+ static create(feature: RangeMediaFeature, constraints: IMediaRange[], options?: IMediaObserverOptions): RangeMediaObserver;
81
+ private _isAwaitingQueries;
82
+ private _valueQueue;
83
+ private _isInitialized;
84
+ private constructor();
85
+ protected setValue(value: MediaQueryList | MediaQueryListEvent, name: string): void;
86
+ }
87
+ /**
88
+ * A media observer that tracks one feature that can be coerced to a boolean value. `none` and 0
89
+ * values evaluate to `true`.
90
+ */
91
+ export declare class BooleanMediaObserver extends MediaObserver<boolean> {
92
+ static create(feature: BooleanMediaFeature, options?: IMediaObserverOptions): BooleanMediaObserver;
93
+ protected setValue(value: MediaQueryList | MediaQueryListEvent, _: never): void;
94
+ }
95
+ /**
96
+ * A media observer that tracks any query.
97
+ */
98
+ export declare class CustomMediaObserver extends MediaObserver<MediaQueryList | MediaQueryListEvent> {
99
+ static create(query: string, options?: IMediaObserverOptions): CustomMediaObserver;
100
+ protected setValue(value: MediaQueryList | MediaQueryListEvent, _: never): void;
101
+ }
@@ -0,0 +1,82 @@
1
+ export declare const DISCRETE_MEDIA_FEATURES: readonly ["any-hover", "any-pointer", "color-gamut", "display-mode", "dynamic-range", "forced-colors", "grid", "hover", "inverted-colors", "orientation", "overflow-block", "overflow-inline", "pointer", "prefers-contrast", "prefers-color-scheme", "prefers-reduced-motion", "scripting", "update", "video-dynamic-range"];
2
+ export declare const RANGE_MEDIA_FEATURES: readonly ["aspect-ratio", "color", "color-index", "height", "monochrome", "resolution", "width"];
3
+ export declare const ALL_MEDIA_FEATURES: ("height" | "width" | "color" | "grid" | "update" | "orientation" | "any-hover" | "any-pointer" | "color-gamut" | "display-mode" | "dynamic-range" | "forced-colors" | "hover" | "inverted-colors" | "overflow-block" | "overflow-inline" | "pointer" | "prefers-contrast" | "prefers-color-scheme" | "prefers-reduced-motion" | "scripting" | "video-dynamic-range" | "aspect-ratio" | "color-index" | "monochrome" | "resolution")[];
4
+ export declare const BOOLEAN_MEDIA_FEATURES: readonly ["any-hover", "any-pointer", "color", "color-index", "forced-colors", "grid", "height", "hover", "inverted-colors", "monochrome", "overflow-block", "overflow-inline", "pointer", "scripting", "update", "width"];
5
+ export declare type DiscreteMediaFeature = typeof DISCRETE_MEDIA_FEATURES[number];
6
+ export declare type RangeMediaFeature = typeof RANGE_MEDIA_FEATURES[number];
7
+ export declare type MediaFeature = DiscreteMediaFeature | RangeMediaFeature;
8
+ export declare type BooleanMediaFeature = typeof BOOLEAN_MEDIA_FEATURES[number];
9
+ export declare const colorGamutValues: readonly ["srbg", "p3", "rec2020"];
10
+ export declare const displayModeValues: readonly ["fullscreen", "standalone", "minimal-ui", "browser", "window-controls-overlay"];
11
+ export declare const dynamicRangeValues: readonly ["standard", "high"];
12
+ export declare const forcedColorsValues: readonly ["none", "active"];
13
+ export declare const gridValues: readonly [0, 1];
14
+ export declare const hoverValues: readonly ["none", "hover"];
15
+ export declare const invertedColorsValues: readonly ["none", "inverted"];
16
+ export declare const orientationValues: readonly ["portrait", "landscape"];
17
+ export declare const overflowBlockValues: readonly ["none", "scroll", "optional-paged", "paged"];
18
+ export declare const overflowInlineValues: readonly ["none", "scroll"];
19
+ export declare const pointerValues: readonly ["none", "coarse", "fine"];
20
+ export declare const prefersContrastValues: readonly ["no-preference", "more", "less", "custom"];
21
+ export declare const prefersColorSchemeValues: readonly ["light", "dark"];
22
+ export declare const prefersReducedMotionValues: readonly ["no-preference", "reduce"];
23
+ export declare const scriptingValues: readonly ["none", "initial-only", "enabled"];
24
+ export declare const updateValues: readonly ["none", "slow", "fast"];
25
+ export declare const videoDynamicRangeValues: readonly ["standard", "high"];
26
+ export declare type ColorGamutValue = typeof colorGamutValues[number];
27
+ export declare type DisplayModeValue = typeof displayModeValues[number];
28
+ export declare type DynamicRangeValue = typeof dynamicRangeValues[number];
29
+ export declare type ForcedColorsValue = typeof forcedColorsValues[number];
30
+ export declare type GridValue = typeof gridValues[number];
31
+ export declare type HoverValue = typeof hoverValues[number];
32
+ export declare type InvertedColorsValue = typeof invertedColorsValues[number];
33
+ export declare type OrientationValue = typeof orientationValues[number];
34
+ export declare type OverflowBlockValue = typeof overflowBlockValues[number];
35
+ export declare type OverflowInlineValue = typeof overflowInlineValues[number];
36
+ export declare type PointerValue = typeof pointerValues[number];
37
+ export declare type PrefersContrastValue = typeof prefersContrastValues[number];
38
+ export declare type PrefersColorSchemeValue = typeof prefersColorSchemeValues[number];
39
+ export declare type PrefersReducedMotionValue = typeof prefersReducedMotionValues[number];
40
+ export declare type ScriptingValue = typeof scriptingValues[number];
41
+ export declare type UpdateValue = typeof updateValues[number];
42
+ export declare type VideoDynamicRangeValue = typeof videoDynamicRangeValues[number];
43
+ export declare type NamedMediaQuery = {
44
+ name: string;
45
+ query: string;
46
+ };
47
+ export declare type ManagedMediaQuery = {
48
+ queryList: MediaQueryList;
49
+ handler: MediaQueryHandler;
50
+ };
51
+ export declare type MediaQueryHandler = (event: MediaQueryList | MediaQueryListEvent) => void;
52
+ export declare const mediaFeatureValues: {
53
+ 'any-hover': ("none" | "hover")[];
54
+ 'any-pointer': ("none" | "coarse" | "fine")[];
55
+ 'color-gamut': ("p3" | "rec2020" | "srbg")[];
56
+ 'display-mode': ("browser" | "fullscreen" | "standalone" | "minimal-ui" | "window-controls-overlay")[];
57
+ 'dynamic-range': ("high" | "standard")[];
58
+ 'forced-colors': ("none" | "active")[];
59
+ grid: (0 | 1)[];
60
+ hover: ("none" | "hover")[];
61
+ 'inverted-colors': ("none" | "inverted")[];
62
+ orientation: ("landscape" | "portrait")[];
63
+ 'overflow-block': ("none" | "scroll" | "optional-paged" | "paged")[];
64
+ 'overflow-inline': ("none" | "scroll")[];
65
+ pointer: ("none" | "coarse" | "fine")[];
66
+ 'prefers-contrast': ("custom" | "no-preference" | "more" | "less")[];
67
+ 'prefers-color-scheme': ("light" | "dark")[];
68
+ 'prefers-reduced-motion': ("reduce" | "no-preference")[];
69
+ scripting: ("none" | "initial-only" | "enabled")[];
70
+ update: ("none" | "slow" | "fast")[];
71
+ 'video-dynamic-range': ("high" | "standard")[];
72
+ };
73
+ export interface IMediaObserverOptions {
74
+ name?: string;
75
+ track?: boolean;
76
+ }
77
+ export interface IMediaRange {
78
+ name: string;
79
+ min?: string | number;
80
+ max?: string | number;
81
+ equals?: string | number;
82
+ }
@@ -0,0 +1,2 @@
1
+ export * from './observable';
2
+ export * from './types';
@@ -0,0 +1,18 @@
1
+ import { Observer } from './types';
2
+ export declare class Subject<T> {
3
+ protected source: T;
4
+ protected subscribers: Subscription<T>[];
5
+ get value(): T;
6
+ constructor(value: T);
7
+ subscribe(observer?: Observer<T>): Subscription<T>;
8
+ protected next(value: T): void;
9
+ protected complete(): void;
10
+ }
11
+ export declare class Subscription<T> {
12
+ readonly observer?: Observer<T>;
13
+ private _parent;
14
+ private _closed;
15
+ get closed(): boolean;
16
+ constructor(parent: Subscription<T>[], observer?: Observer<T>);
17
+ unsubscribe(): void;
18
+ }
@@ -0,0 +1 @@
1
+ export declare type Observer<T> = (value: T) => void;
@@ -0,0 +1,2 @@
1
+ export * from './resize-observer';
2
+ export * from './resize-types';
@@ -0,0 +1,34 @@
1
+ import { ForgeResizeObserverCallback, IResizeObserverOptions } from './resize-types';
2
+ /**
3
+ * Provides a set of methods for observing and responding to resizing of elements.
4
+ */
5
+ export declare abstract class ForgeResizeObserver {
6
+ private static _observer?;
7
+ private static _targets;
8
+ /**
9
+ * Initiates the observing of a specified `Element`. Calling with an already observed `Element`
10
+ * overwrites the exisiting observation. It is expected that the consumer will eventually
11
+ * {@link unobserve} the `Element` to avoid memory leaks.
12
+ *
13
+ * @param target An `Element` reference.
14
+ * @param callback A function that accepts a `ResizeObserverEntry` for the `Element`.
15
+ * @param options An options object allowing you to set options for the observation.
16
+ */
17
+ static observe(target: Element, callback: ForgeResizeObserverCallback, options?: IResizeObserverOptions): void;
18
+ /**
19
+ * Ends the observing of a specified `Element`.
20
+ *
21
+ * @param target An `Element` reference.
22
+ */
23
+ static unobserve(target: Element): void;
24
+ /**
25
+ * Creates or destroys the `ResizeObserver` based on whether targets exist.
26
+ */
27
+ private static _countTargets;
28
+ /**
29
+ * Runs the callback function of targets when they are resized.
30
+ *
31
+ * @param entries An array of `ResizeObserverEntry`s.
32
+ */
33
+ private static _handleResize;
34
+ }
@@ -0,0 +1,4 @@
1
+ export declare type ForgeResizeObserverCallback = (entry: ResizeObserverEntry) => unknown;
2
+ export interface IResizeObserverOptions {
3
+ box: 'content-box' | 'border-box' | 'device-pixel-content-box';
4
+ }