@devalok/shilp-sutra 0.18.2 → 0.19.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.
- package/dist/shell/bottom-navbar.js +4 -4
- package/dist/shell/sidebar.js +2 -2
- package/dist/shell/top-bar.d.ts +45 -20
- package/dist/shell/top-bar.d.ts.map +1 -1
- package/dist/shell/top-bar.js +222 -159
- package/dist/tokens/semantic.css +5 -5
- package/dist/ui/sidebar.js +11 -11
- package/docs/components/_header.md +7 -5
- package/docs/components/composed/activity-feed.md +4 -4
- package/docs/components/composed/command-palette.md +2 -2
- package/docs/components/composed/confirm-dialog.md +1 -1
- package/docs/components/composed/date-picker.md +13 -13
- package/docs/components/composed/schedule-view.md +2 -2
- package/docs/components/composed/status-badge.md +1 -0
- package/docs/components/shell/bottom-navbar.md +4 -0
- package/docs/components/shell/notification-center.md +15 -15
- package/docs/components/shell/sidebar.md +5 -1
- package/docs/components/shell/top-bar.md +101 -24
- package/docs/components/ui/autocomplete.md +1 -1
- package/docs/components/ui/banner.md +1 -0
- package/docs/components/ui/chip.md +1 -0
- package/docs/components/ui/combobox.md +2 -2
- package/docs/components/ui/input.md +1 -1
- package/docs/components/ui/spinner.md +1 -0
- package/docs/components/ui/tabs.md +1 -1
- package/llms-full.txt +164 -73
- package/llms.txt +1 -1
- package/package.json +699 -699
package/dist/ui/sidebar.js
CHANGED
|
@@ -98,7 +98,7 @@ const te = i(
|
|
|
98
98
|
"div",
|
|
99
99
|
{
|
|
100
100
|
className: r(
|
|
101
|
-
"flex h-full w-[--sidebar-width] flex-col bg-surface-
|
|
101
|
+
"flex h-full w-[--sidebar-width] flex-col bg-surface-2 text-surface-fg",
|
|
102
102
|
d
|
|
103
103
|
),
|
|
104
104
|
ref: u,
|
|
@@ -110,7 +110,7 @@ const te = i(
|
|
|
110
110
|
{
|
|
111
111
|
"data-sidebar": "sidebar",
|
|
112
112
|
"data-mobile": "true",
|
|
113
|
-
className: "w-[--sidebar-width] bg-surface-
|
|
113
|
+
className: "w-[--sidebar-width] bg-surface-2 p-0 text-surface-fg [&>button]:hidden",
|
|
114
114
|
style: {
|
|
115
115
|
"--sidebar-width": Q
|
|
116
116
|
},
|
|
@@ -152,7 +152,7 @@ const te = i(
|
|
|
152
152
|
"div",
|
|
153
153
|
{
|
|
154
154
|
"data-sidebar": "sidebar",
|
|
155
|
-
className: "flex h-full w-full flex-col bg-surface-
|
|
155
|
+
className: "flex h-full w-full flex-col bg-surface-2 group-data-[variant=floating]:rounded-ds-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-surface-border group-data-[variant=floating]:shadow",
|
|
156
156
|
children: o
|
|
157
157
|
}
|
|
158
158
|
)
|
|
@@ -202,7 +202,7 @@ const re = i(
|
|
|
202
202
|
"hover:after:bg-surface-border-strong absolute inset-y-0 z-raised hidden w-4 -translate-x-1/2 transition-colors ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex",
|
|
203
203
|
"[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize",
|
|
204
204
|
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
|
|
205
|
-
"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-surface-
|
|
205
|
+
"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-surface-3",
|
|
206
206
|
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
|
|
207
207
|
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
|
|
208
208
|
a
|
|
@@ -234,7 +234,7 @@ const de = i(({ className: a, ...e }, t) => /* @__PURE__ */ s(
|
|
|
234
234
|
ref: t,
|
|
235
235
|
"data-sidebar": "input",
|
|
236
236
|
className: r(
|
|
237
|
-
"h-ds-sm w-full bg-surface-
|
|
237
|
+
"h-ds-sm w-full bg-surface-2 shadow-none focus-visible:ring-2 focus-visible:ring-accent-9",
|
|
238
238
|
a
|
|
239
239
|
),
|
|
240
240
|
...e
|
|
@@ -325,7 +325,7 @@ const pe = i(({ className: a, asChild: e = !1, ...t }, d) => /* @__PURE__ */ s(
|
|
|
325
325
|
ref: d,
|
|
326
326
|
"data-sidebar": "group-action",
|
|
327
327
|
className: r(
|
|
328
|
-
"hover:bg-surface-
|
|
328
|
+
"hover:bg-surface-3 absolute right-ds-04 top-ds-04 flex aspect-square w-5 items-center justify-center rounded-ds-md p-0 text-surface-fg outline-none ring-accent-9 transition-transform hover:text-surface-fg focus-visible:ring-2 [&>svg]:h-ico-sm [&>svg]:w-ico-sm [&>svg]:shrink-0",
|
|
329
329
|
"after:absolute after:-inset-2 after:md:hidden",
|
|
330
330
|
"group-data-[collapsible=icon]:hidden",
|
|
331
331
|
a
|
|
@@ -371,12 +371,12 @@ const ge = i(
|
|
|
371
371
|
);
|
|
372
372
|
ge.displayName = "SidebarMenuItem";
|
|
373
373
|
const he = T(
|
|
374
|
-
"peer/menu-button hover:bg-surface-
|
|
374
|
+
"peer/menu-button hover:bg-surface-3 active:bg-accent-2 data-[active=true]:bg-accent-2 data-[state=open]:hover:bg-surface-3 flex w-full items-center gap-ds-03 overflow-hidden rounded-ds-md p-ds-03 text-left outline-none ring-accent-9 transition-[width,height,padding] hover:text-surface-fg focus-visible:ring-2 active:text-surface-fg disabled:pointer-events-none disabled:opacity-action-disabled group-has-[[data-sidebar=menu-action]]/menu-item:pr-ds-07 aria-disabled:pointer-events-none aria-disabled:opacity-action-disabled data-[active=true]:font-medium data-[active=true]:text-surface-fg data-[state=open]:hover:text-surface-fg group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-ds-03 [&>span:last-child]:truncate [&>svg]:h-ico-sm [&>svg]:w-ico-sm [&>svg]:shrink-0",
|
|
375
375
|
{
|
|
376
376
|
variants: {
|
|
377
377
|
variant: {
|
|
378
|
-
default: "hover:bg-surface-
|
|
379
|
-
outline: "hover:bg-surface-
|
|
378
|
+
default: "hover:bg-surface-3 hover:text-surface-fg",
|
|
379
|
+
outline: "hover:bg-surface-3 bg-surface-2 shadow-[0_0_0_1px_var(--color-surface-border)] hover:text-surface-fg hover:shadow-[0_0_0_1px_var(--color-surface-border-strong)]"
|
|
380
380
|
},
|
|
381
381
|
size: {
|
|
382
382
|
md: "h-ds-sm text-ds-md",
|
|
@@ -445,7 +445,7 @@ const xe = i(({ className: a, asChild: e = !1, showOnHover: t = !1, ...d }, o) =
|
|
|
445
445
|
ref: o,
|
|
446
446
|
"data-sidebar": "menu-action",
|
|
447
447
|
className: r(
|
|
448
|
-
"hover:bg-surface-
|
|
448
|
+
"hover:bg-surface-3 absolute right-ds-02 top-ds-02b flex aspect-square w-5 items-center justify-center rounded-ds-md p-0 text-surface-fg outline-none ring-accent-9 transition-transform hover:text-surface-fg focus-visible:ring-2 peer-hover/menu-button:text-surface-fg [&>svg]:h-ico-sm [&>svg]:w-ico-sm [&>svg]:shrink-0",
|
|
449
449
|
"after:absolute after:-inset-2 after:md:hidden",
|
|
450
450
|
"peer-data-[size=sm]/menu-button:top-1",
|
|
451
451
|
"peer-data-[size=md]/menu-button:top-ds-02b",
|
|
@@ -538,7 +538,7 @@ const Me = i(({ asChild: a = !1, size: e = "md", isActive: t, className: d, ...o
|
|
|
538
538
|
"data-size": e,
|
|
539
539
|
"data-active": t,
|
|
540
540
|
className: r(
|
|
541
|
-
"hover:bg-surface-
|
|
541
|
+
"hover:bg-surface-3 active:bg-accent-2 flex h-ds-xs-plus min-w-0 -translate-x-px items-center gap-ds-03 overflow-hidden rounded-ds-md px-ds-03 text-surface-fg outline-none ring-accent-9 hover:text-surface-fg focus-visible:ring-2 active:text-surface-fg disabled:pointer-events-none disabled:opacity-action-disabled aria-disabled:pointer-events-none aria-disabled:opacity-action-disabled [&>span:last-child]:truncate [&>svg]:h-ico-sm [&>svg]:w-ico-sm [&>svg]:shrink-0 [&>svg]:text-surface-fg",
|
|
542
542
|
"data-[active=true]:bg-accent-2 data-[active=true]:text-surface-fg",
|
|
543
543
|
e === "sm" && "text-ds-sm",
|
|
544
544
|
e === "md" && "text-ds-md",
|
|
@@ -42,10 +42,10 @@ Color tokens use OKLCH (perceptually uniform) with 12 functional steps per palet
|
|
|
42
42
|
| 2 | Subtle background | Sidebar, card alt |
|
|
43
43
|
| 3 | Component bg | Input bg, badge bg |
|
|
44
44
|
| 4 | Component bg hover | Button hover state |
|
|
45
|
-
| 5 |
|
|
46
|
-
| 6 | Border
|
|
47
|
-
| 7 | Border
|
|
48
|
-
| 8 | Border
|
|
45
|
+
| 5 | Border subtle | Semantic `surface-border` in light mode |
|
|
46
|
+
| 6 | Border default | Semantic `surface-border-strong` in light mode |
|
|
47
|
+
| 7 | Border strong | Focus rings, emphasis borders |
|
|
48
|
+
| 8 | Border emphasis | High-contrast outlines |
|
|
49
49
|
| 9 | Solid / accent | Button bg, primary CTA |
|
|
50
50
|
| 10 | Solid hover | Button hover bg |
|
|
51
51
|
| 11 | Low-contrast text | Secondary accent text |
|
|
@@ -54,7 +54,9 @@ Color tokens use OKLCH (perceptually uniform) with 12 functional steps per palet
|
|
|
54
54
|
Semantic layer:
|
|
55
55
|
- Accent (swappable): --color-accent-{1-12} + --color-accent-fg
|
|
56
56
|
- Secondary: --color-secondary-{1-12} + --color-secondary-fg
|
|
57
|
-
- Surface: --color-surface-{1-4} + --color-surface-fg / fg-muted / fg-subtle / border
|
|
57
|
+
- Surface: --color-surface-{1-4} + --color-surface-fg / fg-muted / fg-subtle / border / border-strong
|
|
58
|
+
- Border mapping: light mode border=step5, border-strong=step6; dark mode border=step3, border-strong=step4
|
|
59
|
+
- Shell chrome (sidebar, topbar, bottom nav) uses surface-2 for elevation above surface-1 app background
|
|
58
60
|
- Status: --color-{error,success,warning,info}-{3,7,9,11}
|
|
59
61
|
- Category: --color-category-{teal,amber,slate,indigo,cyan,orange,emerald}
|
|
60
62
|
|
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
|
|
7
7
|
## Props
|
|
8
8
|
items: ActivityItem[] (REQUIRED) — { id, actor?: { name, image? }, action: string|ReactNode, timestamp: Date|string, icon?, color?: 'default'|'success'|'warning'|'error'|'info', detail?: ReactNode }
|
|
9
|
-
onLoadMore
|
|
9
|
+
onLoadMore?: () => void — "Load more" button callback
|
|
10
10
|
loading: boolean — skeleton shimmer
|
|
11
|
-
hasMore
|
|
12
|
-
emptyState
|
|
11
|
+
hasMore?: boolean — shows "Load more" button
|
|
12
|
+
emptyState?: ReactNode — empty state content
|
|
13
13
|
compact: boolean — tighter spacing, no avatars, smaller text
|
|
14
14
|
maxInitialItems: number — truncate with "Show all (N)" toggle
|
|
15
15
|
|
|
16
16
|
## Defaults
|
|
17
|
-
loading=false, compact=false
|
|
17
|
+
loading=false, compact=false, hasMore=false
|
|
18
18
|
|
|
19
19
|
## Example
|
|
20
20
|
```jsx
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
- Category: composed
|
|
6
6
|
|
|
7
7
|
## Props
|
|
8
|
-
groups
|
|
8
|
+
groups?: CommandGroup[] (default: []) — { label: string, items: CommandItem[] }
|
|
9
9
|
placeholder: string (default: "Search or jump to...")
|
|
10
10
|
onSearch: (query: string) => void
|
|
11
11
|
emptyMessage: string (default: "No results found.")
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
CommandItem shape: { id, label, description?, icon?, shortcut?, onSelect: () => void }
|
|
14
14
|
|
|
15
15
|
## Defaults
|
|
16
|
-
placeholder="Search or jump to...", emptyMessage="No results found."
|
|
16
|
+
placeholder="Search or jump to...", emptyMessage="No results found.", groups=[]
|
|
17
17
|
|
|
18
18
|
## Example
|
|
19
19
|
```jsx
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
confirmText: string (default: "Confirm")
|
|
13
13
|
cancelText: string (default: "Cancel")
|
|
14
14
|
color: "default" | "error" (controls confirm button color)
|
|
15
|
-
loading: boolean (default: false, disables buttons and
|
|
15
|
+
loading: boolean (default: false, disables buttons and replaces confirm button text with 'Processing...')
|
|
16
16
|
onConfirm: () => void | Promise<void> (REQUIRED)
|
|
17
17
|
|
|
18
18
|
## Defaults
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
## Props
|
|
8
8
|
|
|
9
9
|
### DatePicker
|
|
10
|
-
value
|
|
11
|
-
onChange
|
|
10
|
+
value?: Date | null
|
|
11
|
+
onChange?: (date: Date | null) => void
|
|
12
12
|
placeholder: string (default: "Pick a date")
|
|
13
13
|
formatStr: string (default: "MMM d, yyyy")
|
|
14
14
|
minDate: Date
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
className: string
|
|
18
18
|
|
|
19
19
|
### DateRangePicker
|
|
20
|
-
startDate
|
|
21
|
-
endDate
|
|
22
|
-
onChange
|
|
20
|
+
startDate?: Date | null
|
|
21
|
+
endDate?: Date | null
|
|
22
|
+
onChange?: (range: { start: Date | null, end: Date | null }) => void
|
|
23
23
|
placeholder: string (default: "Pick a date range")
|
|
24
24
|
formatStr: string (default: "MMM d, yyyy")
|
|
25
25
|
minDate: Date
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
className: string
|
|
41
41
|
|
|
42
42
|
### TimePicker
|
|
43
|
-
value
|
|
44
|
-
onChange
|
|
43
|
+
value?: Date | null (time stored as a Date object)
|
|
44
|
+
onChange?: (date: Date) => void
|
|
45
45
|
format: "12h" | "24h" (default: "12h")
|
|
46
46
|
minuteStep: number (default: 1)
|
|
47
47
|
secondStep: number (default: 1)
|
|
@@ -52,14 +52,14 @@
|
|
|
52
52
|
|
|
53
53
|
### CalendarGrid
|
|
54
54
|
currentMonth: Date (REQUIRED)
|
|
55
|
-
selected
|
|
56
|
-
rangeStart
|
|
57
|
-
rangeEnd
|
|
58
|
-
hoverDate
|
|
55
|
+
selected?: Date | null
|
|
56
|
+
rangeStart?: Date | null
|
|
57
|
+
rangeEnd?: Date | null
|
|
58
|
+
hoverDate?: Date | null
|
|
59
59
|
onSelect: (date: Date) => void (REQUIRED)
|
|
60
|
-
onHover
|
|
60
|
+
onHover?: (date: Date | null) => void
|
|
61
61
|
onMonthChange: (date: Date) => void (REQUIRED)
|
|
62
|
-
onHeaderClick
|
|
62
|
+
onHeaderClick?: () => void
|
|
63
63
|
disabledDates: (date: Date) => boolean
|
|
64
64
|
minDate: Date
|
|
65
65
|
maxDate: Date
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
view: "day" | "week" (REQUIRED)
|
|
9
9
|
date: Date (REQUIRED — current day or any date in target week)
|
|
10
10
|
events: ScheduleEvent[] (REQUIRED) — { id, title, start: Date, end: Date, color? }
|
|
11
|
-
onEventClick
|
|
12
|
-
onSlotClick
|
|
11
|
+
onEventClick?: (event: ScheduleEvent) => void
|
|
12
|
+
onSlotClick?: (start: Date, end: Date) => void
|
|
13
13
|
startHour: number (default: 8)
|
|
14
14
|
endHour: number (default: 18, exclusive)
|
|
15
15
|
slotDuration: number (minutes, default: 30)
|
|
@@ -35,6 +35,10 @@ BottomNavbarUser: { name: string, role?: string }
|
|
|
35
35
|
- Requires LinkProvider for framework-specific link components (e.g., Next.js Link)
|
|
36
36
|
|
|
37
37
|
## Changes
|
|
38
|
+
### v0.19.0
|
|
39
|
+
- **Changed** Background elevated from `bg-surface-1` to `bg-surface-2` for visual hierarchy above app background
|
|
40
|
+
- **Changed** "More" menu and interactive items bumped accordingly
|
|
41
|
+
|
|
38
42
|
### v0.18.0
|
|
39
43
|
- **Fixed** Removed incorrect `role="button"` and `tabIndex` from overlay
|
|
40
44
|
|
|
@@ -6,21 +6,21 @@
|
|
|
6
6
|
|
|
7
7
|
## Props
|
|
8
8
|
notifications?: Notification[]
|
|
9
|
-
unreadCount
|
|
10
|
-
open
|
|
11
|
-
onOpenChange
|
|
12
|
-
isLoading
|
|
13
|
-
hasMore
|
|
14
|
-
onFetchMore
|
|
15
|
-
onMarkRead
|
|
16
|
-
onMarkAllRead
|
|
17
|
-
onNavigate
|
|
18
|
-
getNotificationRoute
|
|
19
|
-
footerSlot
|
|
20
|
-
emptyState
|
|
21
|
-
headerActions
|
|
22
|
-
popoverClassName
|
|
23
|
-
onDismiss
|
|
9
|
+
unreadCount?: number (derived from notifications if not provided)
|
|
10
|
+
open?: boolean (controlled mode)
|
|
11
|
+
onOpenChange?: (open: boolean) => void
|
|
12
|
+
isLoading?: boolean
|
|
13
|
+
hasMore?: boolean
|
|
14
|
+
onFetchMore?: () => void
|
|
15
|
+
onMarkRead?: (id: string) => void
|
|
16
|
+
onMarkAllRead?: () => void
|
|
17
|
+
onNavigate?: (path: string) => void — called when a notification with a route is clicked
|
|
18
|
+
getNotificationRoute?: (notification: Notification) => string | null — returns route for a notification; defaults to () => null
|
|
19
|
+
footerSlot?: ReactNode — content rendered in a sticky footer below the scroll area
|
|
20
|
+
emptyState?: ReactNode — replaces default empty state UI
|
|
21
|
+
headerActions?: ReactNode — extra action buttons after "Mark all read"
|
|
22
|
+
popoverClassName?: string — override default popover dimensions
|
|
23
|
+
onDismiss?: (id: string) => void — when provided, each notification shows a dismiss button
|
|
24
24
|
|
|
25
25
|
Notification: { id: string, title: string, body?: string | null, tier: 'INFO' | 'IMPORTANT' | 'CRITICAL', isRead: boolean, createdAt: string, entityType?: string | null, entityId?: string | null, projectId?: string | null, project?: { title: string } | null, actions?: NotificationAction[] }
|
|
26
26
|
NotificationAction: { label: string, variant?: 'primary' | 'default' | 'danger', onClick: (id: string) => void }
|
|
@@ -21,7 +21,7 @@ NavItem: { title: string, href: string, icon: ReactNode, exact?: boolean, badge?
|
|
|
21
21
|
NavSubItem: { title: string, href: string, icon?: ReactNode, exact?: boolean }
|
|
22
22
|
NavGroup: { label: string, items: NavItem[], action?: ReactNode }
|
|
23
23
|
SidebarUser: { name: string, email?: string, image?: string | null, designation?: string, role?: string }
|
|
24
|
-
SidebarFooterConfig: { links
|
|
24
|
+
SidebarFooterConfig: { links?: Array<{ label: string, href: string }>, version?: string | { label: string, href: string }, slot?: ReactNode, promo?: SidebarPromo }
|
|
25
25
|
SidebarPromo: { text: string, icon?: ReactNode, action?: { label: string, href?: string, onClick?: () => void }, onDismiss?: () => void }
|
|
26
26
|
|
|
27
27
|
## Defaults
|
|
@@ -57,6 +57,10 @@ SidebarPromo: { text: string, icon?: ReactNode, action?: { label: string, href?:
|
|
|
57
57
|
- Badge numbers > 99 display as "99+"
|
|
58
58
|
|
|
59
59
|
## Changes
|
|
60
|
+
### v0.19.0
|
|
61
|
+
- **Changed** Background elevated from `bg-surface-1` to `bg-surface-2` for visual hierarchy above app background
|
|
62
|
+
- **Changed** Interactive hover states bumped from `surface-2` to `surface-3`
|
|
63
|
+
|
|
60
64
|
### v0.18.0
|
|
61
65
|
- **Fixed** `bg-interactive-subtle` changed to `bg-accent-2` (OKLCH migration)
|
|
62
66
|
|
|
@@ -4,16 +4,54 @@
|
|
|
4
4
|
- Server-safe: No
|
|
5
5
|
- Category: shell
|
|
6
6
|
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Composition-based application top bar. Uses dot-notation subcomponents for flexible layout.
|
|
10
|
+
|
|
11
|
+
## Subcomponents
|
|
12
|
+
|
|
13
|
+
| Component | Purpose |
|
|
14
|
+
|-----------|---------|
|
|
15
|
+
| `TopBar` | Root — bg-surface-2, border-b, sticky. Auto-switches to grid when Center is present. |
|
|
16
|
+
| `TopBar.Left` | Left zone — sidebar trigger, title, breadcrumbs |
|
|
17
|
+
| `TopBar.Center` | Optional center zone — search bar, tabs. Triggers 3-column grid layout. |
|
|
18
|
+
| `TopBar.Right` | Right zone — action buttons, user menu. Gets ml-auto in flex mode. |
|
|
19
|
+
| `TopBar.Section` | Groups items with configurable gap |
|
|
20
|
+
| `TopBar.IconButton` | Circular icon button with tooltip (bg-surface-3, hover:bg-surface-4) |
|
|
21
|
+
| `TopBar.Title` | Page title heading, hidden on mobile |
|
|
22
|
+
| `TopBar.UserMenu` | Avatar dropdown with color mode toggle, profile, logout |
|
|
23
|
+
|
|
7
24
|
## Props
|
|
8
|
-
|
|
9
|
-
|
|
25
|
+
|
|
26
|
+
### TopBar (root)
|
|
27
|
+
children: ReactNode
|
|
28
|
+
className?: string
|
|
29
|
+
|
|
30
|
+
### TopBar.Left / TopBar.Center / TopBar.Right
|
|
31
|
+
children: ReactNode
|
|
32
|
+
className?: string
|
|
33
|
+
|
|
34
|
+
### TopBar.Section
|
|
35
|
+
gap?: "tight" | "default" | "loose" (default: "default")
|
|
36
|
+
children: ReactNode
|
|
37
|
+
className?: string
|
|
38
|
+
|
|
39
|
+
Gap values: tight = gap-ds-02, default = gap-ds-04, loose = gap-ds-06
|
|
40
|
+
|
|
41
|
+
### TopBar.IconButton
|
|
42
|
+
icon: ReactNode
|
|
43
|
+
tooltip: string
|
|
44
|
+
...ButtonHTMLAttributes
|
|
45
|
+
|
|
46
|
+
### TopBar.Title
|
|
47
|
+
children: ReactNode
|
|
48
|
+
className?: string
|
|
49
|
+
|
|
50
|
+
### TopBar.UserMenu
|
|
51
|
+
user: TopBarUser — { name, email?, image? }
|
|
10
52
|
onNavigate?: (path: string) => void
|
|
11
53
|
onLogout?: () => void
|
|
12
|
-
|
|
13
|
-
onAiChatClick?: () => void
|
|
14
|
-
mobileLogo?: ReactNode
|
|
15
|
-
notificationSlot?: ReactNode (render NotificationCenter here)
|
|
16
|
-
userMenuItems?: UserMenuItem[] — custom items between Profile and Dark/Light Mode toggle
|
|
54
|
+
userMenuItems?: UserMenuItem[]
|
|
17
55
|
className?: string
|
|
18
56
|
|
|
19
57
|
TopBarUser: { name: string, email?: string, image?: string | null }
|
|
@@ -27,30 +65,69 @@ UserMenuItem fields:
|
|
|
27
65
|
- badge — string for count badge, true for dot indicator
|
|
28
66
|
- disabled — greys out the item
|
|
29
67
|
|
|
30
|
-
## Defaults
|
|
31
|
-
None
|
|
32
|
-
|
|
33
68
|
## Example
|
|
69
|
+
|
|
70
|
+
### Two-zone (standard)
|
|
34
71
|
```jsx
|
|
35
|
-
<TopBar
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
72
|
+
<TopBar>
|
|
73
|
+
<TopBar.Left>
|
|
74
|
+
<SidebarTrigger />
|
|
75
|
+
<TopBar.Title>Dashboard</TopBar.Title>
|
|
76
|
+
</TopBar.Left>
|
|
77
|
+
<TopBar.Right>
|
|
78
|
+
<TopBar.Section gap="tight">
|
|
79
|
+
<TopBar.IconButton icon={<IconSearch />} tooltip="Search (Ctrl+K)" onClick={openSearch} />
|
|
80
|
+
<NotificationCenter notifications={notifications} />
|
|
81
|
+
<TopBar.IconButton icon={<IconSparkles />} tooltip="AI Chat" onClick={openAI} />
|
|
82
|
+
</TopBar.Section>
|
|
83
|
+
<TopBar.UserMenu
|
|
84
|
+
user={{ name: 'John', email: 'john@example.com' }}
|
|
85
|
+
onNavigate={(p) => router.push(p)}
|
|
86
|
+
onLogout={handleLogout}
|
|
87
|
+
userMenuItems={[
|
|
88
|
+
{ label: 'Changelog', icon: <IconNews />, href: '/changelog', badge: '3' },
|
|
89
|
+
]}
|
|
90
|
+
/>
|
|
91
|
+
</TopBar.Right>
|
|
92
|
+
</TopBar>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Three-zone (centered search bar)
|
|
96
|
+
```jsx
|
|
97
|
+
<TopBar>
|
|
98
|
+
<TopBar.Left>
|
|
99
|
+
<SidebarTrigger />
|
|
100
|
+
<TopBar.Title>Dashboard</TopBar.Title>
|
|
101
|
+
</TopBar.Left>
|
|
102
|
+
<TopBar.Center>
|
|
103
|
+
<SearchBarTrigger />
|
|
104
|
+
</TopBar.Center>
|
|
105
|
+
<TopBar.Right>
|
|
106
|
+
<TopBar.Section gap="tight">
|
|
107
|
+
<TopBar.IconButton icon={<IconBell />} tooltip="Notifications" onClick={fn} />
|
|
108
|
+
</TopBar.Section>
|
|
109
|
+
<TopBar.UserMenu user={user} onLogout={logout} />
|
|
110
|
+
</TopBar.Right>
|
|
111
|
+
</TopBar>
|
|
46
112
|
```
|
|
47
113
|
|
|
48
114
|
## Gotchas
|
|
49
|
-
- `
|
|
50
|
-
- `
|
|
51
|
-
-
|
|
115
|
+
- Without `TopBar.Center`, layout is flex (two-zone). With it, layout switches to CSS grid `1fr auto 1fr` for true centering.
|
|
116
|
+
- `TopBar.IconButton` renders any number of action buttons — no artificial limit. Use responsive hiding (`className="hidden md:flex"`) for mobile.
|
|
117
|
+
- `TopBar.UserMenu` includes Profile link, color mode toggle, and logout automatically. `userMenuItems` are inserted between Profile and the toggle.
|
|
118
|
+
- Requires SidebarProvider wrapper for SidebarTrigger to work.
|
|
52
119
|
|
|
53
120
|
## Changes
|
|
121
|
+
### v0.19.0
|
|
122
|
+
- **BREAKING** Rewritten as composition API. Old props-based API removed (`pageTitle`, `onSearchClick`, `onAiChatClick`, `notificationSlot`, `mobileLogo` props).
|
|
123
|
+
- **Added** `TopBar.Left`, `TopBar.Center`, `TopBar.Right` zone components
|
|
124
|
+
- **Added** `TopBar.Section` with `gap` prop (`tight` | `default` | `loose`)
|
|
125
|
+
- **Added** `TopBar.IconButton` — reusable circular icon button with tooltip
|
|
126
|
+
- **Added** `TopBar.Title` — responsive page title (hidden on mobile)
|
|
127
|
+
- **Added** `TopBar.UserMenu` — extracted user dropdown as standalone subcomponent
|
|
128
|
+
- **Added** Auto grid/flex layout detection based on Center zone presence
|
|
129
|
+
- **Changed** Background elevated from `bg-surface-1` to `bg-surface-2`
|
|
130
|
+
|
|
54
131
|
### v0.7.0
|
|
55
132
|
- **Added** `userMenuItems` prop for custom dropdown items
|
|
56
133
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
## Props
|
|
8
8
|
options: AutocompleteOption[] (REQUIRED) — { value: string, label: string }
|
|
9
9
|
value: AutocompleteOption | null
|
|
10
|
-
onValueChange
|
|
10
|
+
onValueChange?: (option: AutocompleteOption) => void
|
|
11
11
|
placeholder: string
|
|
12
12
|
emptyText: string (default: "No options")
|
|
13
13
|
disabled: boolean
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
- MUST use label prop — children are NOT rendered
|
|
31
31
|
- `<Chip>text</Chip>` is WRONG — use `<Chip label="text" />`
|
|
32
32
|
- Wrap dynamic chip lists in `<ChipGroup>` for exit animations
|
|
33
|
+
- `color="primary"` will be renamed to `color="brand"` in v1.0 — use `color="primary"` for now
|
|
33
34
|
|
|
34
35
|
## Changes
|
|
35
36
|
### v0.4.2
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
## Props
|
|
8
8
|
options: ComboboxOption[] (REQUIRED) — { value: string, label: string, description?: string, icon?: ReactNode, disabled?: boolean }
|
|
9
9
|
DISCRIMINATED UNION — type depends on `multiple` flag:
|
|
10
|
-
Single (default): multiple?: false, value
|
|
11
|
-
Multiple: multiple: true, value
|
|
10
|
+
Single (default): multiple?: false, value?: string, onValueChange: (value: string) => void
|
|
11
|
+
Multiple: multiple: true, value?: string[], onValueChange: (value: string[]) => void
|
|
12
12
|
placeholder: string (default: "Select...")
|
|
13
13
|
searchPlaceholder: string (default: "Search...")
|
|
14
14
|
emptyMessage: string (default: "No results found")
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
- HTML native "size" attribute is excluded — use CSS width instead
|
|
27
27
|
- state="error" sets aria-invalid automatically
|
|
28
28
|
- Inside FormField: auto-inherits state, aria-describedby, aria-required from context (explicit props override)
|
|
29
|
-
- Resting border is border-subtle (soft); focus ring is ring-1
|
|
29
|
+
- Resting border is border-subtle (soft); focus ring is `ring-1 ring-accent-7` (v0.12.0)
|
|
30
30
|
- All sizes (sm, md, lg) use text-ds-md (14px) font — size only affects height and padding (v0.15.0)
|
|
31
31
|
|
|
32
32
|
## Changes
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
## Gotchas
|
|
45
45
|
- variant goes on TabsList, NOT on individual TabsTrigger (propagates via context)
|
|
46
|
-
-
|
|
46
|
+
- Normally omit `variant` on TabsTrigger — it inherits from TabsList via context. You CAN set it per-trigger to override.
|
|
47
47
|
|
|
48
48
|
## Changes
|
|
49
49
|
### v0.18.0
|