@tcn/ui 0.10.0 → 0.12.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 (202) hide show
  1. package/dist/feedback/index.d.ts +1 -0
  2. package/dist/feedback/index.d.ts.map +1 -1
  3. package/dist/feedback/index.js +6 -4
  4. package/dist/feedback/index.js.map +1 -1
  5. package/dist/feedback/progress/progress.d.ts +7 -0
  6. package/dist/feedback/progress/progress.d.ts.map +1 -0
  7. package/dist/feedback/progress/progress.js +38 -0
  8. package/dist/feedback/progress/progress.js.map +1 -0
  9. package/dist/feedback/progress/progress_bar.d.ts +0 -1
  10. package/dist/feedback/progress/progress_bar.d.ts.map +1 -1
  11. package/dist/feedback/progress/progress_bar.js +6 -46
  12. package/dist/feedback/progress/progress_bar.js.map +1 -1
  13. package/dist/form/field/common/status_input/status_input.js +4 -3
  14. package/dist/form/field/common/status_input/status_input.js.map +1 -1
  15. package/dist/form/field/h_field/h_field.d.ts.map +1 -1
  16. package/dist/form/field/h_field/h_field.js +33 -35
  17. package/dist/form/field/h_field/h_field.js.map +1 -1
  18. package/dist/form/field/v_field/v_field.d.ts.map +1 -1
  19. package/dist/form/field/v_field/v_field.js +34 -36
  20. package/dist/form/field/v_field/v_field.js.map +1 -1
  21. package/dist/frame.css +1 -1
  22. package/dist/inputs/color_input/color_input.d.ts.map +1 -1
  23. package/dist/inputs/color_input/color_input.js +47 -46
  24. package/dist/inputs/color_input/color_input.js.map +1 -1
  25. package/dist/inputs/combo_box/combo_box.d.ts.map +1 -1
  26. package/dist/inputs/combo_box/combo_box.js +61 -58
  27. package/dist/inputs/combo_box/combo_box.js.map +1 -1
  28. package/dist/inputs/index.d.ts +1 -0
  29. package/dist/inputs/index.d.ts.map +1 -1
  30. package/dist/inputs/index.js +34 -31
  31. package/dist/inputs/index.js.map +1 -1
  32. package/dist/inputs/input/input.js +9 -9
  33. package/dist/inputs/input/input.js.map +1 -1
  34. package/dist/inputs/input_group/input_group.d.ts +5 -0
  35. package/dist/inputs/input_group/input_group.d.ts.map +1 -0
  36. package/dist/inputs/input_group/input_group.js +20 -0
  37. package/dist/inputs/input_group/input_group.js.map +1 -0
  38. package/dist/inputs/phone_number_input/countries_phone_information.d.ts +2 -2
  39. package/dist/inputs/phone_number_input/countries_phone_information.d.ts.map +1 -1
  40. package/dist/inputs/phone_number_input/countries_phone_information.js +5 -353
  41. package/dist/inputs/phone_number_input/countries_phone_information.js.map +1 -1
  42. package/dist/inputs/phone_number_input/phone_number_context.d.ts +24 -0
  43. package/dist/inputs/phone_number_input/phone_number_context.d.ts.map +1 -0
  44. package/dist/inputs/phone_number_input/phone_number_context.js +23 -0
  45. package/dist/inputs/phone_number_input/phone_number_context.js.map +1 -0
  46. package/dist/inputs/phone_number_input/phone_number_country_select_adapter.d.ts +19 -0
  47. package/dist/inputs/phone_number_input/phone_number_country_select_adapter.d.ts.map +1 -0
  48. package/dist/inputs/phone_number_input/phone_number_country_select_adapter.js +77 -0
  49. package/dist/inputs/phone_number_input/phone_number_country_select_adapter.js.map +1 -0
  50. package/dist/inputs/phone_number_input/phone_number_input.d.ts +16 -14
  51. package/dist/inputs/phone_number_input/phone_number_input.d.ts.map +1 -1
  52. package/dist/inputs/phone_number_input/phone_number_input.js +104 -274
  53. package/dist/inputs/phone_number_input/phone_number_input.js.map +1 -1
  54. package/dist/inputs/phone_number_input/phone_number_input_adapter.d.ts +6 -0
  55. package/dist/inputs/phone_number_input/phone_number_input_adapter.d.ts.map +1 -0
  56. package/dist/inputs/phone_number_input/phone_number_input_adapter.js +95 -0
  57. package/dist/inputs/phone_number_input/phone_number_input_adapter.js.map +1 -0
  58. package/dist/inputs/phone_number_input/sip_input.d.ts +12 -0
  59. package/dist/inputs/phone_number_input/sip_input.d.ts.map +1 -0
  60. package/dist/inputs/phone_number_input/sip_input.js +111 -0
  61. package/dist/inputs/phone_number_input/sip_input.js.map +1 -0
  62. package/dist/inputs/select/select.d.ts.map +1 -1
  63. package/dist/inputs/select/select.js +3 -2
  64. package/dist/inputs/select/select.js.map +1 -1
  65. package/dist/inputs/suggestions/suggestion_list.d.ts +4 -1
  66. package/dist/inputs/suggestions/suggestion_list.d.ts.map +1 -1
  67. package/dist/inputs/suggestions/suggestion_list.js +148 -121
  68. package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
  69. package/dist/inputs/textarea/textarea.js +8 -8
  70. package/dist/inputs/textarea/textarea.js.map +1 -1
  71. package/dist/inputs/unit_input/unit_input.d.ts.map +1 -1
  72. package/dist/inputs/unit_input/unit_input.js +39 -39
  73. package/dist/inputs/unit_input/unit_input.js.map +1 -1
  74. package/dist/overlay/frame/frame.d.ts +8 -4
  75. package/dist/overlay/frame/frame.d.ts.map +1 -1
  76. package/dist/overlay/frame/frame.js +88 -24
  77. package/dist/overlay/frame/frame.js.map +1 -1
  78. package/dist/overlay/popper/base/dismissal_decorator.js.map +1 -1
  79. package/dist/overlay/popper/legacy/popper.d.ts.map +1 -1
  80. package/dist/overlay/popper/legacy/popper.js +52 -50
  81. package/dist/overlay/popper/legacy/popper.js.map +1 -1
  82. package/dist/phone_number_input.css +1 -1
  83. package/dist/progress_bar-CPP0Jyv-.js +38 -0
  84. package/dist/progress_bar-CPP0Jyv-.js.map +1 -0
  85. package/dist/progress_bar.css +1 -1
  86. package/dist/stacks/box/bottom_resize_handle.d.ts +2 -8
  87. package/dist/stacks/box/bottom_resize_handle.d.ts.map +1 -1
  88. package/dist/stacks/box/bottom_resize_handle.js.map +1 -1
  89. package/dist/stacks/box/box.d.ts +2 -2
  90. package/dist/stacks/box/box.d.ts.map +1 -1
  91. package/dist/stacks/box/box.js.map +1 -1
  92. package/dist/stacks/box/end_resize_handle.d.ts +2 -8
  93. package/dist/stacks/box/end_resize_handle.d.ts.map +1 -1
  94. package/dist/stacks/box/end_resize_handle.js.map +1 -1
  95. package/dist/stacks/box/left_resize_handle.d.ts +2 -8
  96. package/dist/stacks/box/left_resize_handle.d.ts.map +1 -1
  97. package/dist/stacks/box/left_resize_handle.js.map +1 -1
  98. package/dist/stacks/box/resize_handlers.d.ts +3 -2
  99. package/dist/stacks/box/resize_handlers.d.ts.map +1 -1
  100. package/dist/stacks/box/resize_handlers.js +41 -37
  101. package/dist/stacks/box/resize_handlers.js.map +1 -1
  102. package/dist/stacks/box/right_resize_handle.d.ts +2 -8
  103. package/dist/stacks/box/right_resize_handle.d.ts.map +1 -1
  104. package/dist/stacks/box/right_resize_handle.js.map +1 -1
  105. package/dist/stacks/box/start_resize_handle.d.ts +2 -8
  106. package/dist/stacks/box/start_resize_handle.d.ts.map +1 -1
  107. package/dist/stacks/box/start_resize_handle.js +4 -4
  108. package/dist/stacks/box/start_resize_handle.js.map +1 -1
  109. package/dist/stacks/box/top_resize_handle.d.ts +2 -8
  110. package/dist/stacks/box/top_resize_handle.d.ts.map +1 -1
  111. package/dist/stacks/box/top_resize_handle.js +4 -4
  112. package/dist/stacks/box/top_resize_handle.js.map +1 -1
  113. package/dist/stacks/box/types.d.ts +18 -0
  114. package/dist/stacks/box/types.d.ts.map +1 -0
  115. package/dist/stacks/h_collapsible_box.js +25 -25
  116. package/dist/stacks/h_collapsible_box.js.map +1 -1
  117. package/dist/stacks/index.d.ts +1 -0
  118. package/dist/stacks/index.d.ts.map +1 -1
  119. package/dist/stacks/v_collapsible_box.js +25 -25
  120. package/dist/stacks/v_collapsible_box.js.map +1 -1
  121. package/dist/suggestion_list.css +1 -1
  122. package/dist/surfaces/modal/modal.d.ts +3 -4
  123. package/dist/surfaces/modal/modal.d.ts.map +1 -1
  124. package/dist/surfaces/modal/modal.js +10 -8
  125. package/dist/surfaces/modal/modal.js.map +1 -1
  126. package/dist/surfaces/window/window.d.ts +3 -4
  127. package/dist/surfaces/window/window.d.ts.map +1 -1
  128. package/dist/surfaces/window/window.js +26 -14
  129. package/dist/surfaces/window/window.js.map +1 -1
  130. package/dist/themes/stylesheets/reset.css +1 -1
  131. package/dist/themes/stylesheets/reset.js +8 -1
  132. package/dist/themes/stylesheets/reset.js.map +1 -1
  133. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  134. package/dist/themes/themes/ergo/ergo_theme.js +186 -19
  135. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  136. package/dist/typography/body_text/body_text.d.ts.map +1 -1
  137. package/dist/typography/body_text/body_text.js +12 -10
  138. package/dist/typography/body_text/body_text.js.map +1 -1
  139. package/dist/utils/dnd/hooks/use_drag_container.d.ts.map +1 -1
  140. package/dist/utils/dnd/hooks/use_drag_container.js +22 -19
  141. package/dist/utils/dnd/hooks/use_drag_container.js.map +1 -1
  142. package/package.json +4 -2
  143. package/src/feedback/index.ts +1 -0
  144. package/src/feedback/progress/progress.module.css +5 -0
  145. package/src/feedback/progress/progress.stories.tsx +48 -0
  146. package/src/feedback/progress/progress.tsx +39 -0
  147. package/src/feedback/progress/progress_bar.module.css +4 -28
  148. package/src/feedback/progress/progress_bar.stories.tsx +1 -1
  149. package/src/feedback/progress/progress_bar.tsx +14 -26
  150. package/src/form/field/h_field/h_field.tsx +0 -4
  151. package/src/form/field/v_field/v_field.stories.tsx +8 -0
  152. package/src/form/field/v_field/v_field.tsx +1 -4
  153. package/src/form/field_set/field_set.stories.tsx +2 -1
  154. package/src/inputs/__docs__/inputs.mdx +81 -0
  155. package/src/inputs/__docs__/inputs.stories.tsx +268 -0
  156. package/src/inputs/color_input/color_input.tsx +17 -17
  157. package/src/inputs/combo_box/combo_box.tsx +17 -13
  158. package/src/inputs/index.ts +2 -0
  159. package/src/inputs/input/input.tsx +1 -1
  160. package/src/inputs/input_group/input_group.tsx +26 -0
  161. package/src/inputs/phone_number_input/countries_phone_information.ts +6 -353
  162. package/src/inputs/phone_number_input/phone_number_context.tsx +32 -0
  163. package/src/inputs/phone_number_input/phone_number_country_select_adapter.tsx +126 -0
  164. package/src/inputs/phone_number_input/phone_number_input.module.css +5 -63
  165. package/src/inputs/phone_number_input/phone_number_input.stories.tsx +180 -150
  166. package/src/inputs/phone_number_input/phone_number_input.tsx +133 -400
  167. package/src/inputs/phone_number_input/phone_number_input_adapter.tsx +123 -0
  168. package/src/inputs/phone_number_input/sip_input.tsx +147 -0
  169. package/src/inputs/select/select.stories.tsx +23 -2
  170. package/src/inputs/select/select.tsx +13 -14
  171. package/src/inputs/suggestions/suggestion_list.module.css +1 -0
  172. package/src/inputs/suggestions/suggestion_list.stories.tsx +12 -8
  173. package/src/inputs/suggestions/suggestion_list.tsx +82 -42
  174. package/src/inputs/textarea/textarea.tsx +1 -1
  175. package/src/inputs/unit_input/unit_input.tsx +17 -17
  176. package/src/overlay/frame/frame.module.css +2 -4
  177. package/src/overlay/frame/frame.stories.tsx +13 -10
  178. package/src/overlay/frame/frame.tsx +121 -15
  179. package/src/overlay/popper/base/dismissal_decorator.tsx +1 -1
  180. package/src/overlay/popper/legacy/popper.tsx +5 -1
  181. package/src/stacks/box/bottom_resize_handle.tsx +2 -8
  182. package/src/stacks/box/box.tsx +14 -2
  183. package/src/stacks/box/end_resize_handle.tsx +3 -8
  184. package/src/stacks/box/left_resize_handle.tsx +3 -8
  185. package/src/stacks/box/resize_handlers.ts +28 -12
  186. package/src/stacks/box/right_resize_handle.tsx +2 -8
  187. package/src/stacks/box/start_resize_handle.tsx +4 -9
  188. package/src/stacks/box/top_resize_handle.tsx +4 -8
  189. package/src/stacks/box/types.ts +44 -0
  190. package/src/stacks/h_collapsible_box.tsx +2 -2
  191. package/src/stacks/index.ts +1 -0
  192. package/src/stacks/v_collapsible_box.tsx +2 -2
  193. package/src/surfaces/modal/modal.tsx +6 -4
  194. package/src/surfaces/window/window.stories.tsx +9 -1
  195. package/src/surfaces/window/window.tsx +19 -7
  196. package/src/themes/stories/controls_fieldset.tsx +1 -1
  197. package/src/themes/stylesheets/reset.css +8 -1
  198. package/src/themes/themes/ergo/ergo_theme.css +186 -19
  199. package/src/typography/body_text/body_text.tsx +2 -0
  200. package/src/utils/dnd/__stories__/draggable.stories.tsx +14 -8
  201. package/src/utils/dnd/hooks/use_drag_container.ts +13 -3
  202. package/src/inputs/phone_number_input/__tests__/utils.test.ts +0 -52
@@ -1,50 +1,156 @@
1
- import React from 'react';
2
- import { ZStack, type ZStackProps } from '../../stacks/index.js';
1
+ import { clsx } from 'clsx';
2
+ import React, { useCallback } from 'react';
3
+ import { flushSync } from 'react-dom';
4
+ import { Box, ZStack, type BoxProps } from '../../stacks/index.js';
5
+ import { useDragContainer } from '../../utils/dnd/context.js';
3
6
  import { Draggable } from '../../utils/dnd/draggable/draggable.js';
4
7
  import { Portal } from '../portal/portal.js';
5
8
 
6
9
  // Styles
7
- import { clsx } from 'clsx';
8
10
  import styles from './frame.module.css';
9
-
10
11
  export interface FrameOwnProps {
11
12
  isOpen?: boolean;
12
- children?: React.ReactNode;
13
13
  draggable?: boolean;
14
14
  veil?: boolean;
15
+ resizable?: boolean;
15
16
  }
16
17
 
17
- export type FrameProps = ZStackProps & FrameOwnProps;
18
+ export type FrameProps = Omit<
19
+ BoxProps,
20
+ | 'enableResizeOnLeft'
21
+ | 'enableResizeOnRight'
22
+ | 'enableResizeOnTop'
23
+ | 'enableResizeOnBottom'
24
+ > &
25
+ FrameOwnProps;
18
26
 
19
- export const Frame = React.forwardRef<HTMLDialogElement, FrameProps>(function Frame(
27
+ export const Frame = React.forwardRef<HTMLElement, FrameProps>(function Frame(
20
28
  {
21
29
  children,
22
30
  isOpen = false,
23
31
  draggable = true,
24
32
  veil = false,
33
+ resizable = true,
25
34
  className,
26
35
  ...rest
27
36
  }: FrameProps,
28
37
  ref
29
38
  ) {
30
- if (!isOpen) {
31
- return null;
32
- }
33
-
39
+ if (!isOpen) return null;
34
40
  return (
35
41
  <Portal>
36
42
  <ZStack width="100%" height="100%" data-is-veil={veil} className="tcn-frame-veil">
37
43
  <Draggable draggable={draggable}>
38
- <ZStack
39
- as="dialog"
44
+ <FrameDialog
45
+ className={className}
40
46
  ref={ref}
41
- className={clsx(styles['frame'], 'tcn-frame', className)}
47
+ enableResizeOnLeft={resizable}
48
+ enableResizeOnRight={resizable}
49
+ enableResizeOnTop={resizable}
50
+ enableResizeOnBottom={resizable}
51
+ draggable={draggable}
42
52
  {...rest}
43
53
  >
44
54
  {children}
45
- </ZStack>
55
+ </FrameDialog>
46
56
  </Draggable>
47
57
  </ZStack>
48
58
  </Portal>
49
59
  );
50
60
  });
61
+ interface FrameDialogProps extends BoxProps {}
62
+
63
+ export const FrameDialog = React.forwardRef<HTMLElement, FrameDialogProps>(
64
+ function FrameDialog(
65
+ {
66
+ as = 'div',
67
+ role = 'dialog',
68
+ children,
69
+ className,
70
+ draggable,
71
+ onWidthResize,
72
+ onHeightResize,
73
+ ...rest
74
+ }: FrameDialogProps,
75
+ ref: React.Ref<HTMLElement>
76
+ ) {
77
+ const drag = useDragContainer();
78
+
79
+ const handleWidthResize = React.useCallback(
80
+ (
81
+ width: number,
82
+ origin: 'left' | 'right',
83
+ totalDelta: number,
84
+ currentDelta: number,
85
+ atLimit: boolean
86
+ ) => {
87
+ if (!draggable) return;
88
+ if (atLimit) return;
89
+ if (origin === 'right') {
90
+ flushSync(() => {
91
+ drag.setPosition(prev => ({
92
+ x: prev.x + currentDelta / 2,
93
+ y: prev.y,
94
+ }));
95
+ });
96
+ }
97
+ if (origin === 'left') {
98
+ flushSync(() => {
99
+ drag.setPosition(prev => ({
100
+ x: prev.x - currentDelta / 2,
101
+ y: prev.y,
102
+ }));
103
+ });
104
+ }
105
+
106
+ onWidthResize?.(width, origin, totalDelta, currentDelta, atLimit);
107
+ },
108
+ [onWidthResize, drag, draggable]
109
+ );
110
+
111
+ const handleHeightResize = useCallback(
112
+ (
113
+ height: number,
114
+ origin: 'top' | 'bottom',
115
+ totalDelta: number,
116
+ currentDelta: number,
117
+ atLimit: boolean
118
+ ) => {
119
+ if (!draggable) return;
120
+ if (atLimit) return;
121
+ if (origin === 'bottom') {
122
+ flushSync(() => {
123
+ drag.setPosition(prev => ({
124
+ x: prev.x,
125
+ y: prev.y + currentDelta / 2,
126
+ }));
127
+ });
128
+ }
129
+ if (origin === 'top') {
130
+ flushSync(() => {
131
+ drag.setPosition(prev => ({
132
+ x: prev.x,
133
+ y: prev.y - currentDelta / 2,
134
+ }));
135
+ });
136
+ }
137
+ onHeightResize?.(height, origin, totalDelta, currentDelta, atLimit);
138
+ },
139
+ [onHeightResize, drag, draggable]
140
+ );
141
+
142
+ return (
143
+ <Box
144
+ className={clsx(styles['frame-dialog'], 'tcn-frame-dialog', className)}
145
+ ref={ref}
146
+ onWidthResize={handleWidthResize}
147
+ onHeightResize={handleHeightResize}
148
+ as={as}
149
+ role={role}
150
+ {...rest}
151
+ >
152
+ {children}
153
+ </Box>
154
+ );
155
+ }
156
+ );
@@ -36,7 +36,7 @@ export const PopperDismissalDecorator = forwardRef<
36
36
 
37
37
  function buildExceptionHandler(dismissal: PopperDismissal) {
38
38
  if (dismissal in dismissals) {
39
- return target => isException?.(dismissal, target) ?? false;
39
+ return (target: HTMLElement) => isException?.(dismissal, target) ?? false;
40
40
  }
41
41
  return () => false;
42
42
  }
@@ -152,13 +152,17 @@ export function Popper({
152
152
  };
153
153
 
154
154
  useLayoutEffect(() => {
155
- updatePosition();
156
155
  window.addEventListener('resize', updatePosition);
157
156
  return () => {
158
157
  window.removeEventListener('resize', updatePosition);
159
158
  };
160
159
  });
161
160
 
161
+ // biome-ignore lint/correctness/useExhaustiveDependencies: updatePosition depends on open and anchorElement
162
+ useLayoutEffect(() => {
163
+ updatePosition();
164
+ }, [open, anchorElement]);
165
+
162
166
  useLayoutEffect(() => {
163
167
  if (open) {
164
168
  activeElementRef.current = window.document.activeElement as HTMLElement;
@@ -1,16 +1,10 @@
1
1
  import { clsx } from 'clsx';
2
2
  import React from 'react';
3
3
  import styles from './bottom_resize_handle.module.css';
4
- import type { HandleProps } from './handle_props.js';
5
4
  import { createVerticalResizeHandler } from './resize_handlers.js';
5
+ import type { VerticalResizeHandleProps } from './types.js';
6
6
 
7
- export interface BottomResizeHandleProps {
8
- targetRef: React.MutableRefObject<HTMLElement | null>;
9
- handleProps?: HandleProps;
10
- onHeightResize?: (height: number, origin: 'top' | 'bottom', delta: number) => void;
11
- onHeightResizeEnd?: (height: number, origin: 'top' | 'bottom') => void;
12
- }
13
-
7
+ export type BottomResizeHandleProps = VerticalResizeHandleProps;
14
8
  export function BottomResizeHandle({
15
9
  targetRef,
16
10
  handleProps,
@@ -45,8 +45,20 @@ export interface BoxProps<T extends HTMLElement = HTMLElement> extends HTMLAttri
45
45
  enableResizeOnRight?: boolean;
46
46
  horizontalHandleProps?: HandleProps;
47
47
  verticalHandleProps?: HandleProps;
48
- onWidthResize?: (width: number, origin: 'left' | 'right', delta: number) => void;
49
- onHeightResize?: (height: number, origin: 'top' | 'bottom', delta: number) => void;
48
+ onWidthResize?: (
49
+ width: number,
50
+ origin: 'left' | 'right',
51
+ totalDelta: number,
52
+ currentDelta: number,
53
+ atLimit: boolean
54
+ ) => void;
55
+ onHeightResize?: (
56
+ height: number,
57
+ origin: 'top' | 'bottom',
58
+ totalDelta: number,
59
+ currentDelta: number,
60
+ atLimit: boolean
61
+ ) => void;
50
62
  onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
51
63
  onHeightResizeEnd?: (height: number, origin: 'top' | 'bottom') => void;
52
64
  }
@@ -1,15 +1,10 @@
1
1
  import { clsx } from 'clsx';
2
- import React from 'react';
3
2
  import styles from './end_resize_handle.module.css';
4
- import { HandleProps } from './handle_props.js';
5
3
  import { createHorizontalResizeHandler } from './resize_handlers.js';
4
+ import type { HorizontalResizeHandleProps } from './types.js';
5
+
6
+ export type EndResizeHandleProps = HorizontalResizeHandleProps;
6
7
 
7
- export interface EndResizeHandleProps {
8
- targetRef: React.MutableRefObject<HTMLElement | null>;
9
- handleProps?: HandleProps;
10
- onWidthResize?: (width: number, origin: 'left' | 'right', delta: number) => void;
11
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
12
- }
13
8
  export function EndResizeHandle({
14
9
  targetRef,
15
10
  handleProps,
@@ -1,15 +1,10 @@
1
1
  import { clsx } from 'clsx';
2
- import React from 'react';
3
- import { HandleProps } from './handle_props.js';
4
2
  import styles from './left_resize_handle.module.css';
5
3
  import { createHorizontalResizeHandler } from './resize_handlers.js';
4
+ import type { HorizontalResizeHandleProps } from './types.js';
5
+
6
+ export type LeftResizeHandleProps = HorizontalResizeHandleProps;
6
7
 
7
- export interface LeftResizeHandleProps {
8
- targetRef: React.MutableRefObject<HTMLElement | null>;
9
- handleProps?: HandleProps;
10
- onWidthResize?: (width: number, origin: 'left' | 'right', delta: number) => void;
11
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
12
- }
13
8
  export function LeftResizeHandle({
14
9
  targetRef,
15
10
  handleProps,
@@ -1,3 +1,10 @@
1
+ import {
2
+ OnWidthResize,
3
+ type HeightResizeOrigin,
4
+ type OnHeightResize,
5
+ type WidthResizeOrigin,
6
+ } from './types';
7
+
1
8
  function createVeil() {
2
9
  const veil = window.document.createElement('div');
3
10
  veil.style.position = 'absolute';
@@ -9,9 +16,9 @@ function createVeil() {
9
16
 
10
17
  export function createHorizontalResizeHandler(
11
18
  targetRef: React.MutableRefObject<HTMLElement | null>,
12
- onWidthResize?: (width: number, origin: 'left' | 'right', delta: number) => void,
13
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void,
14
- origin: 'left' | 'right' = 'right',
19
+ onWidthResize?: OnWidthResize,
20
+ onWidthResizeEnd?: (width: number, origin: WidthResizeOrigin) => void,
21
+ origin: WidthResizeOrigin = 'right',
15
22
  invert = false,
16
23
  disableDirection = false
17
24
  ) {
@@ -35,13 +42,18 @@ export function createHorizontalResizeHandler(
35
42
  let width = startRect.width;
36
43
 
37
44
  const drag = (event: MouseEvent) => {
38
- const deltaX = direction * (event.clientX - startX);
39
- const newWidth = startRect.width + deltaX;
45
+ const beforeWidth = box.getBoundingClientRect().width;
46
+ const totalDelta = direction * (event.clientX - startX);
47
+ const newWidth = startRect.width + totalDelta;
48
+ const currentDelta = newWidth - width;
40
49
 
41
50
  width = newWidth;
42
51
 
43
52
  box.style.width = `${newWidth}px`;
44
- onWidthResize?.(newWidth, origin, deltaX);
53
+
54
+ const afterWidth = box.getBoundingClientRect().width;
55
+ const atLimit = afterWidth === beforeWidth;
56
+ onWidthResize?.(newWidth, origin, totalDelta, currentDelta, atLimit);
45
57
  event.stopPropagation();
46
58
  event.preventDefault();
47
59
  };
@@ -74,10 +86,10 @@ export function createHorizontalResizeHandler(
74
86
 
75
87
  export function createVerticalResizeHandler(
76
88
  targetRef: React.MutableRefObject<HTMLElement | null>,
77
- onHeightResize?: (height: number, origin: 'top' | 'bottom', delta: number) => void,
78
- onHeightResizeEnd?: (height: number, origin: 'top' | 'bottom') => void,
89
+ onHeightResize?: OnHeightResize,
90
+ onHeightResizeEnd?: (height: number, origin: HeightResizeOrigin) => void,
79
91
  invert = false,
80
- origin: 'top' | 'bottom' = 'bottom'
92
+ origin: HeightResizeOrigin = 'bottom'
81
93
  ) {
82
94
  const direction = invert ? -1 : 1;
83
95
  return function startVerticalResize(event: React.MouseEvent) {
@@ -95,11 +107,15 @@ export function createVerticalResizeHandler(
95
107
  let height = startRect.height;
96
108
 
97
109
  const drag = (event: MouseEvent) => {
98
- const deltaY = direction * (event.clientY - startY);
99
- const newHeight = startRect.height + deltaY;
110
+ const beforeHeight = box.getBoundingClientRect().height;
111
+ const totalDelta = direction * (event.clientY - startY);
112
+ const newHeight = startRect.height + totalDelta;
113
+ const currentDelta = newHeight - height;
100
114
  height = newHeight;
101
115
  box.style.height = `${newHeight}px`;
102
- onHeightResize?.(newHeight, origin, deltaY);
116
+ const afterHeight = box.getBoundingClientRect().height;
117
+ const atLimit = afterHeight === beforeHeight;
118
+ onHeightResize?.(newHeight, origin, totalDelta, currentDelta, atLimit);
103
119
  event.stopPropagation();
104
120
  event.preventDefault();
105
121
  };
@@ -1,15 +1,9 @@
1
1
  import { clsx } from 'clsx';
2
- import React from 'react';
3
- import { HandleProps } from './handle_props.js';
4
2
  import { createHorizontalResizeHandler } from './resize_handlers.js';
5
3
  import styles from './right_resize_handle.module.css';
4
+ import type { HorizontalResizeHandleProps } from './types.js';
6
5
 
7
- export interface RightResizeHandleProps {
8
- targetRef: React.MutableRefObject<HTMLElement | null>;
9
- handleProps?: HandleProps;
10
- onWidthResize?: (width: number, origin: 'left' | 'right', delta: number) => void;
11
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
12
- }
6
+ export type RightResizeHandleProps = HorizontalResizeHandleProps;
13
7
  export function RightResizeHandle({
14
8
  targetRef,
15
9
  handleProps,
@@ -1,15 +1,10 @@
1
- import React from 'react';
2
- import { HandleProps } from './handle_props.js';
1
+ import { clsx } from 'clsx';
3
2
  import { createHorizontalResizeHandler } from './resize_handlers.js';
4
3
  import styles from './start_resize_handle.module.css';
5
- import { clsx } from 'clsx';
4
+ import type { HorizontalResizeHandleProps } from './types.js';
5
+
6
+ export type StartResizeHandleProps = HorizontalResizeHandleProps;
6
7
 
7
- export interface StartResizeHandleProps {
8
- targetRef: React.MutableRefObject<HTMLElement | null>;
9
- handleProps?: HandleProps;
10
- onWidthResize?: (width: number, origin: 'left' | 'right', delta: number) => void;
11
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
12
- }
13
8
  export function StartResizeHandle({
14
9
  targetRef,
15
10
  handleProps,
@@ -1,15 +1,11 @@
1
+ import { clsx } from 'clsx';
1
2
  import React from 'react';
2
- import { HandleProps } from './handle_props.js';
3
3
  import { createVerticalResizeHandler } from './resize_handlers.js';
4
4
  import styles from './top_resize_handle.module.css';
5
- import { clsx } from 'clsx';
5
+ import type { VerticalResizeHandleProps } from './types.js';
6
+
7
+ export type TopResizeHandleProps = VerticalResizeHandleProps;
6
8
 
7
- export interface TopResizeHandleProps {
8
- targetRef: React.MutableRefObject<HTMLElement | null>;
9
- handleProps?: HandleProps;
10
- onHeightResize?: (height: number, origin: 'top' | 'bottom', delta: number) => void;
11
- onHeightResizeEnd?: (height: number, origin: 'top' | 'bottom') => void;
12
- }
13
9
  export function TopResizeHandle({
14
10
  targetRef,
15
11
  handleProps,
@@ -0,0 +1,44 @@
1
+ import type { HandleProps } from './handle_props.js';
2
+
3
+ export type WidthResizeOrigin = 'left' | 'right';
4
+ export type HeightResizeOrigin = 'top' | 'bottom';
5
+
6
+ export type OnWidthResize = (
7
+ // Newly calculated width
8
+ width: number,
9
+ // Origin of the resize - left or right of the box
10
+ origin: WidthResizeOrigin,
11
+ // Total delta of the resize (the sum of all deltas before end event)
12
+ totalDelta: number,
13
+ // Current delta of the resize (the delta of the current event)
14
+ currentDelta: number,
15
+ // Whether the resize is at the limit of the box, this includes min-content, max-content, and min-width/height
16
+ atLimit: boolean
17
+ ) => void;
18
+
19
+ export type OnHeightResize = (
20
+ // Newly calculated height
21
+ height: number,
22
+ // Origin of the resize - top or bottom of the box
23
+ origin: HeightResizeOrigin,
24
+ // Total delta of the resize (the sum of all deltas before end event)
25
+ totalDelta: number,
26
+ // Current delta of the resize (the delta of the current event)
27
+ currentDelta: number,
28
+ // Whether the resize is at the limit of the box, this includes min-content, max-content, and min-width/height
29
+ atLimit: boolean
30
+ ) => void;
31
+
32
+ export interface HorizontalResizeHandleProps {
33
+ targetRef: React.MutableRefObject<HTMLElement | null>;
34
+ handleProps?: HandleProps;
35
+ onWidthResize?: OnWidthResize;
36
+ onWidthResizeEnd?: (width: number, origin: WidthResizeOrigin) => void;
37
+ }
38
+
39
+ export interface VerticalResizeHandleProps {
40
+ targetRef: React.MutableRefObject<HTMLElement | null>;
41
+ handleProps?: HandleProps;
42
+ onHeightResize?: OnHeightResize;
43
+ onHeightResizeEnd?: (height: number, origin: HeightResizeOrigin) => void;
44
+ }
@@ -32,9 +32,9 @@ export const HCollapsibleBox = React.forwardRef(function CollapsibleBox(
32
32
  data-is-collapsed={!open}
33
33
  data-collapse-orientation="horizontal"
34
34
  data-is-resizing={resizing}
35
- onWidthResize={(width, origin, delta) => {
35
+ onWidthResize={(...args) => {
36
36
  setIsResizing(true);
37
- props.onWidthResize?.(width, origin, delta);
37
+ props.onWidthResize?.(...args);
38
38
  }}
39
39
  onWidthResizeEnd={(width, origin) => {
40
40
  setIsResizing(false);
@@ -1,4 +1,5 @@
1
1
  export * from './box/box.js';
2
+ export * from './box/types.js';
2
3
  export * from './types/alignment.js';
3
4
  export * from './types/as.js';
4
5
  export * from './types/common.js';
@@ -32,9 +32,9 @@ export const VCollapsibleBox = React.forwardRef(function CollapsibleBox(
32
32
  data-is-collapsed={!open}
33
33
  data-collapse-orientation="vertical"
34
34
  data-is-resizing={resizing}
35
- onHeightResize={(height, origin, delta) => {
35
+ onHeightResize={(...args) => {
36
36
  setIsResizing(true);
37
- props.onHeightResize?.(height, origin, delta);
37
+ props.onHeightResize?.(...args);
38
38
  }}
39
39
  onHeightResizeEnd={(height, origin) => {
40
40
  setIsResizing(false);
@@ -1,12 +1,12 @@
1
1
  import { clsx } from 'clsx';
2
2
  import React from 'react';
3
- import { Frame, type FrameOwnProps } from '../../overlay/frame/frame.js';
4
- import { Scaffold, type ScaffoldProps } from '../../layouts/scaffold/scaffold.js';
3
+ import { Frame, type FrameProps } from '../../overlay/frame/frame.js';
4
+ import { Scaffold } from '../../layouts/scaffold/scaffold.js';
5
5
 
6
6
  // Styles
7
7
  import styles from './modal.module.css';
8
8
 
9
- export type ModalProps = FrameOwnProps & ScaffoldProps;
9
+ export type ModalProps = FrameProps;
10
10
 
11
11
  export const Modal = React.forwardRef<HTMLElement, ModalProps>(function Modal(
12
12
  { children, className, isOpen, draggable = false, veil = true, ...props }: ModalProps,
@@ -14,12 +14,14 @@ export const Modal = React.forwardRef<HTMLElement, ModalProps>(function Modal(
14
14
  ) {
15
15
  return (
16
16
  <Frame
17
+ ref={ref}
17
18
  isOpen={isOpen}
18
19
  draggable={draggable}
19
20
  veil={veil}
20
21
  className={clsx(styles['modal'], 'tcn-surface', 'tcn-modal', className)}
22
+ {...props}
21
23
  >
22
- <Scaffold ref={ref} {...props}>
24
+ <Scaffold className={'tcn-modal-scaffold'} width="100%" height="100%">
23
25
  {children}
24
26
  </Scaffold>
25
27
  </Frame>
@@ -25,7 +25,15 @@ export const WindowStory = () => {
25
25
  return (
26
26
  <ZStack height="100%" width="100%" minHeight="600px">
27
27
  <Button onClick={toggle}>{isOpen ? 'Close' : 'Open'}</Button>
28
- <Window isOpen={isOpen} width="400px" height="500px">
28
+ <Window
29
+ isOpen={isOpen}
30
+ width="400px"
31
+ height="500px"
32
+ minWidth="min-content"
33
+ minHeight="300px"
34
+ maxWidth="600px"
35
+ maxHeight="600px"
36
+ >
29
37
  <DragHandle>
30
38
  <Header>
31
39
  <Title>Window Title</Title>
@@ -1,15 +1,25 @@
1
1
  import { clsx } from 'clsx';
2
2
  import React from 'react';
3
- import { Frame, type FrameOwnProps } from '../../overlay/frame/frame.js';
4
- import { Scaffold, type ScaffoldProps } from '../../layouts/scaffold/scaffold.js';
3
+ import { Frame, type FrameProps } from '../../overlay/frame/frame.js';
4
+ import { Scaffold } from '../../layouts/scaffold/scaffold.js';
5
5
 
6
6
  // Styles
7
7
  import styles from './window.module.css';
8
8
 
9
- export type WindowProps = FrameOwnProps & ScaffoldProps;
9
+ export type WindowProps = FrameProps;
10
10
 
11
11
  export const Window = React.forwardRef<HTMLElement, WindowProps>(function Window(
12
- { children, className, isOpen, draggable = true, veil = false, ...props }: WindowProps,
12
+ {
13
+ children,
14
+ className,
15
+ isOpen,
16
+ draggable = true,
17
+ resizable = true,
18
+ veil = false,
19
+ width,
20
+ height,
21
+ ...props
22
+ }: WindowProps,
13
23
  ref
14
24
  ) {
15
25
  return (
@@ -18,10 +28,12 @@ export const Window = React.forwardRef<HTMLElement, WindowProps>(function Window
18
28
  draggable={draggable}
19
29
  veil={veil}
20
30
  className={clsx(styles['window'], 'tcn-surface', 'tcn-window', className)}
21
- width="auto"
22
- height="auto"
31
+ width={width}
32
+ height={height}
33
+ ref={ref}
34
+ {...props}
23
35
  >
24
- <Scaffold ref={ref} {...props}>
36
+ <Scaffold width="100%" height="100%" className={'tcn-window-scaffold'}>
25
37
  {children}
26
38
  </Scaffold>
27
39
  </Frame>
@@ -30,7 +30,7 @@ export function ControlsFieldSet() {
30
30
  const [datePickerValueWithTime, setDatePickerValueWithTime] = useState<Date | null>(
31
31
  null
32
32
  );
33
- const [phoneNumberValue, setPhoneNumberValue] = useState<string>('');
33
+ const [phoneNumberValue, setPhoneNumberValue] = useState<string | undefined>(undefined);
34
34
 
35
35
  // Additional input state
36
36
  const [checkboxValue, setCheckboxValue] = useState<boolean>(false);
@@ -81,7 +81,8 @@
81
81
  mark,
82
82
  audio,
83
83
  button,
84
- video {
84
+ video,
85
+ dialog {
85
86
  margin: 0;
86
87
  padding: 0;
87
88
  border: 0;
@@ -134,4 +135,10 @@
134
135
  font: inherit;
135
136
  color: inherit;
136
137
  }
138
+ dialog {
139
+ max-width: none;
140
+ max-height: none;
141
+ background: transparent;
142
+ color: inherit;
143
+ }
137
144
  }