@tcn/ui 0.11.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 (94) 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/inputs/suggestions/suggestion_list.d.ts.map +1 -1
  16. package/dist/inputs/suggestions/suggestion_list.js +145 -127
  17. package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
  18. package/dist/overlay/frame/frame.d.ts.map +1 -1
  19. package/dist/overlay/frame/frame.js +65 -65
  20. package/dist/overlay/frame/frame.js.map +1 -1
  21. package/dist/progress_bar-CPP0Jyv-.js +38 -0
  22. package/dist/progress_bar-CPP0Jyv-.js.map +1 -0
  23. package/dist/progress_bar.css +1 -1
  24. package/dist/stacks/box/bottom_resize_handle.d.ts +2 -8
  25. package/dist/stacks/box/bottom_resize_handle.d.ts.map +1 -1
  26. package/dist/stacks/box/bottom_resize_handle.js.map +1 -1
  27. package/dist/stacks/box/box.d.ts +2 -2
  28. package/dist/stacks/box/box.d.ts.map +1 -1
  29. package/dist/stacks/box/box.js.map +1 -1
  30. package/dist/stacks/box/end_resize_handle.d.ts +2 -8
  31. package/dist/stacks/box/end_resize_handle.d.ts.map +1 -1
  32. package/dist/stacks/box/end_resize_handle.js.map +1 -1
  33. package/dist/stacks/box/left_resize_handle.d.ts +2 -8
  34. package/dist/stacks/box/left_resize_handle.d.ts.map +1 -1
  35. package/dist/stacks/box/left_resize_handle.js.map +1 -1
  36. package/dist/stacks/box/resize_handlers.d.ts +3 -2
  37. package/dist/stacks/box/resize_handlers.d.ts.map +1 -1
  38. package/dist/stacks/box/resize_handlers.js +36 -32
  39. package/dist/stacks/box/resize_handlers.js.map +1 -1
  40. package/dist/stacks/box/right_resize_handle.d.ts +2 -8
  41. package/dist/stacks/box/right_resize_handle.d.ts.map +1 -1
  42. package/dist/stacks/box/right_resize_handle.js.map +1 -1
  43. package/dist/stacks/box/start_resize_handle.d.ts +2 -8
  44. package/dist/stacks/box/start_resize_handle.d.ts.map +1 -1
  45. package/dist/stacks/box/start_resize_handle.js.map +1 -1
  46. package/dist/stacks/box/top_resize_handle.d.ts +2 -8
  47. package/dist/stacks/box/top_resize_handle.d.ts.map +1 -1
  48. package/dist/stacks/box/top_resize_handle.js.map +1 -1
  49. package/dist/stacks/box/types.d.ts +18 -0
  50. package/dist/stacks/box/types.d.ts.map +1 -0
  51. package/dist/stacks/h_collapsible_box.js +25 -25
  52. package/dist/stacks/h_collapsible_box.js.map +1 -1
  53. package/dist/stacks/index.d.ts +1 -0
  54. package/dist/stacks/index.d.ts.map +1 -1
  55. package/dist/stacks/v_collapsible_box.js +25 -25
  56. package/dist/stacks/v_collapsible_box.js.map +1 -1
  57. package/dist/surfaces/modal/modal.d.ts +3 -4
  58. package/dist/surfaces/modal/modal.d.ts.map +1 -1
  59. package/dist/surfaces/modal/modal.js +10 -8
  60. package/dist/surfaces/modal/modal.js.map +1 -1
  61. package/dist/surfaces/window/window.d.ts +3 -4
  62. package/dist/surfaces/window/window.d.ts.map +1 -1
  63. package/dist/surfaces/window/window.js +20 -18
  64. package/dist/surfaces/window/window.js.map +1 -1
  65. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  66. package/dist/themes/themes/ergo/ergo_theme.js +3 -1
  67. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  68. package/package.json +1 -1
  69. package/src/feedback/index.ts +1 -0
  70. package/src/feedback/progress/progress.module.css +5 -0
  71. package/src/feedback/progress/progress.stories.tsx +48 -0
  72. package/src/feedback/progress/progress.tsx +39 -0
  73. package/src/feedback/progress/progress_bar.module.css +4 -28
  74. package/src/feedback/progress/progress_bar.stories.tsx +1 -1
  75. package/src/feedback/progress/progress_bar.tsx +14 -26
  76. package/src/inputs/select/select.stories.tsx +23 -2
  77. package/src/inputs/suggestions/suggestion_list.tsx +58 -39
  78. package/src/overlay/frame/frame.tsx +10 -12
  79. package/src/stacks/box/bottom_resize_handle.tsx +2 -13
  80. package/src/stacks/box/box.tsx +4 -2
  81. package/src/stacks/box/end_resize_handle.tsx +3 -13
  82. package/src/stacks/box/left_resize_handle.tsx +3 -13
  83. package/src/stacks/box/resize_handlers.ts +22 -18
  84. package/src/stacks/box/right_resize_handle.tsx +2 -13
  85. package/src/stacks/box/start_resize_handle.tsx +3 -13
  86. package/src/stacks/box/top_resize_handle.tsx +3 -12
  87. package/src/stacks/box/types.ts +44 -0
  88. package/src/stacks/h_collapsible_box.tsx +2 -2
  89. package/src/stacks/index.ts +1 -0
  90. package/src/stacks/v_collapsible_box.tsx +2 -2
  91. package/src/surfaces/modal/modal.tsx +6 -4
  92. package/src/surfaces/window/window.stories.tsx +9 -1
  93. package/src/surfaces/window/window.tsx +6 -4
  94. package/src/themes/themes/ergo/ergo_theme.css +3 -1
@@ -60,9 +60,13 @@ export function SuggestionList({
60
60
  ...props
61
61
  }: SuggestionListProps) {
62
62
  // Extract valid Option components from children
63
- const suggestions = Children.toArray(children).filter(
64
- (child): child is React.ReactElement<OptionProps> =>
65
- isValidElement(child) && child.type === Option
63
+ const suggestions = React.useMemo(
64
+ () =>
65
+ Children.toArray(children).filter(
66
+ (child): child is React.ReactElement<OptionProps> =>
67
+ isValidElement(child) && child.type === Option
68
+ ),
69
+ [children]
66
70
  );
67
71
 
68
72
  const [selectedIndex, setSelectedIndex] = useState(() => {
@@ -83,7 +87,7 @@ export function SuggestionList({
83
87
  const internalInputRef = useRef<HTMLInputElement | null>(null);
84
88
  const [totalMatchedLength, setTotalMatchedLength] = useState(suggestions.length);
85
89
  const [matchedOptions, setMatchedOptions] = useState<React.ReactElement<OptionProps>[]>(
86
- () => getMatchedOptions(value, MAX_RESULTS)
90
+ () => []
87
91
  );
88
92
  const [suggestionsWidth, setSuggestionsWidth] = useState<string | undefined>();
89
93
  const [suggestionsHeight, setSuggestionsHeight] = useState<string | undefined>();
@@ -278,42 +282,47 @@ export function SuggestionList({
278
282
  onKeyDown && onKeyDown(event);
279
283
  }
280
284
 
281
- function getMatchedOptions(value: string, maxResults: number) {
282
- const results = suggestions.filter(option => {
283
- const props = option.props;
284
- const label = String(props.label).toLocaleLowerCase();
285
- const keywords = props.keywords?.map(k => k.toLocaleLowerCase()) || [];
286
- const optionValue = String(props.value).toLocaleLowerCase();
287
- const searchValue = value.toLocaleLowerCase();
288
- const obfuscate = props.obfuscate ?? false;
289
-
290
- // Obfuscated options can only be searched by label or keywords, not by value
291
- if (obfuscate) {
292
- return label.includes(searchValue) || keywords.some(k => k.includes(searchValue));
293
- }
285
+ const getMatchedOptions = React.useCallback(
286
+ function getMatchedOptions(value: string, maxResults: number) {
287
+ const results = suggestions.filter(option => {
288
+ const props = option.props;
289
+ const label = String(props.label).toLocaleLowerCase();
290
+ const keywords = props.keywords?.map(k => k.toLocaleLowerCase()) || [];
291
+ const optionValue = String(props.value).toLocaleLowerCase();
292
+ const searchValue = value.toLocaleLowerCase();
293
+ const obfuscate = props.obfuscate ?? false;
294
+
295
+ // Obfuscated options can only be searched by label or keywords, not by value
296
+ if (obfuscate) {
297
+ return (
298
+ label.includes(searchValue) || keywords.some(k => k.includes(searchValue))
299
+ );
300
+ }
294
301
 
295
- return (
296
- label.includes(searchValue) ||
297
- keywords.some(k => k.includes(searchValue)) ||
298
- optionValue.includes(searchValue)
299
- );
300
- });
301
-
302
- if (
303
- haveValueAsOption &&
304
- value.trim().length > 0 &&
305
- !results.some(r => r.props.value === value)
306
- ) {
307
- results.unshift(
308
- <Option key="value" value={value} label={value} keywords={[value]}>
309
- {value}
310
- </Option>
311
- );
312
- }
302
+ return (
303
+ label.includes(searchValue) ||
304
+ keywords.some(k => k.includes(searchValue)) ||
305
+ optionValue.includes(searchValue)
306
+ );
307
+ });
308
+
309
+ if (
310
+ haveValueAsOption &&
311
+ value.trim().length > 0 &&
312
+ !results.some(r => r.props.value === value)
313
+ ) {
314
+ results.unshift(
315
+ <Option key="value" value={value} label={value} keywords={[value]}>
316
+ {value}
317
+ </Option>
318
+ );
319
+ }
313
320
 
314
- setTotalMatchedLength(results.length);
315
- return results.slice(0, maxResults);
316
- }
321
+ setTotalMatchedLength(results.length);
322
+ return results.slice(0, maxResults);
323
+ },
324
+ [suggestions, haveValueAsOption]
325
+ );
317
326
 
318
327
  function focusInput() {
319
328
  const input = internalInputRef.current;
@@ -393,6 +402,11 @@ export function SuggestionList({
393
402
  setInternalValue(searchValue ?? '');
394
403
  }, [searchValue]);
395
404
 
405
+ useLayoutEffect(() => {
406
+ const newMatches = getMatchedOptions(value, MAX_RESULTS);
407
+ setMatchedOptions(newMatches);
408
+ }, [value, getMatchedOptions]);
409
+
396
410
  return (
397
411
  <Popper
398
412
  open={open}
@@ -433,7 +447,12 @@ export function SuggestionList({
433
447
  ))}
434
448
  {totalMatchedLength > matchedOptions.length && (
435
449
  <>
436
- <Button marginBlock="8px" hierarchy="tertiary" onClick={handleShowMore}>
450
+ <Button
451
+ key="show-more"
452
+ marginBlock="8px"
453
+ hierarchy="tertiary"
454
+ onClick={handleShowMore}
455
+ >
437
456
  Show More
438
457
  </Button>
439
458
  </>
@@ -81,12 +81,11 @@ export const FrameDialog = React.forwardRef<HTMLElement, FrameDialogProps>(
81
81
  width: number,
82
82
  origin: 'left' | 'right',
83
83
  totalDelta: number,
84
- currentDelta: number
84
+ currentDelta: number,
85
+ atLimit: boolean
85
86
  ) => {
86
- if (!draggable) {
87
- return;
88
- }
89
- // TODO: add clamp logic
87
+ if (!draggable) return;
88
+ if (atLimit) return;
90
89
  if (origin === 'right') {
91
90
  flushSync(() => {
92
91
  drag.setPosition(prev => ({
@@ -104,7 +103,7 @@ export const FrameDialog = React.forwardRef<HTMLElement, FrameDialogProps>(
104
103
  });
105
104
  }
106
105
 
107
- onWidthResize?.(width, origin, totalDelta, currentDelta);
106
+ onWidthResize?.(width, origin, totalDelta, currentDelta, atLimit);
108
107
  },
109
108
  [onWidthResize, drag, draggable]
110
109
  );
@@ -114,12 +113,11 @@ export const FrameDialog = React.forwardRef<HTMLElement, FrameDialogProps>(
114
113
  height: number,
115
114
  origin: 'top' | 'bottom',
116
115
  totalDelta: number,
117
- currentDelta: number
116
+ currentDelta: number,
117
+ atLimit: boolean
118
118
  ) => {
119
- if (!draggable) {
120
- return;
121
- }
122
- // TODO: add clamp logic
119
+ if (!draggable) return;
120
+ if (atLimit) return;
123
121
  if (origin === 'bottom') {
124
122
  flushSync(() => {
125
123
  drag.setPosition(prev => ({
@@ -136,7 +134,7 @@ export const FrameDialog = React.forwardRef<HTMLElement, FrameDialogProps>(
136
134
  }));
137
135
  });
138
136
  }
139
- onHeightResize?.(height, origin, totalDelta, currentDelta);
137
+ onHeightResize?.(height, origin, totalDelta, currentDelta, atLimit);
140
138
  },
141
139
  [onHeightResize, drag, draggable]
142
140
  );
@@ -1,21 +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?: (
11
- height: number,
12
- origin: 'top' | 'bottom',
13
- totalDelta: number,
14
- currentDelta: number
15
- ) => void;
16
- onHeightResizeEnd?: (height: number, origin: 'top' | 'bottom') => void;
17
- }
18
-
7
+ export type BottomResizeHandleProps = VerticalResizeHandleProps;
19
8
  export function BottomResizeHandle({
20
9
  targetRef,
21
10
  handleProps,
@@ -49,13 +49,15 @@ export interface BoxProps<T extends HTMLElement = HTMLElement> extends HTMLAttri
49
49
  width: number,
50
50
  origin: 'left' | 'right',
51
51
  totalDelta: number,
52
- currentDelta: number
52
+ currentDelta: number,
53
+ atLimit: boolean
53
54
  ) => void;
54
55
  onHeightResize?: (
55
56
  height: number,
56
57
  origin: 'top' | 'bottom',
57
58
  totalDelta: number,
58
- currentDelta: number
59
+ currentDelta: number,
60
+ atLimit: boolean
59
61
  ) => void;
60
62
  onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
61
63
  onHeightResizeEnd?: (height: number, origin: 'top' | 'bottom') => void;
@@ -1,20 +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?: (
11
- width: number,
12
- origin: 'left' | 'right',
13
- totalDelta: number,
14
- currentDelta: number
15
- ) => void;
16
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
17
- }
18
8
  export function EndResizeHandle({
19
9
  targetRef,
20
10
  handleProps,
@@ -1,20 +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?: (
11
- width: number,
12
- origin: 'left' | 'right',
13
- totalDelta: number,
14
- currentDelta: number
15
- ) => void;
16
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
17
- }
18
8
  export function LeftResizeHandle({
19
9
  targetRef,
20
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,14 +16,9 @@ function createVeil() {
9
16
 
10
17
  export function createHorizontalResizeHandler(
11
18
  targetRef: React.MutableRefObject<HTMLElement | null>,
12
- onWidthResize?: (
13
- width: number,
14
- origin: 'left' | 'right',
15
- totalDelta: number,
16
- currentDelta: number
17
- ) => void,
18
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void,
19
- origin: 'left' | 'right' = 'right',
19
+ onWidthResize?: OnWidthResize,
20
+ onWidthResizeEnd?: (width: number, origin: WidthResizeOrigin) => void,
21
+ origin: WidthResizeOrigin = 'right',
20
22
  invert = false,
21
23
  disableDirection = false
22
24
  ) {
@@ -40,6 +42,7 @@ export function createHorizontalResizeHandler(
40
42
  let width = startRect.width;
41
43
 
42
44
  const drag = (event: MouseEvent) => {
45
+ const beforeWidth = box.getBoundingClientRect().width;
43
46
  const totalDelta = direction * (event.clientX - startX);
44
47
  const newWidth = startRect.width + totalDelta;
45
48
  const currentDelta = newWidth - width;
@@ -47,7 +50,10 @@ export function createHorizontalResizeHandler(
47
50
  width = newWidth;
48
51
 
49
52
  box.style.width = `${newWidth}px`;
50
- onWidthResize?.(newWidth, origin, totalDelta, currentDelta);
53
+
54
+ const afterWidth = box.getBoundingClientRect().width;
55
+ const atLimit = afterWidth === beforeWidth;
56
+ onWidthResize?.(newWidth, origin, totalDelta, currentDelta, atLimit);
51
57
  event.stopPropagation();
52
58
  event.preventDefault();
53
59
  };
@@ -80,15 +86,10 @@ export function createHorizontalResizeHandler(
80
86
 
81
87
  export function createVerticalResizeHandler(
82
88
  targetRef: React.MutableRefObject<HTMLElement | null>,
83
- onHeightResize?: (
84
- height: number,
85
- origin: 'top' | 'bottom',
86
- totalDelta: number,
87
- currentDelta: number
88
- ) => void,
89
- onHeightResizeEnd?: (height: number, origin: 'top' | 'bottom') => void,
89
+ onHeightResize?: OnHeightResize,
90
+ onHeightResizeEnd?: (height: number, origin: HeightResizeOrigin) => void,
90
91
  invert = false,
91
- origin: 'top' | 'bottom' = 'bottom'
92
+ origin: HeightResizeOrigin = 'bottom'
92
93
  ) {
93
94
  const direction = invert ? -1 : 1;
94
95
  return function startVerticalResize(event: React.MouseEvent) {
@@ -106,12 +107,15 @@ export function createVerticalResizeHandler(
106
107
  let height = startRect.height;
107
108
 
108
109
  const drag = (event: MouseEvent) => {
110
+ const beforeHeight = box.getBoundingClientRect().height;
109
111
  const totalDelta = direction * (event.clientY - startY);
110
112
  const newHeight = startRect.height + totalDelta;
111
113
  const currentDelta = newHeight - height;
112
114
  height = newHeight;
113
115
  box.style.height = `${newHeight}px`;
114
- onHeightResize?.(newHeight, origin, totalDelta, currentDelta);
116
+ const afterHeight = box.getBoundingClientRect().height;
117
+ const atLimit = afterHeight === beforeHeight;
118
+ onHeightResize?.(newHeight, origin, totalDelta, currentDelta, atLimit);
115
119
  event.stopPropagation();
116
120
  event.preventDefault();
117
121
  };
@@ -1,20 +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?: (
11
- width: number,
12
- origin: 'left' | 'right',
13
- totalDelta: number,
14
- currentDelta: number
15
- ) => void;
16
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
17
- }
6
+ export type RightResizeHandleProps = HorizontalResizeHandleProps;
18
7
  export function RightResizeHandle({
19
8
  targetRef,
20
9
  handleProps,
@@ -1,20 +1,10 @@
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 './start_resize_handle.module.css';
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?: (
11
- width: number,
12
- origin: 'left' | 'right',
13
- totalDelta: number,
14
- currentDelta: number
15
- ) => void;
16
- onWidthResizeEnd?: (width: number, origin: 'left' | 'right') => void;
17
- }
18
8
  export function StartResizeHandle({
19
9
  targetRef,
20
10
  handleProps,
@@ -1,20 +1,11 @@
1
1
  import { clsx } from 'clsx';
2
2
  import React from 'react';
3
- import { HandleProps } from './handle_props.js';
4
3
  import { createVerticalResizeHandler } from './resize_handlers.js';
5
4
  import styles from './top_resize_handle.module.css';
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?: (
11
- height: number,
12
- origin: 'top' | 'bottom',
13
- totalDelta: number,
14
- currentDelta: number
15
- ) => void;
16
- onHeightResizeEnd?: (height: number, origin: 'top' | 'bottom') => void;
17
- }
18
9
  export function TopResizeHandle({
19
10
  targetRef,
20
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, totalDelta, currentDelta) => {
35
+ onWidthResize={(...args) => {
36
36
  setIsResizing(true);
37
- props.onWidthResize?.(width, origin, totalDelta, currentDelta);
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, totalDelta, currentDelta) => {
35
+ onHeightResize={(...args) => {
36
36
  setIsResizing(true);
37
- props.onHeightResize?.(height, origin, totalDelta, currentDelta);
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,12 +1,12 @@
1
1
  import { clsx } from 'clsx';
2
2
  import React from 'react';
3
- import { Scaffold, type ScaffoldProps } from '../../layouts/scaffold/scaffold.js';
4
- import { Frame, type FrameOwnProps } from '../../overlay/frame/frame.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
12
  {
@@ -30,8 +30,10 @@ export const Window = React.forwardRef<HTMLElement, WindowProps>(function Window
30
30
  className={clsx(styles['window'], 'tcn-surface', 'tcn-window', className)}
31
31
  width={width}
32
32
  height={height}
33
+ ref={ref}
34
+ {...props}
33
35
  >
34
- <Scaffold ref={ref} {...props}>
36
+ <Scaffold width="100%" height="100%" className={'tcn-window-scaffold'}>
35
37
  {children}
36
38
  </Scaffold>
37
39
  </Frame>
@@ -686,6 +686,7 @@
686
686
  /* MODAL: */
687
687
  .tcn-modal {
688
688
  --divide-header: 0;
689
+ box-shadow: 0px 4px 34px 0px #00000096;
689
690
 
690
691
  :where(.tcn-scaffold) {
691
692
  border-radius: var(--shape-radius-medium);
@@ -710,10 +711,11 @@
710
711
 
711
712
  /* WINDOW: */
712
713
  .tcn-window {
714
+ box-shadow: 0px 4px 34px 0px #00000096;
715
+
713
716
  --divide-header: 0;
714
717
 
715
718
  :where(.tcn-scaffold) {
716
- box-shadow: 0px 4px 34px 0px #00000096;
717
719
  border-radius: var(--shape-radius-medium);
718
720
  background-color: var(--background-color-primary);
719
721
  overflow: hidden;