@tcn/ui 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) 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/form/field_presenters/field_presenter.d.ts +2 -2
  12. package/dist/form/field_presenters/field_presenter.d.ts.map +1 -1
  13. package/dist/form/field_presenters/field_presenter.js.map +1 -1
  14. package/dist/formatter-EIJCOSYU-DWmgEY3b.js +6 -0
  15. package/dist/{formatter-EIJCOSYU-D6nmx63h.js.map → formatter-EIJCOSYU-DWmgEY3b.js.map} +1 -1
  16. package/dist/inputs/color_input/color_input.js +10 -9
  17. package/dist/inputs/color_input/color_input.js.map +1 -1
  18. package/dist/inputs/date_picker/date_picker_header.js +7 -6
  19. package/dist/inputs/date_picker/date_picker_header.js.map +1 -1
  20. package/dist/inputs/date_picker/date_picker_input.js +3 -2
  21. package/dist/inputs/date_picker/date_picker_input.js.map +1 -1
  22. package/dist/inputs/date_picker/date_picker_time_selector.js +3 -2
  23. package/dist/inputs/date_picker/date_picker_time_selector.js.map +1 -1
  24. package/dist/inputs/date_picker/date_picker_year_input.js +6 -5
  25. package/dist/inputs/date_picker/date_picker_year_input.js.map +1 -1
  26. package/dist/inputs/date_picker/date_picker_year_selector.js +3 -2
  27. package/dist/inputs/date_picker/date_picker_year_selector.js.map +1 -1
  28. package/dist/inputs/multiselect/multiselect_inline_values.js +8 -7
  29. package/dist/inputs/multiselect/multiselect_inline_values.js.map +1 -1
  30. package/dist/inputs/multiselect/multiselect_values.js +3 -2
  31. package/dist/inputs/multiselect/multiselect_values.js.map +1 -1
  32. package/dist/inputs/phone_number_input/phone_number_input.js +44 -43
  33. package/dist/inputs/phone_number_input/phone_number_input.js.map +1 -1
  34. package/dist/inputs/select/select.js +3 -2
  35. package/dist/inputs/select/select.js.map +1 -1
  36. package/dist/inputs/suggestions/suggestion_list.js +3 -2
  37. package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
  38. package/dist/layouts/body/body.d.ts +6 -0
  39. package/dist/layouts/body/body.d.ts.map +1 -0
  40. package/dist/layouts/body/body.js +21 -0
  41. package/dist/layouts/body/body.js.map +1 -0
  42. package/dist/layouts/index.d.ts +5 -0
  43. package/dist/layouts/index.d.ts.map +1 -1
  44. package/dist/layouts/index.js +38 -22
  45. package/dist/layouts/index.js.map +1 -1
  46. package/dist/layouts/rail/main/main.d.ts +6 -0
  47. package/dist/layouts/rail/main/main.d.ts.map +1 -0
  48. package/dist/layouts/rail/main/main.js +21 -0
  49. package/dist/layouts/rail/main/main.js.map +1 -0
  50. package/dist/layouts/rail/rail.d.ts +9 -0
  51. package/dist/layouts/rail/rail.d.ts.map +1 -0
  52. package/dist/layouts/rail/rail.js +55 -0
  53. package/dist/layouts/rail/rail.js.map +1 -0
  54. package/dist/layouts/rail/side/side.d.ts +6 -0
  55. package/dist/layouts/rail/side/side.d.ts.map +1 -0
  56. package/dist/layouts/rail/side/side.js +21 -0
  57. package/dist/layouts/rail/side/side.js.map +1 -0
  58. package/dist/layouts/rail/utility_strip/utility_strip.d.ts +9 -0
  59. package/dist/layouts/rail/utility_strip/utility_strip.d.ts.map +1 -0
  60. package/dist/layouts/rail/utility_strip/utility_strip.js +32 -0
  61. package/dist/layouts/rail/utility_strip/utility_strip.js.map +1 -0
  62. package/dist/layouts/scaffold/scaffold.js +31 -31
  63. package/dist/layouts/scaffold/scaffold.js.map +1 -1
  64. package/dist/layouts/table/table.d.ts +27 -0
  65. package/dist/layouts/table/table.d.ts.map +1 -0
  66. package/dist/layouts/table/table.js +70 -0
  67. package/dist/layouts/table/table.js.map +1 -0
  68. package/dist/main.css +1 -0
  69. package/dist/navigation/tabs/primitives/tabs_list.d.ts.map +1 -1
  70. package/dist/navigation/tabs/primitives/tabs_list.js +61 -21
  71. package/dist/navigation/tabs/primitives/tabs_list.js.map +1 -1
  72. package/dist/navigation/tabs/state/link/tab_link.d.ts.map +1 -1
  73. package/dist/navigation/tabs/state/link/tab_link.js +20 -17
  74. package/dist/navigation/tabs/state/link/tab_link.js.map +1 -1
  75. package/dist/navigation/tabs/state/tab.d.ts.map +1 -1
  76. package/dist/navigation/tabs/state/tab.js +8 -3
  77. package/dist/navigation/tabs/state/tab.js.map +1 -1
  78. package/dist/rail.css +1 -0
  79. package/dist/scaffold.css +1 -1
  80. package/dist/{showcase-DK557szS.js → showcase-y9D3_Y8T.js} +3413 -3396
  81. package/dist/showcase-y9D3_Y8T.js.map +1 -0
  82. package/dist/side.css +1 -0
  83. package/dist/stacks/box/box.d.ts +2 -2
  84. package/dist/stacks/box/box.d.ts.map +1 -1
  85. package/dist/stacks/box/box.js.map +1 -1
  86. package/dist/stacks/story_components/style_box.d.ts +1 -1
  87. package/dist/stacks/story_components/style_box.d.ts.map +1 -1
  88. package/dist/surfaces/alert/alert.js +3 -2
  89. package/dist/surfaces/alert/alert.js.map +1 -1
  90. package/dist/surfaces/pop_confirm/pop_confirm.js +13 -2
  91. package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
  92. package/dist/{syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js → syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js} +2 -2
  93. package/dist/{syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js.map → syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js.map} +1 -1
  94. package/dist/table.css +1 -0
  95. package/dist/table.module-BtSxOntS.js +5 -0
  96. package/dist/table.module-BtSxOntS.js.map +1 -0
  97. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  98. package/dist/themes/themes/ergo/ergo_theme.js +179 -44
  99. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  100. package/dist/utility_strip.css +1 -0
  101. package/package.json +2 -2
  102. package/src/actions/index.ts +1 -0
  103. package/src/form/field_presenters/field_presenter.ts +3 -3
  104. package/src/layouts/__stories__/composed.stories.tsx +113 -0
  105. package/src/layouts/__stories__/composed_stories.module.css +142 -0
  106. package/src/layouts/__stories__/utils.tsx +174 -0
  107. package/src/layouts/body/body.module.css +11 -0
  108. package/src/layouts/body/body.tsx +23 -0
  109. package/src/layouts/index.ts +10 -0
  110. package/src/layouts/rail/__stories__/rail.stories.tsx +64 -0
  111. package/src/layouts/rail/__stories__/rail_stories.module.css +25 -0
  112. package/src/layouts/rail/main/main.module.css +7 -0
  113. package/src/layouts/rail/main/main.tsx +26 -0
  114. package/src/layouts/rail/rail.module.css +10 -0
  115. package/src/layouts/rail/rail.tsx +62 -0
  116. package/src/layouts/rail/side/side.module.css +8 -0
  117. package/src/layouts/rail/side/side.tsx +25 -0
  118. package/src/layouts/rail/utility_strip/utility_strip.module.css +6 -0
  119. package/src/layouts/rail/utility_strip/utility_strip.tsx +40 -0
  120. package/src/layouts/scaffold/__stories__/scaffold.stories.tsx +53 -0
  121. package/src/layouts/scaffold/__stories__/scaffold_stories.module.css +31 -0
  122. package/src/layouts/scaffold/scaffold.module.css +4 -0
  123. package/src/layouts/table/__stories__/mock_data.ts +420 -0
  124. package/src/layouts/table/__stories__/table.stories.tsx +326 -0
  125. package/src/layouts/table/__stories__/table_stories.module.css +30 -0
  126. package/src/layouts/table/table.module.css +37 -0
  127. package/src/layouts/table/table.tsx +132 -0
  128. package/src/navigation/tabs/primitives/tabs_list.tsx +46 -2
  129. package/src/navigation/tabs/state/link/tab_link.tsx +4 -1
  130. package/src/navigation/tabs/state/tab.tsx +10 -0
  131. package/src/stacks/box/box.tsx +1 -1
  132. package/src/surfaces/modal/__stories__/modal.stories.tsx +5 -5
  133. package/src/surfaces/panel/__stories__/panel.stories.tsx +114 -1
  134. package/src/surfaces/pop_confirm/pop_confirm.stories.tsx +4 -2
  135. package/src/themes/themes/ergo/ergo_theme.css +178 -43
  136. package/dist/formatter-EIJCOSYU-D6nmx63h.js +0 -6
  137. package/dist/showcase-DK557szS.js.map +0 -1
@@ -0,0 +1,113 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { VStack } from '../../stacks/v_stack.js';
3
+ import { SBNestedScaffold, SBContent, SBNestedRail } from './utils.js';
4
+
5
+ import styles from './composed_stories.module.css';
6
+ import clsx from 'clsx';
7
+ import { Body } from '../body/body.js';
8
+
9
+ const meta: Meta = {
10
+ title: 'Layouts/Composed',
11
+ component: () => <></>,
12
+ tags: ['autodocs'],
13
+ parameters: {
14
+ docs: {
15
+ description: {
16
+ component: 'Examples of nested layout compositions.',
17
+ },
18
+ },
19
+ },
20
+ };
21
+
22
+ export default meta;
23
+
24
+ type Story = StoryObj;
25
+
26
+ const SBContainer = ({ children }: { children: React.ReactNode }) => {
27
+ return (
28
+ <VStack height="100vh" width="100%" padding="16px" className={styles.sbContainer}>
29
+ {children}
30
+ </VStack>
31
+ );
32
+ };
33
+
34
+ export const Baseline: Story = {
35
+ render: () => (
36
+ <SBContainer>
37
+ <SBNestedScaffold depth={1}>
38
+ <SBNestedRail depth={2}>
39
+ <SBContent />
40
+ <SBContent />
41
+ <SBContent />
42
+ </SBNestedRail>
43
+ </SBNestedScaffold>
44
+ </SBContainer>
45
+ ),
46
+ };
47
+
48
+ export const ScaffoldWithBody: Story = {
49
+ render: () => (
50
+ <SBContainer>
51
+ <SBNestedScaffold depth={1}>
52
+ <SBContent />
53
+ <SBContent />
54
+ <SBContent />
55
+ </SBNestedScaffold>
56
+ </SBContainer>
57
+ ),
58
+ };
59
+
60
+ export const ScaffoldWithMain: Story = {
61
+ render: () => (
62
+ <SBContainer>
63
+ <SBNestedScaffold depth={1}>
64
+ <SBNestedRail depth={2} side={false} utilityStrip={false} scaffold={false}>
65
+ <SBContent />
66
+ <SBContent />
67
+ <SBContent />
68
+ </SBNestedRail>
69
+ </SBNestedScaffold>
70
+ </SBContainer>
71
+ ),
72
+ };
73
+
74
+ export const RailWithMain: Story = {
75
+ render: () => (
76
+ <SBContainer>
77
+ <SBNestedRail depth={1} scaffold={false}>
78
+ <SBContent />
79
+ <SBContent />
80
+ <SBContent />
81
+ </SBNestedRail>
82
+ </SBContainer>
83
+ ),
84
+ };
85
+
86
+ export const RailWithBody: Story = {
87
+ render: () => (
88
+ <SBContainer>
89
+ <SBNestedRail depth={1} scaffold={false}>
90
+ <Body className={clsx(styles.body, styles.secondary)}>
91
+ Body
92
+ <SBContent />
93
+ <SBContent />
94
+ <SBContent />
95
+ </Body>
96
+ </SBNestedRail>
97
+ </SBContainer>
98
+ ),
99
+ };
100
+
101
+ export const WithColumns: Story = {
102
+ render: () => (
103
+ <SBContainer>
104
+ <SBNestedScaffold depth={1} utilityBar={false} body={false} footer={false}>
105
+ <SBNestedRail depth={2} scaffold={false}>
106
+ <SBContent />
107
+ <SBContent />
108
+ <SBContent />
109
+ </SBNestedRail>
110
+ </SBNestedScaffold>
111
+ </SBContainer>
112
+ ),
113
+ };
@@ -0,0 +1,142 @@
1
+ /* Pastel Color Palette */
2
+ .sb-container {
3
+ /* Forest (5) - Greens & teals */
4
+ --pastel-forest-bg: #e8f5e9;
5
+ --pastel-forest-1: #a5d6a7;
6
+ --pastel-forest-2: #81c784;
7
+ --pastel-forest-3: #66bb6a;
8
+ --pastel-forest-4: #4caf50;
9
+
10
+ /* Sunset (5) - Warm peaches, corals & yellows */
11
+ --pastel-sunset-bg: #fff7e3;
12
+ --pastel-sunset-1: #f5c6a0;
13
+ --pastel-sunset-2: #eba985;
14
+ --pastel-sunset-3: #e08f6a;
15
+ --pastel-sunset-4: #d47550;
16
+
17
+ /* Berry (5) - Purples, lavenders & pinks */
18
+ --pastel-berry-bg: #f5eafa;
19
+ --pastel-berry-1: #e8d5f2;
20
+ --pastel-berry-2: #d4b8e8;
21
+ --pastel-berry-3: #c9a7e0;
22
+ --pastel-berry-4: #b78ed4;
23
+
24
+ color: white;
25
+ }
26
+
27
+ .secondary {
28
+ padding: 8px 16px;
29
+ }
30
+
31
+ .primary {
32
+ padding: 8px;
33
+ &[data-depth="1"] {
34
+ --bg: var(--pastel-sunset-bg);
35
+ --bg-1: var(--pastel-sunset-1);
36
+ --bg-2: var(--pastel-sunset-2);
37
+ --bg-3: var(--pastel-sunset-3);
38
+ --bg-4: var(--pastel-sunset-4);
39
+ }
40
+
41
+ &[data-depth="2"] {
42
+ --bg: var(--pastel-berry-bg);
43
+ --bg-1: var(--pastel-berry-1);
44
+ --bg-2: var(--pastel-berry-2);
45
+ --bg-3: var(--pastel-berry-3);
46
+ --bg-4: var(--pastel-berry-4);
47
+ }
48
+
49
+ &[data-depth="3"] {
50
+ --bg: var(--pastel-forest-bg);
51
+ --bg-1: var(--pastel-forest-1);
52
+ --bg-2: var(--pastel-forest-2);
53
+ --bg-3: var(--pastel-forest-3);
54
+ --bg-4: var(--pastel-forest-4);
55
+ }
56
+ }
57
+
58
+ /* Vertical Layouts */
59
+
60
+ .scaffold,
61
+ .rail {
62
+ background: var(--bg);
63
+ }
64
+
65
+ .header {
66
+ background: var(--bg-1);
67
+ }
68
+
69
+ .utilityBar {
70
+ background: var(--bg-2);
71
+ }
72
+
73
+ .footer {
74
+ background: var(--bg-3);
75
+ }
76
+
77
+ .body {
78
+ background: var(--bg-4);
79
+ gap: 8px;
80
+ }
81
+
82
+ /* Horizontal Layouts */
83
+ .utilityStrip {
84
+ background: var(--bg-1);
85
+ gap: 8px;
86
+ }
87
+
88
+ .side {
89
+ background: var(--bg-2);
90
+ }
91
+
92
+ .main {
93
+ background: var(--bg-3);
94
+ gap: 8px;
95
+ }
96
+
97
+ .content {
98
+ background: rgba(0, 0, 0, 0.25);
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: center;
102
+ height: 100%;
103
+ }
104
+
105
+ .action-box {
106
+ width: 16px;
107
+ height: 16px;
108
+ border: 2px solid rgba(0, 0, 0, 0.25);
109
+ padding: 4px;
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ border-radius: 4px;
114
+ }
115
+
116
+ .floating-label {
117
+ height: 0;
118
+ z-index: 2;
119
+ overflow: visible;
120
+ color: var(--font-color);
121
+ position: absolute;
122
+ top: 0;
123
+ left: 50%;
124
+ transform: translateX(-50%);
125
+ }
126
+
127
+ .floating-label-chip {
128
+ padding: 4px;
129
+ border-radius: 4px;
130
+ /* 100% bg at top → 75% opacity of bg at bottom so overlapping content shows through */
131
+ background: linear-gradient(
132
+ to bottom,
133
+ var(--bg) 0%,
134
+ color-mix(in srgb, var(--bg) 75%, transparent) 100%
135
+ );
136
+ color: var(--font-color);
137
+ }
138
+
139
+ .vertical-label {
140
+ writing-mode: vertical-rl;
141
+ text-orientation: mixed;
142
+ }
@@ -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,13 @@ 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
+
19
+ export { TTable, THead, TBody, TFoot, TR, TH, TD } from './table/table.js';
20
+
21
+ export { Rail, type RailProps } from './rail/rail.js';
22
+ export { Main, type MainProps } from './rail/main/main.js';
23
+ export { Side, type SideProps } from './rail/side/side.js';
24
+ export {
25
+ UtilityStrip,
26
+ type UtilityStripProps,
27
+ } 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
+ }