@tcn/ui 0.15.0 → 0.17.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 (204) hide show
  1. package/dist/card.css +1 -0
  2. package/dist/column.css +1 -1
  3. package/dist/containers.css +1 -1
  4. package/dist/containers.module-BmICKsOK.js +5 -0
  5. package/dist/containers.module-BmICKsOK.js.map +1 -0
  6. package/dist/form/field/field.js +11 -8
  7. package/dist/form/field/field.js.map +1 -1
  8. package/dist/inputs/color_input/color_picker.js +5 -2
  9. package/dist/inputs/color_input/color_picker.js.map +1 -1
  10. package/dist/inputs/combo_box/combo_box.js +18 -15
  11. package/dist/inputs/combo_box/combo_box.js.map +1 -1
  12. package/dist/inputs/date_picker/date_picker.js +13 -10
  13. package/dist/inputs/date_picker/date_picker.js.map +1 -1
  14. package/dist/inputs/date_picker/date_picker_input.js +20 -17
  15. package/dist/inputs/date_picker/date_picker_input.js.map +1 -1
  16. package/dist/inputs/date_picker/date_picker_year_selector.js +5 -2
  17. package/dist/inputs/date_picker/date_picker_year_selector.js.map +1 -1
  18. package/dist/inputs/mask_input/key_capture_input.js +26 -23
  19. package/dist/inputs/mask_input/key_capture_input.js.map +1 -1
  20. package/dist/inputs/mask_input/mask_input.js +5 -2
  21. package/dist/inputs/mask_input/mask_input.js.map +1 -1
  22. package/dist/inputs/multiselect/multiselect.js +22 -19
  23. package/dist/inputs/multiselect/multiselect.js.map +1 -1
  24. package/dist/inputs/phone_number_input/phone_number_context.js +7 -4
  25. package/dist/inputs/phone_number_input/phone_number_context.js.map +1 -1
  26. package/dist/inputs/select/select.js +5 -2
  27. package/dist/inputs/select/select.js.map +1 -1
  28. package/dist/inputs/slider/slider.js +19 -16
  29. package/dist/inputs/slider/slider.js.map +1 -1
  30. package/dist/inputs/suggestions/suggestion_list.js +5 -2
  31. package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
  32. package/dist/inputs/switch/switch.js +18 -15
  33. package/dist/inputs/switch/switch.js.map +1 -1
  34. package/dist/inputs/unit_input/unit_input.js +15 -12
  35. package/dist/inputs/unit_input/unit_input.js.map +1 -1
  36. package/dist/layouts/containers/columns/column.d.ts +6 -0
  37. package/dist/layouts/containers/columns/column.d.ts.map +1 -0
  38. package/dist/layouts/containers/columns/column.js +20 -0
  39. package/dist/layouts/containers/columns/column.js.map +1 -0
  40. package/dist/layouts/containers/columns/columns.d.ts +11 -0
  41. package/dist/layouts/containers/columns/columns.d.ts.map +1 -0
  42. package/dist/layouts/containers/columns/columns.js +34 -0
  43. package/dist/layouts/containers/columns/columns.js.map +1 -0
  44. package/dist/layouts/containers/rail.d.ts +2 -5
  45. package/dist/layouts/containers/rail.d.ts.map +1 -1
  46. package/dist/layouts/containers/rail.js +17 -55
  47. package/dist/layouts/containers/rail.js.map +1 -1
  48. package/dist/layouts/containers/rows/index.d.ts +3 -0
  49. package/dist/layouts/containers/rows/index.d.ts.map +1 -0
  50. package/dist/layouts/containers/rows/index.js +7 -0
  51. package/dist/layouts/containers/rows/index.js.map +1 -0
  52. package/dist/layouts/containers/rows/row.d.ts +6 -0
  53. package/dist/layouts/containers/rows/row.d.ts.map +1 -0
  54. package/dist/layouts/containers/rows/row.js +20 -0
  55. package/dist/layouts/containers/rows/row.js.map +1 -0
  56. package/dist/layouts/containers/rows/rows.d.ts +11 -0
  57. package/dist/layouts/containers/rows/rows.d.ts.map +1 -0
  58. package/dist/layouts/containers/rows/rows.js +34 -0
  59. package/dist/layouts/containers/rows/rows.js.map +1 -0
  60. package/dist/layouts/containers/scaffold.d.ts +2 -5
  61. package/dist/layouts/containers/scaffold.d.ts.map +1 -1
  62. package/dist/layouts/containers/scaffold.js +17 -55
  63. package/dist/layouts/containers/scaffold.js.map +1 -1
  64. package/dist/layouts/index.d.ts +4 -2
  65. package/dist/layouts/index.d.ts.map +1 -1
  66. package/dist/layouts/index.js +35 -31
  67. package/dist/layouts/index.js.map +1 -1
  68. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.js +5 -2
  69. package/dist/mobile/inputs/date_picker/mobile_date_picker_header.js.map +1 -1
  70. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.js +5 -2
  71. package/dist/mobile/inputs/date_picker/mobile_date_picker_input.js.map +1 -1
  72. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.js +8 -5
  73. package/dist/mobile/inputs/date_picker/mobile_date_picker_year_selector.js.map +1 -1
  74. package/dist/navigation/tabs/state/link/tab_link.js +9 -6
  75. package/dist/navigation/tabs/state/link/tab_link.js.map +1 -1
  76. package/dist/overlay/menu/menu.js +3 -0
  77. package/dist/overlay/menu/menu.js.map +1 -1
  78. package/dist/overlay/popper/context_popper.js +8 -5
  79. package/dist/overlay/popper/context_popper.js.map +1 -1
  80. package/dist/overlay/popper/element_popper.js +9 -6
  81. package/dist/overlay/popper/element_popper.js.map +1 -1
  82. package/dist/overlay/popper/legacy/popper.js +13 -10
  83. package/dist/overlay/popper/legacy/popper.js.map +1 -1
  84. package/dist/overlay/popper/preview_popper.js +10 -7
  85. package/dist/overlay/popper/preview_popper.js.map +1 -1
  86. package/dist/overlay/tethered/tethered.js +11 -8
  87. package/dist/overlay/tethered/tethered.js.map +1 -1
  88. package/dist/resizable.css +1 -0
  89. package/dist/resizable.module-I6iyBAvM.js +5 -0
  90. package/dist/resizable.module-I6iyBAvM.js.map +1 -0
  91. package/dist/resize_handle.css +1 -0
  92. package/dist/row.css +1 -0
  93. package/dist/stacks/box/box.js +12 -9
  94. package/dist/stacks/box/box.js.map +1 -1
  95. package/dist/stacks/box/detect_resize_bounds.d.ts +1 -0
  96. package/dist/stacks/box/detect_resize_bounds.d.ts.map +1 -1
  97. package/dist/stacks/box/detect_resize_bounds.js +22 -20
  98. package/dist/stacks/box/detect_resize_bounds.js.map +1 -1
  99. package/dist/stacks/h_collapsible_box.js +17 -14
  100. package/dist/stacks/h_collapsible_box.js.map +1 -1
  101. package/dist/stacks/v_collapsible_box.js +19 -16
  102. package/dist/stacks/v_collapsible_box.js.map +1 -1
  103. package/dist/surfaces/card/card.d.ts.map +1 -1
  104. package/dist/surfaces/card/card.js +14 -6
  105. package/dist/surfaces/card/card.js.map +1 -1
  106. package/dist/surfaces/pop_confirm/pop_confirm.js +6 -4
  107. package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
  108. package/dist/test-setup.d.ts +2 -0
  109. package/dist/test-setup.d.ts.map +1 -0
  110. package/dist/test-setup.js +10 -0
  111. package/dist/test-setup.js.map +1 -0
  112. package/dist/themes/theme.d.ts.map +1 -1
  113. package/dist/themes/theme.js +17 -22
  114. package/dist/themes/theme.js.map +1 -1
  115. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  116. package/dist/themes/themes/ergo/ergo_theme.js +225 -27
  117. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  118. package/dist/utils/index.d.ts +1 -0
  119. package/dist/utils/index.d.ts.map +1 -1
  120. package/dist/utils/index.js +39 -26
  121. package/dist/utils/index.js.map +1 -1
  122. package/dist/utils/resize/context.d.ts +4 -0
  123. package/dist/utils/resize/context.d.ts.map +1 -0
  124. package/dist/utils/resize/context.js +10 -0
  125. package/dist/utils/resize/context.js.map +1 -0
  126. package/dist/utils/resize/handle_config.d.ts +32 -0
  127. package/dist/utils/resize/handle_config.d.ts.map +1 -0
  128. package/dist/utils/resize/handle_config.js +85 -0
  129. package/dist/utils/resize/handle_config.js.map +1 -0
  130. package/dist/utils/resize/index.d.ts +10 -0
  131. package/dist/utils/resize/index.d.ts.map +1 -0
  132. package/dist/utils/resize/index.js +16 -0
  133. package/dist/utils/resize/index.js.map +1 -0
  134. package/dist/utils/resize/resizable.d.ts +11 -0
  135. package/dist/utils/resize/resizable.d.ts.map +1 -0
  136. package/dist/utils/resize/resizable.js +52 -0
  137. package/dist/utils/resize/resizable.js.map +1 -0
  138. package/dist/utils/resize/resize_handle.d.ts +7 -0
  139. package/dist/utils/resize/resize_handle.d.ts.map +1 -0
  140. package/dist/utils/resize/resize_handle.js +100 -0
  141. package/dist/utils/resize/resize_handle.js.map +1 -0
  142. package/dist/utils/resize/resize_strategy.d.ts +47 -0
  143. package/dist/utils/resize/resize_strategy.d.ts.map +1 -0
  144. package/dist/utils/resize/resize_strategy.js +108 -0
  145. package/dist/utils/resize/resize_strategy.js.map +1 -0
  146. package/dist/utils/resize/types.d.ts +28 -0
  147. package/dist/utils/resize/types.d.ts.map +1 -0
  148. package/dist/utils/resize/types.js +2 -0
  149. package/dist/utils/resize/types.js.map +1 -0
  150. package/package.json +3 -3
  151. package/src/layouts/__stories__/columns.stories.tsx +77 -0
  152. package/src/layouts/__stories__/composed.stories.tsx +77 -8
  153. package/src/layouts/__stories__/rail.stories.tsx +4 -4
  154. package/src/layouts/__stories__/rows.stories.tsx +77 -0
  155. package/src/layouts/__stories__/utils.tsx +2 -84
  156. package/src/layouts/containers/columns/column.module.css +15 -0
  157. package/src/layouts/containers/columns/column.tsx +22 -0
  158. package/src/layouts/containers/columns/columns.tsx +42 -0
  159. package/src/layouts/containers/containers.module.css +27 -29
  160. package/src/layouts/containers/rail.tsx +9 -51
  161. package/src/layouts/containers/rows/index.ts +2 -0
  162. package/src/layouts/containers/rows/row.module.css +15 -0
  163. package/src/layouts/containers/rows/row.tsx +22 -0
  164. package/src/layouts/containers/rows/rows.tsx +42 -0
  165. package/src/layouts/containers/scaffold.tsx +9 -49
  166. package/src/layouts/index.ts +4 -2
  167. package/src/stacks/box/detect_resize_bounds.ts +5 -1
  168. package/src/surfaces/card/card.module.css +5 -0
  169. package/src/surfaces/card/card.stories.tsx +66 -8
  170. package/src/surfaces/card/card.tsx +6 -2
  171. package/src/surfaces/page/page.stories.tsx +109 -25
  172. package/src/surfaces/panel/__stories__/panel.stories.tsx +139 -1
  173. package/src/test-setup.ts +11 -0
  174. package/src/themes/theme.tsx +6 -16
  175. package/src/themes/themes/ergo/ergo_theme.css +223 -25
  176. package/src/utils/index.ts +2 -0
  177. package/src/utils/resize/__stories__/resizable.stories.tsx +214 -0
  178. package/src/utils/resize/__stories__/resizable_stories.module.css +47 -0
  179. package/src/utils/resize/__tests__/handle_config.test.ts +269 -0
  180. package/src/utils/resize/__tests__/resize_strategy.test.ts +163 -0
  181. package/src/utils/resize/context.ts +9 -0
  182. package/src/utils/resize/handle_config.ts +142 -0
  183. package/src/utils/resize/index.ts +37 -0
  184. package/src/utils/resize/resizable.module.css +5 -0
  185. package/src/utils/resize/resizable.tsx +97 -0
  186. package/src/utils/resize/resize_handle.module.css +146 -0
  187. package/src/utils/resize/resize_handle.tsx +165 -0
  188. package/src/utils/resize/resize_strategy.ts +190 -0
  189. package/src/utils/resize/types.ts +64 -0
  190. package/dist/containers.module-DlGySre0.js +0 -5
  191. package/dist/containers.module-DlGySre0.js.map +0 -1
  192. package/dist/layouts/column/column.d.ts +0 -10
  193. package/dist/layouts/column/column.d.ts.map +0 -1
  194. package/dist/layouts/column/column.js +0 -52
  195. package/dist/layouts/column/column.js.map +0 -1
  196. package/dist/layouts/containers/side/side.d.ts +0 -6
  197. package/dist/layouts/containers/side/side.d.ts.map +0 -1
  198. package/dist/layouts/containers/side/side.js +0 -22
  199. package/dist/layouts/containers/side/side.js.map +0 -1
  200. package/dist/side.css +0 -1
  201. package/src/layouts/column/column.module.css +0 -35
  202. package/src/layouts/column/column.tsx +0 -57
  203. package/src/layouts/containers/side/side.module.css +0 -7
  204. package/src/layouts/containers/side/side.tsx +0 -25
@@ -11,6 +11,7 @@ export type DetectResizeBoundsResult = {
11
11
  hitMin: boolean;
12
12
  hitMax: boolean;
13
13
  clamped: boolean;
14
+ clampedSize: number | null;
14
15
  };
15
16
 
16
17
  const styleKeys = {
@@ -36,10 +37,12 @@ function detectByPixelValue(nextSize: number, min: string, max: string) {
36
37
  const maxPx = parsePx(max);
37
38
  const hitMin = minPx !== null && nextSize < minPx;
38
39
  const hitMax = maxPx !== null && nextSize > maxPx;
40
+ const clamped = hitMin || hitMax;
39
41
  return {
40
42
  hitMin,
41
43
  hitMax,
42
- clamped: hitMin || hitMax,
44
+ clamped,
45
+ clampedSize: clamped ? (hitMin ? minPx : maxPx) : null,
43
46
  };
44
47
  }
45
48
 
@@ -76,6 +79,7 @@ export function detectResizeBounds({
76
79
  hitMin,
77
80
  hitMax,
78
81
  clamped,
82
+ clampedSize: clamped ? renderedSize : null,
79
83
  };
80
84
  } finally {
81
85
  // revert the style change
@@ -0,0 +1,5 @@
1
+ @layer tcn-system {
2
+ .card {
3
+ height: auto;
4
+ }
5
+ }
@@ -6,7 +6,10 @@ import { Box, Spacer } from '../../stacks/index.js';
6
6
  import { Title } from '../../typography/title/title.js';
7
7
  import { Button } from '../../actions/index.js';
8
8
  import { Card } from './card.js';
9
- import { Scaffold } from '../../layouts/index.js';
9
+ import { Detail, Row, Rows, Scaffold } from '../../layouts/index.js';
10
+ import { Key } from '../../tokens/key/key.js';
11
+ import { Term } from '../../tokens/term/term.js';
12
+ import { Value } from '../../tokens/value/value.js';
10
13
 
11
14
  // Styles
12
15
  import styles from './card_stories.module.css';
@@ -52,13 +55,68 @@ export const Default = () => {
52
55
  <Box className={styles['content-box']} />
53
56
  <Box className={styles['content-box']} />
54
57
  </Scaffold>
55
- {/* Cards typically do not have a footer */}
56
- {/* <Footer>
57
- <Title>Footer</Title>
58
- <Spacer />
59
- <Button hierarchy="secondary">Secondary</Button>
60
- <Button hierarchy="primary">Primary</Button>
61
- </Footer> */}
58
+ </Card>
59
+ </div>
60
+ );
61
+ };
62
+
63
+ /**
64
+ * Rows inside a Card body. Fixed-height rows stack vertically with a
65
+ * fill row consuming remaining space — mirrors the Login Information
66
+ * card pattern from the app.
67
+ */
68
+ export const CardWithRows = () => {
69
+ return (
70
+ <div className={styles['stories-container']}>
71
+ <Card maxHeight="500px" maxWidth="400px">
72
+ <Header>
73
+ <Title>Login Information</Title>
74
+ </Header>
75
+ <Scaffold>
76
+ <Rows>
77
+ <Row>
78
+ <Detail>
79
+ <Term>
80
+ <Key>Username:</Key>
81
+ <Value>1026223MinhtestCreateAgent1</Value>
82
+ </Term>
83
+ <Term>
84
+ <Key>Email:</Key>
85
+ <Value severity="encouraged">jsmith@example.com</Value>
86
+ </Term>
87
+ </Detail>
88
+ </Row>
89
+
90
+ <Row>
91
+ <Detail>
92
+ <Term>
93
+ <Key>Force Password Reset:</Key>
94
+ <Value>No</Value>
95
+ </Term>
96
+ <Term>
97
+ <Key>Two-Factor Status:</Key>
98
+ <Value severity="encouraged">Enabled</Value>
99
+ </Term>
100
+ <Term>
101
+ <Key>Two-Factor Type:</Key>
102
+ <Value>Email</Value>
103
+ </Term>
104
+ </Detail>
105
+ </Row>
106
+ <Row>
107
+ <Detail>
108
+ <Term>
109
+ <Key>Access Token:</Key>
110
+ <Value>••••••••••••</Value>
111
+ </Term>
112
+ <Term>
113
+ <Key>Expiration Date:</Key>
114
+ <Value>02/27/2024</Value>
115
+ </Term>
116
+ </Detail>
117
+ </Row>
118
+ </Rows>
119
+ </Scaffold>
62
120
  </Card>
63
121
  </div>
64
122
  );
@@ -1,7 +1,7 @@
1
1
  import { clsx } from 'clsx';
2
2
  import React from 'react';
3
3
  import { Scaffold, type ScaffoldProps } from '../../layouts/containers/scaffold.js';
4
-
4
+ import styles from './card.module.css';
5
5
  export interface CardProps extends Omit<ScaffoldProps, 'as' | 'children'> {
6
6
  children?: React.ReactNode;
7
7
  }
@@ -11,7 +11,11 @@ export const Card = React.forwardRef<HTMLElement, CardProps>(function Card(
11
11
  ref
12
12
  ) {
13
13
  return (
14
- <Scaffold ref={ref} className={clsx(className, 'tcn-surface', 'tcn-card')} {...props}>
14
+ <Scaffold
15
+ ref={ref}
16
+ className={clsx(className, styles.card, 'tcn-surface', 'tcn-card')}
17
+ {...props}
18
+ >
15
19
  {children}
16
20
  </Scaffold>
17
21
  );
@@ -1,11 +1,17 @@
1
+ import { useState } from 'react';
1
2
  import { Header } from '../../layouts/header/header.js';
2
- import { Footer, Rail, Scaffold } from '../../layouts/index.js';
3
+ import { Detail, Footer, Scaffold } from '../../layouts/index.js';
4
+ import { Column } from '../../layouts/containers/columns/column.js';
5
+ import { Columns } from '../../layouts/containers/columns/columns.js';
3
6
  import { BodyText } from '../../typography/body_text/body_text.js';
4
- import { Section } from '../../layouts/section/section.js';
5
7
  import { Title } from '../../typography/title/title.js';
6
8
  import { Page } from './page.js';
7
9
  import { ZStack } from '../../stacks/z_stack.js';
8
10
  import { Panel } from '../panel/panel.js';
11
+ import { Card } from '../card/card.js';
12
+ import { SBContent } from '../../layouts/__stories__/utils.js';
13
+ import { Resizable } from '../../utils/resize/resizable.js';
14
+ import { ResizeHandle } from '../../utils/resize/resize_handle.js';
9
15
 
10
16
  export default {
11
17
  title: 'Surfaces/Page',
@@ -21,9 +27,9 @@ export const Baseline = () => {
21
27
  <Title>Page Header</Title>
22
28
  </Header>
23
29
  <Scaffold>
24
- <Section>
30
+ <Detail>
25
31
  <BodyText>Page Content</BodyText>
26
- </Section>
32
+ </Detail>
27
33
  </Scaffold>
28
34
 
29
35
  <Footer>
@@ -34,33 +40,111 @@ export const Baseline = () => {
34
40
  );
35
41
  };
36
42
 
37
- export const WithPanelBody = () => {
43
+ export const WithColumns = () => {
38
44
  return (
39
45
  <ZStack height="100%" width="100%" minHeight="600px" minWidth="600px">
40
46
  <Page>
41
- <Rail>
42
- <Panel>
43
- <Header>
44
- <Title>Primary</Title>
45
- </Header>
47
+ <Columns>
48
+ <Column minWidth="400px">
46
49
  <Scaffold>
47
- <Section>
48
- <BodyText>Page Content</BodyText>
49
- </Section>
50
- </Scaffold>
51
- </Panel>
50
+ <Header>
51
+ <Title>Tooling Header</Title>
52
+ </Header>
53
+ <Scaffold>
54
+ <Detail>
55
+ <Card>
56
+ <Header>Tooling 1</Header>
57
+ <Scaffold>
58
+ <SBContent />
59
+ </Scaffold>
60
+ </Card>
52
61
 
53
- <Panel width="300px">
54
- <Header>
55
- <Title>Secondary</Title>
56
- </Header>
57
- <Scaffold>
58
- <Section>
59
- <BodyText>Supporting Content</BodyText>
60
- </Section>
62
+ <Card>
63
+ <Header>Tooling 2</Header>
64
+ <Scaffold>
65
+ <SBContent />
66
+ </Scaffold>
67
+ </Card>
68
+ </Detail>
69
+ </Scaffold>
61
70
  </Scaffold>
62
- </Panel>
63
- </Rail>
71
+ </Column>
72
+ <Column minWidth="400px" width="fill">
73
+ <Panel>
74
+ <Header>
75
+ <Title>Primary</Title>
76
+ </Header>
77
+ <Scaffold>
78
+ <Detail>
79
+ <BodyText>Content</BodyText>
80
+ </Detail>
81
+ </Scaffold>
82
+ </Panel>
83
+ </Column>
84
+ <Column minWidth="400px">
85
+ <Panel>
86
+ <Header>
87
+ <Title>Secondary</Title>
88
+ </Header>
89
+ <Scaffold>
90
+ <Detail>
91
+ <BodyText>Content</BodyText>
92
+ </Detail>
93
+ </Scaffold>
94
+ </Panel>
95
+ </Column>
96
+ </Columns>
97
+ </Page>
98
+ </ZStack>
99
+ );
100
+ };
101
+
102
+ /** WIP: Testing Resizable + ResizeHandle with a two-column layout */
103
+ export const ResizableSecondaryColumn = () => {
104
+ const MIN_WIDTH = 200;
105
+ const MAX_WIDTH = 600;
106
+ const [secondaryWidth, setSecondaryWidth] = useState(350);
107
+
108
+ const atMin = secondaryWidth <= MIN_WIDTH;
109
+ const atMax = secondaryWidth >= MAX_WIDTH;
110
+ const constraint = atMin ? ' (At Min)' : atMax ? ' (At Max)' : '';
111
+
112
+ return (
113
+ <ZStack height="100%" width="100%" minHeight="600px" minWidth="600px">
114
+ <Page>
115
+ <Columns>
116
+ <Column width="fill">
117
+ <Panel>
118
+ <Header>
119
+ <Title>Primary</Title>
120
+ </Header>
121
+ <Scaffold>
122
+ <Detail>
123
+ <BodyText>Primary content fills remaining space.</BodyText>
124
+ </Detail>
125
+ </Scaffold>
126
+ </Panel>
127
+ </Column>
128
+ <Resizable onWidthResize={({ width }) => setSecondaryWidth(Math.round(width))}>
129
+ <Column
130
+ width={`${secondaryWidth}px`}
131
+ minWidth={`${MIN_WIDTH}px`}
132
+ maxWidth={`${MAX_WIDTH}px`}
133
+ >
134
+ <Panel>
135
+ <Header>
136
+ <Title>{`Secondary (${secondaryWidth}px)${constraint}`}</Title>
137
+ </Header>
138
+ <Scaffold>
139
+ <Detail>
140
+ <BodyText>Drag the left edge to resize this column.</BodyText>
141
+ </Detail>
142
+ </Scaffold>
143
+ </Panel>
144
+ </Column>
145
+ <ResizeHandle position="left" />
146
+ </Resizable>
147
+ </Columns>
64
148
  </Page>
65
149
  </ZStack>
66
150
  );
@@ -2,7 +2,9 @@ import { GridOneIcon } from '@tcn/icons/grid_one_icon.js';
2
2
  import { Button } from '../../../actions/button/button/button.js';
3
3
  import { Footer } from '../../../layouts/footer/footer.js';
4
4
  import { Header } from '../../../layouts/header/header.js';
5
- import { Detail, Heading, Scaffold, Section } from '../../../layouts/index.js';
5
+ import { Column } from '../../../layouts/containers/columns/column.js';
6
+ import { Columns } from '../../../layouts/containers/columns/columns.js';
7
+ import { Detail, Heading, Row, Rows, Scaffold, Section } from '../../../layouts/index.js';
6
8
  import { UtilityBar } from '../../../layouts/utility_bar/utility_bar.js';
7
9
  import { Box, HStack, Spacer } from '../../../stacks/index.js';
8
10
  import { Title } from '../../../typography/title/title.js';
@@ -327,6 +329,142 @@ export const WithCards = () => {
327
329
  );
328
330
  };
329
331
 
332
+ export const WithColumns = () => {
333
+ return (
334
+ <Box className={styles['stories-container']}>
335
+ <Panel maxHeight="600px">
336
+ <Header>
337
+ <Title emphasis="strong">Panel With Columns</Title>
338
+ <Spacer />
339
+ <UtilGroupExample />
340
+ </Header>
341
+ <Scaffold>
342
+ <Columns>
343
+ <Column minWidth="300px">
344
+ <Section>
345
+ <Heading>General</Heading>
346
+ <Detail>
347
+ <Term>
348
+ <Key>Email</Key>
349
+ <Value>john.doe@example.com</Value>
350
+ </Term>
351
+ <Term>
352
+ <Key>Phone</Key>
353
+ <Value>+1 555 000 1234</Value>
354
+ </Term>
355
+ <Term>
356
+ <Key>Start Date</Key>
357
+ <Value>05/27/2023</Value>
358
+ </Term>
359
+ </Detail>
360
+ </Section>
361
+ <Section>
362
+ <Heading>Contact</Heading>
363
+ <Detail>
364
+ <Term>
365
+ <Key>Email</Key>
366
+ <Value>john.doe@example.com</Value>
367
+ </Term>
368
+ <Term>
369
+ <Key>Phone</Key>
370
+ <Value>+1 555 000 1234</Value>
371
+ </Term>
372
+ <Term>
373
+ <Key>Start Date</Key>
374
+ <Value>05/27/2023</Value>
375
+ </Term>
376
+ </Detail>
377
+ </Section>
378
+ </Column>
379
+ <Column minWidth="300px">
380
+ <Rows>
381
+ <Row>
382
+ <Detail>
383
+ <Term>
384
+ <Key>Email</Key>
385
+ <Value>john.doe@example.com</Value>
386
+ </Term>
387
+ <Term>
388
+ <Key>Phone</Key>
389
+ <Value>+1 555 000 1234</Value>
390
+ </Term>
391
+ <Term>
392
+ <Key>Start Date</Key>
393
+ <Value>05/27/2023</Value>
394
+ </Term>
395
+ </Detail>
396
+ </Row>
397
+ <Row>
398
+ <Detail>
399
+ <Term>
400
+ <Key>Email</Key>
401
+ <Value>john.doe@example.com</Value>
402
+ </Term>
403
+ <Term>
404
+ <Key>Phone</Key>
405
+ <Value>+1 555 000 1234</Value>
406
+ </Term>
407
+ <Term>
408
+ <Key>Start Date</Key>
409
+ <Value>05/27/2023</Value>
410
+ </Term>
411
+ </Detail>
412
+ </Row>
413
+ </Rows>
414
+ </Column>
415
+ <Column minWidth="300px">
416
+ <Card>
417
+ <Header>General</Header>
418
+ <Scaffold>
419
+ <Detail>
420
+ <Term>
421
+ <Key>Email</Key>
422
+ <Value>john.doe@example.com</Value>
423
+ </Term>
424
+ <Term>
425
+ <Key>Phone</Key>
426
+ <Value>+1 555 000 1234</Value>
427
+ </Term>
428
+ <Term>
429
+ <Key>Start Date</Key>
430
+ <Value>05/27/2023</Value>
431
+ </Term>
432
+ </Detail>
433
+ </Scaffold>
434
+ </Card>
435
+
436
+ <Card>
437
+ <Header>Contact</Header>
438
+ <Scaffold>
439
+ <Detail>
440
+ <Term>
441
+ <Key>Email</Key>
442
+ <Value>john.doe@example.com</Value>
443
+ </Term>
444
+ <Term>
445
+ <Key>Phone</Key>
446
+ <Value>+1 555 000 1234</Value>
447
+ </Term>
448
+ <Term>
449
+ <Key>Start Date</Key>
450
+ <Value>05/27/2023</Value>
451
+ </Term>
452
+ </Detail>
453
+ </Scaffold>
454
+ </Card>
455
+ </Column>
456
+ </Columns>
457
+ </Scaffold>
458
+ <Footer>
459
+ <Spacer />
460
+ <Button hierarchy="secondary">Cancel</Button>
461
+ <Button hierarchy="primary">Save</Button>
462
+ </Footer>
463
+ </Panel>
464
+ </Box>
465
+ );
466
+ };
467
+
330
468
  export const WithDetailOnly = () => {
331
469
  return (
332
470
  <Box className={styles['stories-container']}>
@@ -0,0 +1,11 @@
1
+ // ResizeObserver is not available in vitest's jsdom environment.
2
+ // `use_resize_observer.ts` instantiates a registry singleton at module load
3
+ // time, so this stub must be in place before any imports run.
4
+ globalThis.ResizeObserver = class ResizeObserver {
5
+ observe() {}
6
+ unobserve() {}
7
+ disconnect() {}
8
+ };
9
+
10
+ // Required for React's act() to work correctly in jsdom tests.
11
+ globalThis.IS_REACT_ACT_ENVIRONMENT = true;
@@ -5,7 +5,6 @@ import { clsx } from 'clsx';
5
5
  // Styles
6
6
  import './stylesheets/reset.css';
7
7
  import styles from './theme_provider.module.css';
8
- import layers from '../css/layers.css?raw';
9
8
 
10
9
  export interface ThemeProps extends BoxProps {
11
10
  styleSheets: CSSStyleSheet[];
@@ -14,27 +13,18 @@ export interface ThemeProps extends BoxProps {
14
13
  }
15
14
 
16
15
  export function Theme({ styleSheets, children, className, ...boxProps }: ThemeProps) {
17
- useLayoutEffect(() => {
18
- document.adoptedStyleSheets = styleSheets;
19
- }, [styleSheets]);
16
+ const ref = React.useRef<HTMLElement>(null);
20
17
 
21
- // I used this approach instead to guarantee the order of the stylesheets
22
18
  useLayoutEffect(() => {
23
- if (document.getElementById('critical-css')) return;
24
-
25
- const style = document.createElement('style');
26
- style.id = 'critical-css';
27
- style.textContent = layers;
19
+ const root = ref.current?.getRootNode();
20
+ if (!root || !('adoptedStyleSheets' in root)) return;
28
21
 
29
- document.head.prepend(style);
30
-
31
- return () => {
32
- document.getElementById('critical-css')?.remove();
33
- };
34
- }, []);
22
+ (root as Document | ShadowRoot).adoptedStyleSheets = styleSheets;
23
+ }, [styleSheets]);
35
24
 
36
25
  return (
37
26
  <Box
27
+ ref={ref}
38
28
  className={clsx('tcn-theme-root', styles['tcn-theme-provider'], className)}
39
29
  {...boxProps}
40
30
  >