@design-edito/tools 0.5.28 → 0.5.30

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 (39) hide show
  1. package/agnostic/html/hyper-json/smart-tags/coalesced/index.d.ts +7 -7
  2. package/agnostic/html/hyper-json/smart-tags/coalesced/index.js +7 -7
  3. package/agnostic/html/hyper-json/smart-tags/isolated/index.d.ts +1 -1
  4. package/agnostic/html/hyper-json/smart-tags/isolated/index.js +1 -1
  5. package/agnostic/html/index.d.ts +3 -3
  6. package/agnostic/html/index.js +3 -3
  7. package/agnostic/index.d.ts +3 -3
  8. package/agnostic/index.js +3 -3
  9. package/agnostic/misc/index.d.ts +1 -1
  10. package/agnostic/misc/index.js +1 -1
  11. package/agnostic/misc/logs/index.d.ts +1 -1
  12. package/agnostic/misc/logs/index.js +1 -1
  13. package/agnostic/optim/index.d.ts +1 -1
  14. package/agnostic/optim/index.js +1 -1
  15. package/agnostic/time/dates/index.d.ts +1 -1
  16. package/agnostic/time/dates/index.js +1 -1
  17. package/agnostic/time/index.d.ts +1 -1
  18. package/agnostic/time/index.js +1 -1
  19. package/components/Drawer/index.d.ts +26 -2
  20. package/components/Drawer/index.js +96 -8
  21. package/components/Sequencer/index.d.ts +13 -1
  22. package/components/Sequencer/index.js +40 -3
  23. package/components/index.d.ts +2 -2
  24. package/components/index.js +2 -2
  25. package/node/@google-cloud/storage/directory/index.d.ts +2 -2
  26. package/node/@google-cloud/storage/directory/index.js +2 -2
  27. package/node/cloud-storage/index.d.ts +1 -1
  28. package/node/cloud-storage/index.js +1 -1
  29. package/node/cloud-storage/operations/index.d.ts +3 -3
  30. package/node/cloud-storage/operations/index.js +3 -3
  31. package/node/ftps/directory/index.d.ts +1 -1
  32. package/node/ftps/directory/index.js +1 -1
  33. package/node/images/index.d.ts +1 -1
  34. package/node/images/index.js +1 -1
  35. package/node/images/transform/operations/index.d.ts +2 -2
  36. package/node/images/transform/operations/index.js +2 -2
  37. package/node/index.d.ts +2 -2
  38. package/node/index.js +2 -2
  39. package/package.json +1 -1
@@ -2,24 +2,24 @@ export * as add from './add/index.js'
2
2
  export * as addclass from './addclass/index.js'
3
3
  export * as and from './and/index.js'
4
4
  export * as append from './append/index.js'
5
+ export * as at from './at/index.js'
5
6
  export * as call from './call/index.js'
6
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
11
  export * as getproperties from './getproperties/index.js'
11
- export * as at from './at/index.js'
12
12
  export * as getproperty from './getproperty/index.js'
13
13
  export * as hjparse from './hjparse/index.js'
14
14
  export * as hjstringify from './hjstringify/index.js'
15
15
  export * as if from './if/index.js'
16
16
  export * as join from './join/index.js'
17
17
  export * as length from './length/index.js'
18
- export * as initialize from './initialize/index.js'
19
18
  export * as map from './map/index.js'
19
+ export * as initialize from './initialize/index.js'
20
20
  export * as negate from './negate/index.js'
21
- export * as notrailing from './notrailing/index.js'
22
21
  export * as or from './or/index.js'
22
+ export * as notrailing from './notrailing/index.js'
23
23
  export * as pickrandom from './pickrandom/index.js'
24
24
  export * as populate from './populate/index.js'
25
25
  export * as print from './print/index.js'
@@ -32,19 +32,19 @@ export * as renameproperty from './renameproperty/index.js'
32
32
  export * as replace from './replace/index.js'
33
33
  export * as select from './select/index.js'
34
34
  export * as set from './set/index.js'
35
- export * as setattribute from './setattribute/index.js'
36
35
  export * as setproperty from './setproperty/index.js'
37
36
  export * as sorton from './sorton/index.js'
38
37
  export * as split from './split/index.js'
39
38
  export * as spread from './spread/index.js'
40
- export * as toarray from './toarray/index.js'
41
39
  export * as toboolean from './toboolean/index.js'
40
+ export * as toarray from './toarray/index.js'
42
41
  export * as toelement from './toelement/index.js'
43
42
  export * as toggleclass from './toggleclass/index.js'
44
- export * as tonodelist from './tonodelist/index.js'
43
+ export * as setattribute from './setattribute/index.js'
45
44
  export * as tonull from './tonull/index.js'
46
- export * as tonumber from './tonumber/index.js'
45
+ export * as tonodelist from './tonodelist/index.js'
47
46
  export * as torecord from './torecord/index.js'
47
+ export * as tonumber from './tonumber/index.js'
48
48
  export * as toref from './toref/index.js'
49
49
  export * as tostring from './tostring/index.js'
50
50
  export * as totext from './totext/index.js'
@@ -2,24 +2,24 @@ export * as add from './add/index.js'
2
2
  export * as addclass from './addclass/index.js'
3
3
  export * as and from './and/index.js'
4
4
  export * as append from './append/index.js'
5
+ export * as at from './at/index.js'
5
6
  export * as call from './call/index.js'
6
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
11
  export * as getproperties from './getproperties/index.js'
11
- export * as at from './at/index.js'
12
12
  export * as getproperty from './getproperty/index.js'
13
13
  export * as hjparse from './hjparse/index.js'
14
14
  export * as hjstringify from './hjstringify/index.js'
15
15
  export * as if from './if/index.js'
16
16
  export * as join from './join/index.js'
17
17
  export * as length from './length/index.js'
18
- export * as initialize from './initialize/index.js'
19
18
  export * as map from './map/index.js'
19
+ export * as initialize from './initialize/index.js'
20
20
  export * as negate from './negate/index.js'
21
- export * as notrailing from './notrailing/index.js'
22
21
  export * as or from './or/index.js'
22
+ export * as notrailing from './notrailing/index.js'
23
23
  export * as pickrandom from './pickrandom/index.js'
24
24
  export * as populate from './populate/index.js'
25
25
  export * as print from './print/index.js'
@@ -32,19 +32,19 @@ export * as renameproperty from './renameproperty/index.js'
32
32
  export * as replace from './replace/index.js'
33
33
  export * as select from './select/index.js'
34
34
  export * as set from './set/index.js'
35
- export * as setattribute from './setattribute/index.js'
36
35
  export * as setproperty from './setproperty/index.js'
37
36
  export * as sorton from './sorton/index.js'
38
37
  export * as split from './split/index.js'
39
38
  export * as spread from './spread/index.js'
40
- export * as toarray from './toarray/index.js'
41
39
  export * as toboolean from './toboolean/index.js'
40
+ export * as toarray from './toarray/index.js'
42
41
  export * as toelement from './toelement/index.js'
43
42
  export * as toggleclass from './toggleclass/index.js'
44
- export * as tonodelist from './tonodelist/index.js'
43
+ export * as setattribute from './setattribute/index.js'
45
44
  export * as tonull from './tonull/index.js'
46
- export * as tonumber from './tonumber/index.js'
45
+ export * as tonodelist from './tonodelist/index.js'
47
46
  export * as torecord from './torecord/index.js'
47
+ export * as tonumber from './tonumber/index.js'
48
48
  export * as toref from './toref/index.js'
49
49
  export * as tostring from './tostring/index.js'
50
50
  export * as totext from './totext/index.js'
@@ -8,6 +8,6 @@ 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'
11
- export * as string from './string/index.js'
12
11
  export * as ref from './ref/index.js'
12
+ export * as string from './string/index.js'
13
13
  export * as text from './text/index.js'
@@ -8,6 +8,6 @@ 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'
11
- export * as string from './string/index.js'
12
11
  export * as ref from './ref/index.js'
12
+ export * as string from './string/index.js'
13
13
  export * as text from './text/index.js'
@@ -1,10 +1,10 @@
1
+ export * as deepSelect from './deep-select/index.js'
1
2
  export * as getNodeAncestors from './get-node-ancestors/index.js'
2
- export * as getPositionInsideParent from './get-position-inside-parent/index.js'
3
3
  export * as hyperJson from './hyper-json/index.js'
4
4
  export * as insertNode from './insert-node/index.js'
5
+ export * as getPositionInsideParent from './get-position-inside-parent/index.js'
5
6
  export * as placeholders from './placeholders/index.js'
6
7
  export * as replaceInElement from './replace-in-element/index.js'
7
- export * as selectorToElement from './selector-to-element/index.js'
8
8
  export * as stringToNodes from './string-to-nodes/index.js'
9
+ export * as selectorToElement from './selector-to-element/index.js'
9
10
  export * as watchSelection from './watch-selection/index.js'
10
- export * as deepSelect from './deep-select/index.js'
@@ -1,10 +1,10 @@
1
+ export * as deepSelect from './deep-select/index.js'
1
2
  export * as getNodeAncestors from './get-node-ancestors/index.js'
2
- export * as getPositionInsideParent from './get-position-inside-parent/index.js'
3
3
  export * as hyperJson from './hyper-json/index.js'
4
4
  export * as insertNode from './insert-node/index.js'
5
+ export * as getPositionInsideParent from './get-position-inside-parent/index.js'
5
6
  export * as placeholders from './placeholders/index.js'
6
7
  export * as replaceInElement from './replace-in-element/index.js'
7
- export * as selectorToElement from './selector-to-element/index.js'
8
8
  export * as stringToNodes from './string-to-nodes/index.js'
9
+ export * as selectorToElement from './selector-to-element/index.js'
9
10
  export * as watchSelection from './watch-selection/index.js'
10
- export * as deepSelect from './deep-select/index.js'
@@ -3,15 +3,15 @@ export * as booleans from './booleans/index.js'
3
3
  export * as colors from './colors/index.js'
4
4
  export * as css from './css/index.js'
5
5
  export * as errors from './errors/index.js'
6
- export * as html from './html/index.js'
7
- export * as misc from './misc/index.js'
8
6
  export * as numbers from './numbers/index.js'
9
7
  export * as objects from './objects/index.js'
10
- export * as random from './random/index.js'
11
8
  export * as optim from './optim/index.js'
9
+ export * as random from './random/index.js'
12
10
  export * as regexps from './regexps/index.js'
13
11
  export * as sanitization from './sanitization/index.js'
14
12
  export * as strings from './strings/index.js'
13
+ export * as html from './html/index.js'
14
+ export * as misc from './misc/index.js'
15
15
  export * as subtitles from './subtitles/index.js'
16
16
  export * as time from './time/index.js'
17
17
  export * as typescript from './typescript/index.js'
package/agnostic/index.js CHANGED
@@ -3,15 +3,15 @@ export * as booleans from './booleans/index.js'
3
3
  export * as colors from './colors/index.js'
4
4
  export * as css from './css/index.js'
5
5
  export * as errors from './errors/index.js'
6
- export * as html from './html/index.js'
7
- export * as misc from './misc/index.js'
8
6
  export * as numbers from './numbers/index.js'
9
7
  export * as objects from './objects/index.js'
10
- export * as random from './random/index.js'
11
8
  export * as optim from './optim/index.js'
9
+ export * as random from './random/index.js'
12
10
  export * as regexps from './regexps/index.js'
13
11
  export * as sanitization from './sanitization/index.js'
14
12
  export * as strings from './strings/index.js'
13
+ export * as html from './html/index.js'
14
+ export * as misc from './misc/index.js'
15
15
  export * as subtitles from './subtitles/index.js'
16
16
  export * as time from './time/index.js'
17
17
  export * as typescript from './typescript/index.js'
@@ -4,9 +4,9 @@ export * as connection from './connection/index.js'
4
4
  export * as crawler from './crawler/index.js'
5
5
  export * as crossenv from './crossenv/index.js'
6
6
  export * as dataSize from './data-size/index.js'
7
- export * as isConstructorFunction from './is-constructor-function/index.js'
8
7
  export * as isNullish from './is-nullish/index.js'
9
8
  export * as logs from './logs/index.js'
9
+ export * as isConstructorFunction from './is-constructor-function/index.js'
10
10
  export * as loremIpsum from './lorem-ipsum/index.js'
11
11
  export * as normalizeExtension from './normalize-extension/index.js'
12
12
  export * as outcome from './outcome/index.js'
@@ -4,9 +4,9 @@ export * as connection from './connection/index.js'
4
4
  export * as crawler from './crawler/index.js'
5
5
  export * as crossenv from './crossenv/index.js'
6
6
  export * as dataSize from './data-size/index.js'
7
- export * as isConstructorFunction from './is-constructor-function/index.js'
8
7
  export * as isNullish from './is-nullish/index.js'
9
8
  export * as logs from './logs/index.js'
9
+ export * as isConstructorFunction from './is-constructor-function/index.js'
10
10
  export * as loremIpsum from './lorem-ipsum/index.js'
11
11
  export * as normalizeExtension from './normalize-extension/index.js'
12
12
  export * as outcome from './outcome/index.js'
@@ -1,3 +1,3 @@
1
1
  export * as logger from './logger/index.js'
2
- export * as makeTextBlock from './make-text-block/index.js'
3
2
  export * as styles from './styles/index.js'
3
+ export * as makeTextBlock from './make-text-block/index.js'
@@ -1,3 +1,3 @@
1
1
  export * as logger from './logger/index.js'
2
- export * as makeTextBlock from './make-text-block/index.js'
3
2
  export * as styles from './styles/index.js'
3
+ export * as makeTextBlock from './make-text-block/index.js'
@@ -1,2 +1,2 @@
1
- export * as memoize from './memoize/index.js'
2
1
  export * as throttleDebounce from './throttle-debounce/index.js'
2
+ export * as memoize from './memoize/index.js'
@@ -1,2 +1,2 @@
1
- export * as memoize from './memoize/index.js'
2
1
  export * as throttleDebounce from './throttle-debounce/index.js'
2
+ export * as memoize from './memoize/index.js'
@@ -1,2 +1,2 @@
1
- export * as formatDate from './format-date/index.js'
2
1
  export * as toFrenchRepublican from './to-french-republican/index.js'
2
+ export * as formatDate from './format-date/index.js'
@@ -1,2 +1,2 @@
1
- export * as formatDate from './format-date/index.js'
2
1
  export * as toFrenchRepublican from './to-french-republican/index.js'
2
+ export * as formatDate from './format-date/index.js'
@@ -1,5 +1,5 @@
1
- export * as dates from './dates/index.js'
2
1
  export * as duration from './duration/index.js'
2
+ export * as dates from './dates/index.js'
3
3
  export * as timeout from './timeout/index.js'
4
4
  export * as transitions from './transitions/index.js'
5
5
  export * as wait from './wait/index.js'
@@ -1,5 +1,5 @@
1
- export * as dates from './dates/index.js'
2
1
  export * as duration from './duration/index.js'
2
+ export * as dates from './dates/index.js'
3
3
  export * as timeout from './timeout/index.js'
4
4
  export * as transitions from './transitions/index.js'
5
5
  export * as wait from './wait/index.js'
@@ -3,8 +3,19 @@ import type { WithClassName } from '../utils/types.js';
3
3
  /**
4
4
  * Props for the {@link Drawer} component.
5
5
  *
6
- * @property openerContent - Content rendered inside the opener control.
7
- * @property closerContent - Content rendered inside the closer control.
6
+ * @property openerContent - Content rendered inside the opener control. Not
7
+ * necessarily a button: a command is a bar, and most consumers put a title *and* a
8
+ * toggle in it — hence `openerContent` rather than `openerBtnContent`.
9
+ * @property closerContent - Content rendered inside the closer control. Defaults to
10
+ * `openerContent`, so a bar written once serves both states and CSS tells them apart
11
+ * through the root modifiers. Pass `null` to render an empty closer.
12
+ * @property openerBtnSelector - CSS selector picking the toggle *inside*
13
+ * `openerContent`. Without it the whole bar opens the drawer; with it, only a click
14
+ * landing inside a matching descendant does. Whatever it points at receives the
15
+ * `opener-btn` class, so CSS can reach the toggle too. An invalid selector falls back
16
+ * to the whole bar.
17
+ * @property closerBtnSelector - Same, for the closer. Defaults to
18
+ * `openerBtnSelector`, like the content it goes with.
8
19
  * @property defaultIsOpened - Initial open state in uncontrolled mode.
9
20
  * Ignored when `isOpened` is provided. Defaults to `false`.
10
21
  * @property isOpened - Controlled open state. When defined, the component
@@ -23,6 +34,8 @@ import type { WithClassName } from '../utils/types.js';
23
34
  export type Props = PropsWithChildren<WithClassName<{
24
35
  openerContent?: ReactNode;
25
36
  closerContent?: ReactNode;
37
+ openerBtnSelector?: string;
38
+ closerBtnSelector?: string;
26
39
  defaultIsOpened?: boolean;
27
40
  isOpened?: boolean;
28
41
  onOpenerClicked?: (isOpened: boolean) => void;
@@ -49,6 +62,9 @@ export type Props = PropsWithChildren<WithClassName<{
49
62
  * - `opener`
50
63
  * - `closer`
51
64
  * - `content`
65
+ * - `opener-btn` / `closer-btn` — the toggle. On the bar itself when the whole bar is
66
+ * clickable, on whatever `openerBtnSelector` / `closerBtnSelector` point at otherwise.
67
+ * Always present, so a stylesheet has one place to look.
52
68
  *
53
69
  * ### CSS custom properties on the root element
54
70
  * - `--lm-drawer-content-width` / `--lm-drawer-content-width-raw`
@@ -69,5 +85,13 @@ export type Props = PropsWithChildren<WithClassName<{
69
85
  * - `onOpenerClicked` and `onCloserClicked` fire in both modes — a controlled
70
86
  * parent needs them to know a click happened at all.
71
87
  * - `onIsOpenedChanged` fires in both modes too, and never on mount.
88
+ * - **A command is a bar, not a button.** Both content props take whatever the consumer
89
+ * puts in the row — most often a title and a toggle — and `closerContent` /
90
+ * `closerBtnSelector` default to their opener counterpart, so that bar is written
91
+ * once. What tells the two states apart is CSS, through the root modifiers.
92
+ * - **`…BtnSelector` narrows the click, it does not move it.** The handler stays on the
93
+ * bar; the selector only decides which descendants carry the `-btn` class, and the
94
+ * handler asks that class. So the consumer keeps full control of what the row
95
+ * contains, and a stylesheet reaches the toggle without knowing the selector.
72
96
  */
73
97
  export declare const Drawer: FunctionComponent<Props>;
@@ -1,10 +1,62 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from 'react';
2
+ import { useLayoutEffect, useRef, useState } from 'react';
3
3
  import { clss } from '../../agnostic/css/clss/index.js';
4
4
  import { ResizeObserverComponent } from '../ResizeObserver/index.js';
5
5
  import { mergeClassNames, useChangeDispatch } from '../utils/index.js';
6
6
  import { drawer as publicClassName } from '../public-classnames.js';
7
7
  import cssModule from './styles.module.css';
8
+ /**
9
+ * Marks whatever a `…BtnSelector` points at with the command's `-btn` public class.
10
+ *
11
+ * **The class is the single source of truth**, for CSS and for the click handler alike:
12
+ * without it, a stylesheet would have no way to reach the toggle — the selector is a
13
+ * JavaScript prop and leaves no trace in the markup — and the two would answer the
14
+ * question « what is the toggle » by different means.
15
+ *
16
+ * The no-selector case never gets here: the class is then written straight into the
17
+ * bar's own `className`, because the whole bar *is* the toggle. So this hook only ever
18
+ * runs to narrow that down to a few descendants.
19
+ *
20
+ * **It writes into DOM that React owns.** React does not reset an attribute it has not
21
+ * diffed, so the class survives an ordinary re-render — but a bar whose own `className`
22
+ * changes would be rewritten, class included. Hence `content` among the dependencies:
23
+ * whatever makes the content change is also what repairs the marking, before paint.
24
+ *
25
+ * An invalid selector marks the bar itself. A consumer typo would otherwise leave no
26
+ * toggle at all and a drawer that no longer opens; falling back to the whole bar is the
27
+ * behaviour they had before writing the selector.
28
+ */
29
+ function useToggleMarking(barRef, selector, btnClassName, content) {
30
+ useLayoutEffect(() => {
31
+ const bar = barRef.current;
32
+ if (bar === null)
33
+ return;
34
+ bar.querySelectorAll(`.${btnClassName}`).forEach(node => { node.classList.remove(btnClassName); });
35
+ if (selector === undefined)
36
+ return;
37
+ bar.classList.remove(btnClassName);
38
+ try {
39
+ bar.querySelectorAll(selector).forEach(node => { node.classList.add(btnClassName); });
40
+ }
41
+ catch (err) {
42
+ bar.classList.add(btnClassName);
43
+ }
44
+ }, [barRef, selector, btnClassName, content]);
45
+ }
46
+ /**
47
+ * Whether a click on a command should toggle the drawer.
48
+ *
49
+ * The test is « did the click land inside a marked element », never the selector itself:
50
+ * {@link useToggleMarking} has already resolved what the toggle is. `contains` comes on
51
+ * top of `closest` because a marked element could, in principle, sit outside this bar.
52
+ */
53
+ function isToggleHit(event, btnClassName) {
54
+ const { target, currentTarget } = event;
55
+ if (!(target instanceof Element))
56
+ return false;
57
+ const hit = target.closest(`.${btnClassName}`);
58
+ return hit !== null && currentTarget.contains(hit);
59
+ }
8
60
  /**
9
61
  * Drawer component supporting controlled and uncontrolled usage.
10
62
  *
@@ -21,6 +73,9 @@ import cssModule from './styles.module.css';
21
73
  * - `opener`
22
74
  * - `closer`
23
75
  * - `content`
76
+ * - `opener-btn` / `closer-btn` — the toggle. On the bar itself when the whole bar is
77
+ * clickable, on whatever `openerBtnSelector` / `closerBtnSelector` point at otherwise.
78
+ * Always present, so a stylesheet has one place to look.
24
79
  *
25
80
  * ### CSS custom properties on the root element
26
81
  * - `--lm-drawer-content-width` / `--lm-drawer-content-width-raw`
@@ -41,25 +96,55 @@ import cssModule from './styles.module.css';
41
96
  * - `onOpenerClicked` and `onCloserClicked` fire in both modes — a controlled
42
97
  * parent needs them to know a click happened at all.
43
98
  * - `onIsOpenedChanged` fires in both modes too, and never on mount.
99
+ * - **A command is a bar, not a button.** Both content props take whatever the consumer
100
+ * puts in the row — most often a title and a toggle — and `closerContent` /
101
+ * `closerBtnSelector` default to their opener counterpart, so that bar is written
102
+ * once. What tells the two states apart is CSS, through the root modifiers.
103
+ * - **`…BtnSelector` narrows the click, it does not move it.** The handler stays on the
104
+ * bar; the selector only decides which descendants carry the `-btn` class, and the
105
+ * handler asks that class. So the consumer keeps full control of what the row
106
+ * contains, and a stylesheet reaches the toggle without knowing the selector.
44
107
  */
45
- export const Drawer = ({ openerContent, closerContent, defaultIsOpened = false, isOpened: isOpenedProp, onOpenerClicked, onCloserClicked, onIsOpenedChanged, onContentResized, className, children }) => {
108
+ export const Drawer = ({ openerContent, closerContent, openerBtnSelector, closerBtnSelector, defaultIsOpened = false, isOpened: isOpenedProp, onOpenerClicked, onCloserClicked, onIsOpenedChanged, onContentResized, className, children }) => {
46
109
  // State
47
110
  const [internalIsOpened, setInternalIsOpened] = useState(defaultIsOpened);
48
111
  const [contentDimensions, setContentDimensions] = useState();
112
+ const openerRef = useRef(null);
113
+ const closerRef = useRef(null);
49
114
  const isControlled = isOpenedProp !== undefined;
50
115
  const isOpened = isOpenedProp ?? internalIsOpened;
116
+ // Une barre écrite une fois sert les deux états : le plus souvent un titre et une
117
+ // bascule, identiques ouverts et fermés, que les modifieurs de la racine suffisent à
118
+ // distinguer en CSS. `undefined` seul retombe — un `null` explicite reste un closer
119
+ // vide, et le consommateur garde le moyen de n'en rendre aucun.
120
+ const resolvedCloserContent = closerContent === undefined ? openerContent : closerContent;
121
+ const resolvedCloserBtnSelector = closerBtnSelector ?? openerBtnSelector;
122
+ // Class names
123
+ // Le `-btn` désigne la bascule, et il existe dans tous les cas : posé ici quand la
124
+ // barre entière en tient lieu, posé sur les descendants par {@link useToggleMarking}
125
+ // quand un sélecteur la rétrécit. Une feuille n'a donc qu'un endroit où regarder, et
126
+ // le gestionnaire de clic qu'une question à poser.
127
+ const c = clss(publicClassName, { cssModule });
128
+ const openerBtnClss = c('opener-btn');
129
+ const closerBtnClss = c('closer-btn');
130
+ useToggleMarking(openerRef, openerBtnSelector, openerBtnClss, openerContent);
131
+ useToggleMarking(closerRef, resolvedCloserBtnSelector, closerBtnClss, resolvedCloserContent);
51
132
  // State dispatch
52
133
  useChangeDispatch(isOpened, onIsOpenedChanged);
53
134
  useChangeDispatch(contentDimensions, dimensions => { if (dimensions !== undefined)
54
135
  onContentResized?.(dimensions); }, (a, b) => a?.width === b?.width && a?.height === b?.height);
55
136
  // User action handlers
56
- const handleOpenerClick = () => {
137
+ const handleOpenerClick = (event) => {
138
+ if (!isToggleHit(event, openerBtnClss))
139
+ return;
57
140
  onOpenerClicked?.(isOpened);
58
141
  if (isControlled)
59
142
  return;
60
143
  setInternalIsOpened(true);
61
144
  };
62
- const handleCloserClick = () => {
145
+ const handleCloserClick = (event) => {
146
+ if (!isToggleHit(event, closerBtnClss))
147
+ return;
63
148
  onCloserClicked?.(isOpened);
64
149
  if (isControlled)
65
150
  return;
@@ -70,14 +155,17 @@ export const Drawer = ({ openerContent, closerContent, defaultIsOpened = false,
70
155
  setContentDimensions({ width, height });
71
156
  };
72
157
  // Rendering
73
- const c = clss(publicClassName, { cssModule });
74
158
  const rootClss = mergeClassNames(c(null, {
75
159
  'opened': isOpened,
76
160
  'closed': !isOpened,
77
161
  measured: contentDimensions !== undefined
78
162
  }), className);
79
- const openerClss = c('opener');
80
- const closerClss = c('closer');
163
+ const openerClss = openerBtnSelector === undefined
164
+ ? mergeClassNames(c('opener'), openerBtnClss)
165
+ : c('opener');
166
+ const closerClss = resolvedCloserBtnSelector === undefined
167
+ ? mergeClassNames(c('closer'), closerBtnClss)
168
+ : c('closer');
81
169
  const contentClss = c('content');
82
170
  let dataAttributes = {};
83
171
  let customCssProps = {};
@@ -94,5 +182,5 @@ export const Drawer = ({ openerContent, closerContent, defaultIsOpened = false,
94
182
  '--lm-drawer-content-height-raw': `${height}`
95
183
  };
96
184
  }
97
- return _jsxs("div", { className: rootClss, ...dataAttributes, style: { ...customCssProps }, children: [_jsx("div", { className: openerClss, onClick: handleOpenerClick, children: openerContent }), _jsx("div", { className: closerClss, onClick: handleCloserClick, children: closerContent }), _jsx("div", { className: contentClss, children: _jsx(ResizeObserverComponent, { onResized: handleContentResized, children: children }) })] });
185
+ return _jsxs("div", { className: rootClss, ...dataAttributes, style: { ...customCssProps }, children: [_jsx("div", { ref: openerRef, className: openerClss, onClick: handleOpenerClick, children: openerContent }), _jsx("div", { ref: closerRef, className: closerClss, onClick: handleCloserClick, children: resolvedCloserContent }), _jsx("div", { className: contentClss, children: _jsx(ResizeObserverComponent, { onResized: handleContentResized, children: children }) })] });
98
186
  };
@@ -109,7 +109,19 @@ export type Props = PropsWithChildren<WithClassName<{
109
109
  *
110
110
  * ### On the root
111
111
  * `--playing`, `--at-start`, `--at-end`, `--ended`, plus `data-step`, `data-active-step`,
112
- * `data-total-steps` and `data-tempo`.
112
+ * `data-total-steps`, `data-tempo` and `data-lap`.
113
+ *
114
+ * The same five numbers are also published as custom properties —
115
+ * `--lm-sequencer-step`, `--lm-sequencer-active-step`, `--lm-sequencer-total-steps`,
116
+ * `--lm-sequencer-tempo`, `--lm-sequencer-lap` — plus `--lm-sequencer-raw-step`, the
117
+ * counter that keeps growing across laps (`lap × total + step`). **A data attribute
118
+ * selects, a custom property computes**: `attr()` cannot feed a `calc()`, so a rule that
119
+ * wants to turn something by a degree per step needs the property, and gets it on every
120
+ * descendant since custom properties inherit —
121
+ * `transform: rotate(calc(var(--lm-sequencer-raw-step) * 5deg))`.
122
+ *
123
+ * No `-raw` twin as `ResizeObserver` has: every one of these is a bare number, and none
124
+ * of them would mean anything with a unit attached.
113
125
  *
114
126
  * ### On each element child
115
127
  * The `__child` element class, then three pairs, one of each always present:
@@ -145,7 +145,19 @@ function stepsOf(child, elementIndex) {
145
145
  *
146
146
  * ### On the root
147
147
  * `--playing`, `--at-start`, `--at-end`, `--ended`, plus `data-step`, `data-active-step`,
148
- * `data-total-steps` and `data-tempo`.
148
+ * `data-total-steps`, `data-tempo` and `data-lap`.
149
+ *
150
+ * The same five numbers are also published as custom properties —
151
+ * `--lm-sequencer-step`, `--lm-sequencer-active-step`, `--lm-sequencer-total-steps`,
152
+ * `--lm-sequencer-tempo`, `--lm-sequencer-lap` — plus `--lm-sequencer-raw-step`, the
153
+ * counter that keeps growing across laps (`lap × total + step`). **A data attribute
154
+ * selects, a custom property computes**: `attr()` cannot feed a `calc()`, so a rule that
155
+ * wants to turn something by a degree per step needs the property, and gets it on every
156
+ * descendant since custom properties inherit —
157
+ * `transform: rotate(calc(var(--lm-sequencer-raw-step) * 5deg))`.
158
+ *
159
+ * No `-raw` twin as `ResizeObserver` has: every one of these is a bare number, and none
160
+ * of them would mean anything with a unit attached.
149
161
  *
150
162
  * ### On each element child
151
163
  * The `__child` element class, then three pairs, one of each always present:
@@ -212,6 +224,14 @@ export const Sequencer = ({ totalSteps, stepMap, step, defaultStep, play, defaul
212
224
  // absolute, so setting it to a bare position on a looping sequence would count as a
213
225
  // wrap backwards and fire `onLooped` for a move nobody made. `jump-by` is left alone
214
226
  // on purpose — stepping past the last position really is a wrap, and says so.
227
+ //
228
+ // **The lap offset is for looping sequences only, and adding it elsewhere was a bug.**
229
+ // A sequence that does not loop runs its counter one past the end and leaves it there,
230
+ // so `lap` reads `1` from that moment on — and `jump-start` landed on `1 * stepsCount`,
231
+ // which is precisely the ended position it was asked to leave. The symptom: a sequence
232
+ // with `whenVisible='jump-start'` played once, stopped on its last step, and stayed
233
+ // there however many times it was scrolled past. Nothing is lost by dropping the
234
+ // offset here: without `loop`, there is no wrap to misread and `onLooped` never fires.
215
235
  const jumpToPosition = (target) => {
216
236
  if (step !== undefined || stepsCount <= 0)
217
237
  return;
@@ -219,7 +239,7 @@ export const Sequencer = ({ totalSteps, stepMap, step, defaultStep, play, defaul
219
239
  const bounded = loop === true
220
240
  ? absoluteModulo(resolved, stepsCount)
221
241
  : clamp(resolved, 0, stepsCount - 1);
222
- setInternalStep(lap * stepsCount + bounded);
242
+ setInternalStep(loop === true ? lap * stepsCount + bounded : bounded);
223
243
  };
224
244
  const jumpBy = (offset) => {
225
245
  if (step !== undefined || stepsCount <= 0)
@@ -297,8 +317,25 @@ export const Sequencer = ({ totalSteps, stepMap, step, defaultStep, play, defaul
297
317
  }
298
318
  return positions;
299
319
  };
320
+ // **The lap count is the wraps, so it is zero without `loop`.** The internal counter
321
+ // runs one past the end and stays there, which makes `lap` read `1` on a sequence that
322
+ // never wrapped at all — true of the division, false of the thing it is named after,
323
+ // and `onLooped` says the same by never firing without `loop`.
324
+ const publishedLap = loop === true ? lap : 0;
325
+ // Rebuilt from the published lap rather than read off `rawStep`, for that same reason:
326
+ // at the end of a non-looping sequence the internal counter sits one step past the last
327
+ // position, and a number meant to drive a transform must not overshoot the picture.
328
+ const rawStepProp = publishedLap * stepsCount + position;
329
+ const cssCustomProps = {
330
+ '--lm-sequencer-step': `${position}`,
331
+ '--lm-sequencer-active-step': `${activeStep}`,
332
+ '--lm-sequencer-total-steps': `${stepsCount}`,
333
+ '--lm-sequencer-tempo': `${tempo}`,
334
+ '--lm-sequencer-lap': `${publishedLap}`,
335
+ '--lm-sequencer-raw-step': `${rawStepProp}`
336
+ };
300
337
  let elementIndex = -1;
301
- return _jsx("div", { ref: rootRef, className: rootClss, "data-step": position, "data-active-step": activeStep, "data-total-steps": stepsCount, "data-tempo": tempo, children: childrenArr.map((child, childPos) => {
338
+ return _jsx("div", { ref: rootRef, className: rootClss, "data-step": position, "data-active-step": activeStep, "data-total-steps": stepsCount, "data-tempo": tempo, "data-lap": publishedLap, style: { ...cssCustomProps }, children: childrenArr.map((child, childPos) => {
302
339
  if (!isValidElement(child))
303
340
  return child;
304
341
  elementIndex += 1;
@@ -5,8 +5,8 @@ export * as disclaimer from './Disclaimer/index.js'
5
5
  export * as drawer from './Drawer/index.js'
6
6
  export * as eventListener from './EventListener/index.js'
7
7
  export * as gallery from './Gallery/index.js'
8
- export * as image from './Image/index.js'
9
8
  export * as iframe from './Iframe/index.js'
9
+ export * as image from './Image/index.js'
10
10
  export * as input from './Input/index.js'
11
11
  export * as intersectionObserver from './IntersectionObserver/index.js'
12
12
  export * as jsonEditor from './JsonEditor/index.js'
@@ -16,8 +16,8 @@ export * as overlayer from './Overlayer/index.js'
16
16
  export * as paginator from './Paginator/index.js'
17
17
  export * as resizeObserver from './ResizeObserver/index.js'
18
18
  export * as scrllgngn from './Scrllgngn/index.js'
19
- export * as scrollListener from './ScrollListener/index.js'
20
19
  export * as select from './Select/index.js'
20
+ export * as scrollListener from './ScrollListener/index.js'
21
21
  export * as sequencer from './Sequencer/index.js'
22
22
  export * as shadowRoot from './ShadowRoot/index.js'
23
23
  export * as subtitles from './Subtitles/index.js'
@@ -5,8 +5,8 @@ export * as disclaimer from './Disclaimer/index.js'
5
5
  export * as drawer from './Drawer/index.js'
6
6
  export * as eventListener from './EventListener/index.js'
7
7
  export * as gallery from './Gallery/index.js'
8
- export * as image from './Image/index.js'
9
8
  export * as iframe from './Iframe/index.js'
9
+ export * as image from './Image/index.js'
10
10
  export * as input from './Input/index.js'
11
11
  export * as intersectionObserver from './IntersectionObserver/index.js'
12
12
  export * as jsonEditor from './JsonEditor/index.js'
@@ -16,8 +16,8 @@ export * as overlayer from './Overlayer/index.js'
16
16
  export * as paginator from './Paginator/index.js'
17
17
  export * as resizeObserver from './ResizeObserver/index.js'
18
18
  export * as scrllgngn from './Scrllgngn/index.js'
19
- export * as scrollListener from './ScrollListener/index.js'
20
19
  export * as select from './Select/index.js'
20
+ export * as scrollListener from './ScrollListener/index.js'
21
21
  export * as sequencer from './Sequencer/index.js'
22
22
  export * as shadowRoot from './ShadowRoot/index.js'
23
23
  export * as subtitles from './Subtitles/index.js'
@@ -1,4 +1,4 @@
1
- export * as copyDir from './copy-dir/index.js'
2
- export * as list from './list/index.js'
3
1
  export * as moveDir from './move-dir/index.js'
4
2
  export * as removeDir from './remove-dir/index.js'
3
+ export * as copyDir from './copy-dir/index.js'
4
+ export * as list from './list/index.js'
@@ -1,4 +1,4 @@
1
- export * as copyDir from './copy-dir/index.js'
2
- export * as list from './list/index.js'
3
1
  export * as moveDir from './move-dir/index.js'
4
2
  export * as removeDir from './remove-dir/index.js'
3
+ export * as copyDir from './copy-dir/index.js'
4
+ export * as list from './list/index.js'
@@ -1,2 +1,2 @@
1
- export * as operations from './operations/index.js'
2
1
  export * as clients from './clients/index.js'
2
+ export * as operations from './operations/index.js'
@@ -1,2 +1,2 @@
1
- export * as operations from './operations/index.js'
2
1
  export * as clients from './clients/index.js'
2
+ export * as operations from './operations/index.js'
@@ -1,11 +1,11 @@
1
1
  export * as copyDir from './copy-dir/index.js'
2
2
  export * as copyFile from './copy-file/index.js'
3
+ export * as downloadFile from './download-file/index.js'
4
+ export * as existsFile from './exists-file/index.js'
3
5
  export * as listDir from './list-dir/index.js'
4
6
  export * as moveDir from './move-dir/index.js'
5
7
  export * as moveFile from './move-file/index.js'
6
- export * as downloadFile from './download-file/index.js'
7
8
  export * as removeDir from './remove-dir/index.js'
8
9
  export * as removeFile from './remove-file/index.js'
9
- export * as statFile from './stat-file/index.js'
10
- export * as existsFile from './exists-file/index.js'
11
10
  export * as uploadFile from './upload-file/index.js'
11
+ export * as statFile from './stat-file/index.js'
@@ -1,11 +1,11 @@
1
1
  export * as copyDir from './copy-dir/index.js'
2
2
  export * as copyFile from './copy-file/index.js'
3
+ export * as downloadFile from './download-file/index.js'
4
+ export * as existsFile from './exists-file/index.js'
3
5
  export * as listDir from './list-dir/index.js'
4
6
  export * as moveDir from './move-dir/index.js'
5
7
  export * as moveFile from './move-file/index.js'
6
- export * as downloadFile from './download-file/index.js'
7
8
  export * as removeDir from './remove-dir/index.js'
8
9
  export * as removeFile from './remove-file/index.js'
9
- export * as statFile from './stat-file/index.js'
10
- export * as existsFile from './exists-file/index.js'
11
10
  export * as uploadFile from './upload-file/index.js'
11
+ export * as statFile from './stat-file/index.js'
@@ -1,4 +1,4 @@
1
1
  export * as copyDir from './copy-dir/index.js'
2
- export * as list from './list/index.js'
3
2
  export * as moveDir from './move-dir/index.js'
3
+ export * as list from './list/index.js'
4
4
  export * as removeDir from './remove-dir/index.js'
@@ -1,4 +1,4 @@
1
1
  export * as copyDir from './copy-dir/index.js'
2
- export * as list from './list/index.js'
3
2
  export * as moveDir from './move-dir/index.js'
3
+ export * as list from './list/index.js'
4
4
  export * as removeDir from './remove-dir/index.js'
@@ -1,5 +1,5 @@
1
1
  export * as create from './create/index.js'
2
2
  export * as format from './format/index.js'
3
- export * as metadata from './metadata/index.js'
4
3
  export * as transform from './transform/index.js'
5
4
  export * as utils from './utils/index.js'
5
+ export * as metadata from './metadata/index.js'
@@ -1,5 +1,5 @@
1
1
  export * as create from './create/index.js'
2
2
  export * as format from './format/index.js'
3
- export * as metadata from './metadata/index.js'
4
3
  export * as transform from './transform/index.js'
5
4
  export * as utils from './utils/index.js'
5
+ export * as metadata from './metadata/index.js'
@@ -1,13 +1,13 @@
1
1
  export * as blur from './blur/index.js'
2
2
  export * as brighten from './brighten/index.js'
3
- export * as extend from './extend/index.js'
4
3
  export * as extract from './extract/index.js'
5
4
  export * as flatten from './flatten/index.js'
6
5
  export * as flip from './flip/index.js'
7
- export * as flop from './flop/index.js'
8
6
  export * as hue from './hue/index.js'
7
+ export * as flop from './flop/index.js'
9
8
  export * as level from './level/index.js'
10
9
  export * as lighten from './lighten/index.js'
10
+ export * as extend from './extend/index.js'
11
11
  export * as normalize from './normalize/index.js'
12
12
  export * as overlay from './overlay/index.js'
13
13
  export * as resize from './resize/index.js'
@@ -1,13 +1,13 @@
1
1
  export * as blur from './blur/index.js'
2
2
  export * as brighten from './brighten/index.js'
3
- export * as extend from './extend/index.js'
4
3
  export * as extract from './extract/index.js'
5
4
  export * as flatten from './flatten/index.js'
6
5
  export * as flip from './flip/index.js'
7
- export * as flop from './flop/index.js'
8
6
  export * as hue from './hue/index.js'
7
+ export * as flop from './flop/index.js'
9
8
  export * as level from './level/index.js'
10
9
  export * as lighten from './lighten/index.js'
10
+ export * as extend from './extend/index.js'
11
11
  export * as normalize from './normalize/index.js'
12
12
  export * as overlay from './overlay/index.js'
13
13
  export * as resize from './resize/index.js'
package/node/index.d.ts CHANGED
@@ -6,6 +6,6 @@ export * as cloudStorage from './cloud-storage/index.js'
6
6
  export * as encryption from './encryption/index.js'
7
7
  export * as files from './files/index.js'
8
8
  export * as ftps from './ftps/index.js'
9
- export * as images from './images/index.js'
10
- export * as sftp from './sftp/index.js'
11
9
  export * as process from './process/index.js'
10
+ export * as sftp from './sftp/index.js'
11
+ export * as images from './images/index.js'
package/node/index.js CHANGED
@@ -6,6 +6,6 @@ export * as cloudStorage from './cloud-storage/index.js'
6
6
  export * as encryption from './encryption/index.js'
7
7
  export * as files from './files/index.js'
8
8
  export * as ftps from './ftps/index.js'
9
- export * as images from './images/index.js'
10
- export * as sftp from './sftp/index.js'
11
9
  export * as process from './process/index.js'
10
+ export * as sftp from './sftp/index.js'
11
+ export * as images from './images/index.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@design-edito/tools",
3
- "version": "0.5.28",
3
+ "version": "0.5.30",
4
4
  "description": "",
5
5
  "author": "Maxime Fabas",
6
6
  "license": "ISC",