@tcn/ui 0.3.2 → 0.4.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 (207) hide show
  1. package/dist/Color-6BZIO3FS-CWWwv-fq.js +1004 -0
  2. package/dist/Color-6BZIO3FS-CWWwv-fq.js.map +1 -0
  3. package/dist/{WithTooltip-IO6J4KBT-B1oq93K5.js → WithTooltip-65CFNBJE-DvcUZizH.js} +4 -4
  4. package/dist/WithTooltip-65CFNBJE-DvcUZizH.js.map +1 -0
  5. package/dist/actions/__docs__/components/showcase.d.ts.map +1 -1
  6. package/dist/actions/__docs__/components/showcase.js +1 -1
  7. package/dist/actions/button/base_button/base_button.d.ts +2 -4
  8. package/dist/actions/button/base_button/base_button.d.ts.map +1 -1
  9. package/dist/actions/button/base_button/base_button.js +35 -35
  10. package/dist/actions/button/base_button/base_button.js.map +1 -1
  11. package/dist/actions/button/button/button.d.ts +7 -1
  12. package/dist/actions/button/button/button.d.ts.map +1 -1
  13. package/dist/actions/button/button/button.js +9 -7
  14. package/dist/actions/button/button/button.js.map +1 -1
  15. package/dist/actions/button/slim_button/slim_button.d.ts +6 -1
  16. package/dist/actions/button/slim_button/slim_button.d.ts.map +1 -1
  17. package/dist/actions/button/slim_button/slim_button.js +13 -14
  18. package/dist/actions/button/slim_button/slim_button.js.map +1 -1
  19. package/dist/actions/toggle/toggle.d.ts +9 -0
  20. package/dist/actions/toggle/toggle.d.ts.map +1 -0
  21. package/dist/actions/toggle/toggle.js +21 -0
  22. package/dist/actions/toggle/toggle.js.map +1 -0
  23. package/dist/date_picker_time_selector.css +1 -1
  24. package/dist/feedback/lazy/lazy.js +3 -3
  25. package/dist/form/field/common/field_error.js +16 -9
  26. package/dist/form/field/common/field_error.js.map +1 -1
  27. package/dist/formatter-EIJCOSYU-D6nmx63h.js +6 -0
  28. package/dist/formatter-EIJCOSYU-D6nmx63h.js.map +1 -0
  29. package/dist/input.css +1 -1
  30. package/dist/inputs/mask_input/mask.d.ts.map +1 -1
  31. package/dist/inputs/mask_input/mask.js.map +1 -1
  32. package/dist/inputs/multiselect/multiselect_inline_values.js +3 -2
  33. package/dist/inputs/multiselect/multiselect_inline_values.js.map +1 -1
  34. package/dist/inputs/multiselect/multiselect_values.js +3 -2
  35. package/dist/inputs/multiselect/multiselect_values.js.map +1 -1
  36. package/dist/layouts/index.d.ts +2 -1
  37. package/dist/layouts/index.d.ts.map +1 -1
  38. package/dist/layouts/index.js +20 -18
  39. package/dist/layouts/index.js.map +1 -1
  40. package/dist/layouts/row/row.d.ts +4 -0
  41. package/dist/layouts/row/row.d.ts.map +1 -0
  42. package/dist/layouts/row/row.js +11 -0
  43. package/dist/layouts/row/row.js.map +1 -0
  44. package/dist/layouts/section/heading.d.ts +7 -0
  45. package/dist/layouts/section/heading.d.ts.map +1 -0
  46. package/dist/layouts/section/heading.js +9 -0
  47. package/dist/layouts/section/heading.js.map +1 -0
  48. package/dist/layouts/section/section.d.ts +4 -0
  49. package/dist/layouts/section/section.d.ts.map +1 -0
  50. package/dist/layouts/section/section.js +22 -0
  51. package/dist/layouts/section/section.js.map +1 -0
  52. package/dist/navigation/index.d.ts +7 -0
  53. package/dist/navigation/index.d.ts.map +1 -0
  54. package/dist/navigation/index.js +17 -0
  55. package/dist/navigation/index.js.map +1 -0
  56. package/dist/navigation/tabs/primitives/tabs_bar.d.ts +7 -0
  57. package/dist/navigation/tabs/primitives/tabs_bar.d.ts.map +1 -0
  58. package/dist/navigation/tabs/primitives/tabs_bar.js +21 -0
  59. package/dist/navigation/tabs/primitives/tabs_bar.js.map +1 -0
  60. package/dist/navigation/tabs/primitives/tabs_list.d.ts +10 -0
  61. package/dist/navigation/tabs/primitives/tabs_list.d.ts.map +1 -0
  62. package/dist/navigation/tabs/primitives/tabs_list.js +29 -0
  63. package/dist/navigation/tabs/primitives/tabs_list.js.map +1 -0
  64. package/dist/navigation/tabs/state/context.d.ts +21 -0
  65. package/dist/navigation/tabs/state/context.d.ts.map +1 -0
  66. package/dist/navigation/tabs/state/context.js +34 -0
  67. package/dist/navigation/tabs/state/context.js.map +1 -0
  68. package/dist/navigation/tabs/state/link/tab_link.d.ts +9 -0
  69. package/dist/navigation/tabs/state/link/tab_link.d.ts.map +1 -0
  70. package/dist/navigation/tabs/state/link/tab_link.js +36 -0
  71. package/dist/navigation/tabs/state/link/tab_link.js.map +1 -0
  72. package/dist/navigation/tabs/state/link/use_tab_link.d.ts +5 -0
  73. package/dist/navigation/tabs/state/link/use_tab_link.d.ts.map +1 -0
  74. package/dist/navigation/tabs/state/link/use_tab_link.js +13 -0
  75. package/dist/navigation/tabs/state/link/use_tab_link.js.map +1 -0
  76. package/dist/navigation/tabs/state/nav_bar.d.ts +5 -0
  77. package/dist/navigation/tabs/state/nav_bar.d.ts.map +1 -0
  78. package/dist/navigation/tabs/state/nav_bar.js +36 -0
  79. package/dist/navigation/tabs/state/nav_bar.js.map +1 -0
  80. package/dist/navigation/tabs/state/tab.d.ts +6 -0
  81. package/dist/navigation/tabs/state/tab.d.ts.map +1 -0
  82. package/dist/navigation/tabs/state/tab.js +6 -0
  83. package/dist/navigation/tabs/state/tab.js.map +1 -0
  84. package/dist/overlay/carrot/base_carrot.d.ts +8 -0
  85. package/dist/overlay/carrot/base_carrot.d.ts.map +1 -0
  86. package/dist/overlay/carrot/base_carrot.js +21 -0
  87. package/dist/overlay/carrot/base_carrot.js.map +1 -0
  88. package/dist/overlay/portal/portal_platform.d.ts.map +1 -1
  89. package/dist/overlay/portal/portal_platform.js +3 -3
  90. package/dist/overlay/portal/portal_platform.js.map +1 -1
  91. package/dist/row.css +1 -0
  92. package/dist/section.css +1 -0
  93. package/dist/section.module-0wyGkhDg.js +5 -0
  94. package/dist/section.module-0wyGkhDg.js.map +1 -0
  95. package/dist/{showcase-WfP6kBEb.js → showcase-DK557szS.js} +18018 -16269
  96. package/dist/showcase-DK557szS.js.map +1 -0
  97. package/dist/surfaces/pop_confirm/pop_confirm.js +4 -3
  98. package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
  99. package/dist/{syntaxhighlighter-IQDEPFLK-BX_eF8__.js → syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js} +54 -54
  100. package/dist/syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js.map +1 -0
  101. package/dist/tabs_bar.css +1 -0
  102. package/dist/textarea.css +1 -1
  103. package/dist/theme_provider.css +1 -0
  104. package/dist/theme_provider.module-ChZQ5Xsk.js +5 -0
  105. package/dist/theme_provider.module-ChZQ5Xsk.js.map +1 -0
  106. package/dist/themes/stylesheets/reset.css +1 -1
  107. package/dist/themes/stylesheets/reset.js +1 -0
  108. package/dist/themes/stylesheets/reset.js.map +1 -1
  109. package/dist/themes/theme.d.ts +3 -2
  110. package/dist/themes/theme.d.ts.map +1 -1
  111. package/dist/themes/theme.js +20 -10
  112. package/dist/themes/theme.js.map +1 -1
  113. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  114. package/dist/themes/themes/ergo/ergo_theme.d.ts.map +1 -1
  115. package/dist/themes/themes/ergo/ergo_theme.js +488 -238
  116. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  117. package/dist/themes/themes/windows_98/windows_98.css +1 -1
  118. package/dist/themes/themes/windows_98/windows_98_theme.js +149 -4
  119. package/dist/themes/themes/windows_98/windows_98_theme.js.map +1 -1
  120. package/dist/tokens/bubble/bubble.js +31 -24
  121. package/dist/tokens/bubble/bubble.js.map +1 -1
  122. package/dist/tokens/chip/chip.js +15 -8
  123. package/dist/tokens/chip/chip.js.map +1 -1
  124. package/dist/tokens/index.d.ts +2 -0
  125. package/dist/tokens/index.d.ts.map +1 -1
  126. package/dist/tokens/index.js +5 -1
  127. package/dist/tokens/index.js.map +1 -1
  128. package/dist/tokens/key/key.d.ts +3 -0
  129. package/dist/tokens/key/key.d.ts.map +1 -0
  130. package/dist/tokens/key/key.js +8 -0
  131. package/dist/tokens/key/key.js.map +1 -0
  132. package/dist/tokens/value/value.d.ts +3 -0
  133. package/dist/tokens/value/value.d.ts.map +1 -0
  134. package/dist/tokens/value/value.js +8 -0
  135. package/dist/tokens/value/value.js.map +1 -0
  136. package/dist/utils/css_utils.d.ts +9 -0
  137. package/dist/utils/css_utils.d.ts.map +1 -0
  138. package/dist/utils/css_utils.js +45 -0
  139. package/dist/utils/css_utils.js.map +1 -0
  140. package/package.json +8 -1
  141. package/src/actions/__docs__/actions.mdx +159 -34
  142. package/src/actions/__docs__/actions.stories.tsx +416 -101
  143. package/src/actions/__docs__/components/showcase.tsx +10 -6
  144. package/src/actions/button/__stories__/button.stories.tsx +10 -0
  145. package/src/actions/button/__stories__/toggle.stories.tsx +177 -0
  146. package/src/actions/button/base_button/base_button.tsx +8 -10
  147. package/src/actions/button/button/button.tsx +11 -2
  148. package/src/actions/button/slim_button/slim_button.tsx +20 -13
  149. package/src/actions/toggle/toggle.tsx +26 -0
  150. package/src/inputs/date_picker/date_picker_time_selector.module.css +0 -1
  151. package/src/inputs/input/input.module.css +0 -1
  152. package/src/inputs/mask_input/mask.ts +7 -1
  153. package/src/inputs/textarea/textarea.module.css +0 -1
  154. package/src/layouts/index.ts +3 -2
  155. package/src/layouts/row/row.module.css +5 -0
  156. package/src/layouts/row/row.tsx +15 -0
  157. package/src/layouts/section/__stories__/section.stories.module.css +6 -0
  158. package/src/layouts/section/__stories__/section.stories.tsx +152 -0
  159. package/src/layouts/section/heading.tsx +16 -0
  160. package/src/layouts/section/section.module.css +41 -0
  161. package/src/layouts/section/section.tsx +21 -0
  162. package/src/navigation/index.ts +18 -0
  163. package/src/navigation/tabs/__stories__/state.stories.tsx +136 -0
  164. package/src/navigation/tabs/__stories__/tabs.stories.tsx +40 -0
  165. package/src/navigation/tabs/primitives/tabs_bar.module.css +13 -0
  166. package/src/navigation/tabs/primitives/tabs_bar.tsx +25 -0
  167. package/src/navigation/tabs/primitives/tabs_list.tsx +41 -0
  168. package/src/navigation/tabs/state/context.tsx +61 -0
  169. package/src/navigation/tabs/state/link/tab_link.tsx +45 -0
  170. package/src/navigation/tabs/state/link/use_tab_link.ts +17 -0
  171. package/src/navigation/tabs/state/nav_bar.tsx +37 -0
  172. package/src/navigation/tabs/state/tab.tsx +12 -0
  173. package/src/overlay/carrot/base_carrot.tsx +24 -0
  174. package/src/overlay/carrot/carrot.stories.tsx +54 -0
  175. package/src/overlay/portal/portal_platform.tsx +1 -0
  176. package/src/surfaces/card/card.stories.tsx +14 -14
  177. package/src/surfaces/modal/__stories__/modal.stories.tsx +19 -8
  178. package/src/surfaces/window/window.stories.tsx +16 -10
  179. package/src/themes/stylesheets/reset.css +1 -0
  180. package/src/themes/theme.tsx +13 -4
  181. package/src/themes/theme_provider.module.css +6 -0
  182. package/src/themes/themes/ergo/__stories__/components/material_picker/sb_inverted_materials.module.css +4 -4
  183. package/src/themes/themes/ergo/__stories__/components/tone_picker/sb_tone_picker.module.css +3 -0
  184. package/src/themes/themes/ergo/__stories__/components/tone_picker/sb_tone_picker.tsx +5 -2
  185. package/src/themes/themes/ergo/__stories__/material.stories.tsx +2 -2
  186. package/src/themes/themes/ergo/__stories__/sb_materials.module.css +31 -26
  187. package/src/themes/themes/ergo/ergo_theme.css +484 -235
  188. package/src/themes/themes/ergo/ergo_theme.ts +1 -0
  189. package/src/themes/themes/windows_98/windows_98.css +149 -4
  190. package/src/tokens/index.ts +2 -0
  191. package/src/tokens/key/key.tsx +10 -0
  192. package/src/tokens/value/value.tsx +10 -0
  193. package/src/utils/css_utils.ts +64 -0
  194. package/tsconfig.json +6 -0
  195. package/dist/Color-ASIRERSW-B4GaVKuQ.js +0 -990
  196. package/dist/Color-ASIRERSW-B4GaVKuQ.js.map +0 -1
  197. package/dist/WithTooltip-IO6J4KBT-B1oq93K5.js.map +0 -1
  198. package/dist/formatter-QJ4M4OGQ-DaIl2Wi_.js +0 -6
  199. package/dist/formatter-QJ4M4OGQ-DaIl2Wi_.js.map +0 -1
  200. package/dist/layouts/list/section_header.d.ts +0 -6
  201. package/dist/layouts/list/section_header.d.ts.map +0 -1
  202. package/dist/layouts/list/section_header.js +0 -22
  203. package/dist/layouts/list/section_header.js.map +0 -1
  204. package/dist/showcase-WfP6kBEb.js.map +0 -1
  205. package/dist/syntaxhighlighter-IQDEPFLK-BX_eF8__.js.map +0 -1
  206. package/src/layouts/list/section_header.module.css +0 -20
  207. package/src/layouts/list/section_header.tsx +0 -21
@@ -0,0 +1,18 @@
1
+ // Stateful Components
2
+ export { Tabs, useTabs, type TabsProps, type TabsState } from './tabs/state/context.js';
3
+ export {
4
+ TabLink,
5
+ type TabLinkProps,
6
+ type TabLinkOwnProps,
7
+ } from './tabs/state/link/tab_link.js';
8
+ export { Tab, type TabProps } from './tabs/state/tab.js';
9
+ export { TabsNavbar, type TabsNavbarProps } from './tabs/state/nav_bar.js';
10
+
11
+ // Primitive Components
12
+ export { TabsBar, type TabsBarProps } from './tabs/primitives/tabs_bar.js';
13
+ export {
14
+ TabsList,
15
+ TabItem,
16
+ type TabsListProps,
17
+ type TabItemProps,
18
+ } from './tabs/primitives/tabs_list.js';
@@ -0,0 +1,136 @@
1
+ import { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { useState } from 'react';
3
+ import { Tabs } from '../state/context.js';
4
+ import { TabLink } from '../state/link/tab_link.js';
5
+ import { Tab } from '../state/tab.js';
6
+ import { HStack } from '../../../stacks/h_stack.js';
7
+ import { VStack } from '../../../stacks/v_stack.js';
8
+ import { TabsNavbar } from '../state/nav_bar.js';
9
+
10
+ const meta: Meta = {
11
+ title: 'Navigation/Tabs/Stateful',
12
+ tags: ['autodocs'],
13
+ };
14
+
15
+ export default meta;
16
+
17
+ type Story = StoryObj;
18
+
19
+ type ColorTab = 'coral' | 'teal' | 'violet' | 'opalescent';
20
+
21
+ const ColorPanel = ({
22
+ color,
23
+ label,
24
+ description,
25
+ }: {
26
+ color: string;
27
+ label: string;
28
+ description: string;
29
+ }) => (
30
+ <VStack
31
+ role="tabpanel"
32
+ hAlign="center"
33
+ vAlign="center"
34
+ padding="32px"
35
+ minHeight="200px"
36
+ style={{
37
+ borderRadius: 12,
38
+ background: color,
39
+ }}
40
+ >
41
+ <span style={{ fontSize: 24, fontWeight: 700, color: 'white' }}>{label}</span>
42
+ <span style={{ fontSize: 14, color: 'rgba(255,255,255,0.85)', marginTop: 8 }}>
43
+ {description}
44
+ </span>
45
+ </VStack>
46
+ );
47
+
48
+ interface TabsDemoProps {
49
+ variant?: 'inline';
50
+ minItemWidth?: number;
51
+ }
52
+
53
+ const TabsDemo = ({ variant, minItemWidth }: TabsDemoProps) => {
54
+ const [currentTab, setCurrentTab] = useState<ColorTab>('coral');
55
+
56
+ const isInline = variant === 'inline';
57
+
58
+ return (
59
+ <Tabs
60
+ value={currentTab}
61
+ onChange={v => setCurrentTab(v as ColorTab)}
62
+ minItemWidth={minItemWidth}
63
+ >
64
+ <VStack minWidth="400px" gap="8px">
65
+ <HStack
66
+ hAlign={isInline ? 'center' : 'start'}
67
+ gap={isInline ? 'small' : undefined}
68
+ >
69
+ <TabsNavbar variant={variant}>
70
+ <TabLink value="coral">Coral</TabLink>
71
+ <TabLink value="teal">Teal</TabLink>
72
+ <TabLink value="violet">Violet</TabLink>
73
+ <TabLink value="opalescent">Opalescent Periwinkle</TabLink>
74
+ </TabsNavbar>
75
+ </HStack>
76
+
77
+ <Tab value="coral">
78
+ <ColorPanel color="#FF6B6B" label="Coral" description="Warm and energetic" />
79
+ </Tab>
80
+
81
+ <Tab value="teal">
82
+ <ColorPanel color="#20B2AA" label="Teal" description="Calm and balanced" />
83
+ </Tab>
84
+
85
+ <Tab value="violet">
86
+ <ColorPanel
87
+ color="#9B59B6"
88
+ label="Violet"
89
+ description="Creative and mysterious"
90
+ />
91
+ </Tab>
92
+
93
+ <Tab value="opalescent">
94
+ <ColorPanel
95
+ color="#C7C9E8"
96
+ label="Opalescent Periwinkle"
97
+ description="Soft, luminous and serene"
98
+ />
99
+ </Tab>
100
+ </VStack>
101
+ </Tabs>
102
+ );
103
+ };
104
+
105
+ export const Baseline: Story = {
106
+ render: () => {
107
+ const [currentTab, setCurrentTab] = useState('1');
108
+ return (
109
+ <Tabs value={currentTab} onChange={v => setCurrentTab(v)}>
110
+ <TabsNavbar>
111
+ <TabLink value="1">One</TabLink>
112
+ <TabLink value="2">Two</TabLink>
113
+ <TabLink value="3">Three</TabLink>
114
+ <TabLink value="4">Four</TabLink>
115
+ </TabsNavbar>
116
+
117
+ <Tab value="1">Page One</Tab>
118
+ <Tab value="2">Page Two</Tab>
119
+ <Tab value="3">Page Three</Tab>
120
+ <Tab value="4">Page Four</Tab>
121
+ </Tabs>
122
+ );
123
+ },
124
+ };
125
+
126
+ export const MinItemWidth: Story = {
127
+ render: () => <TabsDemo minItemWidth={100} />,
128
+ };
129
+
130
+ export const InlineVariant: Story = {
131
+ render: () => <TabsDemo variant="inline" minItemWidth={100} />,
132
+ };
133
+
134
+ export const AutoWidth: Story = {
135
+ render: () => <TabsDemo />,
136
+ };
@@ -0,0 +1,40 @@
1
+ import { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { TabsList } from '../primitives/tabs_list.js';
3
+ import { TabItem } from '../primitives/tabs_list.js';
4
+ import { TabsBar } from '../primitives/tabs_bar.js';
5
+ import { Spacer } from '../../../stacks/spacer.js';
6
+ import { Bubble } from '../../../tokens/bubble/bubble.js';
7
+
8
+ const meta: Meta = {
9
+ title: 'Navigation/Tabs/Component',
10
+ tags: ['autodocs'],
11
+ };
12
+
13
+ export default meta;
14
+
15
+ type Story = StoryObj;
16
+
17
+ const TabDemo = () => {
18
+ return (
19
+ <TabsBar>
20
+ <TabsList>
21
+ <TabItem width={100}>Tab One</TabItem>
22
+ <TabItem width={100} selected>
23
+ Tab Two
24
+ </TabItem>
25
+ <TabItem width={100}>Tab Three</TabItem>
26
+ <TabItem width={100}>
27
+ Custom Label
28
+ <Spacer width="4px" />
29
+ <Bubble size="sm" backgroundColor="#e0383e" textColor="#fff">
30
+ 10
31
+ </Bubble>
32
+ </TabItem>
33
+ </TabsList>
34
+ </TabsBar>
35
+ );
36
+ };
37
+
38
+ export const Default: Story = {
39
+ render: () => <TabDemo />,
40
+ };
@@ -0,0 +1,13 @@
1
+ @layer tcn-system {
2
+ .tabs-bar {
3
+ width: auto;
4
+ }
5
+
6
+ .tabs-bar[data-variant="inline"] {
7
+ width: auto;
8
+ }
9
+
10
+ .tabs-bar[data-variant="default"] {
11
+ width: 100%;
12
+ }
13
+ }
@@ -0,0 +1,25 @@
1
+ import { type FC, type PropsWithChildren } from 'react';
2
+ import clsx from 'clsx';
3
+ import { HStack, type HStackProps } from '../../../stacks/h_stack.js';
4
+ import styles from './tabs_bar.module.css';
5
+
6
+ export interface TabsBarProps extends HStackProps {
7
+ variant?: 'default' | 'inline';
8
+ }
9
+
10
+ export const TabsBar: FC<PropsWithChildren<TabsBarProps>> = ({
11
+ children,
12
+ className,
13
+ variant = 'default',
14
+ ...props
15
+ }) => {
16
+ return (
17
+ <HStack
18
+ data-variant={variant}
19
+ className={clsx('tcn-tabs-bar', styles['tabs-bar'], className)}
20
+ {...props}
21
+ >
22
+ {children}
23
+ </HStack>
24
+ );
25
+ };
@@ -0,0 +1,41 @@
1
+ import { forwardRef, type FC, type PropsWithChildren } from 'react';
2
+ import { type BaseButtonProps } from '../../../actions/index.js';
3
+ import { HStack, type HStackProps } from '../../../stacks/h_stack.js';
4
+ import clsx from 'clsx';
5
+ import { Toggle } from '../../../actions/toggle/toggle.js';
6
+
7
+ export type TabsListProps = HStackProps;
8
+
9
+ export const TabsList: FC<PropsWithChildren<TabsListProps>> = ({
10
+ children,
11
+ className,
12
+ role = 'tablist',
13
+ as = 'menu',
14
+ ...props
15
+ }) => {
16
+ return (
17
+ <HStack as={as} role={role} className={clsx('tcn-tabs-list', className)} {...props}>
18
+ {children}
19
+ </HStack>
20
+ );
21
+ };
22
+
23
+ export interface TabItemProps extends Omit<BaseButtonProps, 'hierarchy'> {
24
+ selected?: boolean;
25
+ }
26
+
27
+ export const TabItem = forwardRef<HTMLButtonElement, PropsWithChildren<TabItemProps>>(
28
+ ({ children, className, role = 'tab', selected = false, ...props }, ref) => {
29
+ return (
30
+ <Toggle
31
+ ref={ref}
32
+ role={role}
33
+ className={clsx(className, 'tcn-interactive', 'tcn-tab-item')}
34
+ selected={selected}
35
+ {...props}
36
+ >
37
+ {children}
38
+ </Toggle>
39
+ );
40
+ }
41
+ );
@@ -0,0 +1,61 @@
1
+ import {
2
+ createContext,
3
+ useState,
4
+ useContext,
5
+ useMemo,
6
+ type FC,
7
+ type PropsWithChildren,
8
+ } from 'react';
9
+ import type { Rectangle } from '../../../utils/index.js';
10
+
11
+ export interface TabsState {
12
+ value: string;
13
+ onChange?: (value: string) => void;
14
+ minItemWidth?: number;
15
+ maxItemWidth?: number;
16
+ }
17
+
18
+ export interface TabsContextValue extends TabsState {
19
+ activeTrigger: Rectangle | null;
20
+ setActiveTrigger: (trigger: Rectangle) => void;
21
+ }
22
+
23
+ const TabsContext = createContext<TabsContextValue | null>(null);
24
+
25
+ export function useTabs(): TabsContextValue {
26
+ const context = useContext(TabsContext);
27
+ if (!context) {
28
+ throw new Error('useTabs must be used within a Tabs provider');
29
+ }
30
+ return context;
31
+ }
32
+
33
+ export interface TabsProps {
34
+ value: string;
35
+ onChange?: (value: string) => void;
36
+ minItemWidth?: number;
37
+ maxItemWidth?: number;
38
+ }
39
+
40
+ export const Tabs: FC<PropsWithChildren<TabsProps>> = ({
41
+ value,
42
+ onChange,
43
+ children,
44
+ minItemWidth,
45
+ maxItemWidth,
46
+ }) => {
47
+ const [activeTrigger, setActiveTrigger] = useState<Rectangle | null>(null);
48
+ const contextValue = useMemo(
49
+ () => ({
50
+ value,
51
+ onChange,
52
+ activeTrigger,
53
+ setActiveTrigger,
54
+ minItemWidth,
55
+ maxItemWidth,
56
+ }),
57
+ [value, onChange, activeTrigger, minItemWidth, maxItemWidth]
58
+ );
59
+
60
+ return <TabsContext.Provider value={contextValue}>{children}</TabsContext.Provider>;
61
+ };
@@ -0,0 +1,45 @@
1
+ import { forwardRef, useCallback, type PropsWithChildren } from 'react';
2
+ import { TabItem, type TabItemProps } from '../../primitives/tabs_list.js';
3
+ import { useForkRef } from '../../../../utils/index.js';
4
+ import { useTabs } from '../context.js';
5
+ import { useTabLink } from './use_tab_link.js';
6
+
7
+ export interface TabLinkOwnProps {
8
+ value: string;
9
+ }
10
+
11
+ export interface TabLinkProps
12
+ extends Omit<TabItemProps, 'selected' | 'value'>,
13
+ TabLinkOwnProps {}
14
+
15
+ export const TabLink = forwardRef<HTMLButtonElement, PropsWithChildren<TabLinkProps>>(
16
+ ({ children, value, onClick, minWidth, maxWidth, ...props }, forwardedRef) => {
17
+ const { ref: internalRef, isMatch } = useTabLink(value);
18
+ const state = useTabs();
19
+ const ref = useForkRef(internalRef, forwardedRef);
20
+
21
+ const handleClick = useCallback(
22
+ (event: React.MouseEvent<HTMLButtonElement>) => {
23
+ state.onChange?.(value);
24
+ onClick?.(event);
25
+ },
26
+ [state, value, onClick]
27
+ );
28
+
29
+ const pickMinWidth = state.minItemWidth ?? minWidth;
30
+ const pickMaxWidth = state.maxItemWidth ?? maxWidth;
31
+
32
+ return (
33
+ <TabItem
34
+ ref={ref}
35
+ selected={isMatch}
36
+ onClick={handleClick}
37
+ minWidth={pickMinWidth}
38
+ maxWidth={pickMaxWidth}
39
+ {...props}
40
+ >
41
+ {children}
42
+ </TabItem>
43
+ );
44
+ }
45
+ );
@@ -0,0 +1,17 @@
1
+ import { useLayoutEffect } from 'react';
2
+ import { useTabs } from '../context.js';
3
+ import { useTrackActiveItemRectangle } from '../../../../utils/css_utils.js';
4
+
5
+ export function useTabLink(value: string) {
6
+ const state = useTabs();
7
+ const isMatch = state.value === value;
8
+ const { ref, rectangle } = useTrackActiveItemRectangle(isMatch);
9
+
10
+ useLayoutEffect(() => {
11
+ if (rectangle) {
12
+ state.setActiveTrigger(rectangle);
13
+ }
14
+ }, [rectangle, state.setActiveTrigger]);
15
+
16
+ return { ref, isMatch };
17
+ }
@@ -0,0 +1,37 @@
1
+ import { type FC, type PropsWithChildren } from 'react';
2
+ import clsx from 'clsx';
3
+ import { TabsBar, type TabsBarProps } from '../primitives/tabs_bar.js';
4
+ import { TabsList } from '../primitives/tabs_list.js';
5
+ import { useTabs } from './context.js';
6
+ import { convertRectangleToCssVariables } from '../../../utils/css_utils.js';
7
+
8
+ export type TabsNavbarProps = TabsBarProps;
9
+
10
+ export const TabsNavbar: FC<PropsWithChildren<TabsNavbarProps>> = ({
11
+ children,
12
+ className,
13
+ variant = 'default',
14
+ style,
15
+ ...props
16
+ }) => {
17
+ const state = useTabs();
18
+ const cssVariables = convertRectangleToCssVariables(
19
+ 'tabs',
20
+ 'active',
21
+ state.activeTrigger
22
+ );
23
+ const finalStyle = {
24
+ ...cssVariables,
25
+ ...style,
26
+ };
27
+ return (
28
+ <TabsBar
29
+ style={finalStyle}
30
+ className={clsx('tcn-tabs-navbar', className)}
31
+ variant={variant}
32
+ {...props}
33
+ >
34
+ <TabsList>{children}</TabsList>
35
+ </TabsBar>
36
+ );
37
+ };
@@ -0,0 +1,12 @@
1
+ import type { FC, PropsWithChildren } from 'react';
2
+ import { useTabs } from './context.js';
3
+
4
+ export interface TabProps {
5
+ value: string;
6
+ }
7
+
8
+ export const Tab: FC<PropsWithChildren<TabProps>> = ({ value, children }) => {
9
+ const state = useTabs();
10
+ if (state.value !== value) return null;
11
+ return children;
12
+ };
@@ -0,0 +1,24 @@
1
+ import clsx from 'clsx';
2
+ import { Box, type BoxProps } from '../../stacks/box/box.js';
3
+
4
+ export interface BaseCarrotOwnProps {
5
+ direction: 'top' | 'bottom' | 'start' | 'end';
6
+ }
7
+
8
+ export interface BaseCarrotProps extends BaseCarrotOwnProps, BoxProps {}
9
+
10
+ export const BaseCarrot = ({
11
+ direction,
12
+ className,
13
+ as = 'span',
14
+ ...rest
15
+ }: BaseCarrotProps) => {
16
+ return (
17
+ <Box
18
+ as="span"
19
+ data-direction={direction}
20
+ className={clsx('tcn-base-carrot', className)}
21
+ {...rest}
22
+ />
23
+ );
24
+ };
@@ -0,0 +1,54 @@
1
+ import type { StoryObj } from '@storybook/react-vite';
2
+ import { Box } from '../../stacks/index.js';
3
+ import { VStack } from '../../stacks/v_stack.js';
4
+ import { BaseCarrot } from './base_carrot.js';
5
+
6
+ export default {
7
+ title: 'Overlays/Carrot',
8
+ component: BaseCarrot,
9
+ tags: ['autodocs'],
10
+ };
11
+
12
+ interface CarrotStoryProps {
13
+ direction: 'top' | 'bottom' | 'start' | 'end';
14
+ }
15
+
16
+ const CarrotStory = ({ direction }: CarrotStoryProps) => {
17
+ return (
18
+ <VStack
19
+ minWidth="100px"
20
+ minHeight="100px"
21
+ height="100%"
22
+ style={{ backgroundColor: 'gray' }}
23
+ >
24
+ <Box width="100px" height="100px" padding="24px" style={{ backgroundColor: 'red' }}>
25
+ <BaseCarrot direction={direction} />
26
+ </Box>
27
+ </VStack>
28
+ );
29
+ };
30
+
31
+ export const Top: StoryObj<CarrotStoryProps> = {
32
+ render: args => <CarrotStory {...args} />,
33
+ args: {
34
+ direction: 'top',
35
+ },
36
+ };
37
+ export const Bottom: StoryObj<CarrotStoryProps> = {
38
+ render: args => <CarrotStory {...args} />,
39
+ args: {
40
+ direction: 'bottom',
41
+ },
42
+ };
43
+ export const Start: StoryObj<CarrotStoryProps> = {
44
+ render: args => <CarrotStory {...args} />,
45
+ args: {
46
+ direction: 'start',
47
+ },
48
+ };
49
+ export const End: StoryObj<CarrotStoryProps> = {
50
+ render: args => <CarrotStory {...args} />,
51
+ args: {
52
+ direction: 'end',
53
+ },
54
+ };
@@ -51,6 +51,7 @@ export class PortalPlatform {
51
51
  const portalPlatform = this._window.document.createElement('div');
52
52
  portalPlatform.id = 'tcn-portal-platform';
53
53
  portalPlatform.classList.add('tcn-portal-platform');
54
+ portalPlatform.classList.add('tcn-theme-root');
54
55
  root.appendChild(portalPlatform);
55
56
  root.classList.add('tcn-platform-root');
56
57
 
@@ -5,7 +5,7 @@ import { VBody } from '../../layouts/body/v_body.js';
5
5
  import { UtilityBar } from '../../layouts/utility_bar/utility_bar.js';
6
6
  import { Box, Spacer } from '../../stacks/index.js';
7
7
  import { Title } from '../../typography/title/title.js';
8
- import { SlimButton } from '../../actions/index.js';
8
+ import { Button } from '../../actions/index.js';
9
9
  import { Card } from './card.js';
10
10
 
11
11
  // Styles
@@ -24,28 +24,28 @@ export const Default = () => {
24
24
  <Header>
25
25
  <Title>Card Header</Title>
26
26
  <Spacer />
27
- <SlimButton hierarchy="tertiary">
27
+ <Button utility hierarchy="tertiary">
28
28
  <GridOneIcon />
29
- </SlimButton>
30
- <SlimButton hierarchy="tertiary">
29
+ </Button>
30
+ <Button utility hierarchy="secondary">
31
31
  <GridOneIcon />
32
- </SlimButton>
32
+ </Button>
33
+ <Button utility hierarchy="primary">
34
+ <GridOneIcon />
35
+ </Button>
33
36
  </Header>
34
37
  <UtilityBar>
35
38
  <Title>Utility Bar</Title>
36
39
  <Spacer />
37
- <SlimButton hierarchy="tertiary">
38
- <BugIcon />
39
- </SlimButton>
40
- <SlimButton hierarchy="tertiary">
40
+ <Button utility hierarchy="tertiary">
41
41
  <BugIcon />
42
- </SlimButton>
43
- <SlimButton size="md" hierarchy="tertiary">
42
+ </Button>
43
+ <Button utility hierarchy="secondary">
44
44
  <BugIcon />
45
- </SlimButton>
46
- <SlimButton hierarchy="tertiary">
45
+ </Button>
46
+ <Button utility size="md" hierarchy="primary">
47
47
  <BugIcon />
48
- </SlimButton>
48
+ </Button>
49
49
  </UtilityBar>
50
50
 
51
51
  <VBody>
@@ -1,5 +1,5 @@
1
1
  import { useState } from 'react';
2
- import { Button, SlimButton } from '../../../actions/index.js';
2
+ import { Button } from '../../../actions/index.js';
3
3
  import { Footer, Header, UtilityBar, VBody } from '../../../layouts/index.js';
4
4
  import { ZStack } from '../../../stacks/z_stack.js';
5
5
  import { BodyText, Title } from '../../../typography/index.js';
@@ -23,25 +23,36 @@ export const ModalStory = () => {
23
23
 
24
24
  return (
25
25
  <ZStack height="100%" width="100%" minHeight="600px">
26
- <button onClick={toggle}>{isOpen ? 'Close' : 'Open'}</button>
26
+ <Button hierarchy="secondary" onClick={toggle}>
27
+ {isOpen ? 'Close' : 'Open'}
28
+ </Button>
27
29
 
28
30
  <Modal isOpen={isOpen} width="400px" height="500px">
29
31
  <Header>
30
32
  <Title>Modal Title</Title>
31
33
  <Spacer />
32
- <SlimButton hierarchy="tertiary" size="md" onClick={toggle}>
34
+ <Button utility hierarchy="tertiary" size="md" onClick={toggle}>
33
35
  <CrossIcon />
34
- </SlimButton>
36
+ </Button>
37
+ <Button hierarchy="secondary" size="md" onClick={toggle}>
38
+ <CrossIcon />
39
+ </Button>
40
+ <Button utility hierarchy="primary" size="md" onClick={toggle}>
41
+ <CrossIcon />
42
+ </Button>
35
43
  </Header>
36
44
  <UtilityBar>
37
45
  <Title>Utility Bar</Title>
38
46
  <Spacer />
39
- <SlimButton hierarchy="tertiary">
47
+ <Button utility hierarchy="tertiary">
48
+ <BugIcon />
49
+ </Button>
50
+ <Button hierarchy="secondary">
40
51
  <BugIcon />
41
- </SlimButton>
42
- <SlimButton hierarchy="tertiary">
52
+ </Button>
53
+ <Button utility size="md" hierarchy="primary">
43
54
  <BugIcon />
44
- </SlimButton>
55
+ </Button>
45
56
  </UtilityBar>
46
57
  <VBody>
47
58
  <BodyText>This is a modal</BodyText>