@tcn/ui 0.8.0 → 0.9.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 (222) hide show
  1. package/dist/{Color-6BZIO3FS-CWWwv-fq.js → Color-6BZIO3FS-C9xkPWgz.js} +2 -2
  2. package/dist/{Color-6BZIO3FS-CWWwv-fq.js.map → Color-6BZIO3FS-C9xkPWgz.js.map} +1 -1
  3. package/dist/{WithTooltip-65CFNBJE-DvcUZizH.js → WithTooltip-65CFNBJE-DEnh547F.js} +2 -2
  4. package/dist/{WithTooltip-65CFNBJE-DvcUZizH.js.map → WithTooltip-65CFNBJE-DEnh547F.js.map} +1 -1
  5. package/dist/actions/__docs__/components/showcase.js +1 -1
  6. package/dist/actions/index.d.ts +1 -0
  7. package/dist/actions/index.d.ts.map +1 -1
  8. package/dist/actions/index.js +8 -6
  9. package/dist/actions/index.js.map +1 -1
  10. package/dist/body.css +1 -0
  11. package/dist/feedback/progress/progress_bar.js +13 -13
  12. package/dist/form/field/common/field_description.js +7 -8
  13. package/dist/form/field/common/field_description.js.map +1 -1
  14. package/dist/form/field/common/field_error.js +6 -6
  15. package/dist/form/field/common/field_label.js +7 -8
  16. package/dist/form/field/common/field_label.js.map +1 -1
  17. package/dist/form/field_set/field_set.js +7 -7
  18. package/dist/formatter-EIJCOSYU-DWmgEY3b.js +6 -0
  19. package/dist/{formatter-EIJCOSYU-D6nmx63h.js.map → formatter-EIJCOSYU-DWmgEY3b.js.map} +1 -1
  20. package/dist/inputs/color_input/color_input.js +10 -9
  21. package/dist/inputs/color_input/color_input.js.map +1 -1
  22. package/dist/inputs/date_picker/date_picker_date.js +6 -6
  23. package/dist/inputs/date_picker/date_picker_day.js +6 -6
  24. package/dist/inputs/date_picker/date_picker_header.js +7 -6
  25. package/dist/inputs/date_picker/date_picker_header.js.map +1 -1
  26. package/dist/inputs/date_picker/date_picker_input.js +3 -2
  27. package/dist/inputs/date_picker/date_picker_input.js.map +1 -1
  28. package/dist/inputs/date_picker/date_picker_time_selector.js +8 -7
  29. package/dist/inputs/date_picker/date_picker_time_selector.js.map +1 -1
  30. package/dist/inputs/date_picker/date_picker_year_input.js +6 -5
  31. package/dist/inputs/date_picker/date_picker_year_input.js.map +1 -1
  32. package/dist/inputs/date_picker/date_picker_year_selector.js +8 -7
  33. package/dist/inputs/date_picker/date_picker_year_selector.js.map +1 -1
  34. package/dist/inputs/multiselect/multiselect_inline_values.js +8 -7
  35. package/dist/inputs/multiselect/multiselect_inline_values.js.map +1 -1
  36. package/dist/inputs/multiselect/multiselect_values.js +3 -2
  37. package/dist/inputs/multiselect/multiselect_values.js.map +1 -1
  38. package/dist/inputs/phone_number_input/phone_number_input.js +44 -43
  39. package/dist/inputs/phone_number_input/phone_number_input.js.map +1 -1
  40. package/dist/inputs/select/select.js +3 -2
  41. package/dist/inputs/select/select.js.map +1 -1
  42. package/dist/inputs/suggestions/suggestion_list.js +9 -8
  43. package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
  44. package/dist/layouts/body/body.d.ts +6 -0
  45. package/dist/layouts/body/body.d.ts.map +1 -0
  46. package/dist/layouts/body/body.js +21 -0
  47. package/dist/layouts/body/body.js.map +1 -0
  48. package/dist/layouts/index.d.ts +7 -0
  49. package/dist/layouts/index.d.ts.map +1 -1
  50. package/dist/layouts/index.js +42 -22
  51. package/dist/layouts/index.js.map +1 -1
  52. package/dist/layouts/rail/main/main.d.ts +6 -0
  53. package/dist/layouts/rail/main/main.d.ts.map +1 -0
  54. package/dist/layouts/rail/main/main.js +21 -0
  55. package/dist/layouts/rail/main/main.js.map +1 -0
  56. package/dist/layouts/rail/rail.d.ts +9 -0
  57. package/dist/layouts/rail/rail.d.ts.map +1 -0
  58. package/dist/layouts/rail/rail.js +55 -0
  59. package/dist/layouts/rail/rail.js.map +1 -0
  60. package/dist/layouts/rail/side/side.d.ts +6 -0
  61. package/dist/layouts/rail/side/side.d.ts.map +1 -0
  62. package/dist/layouts/rail/side/side.js +21 -0
  63. package/dist/layouts/rail/side/side.js.map +1 -0
  64. package/dist/layouts/rail/utility_strip/utility_strip.d.ts +9 -0
  65. package/dist/layouts/rail/utility_strip/utility_strip.d.ts.map +1 -0
  66. package/dist/layouts/rail/utility_strip/utility_strip.js +32 -0
  67. package/dist/layouts/rail/utility_strip/utility_strip.js.map +1 -0
  68. package/dist/layouts/responsive/breakpoint.d.ts +11 -0
  69. package/dist/layouts/responsive/breakpoint.d.ts.map +1 -0
  70. package/dist/layouts/responsive/breakpoint.js +15 -0
  71. package/dist/layouts/responsive/breakpoint.js.map +1 -0
  72. package/dist/layouts/responsive/responsive.d.ts +7 -0
  73. package/dist/layouts/responsive/responsive.d.ts.map +1 -0
  74. package/dist/layouts/responsive/responsive.js +11 -0
  75. package/dist/layouts/responsive/responsive.js.map +1 -0
  76. package/dist/layouts/responsive/responsive_container.d.ts +7 -0
  77. package/dist/layouts/responsive/responsive_container.d.ts.map +1 -0
  78. package/dist/layouts/responsive/responsive_container.js +30 -0
  79. package/dist/layouts/responsive/responsive_container.js.map +1 -0
  80. package/dist/layouts/responsive/responsive_viewport.d.ts +7 -0
  81. package/dist/layouts/responsive/responsive_viewport.d.ts.map +1 -0
  82. package/dist/layouts/responsive/responsive_viewport.js +12 -0
  83. package/dist/layouts/responsive/responsive_viewport.js.map +1 -0
  84. package/dist/layouts/scaffold/scaffold.js +31 -31
  85. package/dist/layouts/scaffold/scaffold.js.map +1 -1
  86. package/dist/layouts/table/table.d.ts +27 -0
  87. package/dist/layouts/table/table.d.ts.map +1 -0
  88. package/dist/layouts/table/table.js +70 -0
  89. package/dist/layouts/table/table.js.map +1 -0
  90. package/dist/main.css +1 -0
  91. package/dist/rail.css +1 -0
  92. package/dist/scaffold.css +1 -1
  93. package/dist/{showcase-DK557szS.js → showcase-y9D3_Y8T.js} +3413 -3396
  94. package/dist/showcase-y9D3_Y8T.js.map +1 -0
  95. package/dist/side.css +1 -0
  96. package/dist/stacks/box/box.d.ts +2 -2
  97. package/dist/stacks/box/box.d.ts.map +1 -1
  98. package/dist/stacks/box/box.js.map +1 -1
  99. package/dist/stacks/story_components/style_box.d.ts +1 -1
  100. package/dist/stacks/story_components/style_box.d.ts.map +1 -1
  101. package/dist/surfaces/alert/alert.js +3 -2
  102. package/dist/surfaces/alert/alert.js.map +1 -1
  103. package/dist/surfaces/confirm/confirm.js +5 -5
  104. package/dist/surfaces/pop_confirm/pop_confirm.js +14 -2
  105. package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
  106. package/dist/{syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js → syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js} +2 -2
  107. package/dist/{syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js.map → syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js.map} +1 -1
  108. package/dist/table.css +1 -0
  109. package/dist/table.module-BtSxOntS.js +5 -0
  110. package/dist/table.module-BtSxOntS.js.map +1 -0
  111. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  112. package/dist/themes/themes/ergo/ergo_theme.js +174 -43
  113. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  114. package/dist/typography/body_text/body_text.d.ts +2 -1
  115. package/dist/typography/body_text/body_text.d.ts.map +1 -1
  116. package/dist/typography/body_text/body_text.js +24 -23
  117. package/dist/typography/body_text/body_text.js.map +1 -1
  118. package/dist/typography/callout/callout.d.ts +2 -1
  119. package/dist/typography/callout/callout.d.ts.map +1 -1
  120. package/dist/typography/callout/callout.js +28 -27
  121. package/dist/typography/callout/callout.js.map +1 -1
  122. package/dist/typography/caption/caption.d.ts +2 -1
  123. package/dist/typography/caption/caption.d.ts.map +1 -1
  124. package/dist/typography/caption/caption.js +18 -17
  125. package/dist/typography/caption/caption.js.map +1 -1
  126. package/dist/typography/footnote/footnote.d.ts +2 -1
  127. package/dist/typography/footnote/footnote.d.ts.map +1 -1
  128. package/dist/typography/footnote/footnote.js +25 -24
  129. package/dist/typography/footnote/footnote.js.map +1 -1
  130. package/dist/typography/headline/headline.d.ts +2 -1
  131. package/dist/typography/headline/headline.d.ts.map +1 -1
  132. package/dist/typography/headline/headline.js +36 -33
  133. package/dist/typography/headline/headline.js.map +1 -1
  134. package/dist/typography/subheadline/subheadline.d.ts +2 -1
  135. package/dist/typography/subheadline/subheadline.d.ts.map +1 -1
  136. package/dist/typography/subheadline/subheadline.js +35 -32
  137. package/dist/typography/subheadline/subheadline.js.map +1 -1
  138. package/dist/utility_strip.css +1 -0
  139. package/dist/utils/dnd/context.d.ts.map +1 -1
  140. package/dist/utils/dnd/context.js +9 -7
  141. package/dist/utils/dnd/context.js.map +1 -1
  142. package/dist/utils/dnd/hooks/use_drag_container.d.ts.map +1 -1
  143. package/dist/utils/dnd/hooks/use_drag_container.js +29 -15
  144. package/dist/utils/dnd/hooks/use_drag_container.js.map +1 -1
  145. package/dist/utils/dnd/types.d.ts +3 -4
  146. package/dist/utils/dnd/types.d.ts.map +1 -1
  147. package/dist/utils/hooks/use_media_query.d.ts +5 -8
  148. package/dist/utils/hooks/use_media_query.d.ts.map +1 -1
  149. package/dist/utils/hooks/use_media_query.js +10 -11
  150. package/dist/utils/hooks/use_media_query.js.map +1 -1
  151. package/dist/utils/index.d.ts +1 -2
  152. package/dist/utils/index.d.ts.map +1 -1
  153. package/dist/utils/index.js +19 -21
  154. package/dist/utils/index.js.map +1 -1
  155. package/package.json +1 -1
  156. package/src/actions/index.ts +1 -0
  157. package/src/layouts/__stories__/composed.stories.tsx +113 -0
  158. package/src/layouts/__stories__/composed_stories.module.css +142 -0
  159. package/src/layouts/__stories__/utils.tsx +174 -0
  160. package/src/layouts/body/body.module.css +11 -0
  161. package/src/layouts/body/body.tsx +23 -0
  162. package/src/layouts/index.ts +12 -0
  163. package/src/layouts/rail/__stories__/rail.stories.tsx +64 -0
  164. package/src/layouts/rail/__stories__/rail_stories.module.css +25 -0
  165. package/src/layouts/rail/main/main.module.css +7 -0
  166. package/src/layouts/rail/main/main.tsx +26 -0
  167. package/src/layouts/rail/rail.module.css +10 -0
  168. package/src/layouts/rail/rail.tsx +62 -0
  169. package/src/layouts/rail/side/side.module.css +8 -0
  170. package/src/layouts/rail/side/side.tsx +25 -0
  171. package/src/layouts/rail/utility_strip/utility_strip.module.css +6 -0
  172. package/src/layouts/rail/utility_strip/utility_strip.tsx +40 -0
  173. package/src/layouts/responsive/breakpoint.tsx +29 -0
  174. package/src/layouts/responsive/responsive.stories.tsx +37 -0
  175. package/src/layouts/responsive/responsive.tsx +18 -0
  176. package/src/layouts/responsive/responsive_container.tsx +51 -0
  177. package/src/layouts/responsive/responsive_viewport.tsx +17 -0
  178. package/src/layouts/scaffold/__stories__/scaffold.stories.tsx +53 -0
  179. package/src/layouts/scaffold/__stories__/scaffold_stories.module.css +31 -0
  180. package/src/layouts/scaffold/scaffold.module.css +4 -0
  181. package/src/layouts/table/__stories__/mock_data.ts +420 -0
  182. package/src/layouts/table/__stories__/table.stories.tsx +326 -0
  183. package/src/layouts/table/__stories__/table_stories.module.css +30 -0
  184. package/src/layouts/table/table.module.css +37 -0
  185. package/src/layouts/table/table.tsx +132 -0
  186. package/src/stacks/box/box.tsx +1 -1
  187. package/src/surfaces/modal/__stories__/modal.stories.tsx +5 -5
  188. package/src/surfaces/panel/__stories__/panel.stories.tsx +114 -1
  189. package/src/surfaces/pop_confirm/pop_confirm.stories.tsx +4 -2
  190. package/src/themes/themes/ergo/ergo_theme.css +173 -42
  191. package/src/typography/body_text/body_text.tsx +21 -17
  192. package/src/typography/callout/callout.tsx +20 -16
  193. package/src/typography/caption/caption.tsx +20 -16
  194. package/src/typography/footnote/footnote.tsx +20 -16
  195. package/src/typography/headline/headline.tsx +60 -54
  196. package/src/typography/subheadline/subheadline.tsx +60 -54
  197. package/src/utils/dnd/__stories__/draggable.stories.tsx +34 -0
  198. package/src/utils/dnd/context.ts +1 -0
  199. package/src/utils/dnd/hooks/use_drag_container.ts +18 -1
  200. package/src/utils/dnd/types.ts +4 -1
  201. package/src/utils/hooks/use_media_query.ts +16 -27
  202. package/src/utils/index.ts +1 -3
  203. package/dist/body_text.module-h4XQE2pC.js +0 -5
  204. package/dist/body_text.module-h4XQE2pC.js.map +0 -1
  205. package/dist/callout.module-D8ECmxpO.js +0 -5
  206. package/dist/callout.module-D8ECmxpO.js.map +0 -1
  207. package/dist/caption.module-DDq0H4xZ.js +0 -5
  208. package/dist/caption.module-DDq0H4xZ.js.map +0 -1
  209. package/dist/footnote.module-DEyFuqOr.js +0 -5
  210. package/dist/footnote.module-DEyFuqOr.js.map +0 -1
  211. package/dist/formatter-EIJCOSYU-D6nmx63h.js +0 -6
  212. package/dist/headline.module-BiwHBtGf.js +0 -5
  213. package/dist/headline.module-BiwHBtGf.js.map +0 -1
  214. package/dist/showcase-DK557szS.js.map +0 -1
  215. package/dist/subheadline.module-C-v7zMkQ.js +0 -5
  216. package/dist/subheadline.module-C-v7zMkQ.js.map +0 -1
  217. package/dist/utils/responsive/responsive_renderer.d.ts +0 -21
  218. package/dist/utils/responsive/responsive_renderer.d.ts.map +0 -1
  219. package/dist/utils/responsive/responsive_renderer.js +0 -12
  220. package/dist/utils/responsive/responsive_renderer.js.map +0 -1
  221. package/src/utils/responsive/responsive_renderer.stories.tsx +0 -77
  222. package/src/utils/responsive/responsive_renderer.tsx +0 -31
@@ -0,0 +1,174 @@
1
+ import type { PropsWithChildren } from 'react';
2
+ import clsx from 'clsx';
3
+
4
+ import { Scaffold, type ScaffoldProps } from '../scaffold/scaffold.js';
5
+ import { Header } from '../header/header.js';
6
+ import { Body } from '../body/body.js';
7
+ import { Footer } from '../footer/footer.js';
8
+ import { UtilityBar } from '../utility_bar/utility_bar.js';
9
+
10
+ import { Rail, type RailProps } from '../rail/rail.js';
11
+ import { Side } from '../rail/side/side.js';
12
+ import { Main } from '../rail/main/main.js';
13
+ import { Box, Spacer } from '../../stacks/index.js';
14
+ import { UtilityStrip } from '../rail/utility_strip/utility_strip.js';
15
+ import { SearchIcon } from '@tcn/icons/search_icon.js';
16
+
17
+ import styles from './composed_stories.module.css';
18
+
19
+ const FloatingLabel = ({ children }: { children: React.ReactNode }) => {
20
+ return (
21
+ <div className={styles.floatingLabel}>
22
+ <span className={styles.floatingLabelChip}>{children}</span>
23
+ </div>
24
+ );
25
+ };
26
+
27
+ const VerticalLabel = ({ children }: { children: React.ReactNode }) => {
28
+ return <span className={styles.verticalLabel}>{children}</span>;
29
+ };
30
+
31
+ export const SBContent: React.FC<
32
+ PropsWithChildren<{ className?: string; minHeight?: string; minWidth?: string }>
33
+ > = ({ className, children, minHeight = '200px', minWidth = '200px' }) => {
34
+ return (
35
+ <Box
36
+ minHeight={minHeight}
37
+ minWidth={minWidth}
38
+ className={clsx(styles.content, className)}
39
+ >
40
+ ↔ {minWidth}
41
+ <br />↕ {minHeight}
42
+ {children}
43
+ </Box>
44
+ );
45
+ };
46
+
47
+ const SBActionBox = ({ children }: { children: React.ReactNode }) => {
48
+ return <span className={styles.actionBox}>{children}</span>;
49
+ };
50
+
51
+ const SBActions = () => {
52
+ return (
53
+ <>
54
+ <Spacer />
55
+ <SBActionBox>
56
+ <SearchIcon />
57
+ </SBActionBox>
58
+ <SBActionBox>
59
+ <SearchIcon />
60
+ </SBActionBox>
61
+ <SBActionBox>
62
+ <SearchIcon />
63
+ </SBActionBox>
64
+ </>
65
+ );
66
+ };
67
+
68
+ interface SBNestedRailProps extends RailProps {
69
+ depth?: number;
70
+ scaffold?: boolean;
71
+ side?: boolean;
72
+ main?: boolean;
73
+ utilityStrip?: boolean;
74
+ label?: boolean;
75
+ mainLabel?: boolean;
76
+ }
77
+
78
+ export const SBNestedRail: React.FC<PropsWithChildren<SBNestedRailProps>> = ({
79
+ children,
80
+ className,
81
+ depth = 1,
82
+ scaffold = true,
83
+ side = true,
84
+ main = true,
85
+ utilityStrip = true,
86
+ label = true,
87
+ mainLabel = true,
88
+ ...props
89
+ }) => {
90
+ return (
91
+ <Rail
92
+ className={clsx(styles.rail, styles.primary, className)}
93
+ data-depth={depth}
94
+ {...props}
95
+ >
96
+ {label && <FloatingLabel>Rail</FloatingLabel>}
97
+ {utilityStrip && (
98
+ <UtilityStrip className={clsx(styles.utilityStrip, styles.secondary)}>
99
+ <VerticalLabel>Utility Strip</VerticalLabel>
100
+ <SBActions />
101
+ </UtilityStrip>
102
+ )}
103
+ {main && (
104
+ <Main className={clsx(styles.main, styles.secondary)} width="200px">
105
+ {mainLabel && <>Main</>}
106
+ {children}
107
+ </Main>
108
+ )}
109
+ {!main && children}
110
+ {side && (
111
+ <Side className={clsx(styles.side, styles.secondary)} minWidth="200px">
112
+ <span>Side/Column/WIP</span>
113
+ </Side>
114
+ )}
115
+ {scaffold && (
116
+ <SBNestedScaffold
117
+ depth={depth + 1}
118
+ utilityBar={false}
119
+ footer={false}
120
+ minWidth={'fit-content'}
121
+ >
122
+ <SBContent />
123
+ <SBContent />
124
+ <SBContent />
125
+ </SBNestedScaffold>
126
+ )}
127
+ </Rail>
128
+ );
129
+ };
130
+
131
+ interface SBNestedScaffoldProps extends ScaffoldProps {
132
+ depth?: number;
133
+ header?: boolean;
134
+ utilityBar?: boolean;
135
+ body?: boolean;
136
+ footer?: boolean;
137
+ }
138
+
139
+ export const SBNestedScaffold: React.FC<PropsWithChildren<SBNestedScaffoldProps>> = ({
140
+ children,
141
+ className,
142
+ depth = 1,
143
+ header = true,
144
+ utilityBar = true,
145
+ body = true,
146
+ footer = true,
147
+ ...props
148
+ }) => {
149
+ return (
150
+ <Scaffold
151
+ className={clsx(styles.scaffold, styles.primary, className)}
152
+ data-depth={depth}
153
+ {...props}
154
+ >
155
+ <FloatingLabel>Scaffold</FloatingLabel>
156
+ {header && (
157
+ <Header className={clsx(styles.header, styles.secondary)}>Header</Header>
158
+ )}
159
+ {utilityBar && (
160
+ <UtilityBar className={clsx(styles.utilityBar, styles.secondary)}>
161
+ Utility Bar
162
+ <SBActions />
163
+ </UtilityBar>
164
+ )}
165
+ {body && (
166
+ <Body className={clsx(styles.body, styles.secondary)}>Body {children}</Body>
167
+ )}
168
+ {!body && children}
169
+ {footer && (
170
+ <Footer className={clsx(styles.footer, styles.secondary)}>Footer</Footer>
171
+ )}
172
+ </Scaffold>
173
+ );
174
+ };
@@ -0,0 +1,11 @@
1
+ @layer tcn-system {
2
+ .body {
3
+ min-height: 0;
4
+ flex-grow: 1;
5
+ width: 100%;
6
+ height: 100%;
7
+ }
8
+ :where(.tcn-main) {
9
+ height: auto;
10
+ }
11
+ }
@@ -0,0 +1,23 @@
1
+ import { VStack, type VStackProps } from '../../stacks/v_stack.js';
2
+ import React from 'react';
3
+ import { clsx } from 'clsx';
4
+ import styles from './body.module.css';
5
+
6
+ export interface BodyProps extends Omit<VStackProps, 'as'> {}
7
+
8
+ export const Body = React.forwardRef<HTMLElement, BodyProps>(function Body(
9
+ { children, className, overflowY = 'auto', ...props }: BodyProps,
10
+ ref
11
+ ) {
12
+ return (
13
+ <VStack
14
+ ref={ref}
15
+ as="div"
16
+ overflowY={overflowY}
17
+ className={clsx(styles['body'], className, 'tcn-body')}
18
+ {...props}
19
+ >
20
+ {children}
21
+ </VStack>
22
+ );
23
+ });
@@ -15,3 +15,15 @@ export { UtilityBar, type UtilityBarProps } from './utility_bar/utility_bar.js';
15
15
  export { Row } from './row/row.js';
16
16
  export { Section } from './section/section.js';
17
17
  export { Heading, type HeadingOwnProps } from './section/heading.js';
18
+ export { Responsive, type ResponsiveProps } from './responsive/responsive.js';
19
+ export { Breakpoint, type BreakpointProps } from './responsive/breakpoint.js';
20
+
21
+ export { TTable, THead, TBody, TFoot, TR, TH, TD } from './table/table.js';
22
+
23
+ export { Rail, type RailProps } from './rail/rail.js';
24
+ export { Main, type MainProps } from './rail/main/main.js';
25
+ export { Side, type SideProps } from './rail/side/side.js';
26
+ export {
27
+ UtilityStrip,
28
+ type UtilityStripProps,
29
+ } from './rail/utility_strip/utility_strip.js';
@@ -0,0 +1,64 @@
1
+ import { Main } from '../main/main.js';
2
+ import { Rail } from '../rail.js';
3
+ import type { Meta, StoryObj } from '@storybook/react-vite';
4
+ import { Side } from '../side/side.js';
5
+ import { VStack } from '../../../stacks/v_stack.js';
6
+
7
+ import styles from './rail_stories.module.css';
8
+
9
+ const meta: Meta<typeof Rail> = {
10
+ title: 'Layouts/Rail',
11
+ component: Rail,
12
+ tags: ['autodocs'],
13
+ parameters: {
14
+ docs: {
15
+ description: {
16
+ component: 'A rail component that lays out content in a horizontal hierarchy.',
17
+ },
18
+ },
19
+ },
20
+ };
21
+
22
+ export default meta;
23
+
24
+ type Story = StoryObj<typeof Rail>;
25
+
26
+ const Content = ({ children }: { children?: React.ReactNode }) => {
27
+ return (
28
+ <VStack hAlign="start" className={styles.content}>
29
+ {children}
30
+ </VStack>
31
+ );
32
+ };
33
+
34
+ export const Baseline: Story = {
35
+ args: {
36
+ height: '100vh',
37
+ },
38
+ render: () => (
39
+ <Rail height="100vh" className={styles.rail}>
40
+ <Side className={styles.side}>
41
+ <p>Side (Start)</p>
42
+ <p>Fills available space</p>
43
+ <p>Scrolls horizontally</p>
44
+ </Side>
45
+
46
+ <Main className={styles.main}>
47
+ <Content>
48
+ <p>Main</p>
49
+ <p>Fills available space</p>
50
+ <p>Scrolls horizontally</p>
51
+ </Content>
52
+ <Content />
53
+ <Content />
54
+ <Content />
55
+ <Content />
56
+ </Main>
57
+ <Side className={styles.side}>
58
+ <p>Side (End)</p>
59
+ <p>Fills available space</p>
60
+ <p>Scrolls horizontally</p>
61
+ </Side>
62
+ </Rail>
63
+ ),
64
+ };
@@ -0,0 +1,25 @@
1
+ .rail {
2
+ :global(.tcn-rail-stack) {
3
+ gap: 8px;
4
+ }
5
+ }
6
+
7
+ .main {
8
+ background-color: #f1f5f9;
9
+ gap: 16px;
10
+ padding: 16px 0;
11
+ }
12
+
13
+ .side {
14
+ width: 200px;
15
+ background-color: #3b82f6;
16
+ color: white;
17
+ padding: 16px 0;
18
+ }
19
+
20
+ .content {
21
+ background-color: #e5e7eb;
22
+ min-width: 200px;
23
+ height: 100%;
24
+ padding: 16px;
25
+ }
@@ -0,0 +1,7 @@
1
+ @layer tcn-system {
2
+ :where(.main) {
3
+ min-width: 0;
4
+ flex-grow: 1;
5
+ height: 100%;
6
+ }
7
+ }
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { clsx } from 'clsx';
3
+ import { HStack, type HStackProps } from '../../../stacks/h_stack.js';
4
+
5
+ // Styles
6
+ import styles from './main.module.css';
7
+
8
+ export interface MainProps extends Omit<HStackProps, 'as'> {}
9
+
10
+ // WIP: This component is not fully implemented.
11
+ export const Main = React.forwardRef<HTMLElement, MainProps>(function Main(
12
+ { children, className, overflowX = 'auto', ...props }: MainProps,
13
+ ref
14
+ ) {
15
+ return (
16
+ <HStack
17
+ ref={ref}
18
+ as="div"
19
+ overflowX={overflowX}
20
+ className={clsx(styles['main'], className, 'tcn-main')}
21
+ {...props}
22
+ >
23
+ {children}
24
+ </HStack>
25
+ );
26
+ });
@@ -0,0 +1,10 @@
1
+ @layer tcn-system {
2
+ :where(.rail-stack) {
3
+ width: 100%;
4
+ height: 100%;
5
+ overflow: auto;
6
+ :where(.tcn-body) {
7
+ height: 100%;
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,62 @@
1
+ import React from 'react';
2
+ import { clsx } from 'clsx';
3
+ import { Box, type BoxProps } from '../../stacks/box/box.js';
4
+ import type { Alignment } from '../../stacks/types/alignment.js';
5
+ import { HStack } from '../../stacks/h_stack.js';
6
+
7
+ // Styles
8
+ import styles from './rail.module.css';
9
+
10
+ export interface RailProps extends Omit<BoxProps, 'as'> {
11
+ vAlign?: Alignment;
12
+ hAlign?: Alignment;
13
+ }
14
+
15
+ // WIP: This component is not fully implemented.
16
+ export const Rail = React.forwardRef<HTMLElement, RailProps>(function Rail(
17
+ {
18
+ children,
19
+ width,
20
+ height = '100%',
21
+ minWidth,
22
+ maxWidth,
23
+ minHeight,
24
+ maxHeight,
25
+ hAlign = 'start',
26
+ vAlign = 'start',
27
+ className,
28
+ ...props
29
+ }: RailProps,
30
+ ref
31
+ ) {
32
+ return (
33
+ <Box
34
+ ref={ref}
35
+ width={width}
36
+ height={height}
37
+ minWidth={minWidth}
38
+ maxWidth={maxWidth}
39
+ minHeight={minHeight}
40
+ maxHeight={maxHeight}
41
+ data-h-alignment={hAlign}
42
+ data-v-alignment={vAlign}
43
+ className={clsx(className, 'tcn-rail')}
44
+ {...props}
45
+ >
46
+ <HStack
47
+ as="section"
48
+ minWidth={minWidth}
49
+ maxWidth={maxWidth}
50
+ minHeight={minHeight}
51
+ maxHeight={maxHeight}
52
+ hAlign={hAlign}
53
+ vAlign={vAlign}
54
+ ref={ref}
55
+ className={clsx(styles['rail-stack'], 'tcn-rail-stack')}
56
+ zIndex={0}
57
+ >
58
+ {children}
59
+ </HStack>
60
+ </Box>
61
+ );
62
+ });
@@ -0,0 +1,8 @@
1
+ @layer tcn-system {
2
+ :where(.side) {
3
+ min-width: 0;
4
+ height: 100%;
5
+ flex-grow: 0;
6
+ width: auto;
7
+ }
8
+ }
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { clsx } from 'clsx';
3
+ import { VStack, type VStackProps } from '../../../stacks/v_stack.js';
4
+
5
+ import styles from './side.module.css';
6
+
7
+ // UtilityBar
8
+ export interface SideProps extends Omit<VStackProps, 'as'> {}
9
+
10
+ export const Side = React.forwardRef<HTMLElement, SideProps>(function UtilityStrip(
11
+ { children, className, width = 'auto', ...props }: SideProps,
12
+ ref
13
+ ) {
14
+ return (
15
+ <VStack
16
+ ref={ref}
17
+ className={clsx(styles['side'], 'tcn-side', className)}
18
+ as="section"
19
+ width={width}
20
+ {...props}
21
+ >
22
+ {children}
23
+ </VStack>
24
+ );
25
+ });
@@ -0,0 +1,6 @@
1
+ @layer tcn-system {
2
+ :where(.utility-strip) {
3
+ height: 100%;
4
+ min-width: 0;
5
+ }
6
+ }
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import { clsx } from 'clsx';
3
+ import type { Hierarchy, Size } from '../../../utils/index.js';
4
+ import { VStack, type VStackProps } from '../../../stacks/v_stack.js';
5
+
6
+ import styles from './utility_strip.module.css';
7
+
8
+ // UtilityBar
9
+ export interface UtilityStripProps extends Omit<VStackProps, 'as'> {
10
+ hierarchy?: Hierarchy;
11
+ size?: Size;
12
+ }
13
+
14
+ export const UtilityStrip = React.forwardRef<HTMLElement, UtilityStripProps>(
15
+ function UtilityStrip(
16
+ {
17
+ children,
18
+ className,
19
+ width = 'auto',
20
+ hierarchy = 'secondary',
21
+ size = 'md',
22
+ ...props
23
+ }: UtilityStripProps,
24
+ ref
25
+ ) {
26
+ return (
27
+ <VStack
28
+ ref={ref}
29
+ as="header"
30
+ className={clsx(styles['utility-strip'], 'tcn-utility-strip', className)}
31
+ data-hierarchy={hierarchy}
32
+ data-size={size}
33
+ width={width}
34
+ {...props}
35
+ >
36
+ {children}
37
+ </VStack>
38
+ );
39
+ }
40
+ );
@@ -0,0 +1,29 @@
1
+ export interface BreakpointProps {
2
+ from?: number | string;
3
+ to?: number | string;
4
+ children: React.ReactNode;
5
+ }
6
+
7
+ export interface InternalBreakpointProps extends BreakpointProps {
8
+ width: number;
9
+ }
10
+
11
+ function toNumber(value: number | string) {
12
+ if (typeof value === 'number') {
13
+ return value;
14
+ }
15
+
16
+ return parseFloat(value);
17
+ }
18
+
19
+ export function Breakpoint(_: BreakpointProps) {
20
+ return null;
21
+ }
22
+
23
+ export function InternalBreakpoint(props: InternalBreakpointProps) {
24
+ const from = toNumber(props.from ?? 0);
25
+ const to = toNumber(props.to ?? Infinity);
26
+ const isWithinRange = props.width >= from && props.width < to;
27
+
28
+ return isWithinRange ? props.children : null;
29
+ }
@@ -0,0 +1,37 @@
1
+ import { HStack } from '../../stacks/h_stack.js';
2
+ import { Breakpoint } from './breakpoint.js';
3
+ import { Responsive } from './responsive.js';
4
+
5
+ export default {
6
+ title: 'Layouts/Responsive',
7
+ component: Responsive,
8
+ tags: ['autodocs'],
9
+ };
10
+
11
+ export function Container() {
12
+ return (
13
+ <HStack width="100%" hAlign="center">
14
+ <Responsive>
15
+ <Breakpoint to={200}>Small</Breakpoint>
16
+ <Breakpoint from={200} to={800}>
17
+ Medium
18
+ </Breakpoint>
19
+ <Breakpoint from={800}>Large</Breakpoint>
20
+ </Responsive>
21
+ </HStack>
22
+ );
23
+ }
24
+
25
+ export function Viewport() {
26
+ return (
27
+ <HStack width="100%" hAlign="center">
28
+ <Responsive on="viewport">
29
+ <Breakpoint to={200}>Small</Breakpoint>
30
+ <Breakpoint from={200} to={800}>
31
+ Medium
32
+ </Breakpoint>
33
+ <Breakpoint from={800}>Large</Breakpoint>
34
+ </Responsive>
35
+ </HStack>
36
+ );
37
+ }
@@ -0,0 +1,18 @@
1
+ import type { BreakpointProps } from './breakpoint.js';
2
+ import { ResponsiveContainer } from './responsive_container.js';
3
+ import { ResponsiveViewport } from './responsive_viewport.js';
4
+
5
+ export interface ResponsiveProps {
6
+ on?: 'viewport' | 'container';
7
+ children?: React.ReactElement<BreakpointProps>[] | React.ReactElement<BreakpointProps>;
8
+ }
9
+
10
+ export function Responsive(props: ResponsiveProps) {
11
+ const { on = 'container', children } = props;
12
+
13
+ if (on === 'viewport') {
14
+ return <ResponsiveViewport>{children}</ResponsiveViewport>;
15
+ }
16
+
17
+ return <ResponsiveContainer>{children}</ResponsiveContainer>;
18
+ }
@@ -0,0 +1,51 @@
1
+ import React, { useLayoutEffect, useState } from 'react';
2
+ import { useForkRef } from '../../utils/hooks/use_fork_ref.js';
3
+ import { useResizeObserver } from '../../utils/hooks/use_resize_observer.js';
4
+ import { InternalBreakpoint, BreakpointProps } from './breakpoint.js';
5
+
6
+ export interface ResponsiveContainerProps {
7
+ children?: React.ReactElement<BreakpointProps>[] | React.ReactElement<BreakpointProps>;
8
+ }
9
+
10
+ export function ResponsiveContainer(props: ResponsiveContainerProps) {
11
+ const [parent, setParent] = useState<Element | null>(null);
12
+ const [width, setWidth] = useState(0);
13
+
14
+ const resizeRef = useResizeObserver(width => {
15
+ setWidth(width);
16
+ });
17
+
18
+ const forkedRef = useForkRef((element: any) => {
19
+ if (element == null || element.parentElement == null) {
20
+ return;
21
+ }
22
+ resizeRef(element.parentElement);
23
+ setParent(element.parentElement);
24
+ });
25
+
26
+ const hiddenChild = (
27
+ <div
28
+ ref={forkedRef}
29
+ style={{
30
+ display: 'none',
31
+ }}
32
+ ></div>
33
+ );
34
+
35
+ const internalBreakpoints = React.Children.toArray(props.children).map((child: any) => {
36
+ return <InternalBreakpoint key={child.key} {...child.props} width={width} />;
37
+ });
38
+
39
+ useLayoutEffect(() => {
40
+ return () => {
41
+ setParent(null);
42
+ };
43
+ }, []);
44
+
45
+ return (
46
+ <>
47
+ {parent == null ? hiddenChild : null}
48
+ {internalBreakpoints}
49
+ </>
50
+ );
51
+ }
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { InternalBreakpoint, BreakpointProps } from './breakpoint.js';
3
+ import { useMediaQuery } from '../../utils/hooks/use_media_query.js';
4
+
5
+ export interface ResponsiveViewportProps {
6
+ children?: React.ReactElement<BreakpointProps>[] | React.ReactElement<BreakpointProps>;
7
+ }
8
+
9
+ export function ResponsiveViewport(props: ResponsiveViewportProps) {
10
+ const { width } = useMediaQuery();
11
+
12
+ const internalBreakpoints = React.Children.toArray(props.children).map((child: any) => {
13
+ return <InternalBreakpoint key={child.key} {...child.props} width={width} />;
14
+ });
15
+
16
+ return <>{internalBreakpoints}</>;
17
+ }