@devalok/shilp-sutra 0.18.2 → 0.19.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 (34) hide show
  1. package/dist/shell/bottom-navbar.js +4 -4
  2. package/dist/shell/sidebar.js +2 -2
  3. package/dist/shell/top-bar.d.ts +45 -20
  4. package/dist/shell/top-bar.d.ts.map +1 -1
  5. package/dist/shell/top-bar.js +222 -159
  6. package/dist/tokens/semantic.css +5 -5
  7. package/dist/ui/alert-dialog.js +28 -28
  8. package/dist/ui/chip.d.ts.map +1 -1
  9. package/dist/ui/chip.js +13 -12
  10. package/dist/ui/dialog.js +4 -4
  11. package/dist/ui/sidebar.js +11 -11
  12. package/docs/components/_header.md +7 -5
  13. package/docs/components/composed/activity-feed.md +4 -4
  14. package/docs/components/composed/command-palette.md +2 -2
  15. package/docs/components/composed/confirm-dialog.md +1 -1
  16. package/docs/components/composed/date-picker.md +13 -13
  17. package/docs/components/composed/schedule-view.md +2 -2
  18. package/docs/components/composed/status-badge.md +1 -0
  19. package/docs/components/shell/bottom-navbar.md +4 -0
  20. package/docs/components/shell/notification-center.md +15 -15
  21. package/docs/components/shell/sidebar.md +5 -1
  22. package/docs/components/shell/top-bar.md +101 -24
  23. package/docs/components/ui/alert-dialog.md +3 -0
  24. package/docs/components/ui/autocomplete.md +1 -1
  25. package/docs/components/ui/banner.md +1 -0
  26. package/docs/components/ui/chip.md +4 -0
  27. package/docs/components/ui/combobox.md +2 -2
  28. package/docs/components/ui/dialog.md +3 -0
  29. package/docs/components/ui/input.md +1 -1
  30. package/docs/components/ui/spinner.md +1 -0
  31. package/docs/components/ui/tabs.md +1 -1
  32. package/llms-full.txt +173 -73
  33. package/llms.txt +1 -1
  34. package/package.json +699 -699
package/llms-full.txt CHANGED
@@ -5,7 +5,7 @@
5
5
  > All variant values and props verified from source CVA definitions.
6
6
  >
7
7
  > Package: @devalok/shilp-sutra
8
- > Version: 0.18.2
8
+ > Version: 0.19.1
9
9
 
10
10
  ---
11
11
 
@@ -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 | Component bg active | Active/pressed state |
46
- | 6 | Border subtle | Dividers, soft borders |
47
- | 7 | Border default | Input borders, card borders |
48
- | 8 | Border strong | Focus rings, emphasis borders |
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
 
@@ -229,6 +231,9 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
229
231
  - AlertDialogAction does NOT have color="error" styling — add it yourself via className or wrap a Button
230
232
 
231
233
  ## Changes
234
+ ### v0.19.1
235
+ - **Fixed** AlertDialog not centered after Framer Motion animation completes — same `transform: none` fix as Dialog.
236
+
232
237
  ### v0.18.0
233
238
  - **Changed** Overlay animations migrated to Framer Motion (physics-based springs)
234
239
  - **Added** `AlertDialogContentProps`, `AlertDialogActionProps`, `AlertDialogCancelProps` type exports
@@ -273,7 +278,7 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
273
278
  ## Props
274
279
  options: AutocompleteOption[] (REQUIRED) — { value: string, label: string }
275
280
  value: AutocompleteOption | null
276
- onValueChange: (option: AutocompleteOption) => void
281
+ onValueChange?: (option: AutocompleteOption) => void
277
282
  placeholder: string
278
283
  emptyText: string (default: "No options")
279
284
  disabled: boolean
@@ -419,6 +424,7 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
419
424
  ## Gotchas
420
425
  - Banner is full-width (spans container). Alert is inline.
421
426
  - Renders role="alert" automatically
427
+ - `onDismiss` fires after the exit animation completes, not immediately on dismiss button click
422
428
 
423
429
  ## Changes
424
430
  ### v0.3.1
@@ -707,8 +713,12 @@ import { BarChart } from '@devalok/shilp-sutra/ui/charts'
707
713
  - MUST use label prop — children are NOT rendered
708
714
  - `<Chip>text</Chip>` is WRONG — use `<Chip label="text" />`
709
715
  - Wrap dynamic chip lists in `<ChipGroup>` for exit animations
716
+ - `color="primary"` will be renamed to `color="brand"` in v1.0 — use `color="primary"` for now
710
717
 
711
718
  ## Changes
719
+ ### v0.19.1
720
+ - **Fixed** `active:scale-95` tap feedback broken by Framer Motion transform override — replaced with `whileTap={{ scale: 0.95 }}`
721
+
712
722
  ### v0.4.2
713
723
  - **Changed** (BREAKING) `variant="filled"` renamed to `"subtle"`, `variant="outlined"` renamed to `"outline"`, `onDelete` renamed to `onDismiss`
714
724
 
@@ -832,8 +842,8 @@ import { BarChart } from '@devalok/shilp-sutra/ui/charts'
832
842
  ## Props
833
843
  options: ComboboxOption[] (REQUIRED) — { value: string, label: string, description?: string, icon?: ReactNode, disabled?: boolean }
834
844
  DISCRIMINATED UNION — type depends on `multiple` flag:
835
- Single (default): multiple?: false, value: string, onValueChange: (value: string) => void
836
- Multiple: multiple: true, value: string[], onValueChange: (value: string[]) => void
845
+ Single (default): multiple?: false, value?: string, onValueChange: (value: string) => void
846
+ Multiple: multiple: true, value?: string[], onValueChange: (value: string[]) => void
837
847
  placeholder: string (default: "Select...")
838
848
  searchPlaceholder: string (default: "Search...")
839
849
  emptyMessage: string (default: "No results found")
@@ -1122,6 +1132,9 @@ import { DataTableToolbar } from '@devalok/shilp-sutra/ui/data-table-toolbar'
1122
1132
  - DialogTitle is required for accessibility — screen readers announce it when the dialog opens
1123
1133
 
1124
1134
  ## Changes
1135
+ ### v0.19.1
1136
+ - **Fixed** Dialog not centered after Framer Motion animation completes — `transform: none` inline style overrode Tailwind `translate-x/y` classes. Centering now handled via Framer Motion `x`/`y` properties.
1137
+
1125
1138
  ### v0.18.0
1126
1139
  - **Changed** Overlay animations migrated to Framer Motion (physics-based springs)
1127
1140
  - **Added** `DialogContentProps`, `DialogTitleProps` type exports
@@ -1362,7 +1375,7 @@ import { DataTableToolbar } from '@devalok/shilp-sutra/ui/data-table-toolbar'
1362
1375
  - HTML native "size" attribute is excluded — use CSS width instead
1363
1376
  - state="error" sets aria-invalid automatically
1364
1377
  - Inside FormField: auto-inherits state, aria-describedby, aria-required from context (explicit props override)
1365
- - Resting border is border-subtle (soft); focus ring is ring-1 at 50% opacity (v0.12.0)
1378
+ - Resting border is border-subtle (soft); focus ring is `ring-1 ring-accent-7` (v0.12.0)
1366
1379
  - All sizes (sm, md, lg) use text-ds-md (14px) font — size only affects height and padding (v0.15.0)
1367
1380
 
1368
1381
  ## Changes
@@ -2163,6 +2176,7 @@ import { DataTableToolbar } from '@devalok/shilp-sutra/ui/data-table-toolbar'
2163
2176
  variant: "filled" | "bare"
2164
2177
  delay: number (ms — render delay to avoid flicker on fast operations)
2165
2178
  onComplete: () => void (callback after success/error state transition)
2179
+ className: string
2166
2180
 
2167
2181
  ## Defaults
2168
2182
  size: "md"
@@ -2476,7 +2490,7 @@ import { DataTableToolbar } from '@devalok/shilp-sutra/ui/data-table-toolbar'
2476
2490
 
2477
2491
  ## Gotchas
2478
2492
  - variant goes on TabsList, NOT on individual TabsTrigger (propagates via context)
2479
- - DO NOT put variant on TabsTrigger — it inherits from TabsList
2493
+ - Normally omit `variant` on TabsTrigger — it inherits from TabsList via context. You CAN set it per-trigger to override.
2480
2494
 
2481
2495
  ## Changes
2482
2496
  ### v0.18.0
@@ -2891,15 +2905,15 @@ export default function RootLayout({ children }) {
2891
2905
 
2892
2906
  ## Props
2893
2907
  items: ActivityItem[] (REQUIRED) — { id, actor?: { name, image? }, action: string|ReactNode, timestamp: Date|string, icon?, color?: 'default'|'success'|'warning'|'error'|'info', detail?: ReactNode }
2894
- onLoadMore: () => void — "Load more" button callback
2908
+ onLoadMore?: () => void — "Load more" button callback
2895
2909
  loading: boolean — skeleton shimmer
2896
- hasMore: boolean — shows "Load more" button
2897
- emptyState: ReactNode — empty state content
2910
+ hasMore?: boolean — shows "Load more" button
2911
+ emptyState?: ReactNode — empty state content
2898
2912
  compact: boolean — tighter spacing, no avatars, smaller text
2899
2913
  maxInitialItems: number — truncate with "Show all (N)" toggle
2900
2914
 
2901
2915
  ## Defaults
2902
- loading=false, compact=false
2916
+ loading=false, compact=false, hasMore=false
2903
2917
 
2904
2918
  ## Example
2905
2919
  ```jsx
@@ -2965,7 +2979,7 @@ export default function RootLayout({ children }) {
2965
2979
  - Category: composed
2966
2980
 
2967
2981
  ## Props
2968
- groups: CommandGroup[] — { label: string, items: CommandItem[] }
2982
+ groups?: CommandGroup[] (default: []) — { label: string, items: CommandItem[] }
2969
2983
  placeholder: string (default: "Search or jump to...")
2970
2984
  onSearch: (query: string) => void
2971
2985
  emptyMessage: string (default: "No results found.")
@@ -2973,7 +2987,7 @@ export default function RootLayout({ children }) {
2973
2987
  CommandItem shape: { id, label, description?, icon?, shortcut?, onSelect: () => void }
2974
2988
 
2975
2989
  ## Defaults
2976
- placeholder="Search or jump to...", emptyMessage="No results found."
2990
+ placeholder="Search or jump to...", emptyMessage="No results found.", groups=[]
2977
2991
 
2978
2992
  ## Example
2979
2993
  ```jsx
@@ -3012,7 +3026,7 @@ CommandItem shape: { id, label, description?, icon?, shortcut?, onSelect: () =>
3012
3026
  confirmText: string (default: "Confirm")
3013
3027
  cancelText: string (default: "Cancel")
3014
3028
  color: "default" | "error" (controls confirm button color)
3015
- loading: boolean (default: false, disables buttons and shows spinner)
3029
+ loading: boolean (default: false, disables buttons and replaces confirm button text with 'Processing...')
3016
3030
  onConfirm: () => void | Promise<void> (REQUIRED)
3017
3031
 
3018
3032
  ## Defaults
@@ -3089,8 +3103,8 @@ const [open, setOpen] = useState(false)
3089
3103
  ## Props
3090
3104
 
3091
3105
  ### DatePicker
3092
- value: Date | null
3093
- onChange: (date: Date | null) => void
3106
+ value?: Date | null
3107
+ onChange?: (date: Date | null) => void
3094
3108
  placeholder: string (default: "Pick a date")
3095
3109
  formatStr: string (default: "MMM d, yyyy")
3096
3110
  minDate: Date
@@ -3099,9 +3113,9 @@ const [open, setOpen] = useState(false)
3099
3113
  className: string
3100
3114
 
3101
3115
  ### DateRangePicker
3102
- startDate: Date | null
3103
- endDate: Date | null
3104
- onChange: (range: { start: Date | null, end: Date | null }) => void
3116
+ startDate?: Date | null
3117
+ endDate?: Date | null
3118
+ onChange?: (range: { start: Date | null, end: Date | null }) => void
3105
3119
  placeholder: string (default: "Pick a date range")
3106
3120
  formatStr: string (default: "MMM d, yyyy")
3107
3121
  minDate: Date
@@ -3122,8 +3136,8 @@ const [open, setOpen] = useState(false)
3122
3136
  className: string
3123
3137
 
3124
3138
  ### TimePicker
3125
- value: Date | null (time stored as a Date object)
3126
- onChange: (date: Date) => void
3139
+ value?: Date | null (time stored as a Date object)
3140
+ onChange?: (date: Date) => void
3127
3141
  format: "12h" | "24h" (default: "12h")
3128
3142
  minuteStep: number (default: 1)
3129
3143
  secondStep: number (default: 1)
@@ -3134,14 +3148,14 @@ const [open, setOpen] = useState(false)
3134
3148
 
3135
3149
  ### CalendarGrid
3136
3150
  currentMonth: Date (REQUIRED)
3137
- selected: Date | null
3138
- rangeStart: Date | null
3139
- rangeEnd: Date | null
3140
- hoverDate: Date | null
3151
+ selected?: Date | null
3152
+ rangeStart?: Date | null
3153
+ rangeEnd?: Date | null
3154
+ hoverDate?: Date | null
3141
3155
  onSelect: (date: Date) => void (REQUIRED)
3142
- onHover: (date: Date | null) => void
3156
+ onHover?: (date: Date | null) => void
3143
3157
  onMonthChange: (date: Date) => void (REQUIRED)
3144
- onHeaderClick: () => void
3158
+ onHeaderClick?: () => void
3145
3159
  disabledDates: (date: Date) => boolean
3146
3160
  minDate: Date
3147
3161
  maxDate: Date
@@ -3591,8 +3605,8 @@ MentionItem: { id: string; label: string; avatar?: string }
3591
3605
  view: "day" | "week" (REQUIRED)
3592
3606
  date: Date (REQUIRED — current day or any date in target week)
3593
3607
  events: ScheduleEvent[] (REQUIRED) — { id, title, start: Date, end: Date, color? }
3594
- onEventClick: (event: ScheduleEvent) => void
3595
- onSlotClick: (start: Date, end: Date) => void
3608
+ onEventClick?: (event: ScheduleEvent) => void
3609
+ onSlotClick?: (start: Date, end: Date) => void
3596
3610
  startHour: number (default: 8)
3597
3611
  endHour: number (default: 18, exclusive)
3598
3612
  slotDuration: number (minutes, default: 30)
@@ -3670,6 +3684,7 @@ Note: StatusBadge was server-safe prior to v0.18.0 but is NO LONGER server-safe
3670
3684
 
3671
3685
  ## Defaults
3672
3686
  size="md", hideDot=false
3687
+ When neither status nor color is passed, defaults to status='pending' styling
3673
3688
 
3674
3689
  ## Example
3675
3690
  ```jsx
@@ -3784,6 +3799,10 @@ BottomNavbarUser: { name: string, role?: string }
3784
3799
  - Requires LinkProvider for framework-specific link components (e.g., Next.js Link)
3785
3800
 
3786
3801
  ## Changes
3802
+ ### v0.19.0
3803
+ - **Changed** Background elevated from `bg-surface-1` to `bg-surface-2` for visual hierarchy above app background
3804
+ - **Changed** "More" menu and interactive items bumped accordingly
3805
+
3787
3806
  ### v0.18.0
3788
3807
  - **Fixed** Removed incorrect `role="button"` and `tabIndex` from overlay
3789
3808
 
@@ -3892,21 +3911,21 @@ import Link from 'next/link'
3892
3911
 
3893
3912
  ## Props
3894
3913
  notifications?: Notification[]
3895
- unreadCount: number (derived from notifications if not provided)
3896
- open: boolean (controlled mode)
3897
- onOpenChange: (open: boolean) => void
3898
- isLoading: boolean
3899
- hasMore: boolean
3900
- onFetchMore: () => void
3901
- onMarkRead: (id: string) => void
3902
- onMarkAllRead: () => void
3903
- onNavigate: (path: string) => void — called when a notification with a route is clicked
3904
- getNotificationRoute: (notification: Notification) => string | null — returns route for a notification; defaults to () => null
3905
- footerSlot: ReactNode — content rendered in a sticky footer below the scroll area
3906
- emptyState: ReactNode — replaces default empty state UI
3907
- headerActions: ReactNode — extra action buttons after "Mark all read"
3908
- popoverClassName: string — override default popover dimensions
3909
- onDismiss: (id: string) => void — when provided, each notification shows a dismiss button
3914
+ unreadCount?: number (derived from notifications if not provided)
3915
+ open?: boolean (controlled mode)
3916
+ onOpenChange?: (open: boolean) => void
3917
+ isLoading?: boolean
3918
+ hasMore?: boolean
3919
+ onFetchMore?: () => void
3920
+ onMarkRead?: (id: string) => void
3921
+ onMarkAllRead?: () => void
3922
+ onNavigate?: (path: string) => void — called when a notification with a route is clicked
3923
+ getNotificationRoute?: (notification: Notification) => string | null — returns route for a notification; defaults to () => null
3924
+ footerSlot?: ReactNode — content rendered in a sticky footer below the scroll area
3925
+ emptyState?: ReactNode — replaces default empty state UI
3926
+ headerActions?: ReactNode — extra action buttons after "Mark all read"
3927
+ popoverClassName?: string — override default popover dimensions
3928
+ onDismiss?: (id: string) => void — when provided, each notification shows a dismiss button
3910
3929
 
3911
3930
  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[] }
3912
3931
  NotificationAction: { label: string, variant?: 'primary' | 'default' | 'danger', onClick: (id: string) => void }
@@ -4012,7 +4031,7 @@ NavItem: { title: string, href: string, icon: ReactNode, exact?: boolean, badge?
4012
4031
  NavSubItem: { title: string, href: string, icon?: ReactNode, exact?: boolean }
4013
4032
  NavGroup: { label: string, items: NavItem[], action?: ReactNode }
4014
4033
  SidebarUser: { name: string, email?: string, image?: string | null, designation?: string, role?: string }
4015
- SidebarFooterConfig: { links: Array<{ label: string, href: string }>, version: string | { label: string, href: string }, slot: ReactNode, promo: SidebarPromo }
4034
+ SidebarFooterConfig: { links?: Array<{ label: string, href: string }>, version?: string | { label: string, href: string }, slot?: ReactNode, promo?: SidebarPromo }
4016
4035
  SidebarPromo: { text: string, icon?: ReactNode, action?: { label: string, href?: string, onClick?: () => void }, onDismiss?: () => void }
4017
4036
 
4018
4037
  ## Defaults
@@ -4048,6 +4067,10 @@ SidebarPromo: { text: string, icon?: ReactNode, action?: { label: string, href?:
4048
4067
  - Badge numbers > 99 display as "99+"
4049
4068
 
4050
4069
  ## Changes
4070
+ ### v0.19.0
4071
+ - **Changed** Background elevated from `bg-surface-1` to `bg-surface-2` for visual hierarchy above app background
4072
+ - **Changed** Interactive hover states bumped from `surface-2` to `surface-3`
4073
+
4051
4074
  ### v0.18.0
4052
4075
  - **Fixed** `bg-interactive-subtle` changed to `bg-accent-2` (OKLCH migration)
4053
4076
 
@@ -4083,16 +4106,54 @@ SidebarPromo: { text: string, icon?: ReactNode, action?: { label: string, href?:
4083
4106
  - Server-safe: No
4084
4107
  - Category: shell
4085
4108
 
4109
+ ## Overview
4110
+
4111
+ Composition-based application top bar. Uses dot-notation subcomponents for flexible layout.
4112
+
4113
+ ## Subcomponents
4114
+
4115
+ | Component | Purpose |
4116
+ |-----------|---------|
4117
+ | `TopBar` | Root — bg-surface-2, border-b, sticky. Auto-switches to grid when Center is present. |
4118
+ | `TopBar.Left` | Left zone — sidebar trigger, title, breadcrumbs |
4119
+ | `TopBar.Center` | Optional center zone — search bar, tabs. Triggers 3-column grid layout. |
4120
+ | `TopBar.Right` | Right zone — action buttons, user menu. Gets ml-auto in flex mode. |
4121
+ | `TopBar.Section` | Groups items with configurable gap |
4122
+ | `TopBar.IconButton` | Circular icon button with tooltip (bg-surface-3, hover:bg-surface-4) |
4123
+ | `TopBar.Title` | Page title heading, hidden on mobile |
4124
+ | `TopBar.UserMenu` | Avatar dropdown with color mode toggle, profile, logout |
4125
+
4086
4126
  ## Props
4087
- pageTitle?: string (default: "")
4088
- user?: TopBarUser | null — { name, email?, image? }
4127
+
4128
+ ### TopBar (root)
4129
+ children: ReactNode
4130
+ className?: string
4131
+
4132
+ ### TopBar.Left / TopBar.Center / TopBar.Right
4133
+ children: ReactNode
4134
+ className?: string
4135
+
4136
+ ### TopBar.Section
4137
+ gap?: "tight" | "default" | "loose" (default: "default")
4138
+ children: ReactNode
4139
+ className?: string
4140
+
4141
+ Gap values: tight = gap-ds-02, default = gap-ds-04, loose = gap-ds-06
4142
+
4143
+ ### TopBar.IconButton
4144
+ icon: ReactNode
4145
+ tooltip: string
4146
+ ...ButtonHTMLAttributes
4147
+
4148
+ ### TopBar.Title
4149
+ children: ReactNode
4150
+ className?: string
4151
+
4152
+ ### TopBar.UserMenu
4153
+ user: TopBarUser — { name, email?, image? }
4089
4154
  onNavigate?: (path: string) => void
4090
4155
  onLogout?: () => void
4091
- onSearchClick?: () => void
4092
- onAiChatClick?: () => void
4093
- mobileLogo?: ReactNode
4094
- notificationSlot?: ReactNode (render NotificationCenter here)
4095
- userMenuItems?: UserMenuItem[] — custom items between Profile and Dark/Light Mode toggle
4156
+ userMenuItems?: UserMenuItem[]
4096
4157
  className?: string
4097
4158
 
4098
4159
  TopBarUser: { name: string, email?: string, image?: string | null }
@@ -4106,30 +4167,69 @@ UserMenuItem fields:
4106
4167
  - badge — string for count badge, true for dot indicator
4107
4168
  - disabled — greys out the item
4108
4169
 
4109
- ## Defaults
4110
- None
4111
-
4112
4170
  ## Example
4171
+
4172
+ ### Two-zone (standard)
4113
4173
  ```jsx
4114
- <TopBar
4115
- pageTitle="Dashboard"
4116
- user={{ name: 'John', email: 'john@example.com' }}
4117
- onNavigate={(p) => router.push(p)}
4118
- onLogout={handleLogout}
4119
- notificationSlot={<NotificationCenter notifications={notifications} />}
4120
- userMenuItems={[
4121
- { label: 'Changelog', icon: <IconNews />, href: '/changelog', badge: '3' },
4122
- { label: 'Shortcuts', icon: <IconKeyboard />, onClick: () => openModal() },
4123
- ]}
4124
- />
4174
+ <TopBar>
4175
+ <TopBar.Left>
4176
+ <SidebarTrigger />
4177
+ <TopBar.Title>Dashboard</TopBar.Title>
4178
+ </TopBar.Left>
4179
+ <TopBar.Right>
4180
+ <TopBar.Section gap="tight">
4181
+ <TopBar.IconButton icon={<IconSearch />} tooltip="Search (Ctrl+K)" onClick={openSearch} />
4182
+ <NotificationCenter notifications={notifications} />
4183
+ <TopBar.IconButton icon={<IconSparkles />} tooltip="AI Chat" onClick={openAI} />
4184
+ </TopBar.Section>
4185
+ <TopBar.UserMenu
4186
+ user={{ name: 'John', email: 'john@example.com' }}
4187
+ onNavigate={(p) => router.push(p)}
4188
+ onLogout={handleLogout}
4189
+ userMenuItems={[
4190
+ { label: 'Changelog', icon: <IconNews />, href: '/changelog', badge: '3' },
4191
+ ]}
4192
+ />
4193
+ </TopBar.Right>
4194
+ </TopBar>
4195
+ ```
4196
+
4197
+ ### Three-zone (centered search bar)
4198
+ ```jsx
4199
+ <TopBar>
4200
+ <TopBar.Left>
4201
+ <SidebarTrigger />
4202
+ <TopBar.Title>Dashboard</TopBar.Title>
4203
+ </TopBar.Left>
4204
+ <TopBar.Center>
4205
+ <SearchBarTrigger />
4206
+ </TopBar.Center>
4207
+ <TopBar.Right>
4208
+ <TopBar.Section gap="tight">
4209
+ <TopBar.IconButton icon={<IconBell />} tooltip="Notifications" onClick={fn} />
4210
+ </TopBar.Section>
4211
+ <TopBar.UserMenu user={user} onLogout={logout} />
4212
+ </TopBar.Right>
4213
+ </TopBar>
4125
4214
  ```
4126
4215
 
4127
4216
  ## Gotchas
4128
- - `notificationSlot` is where NotificationCenter should be rendered
4129
- - `userMenuItems` are inserted between the Profile link and the Dark/Light Mode toggle in the user dropdown
4130
- - Requires LinkProvider for framework-specific navigation
4217
+ - Without `TopBar.Center`, layout is flex (two-zone). With it, layout switches to CSS grid `1fr auto 1fr` for true centering.
4218
+ - `TopBar.IconButton` renders any number of action buttons no artificial limit. Use responsive hiding (`className="hidden md:flex"`) for mobile.
4219
+ - `TopBar.UserMenu` includes Profile link, color mode toggle, and logout automatically. `userMenuItems` are inserted between Profile and the toggle.
4220
+ - Requires SidebarProvider wrapper for SidebarTrigger to work.
4131
4221
 
4132
4222
  ## Changes
4223
+ ### v0.19.0
4224
+ - **BREAKING** Rewritten as composition API. Old props-based API removed (`pageTitle`, `onSearchClick`, `onAiChatClick`, `notificationSlot`, `mobileLogo` props).
4225
+ - **Added** `TopBar.Left`, `TopBar.Center`, `TopBar.Right` zone components
4226
+ - **Added** `TopBar.Section` with `gap` prop (`tight` | `default` | `loose`)
4227
+ - **Added** `TopBar.IconButton` — reusable circular icon button with tooltip
4228
+ - **Added** `TopBar.Title` — responsive page title (hidden on mobile)
4229
+ - **Added** `TopBar.UserMenu` — extracted user dropdown as standalone subcomponent
4230
+ - **Added** Auto grid/flex layout detection based on Center zone presence
4231
+ - **Changed** Background elevated from `bg-surface-1` to `bg-surface-2`
4232
+
4133
4233
  ### v0.7.0
4134
4234
  - **Added** `userMenuItems` prop for custom dropdown items
4135
4235
 
package/llms.txt CHANGED
@@ -245,7 +245,7 @@ NOTIFICATION SELECTION GUIDE:
245
245
  - Page skeletons: DashboardSkeleton, ProjectListSkeleton, TaskDetailSkeleton (no props, server-safe)
246
246
 
247
247
  ### Shell Components (app-level layout)
248
- - TopBar: pageTitle, user, onNavigate, onLogout, notificationSlot, mobileLogo, userMenuItems?(UserMenuItem[]). Types: TopBarUser = { name, email?, image? }, UserMenuItem = { label, icon?, href?, onClick?, separator?, color?, badge?, disabled? }
248
+ - TopBar: Composition-based. Subcomponents: TopBar.Left, TopBar.Center (optional, triggers grid), TopBar.Right, TopBar.Section(gap: tight|default|loose), TopBar.IconButton(icon, tooltip), TopBar.Title, TopBar.UserMenu(user, onNavigate?, onLogout?, userMenuItems?). Types: TopBarUser = { name, email?, image? }, UserMenuItem = { label, icon?, href?, onClick?, separator?, color?, badge?, disabled? }
249
249
  - AppSidebar: navigation tree with NavItem[], NavGroup[]. Types: NavItem = { title, href, icon, exact?, badge?, children?, defaultOpen? }, NavSubItem = { title, href, icon?, exact? }, NavGroup = { label, items, action? }, SidebarUser = { name, email?, image?, designation?, role? }
250
250
 
251
251
  ### AppSidebar (v0.10.0 additions)