@tcn/ui 0.11.0 → 0.12.1
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.
- package/dist/feedback/index.d.ts +1 -0
- package/dist/feedback/index.d.ts.map +1 -1
- package/dist/feedback/index.js +6 -4
- package/dist/feedback/index.js.map +1 -1
- package/dist/feedback/progress/progress.d.ts +7 -0
- package/dist/feedback/progress/progress.d.ts.map +1 -0
- package/dist/feedback/progress/progress.js +38 -0
- package/dist/feedback/progress/progress.js.map +1 -0
- package/dist/feedback/progress/progress_bar.d.ts +0 -1
- package/dist/feedback/progress/progress_bar.d.ts.map +1 -1
- package/dist/feedback/progress/progress_bar.js +6 -46
- package/dist/feedback/progress/progress_bar.js.map +1 -1
- package/dist/form/field/common/status_input/status_input.js +4 -3
- package/dist/form/field/common/status_input/status_input.js.map +1 -1
- package/dist/inputs/suggestions/suggestion_list.d.ts.map +1 -1
- package/dist/inputs/suggestions/suggestion_list.js +145 -127
- package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
- package/dist/overlay/frame/frame.d.ts.map +1 -1
- package/dist/overlay/frame/frame.js +65 -65
- package/dist/overlay/frame/frame.js.map +1 -1
- package/dist/progress_bar-CPP0Jyv-.js +38 -0
- package/dist/progress_bar-CPP0Jyv-.js.map +1 -0
- package/dist/progress_bar.css +1 -1
- package/dist/stacks/box/bottom_resize_handle.d.ts +2 -8
- package/dist/stacks/box/bottom_resize_handle.d.ts.map +1 -1
- package/dist/stacks/box/bottom_resize_handle.js.map +1 -1
- package/dist/stacks/box/box.d.ts +2 -2
- package/dist/stacks/box/box.d.ts.map +1 -1
- package/dist/stacks/box/box.js.map +1 -1
- package/dist/stacks/box/end_resize_handle.d.ts +2 -8
- package/dist/stacks/box/end_resize_handle.d.ts.map +1 -1
- package/dist/stacks/box/end_resize_handle.js.map +1 -1
- package/dist/stacks/box/left_resize_handle.d.ts +2 -8
- package/dist/stacks/box/left_resize_handle.d.ts.map +1 -1
- package/dist/stacks/box/left_resize_handle.js.map +1 -1
- package/dist/stacks/box/resize_handlers.d.ts +3 -2
- package/dist/stacks/box/resize_handlers.d.ts.map +1 -1
- package/dist/stacks/box/resize_handlers.js +36 -32
- package/dist/stacks/box/resize_handlers.js.map +1 -1
- package/dist/stacks/box/right_resize_handle.d.ts +2 -8
- package/dist/stacks/box/right_resize_handle.d.ts.map +1 -1
- package/dist/stacks/box/right_resize_handle.js.map +1 -1
- package/dist/stacks/box/start_resize_handle.d.ts +2 -8
- package/dist/stacks/box/start_resize_handle.d.ts.map +1 -1
- package/dist/stacks/box/start_resize_handle.js.map +1 -1
- package/dist/stacks/box/top_resize_handle.d.ts +2 -8
- package/dist/stacks/box/top_resize_handle.d.ts.map +1 -1
- package/dist/stacks/box/top_resize_handle.js.map +1 -1
- package/dist/stacks/box/types.d.ts +18 -0
- package/dist/stacks/box/types.d.ts.map +1 -0
- package/dist/stacks/h_collapsible_box.js +25 -25
- package/dist/stacks/h_collapsible_box.js.map +1 -1
- package/dist/stacks/index.d.ts +1 -0
- package/dist/stacks/index.d.ts.map +1 -1
- package/dist/stacks/v_collapsible_box.js +25 -25
- package/dist/stacks/v_collapsible_box.js.map +1 -1
- package/dist/surfaces/modal/modal.d.ts +3 -4
- package/dist/surfaces/modal/modal.d.ts.map +1 -1
- package/dist/surfaces/modal/modal.js +10 -8
- package/dist/surfaces/modal/modal.js.map +1 -1
- package/dist/surfaces/pop_confirm/pop_confirm.d.ts.map +1 -1
- package/dist/surfaces/pop_confirm/pop_confirm.js +18 -12
- package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
- package/dist/surfaces/tooltip/tooltip.d.ts.map +1 -1
- package/dist/surfaces/tooltip/tooltip.js +22 -20
- package/dist/surfaces/tooltip/tooltip.js.map +1 -1
- package/dist/surfaces/window/window.d.ts +3 -4
- package/dist/surfaces/window/window.d.ts.map +1 -1
- package/dist/surfaces/window/window.js +20 -18
- package/dist/surfaces/window/window.js.map +1 -1
- package/dist/themes/themes/ergo/ergo_theme.css +1 -1
- package/dist/themes/themes/ergo/ergo_theme.js +3 -1
- package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
- package/package.json +1 -1
- package/src/feedback/index.ts +1 -0
- package/src/feedback/progress/progress.module.css +5 -0
- package/src/feedback/progress/progress.stories.tsx +48 -0
- package/src/feedback/progress/progress.tsx +39 -0
- package/src/feedback/progress/progress_bar.module.css +4 -28
- package/src/feedback/progress/progress_bar.stories.tsx +1 -1
- package/src/feedback/progress/progress_bar.tsx +14 -26
- package/src/inputs/select/select.stories.tsx +23 -2
- package/src/inputs/suggestions/suggestion_list.tsx +58 -39
- package/src/overlay/frame/frame.tsx +10 -12
- package/src/stacks/box/bottom_resize_handle.tsx +2 -13
- package/src/stacks/box/box.tsx +4 -2
- package/src/stacks/box/end_resize_handle.tsx +3 -13
- package/src/stacks/box/left_resize_handle.tsx +3 -13
- package/src/stacks/box/resize_handlers.ts +22 -18
- package/src/stacks/box/right_resize_handle.tsx +2 -13
- package/src/stacks/box/start_resize_handle.tsx +3 -13
- package/src/stacks/box/top_resize_handle.tsx +3 -12
- package/src/stacks/box/types.ts +44 -0
- package/src/stacks/h_collapsible_box.tsx +2 -2
- package/src/stacks/index.ts +1 -0
- package/src/stacks/v_collapsible_box.tsx +2 -2
- package/src/surfaces/modal/modal.tsx +6 -4
- package/src/surfaces/pop_confirm/pop_confirm.tsx +8 -2
- package/src/surfaces/tooltip/tooltip.tsx +2 -1
- package/src/surfaces/window/window.stories.tsx +9 -1
- package/src/surfaces/window/window.tsx +6 -4
- package/src/themes/themes/ergo/ergo_theme.css +3 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React, { HTMLAttributes } from 'react';
|
|
2
|
+
import { BodyText } from '../../typography/index.js';
|
|
3
|
+
import { HStack } from '../../stacks/h_stack.js';
|
|
4
|
+
import { Spacer } from '../../stacks/spacer.js';
|
|
5
|
+
import { VStack } from '../../stacks/v_stack.js';
|
|
6
|
+
import clsx from 'clsx';
|
|
7
|
+
|
|
8
|
+
import styles from './progress_bar.module.css';
|
|
9
|
+
import { ProgressBar } from './progress_bar.js';
|
|
10
|
+
|
|
11
|
+
export interface ProgressProps extends HTMLAttributes<HTMLDivElement> {
|
|
12
|
+
message: string;
|
|
13
|
+
value: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const Progress = React.forwardRef(function Progress(
|
|
17
|
+
{ message, value, ...props }: ProgressProps,
|
|
18
|
+
ref: React.Ref<HTMLDivElement>
|
|
19
|
+
) {
|
|
20
|
+
const progressPercent = `${(value * 100).toFixed(0)}%`;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<VStack
|
|
24
|
+
ref={ref}
|
|
25
|
+
className={clsx(styles['progress-container'], 'tcn-progress-container')}
|
|
26
|
+
{...props}
|
|
27
|
+
>
|
|
28
|
+
<HStack height="auto" vAlign="end">
|
|
29
|
+
<BodyText>{message}</BodyText>
|
|
30
|
+
<Spacer />
|
|
31
|
+
<Spacer width="8px" />
|
|
32
|
+
<BodyText size="sm" style={{ flexShrink: 0 }}>
|
|
33
|
+
{progressPercent}
|
|
34
|
+
</BodyText>
|
|
35
|
+
</HStack>
|
|
36
|
+
<ProgressBar value={value} />
|
|
37
|
+
</VStack>
|
|
38
|
+
);
|
|
39
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@system {
|
|
1
|
+
@layer tcn-system {
|
|
2
2
|
:root {
|
|
3
3
|
--progress-bar-color: var(--accent-color); /* Default color for progress bar */
|
|
4
4
|
--progress-bar-background: #dadada;
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
:where(.progress-bar-container) {
|
|
8
8
|
width: 100%;
|
|
9
|
+
height: 8px;
|
|
10
|
+
border-radius: 2px;
|
|
11
|
+
overflow: hidden;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
:where(.progress-bar-background) {
|
|
@@ -21,7 +24,6 @@
|
|
|
21
24
|
appearance: none;
|
|
22
25
|
background: transparent;
|
|
23
26
|
user-select: none;
|
|
24
|
-
/* box-shadow: 0 1px 0 0 rgba(222, 222, 222, 0.7), inset 0 1px 0 0 rgba(0, 0, 0, 0.3); */
|
|
25
27
|
overflow: hidden;
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -32,30 +34,4 @@
|
|
|
32
34
|
background-color: var(--progress-bar-color);
|
|
33
35
|
transition: width 200ms ease-out;
|
|
34
36
|
}
|
|
35
|
-
|
|
36
|
-
:where(.progress-bar-fill::before) {
|
|
37
|
-
content: "";
|
|
38
|
-
position: absolute;
|
|
39
|
-
top: 0px;
|
|
40
|
-
left: -20px;
|
|
41
|
-
height: 100%;
|
|
42
|
-
width: calc(100% + 40px);
|
|
43
|
-
background-size: 20px 20px;
|
|
44
|
-
animation: moveStripes 500ms linear infinite;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
:where(.progress-bar-fill[data-finished="true"]::before) {
|
|
48
|
-
animation: none;
|
|
49
|
-
background-image: none;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/* Animation for moving stripes */
|
|
53
|
-
@keyframes moveStripes {
|
|
54
|
-
0% {
|
|
55
|
-
transform: translateX(0);
|
|
56
|
-
}
|
|
57
|
-
100% {
|
|
58
|
-
transform: translateX(20px);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
37
|
}
|
|
@@ -19,7 +19,7 @@ function Base(props: Partial<ProgressBarProps>) {
|
|
|
19
19
|
return () => window.clearTimeout(timer);
|
|
20
20
|
}, [value]);
|
|
21
21
|
|
|
22
|
-
return <Component
|
|
22
|
+
return <Component {...props} value={value} />;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export function ProgressBar() {
|
|
@@ -1,48 +1,36 @@
|
|
|
1
1
|
import React, { HTMLAttributes } from 'react';
|
|
2
|
-
import { BodyText } from '../../typography/index.js';
|
|
3
|
-
import { HStack } from '../../stacks/h_stack.js';
|
|
4
|
-
import { Spacer } from '../../stacks/spacer.js';
|
|
5
|
-
import { VStack } from '../../stacks/v_stack.js';
|
|
6
2
|
import { ZStack } from '../../stacks/z_stack.js';
|
|
7
3
|
import clsx from 'clsx';
|
|
8
4
|
|
|
9
5
|
import styles from './progress_bar.module.css';
|
|
10
6
|
|
|
11
7
|
export interface ProgressBarProps extends HTMLAttributes<HTMLDivElement> {
|
|
12
|
-
message: string;
|
|
13
8
|
value: number;
|
|
14
9
|
}
|
|
15
10
|
|
|
16
11
|
export const ProgressBar = React.forwardRef(function ProgressBar(
|
|
17
|
-
{
|
|
12
|
+
{ value, ...props }: ProgressBarProps,
|
|
18
13
|
ref: React.Ref<HTMLDivElement>
|
|
19
14
|
) {
|
|
20
15
|
const progressPercent = `${(value * 100).toFixed(0)}%`;
|
|
21
16
|
const styleVariables: any = { '--progress-percentage': progressPercent };
|
|
22
17
|
|
|
23
18
|
return (
|
|
24
|
-
<
|
|
19
|
+
<ZStack
|
|
25
20
|
ref={ref}
|
|
26
|
-
|
|
21
|
+
hAlign="start"
|
|
22
|
+
className={clsx(styles['progress-bar-container'], 'tcn-progress-bar-container')}
|
|
27
23
|
{...props}
|
|
28
24
|
>
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
<div
|
|
40
|
-
data-finished={progressPercent === '100%'}
|
|
41
|
-
style={styleVariables}
|
|
42
|
-
className={styles['progress-bar-fill']}
|
|
43
|
-
/>
|
|
44
|
-
<div className={styles['progress-bar']}></div>
|
|
45
|
-
</ZStack>
|
|
46
|
-
</VStack>
|
|
25
|
+
<div
|
|
26
|
+
className={clsx(styles['progress-bar-background'], 'tcn-progress-bar-background')}
|
|
27
|
+
></div>
|
|
28
|
+
<div
|
|
29
|
+
data-finished={progressPercent === '100%'}
|
|
30
|
+
style={styleVariables}
|
|
31
|
+
className={clsx(styles['progress-bar-fill'], 'tcn-progress-bar-fill')}
|
|
32
|
+
/>
|
|
33
|
+
<div className={clsx(styles['progress-bar'], 'tcn-progress-bar')}></div>
|
|
34
|
+
</ZStack>
|
|
47
35
|
);
|
|
48
36
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { Option } from '../options/option.js';
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { Option, type OptionProps } from '../options/option.js';
|
|
3
3
|
import { Select as SelectComponent, SelectProps } from './select.js';
|
|
4
4
|
import { HStack } from '../../stacks/h_stack.js';
|
|
5
5
|
import { VStack } from '../../stacks/v_stack.js';
|
|
@@ -123,6 +123,27 @@ export function CustomWidth(_: Omit<SelectProps, 'children'>) {
|
|
|
123
123
|
);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
export function DelayedOptions() {
|
|
127
|
+
const [value, setValue] = useState<string>('');
|
|
128
|
+
const [options, setOptions] = useState<React.ReactElement<OptionProps>[]>([]);
|
|
129
|
+
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
window.setTimeout(() => {
|
|
132
|
+
setOptions([
|
|
133
|
+
<Option key={1} value="apple" label="Apple" keywords={['fruit', 'red', 'sweet']}>
|
|
134
|
+
Apple
|
|
135
|
+
</Option>,
|
|
136
|
+
]);
|
|
137
|
+
}, 4000);
|
|
138
|
+
}, []);
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<SelectComponent value={value} onChange={setValue} width="100px">
|
|
142
|
+
{options}
|
|
143
|
+
</SelectComponent>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
126
147
|
export function CustomOptions() {
|
|
127
148
|
const [value, setValue] = useState<string>('');
|
|
128
149
|
|
|
@@ -60,9 +60,13 @@ export function SuggestionList({
|
|
|
60
60
|
...props
|
|
61
61
|
}: SuggestionListProps) {
|
|
62
62
|
// Extract valid Option components from children
|
|
63
|
-
const suggestions =
|
|
64
|
-
(
|
|
65
|
-
|
|
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
|
-
() =>
|
|
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
|
-
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
|
|
315
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
package/src/stacks/box/box.tsx
CHANGED
|
@@ -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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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,
|