@design-edito/tools 0.4.6 → 0.4.12

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.
Files changed (59) hide show
  1. package/agnostic/arrays/index.d.ts +1 -1
  2. package/agnostic/arrays/index.js +1 -1
  3. package/agnostic/arrays/make/index.d.ts +1 -1
  4. package/agnostic/css/index.d.ts +2 -2
  5. package/agnostic/css/index.js +2 -2
  6. package/agnostic/css/scale/index.d.ts +46 -16
  7. package/agnostic/css/scale/index.js +67 -38
  8. package/agnostic/css/scale/index.test.js +81 -64
  9. package/agnostic/html/deep-select/index.d.ts +31 -0
  10. package/agnostic/html/deep-select/index.js +52 -0
  11. package/agnostic/html/hyper-json/smart-tags/coalesced/index.d.ts +13 -13
  12. package/agnostic/html/hyper-json/smart-tags/coalesced/index.js +13 -13
  13. package/agnostic/html/hyper-json/smart-tags/isolated/index.d.ts +1 -1
  14. package/agnostic/html/hyper-json/smart-tags/isolated/index.js +1 -1
  15. package/agnostic/html/index.d.ts +4 -2
  16. package/agnostic/html/index.js +4 -2
  17. package/agnostic/html/watch-selection/index.d.ts +41 -0
  18. package/agnostic/html/watch-selection/index.js +50 -0
  19. package/agnostic/index.d.ts +3 -3
  20. package/agnostic/index.js +3 -3
  21. package/agnostic/misc/index.d.ts +1 -1
  22. package/agnostic/misc/index.js +1 -1
  23. package/agnostic/numbers/index.d.ts +3 -3
  24. package/agnostic/numbers/index.js +3 -3
  25. package/agnostic/objects/index.d.ts +2 -2
  26. package/agnostic/objects/index.js +2 -2
  27. package/agnostic/optim/index.d.ts +1 -1
  28. package/agnostic/optim/index.js +1 -1
  29. package/agnostic/strings/index.d.ts +2 -1
  30. package/agnostic/strings/index.js +2 -1
  31. package/agnostic/strings/split-trim/index.d.ts +27 -0
  32. package/agnostic/strings/split-trim/index.js +36 -0
  33. package/components/Video/index.controlled.d.ts +153 -0
  34. package/components/Video/index.controlled.js +255 -0
  35. package/components/Video/index.d.ts +10 -114
  36. package/components/Video/index.js +140 -265
  37. package/components/Video/utils.d.ts +11 -10
  38. package/components/Video/utils.js +30 -37
  39. package/components/index.d.ts +2 -2
  40. package/components/index.js +2 -2
  41. package/components/public-classnames.d.ts +1 -0
  42. package/components/public-classnames.js +1 -0
  43. package/index.d.ts +1 -1
  44. package/index.js +1 -1
  45. package/node/@aws-s3/storage/directory/index.d.ts +1 -1
  46. package/node/@aws-s3/storage/directory/index.js +1 -1
  47. package/node/@aws-s3/storage/file/index.d.ts +1 -1
  48. package/node/@aws-s3/storage/file/index.js +1 -1
  49. package/node/@google-cloud/storage/file/index.d.ts +1 -1
  50. package/node/@google-cloud/storage/file/index.js +1 -1
  51. package/node/ftps/file/index.d.ts +1 -1
  52. package/node/ftps/file/index.js +1 -1
  53. package/node/images/transform/operations/index.d.ts +2 -2
  54. package/node/images/transform/operations/index.js +2 -2
  55. package/node/index.d.ts +3 -3
  56. package/node/index.js +3 -3
  57. package/node/sftp/file/index.d.ts +2 -2
  58. package/node/sftp/file/index.js +2 -2
  59. package/package.json +22 -1
@@ -1,6 +1,6 @@
1
1
  export * as dedupe from './dedupe/index.js'
2
- export * as isArrayOf from './is-array-of/index.js'
3
2
  export * as findDuplicates from './find-duplicates/index.js'
3
+ export * as isArrayOf from './is-array-of/index.js'
4
4
  export * as make from './make/index.js'
5
5
  export * as randomPick from './random-pick/index.js'
6
6
  export * as shuffle from './shuffle/index.js'
@@ -1,6 +1,6 @@
1
1
  export * as dedupe from './dedupe/index.js'
2
- export * as isArrayOf from './is-array-of/index.js'
3
2
  export * as findDuplicates from './find-duplicates/index.js'
3
+ export * as isArrayOf from './is-array-of/index.js'
4
4
  export * as make from './make/index.js'
5
5
  export * as randomPick from './random-pick/index.js'
6
6
  export * as shuffle from './shuffle/index.js'
@@ -1,5 +1,5 @@
1
1
  /** Function that generates a value for each array position. */
2
- type Filler<T = any> = (pos?: number) => T;
2
+ type Filler<T = any> = (pos: number) => T;
3
3
  /**
4
4
  * Creates an array of a specified length using a filler function.
5
5
  *
@@ -1,6 +1,6 @@
1
- export * as bem from './bem/index.js'
2
1
  export * as clss from './clss/index.js'
2
+ export * as generateNiceColor from './generate-nice-color/index.js'
3
3
  export * as isValidCssClassName from './is-valid-css-class-name/index.js'
4
4
  export * as scale from './scale/index.js'
5
- export * as generateNiceColor from './generate-nice-color/index.js'
5
+ export * as bem from './bem/index.js'
6
6
  export * as stylesSet from './styles-set/index.js'
@@ -1,6 +1,6 @@
1
- export * as bem from './bem/index.js'
2
1
  export * as clss from './clss/index.js'
2
+ export * as generateNiceColor from './generate-nice-color/index.js'
3
3
  export * as isValidCssClassName from './is-valid-css-class-name/index.js'
4
4
  export * as scale from './scale/index.js'
5
- export * as generateNiceColor from './generate-nice-color/index.js'
5
+ export * as bem from './bem/index.js'
6
6
  export * as stylesSet from './styles-set/index.js'
@@ -1,20 +1,50 @@
1
- /** Describes a scale configuration for generating CSS values across levels and screen widths. */
2
- export type ScaleDescriptor = {
3
- /** The lower and upper bounds for screen width in pixels, e.g., `[minWidth, maxWidth]`. */ screenBounds: [number, number];
4
- /** The minimum and maximum values for the low-level range, used at the lower end of the scale. */ lowLevel: [number, number];
5
- /** The minimum and maximum values for the high-level range, used at the higher end of the scale. */ highLevel: [number, number];
6
- /** The total number of discrete steps in the scale (must be 2 for interpolation). */ steps: number;
7
- /** Optional. Whether to wrap the resulting CSS value in a `clamp()` function to enforce bounds. */ clamp?: boolean;
1
+ /**
2
+ * Generates an array of interpolated values between a minimum and maximum using a geometric progression.
3
+ *
4
+ * @param {number} min - The starting value of the scale.
5
+ * @param {number} max - The ending value of the scale.
6
+ * @param {number} intermediateLevels - The number of intermediate levels between min and max.
7
+ * @returns {number[]} An array of rounded values including the minimum and interpolated steps up to the maximum.
8
+ */
9
+ export declare const interpolateLevels: (min: number, max: number, intermediateLevels: number) => number[];
10
+ /** Describes the configuration used to compute scale values across breakpoints. */
11
+ export type ScaleDataOptions = {
12
+ /** Ordered list of breakpoint widths in pixels. Must contain at least two values. */ breakpoints: number[];
13
+ /** The minimum and maximum values for the low end of the scale. */ loScaleBounds: [number, number];
14
+ /** The minimum and maximum values for the high end of the scale. */ hiScaleBounds: [number, number];
15
+ /** Number of intermediate levels between the minimum and maximum values. */ intermediateLevels: number;
16
+ };
17
+ /**
18
+ * Computes scale data for each breakpoint, including interpolated levels.
19
+ *
20
+ * @param {ScaleDataOptions} options - Configuration for generating scale data.
21
+ * @param {number[]} options.breakpoints - Ordered list of breakpoint widths in pixels.
22
+ * @param {[number, number]} options.loScaleBounds - Minimum and maximum values for the low end of the scale.
23
+ * @param {[number, number]} options.hiScaleBounds - Minimum and maximum values for the high end of the scale.
24
+ * @param {number} options.intermediateLevels - Number of intermediate levels between bounds.
25
+ * @throws Will throw if `breakpoints` contains fewer than two values.
26
+ */
27
+ export declare const getScaleData: ({ breakpoints, loScaleBounds, hiScaleBounds, intermediateLevels }: ScaleDataOptions) => Array<{
28
+ breakpoint: number;
29
+ levels: number[];
30
+ }>;
31
+ /** Extends scale data options with CSS generation parameters. */
32
+ export type GenerateScaleCssOptions = ScaleDataOptions & {
33
+ /** The base name used for generated CSS custom properties. */ scaleName: string;
34
+ /** The CSS selector that will receive the custom properties. */ targetSelector: string;
35
+ /** The unit to append to each generated value (e.g., `px`, `rem`). */ unit: string;
8
36
  };
9
37
  /**
10
- * Creates a scale function that maps a level to a CSS size value using harmonic interpolation.
38
+ * Generates responsive CSS custom properties for a scale across breakpoints.
11
39
  *
12
- * @param {ScaleDescriptor} descriptor - The scale configuration.
13
- * @param {[number, number]} descriptor.screenBounds - The lower and upper bounds for screen width in pixels.
14
- * @param {[number, number]} descriptor.lowLevel - Minimum and maximum values for the low level range.
15
- * @param {[number, number]} descriptor.highLevel - Minimum and maximum values for the high level range.
16
- * @param {number} descriptor.steps - Number of discrete steps in the scale.
17
- * @param {boolean} [descriptor.clamp] - Whether to wrap the resulting CSS value in a `clamp()` function.
18
- * @returns {(level: number) => string | undefined} A function mapping a level to a CSS value string.
40
+ * @param {GenerateScaleCssOptions} options - Configuration for generating the CSS output.
41
+ * @param {string} options.scaleName - Base name for CSS custom properties.
42
+ * @param {string} options.targetSelector - CSS selector to which the properties will be applied.
43
+ * @param {string} options.unit - Unit appended to each value.
44
+ * @param {number[]} options.breakpoints - Ordered list of breakpoint widths in pixels.
45
+ * @param {[number, number]} options.loScaleBounds - Minimum and maximum values for the low end of the scale.
46
+ * @param {[number, number]} options.hiScaleBounds - Minimum and maximum values for the high end of the scale.
47
+ * @param {number} options.intermediateLevels - Number of intermediate levels between bounds.
48
+ * @returns {string} A CSS string containing custom properties for each breakpoint, wrapped in media queries where applicable.
19
49
  */
20
- export declare function createScale(descriptor: ScaleDescriptor): (level: number) => string | undefined;
50
+ export declare const generateScaleCss: ({ scaleName, targetSelector, unit, ...options }: GenerateScaleCssOptions) => string;
@@ -1,42 +1,71 @@
1
- import { round } from '../../numbers/round/index.js';
2
1
  import { getGeometricStep } from '../../numbers/geometric-progressions/index.js';
2
+ import { round } from '../../numbers/round/index.js';
3
+ import { make as makeArr } from '../../arrays/make/index.js';
4
+ /**
5
+ * Generates an array of interpolated values between a minimum and maximum using a geometric progression.
6
+ *
7
+ * @param {number} min - The starting value of the scale.
8
+ * @param {number} max - The ending value of the scale.
9
+ * @param {number} intermediateLevels - The number of intermediate levels between min and max.
10
+ * @returns {number[]} An array of rounded values including the minimum and interpolated steps up to the maximum.
11
+ */
12
+ export const interpolateLevels = (min, max, intermediateLevels) => [
13
+ round(min, 2),
14
+ ...makeArr(pos => round(getGeometricStep(min, max, pos + 1, intermediateLevels + 1), 2), intermediateLevels + 1)
15
+ ];
16
+ /**
17
+ * Computes scale data for each breakpoint, including interpolated levels.
18
+ *
19
+ * @param {ScaleDataOptions} options - Configuration for generating scale data.
20
+ * @param {number[]} options.breakpoints - Ordered list of breakpoint widths in pixels.
21
+ * @param {[number, number]} options.loScaleBounds - Minimum and maximum values for the low end of the scale.
22
+ * @param {[number, number]} options.hiScaleBounds - Minimum and maximum values for the high end of the scale.
23
+ * @param {number} options.intermediateLevels - Number of intermediate levels between bounds.
24
+ * @throws Will throw if `breakpoints` contains fewer than two values.
25
+ */
26
+ export const getScaleData = ({ breakpoints, loScaleBounds, hiScaleBounds, intermediateLevels }) => {
27
+ const [loMinValuePx, loMaxValuePx] = loScaleBounds;
28
+ const [hiMinValuePx, hiMaxValuePx] = hiScaleBounds;
29
+ const loValueDiff = loMaxValuePx - loMinValuePx;
30
+ const hiValueDiff = hiMaxValuePx - hiMinValuePx;
31
+ const maxBreakpoint = breakpoints.at(-1);
32
+ const minBreakpoint = breakpoints.at(0);
33
+ if (breakpoints.length < 2
34
+ || maxBreakpoint === undefined
35
+ || minBreakpoint === undefined)
36
+ throw new Error(`\`breakpoints\` length must be at least 2. Found ${breakpoints.length}`);
37
+ return breakpoints.map(breakpoint => {
38
+ const thisBreakpointRatio = (breakpoint - minBreakpoint) / (maxBreakpoint - minBreakpoint);
39
+ const lo = (thisBreakpointRatio * loValueDiff) + loMinValuePx;
40
+ const hi = (thisBreakpointRatio * hiValueDiff) + hiMinValuePx;
41
+ return {
42
+ breakpoint,
43
+ levels: interpolateLevels(lo, hi, intermediateLevels)
44
+ };
45
+ });
46
+ };
3
47
  /**
4
- * Creates a scale function that maps a level to a CSS size value using harmonic interpolation.
48
+ * Generates responsive CSS custom properties for a scale across breakpoints.
5
49
  *
6
- * @param {ScaleDescriptor} descriptor - The scale configuration.
7
- * @param {[number, number]} descriptor.screenBounds - The lower and upper bounds for screen width in pixels.
8
- * @param {[number, number]} descriptor.lowLevel - Minimum and maximum values for the low level range.
9
- * @param {[number, number]} descriptor.highLevel - Minimum and maximum values for the high level range.
10
- * @param {number} descriptor.steps - Number of discrete steps in the scale.
11
- * @param {boolean} [descriptor.clamp] - Whether to wrap the resulting CSS value in a `clamp()` function.
12
- * @returns {(level: number) => string | undefined} A function mapping a level to a CSS value string.
50
+ * @param {GenerateScaleCssOptions} options - Configuration for generating the CSS output.
51
+ * @param {string} options.scaleName - Base name for CSS custom properties.
52
+ * @param {string} options.targetSelector - CSS selector to which the properties will be applied.
53
+ * @param {string} options.unit - Unit appended to each value.
54
+ * @param {number[]} options.breakpoints - Ordered list of breakpoint widths in pixels.
55
+ * @param {[number, number]} options.loScaleBounds - Minimum and maximum values for the low end of the scale.
56
+ * @param {[number, number]} options.hiScaleBounds - Minimum and maximum values for the high end of the scale.
57
+ * @param {number} options.intermediateLevels - Number of intermediate levels between bounds.
58
+ * @returns {string} A CSS string containing custom properties for each breakpoint, wrapped in media queries where applicable.
13
59
  */
14
- export function createScale(descriptor) {
15
- const { screenBounds: [loBound, hiBound], lowLevel: [loLevelMin, loLevelMax], highLevel: [hiLevelMin, hiLevelMax], steps, clamp } = descriptor;
16
- return function scale(level) {
17
- if (steps < 2)
18
- return;
19
- const loBoundVal = getGeometricStep(loLevelMin, hiLevelMin, level - 1, steps - 1);
20
- const hiBoundVal = getGeometricStep(loLevelMax, hiLevelMax, level - 1, steps - 1);
21
- if (loBoundVal === undefined)
22
- return;
23
- if (hiBoundVal === undefined)
24
- return;
25
- const affine = getAffineFunction(loBound, loBoundVal, hiBound, hiBoundVal);
26
- const cssFormula = getCssValueFromAffine(affine);
27
- return clamp === true
28
- ? `clamp(${round(loBoundVal, 2)}px, ${cssFormula}, ${round(hiBoundVal, 2)}px)`
29
- : cssFormula;
30
- };
31
- }
32
- function getAffineFunction(x1, y1, x2, y2) {
33
- const slope = (y2 - y1) / (x2 - x1);
34
- const yIntercept = y1 - (x1 * slope);
35
- return { slope, yIntercept };
36
- }
37
- function getCssValueFromAffine(affine) {
38
- const { slope, yIntercept } = affine;
39
- const roundedSlope = round(100 * slope, 3);
40
- const roundedIntercept = round(yIntercept, 2);
41
- return `calc(${roundedSlope}vw + ${roundedIntercept}px)`;
42
- }
60
+ export const generateScaleCss = ({ scaleName, targetSelector, unit, ...options }) => getScaleData(options).map(({ breakpoint, levels }, pos) => {
61
+ const levelsCss = levels.map((lvlVal, lvlPos) => `--${scaleName}-${lvlPos}: ${lvlVal}${unit};`);
62
+ if (pos === 0)
63
+ return `${targetSelector} {
64
+ ${levelsCss.join('\n ')}
65
+ }\n`;
66
+ return `@media (min-width: ${breakpoint}px) {
67
+ ${targetSelector} {
68
+ ${levelsCss.join('\n ')}
69
+ }
70
+ }\n`;
71
+ }).join('\n');
@@ -1,71 +1,88 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { createScale } from './index.js';
3
- import * as geo from '../../numbers/geometric-progressions/index.js';
4
- describe('createScale', () => {
5
- it('returns a function', () => {
6
- const descriptor = {
7
- screenBounds: [320, 1280],
8
- lowLevel: [10, 20],
9
- highLevel: [30, 60],
10
- steps: 5
11
- };
12
- const scaleFn = createScale(descriptor);
13
- expect(typeof scaleFn).toBe('function');
1
+ import { describe, it, expect } from 'vitest';
2
+ import { interpolateLevels, getScaleData, generateScaleCss } from './index.js';
3
+ describe('interpolateLevels', () => {
4
+ it('returns an array including min and interpolated values', () => {
5
+ const result = interpolateLevels(10, 20, 2);
6
+ expect(result.length).toBe(4);
7
+ expect(result[0]).toBe(10);
8
+ expect(result.at(-1)).toBeCloseTo(20, 2);
14
9
  });
15
- it('produces CSS calc() formula for intermediate levels', () => {
16
- const descriptor = {
17
- screenBounds: [320, 1280],
18
- lowLevel: [10, 20],
19
- highLevel: [30, 60],
20
- steps: 5
21
- };
22
- const scaleFn = createScale(descriptor);
23
- const cssValue = scaleFn(3);
24
- expect(cssValue).toMatch(/^calc\([\d.]+vw \+ [\d.]+px\)$/);
10
+ it('rounds values to 2 decimals', () => {
11
+ const result = interpolateLevels(10, 20, 3);
12
+ result.forEach(val => {
13
+ expect(Number(val.toFixed(2))).toBe(val);
14
+ });
25
15
  });
26
- it('wraps result in clamp() when clamp is true', () => {
27
- const descriptor = {
28
- screenBounds: [320, 1280],
29
- lowLevel: [10, 20],
30
- highLevel: [30, 60],
31
- steps: 5,
32
- clamp: true
33
- };
34
- const scaleFn = createScale(descriptor);
35
- const cssValue = scaleFn(3);
36
- expect(cssValue).toMatch(/^clamp\([\d.]+px, calc\([\d.]+vw \+ [\d.]+px\), [\d.]+px\)$/);
16
+ it('handles descending ranges', () => {
17
+ const result = interpolateLevels(20, 10, 2);
18
+ expect(result[0]).toBe(20);
19
+ expect(result.at(-1)).toBeCloseTo(10, 2);
37
20
  });
38
- it('returns undefined if steps < 2', () => {
39
- const descriptor = {
40
- screenBounds: [320, 1280],
41
- lowLevel: [10, 20],
42
- highLevel: [30, 60],
43
- steps: 1
44
- };
45
- const scaleFn = createScale(descriptor);
46
- expect(scaleFn(1)).toBeUndefined();
21
+ });
22
+ describe('getScaleData', () => {
23
+ const baseOptions = {
24
+ breakpoints: [320, 768, 1280],
25
+ loScaleBounds: [10, 20],
26
+ hiScaleBounds: [30, 60],
27
+ intermediateLevels: 2
28
+ };
29
+ it('returns one entry per breakpoint', () => {
30
+ const result = getScaleData(baseOptions);
31
+ expect(result.length).toBe(baseOptions.breakpoints.length);
32
+ });
33
+ it('includes breakpoint and levels', () => {
34
+ const result = getScaleData(baseOptions);
35
+ result.forEach(entry => {
36
+ expect(entry).toHaveProperty('breakpoint');
37
+ expect(entry).toHaveProperty('levels');
38
+ expect(Array.isArray(entry.levels)).toBe(true);
39
+ });
40
+ });
41
+ it('interpolates values between low and high bounds', () => {
42
+ const result = getScaleData(baseOptions);
43
+ const first = result[0];
44
+ const last = result.at(-1);
45
+ expect(first?.levels[0]).toBeCloseTo(10, 2);
46
+ expect(last?.levels.at(-1)).toBeCloseTo(60, 2);
47
+ });
48
+ it('throws if breakpoints length < 2', () => {
49
+ expect(() => getScaleData({
50
+ ...baseOptions,
51
+ breakpoints: [320]
52
+ })).toThrow();
53
+ });
54
+ });
55
+ describe('generateScaleCss', () => {
56
+ const options = {
57
+ scaleName: 'size',
58
+ targetSelector: ':root',
59
+ unit: 'px',
60
+ breakpoints: [320, 768],
61
+ loScaleBounds: [10, 20],
62
+ hiScaleBounds: [30, 40],
63
+ intermediateLevels: 1
64
+ };
65
+ it('generates base CSS block for first breakpoint', () => {
66
+ const css = generateScaleCss(options);
67
+ expect(css).toMatch(/:root\s*{[^}]+}/);
68
+ });
69
+ it('generates media queries for subsequent breakpoints', () => {
70
+ const css = generateScaleCss(options);
71
+ expect(css).toMatch(/@media \(min-width: 768px\)/);
72
+ });
73
+ it('generates CSS custom properties with correct naming', () => {
74
+ const css = generateScaleCss(options);
75
+ expect(css).toMatch(/--size-0:/);
76
+ expect(css).toMatch(/--size-1:/);
47
77
  });
48
- it('handles descending low/high levels', () => {
49
- const descriptor = {
50
- screenBounds: [320, 1280],
51
- lowLevel: [20, 10],
52
- highLevel: [60, 30],
53
- steps: 5
54
- };
55
- const scaleFn = createScale(descriptor);
56
- const cssValue = scaleFn(3);
57
- expect(cssValue).toMatch(/^calc\(-?[\d.]+vw \+ -?[\d.]+px\)$/);
78
+ it('applies the provided unit', () => {
79
+ const css = generateScaleCss(options);
80
+ expect(css).toMatch(/px;/);
58
81
  });
59
- it('propagates NaN from getGeometricStep', () => {
60
- vi.spyOn(geo, 'getGeometricStep').mockReturnValueOnce(NaN);
61
- const descriptor = {
62
- screenBounds: [320, 1280],
63
- lowLevel: [10, 20],
64
- highLevel: [30, 60],
65
- steps: 5
66
- };
67
- const scaleFn = createScale(descriptor);
68
- const result = scaleFn(2);
69
- expect(result).toBe('calc(NaNvw + NaNpx)');
82
+ it('produces consistent number of variables per breakpoint', () => {
83
+ const css = generateScaleCss(options);
84
+ const matches = css.match(/--size-\d+:/g) ?? [];
85
+ // 3 levels * 2 breakpoints
86
+ expect(matches.length).toBe(6);
70
87
  });
71
88
  });
@@ -0,0 +1,31 @@
1
+ /** Options for `deepSelect`. */
2
+ type Options = {
3
+ /** Root node to start traversal from. Defaults to `document`. */
4
+ fromElement?: Element;
5
+ /** Number of element nodes to visit before yielding to the main thread. Defaults to `500`. */
6
+ chunkSize?: number;
7
+ };
8
+ /**
9
+ * Queries the DOM for all elements matching a CSS selector, including inside open shadow roots.
10
+ *
11
+ * Walks the tree with `document.createTreeWalker` instead of `querySelectorAll`, so traversal can
12
+ * descend into `element.shadowRoot` trees that standard selectors do not pierce. The traversal
13
+ * root (`fromElement` or `document`) is never included in the results, even if it matches.
14
+ *
15
+ * Yields to the main thread every `chunkSize` visited nodes, using `scheduler.yield()` when
16
+ * available or `setTimeout(0)` as a fallback. Requires a browser environment with `document`.
17
+ *
18
+ * @param {string} selector - CSS selector tested with `Element.prototype.matches`.
19
+ * @param {Options} [options] - Optional configuration:
20
+ * - `fromElement`: Element (or `document`) to start the walk from.
21
+ * - `chunkSize`: How many element nodes to process between yields.
22
+ * @returns {Promise<Element[]>} All matching elements in tree-walker order (depth-first).
23
+ *
24
+ * @example
25
+ * const items = await deepSelect('[data-item]', { fromElement: app })
26
+ *
27
+ * @example
28
+ * const labels = await deepSelect('.label', { chunkSize: 100 })
29
+ */
30
+ export declare const deepSelect: (selector: string, options?: Options) => Promise<Element[]>;
31
+ export {};
@@ -0,0 +1,52 @@
1
+ import * as Window from '../../misc/crossenv/window/index.js';
2
+ const yieldToMain = async (windowLike) => {
3
+ if (typeof windowLike.scheduler?.yield === 'function')
4
+ return windowLike.scheduler.yield();
5
+ return await new Promise(resolve => setTimeout(resolve, 0));
6
+ };
7
+ /**
8
+ * Queries the DOM for all elements matching a CSS selector, including inside open shadow roots.
9
+ *
10
+ * Walks the tree with `document.createTreeWalker` instead of `querySelectorAll`, so traversal can
11
+ * descend into `element.shadowRoot` trees that standard selectors do not pierce. The traversal
12
+ * root (`fromElement` or `document`) is never included in the results, even if it matches.
13
+ *
14
+ * Yields to the main thread every `chunkSize` visited nodes, using `scheduler.yield()` when
15
+ * available or `setTimeout(0)` as a fallback. Requires a browser environment with `document`.
16
+ *
17
+ * @param {string} selector - CSS selector tested with `Element.prototype.matches`.
18
+ * @param {Options} [options] - Optional configuration:
19
+ * - `fromElement`: Element (or `document`) to start the walk from.
20
+ * - `chunkSize`: How many element nodes to process between yields.
21
+ * @returns {Promise<Element[]>} All matching elements in tree-walker order (depth-first).
22
+ *
23
+ * @example
24
+ * const items = await deepSelect('[data-item]', { fromElement: app })
25
+ *
26
+ * @example
27
+ * const labels = await deepSelect('.label', { chunkSize: 100 })
28
+ */
29
+ export const deepSelect = async (selector, options) => {
30
+ const window = Window.get();
31
+ const { document } = window;
32
+ const from = options?.fromElement ?? document;
33
+ const results = [];
34
+ const chunkSize = options?.chunkSize ?? 500;
35
+ let nodeCount = 0;
36
+ const traverse = async (root) => {
37
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
38
+ let node = walker.currentNode;
39
+ while (node instanceof Element) {
40
+ if (node !== root && node.matches(selector))
41
+ results.push(node);
42
+ if (node.shadowRoot !== null)
43
+ await traverse(node.shadowRoot);
44
+ nodeCount++;
45
+ if (nodeCount % chunkSize === 0)
46
+ await yieldToMain(window);
47
+ node = walker.nextNode();
48
+ }
49
+ };
50
+ await traverse(from);
51
+ return results;
52
+ };
@@ -1,52 +1,52 @@
1
- export * as addclass from './addclass/index.js'
2
1
  export * as add from './add/index.js'
2
+ export * as addclass from './addclass/index.js'
3
3
  export * as and from './and/index.js'
4
- export * as at from './at/index.js'
5
4
  export * as append from './append/index.js'
6
5
  export * as call from './call/index.js'
6
+ export * as at from './at/index.js'
7
+ export * as clone from './clone/index.js'
7
8
  export * as deleteproperties from './deleteproperties/index.js'
8
9
  export * as equals from './equals/index.js'
9
10
  export * as getattribute from './getattribute/index.js'
10
- export * as clone from './clone/index.js'
11
+ export * as getproperties from './getproperties/index.js'
11
12
  export * as getproperty from './getproperty/index.js'
12
13
  export * as hjparse from './hjparse/index.js'
13
14
  export * as hjstringify from './hjstringify/index.js'
14
- export * as initialize from './initialize/index.js'
15
15
  export * as if from './if/index.js'
16
16
  export * as join from './join/index.js'
17
- export * as getproperties from './getproperties/index.js'
17
+ export * as initialize from './initialize/index.js'
18
18
  export * as length from './length/index.js'
19
19
  export * as map from './map/index.js'
20
20
  export * as notrailing from './notrailing/index.js'
21
21
  export * as or from './or/index.js'
22
- export * as negate from './negate/index.js'
23
22
  export * as pickrandom from './pickrandom/index.js'
24
- export * as print from './print/index.js'
23
+ export * as negate from './negate/index.js'
25
24
  export * as populate from './populate/index.js'
25
+ export * as print from './print/index.js'
26
26
  export * as push from './push/index.js'
27
27
  export * as pusheach from './pusheach/index.js'
28
- export * as removeattribute from './removeattribute/index.js'
29
28
  export * as recordtoarray from './recordtoarray/index.js'
29
+ export * as removeattribute from './removeattribute/index.js'
30
30
  export * as renameproperty from './renameproperty/index.js'
31
31
  export * as removeclass from './removeclass/index.js'
32
32
  export * as replace from './replace/index.js'
33
33
  export * as select from './select/index.js'
34
+ export * as setattribute from './setattribute/index.js'
34
35
  export * as setproperty from './setproperty/index.js'
36
+ export * as set from './set/index.js'
35
37
  export * as sorton from './sorton/index.js'
36
- export * as split from './split/index.js'
37
38
  export * as spread from './spread/index.js'
38
- export * as set from './set/index.js'
39
- export * as setattribute from './setattribute/index.js'
39
+ export * as split from './split/index.js'
40
40
  export * as toarray from './toarray/index.js'
41
41
  export * as toboolean from './toboolean/index.js'
42
42
  export * as toelement from './toelement/index.js'
43
43
  export * as toggleclass from './toggleclass/index.js'
44
44
  export * as tonodelist from './tonodelist/index.js'
45
- export * as tonumber from './tonumber/index.js'
46
45
  export * as tonull from './tonull/index.js'
46
+ export * as tonumber from './tonumber/index.js'
47
47
  export * as torecord from './torecord/index.js'
48
48
  export * as toref from './toref/index.js'
49
- export * as totext from './totext/index.js'
50
49
  export * as tostring from './tostring/index.js'
50
+ export * as totext from './totext/index.js'
51
51
  export * as transformselected from './transformselected/index.js'
52
52
  export * as trim from './trim/index.js'
@@ -1,52 +1,52 @@
1
- export * as addclass from './addclass/index.js'
2
1
  export * as add from './add/index.js'
2
+ export * as addclass from './addclass/index.js'
3
3
  export * as and from './and/index.js'
4
- export * as at from './at/index.js'
5
4
  export * as append from './append/index.js'
6
5
  export * as call from './call/index.js'
6
+ export * as at from './at/index.js'
7
+ export * as clone from './clone/index.js'
7
8
  export * as deleteproperties from './deleteproperties/index.js'
8
9
  export * as equals from './equals/index.js'
9
10
  export * as getattribute from './getattribute/index.js'
10
- export * as clone from './clone/index.js'
11
+ export * as getproperties from './getproperties/index.js'
11
12
  export * as getproperty from './getproperty/index.js'
12
13
  export * as hjparse from './hjparse/index.js'
13
14
  export * as hjstringify from './hjstringify/index.js'
14
- export * as initialize from './initialize/index.js'
15
15
  export * as if from './if/index.js'
16
16
  export * as join from './join/index.js'
17
- export * as getproperties from './getproperties/index.js'
17
+ export * as initialize from './initialize/index.js'
18
18
  export * as length from './length/index.js'
19
19
  export * as map from './map/index.js'
20
20
  export * as notrailing from './notrailing/index.js'
21
21
  export * as or from './or/index.js'
22
- export * as negate from './negate/index.js'
23
22
  export * as pickrandom from './pickrandom/index.js'
24
- export * as print from './print/index.js'
23
+ export * as negate from './negate/index.js'
25
24
  export * as populate from './populate/index.js'
25
+ export * as print from './print/index.js'
26
26
  export * as push from './push/index.js'
27
27
  export * as pusheach from './pusheach/index.js'
28
- export * as removeattribute from './removeattribute/index.js'
29
28
  export * as recordtoarray from './recordtoarray/index.js'
29
+ export * as removeattribute from './removeattribute/index.js'
30
30
  export * as renameproperty from './renameproperty/index.js'
31
31
  export * as removeclass from './removeclass/index.js'
32
32
  export * as replace from './replace/index.js'
33
33
  export * as select from './select/index.js'
34
+ export * as setattribute from './setattribute/index.js'
34
35
  export * as setproperty from './setproperty/index.js'
36
+ export * as set from './set/index.js'
35
37
  export * as sorton from './sorton/index.js'
36
- export * as split from './split/index.js'
37
38
  export * as spread from './spread/index.js'
38
- export * as set from './set/index.js'
39
- export * as setattribute from './setattribute/index.js'
39
+ export * as split from './split/index.js'
40
40
  export * as toarray from './toarray/index.js'
41
41
  export * as toboolean from './toboolean/index.js'
42
42
  export * as toelement from './toelement/index.js'
43
43
  export * as toggleclass from './toggleclass/index.js'
44
44
  export * as tonodelist from './tonodelist/index.js'
45
- export * as tonumber from './tonumber/index.js'
46
45
  export * as tonull from './tonull/index.js'
46
+ export * as tonumber from './tonumber/index.js'
47
47
  export * as torecord from './torecord/index.js'
48
48
  export * as toref from './toref/index.js'
49
- export * as totext from './totext/index.js'
50
49
  export * as tostring from './tostring/index.js'
50
+ export * as totext from './totext/index.js'
51
51
  export * as transformselected from './transformselected/index.js'
52
52
  export * as trim from './trim/index.js'
@@ -3,8 +3,8 @@ export * as array from './array/index.js'
3
3
  export * as boolean from './boolean/index.js'
4
4
  export * as element from './element/index.js'
5
5
  export * as get from './get/index.js'
6
- export * as nodelist from './nodelist/index.js'
7
6
  export * as guess from './guess/index.js'
7
+ export * as nodelist from './nodelist/index.js'
8
8
  export * as null from './null/index.js'
9
9
  export * as number from './number/index.js'
10
10
  export * as record from './record/index.js'
@@ -3,8 +3,8 @@ export * as array from './array/index.js'
3
3
  export * as boolean from './boolean/index.js'
4
4
  export * as element from './element/index.js'
5
5
  export * as get from './get/index.js'
6
- export * as nodelist from './nodelist/index.js'
7
6
  export * as guess from './guess/index.js'
7
+ export * as nodelist from './nodelist/index.js'
8
8
  export * as null from './null/index.js'
9
9
  export * as number from './number/index.js'
10
10
  export * as record from './record/index.js'