@torch-ui/solid 0.1.3
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.
- package/README.md +166 -0
- package/package.json +67 -0
- package/src/components/actions/Button.tsx +612 -0
- package/src/components/actions/ButtonGroup.tsx +728 -0
- package/src/components/actions/Copy.tsx +98 -0
- package/src/components/actions/DarkModeToggle.tsx +80 -0
- package/src/components/actions/Link.tsx +37 -0
- package/src/components/actions/index.ts +19 -0
- package/src/components/actions/useCopyToClipboard.ts +90 -0
- package/src/components/charts/Chart.tsx +331 -0
- package/src/components/charts/Sparkline.tsx +156 -0
- package/src/components/charts/index.ts +13 -0
- package/src/components/data-display/Avatar.tsx +208 -0
- package/src/components/data-display/AvatarGroup.tsx +228 -0
- package/src/components/data-display/Badge.tsx +70 -0
- package/src/components/data-display/Carousel.tsx +214 -0
- package/src/components/data-display/ColorSwatch.tsx +56 -0
- package/src/components/data-display/DataTable.tsx +886 -0
- package/src/components/data-display/EmptyState.tsx +61 -0
- package/src/components/data-display/Image.tsx +277 -0
- package/src/components/data-display/Kbd.tsx +114 -0
- package/src/components/data-display/Persona.tsx +78 -0
- package/src/components/data-display/StatCard.tsx +338 -0
- package/src/components/data-display/Table.tsx +147 -0
- package/src/components/data-display/Tag.tsx +91 -0
- package/src/components/data-display/Timeline.tsx +200 -0
- package/src/components/data-display/TreeView.tsx +172 -0
- package/src/components/data-display/Video.tsx +95 -0
- package/src/components/data-display/avatar-utils.ts +32 -0
- package/src/components/data-display/index.ts +81 -0
- package/src/components/feedback/Loading.tsx +159 -0
- package/src/components/feedback/Progress.tsx +321 -0
- package/src/components/feedback/Skeleton.tsx +62 -0
- package/src/components/feedback/SkeletonBlocks.tsx +222 -0
- package/src/components/feedback/Toast.tsx +648 -0
- package/src/components/feedback/index.ts +44 -0
- package/src/components/feedback/password/PasswordStrengthIndicator.tsx +232 -0
- package/src/components/feedback/password/password-strength.ts +115 -0
- package/src/components/feedback/password/password-validation-data.ts +66 -0
- package/src/components/feedback/password/password-validation.ts +93 -0
- package/src/components/forms/Autocomplete.tsx +268 -0
- package/src/components/forms/Checkbox.tsx +155 -0
- package/src/components/forms/CodeInput.tsx +237 -0
- package/src/components/forms/ColorPicker/ColorPicker.tsx +469 -0
- package/src/components/forms/ColorPicker/color-utils.ts +75 -0
- package/src/components/forms/ColorPicker/index.ts +2 -0
- package/src/components/forms/DatePicker.tsx +516 -0
- package/src/components/forms/DateRangePicker.tsx +464 -0
- package/src/components/forms/FieldPicker.tsx +64 -0
- package/src/components/forms/FileUpload.tsx +614 -0
- package/src/components/forms/FilterBuilder/FilterGroupBlock.ts +6 -0
- package/src/components/forms/FilterBuilder.tsx +16 -0
- package/src/components/forms/FilterRuleRow.tsx +68 -0
- package/src/components/forms/Input.tsx +200 -0
- package/src/components/forms/MultiSelect.tsx +361 -0
- package/src/components/forms/NumberField.tsx +145 -0
- package/src/components/forms/RadioGroup.tsx +135 -0
- package/src/components/forms/RelativeDateDefaultInput.tsx +62 -0
- package/src/components/forms/ReorderableList.tsx +163 -0
- package/src/components/forms/Select.tsx +268 -0
- package/src/components/forms/Slider.tsx +260 -0
- package/src/components/forms/Switch.tsx +135 -0
- package/src/components/forms/TextArea.tsx +202 -0
- package/src/components/forms/ViewCustomizer.tsx +44 -0
- package/src/components/forms/index.ts +43 -0
- package/src/components/layout/Accordion.tsx +110 -0
- package/src/components/layout/Alert.tsx +156 -0
- package/src/components/layout/BlockQuote.tsx +70 -0
- package/src/components/layout/Card.tsx +166 -0
- package/src/components/layout/CodeBlock/CodeBlock.tsx +477 -0
- package/src/components/layout/CodeBlock/code-block-tokens.css +104 -0
- package/src/components/layout/CodeBlock/prism.ts +81 -0
- package/src/components/layout/Collapsible.tsx +84 -0
- package/src/components/layout/Container.tsx +55 -0
- package/src/components/layout/Divider.tsx +64 -0
- package/src/components/layout/Form.tsx +39 -0
- package/src/components/layout/FormActions.tsx +50 -0
- package/src/components/layout/Grid.tsx +53 -0
- package/src/components/layout/PageHeading.tsx +46 -0
- package/src/components/layout/PromptWithAction.tsx +49 -0
- package/src/components/layout/Section.tsx +60 -0
- package/src/components/layout/TablePanel.tsx +24 -0
- package/src/components/layout/TableView/TableView.tsx +1018 -0
- package/src/components/layout/TableView/index.ts +3 -0
- package/src/components/layout/TableView/types.ts +51 -0
- package/src/components/layout/WizardStep.tsx +40 -0
- package/src/components/layout/WizardStepper.tsx +173 -0
- package/src/components/layout/index.ts +96 -0
- package/src/components/navigation/Breadcrumbs.tsx +66 -0
- package/src/components/navigation/DropdownMenu.tsx +86 -0
- package/src/components/navigation/MegaMenu.tsx +480 -0
- package/src/components/navigation/NavigationMenu.tsx +305 -0
- package/src/components/navigation/Pagination.tsx +298 -0
- package/src/components/navigation/Sidebar.tsx +280 -0
- package/src/components/navigation/Tabs.tsx +122 -0
- package/src/components/navigation/ViewSwitcher.tsx +314 -0
- package/src/components/navigation/index.ts +66 -0
- package/src/components/overlays/AlertDialog.tsx +174 -0
- package/src/components/overlays/ContextMenu.tsx +65 -0
- package/src/components/overlays/Dialog.tsx +279 -0
- package/src/components/overlays/Drawer.tsx +370 -0
- package/src/components/overlays/HoverCard.tsx +107 -0
- package/src/components/overlays/Popover.tsx +73 -0
- package/src/components/overlays/Tooltip.tsx +31 -0
- package/src/components/overlays/index.ts +71 -0
- package/src/components/typography/Code.tsx +72 -0
- package/src/components/typography/Icon.tsx +36 -0
- package/src/components/typography/index.ts +10 -0
- package/src/env.d.ts +9 -0
- package/src/index.ts +13 -0
- package/src/styles/theme.css +226 -0
- package/src/types/avatar-types.ts +11 -0
- package/src/types/filter-types.ts +35 -0
- package/src/utilities/classNames.ts +6 -0
- package/src/utilities/componentSize.ts +46 -0
- package/src/utilities/i18n.tsx +60 -0
- package/src/utilities/mergeRefs.ts +12 -0
- package/src/utilities/relativeDateDefault.ts +14 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { type JSX, splitProps, Show, For } from 'solid-js'
|
|
2
|
+
import { cn } from '../../utilities/classNames'
|
|
3
|
+
|
|
4
|
+
export interface SidebarItem {
|
|
5
|
+
/** Unique key for the item */
|
|
6
|
+
key: string
|
|
7
|
+
/** Display label for the item */
|
|
8
|
+
label: string
|
|
9
|
+
/** Icon to display (optional) */
|
|
10
|
+
icon?: JSX.Element
|
|
11
|
+
/** Whether the item is currently active */
|
|
12
|
+
active?: boolean
|
|
13
|
+
/** Whether the item is disabled */
|
|
14
|
+
disabled?: boolean
|
|
15
|
+
/** Badge to show (optional) */
|
|
16
|
+
badge?: string | number
|
|
17
|
+
/** Click handler */
|
|
18
|
+
onClick?: () => void
|
|
19
|
+
/** Link href (renders as anchor if provided) */
|
|
20
|
+
href?: string
|
|
21
|
+
/** Sub-items for nested navigation */
|
|
22
|
+
items?: SidebarItem[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SidebarFooter {
|
|
26
|
+
/** Footer content */
|
|
27
|
+
content: JSX.Element
|
|
28
|
+
/** Whether footer is sticky to bottom (default: false) */
|
|
29
|
+
sticky?: boolean
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface SidebarProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
33
|
+
/** Array of navigation items */
|
|
34
|
+
items: SidebarItem[]
|
|
35
|
+
/** Sidebar title */
|
|
36
|
+
title?: string
|
|
37
|
+
/** Whether to show the sidebar title */
|
|
38
|
+
showTitle?: boolean
|
|
39
|
+
/** Whether the sidebar is collapsible */
|
|
40
|
+
collapsible?: boolean
|
|
41
|
+
/** Whether the sidebar is collapsed */
|
|
42
|
+
collapsed?: boolean
|
|
43
|
+
/** Callback when collapse state changes */
|
|
44
|
+
onCollapseChange?: (collapsed: boolean) => void
|
|
45
|
+
/** Whether to show icons */
|
|
46
|
+
showIcons?: boolean | undefined
|
|
47
|
+
/** Whether to show badges */
|
|
48
|
+
showBadges?: boolean | undefined
|
|
49
|
+
/** Custom footer content */
|
|
50
|
+
footer?: JSX.Element | SidebarFooter
|
|
51
|
+
/** Variant styling */
|
|
52
|
+
variant?: 'default' | 'minimal' | 'padded'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Sidebar component with nested navigation support.
|
|
57
|
+
* Built with accessibility in mind and supports various styling options.
|
|
58
|
+
*/
|
|
59
|
+
export function Sidebar(props: SidebarProps) {
|
|
60
|
+
const [local, others] = splitProps(props, [
|
|
61
|
+
'items',
|
|
62
|
+
'title',
|
|
63
|
+
'showTitle',
|
|
64
|
+
'collapsible',
|
|
65
|
+
'collapsed',
|
|
66
|
+
'onCollapseChange',
|
|
67
|
+
'showIcons',
|
|
68
|
+
'showBadges',
|
|
69
|
+
'footer',
|
|
70
|
+
'variant',
|
|
71
|
+
'class',
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
const variantClasses = () => {
|
|
75
|
+
switch (local.variant) {
|
|
76
|
+
case 'minimal':
|
|
77
|
+
return 'border-r border-ink-200 bg-surface-base'
|
|
78
|
+
case 'padded':
|
|
79
|
+
return 'border-r border-ink-200 bg-surface-raised px-3 py-2'
|
|
80
|
+
default:
|
|
81
|
+
return 'border-r border-ink-200 bg-surface-raised'
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const sidebarClass = () =>
|
|
86
|
+
cn(
|
|
87
|
+
local.footer && typeof local.footer === 'object' && 'sticky' in local.footer && local.footer.sticky === true
|
|
88
|
+
? 'flex flex-col h-full min-w-0'
|
|
89
|
+
: 'h-full overflow-x-hidden overflow-y-auto min-w-0',
|
|
90
|
+
variantClasses(),
|
|
91
|
+
local.collapsed ? 'w-16' : local.variant === 'padded' ? 'w-72' : 'w-64',
|
|
92
|
+
'transition-all duration-300 ease-in-out',
|
|
93
|
+
local.class
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
const titleClass = () =>
|
|
97
|
+
cn(
|
|
98
|
+
'px-4 py-3 text-lg font-semibold text-ink-900 border-b border-ink-200',
|
|
99
|
+
local.collapsed ? 'hidden' : 'block'
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
const navigationClass = () =>
|
|
103
|
+
cn(
|
|
104
|
+
local.footer && typeof local.footer === 'object' && 'sticky' in local.footer && local.footer.sticky === true
|
|
105
|
+
? 'flex-1 overflow-x-hidden overflow-y-auto'
|
|
106
|
+
: '',
|
|
107
|
+
local.variant === 'padded' ? 'py-1' : 'py-4'
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
const footerClass = () =>
|
|
111
|
+
cn(
|
|
112
|
+
'border-t border-ink-200 p-4',
|
|
113
|
+
local.collapsed ? 'hidden' : 'block'
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
const renderSidebarItem = (item: SidebarItem, level: number = 0) => {
|
|
117
|
+
const itemClass = () =>
|
|
118
|
+
cn(
|
|
119
|
+
'flex items-center w-full min-w-0 px-3 py-2 text-sm rounded-md transition-colors',
|
|
120
|
+
'hover:bg-surface-hover focus:bg-surface-hover focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2',
|
|
121
|
+
item.active
|
|
122
|
+
? 'bg-primary-600 text-white font-medium'
|
|
123
|
+
: 'text-ink-700 hover:text-ink-900 dark:hover:text-ink-900',
|
|
124
|
+
item.disabled && 'opacity-50 cursor-not-allowed',
|
|
125
|
+
level > 0 && 'ml-4'
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
const iconClass = () =>
|
|
129
|
+
cn(
|
|
130
|
+
'w-5 h-5 flex-shrink-0',
|
|
131
|
+
(local.showIcons ?? true) && !local.collapsed && 'mr-3',
|
|
132
|
+
(local.showIcons ?? true) && local.collapsed && 'mx-auto',
|
|
133
|
+
item.active ? 'text-white' : 'text-ink-500'
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
const badgeClass = () =>
|
|
137
|
+
cn(
|
|
138
|
+
'px-2 py-1 text-xs rounded-full font-medium flex-shrink-0',
|
|
139
|
+
(local.showBadges ?? true) && !local.collapsed && 'ml-auto',
|
|
140
|
+
item.active
|
|
141
|
+
? 'bg-white text-primary-600'
|
|
142
|
+
: 'bg-surface-dim text-ink-600'
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
const ItemContent = () => (
|
|
146
|
+
<>
|
|
147
|
+
{/* Icon */}
|
|
148
|
+
<Show when={item.icon && (local.showIcons ?? true)}>
|
|
149
|
+
<div class={iconClass()}>
|
|
150
|
+
{item.icon}
|
|
151
|
+
</div>
|
|
152
|
+
</Show>
|
|
153
|
+
|
|
154
|
+
{/* Label */}
|
|
155
|
+
<span class="truncate">{item.label}</span>
|
|
156
|
+
|
|
157
|
+
{/* Badge */}
|
|
158
|
+
<Show when={item.badge && (local.showBadges ?? true) && !local.collapsed}>
|
|
159
|
+
<span class={badgeClass()}>
|
|
160
|
+
{item.badge}
|
|
161
|
+
</span>
|
|
162
|
+
</Show>
|
|
163
|
+
</>
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
// Handle nested items
|
|
167
|
+
if (item.items && item.items.length > 0) {
|
|
168
|
+
return (
|
|
169
|
+
<li role="listitem">
|
|
170
|
+
<div class="space-y-1">
|
|
171
|
+
{/* Parent item */}
|
|
172
|
+
{item.href ? (
|
|
173
|
+
<a
|
|
174
|
+
href={item.href}
|
|
175
|
+
class={itemClass()}
|
|
176
|
+
aria-current={item.active ? 'page' : undefined}
|
|
177
|
+
>
|
|
178
|
+
<ItemContent />
|
|
179
|
+
</a>
|
|
180
|
+
) : (
|
|
181
|
+
<button
|
|
182
|
+
type="button"
|
|
183
|
+
class={itemClass()}
|
|
184
|
+
onClick={item.onClick}
|
|
185
|
+
disabled={item.disabled}
|
|
186
|
+
aria-current={item.active ? 'page' : undefined}
|
|
187
|
+
>
|
|
188
|
+
<ItemContent />
|
|
189
|
+
</button>
|
|
190
|
+
)}
|
|
191
|
+
|
|
192
|
+
{/* Nested items */}
|
|
193
|
+
<Show when={!local.collapsed}>
|
|
194
|
+
<div class="ml-4 space-y-1">
|
|
195
|
+
{renderNavigationItems(item.items, level + 1)}
|
|
196
|
+
</div>
|
|
197
|
+
</Show>
|
|
198
|
+
</div>
|
|
199
|
+
</li>
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Handle regular items
|
|
204
|
+
return (
|
|
205
|
+
<li role="listitem">
|
|
206
|
+
{item.href ? (
|
|
207
|
+
<a
|
|
208
|
+
href={item.href}
|
|
209
|
+
class={itemClass()}
|
|
210
|
+
onClick={item.onClick}
|
|
211
|
+
aria-current={item.active ? 'page' : undefined}
|
|
212
|
+
>
|
|
213
|
+
<ItemContent />
|
|
214
|
+
</a>
|
|
215
|
+
) : (
|
|
216
|
+
<button
|
|
217
|
+
type="button"
|
|
218
|
+
class={itemClass()}
|
|
219
|
+
onClick={item.onClick}
|
|
220
|
+
disabled={item.disabled}
|
|
221
|
+
aria-current={item.active ? 'page' : undefined}
|
|
222
|
+
>
|
|
223
|
+
<ItemContent />
|
|
224
|
+
</button>
|
|
225
|
+
)}
|
|
226
|
+
</li>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const renderNavigationItems = (items: SidebarItem[], level: number = 0) => {
|
|
231
|
+
return (
|
|
232
|
+
<div class="space-y-1 min-w-0">
|
|
233
|
+
<For each={items}>
|
|
234
|
+
{(item) => {
|
|
235
|
+
if (item.items && item.items.length > 0) {
|
|
236
|
+
return (
|
|
237
|
+
<div class="space-y-1 min-w-0">
|
|
238
|
+
{renderSidebarItem(item, level)}
|
|
239
|
+
</div>
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
return renderSidebarItem(item, level)
|
|
243
|
+
}}
|
|
244
|
+
</For>
|
|
245
|
+
</div>
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return (
|
|
250
|
+
<div class={sidebarClass()} {...others}>
|
|
251
|
+
{/* Header */}
|
|
252
|
+
<Show when={local.title && local.showTitle !== false}>
|
|
253
|
+
<div class={titleClass()}>
|
|
254
|
+
{!local.collapsed && local.title}
|
|
255
|
+
</div>
|
|
256
|
+
</Show>
|
|
257
|
+
|
|
258
|
+
{/* Navigation */}
|
|
259
|
+
<nav
|
|
260
|
+
class={navigationClass()}
|
|
261
|
+
aria-label={local.title || 'Sidebar navigation'}
|
|
262
|
+
>
|
|
263
|
+
<ul class="space-y-1" role="list">
|
|
264
|
+
{renderNavigationItems(local.items)}
|
|
265
|
+
</ul>
|
|
266
|
+
</nav>
|
|
267
|
+
|
|
268
|
+
{/* Footer */}
|
|
269
|
+
<Show when={local.footer}>
|
|
270
|
+
<div class={footerClass()}>
|
|
271
|
+
{!local.collapsed && local.footer && (
|
|
272
|
+
typeof local.footer === 'object' && 'content' in local.footer
|
|
273
|
+
? local.footer.content
|
|
274
|
+
: local.footer
|
|
275
|
+
)}
|
|
276
|
+
</div>
|
|
277
|
+
</Show>
|
|
278
|
+
</div>
|
|
279
|
+
)
|
|
280
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { For, splitProps, type Accessor } from 'solid-js'
|
|
2
|
+
import { Tabs as KobalteTabs, type TabsRootProps as KobalteTabsRootProps, type TabsListProps as KobalteTabsListProps, type TabsTriggerProps as KobalteTabsTriggerProps, type TabsContentProps as KobalteTabsContentProps } from '@kobalte/core/tabs'
|
|
3
|
+
import { cn } from '../../utilities/classNames'
|
|
4
|
+
|
|
5
|
+
/** Kobalte tabs root. Use for custom tab layouts; prefer Tabs for the standard tab bar. */
|
|
6
|
+
export { KobalteTabs }
|
|
7
|
+
|
|
8
|
+
export interface TabItem {
|
|
9
|
+
id: string
|
|
10
|
+
label: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface TabsProps
|
|
14
|
+
extends Omit<KobalteTabsRootProps, 'value' | 'defaultValue' | 'onChange'> {
|
|
15
|
+
tabs: TabItem[]
|
|
16
|
+
/** Current tab id (controlled), or omit and use defaultValue for uncontrolled. */
|
|
17
|
+
value?: string | Accessor<string>
|
|
18
|
+
/** Initial tab id when uncontrolled. */
|
|
19
|
+
defaultValue?: string
|
|
20
|
+
/** Called when selected tab changes. Optional for uncontrolled usage. */
|
|
21
|
+
onValueChange?: (tabId: string) => void
|
|
22
|
+
/** Accessible label for the tab list. Default: "Tabs". */
|
|
23
|
+
ariaLabel?: string
|
|
24
|
+
class?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Generic tab bar. Content is rendered by the parent based on value. */
|
|
28
|
+
export function Tabs(props: TabsProps) {
|
|
29
|
+
const [local, others] = splitProps(props, [
|
|
30
|
+
'tabs', 'value', 'defaultValue', 'onValueChange', 'ariaLabel', 'class',
|
|
31
|
+
])
|
|
32
|
+
|
|
33
|
+
const resolvedValue = () => {
|
|
34
|
+
const v = local.value
|
|
35
|
+
if (v === undefined) return undefined
|
|
36
|
+
return typeof v === 'function' ? v() : v
|
|
37
|
+
}
|
|
38
|
+
const isControlled = () => local.value !== undefined
|
|
39
|
+
// Tab ids are never empty — coerce empty string to undefined so Kobalte
|
|
40
|
+
// doesn't try to select a non-existent tab.
|
|
41
|
+
const normalizedValue = () => {
|
|
42
|
+
const v = resolvedValue()
|
|
43
|
+
return v && v.length > 0 ? v : undefined
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div class={cn('mb-6 border-b border-surface-border', local.class)}>
|
|
48
|
+
<KobalteTabs
|
|
49
|
+
value={isControlled() ? normalizedValue() : undefined}
|
|
50
|
+
defaultValue={!isControlled() ? (local.defaultValue ?? local.tabs[0]?.id) : undefined}
|
|
51
|
+
onChange={local.onValueChange}
|
|
52
|
+
{...others}
|
|
53
|
+
>
|
|
54
|
+
<KobalteTabs.List
|
|
55
|
+
class="flex w-full flex-nowrap gap-1 overflow-x-auto rounded-none border-0 bg-transparent p-0"
|
|
56
|
+
aria-label={local.ariaLabel ?? 'Tabs'}
|
|
57
|
+
>
|
|
58
|
+
<For each={local.tabs}>
|
|
59
|
+
{(tab) => (
|
|
60
|
+
<KobalteTabs.Trigger
|
|
61
|
+
value={tab.id}
|
|
62
|
+
class="shrink-0 whitespace-nowrap rounded-none border-b-2 border-transparent bg-transparent px-5 py-3 text-sm font-medium text-ink-500 transition-colors hover:border-primary-300 hover:text-primary-700 data-[selected]:border-primary-500 data-[selected]:bg-transparent data-[selected]:text-primary-600 data-[selected]:shadow-none dark:hover:text-primary-400 dark:data-[selected]:border-primary-400 dark:data-[selected]:text-primary-400"
|
|
63
|
+
>
|
|
64
|
+
{tab.label}
|
|
65
|
+
</KobalteTabs.Trigger>
|
|
66
|
+
)}
|
|
67
|
+
</For>
|
|
68
|
+
</KobalteTabs.List>
|
|
69
|
+
</KobalteTabs>
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface TabsListProps extends KobalteTabsListProps {
|
|
75
|
+
class?: string
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function TabsList(props: TabsListProps) {
|
|
79
|
+
const [local, others] = splitProps(props, ['class'])
|
|
80
|
+
return (
|
|
81
|
+
<KobalteTabs.List
|
|
82
|
+
class={cn(
|
|
83
|
+
'inline-flex items-center gap-1 rounded-lg border border-surface-border bg-surface-raised p-1',
|
|
84
|
+
local.class,
|
|
85
|
+
)}
|
|
86
|
+
{...others}
|
|
87
|
+
/>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface TabsTriggerProps extends KobalteTabsTriggerProps {
|
|
92
|
+
class?: string
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function TabsTrigger(props: TabsTriggerProps) {
|
|
96
|
+
const [local, others] = splitProps(props, ['class'])
|
|
97
|
+
return (
|
|
98
|
+
<KobalteTabs.Trigger
|
|
99
|
+
class={cn(
|
|
100
|
+
'rounded-md px-3 py-1.5 text-xs font-medium text-ink-500 transition-colors',
|
|
101
|
+
'data-[selected]:bg-surface-overlay data-[selected]:text-ink-900',
|
|
102
|
+
'data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed',
|
|
103
|
+
local.class,
|
|
104
|
+
)}
|
|
105
|
+
{...others}
|
|
106
|
+
/>
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface TabsContentProps extends KobalteTabsContentProps {
|
|
111
|
+
class?: string
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function TabsContent(props: TabsContentProps) {
|
|
115
|
+
const [local, others] = splitProps(props, ['class'])
|
|
116
|
+
return (
|
|
117
|
+
<KobalteTabs.Content
|
|
118
|
+
class={cn('mt-4', local.class)}
|
|
119
|
+
{...others}
|
|
120
|
+
/>
|
|
121
|
+
)
|
|
122
|
+
}
|