@tcn/ui 0.1.1 → 0.2.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.
- package/README.md +38 -3
- package/dist/draggable.css +1 -0
- package/dist/feedback/progress/progress_bar.js +1 -1
- package/dist/form/field/common/field_description.js +1 -1
- package/dist/form/field/common/field_error.js +1 -1
- package/dist/form/field/common/field_label.js +1 -1
- package/dist/inputs/date_picker/date_picker_date.js +1 -1
- package/dist/inputs/date_picker/date_picker_day.js +1 -1
- package/dist/inputs/date_picker/date_picker_time_selector.js +1 -1
- package/dist/inputs/date_picker/date_picker_year_selector.js +1 -1
- package/dist/inputs/phone_number_input/phone_number_input.d.ts +2 -0
- package/dist/inputs/phone_number_input/phone_number_input.d.ts.map +1 -1
- package/dist/inputs/phone_number_input/phone_number_input.js +159 -153
- package/dist/inputs/phone_number_input/phone_number_input.js.map +1 -1
- package/dist/inputs/suggestions/suggestion_list.js +1 -1
- package/dist/inputs/textarea/textarea.d.ts +2 -2
- package/dist/inputs/textarea/textarea.d.ts.map +1 -1
- package/dist/inputs/textarea/textarea.js.map +1 -1
- package/dist/layouts/header/header.d.ts.map +1 -1
- package/dist/layouts/header/header.js.map +1 -1
- package/dist/overlay/frame/frame.d.ts +11 -0
- package/dist/overlay/frame/frame.d.ts.map +1 -0
- package/dist/overlay/frame/frame.js +18 -0
- package/dist/overlay/frame/frame.js.map +1 -0
- package/dist/overlay/index.d.ts +1 -0
- package/dist/overlay/index.d.ts.map +1 -1
- package/dist/overlay/index.js +4 -2
- package/dist/overlay/index.js.map +1 -1
- package/dist/stacks/box/box.d.ts +1 -1
- package/dist/stacks/box/box.d.ts.map +1 -1
- package/dist/stacks/box/box.js.map +1 -1
- package/dist/surfaces/index.d.ts +2 -2
- package/dist/surfaces/index.d.ts.map +1 -1
- package/dist/surfaces/index.js +22 -22
- package/dist/surfaces/modal/modal.d.ts +3 -2
- package/dist/surfaces/modal/modal.d.ts.map +1 -1
- package/dist/surfaces/modal/modal.js +14 -13
- package/dist/surfaces/modal/modal.js.map +1 -1
- package/dist/surfaces/window/window.d.ts +3 -2
- package/dist/surfaces/window/window.d.ts.map +1 -1
- package/dist/surfaces/window/window.js +17 -7
- package/dist/surfaces/window/window.js.map +1 -1
- package/dist/themes/themes/ergo/ergo_theme.js +69 -0
- package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
- package/dist/typography/title/title.d.ts +2 -1
- package/dist/typography/title/title.d.ts.map +1 -1
- package/dist/typography/title/title.js +23 -22
- package/dist/typography/title/title.js.map +1 -1
- package/dist/utils/dnd/context.d.ts +4 -0
- package/dist/utils/dnd/context.d.ts.map +1 -0
- package/dist/utils/dnd/context.js +20 -0
- package/dist/utils/dnd/context.js.map +1 -0
- package/dist/utils/dnd/draggable/draggable.d.ts +7 -0
- package/dist/utils/dnd/draggable/draggable.d.ts.map +1 -0
- package/dist/utils/dnd/draggable/draggable.js +27 -0
- package/dist/utils/dnd/draggable/draggable.js.map +1 -0
- package/dist/utils/dnd/handle.d.ts +6 -0
- package/dist/utils/dnd/handle.d.ts.map +1 -0
- package/dist/utils/dnd/handle.js +22 -0
- package/dist/utils/dnd/handle.js.map +1 -0
- package/dist/utils/dnd/hooks/use_drag_container.d.ts +7 -0
- package/dist/utils/dnd/hooks/use_drag_container.d.ts.map +1 -0
- package/dist/utils/dnd/hooks/use_drag_container.js +30 -0
- package/dist/utils/dnd/hooks/use_drag_container.js.map +1 -0
- package/dist/utils/{hooks → dnd/hooks}/use_draggable.d.ts +3 -3
- package/dist/utils/dnd/hooks/use_draggable.d.ts.map +1 -0
- package/dist/utils/dnd/hooks/use_draggable.js +41 -0
- package/dist/utils/dnd/hooks/use_draggable.js.map +1 -0
- package/dist/utils/dnd/types.d.ts +10 -0
- package/dist/utils/dnd/types.d.ts.map +1 -0
- package/dist/utils/dnd/types.js +2 -0
- package/dist/utils/dnd/types.js.map +1 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/package.json +9 -3
- package/src/inputs/phone_number_input/phone_number_input.tsx +8 -0
- package/src/inputs/textarea/textarea.tsx +2 -2
- package/src/layouts/header/header.tsx +0 -1
- package/src/overlay/frame/frame.stories.tsx +40 -0
- package/src/overlay/frame/frame.tsx +34 -0
- package/src/overlay/frame/frame_stories.module.css +14 -0
- package/src/overlay/index.ts +1 -0
- package/src/stacks/box/box.tsx +8 -2
- package/src/surfaces/index.ts +2 -2
- package/src/surfaces/modal/__stories__/modal.stories.tsx +19 -27
- package/src/surfaces/modal/modal.tsx +13 -10
- package/src/surfaces/window/window.stories.tsx +37 -4
- package/src/surfaces/window/window.tsx +14 -6
- package/src/themes/themes/ergo/ergo_theme.css +69 -0
- package/src/typography/title/title.tsx +22 -18
- package/src/utils/dnd/__stories__/draggable.stories.tsx +48 -0
- package/src/utils/dnd/__stories__/draggable_stories.module.css +21 -0
- package/src/utils/{__stories__ → dnd/__stories__}/use_draggable.stories.tsx +15 -10
- package/src/utils/dnd/context.ts +24 -0
- package/src/utils/dnd/draggable/draggable.module.css +8 -0
- package/src/utils/dnd/draggable/draggable.tsx +42 -0
- package/src/utils/dnd/handle.tsx +32 -0
- package/src/utils/dnd/hooks/use_drag_container.ts +42 -0
- package/src/utils/{hooks → dnd/hooks}/use_draggable.ts +23 -17
- package/src/utils/dnd/types.ts +6 -0
- package/src/utils/index.ts +1 -1
- package/dist/title.module-B16de2jd.js +0 -5
- package/dist/title.module-B16de2jd.js.map +0 -1
- package/dist/utils/hooks/use_draggable.d.ts.map +0 -1
- package/dist/utils/hooks/use_draggable.js +0 -30
- package/dist/utils/hooks/use_draggable.js.map +0 -1
|
@@ -118,6 +118,8 @@ function getCountryCodeFromValue(
|
|
|
118
118
|
export interface PhoneNumberInputProps
|
|
119
119
|
extends Omit<HStackProps, 'onChange' | 'children'> {
|
|
120
120
|
value?: string;
|
|
121
|
+
name?: string;
|
|
122
|
+
autoComplete?: string;
|
|
121
123
|
defaultCountry?: string;
|
|
122
124
|
/**
|
|
123
125
|
* Callback fired when the phone number value changes.
|
|
@@ -135,6 +137,8 @@ export interface PhoneNumberInputProps
|
|
|
135
137
|
export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
|
|
136
138
|
{
|
|
137
139
|
value = '',
|
|
140
|
+
name,
|
|
141
|
+
autoComplete,
|
|
138
142
|
defaultCountry = 'US',
|
|
139
143
|
onChange,
|
|
140
144
|
countrySelectRef: countryRef,
|
|
@@ -345,6 +349,8 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
|
|
|
345
349
|
{obfuscateValue ? (
|
|
346
350
|
<MaskInput
|
|
347
351
|
key="obfuscated"
|
|
352
|
+
name={name}
|
|
353
|
+
autoComplete={autoComplete}
|
|
348
354
|
ref={forkedInputRef}
|
|
349
355
|
value=""
|
|
350
356
|
mask={createObfuscatedMasks(currentMasks)}
|
|
@@ -365,6 +371,8 @@ export const PhoneNumberInput = React.forwardRef(function PhoneNumberInput(
|
|
|
365
371
|
) : (
|
|
366
372
|
<MaskInput
|
|
367
373
|
key="normal"
|
|
374
|
+
name={name}
|
|
375
|
+
autoComplete={autoComplete}
|
|
368
376
|
ref={forkedInputRef}
|
|
369
377
|
value={phoneNumber}
|
|
370
378
|
mask={currentMasks}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { TextareaHTMLAttributes } from 'react';
|
|
4
4
|
import styles from './textarea.module.css';
|
|
5
5
|
|
|
6
6
|
export interface TextareaProps
|
|
7
|
-
extends Omit<
|
|
7
|
+
extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange'> {
|
|
8
8
|
value?: string;
|
|
9
9
|
width?: string;
|
|
10
10
|
height?: string;
|
|
@@ -4,7 +4,6 @@ import { HStack, type HStackProps } from '../../stacks/h_stack.js';
|
|
|
4
4
|
import type { Hierarchy, Size } from '../../utils/index.js';
|
|
5
5
|
import styles from './header.module.css';
|
|
6
6
|
|
|
7
|
-
// UtilityBar
|
|
8
7
|
export interface HeaderProps extends Omit<HStackProps, 'as'> {
|
|
9
8
|
hierarchy?: Hierarchy;
|
|
10
9
|
size?: Size;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ZStack } from '../../stacks/z_stack.js';
|
|
2
|
+
import { Frame, type FrameOwnProps } from './frame.js';
|
|
3
|
+
import { DragHandle } from '../../utils/dnd/handle.js';
|
|
4
|
+
import { Title } from '../../typography/title/title.js';
|
|
5
|
+
import { BodyText } from '../../typography/index.js';
|
|
6
|
+
import { Header } from '../../layouts/index.js';
|
|
7
|
+
import styles from './frame_stories.module.css';
|
|
8
|
+
export default {
|
|
9
|
+
title: 'Overlay/Floating/Frame',
|
|
10
|
+
component: Frame,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
|
|
13
|
+
args: {
|
|
14
|
+
isOpen: true,
|
|
15
|
+
draggable: true,
|
|
16
|
+
veil: false,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const FrameStory = (args: Omit<FrameOwnProps, 'children'>) => {
|
|
21
|
+
return (
|
|
22
|
+
<ZStack height="100%" width="100%" minHeight="600px">
|
|
23
|
+
<Frame
|
|
24
|
+
width="300px"
|
|
25
|
+
height="300px"
|
|
26
|
+
className={styles['sb-frame-container']}
|
|
27
|
+
{...args}
|
|
28
|
+
>
|
|
29
|
+
<Header className={styles['sb-frame-header']}>
|
|
30
|
+
<Title> This is a frame</Title>
|
|
31
|
+
</Header>
|
|
32
|
+
<DragHandle>
|
|
33
|
+
<Header className={styles['sb-frame-header']}>
|
|
34
|
+
<BodyText> You can drag here.</BodyText>
|
|
35
|
+
</Header>
|
|
36
|
+
</DragHandle>
|
|
37
|
+
</Frame>
|
|
38
|
+
</ZStack>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ZStack, type ZStackProps } from '../../stacks/index.js';
|
|
3
|
+
import { Portal } from '../portal/portal.js';
|
|
4
|
+
import { Draggable } from '../../utils/dnd/draggable/draggable.js';
|
|
5
|
+
|
|
6
|
+
export interface FrameOwnProps {
|
|
7
|
+
isOpen?: boolean;
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
draggable?: boolean;
|
|
10
|
+
veil?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type FrameProps = ZStackProps & FrameOwnProps;
|
|
14
|
+
|
|
15
|
+
export const Frame = React.forwardRef<HTMLDialogElement, FrameProps>(function Frame(
|
|
16
|
+
{ children, isOpen = false, draggable = true, veil = false, ...rest }: FrameProps,
|
|
17
|
+
ref
|
|
18
|
+
) {
|
|
19
|
+
if (!isOpen) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Portal>
|
|
25
|
+
<ZStack width="100%" height="100%" data-is-veil={veil} className="tcn-frame">
|
|
26
|
+
<Draggable draggable={draggable}>
|
|
27
|
+
<ZStack ref={ref} {...rest}>
|
|
28
|
+
{children}
|
|
29
|
+
</ZStack>
|
|
30
|
+
</Draggable>
|
|
31
|
+
</ZStack>
|
|
32
|
+
</Portal>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
.sb-frame-header {
|
|
2
|
+
background: var(--accent-color);
|
|
3
|
+
color: white;
|
|
4
|
+
font-weight: bold;
|
|
5
|
+
border: 2px solid black;
|
|
6
|
+
padding: var(--padding-medium);
|
|
7
|
+
border-radius: var(--shape-radius-medium);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.sb-frame-container {
|
|
11
|
+
background: #f7e9fe;
|
|
12
|
+
padding: var(--padding-medium);
|
|
13
|
+
border-radius: var(--shape-radius-large);
|
|
14
|
+
}
|
package/src/overlay/index.ts
CHANGED
package/src/stacks/box/box.tsx
CHANGED
|
@@ -45,8 +45,14 @@ export interface BoxProps extends HTMLAttributes<HTMLElement> {
|
|
|
45
45
|
enableResizeOnRight?: boolean;
|
|
46
46
|
horizontalHandleProps?: HandleProps;
|
|
47
47
|
verticalHandleProps?: HandleProps;
|
|
48
|
-
onWidthResize?: (
|
|
49
|
-
|
|
48
|
+
onWidthResize?: (
|
|
49
|
+
width: number
|
|
50
|
+
// origin: 'left' | 'right'
|
|
51
|
+
) => void;
|
|
52
|
+
onHeightResize?: (
|
|
53
|
+
height: number
|
|
54
|
+
// origin: 'top' | 'bottom'
|
|
55
|
+
) => void;
|
|
50
56
|
onWidthResizeEnd?: (width: number) => void;
|
|
51
57
|
onHeightResizeEnd?: (width: number) => void;
|
|
52
58
|
}
|
package/src/surfaces/index.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export * from './alert/alert.js';
|
|
2
2
|
export * from './card/card.js';
|
|
3
3
|
export * from './confirm/confirm.js';
|
|
4
|
-
export * from './modal/modal.js';
|
|
5
4
|
export * from './page/h_page.js';
|
|
6
5
|
export * from './page/v_page.js';
|
|
7
6
|
export * from './panel/h_panel.js';
|
|
8
7
|
export * from './panel/v_panel.js';
|
|
9
8
|
export * from './popover/popover.js';
|
|
10
|
-
export * from './window/window.js';
|
|
11
9
|
export * from './drawers/drawer_bottom/drawer_bottom.js';
|
|
12
10
|
export * from './drawers/drawer_top/drawer_top.js';
|
|
13
11
|
export * from './drawers/drawer_start/drawer_start.js';
|
|
14
12
|
export * from './drawers/drawer_end/drawer_end.js';
|
|
13
|
+
export { Window, type WindowProps } from './window/window.js';
|
|
14
|
+
export { Modal, type ModalProps } from './modal/modal.js';
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import { Button, SlimButton } from '../../../actions/index.js';
|
|
3
3
|
import { Footer, Header, VBody } from '../../../layouts/index.js';
|
|
4
|
-
import { Portal } from '../../../overlay/index.js';
|
|
5
4
|
import { ZStack } from '../../../stacks/z_stack.js';
|
|
6
5
|
import { BodyText, Title } from '../../../typography/index.js';
|
|
7
6
|
import { Modal } from '../modal.js';
|
|
8
|
-
import { ClickAwayListener } from '../../../utils/index.js';
|
|
9
7
|
import { Spacer } from '../../../stacks/index.js';
|
|
10
8
|
import { CrossIcon } from '@tcn/icons/cross_icon.js';
|
|
11
9
|
|
|
@@ -21,34 +19,28 @@ export const ModalStory = () => {
|
|
|
21
19
|
function toggle() {
|
|
22
20
|
setIsOpen(!isOpen);
|
|
23
21
|
}
|
|
22
|
+
|
|
24
23
|
return (
|
|
25
24
|
<ZStack height="100%" width="100%" minHeight="600px">
|
|
26
25
|
<button onClick={toggle}>{isOpen ? 'Close' : 'Open'}</button>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<Button hierarchy="primary">Save</Button>
|
|
46
|
-
</Footer>
|
|
47
|
-
</Modal>
|
|
48
|
-
</ClickAwayListener>
|
|
49
|
-
</ZStack>
|
|
50
|
-
</Portal>
|
|
51
|
-
)}
|
|
26
|
+
|
|
27
|
+
<Modal isOpen={isOpen} width="400px" height="500px">
|
|
28
|
+
<Header>
|
|
29
|
+
<Title>Modal Title</Title>
|
|
30
|
+
<Spacer />
|
|
31
|
+
<SlimButton hierarchy="tertiary" size="md" onClick={toggle}>
|
|
32
|
+
<CrossIcon />
|
|
33
|
+
</SlimButton>
|
|
34
|
+
</Header>
|
|
35
|
+
<VBody>
|
|
36
|
+
<BodyText>This is a modal</BodyText>
|
|
37
|
+
</VBody>
|
|
38
|
+
<Footer>
|
|
39
|
+
<Spacer />
|
|
40
|
+
<Button hierarchy="secondary">Cancel</Button>
|
|
41
|
+
<Button hierarchy="primary">Save</Button>
|
|
42
|
+
</Footer>
|
|
43
|
+
</Modal>
|
|
52
44
|
</ZStack>
|
|
53
45
|
);
|
|
54
46
|
};
|
|
@@ -2,21 +2,24 @@ import { VStack, type VStackProps } from '../../stacks/v_stack.js';
|
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import styles from './modal.module.css';
|
|
5
|
+
import { Frame, type FrameOwnProps } from '../../overlay/frame/frame.js';
|
|
5
6
|
|
|
6
|
-
export type ModalProps = Omit<VStackProps<HTMLDialogElement>, 'as'>;
|
|
7
|
+
export type ModalProps = FrameOwnProps & Omit<VStackProps<HTMLDialogElement>, 'as'>;
|
|
7
8
|
|
|
8
9
|
export const Modal = React.forwardRef<HTMLDialogElement, ModalProps>(function Modal(
|
|
9
|
-
{ children, className, ...props }: ModalProps,
|
|
10
|
+
{ children, className, isOpen, draggable = false, veil = true, ...props }: ModalProps,
|
|
10
11
|
ref
|
|
11
12
|
) {
|
|
12
13
|
return (
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
<Frame isOpen={isOpen} draggable={draggable} veil={veil}>
|
|
15
|
+
<VStack
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={clsx(styles['modal'], 'tcn-modal', className)}
|
|
18
|
+
as="dialog"
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</VStack>
|
|
23
|
+
</Frame>
|
|
21
24
|
);
|
|
22
25
|
});
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
1
2
|
import { Window } from './window.js';
|
|
3
|
+
import { Footer, Header, VBody } from '../../layouts/index.js';
|
|
4
|
+
import { BodyText, Title } from '../../typography/index.js';
|
|
5
|
+
import { Spacer } from '../../stacks/spacer.js';
|
|
6
|
+
import { Button, SlimButton } from '../../actions/index.js';
|
|
7
|
+
import { CrossIcon } from '@tcn/icons/cross_icon.js';
|
|
8
|
+
import { ZStack } from '../../stacks/z_stack.js';
|
|
9
|
+
import { DragHandle } from '../../utils/dnd/handle.js';
|
|
2
10
|
|
|
3
11
|
export default {
|
|
4
12
|
title: 'Surfaces/Window',
|
|
@@ -6,10 +14,35 @@ export default {
|
|
|
6
14
|
tags: ['autodocs'],
|
|
7
15
|
};
|
|
8
16
|
|
|
9
|
-
export const
|
|
17
|
+
export const WindowStory = () => {
|
|
18
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
19
|
+
|
|
20
|
+
function toggle() {
|
|
21
|
+
setIsOpen(!isOpen);
|
|
22
|
+
}
|
|
23
|
+
|
|
10
24
|
return (
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
<ZStack height="100%" width="100%" minHeight="600px">
|
|
26
|
+
<button onClick={toggle}>{isOpen ? 'Close' : 'Open'}</button>
|
|
27
|
+
<Window isOpen={isOpen} width="400px" height="500px">
|
|
28
|
+
<DragHandle>
|
|
29
|
+
<Header>
|
|
30
|
+
<Title>Window Title</Title>
|
|
31
|
+
<Spacer />
|
|
32
|
+
<SlimButton hierarchy="tertiary" size="md" onClick={toggle}>
|
|
33
|
+
<CrossIcon />
|
|
34
|
+
</SlimButton>
|
|
35
|
+
</Header>
|
|
36
|
+
</DragHandle>
|
|
37
|
+
<VBody>
|
|
38
|
+
<BodyText>This is a window</BodyText>
|
|
39
|
+
</VBody>
|
|
40
|
+
<Footer>
|
|
41
|
+
<Spacer />
|
|
42
|
+
<Button hierarchy="secondary">Cancel</Button>
|
|
43
|
+
<Button hierarchy="primary">Save</Button>
|
|
44
|
+
</Footer>
|
|
45
|
+
</Window>
|
|
46
|
+
</ZStack>
|
|
14
47
|
);
|
|
15
48
|
};
|
|
@@ -2,16 +2,24 @@ import { VStack, type VStackProps } from '../../stacks/v_stack.js';
|
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import styles from './window.module.css';
|
|
5
|
+
import { Frame, type FrameOwnProps } from '../../overlay/frame/frame.js';
|
|
5
6
|
|
|
6
|
-
export type WindowProps = Omit<VStackProps
|
|
7
|
+
export type WindowProps = FrameOwnProps & Omit<VStackProps<HTMLDialogElement>, 'as'>;
|
|
7
8
|
|
|
8
|
-
export const Window = React.forwardRef<
|
|
9
|
-
{ children, className, ...props }: WindowProps,
|
|
9
|
+
export const Window = React.forwardRef<HTMLDialogElement, WindowProps>(function Window(
|
|
10
|
+
{ children, className, isOpen, draggable = true, veil = false, ...props }: WindowProps,
|
|
10
11
|
ref
|
|
11
12
|
) {
|
|
12
13
|
return (
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
<Frame isOpen={isOpen} draggable={draggable} veil={veil}>
|
|
15
|
+
<VStack
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={clsx(styles['window'], 'tcn-window', className)}
|
|
18
|
+
as="dialog"
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</VStack>
|
|
23
|
+
</Frame>
|
|
16
24
|
);
|
|
17
25
|
});
|
|
@@ -445,6 +445,16 @@ legend {
|
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
/* ===== SURFACES ===== */
|
|
448
|
+
.tcn-draggable[data-is-draggable="true"] {
|
|
449
|
+
.tcn-drag-handle {
|
|
450
|
+
cursor: move;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.tcn-frame[data-is-veil="true"] {
|
|
455
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
456
|
+
}
|
|
457
|
+
|
|
448
458
|
.tcn-list {
|
|
449
459
|
gap: var(--gap-medium);
|
|
450
460
|
.tcn-item {
|
|
@@ -518,6 +528,65 @@ legend {
|
|
|
518
528
|
}
|
|
519
529
|
}
|
|
520
530
|
|
|
531
|
+
/* WINDOW: */
|
|
532
|
+
.tcn-window {
|
|
533
|
+
--v-inset: var(--padding-large);
|
|
534
|
+
background-color: var(--background-color-primary);
|
|
535
|
+
border-radius: var(--shape-radius-medium);
|
|
536
|
+
/* TODO: This should be a variable */
|
|
537
|
+
border: 1px solid rgba(170, 170, 170, 1);
|
|
538
|
+
overflow: hidden;
|
|
539
|
+
|
|
540
|
+
:where(.tcn-typography) {
|
|
541
|
+
color: inherit;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
:where(.tcn-header) {
|
|
545
|
+
--material: var(--material-secondary-dark);
|
|
546
|
+
--on-material: 0, 0%, 100%;
|
|
547
|
+
--action: var(--material-tan);
|
|
548
|
+
--on-action: 0, 0%, 100%;
|
|
549
|
+
background-color: hsl(var(--material));
|
|
550
|
+
color: hsl(var(--on-material));
|
|
551
|
+
min-height: 40px;
|
|
552
|
+
padding: 0 var(--v-inset);
|
|
553
|
+
gap: var(--gap-medium);
|
|
554
|
+
|
|
555
|
+
:where(.tcn-divider) {
|
|
556
|
+
padding: 4px 0;
|
|
557
|
+
:where(.tcn-divider-line) {
|
|
558
|
+
width: 1.5px;
|
|
559
|
+
min-height: 18px;
|
|
560
|
+
height: auto;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
:where(.tcn-utility-bar) {
|
|
566
|
+
min-height: 32px;
|
|
567
|
+
border-bottom: 1px solid var(--foreground-color-primary);
|
|
568
|
+
padding: 0 var(--v-inset);
|
|
569
|
+
|
|
570
|
+
:where(.tcn-button) {
|
|
571
|
+
padding: 0;
|
|
572
|
+
min-width: 18px;
|
|
573
|
+
min-height: 18px;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
:where(.tcn-body) {
|
|
578
|
+
padding: 0 var(--v-inset);
|
|
579
|
+
gap: var(--gap-medium);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
:where(.tcn-footer) {
|
|
583
|
+
gap: var(--gap-medium);
|
|
584
|
+
min-height: 40px;
|
|
585
|
+
border-top: 1px solid var(--foreground-color-primary);
|
|
586
|
+
padding: 0 var(--v-inset);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
521
590
|
/* PANEL */
|
|
522
591
|
.tcn-panel {
|
|
523
592
|
--v-inset: var(--padding-large);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
3
|
import type { WithDetailedHTMLProps } from '../../stacks/types/as.js';
|
|
4
4
|
import type { Emphasis, Hierarchy, Size } from '../../utils/index.js';
|
|
@@ -21,22 +21,25 @@ export interface TitleOwnProps {
|
|
|
21
21
|
|
|
22
22
|
export type TitleProps = WithDetailedHTMLProps<TitleOwnProps, 'h1' | 'h2' | 'h3'>;
|
|
23
23
|
|
|
24
|
-
export function Title(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
export const Title = forwardRef<HTMLHeadingElement, TitleProps>(function Title(
|
|
25
|
+
{
|
|
26
|
+
size = 'md',
|
|
27
|
+
emphasis = 'normal',
|
|
28
|
+
hierarchy = 'primary',
|
|
29
|
+
color,
|
|
30
|
+
children,
|
|
31
|
+
className,
|
|
32
|
+
style = {},
|
|
33
|
+
padStart,
|
|
34
|
+
padEnd,
|
|
35
|
+
padBottom,
|
|
36
|
+
padTop,
|
|
37
|
+
pad,
|
|
38
|
+
selectable = true,
|
|
39
|
+
as,
|
|
40
|
+
},
|
|
41
|
+
ref
|
|
42
|
+
) {
|
|
40
43
|
let As: React.ElementType = as as React.ElementType;
|
|
41
44
|
|
|
42
45
|
if (as == null) {
|
|
@@ -75,6 +78,7 @@ export function Title({
|
|
|
75
78
|
|
|
76
79
|
return (
|
|
77
80
|
<As
|
|
81
|
+
ref={ref}
|
|
78
82
|
data-hierarchy={hierarchy}
|
|
79
83
|
data-emphasis={emphasis}
|
|
80
84
|
data-selectable={selectable}
|
|
@@ -85,4 +89,4 @@ export function Title({
|
|
|
85
89
|
{children}
|
|
86
90
|
</As>
|
|
87
91
|
);
|
|
88
|
-
}
|
|
92
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Draggable } from '../draggable/draggable.js';
|
|
2
|
+
import { VStack } from '../../../stacks/v_stack.js';
|
|
3
|
+
import { DragHandle } from '../handle.js';
|
|
4
|
+
import { Box } from '../../../stacks/box/box.js';
|
|
5
|
+
import { BodyText } from '../../../typography/index.js';
|
|
6
|
+
import styles from './draggable_stories.module.css';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: 'Utils/Draggable',
|
|
10
|
+
component: Draggable,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const DraggableStory = () => {
|
|
15
|
+
return (
|
|
16
|
+
<VStack minHeight="600px" height="100%" width="100%">
|
|
17
|
+
<Draggable>
|
|
18
|
+
<Box width="400px" height="300px" className={styles['handle-container']}>
|
|
19
|
+
<DragHandle>
|
|
20
|
+
<Box
|
|
21
|
+
className={styles.handle}
|
|
22
|
+
width="100px"
|
|
23
|
+
style={{
|
|
24
|
+
top: 50,
|
|
25
|
+
left: 100,
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
<BodyText>Drag Handle</BodyText>
|
|
29
|
+
</Box>
|
|
30
|
+
</DragHandle>
|
|
31
|
+
|
|
32
|
+
<DragHandle>
|
|
33
|
+
<Box
|
|
34
|
+
className={styles.handle}
|
|
35
|
+
width="150px"
|
|
36
|
+
style={{
|
|
37
|
+
top: 200,
|
|
38
|
+
left: 50,
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
<BodyText>Another Drag Handle</BodyText>
|
|
42
|
+
</Box>
|
|
43
|
+
</DragHandle>
|
|
44
|
+
</Box>
|
|
45
|
+
</Draggable>
|
|
46
|
+
</VStack>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.handle {
|
|
2
|
+
position: relative;
|
|
3
|
+
background: var(--accent-color);
|
|
4
|
+
color: white;
|
|
5
|
+
font-weight: bold;
|
|
6
|
+
border: 2px solid black;
|
|
7
|
+
padding: var(--padding-medium);
|
|
8
|
+
border-radius: var(--shape-radius-medium);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.handle-container {
|
|
12
|
+
background: #f7e9fe;
|
|
13
|
+
padding: var(--padding-medium);
|
|
14
|
+
border-radius: var(--shape-radius-large);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.handle-container[data-is-dragging="true"] {
|
|
18
|
+
box-shadow:
|
|
19
|
+
0 4px 16px 0 rgba(25, 118, 210, 0.2),
|
|
20
|
+
0 1.5px 4px 0 rgba(21, 101, 192, 0.15);
|
|
21
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useState, useRef } from 'react';
|
|
2
2
|
import { useDraggable } from '../hooks/use_draggable';
|
|
3
|
-
import { Box } from '
|
|
3
|
+
import { Box } from '../../../stacks/box/box.js';
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
|
-
title: '
|
|
6
|
+
title: 'Utils/useDraggable',
|
|
7
7
|
component: <></>,
|
|
8
8
|
args: {
|
|
9
9
|
startX: 200,
|
|
@@ -16,8 +16,9 @@ export const BasicDraggable = {
|
|
|
16
16
|
const [position, setPosition] = useState({ x: args.startX, y: args.startY });
|
|
17
17
|
const [isDragging, setIsDragging] = useState(false);
|
|
18
18
|
const elementStartPosition = useRef({ x: args.startX, y: args.startY });
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const dragRef = useRef<HTMLDivElement>(null);
|
|
20
|
+
useDraggable({
|
|
21
|
+
handles: dragRef,
|
|
21
22
|
startDragCallback: () => {
|
|
22
23
|
setIsDragging(true);
|
|
23
24
|
elementStartPosition.current = { x: position.x, y: position.y };
|
|
@@ -76,8 +77,10 @@ export const MultipleDraggables = {
|
|
|
76
77
|
|
|
77
78
|
const createDragHandlers = (
|
|
78
79
|
id: number,
|
|
79
|
-
elementStartPosition: React.RefObject<{ x: number; y: number }
|
|
80
|
+
elementStartPosition: React.RefObject<{ x: number; y: number }>,
|
|
81
|
+
handleRef: React.RefObject<HTMLDivElement>
|
|
80
82
|
) => ({
|
|
83
|
+
handles: handleRef,
|
|
81
84
|
startDragCallback: () => {
|
|
82
85
|
const box = boxes.find(b => b.id === id);
|
|
83
86
|
if (box && elementStartPosition.current) {
|
|
@@ -120,11 +123,12 @@ export const MultipleDraggables = {
|
|
|
120
123
|
</p>
|
|
121
124
|
{boxes.map(box => {
|
|
122
125
|
const elementStartPosition = useRef({ x: box.x, y: box.y });
|
|
123
|
-
const
|
|
126
|
+
const handleRef = useRef<HTMLDivElement>(null);
|
|
127
|
+
useDraggable(createDragHandlers(box.id, elementStartPosition, handleRef));
|
|
124
128
|
return (
|
|
125
129
|
<Box
|
|
126
130
|
key={box.id}
|
|
127
|
-
ref={
|
|
131
|
+
ref={handleRef}
|
|
128
132
|
style={{
|
|
129
133
|
width: '90px',
|
|
130
134
|
height: '100px',
|
|
@@ -155,8 +159,9 @@ export const CustomDragHandle = {
|
|
|
155
159
|
const [position, setPosition] = useState({ x: args.startX, y: args.startY });
|
|
156
160
|
const [isDragging, setIsDragging] = useState(false);
|
|
157
161
|
const elementStartPosition = useRef({ x: args.startX, y: args.startY });
|
|
158
|
-
|
|
159
|
-
|
|
162
|
+
const handleRef = useRef<HTMLDivElement>(null);
|
|
163
|
+
useDraggable({
|
|
164
|
+
handles: handleRef,
|
|
160
165
|
startDragCallback: () => {
|
|
161
166
|
setIsDragging(true);
|
|
162
167
|
elementStartPosition.current = { x: position.x, y: position.y };
|
|
@@ -189,7 +194,7 @@ export const CustomDragHandle = {
|
|
|
189
194
|
}}
|
|
190
195
|
>
|
|
191
196
|
<Box
|
|
192
|
-
ref={
|
|
197
|
+
ref={handleRef}
|
|
193
198
|
style={{
|
|
194
199
|
height: '30px',
|
|
195
200
|
backgroundColor: '#2196F3',
|