@tcn/ui 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/dist/card.css +1 -0
  2. package/dist/column.css +1 -1
  3. package/dist/containers.css +1 -1
  4. package/dist/containers.module-BmICKsOK.js +5 -0
  5. package/dist/containers.module-BmICKsOK.js.map +1 -0
  6. package/dist/form/field/field.js +11 -8
  7. package/dist/form/field/field.js.map +1 -1
  8. package/dist/inputs/color_input/color_picker.js +5 -2
  9. package/dist/inputs/color_input/color_picker.js.map +1 -1
  10. package/dist/inputs/combo_box/combo_box.js +18 -15
  11. package/dist/inputs/combo_box/combo_box.js.map +1 -1
  12. package/dist/inputs/date_picker/date_picker.js +13 -10
  13. package/dist/inputs/date_picker/date_picker.js.map +1 -1
  14. package/dist/inputs/date_picker/date_picker_input.js +20 -17
  15. package/dist/inputs/date_picker/date_picker_input.js.map +1 -1
  16. package/dist/inputs/date_picker/date_picker_year_selector.js +5 -2
  17. package/dist/inputs/date_picker/date_picker_year_selector.js.map +1 -1
  18. package/dist/inputs/mask_input/key_capture_input.js +26 -23
  19. package/dist/inputs/mask_input/key_capture_input.js.map +1 -1
  20. package/dist/inputs/mask_input/mask_input.js +5 -2
  21. package/dist/inputs/mask_input/mask_input.js.map +1 -1
  22. package/dist/inputs/multiselect/multiselect.js +22 -19
  23. package/dist/inputs/multiselect/multiselect.js.map +1 -1
  24. package/dist/inputs/phone_number_input/phone_number_context.js +7 -4
  25. package/dist/inputs/phone_number_input/phone_number_context.js.map +1 -1
  26. package/dist/inputs/select/select.js +5 -2
  27. package/dist/inputs/select/select.js.map +1 -1
  28. package/dist/inputs/slider/slider.js +19 -16
  29. package/dist/inputs/slider/slider.js.map +1 -1
  30. package/dist/inputs/suggestions/suggestion_list.js +5 -2
  31. package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
  32. package/dist/inputs/switch/switch.js +18 -15
  33. package/dist/inputs/switch/switch.js.map +1 -1
  34. package/dist/inputs/unit_input/unit_input.js +15 -12
  35. package/dist/inputs/unit_input/unit_input.js.map +1 -1
  36. package/dist/layouts/containers/columns/columns.d.ts +6 -1
  37. package/dist/layouts/containers/columns/columns.d.ts.map +1 -1
  38. package/dist/layouts/containers/columns/columns.js +30 -7
  39. package/dist/layouts/containers/columns/columns.js.map +1 -1
  40. package/dist/layouts/containers/rail.d.ts +2 -5
  41. package/dist/layouts/containers/rail.d.ts.map +1 -1
  42. package/dist/layouts/containers/rail.js +17 -55
  43. package/dist/layouts/containers/rail.js.map +1 -1
  44. package/dist/layouts/containers/rows/index.d.ts +3 -0
  45. package/dist/layouts/containers/rows/index.d.ts.map +1 -0
  46. package/dist/layouts/containers/rows/index.js +7 -0
  47. package/dist/layouts/containers/rows/index.js.map +1 -0
  48. package/dist/layouts/containers/rows/row.d.ts +6 -0
  49. package/dist/layouts/containers/rows/row.d.ts.map +1 -0
  50. package/dist/layouts/containers/rows/row.js +20 -0
  51. package/dist/layouts/containers/rows/row.js.map +1 -0
  52. package/dist/layouts/containers/rows/rows.d.ts +11 -0
  53. package/dist/layouts/containers/rows/rows.d.ts.map +1 -0
  54. package/dist/layouts/containers/rows/rows.js +34 -0
  55. package/dist/layouts/containers/rows/rows.js.map +1 -0
  56. package/dist/layouts/containers/scaffold.d.ts +2 -5
  57. package/dist/layouts/containers/scaffold.d.ts.map +1 -1
  58. package/dist/layouts/containers/scaffold.js +17 -55
  59. package/dist/layouts/containers/scaffold.js.map +1 -1
  60. package/dist/layouts/index.d.ts +2 -0
  61. package/dist/layouts/index.d.ts.map +1 -1
  62. package/dist/layouts/index.js +26 -22
  63. package/dist/layouts/index.js.map +1 -1
  64. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.js +5 -2
  65. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.js.map +1 -1
  66. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.js +5 -2
  67. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.js.map +1 -1
  68. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.js +8 -5
  69. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.js.map +1 -1
  70. package/dist/navigation/tabs/state/link/tab_link.js +9 -6
  71. package/dist/navigation/tabs/state/link/tab_link.js.map +1 -1
  72. package/dist/overlay/menu/menu.js +3 -0
  73. package/dist/overlay/menu/menu.js.map +1 -1
  74. package/dist/overlay/popper/context_popper.js +8 -5
  75. package/dist/overlay/popper/context_popper.js.map +1 -1
  76. package/dist/overlay/popper/element_popper.js +9 -6
  77. package/dist/overlay/popper/element_popper.js.map +1 -1
  78. package/dist/overlay/popper/legacy/popper.js +13 -10
  79. package/dist/overlay/popper/legacy/popper.js.map +1 -1
  80. package/dist/overlay/popper/preview_popper.js +10 -7
  81. package/dist/overlay/popper/preview_popper.js.map +1 -1
  82. package/dist/overlay/tethered/tethered.js +11 -8
  83. package/dist/overlay/tethered/tethered.js.map +1 -1
  84. package/dist/resizable.css +1 -0
  85. package/dist/resizable.module-I6iyBAvM.js +5 -0
  86. package/dist/resizable.module-I6iyBAvM.js.map +1 -0
  87. package/dist/resize_handle.css +1 -0
  88. package/dist/row.css +1 -0
  89. package/dist/stacks/box/box.js +12 -9
  90. package/dist/stacks/box/box.js.map +1 -1
  91. package/dist/stacks/box/detect_resize_bounds.d.ts +1 -0
  92. package/dist/stacks/box/detect_resize_bounds.d.ts.map +1 -1
  93. package/dist/stacks/box/detect_resize_bounds.js +22 -20
  94. package/dist/stacks/box/detect_resize_bounds.js.map +1 -1
  95. package/dist/stacks/h_collapsible_box.js +17 -14
  96. package/dist/stacks/h_collapsible_box.js.map +1 -1
  97. package/dist/stacks/v_collapsible_box.js +19 -16
  98. package/dist/stacks/v_collapsible_box.js.map +1 -1
  99. package/dist/surfaces/card/card.d.ts.map +1 -1
  100. package/dist/surfaces/card/card.js +14 -6
  101. package/dist/surfaces/card/card.js.map +1 -1
  102. package/dist/surfaces/pop_confirm/pop_confirm.js +4 -2
  103. package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
  104. package/dist/test-setup.d.ts +2 -0
  105. package/dist/test-setup.d.ts.map +1 -0
  106. package/dist/test-setup.js +10 -0
  107. package/dist/test-setup.js.map +1 -0
  108. package/dist/themes/theme.d.ts.map +1 -1
  109. package/dist/themes/theme.js +17 -22
  110. package/dist/themes/theme.js.map +1 -1
  111. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  112. package/dist/themes/themes/ergo/ergo_theme.js +201 -21
  113. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  114. package/dist/utils/index.d.ts +1 -0
  115. package/dist/utils/index.d.ts.map +1 -1
  116. package/dist/utils/index.js +39 -26
  117. package/dist/utils/index.js.map +1 -1
  118. package/dist/utils/resize/context.d.ts +4 -0
  119. package/dist/utils/resize/context.d.ts.map +1 -0
  120. package/dist/utils/resize/context.js +10 -0
  121. package/dist/utils/resize/context.js.map +1 -0
  122. package/dist/utils/resize/handle_config.d.ts +32 -0
  123. package/dist/utils/resize/handle_config.d.ts.map +1 -0
  124. package/dist/utils/resize/handle_config.js +85 -0
  125. package/dist/utils/resize/handle_config.js.map +1 -0
  126. package/dist/utils/resize/index.d.ts +10 -0
  127. package/dist/utils/resize/index.d.ts.map +1 -0
  128. package/dist/utils/resize/index.js +16 -0
  129. package/dist/utils/resize/index.js.map +1 -0
  130. package/dist/utils/resize/resizable.d.ts +11 -0
  131. package/dist/utils/resize/resizable.d.ts.map +1 -0
  132. package/dist/utils/resize/resizable.js +52 -0
  133. package/dist/utils/resize/resizable.js.map +1 -0
  134. package/dist/utils/resize/resize_handle.d.ts +7 -0
  135. package/dist/utils/resize/resize_handle.d.ts.map +1 -0
  136. package/dist/utils/resize/resize_handle.js +100 -0
  137. package/dist/utils/resize/resize_handle.js.map +1 -0
  138. package/dist/utils/resize/resize_strategy.d.ts +47 -0
  139. package/dist/utils/resize/resize_strategy.d.ts.map +1 -0
  140. package/dist/utils/resize/resize_strategy.js +108 -0
  141. package/dist/utils/resize/resize_strategy.js.map +1 -0
  142. package/dist/utils/resize/types.d.ts +28 -0
  143. package/dist/utils/resize/types.d.ts.map +1 -0
  144. package/dist/utils/resize/types.js +2 -0
  145. package/dist/utils/resize/types.js.map +1 -0
  146. package/package.json +3 -3
  147. package/src/layouts/__stories__/columns.stories.tsx +31 -0
  148. package/src/layouts/__stories__/composed.stories.tsx +77 -8
  149. package/src/layouts/__stories__/rows.stories.tsx +77 -0
  150. package/src/layouts/__stories__/utils.tsx +2 -84
  151. package/src/layouts/containers/columns/column.module.css +3 -2
  152. package/src/layouts/containers/columns/columns.tsx +29 -3
  153. package/src/layouts/containers/containers.module.css +27 -29
  154. package/src/layouts/containers/rail.tsx +9 -51
  155. package/src/layouts/containers/rows/index.ts +2 -0
  156. package/src/layouts/containers/rows/row.module.css +15 -0
  157. package/src/layouts/containers/rows/row.tsx +22 -0
  158. package/src/layouts/containers/rows/rows.tsx +42 -0
  159. package/src/layouts/containers/scaffold.tsx +9 -49
  160. package/src/layouts/index.ts +2 -0
  161. package/src/stacks/box/detect_resize_bounds.ts +5 -1
  162. package/src/surfaces/card/card.module.css +5 -0
  163. package/src/surfaces/card/card.stories.tsx +66 -8
  164. package/src/surfaces/card/card.tsx +6 -2
  165. package/src/surfaces/page/page.stories.tsx +84 -4
  166. package/src/surfaces/panel/__stories__/panel.stories.tsx +84 -9
  167. package/src/test-setup.ts +11 -0
  168. package/src/themes/theme.tsx +6 -16
  169. package/src/themes/themes/ergo/ergo_theme.css +199 -19
  170. package/src/utils/index.ts +2 -0
  171. package/src/utils/resize/__stories__/resizable.stories.tsx +214 -0
  172. package/src/utils/resize/__stories__/resizable_stories.module.css +47 -0
  173. package/src/utils/resize/__tests__/handle_config.test.ts +269 -0
  174. package/src/utils/resize/__tests__/resize_strategy.test.ts +163 -0
  175. package/src/utils/resize/context.ts +9 -0
  176. package/src/utils/resize/handle_config.ts +142 -0
  177. package/src/utils/resize/index.ts +37 -0
  178. package/src/utils/resize/resizable.module.css +5 -0
  179. package/src/utils/resize/resizable.tsx +97 -0
  180. package/src/utils/resize/resize_handle.module.css +146 -0
  181. package/src/utils/resize/resize_handle.tsx +165 -0
  182. package/src/utils/resize/resize_strategy.ts +190 -0
  183. package/src/utils/resize/types.ts +64 -0
  184. package/dist/containers.module-DlGySre0.js +0 -5
  185. package/dist/containers.module-DlGySre0.js.map +0 -1
@@ -0,0 +1,97 @@
1
+ import React, { useMemo, useRef } from 'react';
2
+ import { clsx } from 'clsx';
3
+ import { useForkRef } from '../hooks/use_fork_ref.js';
4
+ import { ResizableContext } from './context.js';
5
+ import type {
6
+ OnWidthResize,
7
+ OnWidthResizeEnd,
8
+ OnHeightResize,
9
+ OnHeightResizeEnd,
10
+ ResizableContextValue,
11
+ } from './types.js';
12
+ import styles from './resizable.module.css';
13
+
14
+ export interface ResizableProps {
15
+ children: React.ReactNode;
16
+ onWidthResize?: OnWidthResize;
17
+ onWidthResizeEnd?: OnWidthResizeEnd;
18
+ onHeightResize?: OnHeightResize;
19
+ onHeightResizeEnd?: OnHeightResizeEnd;
20
+ }
21
+
22
+ interface ResizableTargetProps {
23
+ className?: string;
24
+ children?: React.ReactNode;
25
+ ref?: React.Ref<HTMLElement>;
26
+ }
27
+
28
+ type ResizableTarget = React.ReactElement<ResizableTargetProps>;
29
+
30
+ function isResizableTarget(child: React.ReactNode): child is ResizableTarget {
31
+ if (!React.isValidElement(child)) return false;
32
+ const type = child.type;
33
+ if (typeof type === 'string') return true;
34
+ if (typeof type === 'function' || typeof type === 'object') {
35
+ return (type as { displayName?: string }).displayName !== 'ResizeHandle';
36
+ }
37
+ return false;
38
+ }
39
+
40
+ function isResizeHandle(child: React.ReactNode): boolean {
41
+ return React.isValidElement(child) && !isResizableTarget(child);
42
+ }
43
+
44
+ export function Resizable({
45
+ children,
46
+ onWidthResize,
47
+ onWidthResizeEnd,
48
+ onHeightResize,
49
+ onHeightResizeEnd,
50
+ }: ResizableProps) {
51
+ const targetRef = useRef<HTMLElement | null>(null);
52
+
53
+ const childArray = React.Children.toArray(children);
54
+ const targetChild = childArray.find(isResizableTarget);
55
+ const handleChildren = childArray.filter(isResizeHandle);
56
+
57
+ const contextValue = useMemo<ResizableContextValue>(
58
+ () => ({
59
+ targetRef,
60
+ onWidthResize,
61
+ onWidthResizeEnd,
62
+ onHeightResize,
63
+ onHeightResizeEnd,
64
+ }),
65
+ [onWidthResize, onWidthResizeEnd, onHeightResize, onHeightResizeEnd]
66
+ );
67
+
68
+ const forkedRef = useForkRef(targetRef, targetChild?.props.ref);
69
+
70
+ if (!targetChild) {
71
+ return (
72
+ <ResizableContext.Provider value={contextValue}>
73
+ {children}
74
+ </ResizableContext.Provider>
75
+ );
76
+ }
77
+
78
+ const clonedTarget = React.cloneElement(
79
+ targetChild,
80
+ {
81
+ ref: forkedRef,
82
+ className: clsx(
83
+ targetChild.props.className,
84
+ styles['resizable-target'],
85
+ 'tcn-resizable-target'
86
+ ),
87
+ },
88
+ targetChild.props.children,
89
+ ...handleChildren
90
+ );
91
+
92
+ return (
93
+ <ResizableContext.Provider value={contextValue}>
94
+ {clonedTarget}
95
+ </ResizableContext.Provider>
96
+ );
97
+ }
@@ -0,0 +1,146 @@
1
+ @layer tcn-system {
2
+ .resize-handle {
3
+ position: absolute;
4
+ z-index: 1;
5
+ pointer-events: auto;
6
+ }
7
+
8
+ /* Horizontal edges: left, right, start, end */
9
+ :where(.resize-handle[data-position="left"]),
10
+ :where(.resize-handle[data-position="right"]),
11
+ :where(.resize-handle[data-position="start"]),
12
+ :where(.resize-handle[data-position="end"]) {
13
+ top: 0;
14
+ height: 100%;
15
+ width: 16px;
16
+ cursor: ew-resize;
17
+ }
18
+
19
+ :where(.resize-handle[data-position="left"]) {
20
+ left: var(--resize-offset, 0px);
21
+ }
22
+
23
+ :where(.resize-handle[data-position="right"]) {
24
+ right: var(--resize-offset, 0px);
25
+ }
26
+
27
+ :where(.resize-handle[data-position="start"]:dir(ltr)) {
28
+ left: var(--resize-offset, 0px);
29
+ }
30
+
31
+ :where(.resize-handle[data-position="start"]:dir(rtl)) {
32
+ right: var(--resize-offset, 0px);
33
+ }
34
+
35
+ :where(.resize-handle[data-position="end"]:dir(ltr)) {
36
+ right: var(--resize-offset, 0px);
37
+ }
38
+
39
+ :where(.resize-handle[data-position="end"]:dir(rtl)) {
40
+ left: var(--resize-offset, 0px);
41
+ }
42
+
43
+ /* Vertical edges: top, bottom */
44
+ :where(.resize-handle[data-position="top"]),
45
+ :where(.resize-handle[data-position="bottom"]) {
46
+ left: 0;
47
+ width: 100%;
48
+ height: 16px;
49
+ cursor: ns-resize;
50
+ }
51
+
52
+ :where(.resize-handle[data-position="top"]) {
53
+ top: var(--resize-offset, 0px);
54
+ }
55
+
56
+ :where(.resize-handle[data-position="bottom"]) {
57
+ bottom: var(--resize-offset, 0px);
58
+ }
59
+
60
+ /* Corners: small square at intersection */
61
+ :where(.resize-handle[data-position="top-left"]),
62
+ :where(.resize-handle[data-position="top-right"]),
63
+ :where(.resize-handle[data-position="bottom-left"]),
64
+ :where(.resize-handle[data-position="bottom-right"]),
65
+ :where(.resize-handle[data-position="top-start"]),
66
+ :where(.resize-handle[data-position="top-end"]),
67
+ :where(.resize-handle[data-position="bottom-start"]),
68
+ :where(.resize-handle[data-position="bottom-end"]) {
69
+ width: 16px;
70
+ height: 16px;
71
+ }
72
+
73
+ /* Physical corners */
74
+ :where(.resize-handle[data-position="top-left"]) {
75
+ top: var(--resize-offset, 0px);
76
+ left: var(--resize-offset, 0px);
77
+ cursor: nwse-resize;
78
+ }
79
+
80
+ :where(.resize-handle[data-position="top-right"]) {
81
+ top: var(--resize-offset, 0px);
82
+ right: var(--resize-offset, 0px);
83
+ cursor: nesw-resize;
84
+ }
85
+
86
+ :where(.resize-handle[data-position="bottom-left"]) {
87
+ bottom: var(--resize-offset, 0px);
88
+ left: var(--resize-offset, 0px);
89
+ cursor: nesw-resize;
90
+ }
91
+
92
+ :where(.resize-handle[data-position="bottom-right"]) {
93
+ bottom: var(--resize-offset, 0px);
94
+ right: var(--resize-offset, 0px);
95
+ cursor: nwse-resize;
96
+ }
97
+
98
+ /* Logical corners (RTL-aware) */
99
+ :where(.resize-handle[data-position="top-start"]:dir(ltr)) {
100
+ top: var(--resize-offset, 0px);
101
+ left: var(--resize-offset, 0px);
102
+ cursor: nwse-resize;
103
+ }
104
+
105
+ :where(.resize-handle[data-position="top-start"]:dir(rtl)) {
106
+ top: var(--resize-offset, 0px);
107
+ right: var(--resize-offset, 0px);
108
+ cursor: nesw-resize;
109
+ }
110
+
111
+ :where(.resize-handle[data-position="top-end"]:dir(ltr)) {
112
+ top: var(--resize-offset, 0px);
113
+ right: var(--resize-offset, 0px);
114
+ cursor: nesw-resize;
115
+ }
116
+
117
+ :where(.resize-handle[data-position="top-end"]:dir(rtl)) {
118
+ top: var(--resize-offset, 0px);
119
+ left: var(--resize-offset, 0px);
120
+ cursor: nwse-resize;
121
+ }
122
+
123
+ :where(.resize-handle[data-position="bottom-start"]:dir(ltr)) {
124
+ bottom: var(--resize-offset, 0px);
125
+ left: var(--resize-offset, 0px);
126
+ cursor: nesw-resize;
127
+ }
128
+
129
+ :where(.resize-handle[data-position="bottom-start"]:dir(rtl)) {
130
+ bottom: var(--resize-offset, 0px);
131
+ right: var(--resize-offset, 0px);
132
+ cursor: nwse-resize;
133
+ }
134
+
135
+ :where(.resize-handle[data-position="bottom-end"]:dir(ltr)) {
136
+ bottom: var(--resize-offset, 0px);
137
+ right: var(--resize-offset, 0px);
138
+ cursor: nwse-resize;
139
+ }
140
+
141
+ :where(.resize-handle[data-position="bottom-end"]:dir(rtl)) {
142
+ bottom: var(--resize-offset, 0px);
143
+ left: var(--resize-offset, 0px);
144
+ cursor: nesw-resize;
145
+ }
146
+ }
@@ -0,0 +1,165 @@
1
+ import React, { forwardRef, useMemo } from 'react';
2
+ import { clsx } from 'clsx';
3
+ import { useResizable } from './context.js';
4
+ import { getHandleConfig } from './handle_config.js';
5
+ import { ResizeHandleStrategy } from './resize_strategy.js';
6
+ import { detectResizeBounds } from '../../stacks/box/detect_resize_bounds.js';
7
+ import type { ResizeHandlePosition } from './types.js';
8
+ import styles from './resize_handle.module.css';
9
+
10
+ export interface ResizeHandleProps extends React.HTMLAttributes<HTMLDivElement> {
11
+ position: ResizeHandlePosition;
12
+ }
13
+
14
+ export const ResizeHandle = forwardRef<HTMLDivElement, ResizeHandleProps>(
15
+ function ResizeHandle({ position, className, ...rest }, ref) {
16
+ const {
17
+ targetRef,
18
+ onWidthResize,
19
+ onWidthResizeEnd,
20
+ onHeightResize,
21
+ onHeightResizeEnd,
22
+ } = useResizable();
23
+
24
+ const config = getHandleConfig(position);
25
+ const axis =
26
+ config.horizontal && config.vertical
27
+ ? 'corner'
28
+ : config.horizontal
29
+ ? 'horizontal'
30
+ : 'vertical';
31
+
32
+ const strategy = useMemo(() => new ResizeHandleStrategy(position), [position]);
33
+
34
+ const handleMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
35
+ const target = targetRef.current;
36
+ if (target == null) return;
37
+
38
+ const rect = target.getBoundingClientRect();
39
+ strategy.startResize({
40
+ rectangle: {
41
+ dimensions: {
42
+ width: rect.width,
43
+ height: rect.height,
44
+ },
45
+ position: {
46
+ x: event.clientX,
47
+ y: event.clientY,
48
+ },
49
+ },
50
+ languageDirection: window.getComputedStyle(target).direction,
51
+ });
52
+
53
+ let frameId = 0;
54
+
55
+ const drag = (e: MouseEvent) => {
56
+ e.stopPropagation();
57
+ e.preventDefault();
58
+
59
+ cancelAnimationFrame(frameId);
60
+ frameId = requestAnimationFrame(() => {
61
+ const result = strategy.resize({ x: e.clientX, y: e.clientY });
62
+
63
+ let appliedWidth = rect.width;
64
+ let appliedHeight = rect.height;
65
+
66
+ if (result.horizontal) {
67
+ const bounds = detectResizeBounds({
68
+ element: target,
69
+ axis: 'width',
70
+ nextSize: result.horizontal.newSize,
71
+ });
72
+ if (!bounds.clamped) {
73
+ appliedWidth = result.horizontal.newSize;
74
+ target.style.width = `${result.horizontal.newSize}px`;
75
+ onWidthResize?.({
76
+ width: result.horizontal.newSize,
77
+ origin: result.horizontal.origin,
78
+ totalDelta: result.horizontal.totalDelta,
79
+ currentDelta: result.horizontal.currentDelta,
80
+ });
81
+ } else if (
82
+ bounds.clampedSize !== null &&
83
+ bounds.clampedSize !== appliedWidth
84
+ ) {
85
+ appliedWidth = bounds.clampedSize;
86
+ target.style.width = `${bounds.clampedSize}px`;
87
+ onWidthResize?.({
88
+ width: bounds.clampedSize,
89
+ origin: result.horizontal.origin,
90
+ totalDelta: result.horizontal.totalDelta,
91
+ currentDelta: result.horizontal.currentDelta,
92
+ });
93
+ }
94
+ }
95
+
96
+ if (result.vertical) {
97
+ const bounds = detectResizeBounds({
98
+ element: target,
99
+ axis: 'height',
100
+ nextSize: result.vertical.newSize,
101
+ });
102
+ if (!bounds.clamped) {
103
+ appliedHeight = result.vertical.newSize;
104
+ target.style.height = `${result.vertical.newSize}px`;
105
+ onHeightResize?.({
106
+ height: result.vertical.newSize,
107
+ origin: result.vertical.origin,
108
+ totalDelta: result.vertical.totalDelta,
109
+ currentDelta: result.vertical.currentDelta,
110
+ });
111
+ } else if (
112
+ bounds.clampedSize !== null &&
113
+ bounds.clampedSize !== appliedHeight
114
+ ) {
115
+ appliedHeight = bounds.clampedSize;
116
+ target.style.height = `${bounds.clampedSize}px`;
117
+ onHeightResize?.({
118
+ height: bounds.clampedSize,
119
+ origin: result.vertical.origin,
120
+ totalDelta: result.vertical.totalDelta,
121
+ currentDelta: result.vertical.currentDelta,
122
+ });
123
+ }
124
+ }
125
+
126
+ strategy.commitResize({ width: appliedWidth, height: appliedHeight });
127
+ });
128
+ };
129
+
130
+ const endDrag = () => {
131
+ cancelAnimationFrame(frameId);
132
+ document.body.removeEventListener('mousemove', drag);
133
+ document.body.removeEventListener('mouseup', endDrag);
134
+ window.removeEventListener('blur', endDrag);
135
+
136
+ const result = strategy.endResize();
137
+ if (result.horizontal) {
138
+ onWidthResizeEnd?.(result.horizontal.width, result.horizontal.origin);
139
+ }
140
+ if (result.vertical) {
141
+ onHeightResizeEnd?.(result.vertical.height, result.vertical.origin);
142
+ }
143
+ };
144
+
145
+ document.body.addEventListener('mousemove', drag);
146
+ document.body.addEventListener('mouseup', endDrag);
147
+ window.addEventListener('blur', endDrag);
148
+ event.stopPropagation();
149
+ event.preventDefault();
150
+ };
151
+
152
+ return (
153
+ <div
154
+ ref={ref}
155
+ className={clsx(styles['resize-handle'], 'tcn-resize-handle', className)}
156
+ data-position={position}
157
+ data-axis={axis}
158
+ onMouseDown={handleMouseDown}
159
+ {...rest}
160
+ />
161
+ );
162
+ }
163
+ );
164
+
165
+ ResizeHandle.displayName = 'ResizeHandle';
@@ -0,0 +1,190 @@
1
+ import {
2
+ getHandleConfig,
3
+ resolveDirection,
4
+ computeResizeState,
5
+ } from './handle_config.js';
6
+ import type {
7
+ AxisConfig,
8
+ ResizeHandlePosition,
9
+ WidthResizeOrigin,
10
+ HeightResizeOrigin,
11
+ } from './types.js';
12
+ import type { Dimensions, Position, Rectangle } from '../types/dimensions.js';
13
+
14
+ export interface StartResizeParams {
15
+ rectangle: Rectangle;
16
+ languageDirection: string;
17
+ }
18
+
19
+ export interface AxisResizeResult {
20
+ newSize: number;
21
+ totalDelta: number;
22
+ currentDelta: number;
23
+ }
24
+
25
+ export interface HorizontalResizeResult extends AxisResizeResult {
26
+ origin: WidthResizeOrigin;
27
+ }
28
+
29
+ export interface VerticalResizeResult extends AxisResizeResult {
30
+ origin: HeightResizeOrigin;
31
+ }
32
+
33
+ export interface ResizeResult {
34
+ horizontal?: HorizontalResizeResult;
35
+ vertical?: VerticalResizeResult;
36
+ }
37
+
38
+ export interface EndResizeResult {
39
+ horizontal?: { width: number; origin: WidthResizeOrigin };
40
+ vertical?: { height: number; origin: HeightResizeOrigin };
41
+ }
42
+
43
+ /**
44
+ * Single-axis resize handler. Pure — no DOM, no React.
45
+ * Subclasses extract the correct axis from uniform args.
46
+ */
47
+ abstract class AxisResizeHandler {
48
+ protected direction = 1;
49
+ protected startSize = 0;
50
+ protected startCoord = 0;
51
+ protected currentSize = 0;
52
+
53
+ constructor(protected axisConfig: AxisConfig) {}
54
+
55
+ get origin() {
56
+ return this.axisConfig.origin;
57
+ }
58
+
59
+ get size() {
60
+ return this.currentSize;
61
+ }
62
+
63
+ protected abstract extractSize(dimensions: Dimensions): number;
64
+ protected abstract extractCoord(coord: Position): number;
65
+ abstract applyResize(coord: Position): Partial<ResizeResult>;
66
+ abstract applyEnd(): Partial<EndResizeResult>;
67
+
68
+ start(rect: Rectangle, languageDirection: string) {
69
+ this.direction = resolveDirection(
70
+ languageDirection,
71
+ this.axisConfig.invert,
72
+ this.axisConfig.disableDirection
73
+ );
74
+ this.startSize = this.extractSize(rect.dimensions);
75
+ this.startCoord = this.extractCoord(rect.position);
76
+ this.currentSize = this.startSize;
77
+ }
78
+
79
+ resize(coord: Position): AxisResizeResult {
80
+ return computeResizeState(
81
+ this.startSize,
82
+ this.startCoord,
83
+ this.extractCoord(coord),
84
+ this.direction,
85
+ this.currentSize
86
+ );
87
+ }
88
+
89
+ commit(dimensions: Dimensions) {
90
+ this.currentSize = this.extractSize(dimensions);
91
+ }
92
+ }
93
+
94
+ class HorizontalAxisResizeHandler extends AxisResizeHandler {
95
+ protected extractSize(dimensions: Dimensions) {
96
+ return dimensions.width;
97
+ }
98
+
99
+ protected extractCoord(coord: Position) {
100
+ return coord.x;
101
+ }
102
+
103
+ applyResize(coord: Position): Partial<ResizeResult> {
104
+ return {
105
+ horizontal: {
106
+ ...this.resize(coord),
107
+ origin: this.origin as WidthResizeOrigin,
108
+ },
109
+ };
110
+ }
111
+
112
+ applyEnd(): Partial<EndResizeResult> {
113
+ return {
114
+ horizontal: {
115
+ width: this.size,
116
+ origin: this.origin as WidthResizeOrigin,
117
+ },
118
+ };
119
+ }
120
+ }
121
+
122
+ class VerticalAxisResizeHandler extends AxisResizeHandler {
123
+ protected extractSize(dimensions: Dimensions) {
124
+ return dimensions.height;
125
+ }
126
+
127
+ protected extractCoord(coord: Position) {
128
+ return coord.y;
129
+ }
130
+
131
+ applyResize(coord: Position): Partial<ResizeResult> {
132
+ return {
133
+ vertical: {
134
+ ...this.resize(coord),
135
+ origin: this.origin as HeightResizeOrigin,
136
+ },
137
+ };
138
+ }
139
+
140
+ applyEnd(): Partial<EndResizeResult> {
141
+ return {
142
+ vertical: {
143
+ height: this.size,
144
+ origin: this.origin as HeightResizeOrigin,
145
+ },
146
+ };
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Flow:
152
+ * 1. adapter calls startResize() with rect/coords from DOM
153
+ * 2. adapter calls resize() on each mousemove with coord
154
+ * 3. adapter checks bounds (DOM), applies style, then calls commitResize()
155
+ * 4. adapter calls endResize() on mouseup to get final state
156
+ */
157
+ export class ResizeHandleStrategy {
158
+ private handlers: AxisResizeHandler[];
159
+
160
+ constructor(position: ResizeHandlePosition) {
161
+ const config = getHandleConfig(position);
162
+ this.handlers = [];
163
+ if (config.horizontal) {
164
+ this.handlers.push(new HorizontalAxisResizeHandler(config.horizontal));
165
+ }
166
+ if (config.vertical) {
167
+ this.handlers.push(new VerticalAxisResizeHandler(config.vertical));
168
+ }
169
+ }
170
+
171
+ startResize(params: StartResizeParams): void {
172
+ for (const handler of this.handlers) {
173
+ handler.start(params.rectangle, params.languageDirection);
174
+ }
175
+ }
176
+
177
+ resize(position: Position): ResizeResult {
178
+ return Object.assign({}, ...this.handlers.map(h => h.applyResize(position)));
179
+ }
180
+
181
+ commitResize(dimensions: Dimensions): void {
182
+ for (const handler of this.handlers) {
183
+ handler.commit(dimensions);
184
+ }
185
+ }
186
+
187
+ endResize(): EndResizeResult {
188
+ return Object.assign({}, ...this.handlers.map(h => h.applyEnd()));
189
+ }
190
+ }
@@ -0,0 +1,64 @@
1
+ import type {
2
+ OnWidthResize,
3
+ OnWidthResizeEnd,
4
+ OnHeightResize,
5
+ OnHeightResizeEnd,
6
+ WidthResizeOrigin,
7
+ HeightResizeOrigin,
8
+ } from '../../stacks/box/types.js';
9
+
10
+ export type {
11
+ OnWidthResize,
12
+ OnWidthResizeEnd,
13
+ OnHeightResize,
14
+ OnHeightResizeEnd,
15
+ WidthResizeOrigin,
16
+ HeightResizeOrigin,
17
+ };
18
+
19
+ export type ResizeHandlePosition =
20
+ // Edges (single axis)
21
+ | 'top'
22
+ | 'bottom'
23
+ | 'left'
24
+ | 'right'
25
+ | 'start'
26
+ | 'end'
27
+ // Corners (dual axis)
28
+ | 'top-left'
29
+ | 'top-right'
30
+ | 'bottom-left'
31
+ | 'bottom-right'
32
+ | 'top-start'
33
+ | 'top-end'
34
+ | 'bottom-start'
35
+ | 'bottom-end';
36
+
37
+ export interface AxisConfig {
38
+ origin: WidthResizeOrigin | HeightResizeOrigin;
39
+ invert: boolean;
40
+ disableDirection: boolean;
41
+ }
42
+
43
+ export interface HandleConfig {
44
+ horizontal?: AxisConfig;
45
+ vertical?: AxisConfig;
46
+ }
47
+
48
+ export interface ResolvedAxisConfig {
49
+ origin: WidthResizeOrigin | HeightResizeOrigin;
50
+ direction: number;
51
+ }
52
+
53
+ export interface ResolvedHandleConfig {
54
+ horizontal?: ResolvedAxisConfig;
55
+ vertical?: ResolvedAxisConfig;
56
+ }
57
+
58
+ export interface ResizableContextValue {
59
+ targetRef: React.RefObject<HTMLElement | null>;
60
+ onWidthResize?: OnWidthResize;
61
+ onWidthResizeEnd?: OnWidthResizeEnd;
62
+ onHeightResize?: OnHeightResize;
63
+ onHeightResizeEnd?: OnHeightResizeEnd;
64
+ }
@@ -1,5 +0,0 @@
1
- import './containers.css';const a = "_scaffold_7e9ff51", c = "_rail_9474c96", t = "_container_336e83e", s = "_container-stack_0d2e80a", o = "_scaffold-stack_3a72ba8", n = "_rail-stack_2e4d934", e = { scaffold: a, rail: c, container: t, "container-stack": s, "scaffold-stack": o, "rail-stack": n };
2
- export {
3
- e as s
4
- };
5
- //# sourceMappingURL=containers.module-DlGySre0.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"containers.module-DlGySre0.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}