@devalok/shilp-sutra 0.25.1 → 0.27.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 (123) hide show
  1. package/dist/_chunks/framer.js +4824 -805
  2. package/dist/_chunks/primitives.js +39 -39
  3. package/dist/_chunks/sonner.js +747 -0
  4. package/dist/_chunks/tiptap.js +3949 -2969
  5. package/dist/_chunks/vendor-client.js +1071 -1793
  6. package/dist/_chunks/vendor-utils.js +632 -5795
  7. package/dist/ai/index.js +1 -1
  8. package/dist/composed/avatar-group.js +1 -1
  9. package/dist/composed/bulk-action-bar.d.ts +29 -0
  10. package/dist/composed/bulk-action-bar.d.ts.map +1 -0
  11. package/dist/composed/bulk-action-bar.js +123 -0
  12. package/dist/composed/content-card.js +1 -1
  13. package/dist/composed/deadline-indicator.d.ts +18 -0
  14. package/dist/composed/deadline-indicator.d.ts.map +1 -0
  15. package/dist/composed/deadline-indicator.js +75 -0
  16. package/dist/composed/emoji-picker.d.ts +26 -0
  17. package/dist/composed/emoji-picker.d.ts.map +1 -0
  18. package/dist/composed/emoji-picker.js +104 -0
  19. package/dist/composed/file-preview.d.ts +22 -0
  20. package/dist/composed/file-preview.d.ts.map +1 -0
  21. package/dist/composed/file-preview.js +675 -0
  22. package/dist/composed/filter-bar.d.ts +38 -0
  23. package/dist/composed/filter-bar.d.ts.map +1 -0
  24. package/dist/composed/filter-bar.js +133 -0
  25. package/dist/composed/form-section.d.ts +12 -0
  26. package/dist/composed/form-section.d.ts.map +1 -0
  27. package/dist/composed/form-section.js +45 -0
  28. package/dist/composed/index.d.ts +22 -0
  29. package/dist/composed/index.d.ts.map +1 -1
  30. package/dist/composed/index.js +61 -36
  31. package/dist/composed/inline-edit.d.ts +16 -0
  32. package/dist/composed/inline-edit.d.ts.map +1 -0
  33. package/dist/composed/inline-edit.js +107 -0
  34. package/dist/composed/markdown-viewer.d.ts +14 -0
  35. package/dist/composed/markdown-viewer.d.ts.map +1 -0
  36. package/dist/composed/markdown-viewer.js +143 -0
  37. package/dist/composed/master-detail.d.ts +35 -0
  38. package/dist/composed/master-detail.d.ts.map +1 -0
  39. package/dist/composed/master-detail.js +124 -0
  40. package/dist/composed/member-picker.d.ts.map +1 -1
  41. package/dist/composed/member-picker.js +41 -88
  42. package/dist/composed/multi-select-popover.d.ts +44 -0
  43. package/dist/composed/multi-select-popover.d.ts.map +1 -0
  44. package/dist/composed/multi-select-popover.js +185 -0
  45. package/dist/composed/priority-indicator.js +1 -1
  46. package/dist/composed/responsive-overlay.d.ts +15 -0
  47. package/dist/composed/responsive-overlay.d.ts.map +1 -0
  48. package/dist/composed/responsive-overlay.js +45 -0
  49. package/dist/composed/status-badge.js +1 -1
  50. package/dist/tailwind/index.cjs +37 -3
  51. package/dist/tailwind/preset.js +1 -1
  52. package/dist/ui/alert-dialog.js +10 -10
  53. package/dist/ui/alert.js +1 -1
  54. package/dist/ui/avatar.js +2 -2
  55. package/dist/ui/badge.js +1 -1
  56. package/dist/ui/banner.js +4 -4
  57. package/dist/ui/button.d.ts +1 -1
  58. package/dist/ui/button.d.ts.map +1 -1
  59. package/dist/ui/button.js +48 -42
  60. package/dist/ui/card.d.ts +6 -48
  61. package/dist/ui/card.d.ts.map +1 -1
  62. package/dist/ui/card.js +92 -49
  63. package/dist/ui/checkbox.js +1 -1
  64. package/dist/ui/chip.js +1 -1
  65. package/dist/ui/collapsible.js +1 -1
  66. package/dist/ui/color-swatch.d.ts +27 -0
  67. package/dist/ui/color-swatch.d.ts.map +1 -0
  68. package/dist/ui/color-swatch.js +91 -0
  69. package/dist/ui/data-table.d.ts +7 -1
  70. package/dist/ui/data-table.d.ts.map +1 -1
  71. package/dist/ui/data-table.js +221 -215
  72. package/dist/ui/dialog.js +4 -4
  73. package/dist/ui/dropdown-menu.js +31 -31
  74. package/dist/ui/index.d.ts +3 -0
  75. package/dist/ui/index.d.ts.map +1 -1
  76. package/dist/ui/index.js +187 -180
  77. package/dist/ui/input.d.ts +1 -1
  78. package/dist/ui/input.d.ts.map +1 -1
  79. package/dist/ui/input.js +11 -10
  80. package/dist/ui/label.js +1 -1
  81. package/dist/ui/lib/utils.js +1 -1
  82. package/dist/ui/progress-ring.d.ts +46 -0
  83. package/dist/ui/progress-ring.d.ts.map +1 -0
  84. package/dist/ui/progress-ring.js +144 -0
  85. package/dist/ui/progress.js +12 -12
  86. package/dist/ui/search-input.d.ts +1 -1
  87. package/dist/ui/search-input.d.ts.map +1 -1
  88. package/dist/ui/search-input.js +9 -8
  89. package/dist/ui/segmented-control.js +1 -1
  90. package/dist/ui/select.d.ts +1 -1
  91. package/dist/ui/select.d.ts.map +1 -1
  92. package/dist/ui/select.js +29 -28
  93. package/dist/ui/sheet.js +6 -6
  94. package/dist/ui/sidebar.js +15 -15
  95. package/dist/ui/skeleton.js +1 -1
  96. package/dist/ui/status-dot.d.ts +27 -0
  97. package/dist/ui/status-dot.d.ts.map +1 -0
  98. package/dist/ui/status-dot.js +64 -0
  99. package/dist/ui/tabs.js +18 -18
  100. package/dist/ui/text.js +1 -1
  101. package/dist/ui/textarea.d.ts +1 -1
  102. package/dist/ui/textarea.d.ts.map +1 -1
  103. package/dist/ui/textarea.js +14 -13
  104. package/dist/ui/toast.js +1 -1
  105. package/dist/ui/toaster.js +1 -1
  106. package/dist/ui/toggle.js +4 -4
  107. package/docs/components/composed/bulk-action-bar.md +40 -0
  108. package/docs/components/composed/deadline-indicator.md +27 -0
  109. package/docs/components/composed/emoji-picker.md +43 -0
  110. package/docs/components/composed/file-preview.md +40 -0
  111. package/docs/components/composed/filter-bar.md +57 -0
  112. package/docs/components/composed/form-section.md +31 -0
  113. package/docs/components/composed/inline-edit.md +35 -0
  114. package/docs/components/composed/markdown-viewer.md +27 -0
  115. package/docs/components/composed/master-detail.md +48 -0
  116. package/docs/components/composed/multi-select-popover.md +53 -0
  117. package/docs/components/composed/responsive-overlay.md +34 -0
  118. package/docs/components/ui/color-swatch.md +25 -0
  119. package/docs/components/ui/progress-ring.md +41 -0
  120. package/docs/components/ui/status-dot.md +26 -0
  121. package/llms-full.txt +528 -1
  122. package/llms.txt +53 -9
  123. package/package.json +820 -733
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.25.1
8
+ > Version: 0.27.0
9
9
 
10
10
  ---
11
11
 
@@ -871,6 +871,31 @@ import { BarChart } from '@devalok/shilp-sutra/ui/charts'
871
871
 
872
872
  ### v0.1.0
873
873
  - **Added** Initial release
874
+ # ColorSwatch
875
+
876
+ - Import: @devalok/shilp-sutra/ui/color-swatch
877
+ - Server-safe: Yes
878
+ - Category: ui
879
+
880
+ ## Props
881
+ color: string (any valid CSS color — hex, rgb, oklch, etc.)
882
+ size: "sm" | "md" | "lg"
883
+ shape: "circle" | "square" | "rounded"
884
+ ring: boolean (shows subtle ring border — useful for light colors that blend into the background)
885
+
886
+ ## Defaults
887
+ size="md", shape="circle", ring={false}
888
+
889
+ ## Example
890
+ ```jsx
891
+ <ColorSwatch color="#FF5733" />
892
+ <ColorSwatch color={org.brandColor} size="lg" ring />
893
+ <ColorSwatch color="oklch(0.7 0.15 200)" shape="rounded" />
894
+ ```
895
+
896
+ ## Gotchas
897
+ - Color is applied via inline `backgroundColor` style, not a token class — accepts any runtime CSS color string
898
+ - Renders `role="presentation"` — purely decorative, not interactive
874
899
  # Combobox
875
900
 
876
901
  - Import: @devalok/shilp-sutra/ui/combobox
@@ -1775,6 +1800,47 @@ import { DataTableToolbar } from '@devalok/shilp-sutra/ui/data-table-toolbar'
1775
1800
  ## Changes
1776
1801
  ### v0.1.0
1777
1802
  - **Added** Initial release with `size`, `color`, `indeterminate` variants and optional label slot
1803
+ # ProgressRing
1804
+
1805
+ - Import: @devalok/shilp-sutra/ui/progress-ring
1806
+ - Server-safe: No
1807
+ - Category: ui
1808
+
1809
+ ## Props
1810
+
1811
+ ### ProgressRing
1812
+ value: number (current progress value)
1813
+ max: number (maximum value)
1814
+ size: "sm" | "md" | "lg"
1815
+ color: "default" | "success" | "warning" | "error" | "info"
1816
+ showValue: boolean (show percentage text in center)
1817
+ label: string (accessible label — falls back to "{n}% progress")
1818
+
1819
+ ### MultiProgressRing
1820
+ rings: Array<{ value: number; max?: number; color?: "default" | "success" | "warning" | "error" | "info"; label?: string }>
1821
+ size: "sm" | "md" | "lg"
1822
+
1823
+ ## Defaults
1824
+ max={100}, size="md", color="default", showValue={false}
1825
+
1826
+ ## Example
1827
+ ```jsx
1828
+ <ProgressRing value={75} />
1829
+ <ProgressRing value={3} max={12} size="lg" color="warning" showValue />
1830
+
1831
+ <MultiProgressRing
1832
+ rings={[
1833
+ { value: 80, color: 'error', label: 'Move' },
1834
+ { value: 60, color: 'success', label: 'Exercise' },
1835
+ ]}
1836
+ size="lg"
1837
+ />
1838
+ ```
1839
+
1840
+ ## Gotchas
1841
+ - Uses Framer Motion for the animated fill — not server-safe
1842
+ - Value is clamped to `[0, max]` internally
1843
+ - MultiProgressRing skips rings whose computed radius would be <= 0 (too many rings for the size)
1778
1844
  # RadioGroup
1779
1845
 
1780
1846
  - Import: @devalok/shilp-sutra/ui/radio
@@ -2359,6 +2425,32 @@ import { DataTableToolbar } from '@devalok/shilp-sutra/ui/data-table-toolbar'
2359
2425
 
2360
2426
  ### v0.1.0
2361
2427
  - **Added** Initial release
2428
+ # StatusDot
2429
+
2430
+ - Import: @devalok/shilp-sutra/ui/status-dot
2431
+ - Server-safe: Yes
2432
+ - Category: ui
2433
+
2434
+ ## Props
2435
+ status: "healthy" | "warning" | "critical" | "neutral" | "inactive"
2436
+ size: "sm" | "md" | "lg"
2437
+ pulse: boolean (ping animation; defaults to true for "healthy", false for others)
2438
+ label: string (inline text rendered after the dot)
2439
+ labelClassName: string (extra classes on the label span)
2440
+
2441
+ ## Defaults
2442
+ size="md", pulse={status === "healthy"}
2443
+
2444
+ ## Example
2445
+ ```jsx
2446
+ <StatusDot status="healthy" />
2447
+ <StatusDot status="critical" label="Service down" pulse />
2448
+ <StatusDot status="warning" size="lg" label="Elevated load" />
2449
+ ```
2450
+
2451
+ ## Gotchas
2452
+ - The `pulse` prop auto-enables for "healthy" status — pass `pulse={false}` to suppress
2453
+ - Status type is exported as `StatusDotStatus` if you need it in consumer code
2362
2454
  # Stepper / Step
2363
2455
 
2364
2456
  - Import: @devalok/shilp-sutra/ui/stepper
@@ -3063,6 +3155,46 @@ export default function RootLayout({ children }) {
3063
3155
 
3064
3156
  ### v0.1.0
3065
3157
  - **Added** Initial release
3158
+ # BulkActionBar
3159
+
3160
+ - Import: @devalok/shilp-sutra/composed/bulk-action-bar
3161
+ - Server-safe: No
3162
+ - Category: composed
3163
+
3164
+ ## Props
3165
+ show: boolean (controls visibility)
3166
+ count: number (number of selected items — displayed in badge)
3167
+ onClearSelection: () => void
3168
+ actions: BulkActionBarAction[]
3169
+ className: string
3170
+
3171
+ ### BulkActionBarAction
3172
+ label: string
3173
+ icon: ComponentType<{ className?: string }> (optional icon component)
3174
+ onClick: () => void
3175
+ color: "default" | "error"
3176
+ disabled: boolean
3177
+
3178
+ ## Defaults
3179
+ (no optional props with defaults)
3180
+
3181
+ ## Example
3182
+ ```jsx
3183
+ <BulkActionBar
3184
+ show={selected.length > 0}
3185
+ count={selected.length}
3186
+ onClearSelection={() => setSelected([])}
3187
+ actions={[
3188
+ { label: 'Archive', icon: IconArchive, onClick: archiveSelected },
3189
+ { label: 'Delete', icon: IconTrash, onClick: deleteSelected, color: 'error' },
3190
+ ]}
3191
+ />
3192
+ ```
3193
+
3194
+ ## Gotchas
3195
+ - Renders via `createPortal` into `document.body` — will not appear during SSR (mounts only client-side)
3196
+ - Positioned fixed at bottom-center with `z-50`; ensure no other fixed elements conflict
3197
+ - Uses Framer Motion AnimatePresence for slide-in/out animation
3066
3198
  # CommandPalette
3067
3199
 
3068
3200
  - Import: @devalok/shilp-sutra/composed/command-palette
@@ -3315,6 +3447,76 @@ PresetKey: 'today' | 'yesterday' | 'last7days' | 'last30days' | 'thisMonth' | 'l
3315
3447
 
3316
3448
  ### v0.1.0
3317
3449
  - **Added** Initial release
3450
+ # DeadlineIndicator
3451
+
3452
+ - Import: @devalok/shilp-sutra/composed/deadline-indicator
3453
+ - Server-safe: Yes
3454
+ - Category: composed
3455
+
3456
+ ## Props
3457
+ deadline: Date | string (deadline timestamp)
3458
+ warningThreshold: number (minutes before deadline to show warning color)
3459
+ criticalThreshold: number (minutes before deadline to show critical/error color)
3460
+ format: "relative" | "absolute"
3461
+ showIcon: boolean (show clock icon prefix)
3462
+
3463
+ ## Defaults
3464
+ warningThreshold={1440} (24h), criticalThreshold={240} (4h), format="relative", showIcon={false}
3465
+
3466
+ ## Example
3467
+ ```jsx
3468
+ <DeadlineIndicator deadline={task.dueDate} />
3469
+ <DeadlineIndicator deadline="2026-03-20T17:00:00Z" showIcon format="absolute" />
3470
+ <DeadlineIndicator deadline={task.dueDate} warningThreshold={2880} criticalThreshold={480} />
3471
+ ```
3472
+
3473
+ ## Gotchas
3474
+ - Color is semantic: green (on-track) -> yellow (warning threshold) -> red (critical/overdue)
3475
+ - Overdue deadlines show bold red text with "Overdue by Xd/h/m"
3476
+ - Relative format uses `Date.now()` at render time — does not live-update (re-render to refresh)
3477
+ # EmojiPicker
3478
+
3479
+ - Import: @devalok/shilp-sutra/composed/emoji-picker
3480
+ - Server-safe: No
3481
+ - Category: composed
3482
+
3483
+ ## Exports
3484
+ EmojiPicker, EmojiPickerPopover
3485
+
3486
+ ## Props
3487
+
3488
+ ### EmojiPicker
3489
+ onSelect: (emoji: EmojiData) => void
3490
+ theme: "auto" | "light" | "dark"
3491
+ previewPosition: "top" | "bottom" | "none"
3492
+ skinTonePosition: "search" | "preview" | "none"
3493
+ className: string
3494
+
3495
+ ### EmojiPickerPopover (extends EmojiPicker props)
3496
+ children: ReactNode (trigger element)
3497
+ align: "start" | "center" | "end"
3498
+
3499
+ ### EmojiData
3500
+ id: string
3501
+ native: string (the emoji character)
3502
+ shortcodes: string
3503
+
3504
+ ## Defaults
3505
+ theme="auto", previewPosition="none", skinTonePosition="search", align="start"
3506
+
3507
+ ## Example
3508
+ ```jsx
3509
+ <EmojiPickerPopover onSelect={(emoji) => insertEmoji(emoji.native)}>
3510
+ <Button variant="ghost" size="icon-sm">😀</Button>
3511
+ </EmojiPickerPopover>
3512
+
3513
+ <EmojiPicker onSelect={handleEmoji} theme="dark" />
3514
+ ```
3515
+
3516
+ ## Gotchas
3517
+ - Wraps `@emoji-mart/react` which is lazy-loaded — shows a Skeleton placeholder while loading
3518
+ - `theme="auto"` reads the `.dark` class on `<html>` to pick light/dark
3519
+ - EmojiPickerPopover auto-closes after selection
3318
3520
  # EmptyState
3319
3521
 
3320
3522
  - Import: @devalok/shilp-sutra/composed/empty-state
@@ -3397,6 +3599,134 @@ Note: EmptyState was server-safe prior to v0.18.0 but is NO LONGER server-safe d
3397
3599
 
3398
3600
  ### v0.1.0
3399
3601
  - **Added** Initial release
3602
+ # FilePreview
3603
+
3604
+ - Import: @devalok/shilp-sutra/composed/file-preview
3605
+ - Server-safe: No
3606
+ - Category: composed
3607
+
3608
+ ## Props
3609
+ url: string (file URL — required)
3610
+ type: "image" | "pdf" | "video" | "audio" | "embed" (auto-detected from URL/mimeType)
3611
+ mimeType: string (helps auto-detection)
3612
+ alt: string (image alt text)
3613
+ initialPage: number (PDF starting page, default 1)
3614
+ fileName: string (displayed in file info bar)
3615
+ fileSize: string (displayed as badge, e.g. "2.4 MB")
3616
+ onError: (error: string) => void (called on load failures)
3617
+
3618
+ ## Defaults
3619
+ initialPage={1}, type auto-detected
3620
+
3621
+ ## Features by Type
3622
+
3623
+ **Image:** Pinch/scroll zoom (0.1x–8x), double-click toggle, floating toolbar (zoom %/reset/fullscreen), keyboard (+/-/0/F/Esc)
3624
+ **PDF:** react-pdf page nav (prev/next + direct input), keyboard (←→), crossfade between pages
3625
+ **Video:** Custom branded player, play overlay, auto-hiding controls, progress bar + scrub handle, mute, fullscreen
3626
+ **Audio:** Branded mini-player, full-width progress bar with hover tooltip + scrub handle, volume, file name display
3627
+ **Embed:** 16:9 aspect ratio, auto-converts YouTube/Vimeo/Figma/Loom URLs, 15s timeout
3628
+
3629
+ ## Example
3630
+ ```jsx
3631
+ <FilePreview url="/uploads/mockup.png" fileName="mockup.png" fileSize="2.4 MB" />
3632
+ <FilePreview url="/docs/contract.pdf" initialPage={3} />
3633
+ <FilePreview url="https://youtube.com/watch?v=..." />
3634
+ ```
3635
+
3636
+ ## Gotchas
3637
+ - Image/PDF lazy-loaded (Skeleton on first render)
3638
+ - PDF worker from unpkg CDN — configure workerSrc for offline apps
3639
+ - All types have error fallback with download link
3640
+ - Embed URLs auto-converted to embed format
3641
+ - Audio player doesn't show separate Download button (integrated in card)
3642
+ # FilterBar
3643
+
3644
+ - Import: @devalok/shilp-sutra/composed/filter-bar
3645
+ - Server-safe: No
3646
+ - Category: composed
3647
+
3648
+ ## Exports
3649
+ FilterBar, FilterSelect, FilterMultiSelect
3650
+
3651
+ ## Props
3652
+
3653
+ ### FilterBar
3654
+ searchValue: string
3655
+ onSearchChange: (value: string) => void (renders SearchInput when provided)
3656
+ searchPlaceholder: string
3657
+ onClearAll: () => void (renders "Clear all" button when provided)
3658
+ size: "xs" | "sm" | "md" (propagated to all child controls via context)
3659
+ children: ReactNode (FilterSelect / FilterMultiSelect controls)
3660
+
3661
+ ### FilterSelect
3662
+ label: string
3663
+ value: string
3664
+ onValueChange: (value: string) => void
3665
+ options: { value: string; label: string }[]
3666
+ allLabel: string (label for the "all" option)
3667
+
3668
+ ### FilterMultiSelect
3669
+ label: string
3670
+ value: string[]
3671
+ onValueChange: (values: string[]) => void
3672
+ options: { value: string; label: string }[]
3673
+
3674
+ ## Defaults
3675
+ size="sm", searchPlaceholder="Search...", allLabel="All"
3676
+
3677
+ ## Example
3678
+ ```jsx
3679
+ <FilterBar searchValue={search} onSearchChange={setSearch} onClearAll={clearFilters}>
3680
+ <FilterSelect
3681
+ label="Status"
3682
+ value={status}
3683
+ onValueChange={setStatus}
3684
+ options={[{ value: 'active', label: 'Active' }, { value: 'done', label: 'Done' }]}
3685
+ />
3686
+ <FilterMultiSelect
3687
+ label="Assignees"
3688
+ value={assignees}
3689
+ onValueChange={setAssignees}
3690
+ options={memberOptions}
3691
+ />
3692
+ </FilterBar>
3693
+ ```
3694
+
3695
+ ## Gotchas
3696
+ - FilterSelect and FilterMultiSelect must be direct children of FilterBar to inherit the size context
3697
+ - FilterSelect uses `"all"` as the sentinel value for "no filter" — do not use `"all"` as a real option value
3698
+ - Active filters get an accent border highlight automatically
3699
+ # FormSection
3700
+
3701
+ - Import: @devalok/shilp-sutra/composed/form-section
3702
+ - Server-safe: No
3703
+ - Category: composed
3704
+
3705
+ ## Props
3706
+ title: string
3707
+ description: string (subtitle text below the title)
3708
+ collapsible: boolean (wraps content in a Collapsible)
3709
+ defaultOpen: boolean (initial open state when collapsible)
3710
+ children: ReactNode (form fields)
3711
+
3712
+ ## Defaults
3713
+ collapsible={false}, defaultOpen={true}
3714
+
3715
+ ## Example
3716
+ ```jsx
3717
+ <FormSection title="General" description="Basic project settings">
3718
+ <FormField .../>
3719
+ <FormField .../>
3720
+ </FormSection>
3721
+
3722
+ <FormSection title="Advanced" collapsible defaultOpen={false}>
3723
+ <FormField .../>
3724
+ </FormSection>
3725
+ ```
3726
+
3727
+ ## Gotchas
3728
+ - `defaultOpen` only applies when `collapsible={true}` — otherwise the section is always open
3729
+ - Renders a horizontal rule between the header and content automatically
3400
3730
  # GlobalLoading
3401
3731
 
3402
3732
  - Import: @devalok/shilp-sutra/composed/global-loading
@@ -3424,6 +3754,41 @@ Note: EmptyState was server-safe prior to v0.18.0 but is NO LONGER server-safe d
3424
3754
 
3425
3755
  ### v0.1.0
3426
3756
  - **Added** Initial release
3757
+ # InlineEdit
3758
+
3759
+ - Import: @devalok/shilp-sutra/composed/inline-edit
3760
+ - Server-safe: No
3761
+ - Category: composed
3762
+
3763
+ ## Props
3764
+ value: string (current text value)
3765
+ onSave: (newValue: string) => void | Promise<void> (called on commit; async shows spinner)
3766
+ placeholder: string (shown when value is empty)
3767
+ textClassName: string (CSS class for the editable text, e.g. "text-ds-lg font-semibold")
3768
+ readOnly: boolean
3769
+ maxLength: number
3770
+ saving: boolean (external saving state — shows spinner, disables editing)
3771
+
3772
+ ## Defaults
3773
+ placeholder="Click to edit", readOnly={false}, saving={false}
3774
+
3775
+ ## Example
3776
+ ```jsx
3777
+ <InlineEdit
3778
+ value={title}
3779
+ onSave={(v) => updateTitle(v)}
3780
+ textClassName="text-ds-lg font-semibold"
3781
+ />
3782
+ ```
3783
+
3784
+ ## Gotchas
3785
+ - Uses contentEditable — the text IS the editor. No input field appears.
3786
+ - Click to focus → cursor appears in text. Type to edit. Enter saves. Escape reverts.
3787
+ - Text is auto-selected on focus (like renaming a file in Finder)
3788
+ - Paste is restricted to plain text (no rich content)
3789
+ - The value is trimmed before calling `onSave`; if unchanged, `onSave` is not called
3790
+ - If `onSave` returns a Promise, a spinner is shown and editing is disabled until it resolves
3791
+ - On Promise rejection, the text reverts to the original value
3427
3792
  # LoadingSkeleton
3428
3793
 
3429
3794
  - Import: @devalok/shilp-sutra/composed/loading-skeleton
@@ -3475,6 +3840,81 @@ Exports: CardSkeleton, TableSkeleton, BoardSkeleton, ListSkeleton
3475
3840
 
3476
3841
  ### v0.1.0
3477
3842
  - **Added** Initial release
3843
+ # MarkdownViewer
3844
+
3845
+ - Import: @devalok/shilp-sutra/composed/markdown-viewer
3846
+ - Server-safe: No
3847
+ - Category: composed
3848
+
3849
+ ## Props
3850
+ content: string (markdown source)
3851
+ compact: boolean (tighter spacing for inline use)
3852
+ allowHtml: boolean (allow raw HTML in markdown)
3853
+ linkTarget: string (target attribute for links)
3854
+
3855
+ ## Defaults
3856
+ compact={false}, allowHtml={false}, linkTarget="_blank"
3857
+
3858
+ ## Example
3859
+ ```jsx
3860
+ <MarkdownViewer content={message.body} />
3861
+ <MarkdownViewer content={comment} compact />
3862
+ <MarkdownViewer content={trustedHtml} allowHtml />
3863
+ ```
3864
+
3865
+ ## Gotchas
3866
+ - Code blocks with a language fence are syntax-highlighted via `react-syntax-highlighter` (lazy-loaded) — the first render shows a plain `<pre>` fallback
3867
+ - GFM (tables, strikethrough, task lists) is supported via `remark-gfm`
3868
+ - Raw HTML is stripped by default — only enable `allowHtml` for trusted content
3869
+ - Links open in a new tab by default (`target="_blank"` with `rel="noopener noreferrer"`)
3870
+ # MasterDetail
3871
+
3872
+ - Import: @devalok/shilp-sutra/composed/master-detail
3873
+ - Server-safe: No
3874
+ - Category: composed
3875
+
3876
+ ## Compound Components
3877
+ MasterDetail (root), MasterDetail.List, MasterDetail.Detail, MasterDetail.ListItem
3878
+
3879
+ ## Props
3880
+
3881
+ ### MasterDetail (root)
3882
+ selected: string | null (ID of currently selected item; null = show list on mobile)
3883
+ onBack: () => void (called when mobile back button is pressed)
3884
+ masterWidth: string (master panel width on desktop)
3885
+ breakpoint: "sm" | "md" | "lg" (below this, stacked mobile mode activates)
3886
+
3887
+ ### MasterDetail.ListItem
3888
+ active: boolean (highlights the item)
3889
+ (extends ButtonHTMLAttributes)
3890
+
3891
+ ## Defaults
3892
+ selected={null}, masterWidth="280px", breakpoint="md"
3893
+
3894
+ ## Example
3895
+ ```jsx
3896
+ <MasterDetail selected={selectedId} onBack={() => setSelectedId(null)}>
3897
+ <MasterDetail.List>
3898
+ {items.map((item) => (
3899
+ <MasterDetail.ListItem
3900
+ key={item.id}
3901
+ active={item.id === selectedId}
3902
+ onClick={() => setSelectedId(item.id)}
3903
+ >
3904
+ {item.name}
3905
+ </MasterDetail.ListItem>
3906
+ ))}
3907
+ </MasterDetail.List>
3908
+ <MasterDetail.Detail>
3909
+ {selectedId ? <ItemDetail id={selectedId} /> : <EmptyState />}
3910
+ </MasterDetail.Detail>
3911
+ </MasterDetail>
3912
+ ```
3913
+
3914
+ ## Gotchas
3915
+ - On mobile (below breakpoint), List and Detail are mutually exclusive — selecting an item hides the list
3916
+ - The `onBack` callback is required for the mobile back button to appear in the Detail pane
3917
+ - Uses `window.matchMedia` — SSR renders desktop layout initially, then hydrates to correct mode
3478
3918
  # MemberPicker
3479
3919
 
3480
3920
  - Import: @devalok/shilp-sutra/composed/member-picker
@@ -3510,6 +3950,59 @@ Exports: CardSkeleton, TableSkeleton, BoardSkeleton, ListSkeleton
3510
3950
 
3511
3951
  ### v0.1.0
3512
3952
  - **Added** Initial release
3953
+ # MultiSelectPopover
3954
+
3955
+ - Import: @devalok/shilp-sutra/composed/multi-select-popover
3956
+ - Server-safe: No
3957
+ - Category: composed
3958
+
3959
+ ## Props
3960
+ items: MultiSelectItem[] (flat list — use `groups` for grouped rendering)
3961
+ groups: MultiSelectGroup[] (grouped items with section headers)
3962
+ value: string[] (currently selected item IDs)
3963
+ onValueChange: (ids: string[]) => void
3964
+ searchPlaceholder: string
3965
+ onSearch: (query: string) => Promise<MultiSelectItem[]> (async search — replaces local filter)
3966
+ searchDebounce: number (debounce for async search in ms)
3967
+ renderItem: (item: MultiSelectItem, selected: boolean) => ReactNode (custom item renderer)
3968
+ emptyMessage: string (message when no items match)
3969
+ maxSelections: number (cap on selections)
3970
+ align: "start" | "center" | "end"
3971
+ width: string | number (popover width)
3972
+ children: ReactNode (trigger element)
3973
+
3974
+ ### MultiSelectItem
3975
+ id: string
3976
+ label: string
3977
+ image?: string
3978
+ description?: string
3979
+ disabled?: boolean
3980
+
3981
+ ### MultiSelectGroup
3982
+ label: string
3983
+ items: MultiSelectItem[]
3984
+
3985
+ ## Defaults
3986
+ searchPlaceholder="Search...", searchDebounce={300}, emptyMessage="No results found", align="start", width={240}
3987
+
3988
+ ## Example
3989
+ ```jsx
3990
+ <MultiSelectPopover
3991
+ items={[
3992
+ { id: '1', label: 'Alice', image: '/alice.jpg' },
3993
+ { id: '2', label: 'Bob' },
3994
+ ]}
3995
+ value={selected}
3996
+ onValueChange={setSelected}
3997
+ >
3998
+ <Button>Assign members</Button>
3999
+ </MultiSelectPopover>
4000
+ ```
4001
+
4002
+ ## Gotchas
4003
+ - Supply either `items` (flat) or `groups` (sectioned), not both
4004
+ - When `onSearch` is provided, local filtering is disabled — the callback must return results
4005
+ - Search state resets when the popover closes
3513
4006
  # PageHeader
3514
4007
 
3515
4008
  - Import: @devalok/shilp-sutra/composed/page-header
@@ -3615,6 +4108,40 @@ Priority = 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT' | 'low' | 'medium' | 'high' | 'u
3615
4108
 
3616
4109
  ### v0.1.0
3617
4110
  - **Added** Initial release
4111
+ # ResponsiveOverlay
4112
+
4113
+ - Import: @devalok/shilp-sutra/composed/responsive-overlay
4114
+ - Server-safe: No
4115
+ - Category: composed
4116
+
4117
+ ## Props
4118
+ open: boolean
4119
+ onOpenChange: (open: boolean) => void
4120
+ title: string
4121
+ description: string
4122
+ breakpoint: "sm" | "md" (below this renders as bottom Sheet; above as Dialog)
4123
+ children: ReactNode
4124
+ className: string
4125
+
4126
+ ## Defaults
4127
+ breakpoint="md"
4128
+
4129
+ ## Example
4130
+ ```jsx
4131
+ <ResponsiveOverlay
4132
+ open={open}
4133
+ onOpenChange={setOpen}
4134
+ title="Edit task"
4135
+ description="Update the task details"
4136
+ >
4137
+ <TaskForm />
4138
+ </ResponsiveOverlay>
4139
+ ```
4140
+
4141
+ ## Gotchas
4142
+ - Renders a centered Dialog on desktop and a bottom Sheet on mobile — same content, different container
4143
+ - Uses `window.matchMedia` internally — SSR defaults to desktop (Dialog) until hydration
4144
+ - Title and description are optional; if omitted, no header is rendered in either mode
3618
4145
  # RichTextEditor
3619
4146
 
3620
4147
  - Import: @devalok/shilp-sutra/composed/rich-text-editor