@tcn/ui 0.12.4 → 0.12.6

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 (150) hide show
  1. package/dist/inputs/color_input/color_input.js +18 -18
  2. package/dist/inputs/color_input/color_input.js.map +1 -1
  3. package/dist/inputs/control/control.d.ts +10 -0
  4. package/dist/inputs/control/control.d.ts.map +1 -0
  5. package/dist/inputs/control/control.js +17 -0
  6. package/dist/inputs/control/control.js.map +1 -0
  7. package/dist/inputs/control_set/control_set.d.ts +5 -0
  8. package/dist/inputs/control_set/control_set.d.ts.map +1 -0
  9. package/dist/inputs/control_set/control_set.js +20 -0
  10. package/dist/inputs/{input_group/input_group.js.map → control_set/control_set.js.map} +1 -1
  11. package/dist/inputs/date_picker/date_picker_input.js +20 -20
  12. package/dist/inputs/date_picker/date_picker_input.js.map +1 -1
  13. package/dist/inputs/index.d.ts +2 -1
  14. package/dist/inputs/index.d.ts.map +1 -1
  15. package/dist/inputs/index.js +27 -24
  16. package/dist/inputs/index.js.map +1 -1
  17. package/dist/inputs/input/input.js +6 -6
  18. package/dist/inputs/input/input.js.map +1 -1
  19. package/dist/inputs/phone_number_input/phone_number_country_select_adapter.js +15 -15
  20. package/dist/inputs/phone_number_input/phone_number_country_select_adapter.js.map +1 -1
  21. package/dist/inputs/phone_number_input/phone_number_input.js +24 -24
  22. package/dist/inputs/phone_number_input/phone_number_input.js.map +1 -1
  23. package/dist/inputs/phone_number_input/phone_number_input_adapter.js +21 -21
  24. package/dist/inputs/phone_number_input/phone_number_input_adapter.js.map +1 -1
  25. package/dist/inputs/phone_number_input/sip_input.js +14 -14
  26. package/dist/inputs/phone_number_input/sip_input.js.map +1 -1
  27. package/dist/inputs/select/select.js +6 -6
  28. package/dist/inputs/select/select.js.map +1 -1
  29. package/dist/inputs/textarea/textarea.js +8 -8
  30. package/dist/inputs/textarea/textarea.js.map +1 -1
  31. package/dist/inputs/unit_input/unit_input.js +20 -20
  32. package/dist/inputs/unit_input/unit_input.js.map +1 -1
  33. package/dist/overlay/frame/frame.d.ts +2 -2
  34. package/dist/overlay/frame/frame.d.ts.map +1 -1
  35. package/dist/overlay/frame/frame.js +68 -66
  36. package/dist/overlay/frame/frame.js.map +1 -1
  37. package/dist/overlay/slide/slide.d.ts +9 -0
  38. package/dist/overlay/slide/slide.d.ts.map +1 -0
  39. package/dist/overlay/slide/slide.js +29 -0
  40. package/dist/overlay/slide/slide.js.map +1 -0
  41. package/dist/slide.css +1 -0
  42. package/dist/stacks/box/box.d.ts +5 -4
  43. package/dist/stacks/box/box.d.ts.map +1 -1
  44. package/dist/stacks/box/box.js.map +1 -1
  45. package/dist/stacks/box/detect_resize_bounds.d.ts +15 -0
  46. package/dist/stacks/box/detect_resize_bounds.d.ts.map +1 -0
  47. package/dist/stacks/box/detect_resize_bounds.js +49 -0
  48. package/dist/stacks/box/detect_resize_bounds.js.map +1 -0
  49. package/dist/stacks/box/resize_handlers.d.ts.map +1 -1
  50. package/dist/stacks/box/resize_handlers.js +51 -44
  51. package/dist/stacks/box/resize_handlers.js.map +1 -1
  52. package/dist/stacks/box/start_resize_handle.d.ts.map +1 -1
  53. package/dist/stacks/box/start_resize_handle.js +2 -1
  54. package/dist/stacks/box/start_resize_handle.js.map +1 -1
  55. package/dist/stacks/box/types.d.ts +17 -4
  56. package/dist/stacks/box/types.d.ts.map +1 -1
  57. package/dist/surfaces/drawers/drawer.d.ts +5 -0
  58. package/dist/surfaces/drawers/drawer.d.ts.map +1 -0
  59. package/dist/surfaces/drawers/drawer.js +23 -0
  60. package/dist/surfaces/drawers/drawer.js.map +1 -0
  61. package/dist/surfaces/index.d.ts +1 -4
  62. package/dist/surfaces/index.d.ts.map +1 -1
  63. package/dist/surfaces/index.js +20 -26
  64. package/dist/surfaces/index.js.map +1 -1
  65. package/dist/surfaces/modal/modal.d.ts +1 -1
  66. package/dist/surfaces/modal/modal.d.ts.map +1 -1
  67. package/dist/surfaces/modal/modal.js +22 -13
  68. package/dist/surfaces/modal/modal.js.map +1 -1
  69. package/dist/surfaces/window/window.d.ts +1 -1
  70. package/dist/surfaces/window/window.d.ts.map +1 -1
  71. package/dist/surfaces/window/window.js +21 -24
  72. package/dist/surfaces/window/window.js.map +1 -1
  73. package/dist/themes/stylesheets/reset.css +1 -1
  74. package/dist/themes/stylesheets/reset.js +2 -2
  75. package/dist/themes/stylesheets/reset.js.map +1 -1
  76. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  77. package/dist/themes/themes/ergo/ergo_theme.js +70 -6
  78. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  79. package/dist/utils/dnd/hooks/use_drag_container.d.ts.map +1 -1
  80. package/dist/utils/dnd/hooks/use_drag_container.js.map +1 -1
  81. package/package.json +2 -2
  82. package/src/inputs/color_input/color_input.tsx +3 -3
  83. package/src/inputs/control/control.stories.tsx +158 -0
  84. package/src/inputs/control/control.tsx +32 -0
  85. package/src/inputs/control/control_stories.module.css +7 -0
  86. package/src/inputs/control_set/control_set.stories.tsx +46 -0
  87. package/src/inputs/{input_group/input_group.tsx → control_set/control_set.tsx} +5 -5
  88. package/src/inputs/date_picker/date_picker_input.stories.tsx +1 -1
  89. package/src/inputs/date_picker/date_picker_input.tsx +1 -1
  90. package/src/inputs/index.ts +2 -1
  91. package/src/inputs/input/input.tsx +1 -1
  92. package/src/inputs/phone_number_input/phone_number_country_select_adapter.tsx +1 -1
  93. package/src/inputs/phone_number_input/phone_number_input.tsx +1 -1
  94. package/src/inputs/phone_number_input/phone_number_input_adapter.tsx +2 -2
  95. package/src/inputs/phone_number_input/sip_input.tsx +4 -4
  96. package/src/inputs/select/select.tsx +1 -1
  97. package/src/inputs/textarea/textarea.stories.tsx +1 -1
  98. package/src/inputs/textarea/textarea.tsx +1 -1
  99. package/src/inputs/unit_input/unit_input.tsx +3 -3
  100. package/src/overlay/frame/frame.tsx +43 -63
  101. package/src/overlay/slide/slide.module.css +30 -0
  102. package/src/overlay/slide/slide.stories.tsx +58 -0
  103. package/src/overlay/slide/slide.tsx +51 -0
  104. package/src/stacks/box/box.tsx +10 -16
  105. package/src/stacks/box/detect_resize_bounds.ts +84 -0
  106. package/src/stacks/box/resize_handlers.ts +27 -15
  107. package/src/stacks/box/start_resize_handle.tsx +6 -3
  108. package/src/stacks/box/types.ts +23 -25
  109. package/src/surfaces/drawers/drawer.stories.tsx +130 -0
  110. package/src/surfaces/drawers/drawer.tsx +26 -0
  111. package/src/surfaces/index.ts +1 -4
  112. package/src/surfaces/modal/__stories__/modal.stories.tsx +70 -3
  113. package/src/surfaces/modal/modal.tsx +11 -2
  114. package/src/surfaces/window/window.stories.tsx +64 -8
  115. package/src/surfaces/window/window.tsx +6 -9
  116. package/src/themes/stylesheets/reset.css +2 -2
  117. package/src/themes/themes/ergo/ergo_theme.css +70 -6
  118. package/src/utils/dnd/hooks/use_drag_container.ts +0 -7
  119. package/dist/drawer_bottom.css +0 -1
  120. package/dist/drawer_end.css +0 -1
  121. package/dist/drawer_start.css +0 -1
  122. package/dist/drawer_top.css +0 -1
  123. package/dist/inputs/input_group/input_group.d.ts +0 -5
  124. package/dist/inputs/input_group/input_group.d.ts.map +0 -1
  125. package/dist/inputs/input_group/input_group.js +0 -20
  126. package/dist/surfaces/drawers/drawer_bottom/drawer_bottom.d.ts +0 -7
  127. package/dist/surfaces/drawers/drawer_bottom/drawer_bottom.d.ts.map +0 -1
  128. package/dist/surfaces/drawers/drawer_bottom/drawer_bottom.js +0 -22
  129. package/dist/surfaces/drawers/drawer_bottom/drawer_bottom.js.map +0 -1
  130. package/dist/surfaces/drawers/drawer_end/drawer_end.d.ts +0 -7
  131. package/dist/surfaces/drawers/drawer_end/drawer_end.d.ts.map +0 -1
  132. package/dist/surfaces/drawers/drawer_end/drawer_end.js +0 -20
  133. package/dist/surfaces/drawers/drawer_end/drawer_end.js.map +0 -1
  134. package/dist/surfaces/drawers/drawer_start/drawer_start.d.ts +0 -7
  135. package/dist/surfaces/drawers/drawer_start/drawer_start.d.ts.map +0 -1
  136. package/dist/surfaces/drawers/drawer_start/drawer_start.js +0 -22
  137. package/dist/surfaces/drawers/drawer_start/drawer_start.js.map +0 -1
  138. package/dist/surfaces/drawers/drawer_top/drawer_top.d.ts +0 -7
  139. package/dist/surfaces/drawers/drawer_top/drawer_top.d.ts.map +0 -1
  140. package/dist/surfaces/drawers/drawer_top/drawer_top.js +0 -20
  141. package/dist/surfaces/drawers/drawer_top/drawer_top.js.map +0 -1
  142. package/src/surfaces/drawers/__stories__/drawers.stories.tsx +0 -26
  143. package/src/surfaces/drawers/drawer_bottom/drawer_bottom.module.css +0 -5
  144. package/src/surfaces/drawers/drawer_bottom/drawer_bottom.tsx +0 -23
  145. package/src/surfaces/drawers/drawer_end/drawer_end.module.css +0 -5
  146. package/src/surfaces/drawers/drawer_end/drawer_end.tsx +0 -24
  147. package/src/surfaces/drawers/drawer_start/drawer_start.module.css +0 -5
  148. package/src/surfaces/drawers/drawer_start/drawer_start.tsx +0 -23
  149. package/src/surfaces/drawers/drawer_top/drawer_top.module.css +0 -5
  150. package/src/surfaces/drawers/drawer_top/drawer_top.tsx +0 -24
@@ -0,0 +1,158 @@
1
+ import React from 'react';
2
+ import { Control, ControlRow } from './control.js';
3
+ import { Input } from '../input/input.js';
4
+ import { Button } from '../../actions/button/button/button.js';
5
+ import { SearchIcon } from '@tcn/icons/search_icon.js';
6
+ import { CrossIcon } from '@tcn/icons/cross_icon.js';
7
+ import { Textarea } from '../textarea/textarea.js';
8
+ import { BugIcon } from '@tcn/icons/bug_icon.js';
9
+ import { BodyText } from '../../typography/index.js';
10
+ import { Spacer } from '../../stacks/spacer.js';
11
+ import { CopyIcon } from '@tcn/icons/copy_icon.js';
12
+ import { SendOneIcon } from '@tcn/icons/send_one_icon.js';
13
+ import { FilterOneIcon } from '@tcn/icons/filter_one_icon.js';
14
+ import { PlusIcon } from '@tcn/icons/plus_icon.js';
15
+ import styles from './control_stories.module.css';
16
+ import { RefreshCcwAlertIcon } from '@tcn/icons/refresh_ccw_alert_icon.js';
17
+ import { PlayIcon } from '@tcn/icons/play_icon.js';
18
+ import { DatePickerInput } from '../date_picker/date_picker_input.js';
19
+ import { Divider } from '../../layouts/index.js';
20
+ import { CalendarDatesIcon } from '@tcn/icons/calendar_dates_icon.js';
21
+
22
+ export default {
23
+ title: 'Inputs/Control',
24
+ parameters: {
25
+ docs: {
26
+ description: {
27
+ component:
28
+ 'Control and ControlRow layout components for grouping inputs with optional leading/trailing slots (icons, actions).',
29
+ },
30
+ },
31
+ },
32
+ tags: ['autodocs'],
33
+ };
34
+
35
+ function BaseInput(props: React.ComponentProps<typeof Input>) {
36
+ const [value, setValue] = React.useState(props.value ?? '');
37
+ return <Input {...props} value={value} onChange={setValue} />;
38
+ }
39
+
40
+ export function Baseline() {
41
+ return (
42
+ <Control maxWidth={400}>
43
+ <ControlRow>
44
+ <BaseInput placeholder="Enter text..." />
45
+ </ControlRow>
46
+ </Control>
47
+ );
48
+ }
49
+
50
+ export function Icons() {
51
+ return (
52
+ <Control maxWidth={400}>
53
+ <ControlRow>
54
+ <BugIcon />
55
+ <BaseInput placeholder="Search..." />
56
+ <FilterOneIcon />
57
+ <SearchIcon />
58
+ </ControlRow>
59
+ </Control>
60
+ );
61
+ }
62
+
63
+ export function Actions() {
64
+ return (
65
+ <Control maxWidth={400}>
66
+ <ControlRow>
67
+ <Button utility onClick={() => {}} hierarchy="tertiary">
68
+ <PlusIcon />
69
+ </Button>
70
+ <BaseInput placeholder="Type to clear..." value="Hello" />
71
+ <Button utility onClick={() => {}} hierarchy="tertiary">
72
+ <CrossIcon />
73
+ </Button>
74
+ </ControlRow>
75
+ </Control>
76
+ );
77
+ }
78
+
79
+ export function DatePickerControl() {
80
+ const [value, setValue] = React.useState<Date | null>(null);
81
+ return (
82
+ <Control maxWidth={400}>
83
+ <ControlRow>
84
+ <DatePickerInput value={value} onChange={setValue} width="fill" />
85
+ <Button utility onClick={() => {}} hierarchy="tertiary">
86
+ <CrossIcon />
87
+ </Button>
88
+ <Divider vertical length="sm" />
89
+ <CalendarDatesIcon />
90
+ </ControlRow>
91
+ </Control>
92
+ );
93
+ }
94
+
95
+ export function StartRow() {
96
+ return (
97
+ <Control maxWidth={400}>
98
+ <ControlRow>
99
+ <BugIcon />
100
+ <BodyText>script.js</BodyText>
101
+ <Spacer />
102
+ <Button utility onClick={() => {}} hierarchy="tertiary">
103
+ <CopyIcon />
104
+ </Button>
105
+ </ControlRow>
106
+ <ControlRow growWeight={1}>
107
+ <Textarea placeholder="console.log('Hello, world!');" />
108
+ </ControlRow>
109
+ </Control>
110
+ );
111
+ }
112
+
113
+ export function EndRow() {
114
+ return (
115
+ <Control maxWidth={400}>
116
+ <ControlRow growWeight={1}>
117
+ <Textarea rows={6} placeholder="What's on your mind?" />
118
+ </ControlRow>
119
+ <Spacer />
120
+ <ControlRow growWeight={1}>
121
+ <BodyText>{`<n> characters remaining`}</BodyText>
122
+ <Spacer />
123
+ <Button onClick={() => {}} hierarchy="tertiary">
124
+ Post <SendOneIcon />
125
+ </Button>
126
+ </ControlRow>
127
+ </Control>
128
+ );
129
+ }
130
+
131
+ export function CustomStyles() {
132
+ return (
133
+ <Control className={styles.customStyles} maxWidth={400}>
134
+ <ControlRow growWeight={1}>
135
+ <BugIcon />
136
+ <BodyText>script.js</BodyText>
137
+ <Spacer />
138
+ <Button utility onClick={() => {}} hierarchy="tertiary">
139
+ <RefreshCcwAlertIcon />
140
+ </Button>
141
+ <Button utility onClick={() => {}} hierarchy="tertiary">
142
+ <CopyIcon />
143
+ </Button>
144
+ </ControlRow>
145
+ <ControlRow growWeight={1}>
146
+ <Textarea rows={6} placeholder="Enter your code..." />
147
+ </ControlRow>
148
+ <Spacer />
149
+ <ControlRow growWeight={1}>
150
+ <BodyText>{`Line <i> Column <j>`}</BodyText>
151
+ <Spacer />
152
+ <Button onClick={() => {}} hierarchy="tertiary">
153
+ Run <PlayIcon />
154
+ </Button>
155
+ </ControlRow>
156
+ </Control>
157
+ );
158
+ }
@@ -0,0 +1,32 @@
1
+ import { clsx } from 'clsx';
2
+ import React from 'react';
3
+ import { VStack, type VStackProps } from '../../stacks/v_stack.js';
4
+ import { HStack, type HStackProps } from '../../stacks/h_stack.js';
5
+
6
+ export interface ControlProps extends VStackProps {}
7
+
8
+ export const Control = React.forwardRef<HTMLDivElement, ControlProps>(function Control(
9
+ { as = 'div', className, children, ...props }: ControlProps,
10
+ ref: React.Ref<HTMLDivElement>
11
+ ) {
12
+ return (
13
+ <VStack ref={ref} as={as} className={clsx(className, 'tcn-control')} {...props}>
14
+ {children}
15
+ </VStack>
16
+ );
17
+ });
18
+
19
+ export interface ControlRowProps extends HStackProps {}
20
+
21
+ export const ControlRow = React.forwardRef<HTMLDivElement, ControlRowProps>(
22
+ function ControlRow(
23
+ { as = 'div', className, children, ...props }: ControlRowProps,
24
+ ref: React.Ref<HTMLDivElement>
25
+ ) {
26
+ return (
27
+ <HStack ref={ref} as={as} className={clsx(className, 'tcn-control-row')} {...props}>
28
+ {children}
29
+ </HStack>
30
+ );
31
+ }
32
+ );
@@ -0,0 +1,7 @@
1
+ .custom-styles > *:not(:last-child) {
2
+ border-bottom: 1px solid var(--ergo-grey);
3
+ }
4
+
5
+ .custom-styles > :global(.tcn-control-row) {
6
+ min-height: 40px;
7
+ }
@@ -0,0 +1,46 @@
1
+ import { useState } from 'react';
2
+ import { ControlSet } from './control_set.js';
3
+ import { Input } from '../input/input.js';
4
+ import { Select } from '../select/select.js';
5
+ import { Option } from '../options/option.js';
6
+
7
+ export default {
8
+ title: 'Inputs/Control Set',
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component:
13
+ 'Control Sets are used to group controls and/or inputs that manage multiple values that are closely related and must be entered together. Usually a tuple like (value, unit) or (start, end). For example a value + unit input/selection.',
14
+ },
15
+ },
16
+ },
17
+ tags: ['autodocs'],
18
+ };
19
+
20
+ export function Baseline() {
21
+ const [value, setValue] = useState('42');
22
+ const [unit, setUnit] = useState('kg');
23
+
24
+ return (
25
+ <ControlSet maxWidth="200px">
26
+ <Input type="number" value={value} onChange={setValue} placeholder="Value" />
27
+ <Select
28
+ width="auto"
29
+ minWidth="24px"
30
+ value={unit}
31
+ onChange={setUnit}
32
+ placeholder="Unit"
33
+ >
34
+ <Option value="kg" label="kg">
35
+ kg
36
+ </Option>
37
+ <Option value="lb" label="lb">
38
+ lb
39
+ </Option>
40
+ <Option value="g" label="g">
41
+ g
42
+ </Option>
43
+ </Select>
44
+ </ControlSet>
45
+ );
46
+ }
@@ -2,23 +2,23 @@ import React from 'react';
2
2
  import { clsx } from 'clsx';
3
3
  import { HStack, type HStackProps } from '../../stacks/h_stack.js';
4
4
 
5
- export type InputGroupProps = HStackProps;
5
+ export type ControlSetProps = HStackProps;
6
6
 
7
- export const InputGroup = React.forwardRef<HTMLElement, InputGroupProps>(
7
+ export const ControlSet = React.forwardRef<HTMLElement, ControlSetProps>(
8
8
  function InputGroup(
9
- { children, as = 'div', className, ...props }: InputGroupProps,
9
+ { children, as = 'div', className, ...props }: ControlSetProps,
10
10
  ref
11
11
  ) {
12
12
  const clonedChildren = React.Children.map(children, child =>
13
13
  React.isValidElement(child)
14
14
  ? React.cloneElement(child, {
15
15
  ...child.props,
16
- className: clsx(child.props.className, 'tcn-input-group-slot'),
16
+ className: clsx(child.props.className, 'tcn-control-set-item'),
17
17
  })
18
18
  : child
19
19
  );
20
20
  return (
21
- <HStack ref={ref} as={as} className={clsx(className, 'tcn-input-group')} {...props}>
21
+ <HStack ref={ref} as={as} className={clsx(className, 'tcn-control-set')} {...props}>
22
22
  {clonedChildren}
23
23
  </HStack>
24
24
  );
@@ -61,7 +61,7 @@ function DatePickerActions({ presenter }: { presenter: DatePickerPresenter }) {
61
61
  );
62
62
  }
63
63
 
64
- export function DatePickerInput() {
64
+ export function Baseline() {
65
65
  const [value, setValue] = useState<Date | null>(null);
66
66
 
67
67
  return <DatePickerInputComponent value={value} onChange={setValue} width="300px" />;
@@ -125,7 +125,7 @@ export const DatePickerInput = React.forwardRef<HTMLButtonElement, DatePickerInp
125
125
  <>
126
126
  <Button
127
127
  ref={ref}
128
- className={clsx(styles.button, 'tcn-select')}
128
+ className={clsx(styles.button, 'tcn-entry', 'tcn-date-picker-input')}
129
129
  hAlign="start"
130
130
  disabled={disabled}
131
131
  hierarchy={hierarchy}
@@ -55,7 +55,8 @@ export * from './textarea/textarea.js';
55
55
 
56
56
  export * from './unit_input/unit_input.js';
57
57
 
58
- export * from './input_group/input_group.js';
58
+ export * from './control_set/control_set.js';
59
+ export * from './control/control.js';
59
60
 
60
61
  export {
61
62
  SelectGroup,
@@ -22,7 +22,7 @@ export const Input = React.forwardRef(function Input(
22
22
  ) {
23
23
  return (
24
24
  <input
25
- className={clsx(styles.input, className, 'tcn-input', 'tcn-control')}
25
+ className={clsx(styles.input, className, 'tcn-input', 'tcn-entry')}
26
26
  type={type}
27
27
  ref={ref}
28
28
  data-is-disabled={props.disabled || false}
@@ -117,7 +117,7 @@ export function PhoneNumberCountrySelectAdapter({
117
117
  onChange={handleChange}
118
118
  disabled={disabled}
119
119
  aria-label={ariaLabel ?? 'Country'}
120
- className={clsx(className, 'tcn-input-group-slot')}
120
+ className={clsx(className, 'tcn-control-set-item')}
121
121
  width="auto"
122
122
  >
123
123
  {items}
@@ -150,7 +150,7 @@ export function PhoneNumberInput({
150
150
  className={clsx(
151
151
  styles['phone-number-input'],
152
152
  'tcn-phone-number-input',
153
- 'tcn-input-group'
153
+ 'tcn-control-set'
154
154
  )}
155
155
  displayInitialValueAsLocalNumber
156
156
  addInternationalOption={false}
@@ -95,13 +95,13 @@ export const PhoneNumberInputAdapter = forwardRef<
95
95
  ref={forkedRef}
96
96
  value={value}
97
97
  {...(rest as any)}
98
- className={clsx(className, 'tcn-input-group-slot')}
98
+ className={clsx(className, 'tcn-control-set-item')}
99
99
  onChange={handleChange}
100
100
  />
101
101
  {showPhoneBook && (
102
102
  <Button
103
103
  disabled={disabled}
104
- className={clsx('tcn-input-group-slot', 'tcn-phone-number-phone-book')}
104
+ className={clsx('tcn-control-set-item', 'tcn-phone-number-phone-book')}
105
105
  aria-label={ariaPhoneBookButtonLabel}
106
106
  onClick={togglePhoneBook}
107
107
  size="md"
@@ -2,7 +2,7 @@ import React, { useLayoutEffect } from 'react';
2
2
  import { NotebookIcon } from '@tcn/icons/notebook_icon.js';
3
3
  import { Input } from '../input/input.js';
4
4
  import { Button } from '../../actions/index.js';
5
- import { InputGroup } from '../input_group/input_group.js';
5
+ import { ControlSet } from '../control_set/control_set.js';
6
6
  import clsx from 'clsx';
7
7
  import { usePhoneContext } from './phone_number_context.js';
8
8
  import type { CountryCode } from 'libphonenumber-js';
@@ -104,7 +104,7 @@ export function SipInput({
104
104
 
105
105
  return (
106
106
  <>
107
- <InputGroup>
107
+ <ControlSet>
108
108
  <PhoneNumberCountrySelectAdapter
109
109
  value="SIP"
110
110
  onChange={selectCountry}
@@ -124,7 +124,7 @@ export function SipInput({
124
124
  {showPhoneBook && (
125
125
  <Button
126
126
  disabled={disabled}
127
- className={clsx('tcn-input-group-slot', 'tcn-phone-number-phone-book')}
127
+ className={clsx('tcn-control-set-item', 'tcn-phone-number-phone-book')}
128
128
  aria-label={ariaPhoneBookButtonLabel}
129
129
  onClick={togglePhoneBook}
130
130
  size="md"
@@ -132,7 +132,7 @@ export function SipInput({
132
132
  <NotebookIcon size="md" />
133
133
  </Button>
134
134
  )}
135
- </InputGroup>
135
+ </ControlSet>
136
136
  <SuggestionList
137
137
  open={isPhoneBookOpen}
138
138
  anchorElement={phoneBookElement}
@@ -130,7 +130,7 @@ export const Select = React.forwardRef(function Select(
130
130
  <>
131
131
  <Button
132
132
  ref={forkedRef}
133
- className={clsx(className, 'tcn-select', 'tcn-control', styles.select)}
133
+ className={clsx(className, 'tcn-select', 'tcn-entry', styles.select)}
134
134
  width="100%"
135
135
  {...props}
136
136
  hAlign="start"
@@ -20,7 +20,7 @@ export default {
20
20
  tags: ['autodocs'],
21
21
  };
22
22
 
23
- export function Textarea() {
23
+ export function Baseline(props: TextareaProps) {
24
24
  return (
25
25
  <table className={styles.story}>
26
26
  <colgroup>
@@ -20,7 +20,7 @@ export const Textarea = React.forwardRef(function Textarea(
20
20
  return (
21
21
  <textarea
22
22
  style={{ width, height, ...style }}
23
- className={clsx(className, styles.textarea, 'tcn-textarea', 'tcn-control')}
23
+ className={clsx(className, styles.textarea, 'tcn-textarea', 'tcn-entry')}
24
24
  data-is-disabled={props.disabled || false}
25
25
  ref={ref}
26
26
  onChange={e => {
@@ -7,7 +7,7 @@ import { Select } from '../select/select.js';
7
7
  import { OptionProps } from '../options/option.js';
8
8
  import styles from './unit_input.module.css';
9
9
 
10
- import { InputGroup } from '../input_group/input_group.js';
10
+ import { ControlSet } from '../control_set/control_set.js';
11
11
 
12
12
  function getDisplayValue(value: string) {
13
13
  return value
@@ -80,7 +80,7 @@ export const UnitInput = React.forwardRef(function UnitInput(
80
80
  }
81
81
 
82
82
  return (
83
- <InputGroup
83
+ <ControlSet
84
84
  ref={ref}
85
85
  className={clsx(styles['unit-input'], 'tcn-unit-input')}
86
86
  height="auto"
@@ -110,6 +110,6 @@ export const UnitInput = React.forwardRef(function UnitInput(
110
110
  >
111
111
  {children}
112
112
  </Select>
113
- </InputGroup>
113
+ </ControlSet>
114
114
  );
115
115
  });
@@ -1,7 +1,13 @@
1
1
  import { clsx } from 'clsx';
2
2
  import React, { useCallback } from 'react';
3
3
  import { flushSync } from 'react-dom';
4
- import { Box, ZStack, type BoxProps } from '../../stacks/index.js';
4
+ import {
5
+ Box,
6
+ ZStack,
7
+ type BoxProps,
8
+ type OnHeightResizePayload,
9
+ type OnWidthResizePayload,
10
+ } from '../../stacks/index.js';
5
11
  import { useDragContainer } from '../../utils/dnd/context.js';
6
12
  import { Draggable } from '../../utils/dnd/draggable/draggable.js';
7
13
  import { Portal } from '../portal/portal.js';
@@ -15,14 +21,7 @@ export interface FrameOwnProps {
15
21
  resizable?: boolean;
16
22
  }
17
23
 
18
- export type FrameProps = Omit<
19
- BoxProps,
20
- | 'enableResizeOnLeft'
21
- | 'enableResizeOnRight'
22
- | 'enableResizeOnTop'
23
- | 'enableResizeOnBottom'
24
- > &
25
- FrameOwnProps;
24
+ export type FrameProps = BoxProps & FrameOwnProps;
26
25
 
27
26
  export const Frame = React.forwardRef<HTMLElement, FrameProps>(function Frame(
28
27
  {
@@ -32,6 +31,12 @@ export const Frame = React.forwardRef<HTMLElement, FrameProps>(function Frame(
32
31
  veil = false,
33
32
  resizable = true,
34
33
  className,
34
+ enableResizeOnTop = true,
35
+ enableResizeOnBottom = true,
36
+ enableResizeOnStart = true,
37
+ enableResizeOnEnd = true,
38
+ enableResizeOnLeft = false,
39
+ enableResizeOnRight = false,
35
40
  ...rest
36
41
  }: FrameProps,
37
42
  ref
@@ -44,10 +49,12 @@ export const Frame = React.forwardRef<HTMLElement, FrameProps>(function Frame(
44
49
  <FrameDialog
45
50
  className={className}
46
51
  ref={ref}
47
- enableResizeOnLeft={resizable}
48
- enableResizeOnRight={resizable}
49
- enableResizeOnTop={resizable}
50
- enableResizeOnBottom={resizable}
52
+ enableResizeOnStart={resizable && enableResizeOnStart}
53
+ enableResizeOnEnd={resizable && enableResizeOnEnd}
54
+ enableResizeOnTop={resizable && enableResizeOnTop}
55
+ enableResizeOnBottom={resizable && enableResizeOnBottom}
56
+ enableResizeOnRight={resizable && enableResizeOnRight}
57
+ enableResizeOnLeft={resizable && enableResizeOnLeft}
51
58
  draggable={draggable}
52
59
  {...rest}
53
60
  >
@@ -77,64 +84,37 @@ export const FrameDialog = React.forwardRef<HTMLElement, FrameDialogProps>(
77
84
  const drag = useDragContainer();
78
85
 
79
86
  const handleWidthResize = React.useCallback(
80
- (
81
- width: number,
82
- origin: 'left' | 'right',
83
- totalDelta: number,
84
- currentDelta: number,
85
- atLimit: boolean
86
- ) => {
87
+ (payload: OnWidthResizePayload) => {
87
88
  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
- }
89
+ if (payload.currentDelta === 0) return;
90
+ const sign = payload.origin === 'right' ? 1 : -1;
91
+ const dx = (payload.currentDelta / 2) * sign;
92
+ flushSync(() => {
93
+ drag.setPosition(prev => ({
94
+ x: prev.x + dx,
95
+ y: prev.y,
96
+ }));
97
+ });
105
98
 
106
- onWidthResize?.(width, origin, totalDelta, currentDelta, atLimit);
99
+ onWidthResize?.(payload);
107
100
  },
108
101
  [onWidthResize, drag, draggable]
109
102
  );
110
103
 
111
104
  const handleHeightResize = useCallback(
112
- (
113
- height: number,
114
- origin: 'top' | 'bottom',
115
- totalDelta: number,
116
- currentDelta: number,
117
- atLimit: boolean
118
- ) => {
105
+ (payload: OnHeightResizePayload) => {
119
106
  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);
107
+ if (payload.currentDelta === 0) return;
108
+ const sign = payload.origin === 'bottom' ? 1 : -1;
109
+ const half = payload.currentDelta / 2;
110
+ const dy = half * sign;
111
+ flushSync(() => {
112
+ drag.setPosition(prev => ({
113
+ x: prev.x,
114
+ y: prev.y + dy,
115
+ }));
116
+ });
117
+ onHeightResize?.(payload);
138
118
  },
139
119
  [onHeightResize, drag, draggable]
140
120
  );
@@ -0,0 +1,30 @@
1
+ @layer tcn-system {
2
+ :where(.slide) {
3
+ position: absolute;
4
+
5
+ &[data-side="top"],
6
+ &[data-side="bottom"] {
7
+ width: 100%;
8
+ }
9
+ &[data-side="start"],
10
+ &[data-side="end"] {
11
+ height: 100%;
12
+ }
13
+ &[data-side="top"] {
14
+ top: 0;
15
+ }
16
+
17
+ &[data-side="bottom"] {
18
+ bottom: 0;
19
+ }
20
+
21
+ /* TODO: support LTR directionality */
22
+ &[data-side="start"] {
23
+ left: 0;
24
+ }
25
+
26
+ &[data-side="end"] {
27
+ right: 0;
28
+ }
29
+ }
30
+ }