@design-edito/tools 0.5.2 → 0.5.3

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 (129) hide show
  1. package/agnostic/html/deep-select/index.js +5 -3
  2. package/agnostic/html/hyper-json/smart-tags/coalesced/index.d.ts +8 -8
  3. package/agnostic/html/hyper-json/smart-tags/coalesced/index.js +8 -8
  4. package/agnostic/html/hyper-json/smart-tags/isolated/index.d.ts +2 -2
  5. package/agnostic/html/hyper-json/smart-tags/isolated/index.js +2 -2
  6. package/agnostic/html/index.d.ts +1 -1
  7. package/agnostic/html/index.js +1 -1
  8. package/agnostic/misc/index.d.ts +3 -3
  9. package/agnostic/misc/index.js +3 -3
  10. package/agnostic/numbers/index.d.ts +1 -1
  11. package/agnostic/numbers/index.js +1 -1
  12. package/agnostic/optim/index.d.ts +1 -1
  13. package/agnostic/optim/index.js +1 -1
  14. package/agnostic/strings/index.d.ts +1 -1
  15. package/agnostic/strings/index.js +1 -1
  16. package/agnostic/time/dates/format-date/index.d.ts +4 -2
  17. package/agnostic/time/dates/format-date/index.js +43 -94
  18. package/agnostic/time/dates/format-date/index.test.js +154 -0
  19. package/agnostic/time/dates/format-date/parts.d.ts +28 -0
  20. package/agnostic/time/dates/format-date/parts.js +136 -0
  21. package/agnostic/time/dates/format-date/types.d.ts +84 -0
  22. package/agnostic/time/dates/format-date/types.js +1 -0
  23. package/agnostic/time/duration/format-duration/index.d.ts +42 -0
  24. package/agnostic/time/duration/format-duration/index.js +94 -0
  25. package/agnostic/time/duration/format-duration/index.test.d.ts +1 -0
  26. package/agnostic/time/duration/format-duration/index.test.js +148 -0
  27. package/agnostic/time/duration/format-duration/parts.d.ts +32 -0
  28. package/agnostic/time/duration/format-duration/parts.js +107 -0
  29. package/agnostic/time/duration/format-duration/types.d.ts +93 -0
  30. package/agnostic/time/duration/format-duration/types.js +1 -0
  31. package/agnostic/time/duration/index.d.ts +6 -1
  32. package/agnostic/time/duration/index.js +2 -2
  33. package/agnostic/time/duration/index.test.d.ts +1 -0
  34. package/agnostic/time/duration/index.test.js +168 -0
  35. package/agnostic/time/index.d.ts +1 -1
  36. package/agnostic/time/index.js +1 -1
  37. package/components/BeforeAfter/index.controlled.d.ts +25 -25
  38. package/components/BeforeAfter/index.controlled.js +47 -53
  39. package/components/BeforeAfter/index.d.ts +20 -23
  40. package/components/BeforeAfter/index.js +48 -40
  41. package/components/Button/index.js +1 -1
  42. package/components/Clippable/index.d.ts +17 -26
  43. package/components/Clippable/index.js +21 -23
  44. package/components/Disclaimer/index.d.ts +29 -22
  45. package/components/Disclaimer/index.js +29 -24
  46. package/components/Drawer/index.d.ts +45 -25
  47. package/components/Drawer/index.js +61 -52
  48. package/components/EventListener/index.d.ts +4 -5
  49. package/components/Gallery/index.d.ts +14 -16
  50. package/components/Gallery/index.js +25 -30
  51. package/components/Iframe/index.js +2 -2
  52. package/components/Image/index.d.ts +5 -12
  53. package/components/Image/index.js +11 -32
  54. package/components/Input/index.d.ts +23 -19
  55. package/components/Input/index.js +30 -20
  56. package/components/JsonEditor/index.d.ts +177 -9
  57. package/components/JsonEditor/index.js +133 -77
  58. package/components/JsonEditor/types.d.ts +11 -0
  59. package/components/JsonEditor/types.js +1 -0
  60. package/components/JsonEditor/utils.d.ts +8 -0
  61. package/components/JsonEditor/utils.js +23 -0
  62. package/components/ListLoader/index.controlled.d.ts +5 -5
  63. package/components/ListLoader/index.controlled.js +4 -4
  64. package/components/ListLoader/index.d.ts +11 -11
  65. package/components/ListLoader/index.js +12 -12
  66. package/components/Overlayer/index.js +4 -4
  67. package/components/Paginator/index.d.ts +7 -12
  68. package/components/Paginator/index.js +7 -11
  69. package/components/ResizeObserver/index.d.ts +14 -3
  70. package/components/ResizeObserver/index.js +49 -24
  71. package/components/Scrllgngn/index.d.ts +17 -13
  72. package/components/Scrllgngn/index.js +25 -84
  73. package/components/Scrllgngn/utils.d.ts +52 -0
  74. package/components/Scrllgngn/utils.js +102 -0
  75. package/components/ScrollListener/index.d.ts +43 -28
  76. package/components/ScrollListener/index.js +59 -79
  77. package/components/ScrollListener/utils.d.ts +37 -16
  78. package/components/ScrollListener/utils.js +141 -28
  79. package/components/Select/index.d.ts +24 -20
  80. package/components/Select/index.js +30 -20
  81. package/components/Sequencer/index.controlled.d.ts +16 -26
  82. package/components/Sequencer/index.controlled.js +15 -12
  83. package/components/Sequencer/index.d.ts +25 -30
  84. package/components/Sequencer/index.js +20 -34
  85. package/components/Subtitles/index.d.ts +29 -5
  86. package/components/Subtitles/index.js +90 -12
  87. package/components/Textarea/index.d.ts +26 -20
  88. package/components/Textarea/index.js +40 -21
  89. package/components/Theatre/index.d.ts +35 -39
  90. package/components/Theatre/index.js +46 -58
  91. package/components/UIModule/index.d.ts +25 -29
  92. package/components/UIModule/index.js +81 -110
  93. package/components/Video/index.controlled.d.ts +51 -51
  94. package/components/Video/index.controlled.js +75 -72
  95. package/components/Video/index.d.ts +12 -14
  96. package/components/Video/index.js +41 -86
  97. package/components/Video/utils.d.ts +35 -3
  98. package/components/Video/utils.js +37 -14
  99. package/components/index.d.ts +1 -1
  100. package/components/index.js +1 -1
  101. package/components/utils/index.d.ts +22 -0
  102. package/components/utils/index.js +31 -0
  103. package/index.d.ts +1 -1
  104. package/index.js +1 -1
  105. package/node/@aws-s3/storage/file/index.d.ts +1 -1
  106. package/node/@aws-s3/storage/file/index.js +1 -1
  107. package/node/@google-cloud/storage/index.d.ts +1 -1
  108. package/node/@google-cloud/storage/index.js +1 -1
  109. package/node/images/index.d.ts +1 -1
  110. package/node/images/index.js +1 -1
  111. package/node/images/transform/operations/index.d.ts +1 -1
  112. package/node/images/transform/operations/index.js +1 -1
  113. package/node/index.d.ts +1 -1
  114. package/node/index.js +1 -1
  115. package/package.json +20 -5
  116. package/TODO.md +0 -269
  117. package/components/BeforeAfter/utils.d.ts +0 -4
  118. package/components/BeforeAfter/utils.js +0 -9
  119. package/components/Input/index.controlled.d.ts +0 -42
  120. package/components/Input/index.controlled.js +0 -54
  121. package/components/Select/index.controlled.d.ts +0 -43
  122. package/components/Select/index.controlled.js +0 -54
  123. package/components/Subtitles/types.d.ts +0 -24
  124. package/components/Subtitles/utils.d.ts +0 -32
  125. package/components/Subtitles/utils.js +0 -107
  126. package/components/Textarea/index.controlled.d.ts +0 -50
  127. package/components/Textarea/index.controlled.js +0 -75
  128. /package/{components/Subtitles/types.js → agnostic/time/dates/format-date/index.test.d.ts} +0 -0
  129. /package/components/ResizeObserver/{style.module.css → styles.module.css} +0 -0
@@ -1,54 +1,67 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useRef, useEffect } from 'react';
2
+ import { useState } from 'react';
3
3
  import { clss } from '../../agnostic/css/clss/index.js';
4
- import { mergeClassNames } from '../utils/index.js';
4
+ import { ResizeObserverComponent } from '../ResizeObserver/index.js';
5
+ import { mergeClassNames, useChangeDispatch } from '../utils/index.js';
5
6
  import { drawer as publicClassName } from '../public-classnames.js';
6
7
  import cssModule from './styles.module.css';
7
- import { ResizeObserverComponent } from '../ResizeObserver/index.js';
8
8
  /**
9
- * Drawer component with optional controlled and uncontrolled behavior.
9
+ * Drawer component supporting controlled and uncontrolled usage.
10
10
  *
11
- * @remarks
12
- * - In controlled mode (`isOpened` defined), visibility is fully driven by the prop.
13
- * - In uncontrolled mode, internal state is initialized from `initialIsOpened`.
14
- * - The component measures its content using `ResizeObserverComponent`
15
- * and exposes the dimensions:
16
- * - As CSS custom properties:
17
- * --{prefix}-content-height
18
- * --{prefix}-content-height-px
19
- * --{prefix}-content-width
20
- * --{prefix}-content-width-px
21
- * - As `data-content-width` and `data-content-height` attributes.
11
+ * The content is measured through a {@link ResizeObserverComponent} so its
12
+ * dimensions can drive the open/close transition from CSS alone.
13
+ *
14
+ * ### CSS modifiers
15
+ * - `opened` — the drawer is open.
16
+ * - `closed` the drawer is closed.
17
+ *
18
+ * ### CSS elements
19
+ * - `opener`
20
+ * - `closer`
21
+ * - `content`
22
+ *
23
+ * ### CSS custom properties on the root element
24
+ * - `--lm-drawer-content-width` / `--lm-drawer-content-width-raw`
25
+ * - `--lm-drawer-content-height` / `--lm-drawer-content-height-raw`
26
+ * Absent until the first measurement lands.
22
27
  *
23
- * CSS modifier classes:
24
- * - `opened` when open
25
- * - `closed` when closed
28
+ * ### Data attributes on the root element
29
+ * - `data-content-width`, `data-content-height` the measured content size.
30
+ * Absent until the first measurement lands.
31
+ *
32
+ * @param props - Component properties.
33
+ * @see {@link Props}
34
+ * @returns A root `<div>` holding the opener, the closer and the measured content.
35
+ *
36
+ * @remarks
37
+ * - In controlled mode (`isOpened` defined), the open state is fully driven by
38
+ * the parent and internal state is never updated.
39
+ * - `onOpenerClicked` and `onCloserClicked` fire in both modes — a controlled
40
+ * parent needs them to know a click happened at all.
41
+ * - `onIsOpenedChanged` fires in both modes too, and never on mount.
26
42
  */
27
- export const Drawer = ({ openerContent, closerContent, initialIsOpened = false, isOpened: isOpenedProp, stateHandlers, className, children }) => {
28
- // State & handlers
29
- const [internalIsOpened, setInternalIsOpened] = useState(isOpenedProp ?? initialIsOpened);
43
+ export const Drawer = ({ openerContent, closerContent, defaultIsOpened = false, isOpened: isOpenedProp, onOpenerClicked, onCloserClicked, onIsOpenedChanged, className, children }) => {
44
+ // State
45
+ const [internalIsOpened, setInternalIsOpened] = useState(defaultIsOpened);
46
+ const [contentDimensions, setContentDimensions] = useState();
47
+ const isControlled = isOpenedProp !== undefined;
30
48
  const isOpened = isOpenedProp ?? internalIsOpened;
31
- const pIsOpened = useRef(isOpened);
32
- const [{ width, height }, setContentDimensions] = useState({});
33
- // State change handlers
34
- useEffect(() => {
35
- if (pIsOpened.current === isOpened)
36
- return;
37
- pIsOpened.current = isOpened;
38
- stateHandlers?.toggled?.(isOpened);
39
- }, [isOpened]);
49
+ // State dispatch
50
+ useChangeDispatch(isOpened, onIsOpenedChanged);
40
51
  // User action handlers
41
52
  const handleOpenerClick = () => {
42
- if (isOpenedProp !== undefined)
53
+ onOpenerClicked?.(isOpened);
54
+ if (isControlled)
43
55
  return;
44
56
  setInternalIsOpened(true);
45
57
  };
46
58
  const handleCloserClick = () => {
47
- if (isOpenedProp !== undefined)
59
+ onCloserClicked?.(isOpened);
60
+ if (isControlled)
48
61
  return;
49
62
  setInternalIsOpened(false);
50
63
  };
51
- const handleROCompResize = ({ entry }) => {
64
+ const handleContentResized = ({ entry }) => {
52
65
  const { width, height } = entry.contentRect;
53
66
  setContentDimensions({ width, height });
54
67
  };
@@ -61,24 +74,20 @@ export const Drawer = ({ openerContent, closerContent, initialIsOpened = false,
61
74
  const openerClss = c('opener');
62
75
  const closerClss = c('closer');
63
76
  const contentClss = c('content');
64
- const dimensions = { width, height };
65
- const customCssProps = Object
66
- .entries(dimensions)
67
- .reduce((acc, [key, val]) => {
68
- if (val === undefined)
69
- return acc;
70
- return {
71
- ...acc,
72
- [`--${publicClassName}-content-${key}`]: `${val}`,
73
- [`--${publicClassName}-content-${key}-px`]: `${val}px`
77
+ let dataAttributes = {};
78
+ let customCssProps = {};
79
+ if (contentDimensions !== undefined) {
80
+ const { width, height } = contentDimensions;
81
+ dataAttributes = {
82
+ 'data-content-width': `${width}`,
83
+ 'data-content-height': `${height}`
84
+ };
85
+ customCssProps = {
86
+ '--lm-drawer-content-width': `${width}px`,
87
+ '--lm-drawer-content-width-raw': `${width}`,
88
+ '--lm-drawer-content-height': `${height}px`,
89
+ '--lm-drawer-content-height-raw': `${height}`
74
90
  };
75
- }, {});
76
- const dataAttributes = Object
77
- .entries(dimensions)
78
- .reduce((acc, [key, val]) => {
79
- if (val === undefined)
80
- return acc;
81
- return { ...acc, [`data-content-${key}`]: `${val}` };
82
- }, {});
83
- 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: handleROCompResize, children: children }) })] });
91
+ }
92
+ 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 }) })] });
84
93
  };
@@ -1,4 +1,5 @@
1
- import { type ReactNode, type FunctionComponent } from 'react';
1
+ import { type PropsWithChildren, type FunctionComponent } from 'react';
2
+ import type { WithClassName } from '../utils/types.js';
2
3
  /**
3
4
  * Props for the EventListenerComponent.
4
5
  *
@@ -10,13 +11,11 @@ import { type ReactNode, type FunctionComponent } from 'react';
10
11
  * Receives the native DOM Event object.
11
12
  * @property children - React children rendered inside the root element.
12
13
  */
13
- export type Props = {
14
- className?: string;
14
+ export type Props = PropsWithChildren<WithClassName<{
15
15
  type?: string | string[];
16
16
  targetSelector?: string;
17
17
  onEvent?: (e: Event) => void;
18
- children?: ReactNode;
19
- };
18
+ }>>;
20
19
  /**
21
20
  * Component that attaches one or multiple DOM event listeners to its root element
22
21
  * or to matching descendants.
@@ -18,17 +18,19 @@ import type { WithClassName } from '../utils/types.js';
18
18
  * - A ReactNode used for all pages,
19
19
  * - A function receiving the page index and returning a ReactNode,
20
20
  * - Undefined, in which case the page index is displayed.
21
- * @property initActive - Optional. When uncontrolled mode, sets the default active slot at mount
21
+ * @property defaultActive - Optional. When uncontrolled mode, sets the default active slot at mount
22
22
  * @property active - Optional controlled index. When provided, the active slot is driven by this
23
23
  * value instead of internal scroll-derived state. When omitted, the component manages its own
24
24
  * active index based on scroll position.
25
25
  * @property noSnap - Optional, defines if scroll is free in side the scroller or not (defaults to false)
26
- * @property stateHandlers - Callbacks called after the state changed
27
- * @property stateHandlers.slotChanged - Called when the active slot changes due to scrolling. Receives the new active index.
28
- * @property actionHandlers - Callbacks called after a user interaction
29
- * @property actionHandlers.prevClick - Called when the "previous" control is clicked. Receives the current active index before navigation occurs.
30
- * @property actionHandlers.nextClick - Called when the "next" control is clicked. Receives the current active index before navigation occurs.
31
- * @property actionHandlers.paginationClick - Called when a pagination item is clicked. Receives the current active index and the target index.
26
+ * @property onPrevClicked - Called when the "previous" control is clicked,
27
+ * before the gallery reacts, with the active index as it was.
28
+ * @property onNextClicked - Called when the "next" control is clicked, before
29
+ * the gallery reacts, with the active index as it was.
30
+ * @property onPaginationClicked - Called when a pagination item is clicked,
31
+ * before the gallery reacts, with the active index as it was and the target index.
32
+ * @property onActiveSlotChanged - Called after the active slot changed, with
33
+ * the new index.
32
34
  * @property className - Optional additional class name(s) applied to the root element.
33
35
  * @property children - Elements rendered as gallery slots. Each child is wrapped in a slot container.
34
36
  */
@@ -39,17 +41,13 @@ export type Props = PropsWithChildren<WithClassName<{
39
41
  prevButtonContent?: ReactNode;
40
42
  nextButtonContent?: ReactNode;
41
43
  paginationContent?: ReactNode | ((page: number) => ReactNode);
42
- initActive?: number;
44
+ defaultActive?: number;
43
45
  active?: number;
44
46
  noSnap?: boolean;
45
- stateHandlers?: {
46
- slotChanged?: (activePos: number) => void;
47
- };
48
- actionHandlers?: {
49
- prevClick?: (activePos: number) => void;
50
- nextClick?: (activePos: number) => void;
51
- paginationClick?: (activePos: number, targetPos: number) => void;
52
- };
47
+ onPrevClicked?: (activePos: number) => void;
48
+ onNextClicked?: (activePos: number) => void;
49
+ onPaginationClicked?: (activePos: number, targetPos: number) => void;
50
+ onActiveSlotChanged?: (activePos: number) => void;
53
51
  }>>;
54
52
  /**
55
53
  * Horizontally scrollable gallery component with navigation controls and pagination.
@@ -1,10 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Children, useEffect, useState, useRef } from 'react';
3
3
  import { clss } from '../../agnostic/css/clss/index.js';
4
- import { mergeClassNames } from '../utils/index.js';
4
+ import { mergeClassNames, useChangeDispatch } from '../utils/index.js';
5
5
  import { gallery as publicClassName } from '../public-classnames.js';
6
6
  import { forceActivateSlot } from './utils.js';
7
7
  import cssModule from './styles.module.css';
8
+ /** Resolves one side's padding to a CSS length, falling back to the shorthand then to `0px`. */
9
+ function resolvePadding(side, shorthand) {
10
+ const value = side ?? shorthand ?? 0;
11
+ return typeof value === 'number' ? `${value}px` : value;
12
+ }
8
13
  /**
9
14
  * Horizontally scrollable gallery component with navigation controls and pagination.
10
15
  *
@@ -18,32 +23,34 @@ import cssModule from './styles.module.css';
18
23
  * - Previous/next navigation controls,
19
24
  * - Pagination controls allowing direct slot activation.
20
25
  */
21
- export const Gallery = ({ paddingLeft, paddingRight, padding, prevButtonContent, nextButtonContent, paginationContent, initActive, active, noSnap, stateHandlers, actionHandlers, children, className }) => {
26
+ export const Gallery = ({ paddingLeft, paddingRight, padding, prevButtonContent, nextButtonContent, paginationContent, defaultActive, active, noSnap, onPrevClicked, onNextClicked, onPaginationClicked, onActiveSlotChanged, children, className }) => {
22
27
  // State & refs
23
28
  const scrollerRef = useRef(null);
24
29
  const [activeIndex, setActiveIndex] = useState(0);
25
30
  const [canGoLeft, setCanGoLeft] = useState(false);
26
31
  const [canGoRight, setCanGoRight] = useState(false);
27
32
  const childrenCount = Children.count(children);
28
- // State change handlers
29
- useEffect(() => {
30
- stateHandlers?.slotChanged?.(activeIndex);
31
- }, [activeIndex]);
33
+ const isControlled = active !== undefined;
34
+ // State dispatch
35
+ useChangeDispatch(activeIndex, onActiveSlotChanged);
32
36
  // User actions handlers
33
37
  const handlePrevClick = () => {
34
- actionHandlers?.prevClick?.(activeIndex);
35
- if (active === undefined)
36
- forceActivateSlot(scrollerRef.current, activeIndex - 1);
38
+ onPrevClicked?.(activeIndex);
39
+ if (isControlled)
40
+ return;
41
+ forceActivateSlot(scrollerRef.current, activeIndex - 1);
37
42
  };
38
43
  const handleNextClick = () => {
39
- actionHandlers?.nextClick?.(activeIndex);
40
- if (active === undefined)
41
- forceActivateSlot(scrollerRef.current, activeIndex + 1);
44
+ onNextClicked?.(activeIndex);
45
+ if (isControlled)
46
+ return;
47
+ forceActivateSlot(scrollerRef.current, activeIndex + 1);
42
48
  };
43
49
  const handlePaginationClick = (pos) => {
44
- actionHandlers?.paginationClick?.(activeIndex, pos);
45
- if (active === undefined)
46
- forceActivateSlot(scrollerRef.current, pos);
50
+ onPaginationClicked?.(activeIndex, pos);
51
+ if (isControlled)
52
+ return;
53
+ forceActivateSlot(scrollerRef.current, pos);
47
54
  };
48
55
  // Scroll position calculation
49
56
  useEffect(() => {
@@ -87,7 +94,7 @@ export const Gallery = ({ paddingLeft, paddingRight, padding, prevButtonContent,
87
94
  }, []);
88
95
  // Sync scroll position to 'active' prop at mount time
89
96
  useEffect(() => {
90
- const toActivate = active ?? initActive;
97
+ const toActivate = active ?? defaultActive;
91
98
  if (toActivate === undefined)
92
99
  return;
93
100
  const id = setTimeout(() => forceActivateSlot(scrollerRef.current, toActivate, false), 50);
@@ -115,20 +122,8 @@ export const Gallery = ({ paddingLeft, paddingRight, padding, prevButtonContent,
115
122
  const nextBtnClss = c('next');
116
123
  const paginationClss = c('pagination');
117
124
  const dataAttributes = { 'data-active': `${activeIndex}` };
118
- const actualPaddingLeft = typeof paddingLeft === 'number'
119
- ? `${paddingLeft}px`
120
- : typeof paddingLeft === 'string'
121
- ? paddingLeft
122
- : typeof padding === 'number'
123
- ? `${padding}px`
124
- : padding ?? '0px';
125
- const actualPaddingRight = typeof paddingRight === 'number'
126
- ? `${paddingRight}px`
127
- : typeof paddingRight === 'string'
128
- ? paddingRight
129
- : typeof padding === 'number'
130
- ? `${padding}px`
131
- : padding ?? '0px';
125
+ const actualPaddingLeft = resolvePadding(paddingLeft, padding);
126
+ const actualPaddingRight = resolvePadding(paddingRight, padding);
132
127
  return _jsxs("div", { className: rootClss, ...dataAttributes, children: [_jsx("div", { className: scrollerClss, ref: scrollerRef, children: Children.map(children, (child, pos) => {
133
128
  const slotClss = c('slot', { active: pos === activeIndex });
134
129
  const style = {
@@ -5,7 +5,7 @@ import { randomHash } from '../../agnostic/random/uuid/index.js';
5
5
  import { mergeClassNames } from '../utils/index.js';
6
6
  import { iframe as publicClassName } from '../public-classnames.js';
7
7
  import cssModule from './styles.module.css';
8
- const innerAutoHeightNitifier = (messageType) => `<script>
8
+ const innerAutoHeightNotifier = (messageType) => `<script>
9
9
  (() => {
10
10
  const notify = () => {
11
11
  const height = Math.max(
@@ -71,7 +71,7 @@ export const Iframe = ({ autoHeight = false, className, srcDoc, style, ...iframe
71
71
  const rootClss = mergeClassNames(c(), className);
72
72
  const html = useMemo(() => {
73
73
  const autoHeightScript = autoHeight
74
- ? innerAutoHeightNitifier(innerMessageType)
74
+ ? innerAutoHeightNotifier(innerMessageType)
75
75
  : '';
76
76
  return `<!doctype html>
77
77
  <html>
@@ -1,5 +1,4 @@
1
1
  import { type FunctionComponent, type ImgHTMLAttributes } from 'react';
2
- import { type Props as DisclaimerProps } from '../Disclaimer/index.js';
3
2
  import { type Props as TheatreProps } from '../Theatre/index.js';
4
3
  import type { WithClassName } from '../utils/types.js';
5
4
  /**
@@ -28,31 +27,25 @@ type SourceData = {
28
27
  * - a single srcSet string,
29
28
  * - an array of srcSet strings,
30
29
  * - an array of {@link SourceData} objects for full `<source>` control.
31
- * @property disclaimer - Props forwarded to the internal {@link Disclaimer} component.
32
- * While the disclaimer is active the `<img>` is hidden.
33
30
  * @property theatre - Props forwarded to the internal {@link Theatre} component.
34
31
  * @property className - Optional additional class name(s) applied to the root element.
35
32
  */
36
33
  export type Props = WithClassName<{
37
34
  sources?: string | string[] | SourceData[];
38
- disclaimer?: DisclaimerProps;
39
35
  theatre?: TheatreProps;
40
36
  }> & ImgHTMLAttributes<HTMLImageElement>;
41
37
  /**
42
38
  * Image component. Wraps a native `<img>` (or `<picture>`) element with
43
- * optional responsive sources, an optional disclaimer gate, and
44
- * viewport-driven visibility tracking.
39
+ * optional responsive sources and an optional theatre mode.
45
40
  *
46
- *
47
- * ### Child elements
48
- * - `__picture` — wrapping `<picture>` element, always rendered. Contains the
41
+ * ### CSS elements
42
+ * - `picture` — wrapping `<picture>` element, always rendered. Contains the
49
43
  * `<source>` elements (if any) and the `<img>`.
50
- * - `__img` — the native `<img>` element.
44
+ * - `image` — the native `<img>` element.
51
45
  *
52
46
  * @param props - Component properties.
53
47
  * @see {@link Props}
54
- * @returns A `<figure>` element containing a `<picture>` with the image,
55
- * and an optional disclaimer overlay.
48
+ * @returns A `<figure>` element containing a `<picture>` with the image.
56
49
  */
57
50
  export declare const Image: FunctionComponent<Props>;
58
51
  export {};
@@ -1,37 +1,25 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useMemo, useCallback } from 'react';
2
+ import { useMemo } from 'react';
3
3
  import { clss } from '../../agnostic/css/clss/index.js';
4
- import { Disclaimer } from '../Disclaimer/index.js';
5
4
  import { Theatre } from '../Theatre/index.js';
6
5
  import { mergeClassNames } from '../utils/index.js';
7
6
  import { image as publicClassName } from '../public-classnames.js';
8
7
  import cssModule from './styles.module.css';
9
8
  /**
10
9
  * Image component. Wraps a native `<img>` (or `<picture>`) element with
11
- * optional responsive sources, an optional disclaimer gate, and
12
- * viewport-driven visibility tracking.
10
+ * optional responsive sources and an optional theatre mode.
13
11
  *
14
- *
15
- * ### Child elements
16
- * - `__picture` — wrapping `<picture>` element, always rendered. Contains the
12
+ * ### CSS elements
13
+ * - `picture` — wrapping `<picture>` element, always rendered. Contains the
17
14
  * `<source>` elements (if any) and the `<img>`.
18
- * - `__img` — the native `<img>` element.
15
+ * - `image` — the native `<img>` element.
19
16
  *
20
17
  * @param props - Component properties.
21
18
  * @see {@link Props}
22
- * @returns A `<figure>` element containing a `<picture>` with the image,
23
- * and an optional disclaimer overlay.
19
+ * @returns A `<figure>` element containing a `<picture>` with the image.
24
20
  */
25
- export const Image = ({ sources, disclaimer, theatre, className, ...intrinsicImgAttributes }) => {
21
+ export const Image = ({ sources, theatre, className, ...intrinsicImgAttributes }) => {
26
22
  // State
27
- const [isDisclaimerOn, setIsDisclaimerOn] = useState(disclaimer?.isOn === true
28
- || disclaimer?.defaultIsOn === true
29
- || (disclaimer !== undefined && disclaimer.defaultIsOn === undefined));
30
- let shouldDisclaimerBeOn = isDisclaimerOn;
31
- if (disclaimer?.isOn === true)
32
- shouldDisclaimerBeOn = true;
33
- if (disclaimer?.isOn === false)
34
- shouldDisclaimerBeOn = false;
35
23
  const parsedSources = useMemo(() => {
36
24
  if (sources === undefined)
37
25
  return [];
@@ -48,23 +36,14 @@ export const Image = ({ sources, disclaimer, theatre, className, ...intrinsicImg
48
36
  }
49
37
  return [];
50
38
  }, [sources]);
51
- // User actions handlers
52
- const handleDisclaimerDismissClick = useCallback(() => {
53
- disclaimer?.actionHandlers?.dismissClick?.(isDisclaimerOn);
54
- setIsDisclaimerOn(false);
55
- }, []);
56
39
  // Rendering
57
40
  const c = clss(publicClassName, { cssModule });
58
41
  const rootClss = mergeClassNames(c(), className);
59
- const rootAttributes = {};
60
42
  const pictureClss = c('picture');
61
43
  const imgClss = c('image');
62
- const sensitiveContent = _jsxs("picture", { className: pictureClss, children: [parsedSources.map((source, index) => _jsx("source", { srcSet: typeof source === 'string' ? source : source.srcSet, type: typeof source === 'string' ? undefined : source.type, media: typeof source === 'string' ? undefined : source.media, sizes: typeof source === 'string' ? undefined : source.sizes }, index)), _jsx("img", { className: imgClss, ...intrinsicImgAttributes })] });
44
+ const pictureContent = _jsxs("picture", { className: pictureClss, children: [parsedSources.map((source, index) => _jsx("source", { srcSet: typeof source === 'string' ? source : source.srcSet, type: typeof source === 'string' ? undefined : source.type, media: typeof source === 'string' ? undefined : source.media, sizes: typeof source === 'string' ? undefined : source.sizes }, index)), _jsx("img", { className: imgClss, ...intrinsicImgAttributes })] });
63
45
  const theatricalContent = theatre !== undefined
64
- ? _jsx(Theatre, { defaultIsOn: false, ...theatre, children: sensitiveContent })
65
- : sensitiveContent;
66
- const disclaimedContent = disclaimer !== undefined
67
- ? _jsx(Disclaimer, { ...disclaimer, isOn: shouldDisclaimerBeOn, actionHandlers: { dismissClick: handleDisclaimerDismissClick }, children: theatricalContent })
68
- : theatricalContent;
69
- return _jsx("figure", { className: rootClss, ...rootAttributes, children: disclaimedContent });
46
+ ? _jsx(Theatre, { defaultIsOn: false, ...theatre, children: pictureContent })
47
+ : pictureContent;
48
+ return _jsx("figure", { className: rootClss, children: theatricalContent });
70
49
  };
@@ -1,20 +1,27 @@
1
- import { type FunctionComponent } from 'react';
2
- import { type Props as ControlledProps } from './index.controlled.js';
1
+ import { type FunctionComponent, type InputHTMLAttributes, type ReactNode } from 'react';
2
+ import type { WithClassName } from '../utils/types.js';
3
3
  /**
4
4
  * Props for the {@link Input} component.
5
5
  *
6
- * Alias of {@link ControlledProps}.
6
+ * Extends all native {@link InputHTMLAttributes} and {@link WithClassName}
7
+ * with optional label and error content.
7
8
  *
8
- * All native input attributes remain available, including `value`
9
- * and `onChange`, allowing the component to operate in either
10
- * controlled or hybrid mode.
9
+ * @property label - Content rendered as an associated `<label>`. When omitted, no label is rendered.
10
+ * @property error - Content rendered as an error message below the input. When omitted, no error is rendered.
11
+ * @property className - Additional class name(s) applied to the input element.
11
12
  */
12
- export type Props = ControlledProps;
13
+ export type Props = InputHTMLAttributes<HTMLInputElement> & WithClassName<{
14
+ label?: ReactNode;
15
+ error?: ReactNode;
16
+ }>;
13
17
  /**
14
- * Input field component supporting controlled and hybrid usage.
18
+ * Input field supporting controlled and uncontrolled usage.
15
19
  *
16
- * Wraps {@link ControlledInput} and automatically manages the input value
17
- * when no `value` prop is provided.
20
+ * Renders a native `<input>` with optional label and error feedback. All
21
+ * standard input attributes are forwarded to the underlying element.
22
+ *
23
+ * A stable auto-generated `id` is created on mount and used to associate the
24
+ * rendered label through the `htmlFor` attribute.
18
25
  *
19
26
  * ### CSS elements
20
27
  * - `label`
@@ -22,16 +29,13 @@ export type Props = ControlledProps;
22
29
  *
23
30
  * @param props - Component properties.
24
31
  * @see {@link Props}
25
- *
26
- * @returns A labelled input with optional internal value management.
32
+ * @returns A labelled input with optional error feedback.
27
33
  *
28
34
  * @remarks
29
- * - When `value` is defined, the component behaves as a controlled component:
30
- * displayed value updates are entirely driven by the parent component.
31
- * - When `value` is omitted, the component behaves in hybrid mode:
32
- * it initializes an internal state from the initial `value` prop and
33
- * subsequently manages value updates itself.
34
- * - In hybrid mode, the internal value is updated before forwarding
35
- * the `onChange` callback.
35
+ * - In controlled mode (`value` defined), the displayed value is fully driven
36
+ * by the parent and internal state is never updated.
37
+ * - In uncontrolled mode, internal state is initialized from `defaultValue` and
38
+ * updated before `onChange` is forwarded.
39
+ * - `onChange` fires in both modes.
36
40
  */
37
41
  export declare const Input: FunctionComponent<Props>;
@@ -1,11 +1,19 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import { ControlledInput } from './index.controlled.js';
3
+ import { clss } from '../../agnostic/css/clss/index.js';
4
+ import { isNotFalsy } from '../../agnostic/booleans/is-falsy/index.js';
5
+ import { randomHash } from '../../agnostic/random/uuid/index.js';
6
+ import { mergeClassNames } from '../utils/index.js';
7
+ import { input as publicClassName } from '../public-classnames.js';
8
+ import cssModule from './styles.module.css';
4
9
  /**
5
- * Input field component supporting controlled and hybrid usage.
10
+ * Input field supporting controlled and uncontrolled usage.
6
11
  *
7
- * Wraps {@link ControlledInput} and automatically manages the input value
8
- * when no `value` prop is provided.
12
+ * Renders a native `<input>` with optional label and error feedback. All
13
+ * standard input attributes are forwarded to the underlying element.
14
+ *
15
+ * A stable auto-generated `id` is created on mount and used to associate the
16
+ * rendered label through the `htmlFor` attribute.
9
17
  *
10
18
  * ### CSS elements
11
19
  * - `label`
@@ -13,27 +21,29 @@ import { ControlledInput } from './index.controlled.js';
13
21
  *
14
22
  * @param props - Component properties.
15
23
  * @see {@link Props}
16
- *
17
- * @returns A labelled input with optional internal value management.
24
+ * @returns A labelled input with optional error feedback.
18
25
  *
19
26
  * @remarks
20
- * - When `value` is defined, the component behaves as a controlled component:
21
- * displayed value updates are entirely driven by the parent component.
22
- * - When `value` is omitted, the component behaves in hybrid mode:
23
- * it initializes an internal state from the initial `value` prop and
24
- * subsequently manages value updates itself.
25
- * - In hybrid mode, the internal value is updated before forwarding
26
- * the `onChange` callback.
27
+ * - In controlled mode (`value` defined), the displayed value is fully driven
28
+ * by the parent and internal state is never updated.
29
+ * - In uncontrolled mode, internal state is initialized from `defaultValue` and
30
+ * updated before `onChange` is forwarded.
31
+ * - `onChange` fires in both modes.
27
32
  */
28
- export const Input = (props) => {
29
- const { value, defaultValue, onChange, ...rest } = props;
33
+ export const Input = ({ label, error, value, defaultValue, onChange, className, ...rest }) => {
34
+ // State
35
+ const [id] = useState(`_${randomHash(12)}`);
36
+ const [internalValue, setInternalValue] = useState(defaultValue ?? '');
30
37
  const isControlled = value !== undefined;
31
- const [internal, setInternal] = useState(defaultValue ?? '');
32
- const currentValue = isControlled ? value : internal;
38
+ const currentValue = isControlled ? value : internalValue;
39
+ // User action handlers
33
40
  const handleChange = (e) => {
34
41
  if (!isControlled)
35
- setInternal(e.target.value);
42
+ setInternalValue(e.target.value);
36
43
  onChange?.(e);
37
44
  };
38
- return _jsx(ControlledInput, { ...rest, value: currentValue, onChange: handleChange });
45
+ // Rendering
46
+ const c = clss(publicClassName, { cssModule });
47
+ const rootClss = mergeClassNames(c(), className);
48
+ return _jsxs(_Fragment, { children: [isNotFalsy(label) && _jsx("label", { className: c('label'), htmlFor: id, children: label }), _jsx("input", { ...rest, id: id, className: rootClss, value: currentValue, onChange: handleChange }), isNotFalsy(error) && _jsx("span", { className: c('error'), children: error })] });
39
49
  };