@tcn/ui 0.15.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 (204) 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/column.d.ts +6 -0
  37. package/dist/layouts/containers/columns/column.d.ts.map +1 -0
  38. package/dist/layouts/containers/columns/column.js +20 -0
  39. package/dist/layouts/containers/columns/column.js.map +1 -0
  40. package/dist/layouts/containers/columns/columns.d.ts +11 -0
  41. package/dist/layouts/containers/columns/columns.d.ts.map +1 -0
  42. package/dist/layouts/containers/columns/columns.js +34 -0
  43. package/dist/layouts/containers/columns/columns.js.map +1 -0
  44. package/dist/layouts/containers/rail.d.ts +2 -5
  45. package/dist/layouts/containers/rail.d.ts.map +1 -1
  46. package/dist/layouts/containers/rail.js +17 -55
  47. package/dist/layouts/containers/rail.js.map +1 -1
  48. package/dist/layouts/containers/rows/index.d.ts +3 -0
  49. package/dist/layouts/containers/rows/index.d.ts.map +1 -0
  50. package/dist/layouts/containers/rows/index.js +7 -0
  51. package/dist/layouts/containers/rows/index.js.map +1 -0
  52. package/dist/layouts/containers/rows/row.d.ts +6 -0
  53. package/dist/layouts/containers/rows/row.d.ts.map +1 -0
  54. package/dist/layouts/containers/rows/row.js +20 -0
  55. package/dist/layouts/containers/rows/row.js.map +1 -0
  56. package/dist/layouts/containers/rows/rows.d.ts +11 -0
  57. package/dist/layouts/containers/rows/rows.d.ts.map +1 -0
  58. package/dist/layouts/containers/rows/rows.js +34 -0
  59. package/dist/layouts/containers/rows/rows.js.map +1 -0
  60. package/dist/layouts/containers/scaffold.d.ts +2 -5
  61. package/dist/layouts/containers/scaffold.d.ts.map +1 -1
  62. package/dist/layouts/containers/scaffold.js +17 -55
  63. package/dist/layouts/containers/scaffold.js.map +1 -1
  64. package/dist/layouts/index.d.ts +4 -2
  65. package/dist/layouts/index.d.ts.map +1 -1
  66. package/dist/layouts/index.js +35 -31
  67. package/dist/layouts/index.js.map +1 -1
  68. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.js +5 -2
  69. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.js.map +1 -1
  70. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.js +5 -2
  71. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.js.map +1 -1
  72. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.js +8 -5
  73. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.js.map +1 -1
  74. package/dist/navigation/tabs/state/link/tab_link.js +9 -6
  75. package/dist/navigation/tabs/state/link/tab_link.js.map +1 -1
  76. package/dist/overlay/menu/menu.js +3 -0
  77. package/dist/overlay/menu/menu.js.map +1 -1
  78. package/dist/overlay/popper/context_popper.js +8 -5
  79. package/dist/overlay/popper/context_popper.js.map +1 -1
  80. package/dist/overlay/popper/element_popper.js +9 -6
  81. package/dist/overlay/popper/element_popper.js.map +1 -1
  82. package/dist/overlay/popper/legacy/popper.js +13 -10
  83. package/dist/overlay/popper/legacy/popper.js.map +1 -1
  84. package/dist/overlay/popper/preview_popper.js +10 -7
  85. package/dist/overlay/popper/preview_popper.js.map +1 -1
  86. package/dist/overlay/tethered/tethered.js +11 -8
  87. package/dist/overlay/tethered/tethered.js.map +1 -1
  88. package/dist/resizable.css +1 -0
  89. package/dist/resizable.module-I6iyBAvM.js +5 -0
  90. package/dist/resizable.module-I6iyBAvM.js.map +1 -0
  91. package/dist/resize_handle.css +1 -0
  92. package/dist/row.css +1 -0
  93. package/dist/stacks/box/box.js +12 -9
  94. package/dist/stacks/box/box.js.map +1 -1
  95. package/dist/stacks/box/detect_resize_bounds.d.ts +1 -0
  96. package/dist/stacks/box/detect_resize_bounds.d.ts.map +1 -1
  97. package/dist/stacks/box/detect_resize_bounds.js +22 -20
  98. package/dist/stacks/box/detect_resize_bounds.js.map +1 -1
  99. package/dist/stacks/h_collapsible_box.js +17 -14
  100. package/dist/stacks/h_collapsible_box.js.map +1 -1
  101. package/dist/stacks/v_collapsible_box.js +19 -16
  102. package/dist/stacks/v_collapsible_box.js.map +1 -1
  103. package/dist/surfaces/card/card.d.ts.map +1 -1
  104. package/dist/surfaces/card/card.js +14 -6
  105. package/dist/surfaces/card/card.js.map +1 -1
  106. package/dist/surfaces/pop_confirm/pop_confirm.js +6 -4
  107. package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
  108. package/dist/test-setup.d.ts +2 -0
  109. package/dist/test-setup.d.ts.map +1 -0
  110. package/dist/test-setup.js +10 -0
  111. package/dist/test-setup.js.map +1 -0
  112. package/dist/themes/theme.d.ts.map +1 -1
  113. package/dist/themes/theme.js +17 -22
  114. package/dist/themes/theme.js.map +1 -1
  115. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  116. package/dist/themes/themes/ergo/ergo_theme.js +225 -27
  117. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  118. package/dist/utils/index.d.ts +1 -0
  119. package/dist/utils/index.d.ts.map +1 -1
  120. package/dist/utils/index.js +39 -26
  121. package/dist/utils/index.js.map +1 -1
  122. package/dist/utils/resize/context.d.ts +4 -0
  123. package/dist/utils/resize/context.d.ts.map +1 -0
  124. package/dist/utils/resize/context.js +10 -0
  125. package/dist/utils/resize/context.js.map +1 -0
  126. package/dist/utils/resize/handle_config.d.ts +32 -0
  127. package/dist/utils/resize/handle_config.d.ts.map +1 -0
  128. package/dist/utils/resize/handle_config.js +85 -0
  129. package/dist/utils/resize/handle_config.js.map +1 -0
  130. package/dist/utils/resize/index.d.ts +10 -0
  131. package/dist/utils/resize/index.d.ts.map +1 -0
  132. package/dist/utils/resize/index.js +16 -0
  133. package/dist/utils/resize/index.js.map +1 -0
  134. package/dist/utils/resize/resizable.d.ts +11 -0
  135. package/dist/utils/resize/resizable.d.ts.map +1 -0
  136. package/dist/utils/resize/resizable.js +52 -0
  137. package/dist/utils/resize/resizable.js.map +1 -0
  138. package/dist/utils/resize/resize_handle.d.ts +7 -0
  139. package/dist/utils/resize/resize_handle.d.ts.map +1 -0
  140. package/dist/utils/resize/resize_handle.js +100 -0
  141. package/dist/utils/resize/resize_handle.js.map +1 -0
  142. package/dist/utils/resize/resize_strategy.d.ts +47 -0
  143. package/dist/utils/resize/resize_strategy.d.ts.map +1 -0
  144. package/dist/utils/resize/resize_strategy.js +108 -0
  145. package/dist/utils/resize/resize_strategy.js.map +1 -0
  146. package/dist/utils/resize/types.d.ts +28 -0
  147. package/dist/utils/resize/types.d.ts.map +1 -0
  148. package/dist/utils/resize/types.js +2 -0
  149. package/dist/utils/resize/types.js.map +1 -0
  150. package/package.json +3 -3
  151. package/src/layouts/__stories__/columns.stories.tsx +77 -0
  152. package/src/layouts/__stories__/composed.stories.tsx +77 -8
  153. package/src/layouts/__stories__/rail.stories.tsx +4 -4
  154. package/src/layouts/__stories__/rows.stories.tsx +77 -0
  155. package/src/layouts/__stories__/utils.tsx +2 -84
  156. package/src/layouts/containers/columns/column.module.css +15 -0
  157. package/src/layouts/containers/columns/column.tsx +22 -0
  158. package/src/layouts/containers/columns/columns.tsx +42 -0
  159. package/src/layouts/containers/containers.module.css +27 -29
  160. package/src/layouts/containers/rail.tsx +9 -51
  161. package/src/layouts/containers/rows/index.ts +2 -0
  162. package/src/layouts/containers/rows/row.module.css +15 -0
  163. package/src/layouts/containers/rows/row.tsx +22 -0
  164. package/src/layouts/containers/rows/rows.tsx +42 -0
  165. package/src/layouts/containers/scaffold.tsx +9 -49
  166. package/src/layouts/index.ts +4 -2
  167. package/src/stacks/box/detect_resize_bounds.ts +5 -1
  168. package/src/surfaces/card/card.module.css +5 -0
  169. package/src/surfaces/card/card.stories.tsx +66 -8
  170. package/src/surfaces/card/card.tsx +6 -2
  171. package/src/surfaces/page/page.stories.tsx +109 -25
  172. package/src/surfaces/panel/__stories__/panel.stories.tsx +139 -1
  173. package/src/test-setup.ts +11 -0
  174. package/src/themes/theme.tsx +6 -16
  175. package/src/themes/themes/ergo/ergo_theme.css +223 -25
  176. package/src/utils/index.ts +2 -0
  177. package/src/utils/resize/__stories__/resizable.stories.tsx +214 -0
  178. package/src/utils/resize/__stories__/resizable_stories.module.css +47 -0
  179. package/src/utils/resize/__tests__/handle_config.test.ts +269 -0
  180. package/src/utils/resize/__tests__/resize_strategy.test.ts +163 -0
  181. package/src/utils/resize/context.ts +9 -0
  182. package/src/utils/resize/handle_config.ts +142 -0
  183. package/src/utils/resize/index.ts +37 -0
  184. package/src/utils/resize/resizable.module.css +5 -0
  185. package/src/utils/resize/resizable.tsx +97 -0
  186. package/src/utils/resize/resize_handle.module.css +146 -0
  187. package/src/utils/resize/resize_handle.tsx +165 -0
  188. package/src/utils/resize/resize_strategy.ts +190 -0
  189. package/src/utils/resize/types.ts +64 -0
  190. package/dist/containers.module-DlGySre0.js +0 -5
  191. package/dist/containers.module-DlGySre0.js.map +0 -1
  192. package/dist/layouts/column/column.d.ts +0 -10
  193. package/dist/layouts/column/column.d.ts.map +0 -1
  194. package/dist/layouts/column/column.js +0 -52
  195. package/dist/layouts/column/column.js.map +0 -1
  196. package/dist/layouts/containers/side/side.d.ts +0 -6
  197. package/dist/layouts/containers/side/side.d.ts.map +0 -1
  198. package/dist/layouts/containers/side/side.js +0 -22
  199. package/dist/layouts/containers/side/side.js.map +0 -1
  200. package/dist/side.css +0 -1
  201. package/src/layouts/column/column.module.css +0 -35
  202. package/src/layouts/column/column.tsx +0 -57
  203. package/src/layouts/containers/side/side.module.css +0 -7
  204. package/src/layouts/containers/side/side.tsx +0 -25
@@ -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":";"}
@@ -1,10 +0,0 @@
1
- import { default as React } from 'react';
2
- import { BoxProps } from '../../stacks/box/box.js';
3
- import { Alignment } from '../../stacks/types/alignment.js';
4
- export interface ColumnProps extends Omit<BoxProps, 'as' | 'children'> {
5
- hAlign?: Alignment;
6
- vAlign?: Alignment;
7
- children?: React.ReactNode;
8
- }
9
- export declare const Column: React.ForwardRefExoticComponent<ColumnProps & React.RefAttributes<HTMLElement>>;
10
- //# sourceMappingURL=column.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"column.d.ts","sourceRoot":"","sources":["../../../src/layouts/column/column.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAG5D,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,UAAU,CAAC;IACpE,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,eAAO,MAAM,MAAM,iFA2CjB,CAAC"}