@devalok/shilp-sutra 0.6.2 → 0.8.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 (108) hide show
  1. package/dist/_virtual/client.js +5 -0
  2. package/dist/_virtual/index.js +5 -0
  3. package/dist/_virtual/react-dom-client.development.js +5 -0
  4. package/dist/_virtual/react-dom-client.production.js +5 -0
  5. package/dist/_virtual/scheduler.development.js +5 -0
  6. package/dist/_virtual/scheduler.production.js +5 -0
  7. package/dist/composed/command-palette.d.ts.map +1 -1
  8. package/dist/composed/command-palette.js +84 -73
  9. package/dist/composed/confirm-dialog.d.ts +27 -0
  10. package/dist/composed/confirm-dialog.d.ts.map +1 -0
  11. package/dist/composed/confirm-dialog.js +45 -0
  12. package/dist/composed/extensions/emoji-suggestion.d.ts +9 -0
  13. package/dist/composed/extensions/emoji-suggestion.d.ts.map +1 -0
  14. package/dist/composed/extensions/emoji-suggestion.js +119 -0
  15. package/dist/composed/extensions/file-attachment.d.ts +4 -0
  16. package/dist/composed/extensions/file-attachment.d.ts.map +1 -0
  17. package/dist/composed/extensions/file-attachment.js +55 -0
  18. package/dist/composed/extensions/mention-suggestion.d.ts +10 -0
  19. package/dist/composed/extensions/mention-suggestion.d.ts.map +1 -0
  20. package/dist/composed/extensions/mention-suggestion.js +79 -0
  21. package/dist/composed/index.d.ts +3 -1
  22. package/dist/composed/index.d.ts.map +1 -1
  23. package/dist/composed/index.js +28 -26
  24. package/dist/composed/rich-text-editor.d.ts +19 -0
  25. package/dist/composed/rich-text-editor.d.ts.map +1 -1
  26. package/dist/composed/rich-text-editor.js +347 -176
  27. package/dist/composed/status-badge.d.ts +11 -1
  28. package/dist/composed/status-badge.d.ts.map +1 -1
  29. package/dist/composed/status-badge.js +48 -20
  30. package/dist/hooks/use-color-mode.d.ts.map +1 -1
  31. package/dist/hooks/use-color-mode.js +8 -4
  32. package/dist/hooks/use-mobile.d.ts +5 -0
  33. package/dist/hooks/use-mobile.d.ts.map +1 -1
  34. package/dist/node_modules/.pnpm/@emoji-mart_data@1.2.1/node_modules/@emoji-mart/data/sets/15/native.json.js +40141 -0
  35. package/dist/node_modules/.pnpm/@emoji-mart_react@1.1.1_emoji-mart@5.6.0_react@19.2.4/node_modules/@emoji-mart/react/dist/module.js +17 -0
  36. package/dist/node_modules/.pnpm/emoji-mart@5.6.0/node_modules/emoji-mart/dist/module.js +2958 -0
  37. package/dist/node_modules/.pnpm/react-dom@19.2.4_react@19.2.4/node_modules/react-dom/cjs/react-dom-client.development.js +17062 -0
  38. package/dist/node_modules/.pnpm/react-dom@19.2.4_react@19.2.4/node_modules/react-dom/cjs/react-dom-client.production.js +9790 -0
  39. package/dist/node_modules/.pnpm/react-dom@19.2.4_react@19.2.4/node_modules/react-dom/client.js +20 -0
  40. package/dist/node_modules/.pnpm/scheduler@0.27.0/node_modules/scheduler/cjs/scheduler.development.js +237 -0
  41. package/dist/node_modules/.pnpm/scheduler@0.27.0/node_modules/scheduler/cjs/scheduler.production.js +234 -0
  42. package/dist/node_modules/.pnpm/scheduler@0.27.0/node_modules/scheduler/index.js +11 -0
  43. package/dist/primitives/_internal/react-arrow.js +8 -19
  44. package/dist/primitives/_internal/react-compose-refs.js +14 -14
  45. package/dist/primitives/_internal/react-context.js +41 -39
  46. package/dist/primitives/_internal/react-dismissable-layer.js +62 -90
  47. package/dist/primitives/_internal/react-popper.js +107 -169
  48. package/dist/primitives/_internal/react-portal.js +1 -1
  49. package/dist/primitives/_internal/react-primitive.js +1 -1
  50. package/dist/primitives/_internal/react-use-size.js +8 -8
  51. package/dist/primitives/react-slot.js +12 -12
  52. package/dist/shell/app-command-palette.d.ts +3 -1
  53. package/dist/shell/app-command-palette.d.ts.map +1 -1
  54. package/dist/shell/app-command-palette.js +35 -34
  55. package/dist/shell/bottom-navbar.d.ts.map +1 -1
  56. package/dist/shell/bottom-navbar.js +31 -31
  57. package/dist/shell/index.d.ts +1 -1
  58. package/dist/shell/index.d.ts.map +1 -1
  59. package/dist/shell/notification-center.d.ts +10 -0
  60. package/dist/shell/notification-center.d.ts.map +1 -1
  61. package/dist/shell/notification-center.js +129 -117
  62. package/dist/shell/top-bar.d.ts +20 -0
  63. package/dist/shell/top-bar.d.ts.map +1 -1
  64. package/dist/shell/top-bar.js +100 -70
  65. package/dist/tailwind/index.cjs +3 -0
  66. package/dist/tailwind/preset.d.ts.map +1 -1
  67. package/dist/tailwind/preset.js +3 -0
  68. package/dist/tokens/semantic.css +10 -1
  69. package/dist/ui/alert.js +42 -63
  70. package/dist/ui/avatar.js +20 -62
  71. package/dist/ui/badge.d.ts +1 -1
  72. package/dist/ui/badge.d.ts.map +1 -1
  73. package/dist/ui/badge.js +89 -112
  74. package/dist/ui/banner.js +12 -12
  75. package/dist/ui/button-group.js +14 -29
  76. package/dist/ui/button.js +64 -108
  77. package/dist/ui/card.js +18 -62
  78. package/dist/ui/checkbox.js +1 -21
  79. package/dist/ui/chip.d.ts.map +1 -1
  80. package/dist/ui/chip.js +1 -1
  81. package/dist/ui/color-input.d.ts +17 -0
  82. package/dist/ui/color-input.d.ts.map +1 -0
  83. package/dist/ui/color-input.js +88 -0
  84. package/dist/ui/combobox.d.ts +20 -11
  85. package/dist/ui/combobox.d.ts.map +1 -1
  86. package/dist/ui/dialog.js +9 -9
  87. package/dist/ui/form.js +14 -35
  88. package/dist/ui/index.d.ts +1 -0
  89. package/dist/ui/index.d.ts.map +1 -1
  90. package/dist/ui/index.js +314 -312
  91. package/dist/ui/input.d.ts.map +1 -1
  92. package/dist/ui/input.js +31 -56
  93. package/dist/ui/label.js +1 -15
  94. package/dist/ui/number-input.d.ts.map +1 -1
  95. package/dist/ui/number-input.js +39 -35
  96. package/dist/ui/popover.js +6 -6
  97. package/dist/ui/separator.js +4 -19
  98. package/dist/ui/sheet.js +21 -21
  99. package/dist/ui/spinner.js +1 -36
  100. package/dist/ui/switch.js +1 -20
  101. package/dist/ui/tabs.js +20 -47
  102. package/dist/ui/textarea.d.ts.map +1 -1
  103. package/dist/ui/textarea.js +30 -24
  104. package/dist/ui/toast.js +18 -18
  105. package/dist/ui/tooltip.js +6 -17
  106. package/llms-full.txt +123 -13
  107. package/llms.txt +9 -6
  108. package/package.json +80 -11
package/dist/ui/toast.js CHANGED
@@ -1,14 +1,14 @@
1
1
  "use client";
2
- import { jsx as s } from "react/jsx-runtime";
2
+ import { jsx as o } from "react/jsx-runtime";
3
3
  import * as r from "react";
4
4
  import { Provider as p, Root as i, Action as d, Close as n, Description as l, Title as c, Viewport as m } from "../primitives/react-toast.js";
5
5
  import { cva as u } from "class-variance-authority";
6
- import { IconX as b } from "@tabler/icons-react";
6
+ import { IconX as x } from "@tabler/icons-react";
7
7
  import { cn as a } from "./lib/utils.js";
8
- const C = p, x = r.forwardRef(({ className: e, ...t }, o) => /* @__PURE__ */ s(
8
+ const C = p, b = r.forwardRef(({ className: e, ...t }, s) => /* @__PURE__ */ o(
9
9
  m,
10
10
  {
11
- ref: o,
11
+ ref: s,
12
12
  className: a(
13
13
  "fixed top-0 z-toast flex max-h-screen w-full flex-col-reverse p-ds-05 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
14
14
  e
@@ -16,7 +16,7 @@ const C = p, x = r.forwardRef(({ className: e, ...t }, o) => /* @__PURE__ */ s(
16
16
  ...t
17
17
  }
18
18
  ));
19
- x.displayName = m.displayName;
19
+ b.displayName = m.displayName;
20
20
  const v = u(
21
21
  "group pointer-events-auto relative flex w-full items-center justify-between space-x-ds-03 overflow-hidden rounded-ds-md border p-ds-05 pr-ds-06 shadow-03 transition-all duration-moderate-02 data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
22
22
  {
@@ -33,21 +33,21 @@ const v = u(
33
33
  color: "neutral"
34
34
  }
35
35
  }
36
- ), w = r.forwardRef(({ className: e, color: t, ...o }, f) => /* @__PURE__ */ s(
36
+ ), w = r.forwardRef(({ className: e, color: t, ...s }, f) => /* @__PURE__ */ o(
37
37
  i,
38
38
  {
39
39
  ref: f,
40
40
  role: "status",
41
41
  "aria-live": "polite",
42
42
  className: a(v({ color: t }), e),
43
- ...o
43
+ ...s
44
44
  }
45
45
  ));
46
46
  w.displayName = i.displayName;
47
- const y = r.forwardRef(({ className: e, ...t }, o) => /* @__PURE__ */ s(
47
+ const y = r.forwardRef(({ className: e, ...t }, s) => /* @__PURE__ */ o(
48
48
  d,
49
49
  {
50
- ref: o,
50
+ ref: s,
51
51
  className: a(
52
52
  "inline-flex h-ds-sm shrink-0 items-center justify-center rounded-ds-md border border-border bg-transparent px-ds-04 text-ds-md font-medium transition-colors hover:bg-layer-02 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-[0.38] group-[.destructive]:border-border-error group-[.destructive]:hover:bg-error-surface",
53
53
  e
@@ -56,33 +56,33 @@ const y = r.forwardRef(({ className: e, ...t }, o) => /* @__PURE__ */ s(
56
56
  }
57
57
  ));
58
58
  y.displayName = d.displayName;
59
- const g = r.forwardRef(({ className: e, ...t }, o) => /* @__PURE__ */ s(
59
+ const g = r.forwardRef(({ className: e, ...t }, s) => /* @__PURE__ */ o(
60
60
  n,
61
61
  {
62
- ref: o,
62
+ ref: s,
63
63
  className: a(
64
- "absolute right-ds-02 top-ds-02 min-h-6 min-w-6 flex items-center justify-center rounded-ds-md p-ds-02 text-text-secondary opacity-70 transition-opacity hover:text-text-primary hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus",
64
+ "absolute right-ds-02 top-ds-02 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-ds-md p-ds-02 text-text-secondary opacity-70 transition-opacity hover:text-text-primary hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus",
65
65
  e
66
66
  ),
67
67
  "toast-close": "",
68
68
  ...t,
69
- children: /* @__PURE__ */ s(b, { className: "h-ico-sm w-ico-sm" })
69
+ children: /* @__PURE__ */ o(x, { className: "h-ico-sm w-ico-sm" })
70
70
  }
71
71
  ));
72
72
  g.displayName = n.displayName;
73
- const N = r.forwardRef(({ className: e, ...t }, o) => /* @__PURE__ */ s(
73
+ const N = r.forwardRef(({ className: e, ...t }, s) => /* @__PURE__ */ o(
74
74
  c,
75
75
  {
76
- ref: o,
76
+ ref: s,
77
77
  className: a("text-ds-md font-semibold [&+div]:text-ds-sm", e),
78
78
  ...t
79
79
  }
80
80
  ));
81
81
  N.displayName = c.displayName;
82
- const h = r.forwardRef(({ className: e, ...t }, o) => /* @__PURE__ */ s(
82
+ const h = r.forwardRef(({ className: e, ...t }, s) => /* @__PURE__ */ o(
83
83
  l,
84
84
  {
85
- ref: o,
85
+ ref: s,
86
86
  className: a("text-ds-md opacity-[0.9]", e),
87
87
  ...t
88
88
  }
@@ -95,5 +95,5 @@ export {
95
95
  h as ToastDescription,
96
96
  C as ToastProvider,
97
97
  N as ToastTitle,
98
- x as ToastViewport
98
+ b as ToastViewport
99
99
  };
@@ -1,24 +1,13 @@
1
1
  "use client";
2
2
  import { jsx as t } from "react/jsx-runtime";
3
- import * as r from "react";
4
- import { Root as s, Provider as n, Trigger as m, Portal as l, Content as o } from "../primitives/react-tooltip.js";
5
- import { cn as p } from "./lib/utils.js";
6
- const u = n, T = s, h = m, f = r.forwardRef(({ className: e, sideOffset: a = 4, ...i }, d) => /* @__PURE__ */ t(l, { children: /* @__PURE__ */ t(
7
- o,
8
- {
9
- ref: d,
10
- sideOffset: a,
11
- className: p(
12
- "z-tooltip overflow-hidden rounded-ds-md bg-text-primary px-ds-04 py-ds-02b text-ds-sm text-text-inverse shadow-02 duration-fast-02 ease-productive-entrance animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
13
- e
14
- ),
15
- ...i
16
- }
17
- ) }));
18
- f.displayName = o.displayName;
3
+ import * as s from "react";
4
+ import { Root as r, Provider as n, Trigger as m, Portal as l, Content as o } from "../primitives/react-tooltip.js";
5
+ import { cn as f } from "./lib/utils.js";
6
+ const u = n, T = r, h = m, p = s.forwardRef(({ className: e, sideOffset: a = 4, ...i }, d) => t(l, { children: t(o, { ref: d, sideOffset: a, className: f("z-tooltip overflow-hidden rounded-ds-md bg-text-primary px-ds-04 py-ds-02b text-ds-sm text-text-inverse shadow-02 duration-fast-02 ease-productive-entrance animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", e), ...i }) }));
7
+ p.displayName = o.displayName;
19
8
  export {
20
9
  T as Tooltip,
21
- f as TooltipContent,
10
+ p as TooltipContent,
22
11
  u as TooltipProvider,
23
12
  h as TooltipTrigger
24
13
  };
package/llms-full.txt CHANGED
@@ -197,7 +197,7 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
197
197
  - Props:
198
198
  variant: "subtle" | "solid" | "outline" | "secondary" (alias->subtle) | "destructive" (alias->solid+error)
199
199
  color: "default" | "info" | "success" | "error" | "warning" | "brand" | "accent" | "teal" | "amber" | "slate" | "indigo" | "cyan" | "orange" | "emerald"
200
- size: "sm" | "md" | "lg"
200
+ size: "xs" | "sm" | "md" | "lg"
201
201
  dot: boolean (shows leading dot indicator)
202
202
  onDismiss: () => void (shows X button when provided)
203
203
  children: ReactNode
@@ -353,6 +353,24 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
353
353
  <Code variant="block">{`const x = 1;\nconsole.log(x);`}</Code>
354
354
  - Gotchas: "block" renders as <pre><code>, "inline" renders as <code>
355
355
 
356
+ ## ColorInput
357
+ - Import: @devalok/shilp-sutra/ui/color-input
358
+ - Server-safe: No
359
+ - Props:
360
+ value: string (hex color, e.g. "#d33163")
361
+ onChange: (value: string) => void
362
+ presets: string[] (optional preset color swatches)
363
+ disabled: boolean
364
+ className: string
365
+ - Defaults: value="#000000", disabled=false
366
+ - Example:
367
+ <ColorInput
368
+ value={color}
369
+ onChange={setColor}
370
+ presets={['#d33163', '#2563eb', '#16a34a']}
371
+ />
372
+ - Gotchas: Uses native color picker under the hood; value must be a valid hex string
373
+
356
374
  ## Collapsible
357
375
  - Import: @devalok/shilp-sutra/ui/collapsible
358
376
  - Server-safe: No
@@ -372,12 +390,12 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
372
390
  - Server-safe: No
373
391
  - Props:
374
392
  options: ComboboxOption[] (REQUIRED) — { value: string, label: string, description?: string, icon?: ReactNode, disabled?: boolean }
375
- value: string | string[]
376
- onValueChange: (value: string | string[]) => void (REQUIRED)
393
+ DISCRIMINATED UNION type depends on `multiple` flag:
394
+ Single (default): multiple?: false, value: string, onValueChange: (value: string) => void
395
+ Multiple: multiple: true, value: string[], onValueChange: (value: string[]) => void
377
396
  placeholder: string (default: "Select...")
378
397
  searchPlaceholder: string (default: "Search...")
379
398
  emptyMessage: string (default: "No results found")
380
- multiple: boolean (default: false)
381
399
  disabled: boolean
382
400
  triggerClassName: string
383
401
  maxVisible: number (default: 6, max dropdown items before scroll)
@@ -387,7 +405,7 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
387
405
  multiple
388
406
  options={tagOptions}
389
407
  value={selectedTags}
390
- onValueChange={(v) => setSelectedTags(v as string[])}
408
+ onValueChange={setSelectedTags}
391
409
  placeholder="Select tags..."
392
410
  />
393
411
  - Gotchas:
@@ -575,6 +593,7 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
575
593
  - Gotchas:
576
594
  - HTML native "size" attribute is excluded — use CSS width instead
577
595
  - state="error" sets aria-invalid automatically
596
+ - Inside FormField: auto-inherits state, aria-describedby, aria-required from context (explicit props override)
578
597
 
579
598
  ## InputOTP
580
599
  - Import: @devalok/shilp-sutra/ui/input-otp
@@ -1116,6 +1135,7 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
1116
1135
  - Example:
1117
1136
  <Textarea size="lg" state="error" placeholder="Describe the issue..." />
1118
1137
  - Gotchas: state="error" sets aria-invalid automatically; all sizes are vertically resizable
1138
+ - Inside FormField: auto-inherits state, aria-describedby, aria-required from context (explicit props override)
1119
1139
 
1120
1140
  ## Toast / Toaster
1121
1141
  - Import: @devalok/shilp-sutra/ui/toast, @devalok/shilp-sutra/ui/toaster
@@ -1302,6 +1322,36 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
1302
1322
  />
1303
1323
  - Gotchas: Opens with Ctrl+K / Cmd+K by default
1304
1324
 
1325
+ ## ConfirmDialog
1326
+ - Import: @devalok/shilp-sutra/composed/confirm-dialog
1327
+ - Server-safe: No
1328
+ - Props:
1329
+ open: boolean (REQUIRED, controlled)
1330
+ onOpenChange: (open: boolean) => void (REQUIRED)
1331
+ title: string (REQUIRED)
1332
+ description: string (REQUIRED)
1333
+ confirmText: string (default: "Confirm")
1334
+ cancelText: string (default: "Cancel")
1335
+ color: "default" | "error" (controls confirm button color)
1336
+ loading: boolean (default: false, disables buttons and shows spinner)
1337
+ onConfirm: () => void | Promise<void> (REQUIRED)
1338
+ - Defaults: confirmText="Confirm", cancelText="Cancel", color="default", loading=false
1339
+ - Example:
1340
+ const [open, setOpen] = useState(false)
1341
+ <ConfirmDialog
1342
+ open={open}
1343
+ onOpenChange={setOpen}
1344
+ title="Delete project?"
1345
+ description="This action cannot be undone."
1346
+ color="error"
1347
+ confirmText="Delete"
1348
+ loading={isDeleting}
1349
+ onConfirm={async () => { await deleteProject(); setOpen(false) }}
1350
+ />
1351
+ - Gotchas:
1352
+ - Dialog stays open after confirm — consumer must close it via onOpenChange
1353
+ - Built on AlertDialog internally
1354
+
1305
1355
  ## ContentCard
1306
1356
  - Import: @devalok/shilp-sutra/composed/content-card
1307
1357
  - Server-safe: Yes
@@ -1486,13 +1536,41 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
1486
1536
  onChange: (html: string) => void
1487
1537
  className: string
1488
1538
  editable: boolean (default: true)
1539
+ onImageUpload?: (file: File) => Promise<string> — return URL. If omitted, images paste as base64
1540
+ onFileUpload?: (file: File) => Promise<{ url: string; name: string; size: number }> — enables file attachments. If omitted, non-image files ignored
1541
+ mentions?: MentionItem[] — static list for @mention autocomplete
1542
+ onMentionSearch?: (query: string) => Promise<MentionItem[]> — async search, takes precedence over static mentions
1543
+ onMentionSelect?: (item: MentionItem) => void — callback when mention selected
1544
+ - MentionItem: { id: string; label: string; avatar?: string }
1489
1545
  - Props (RichTextViewer):
1490
1546
  content: string (REQUIRED, HTML string)
1491
1547
  className: string
1548
+ - Features:
1549
+ Formatting: bold, italic, underline, strikethrough, highlight, headings (H2/H3), blockquote
1550
+ Lists: bullet, ordered, task lists (checkboxes)
1551
+ Code: inline code, code blocks
1552
+ Links: auto-link, inline URL editor popover
1553
+ Images: paste/drop/toolbar upload, base64 fallback or custom upload callback
1554
+ File attachments: drop/paste/toolbar, renders as download card [icon filename (size)]
1555
+ Mentions: type @ for autocomplete dropdown (static or async)
1556
+ Emoji: toolbar picker (emoji-mart, lazy loaded) + :shortcode: inline suggestions
1557
+ Text alignment: left/center/right
1558
+ Horizontal rule
1492
1559
  - Example:
1493
1560
  <RichTextEditor content={html} onChange={setHtml} placeholder="Write your message..." />
1561
+ <RichTextEditor
1562
+ content={html}
1563
+ onChange={setHtml}
1564
+ mentions={[{ id: '1', label: 'Aarav' }]}
1565
+ onImageUpload={async (file) => uploadAndReturnUrl(file)}
1566
+ onFileUpload={async (file) => ({ url: uploadUrl, name: file.name, size: file.size })}
1567
+ />
1494
1568
  <RichTextViewer content={savedHtml} />
1495
- - Gotchas: Requires @tiptap/react, @tiptap/starter-kit, @tiptap/extension-placeholder as peer deps
1569
+ - Gotchas:
1570
+ Requires Tiptap peer deps: @tiptap/react, @tiptap/starter-kit, @tiptap/extension-placeholder, plus extension-specific peers (image, link, underline, highlight, task-list, task-item, text-align, mention, suggestion)
1571
+ Emoji picker requires @emoji-mart/react + @emoji-mart/data peers
1572
+ Images without onImageUpload are stored as base64 in HTML — large images bloat content
1573
+ Mention rendering in viewer always works (no mention props needed, just the HTML)
1496
1574
 
1497
1575
  ## ScheduleView
1498
1576
  - Import: @devalok/shilp-sutra/composed/schedule-view
@@ -1558,17 +1636,20 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
1558
1636
  - Server-safe: No
1559
1637
  - Props:
1560
1638
  user: AppCommandPaletteUser | null — { name, role? }
1639
+ isAdmin: boolean (shows admin command groups regardless of user.role; takes precedence over role-based detection)
1561
1640
  extraGroups: CommandGroup[]
1562
1641
  onNavigate: (path: string) => void
1563
1642
  onSearch: (query: string) => void
1564
1643
  searchResults: SearchResult[] — { id, title, snippet?, entityType, projectId?, metadata? }
1565
- onSelectResult: (result: SearchResult) => void
1644
+ isSearching: boolean (shows loading state while search is in progress)
1645
+ onSearchResultSelect: (result: SearchResult) => void
1566
1646
  - Example:
1567
1647
  <AppCommandPalette
1568
1648
  user={{ name: 'John', role: 'admin' }}
1649
+ isAdmin={true}
1569
1650
  onNavigate={(path) => router.push(path)}
1570
1651
  searchResults={results}
1571
- onSelectResult={(r) => router.push(`/${r.entityType}/${r.id}`)}
1652
+ onSearchResultSelect={(r) => router.push(`/${r.entityType}/${r.id}`)}
1572
1653
  />
1573
1654
 
1574
1655
  ## AppSidebar
@@ -1601,7 +1682,7 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
1601
1682
  - Server-safe: No
1602
1683
  - Props:
1603
1684
  currentPath: string
1604
- user: BottomNavbarUser | null — { name, role? }
1685
+ user: BottomNavbarUser | null (optional) — { name, role? }. Not required to render.
1605
1686
  primaryItems: BottomNavItem[] (max 4 recommended) — { title, href, icon, exact? }
1606
1687
  moreItems: BottomNavItem[] (overflow items in "More" menu)
1607
1688
  className: string
@@ -1642,13 +1723,25 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
1642
1723
  onFetchMore: () => void
1643
1724
  onMarkRead: (id: string) => void
1644
1725
  onMarkAllRead: () => void
1645
- onNotificationClick: (notification: Notification) => void
1726
+ onNavigate: (path: string) => void — called when a notification with a route is clicked
1727
+ getNotificationRoute: (notification: Notification) => string | null — returns route for a notification; defaults to () => null when not provided (no hardcoded routes)
1728
+ footerSlot: ReactNode — content rendered in a sticky footer below the scroll area (e.g., "View all" link)
1729
+ emptyState: ReactNode — replaces the default empty state UI when there are no notifications
1730
+ headerActions: ReactNode — extra action buttons rendered after the "Mark all read" button in the header
1731
+ popoverClassName: string — override default popover dimensions via className
1732
+ onDismiss: (id: string) => void — when provided, each notification shows a dismiss/close button; called with the notification id
1646
1733
  - Example:
1647
1734
  <NotificationCenter
1648
1735
  notifications={notifications}
1649
1736
  onMarkRead={markAsRead}
1650
1737
  onMarkAllRead={markAllAsRead}
1651
- onNotificationClick={(n) => router.push(`/notifications/${n.id}`)}
1738
+ onNavigate={(path) => router.push(path)}
1739
+ getNotificationRoute={(n) => n.entityType === 'task' ? `/tasks/${n.entityId}` : null}
1740
+ onDismiss={(id) => dismissNotification(id)}
1741
+ footerSlot={<Link href="/notifications">View all notifications</Link>}
1742
+ emptyState={<p>You're all caught up!</p>}
1743
+ headerActions={<Button variant="ghost" size="sm">Settings</Button>}
1744
+ popoverClassName="w-[480px]"
1652
1745
  />
1653
1746
 
1654
1747
  ## NotificationPreferences
@@ -1658,13 +1751,18 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
1658
1751
  preferences: NotificationPreference[] — { id, userId?, projectId, channel, minTier, muted }
1659
1752
  projects: NotificationProject[] — { id, title }
1660
1753
  isLoading: boolean
1661
- onSave: (preference: { projectId, channel, minTier, muted }) => void
1662
- onDelete: (id: string) => void
1754
+ onSave: (preference: { projectId, channel, minTier, muted }) => void | Promise<void>
1755
+ onToggleMute: (preference: NotificationPreference) => void | Promise<void>
1756
+ onUpdateTier: (preference: NotificationPreference, newTier: string) => void | Promise<void>
1757
+ onDelete: (preferenceId: string) => void | Promise<void>
1758
+ className: string
1663
1759
  - Example:
1664
1760
  <NotificationPreferences
1665
1761
  preferences={prefs}
1666
1762
  projects={projectList}
1667
1763
  onSave={handleSavePref}
1764
+ onToggleMute={handleToggleMute}
1765
+ onUpdateTier={handleUpdateTier}
1668
1766
  onDelete={handleDeletePref}
1669
1767
  />
1670
1768
 
@@ -1680,7 +1778,15 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
1680
1778
  onAiChatClick: () => void
1681
1779
  mobileLogo: ReactNode
1682
1780
  notificationSlot: ReactNode (render NotificationCenter here)
1781
+ userMenuItems?: UserMenuItem[] — custom items between Profile and Dark/Light Mode toggle
1683
1782
  className: string
1783
+ - UserMenuItem: { label: string, icon?: ReactNode, href?: string, onClick?: () => void, separator?: boolean, color?: string, badge?: string | boolean, disabled?: boolean }
1784
+ href — navigates via onNavigate callback
1785
+ onClick — custom action (takes precedence over href)
1786
+ separator — renders a DropdownMenuSeparator before this item
1787
+ color — semantic text color (e.g. "error" → text-error)
1788
+ badge — string for count badge, true for dot indicator
1789
+ disabled — greys out the item
1684
1790
  - Example:
1685
1791
  <TopBar
1686
1792
  pageTitle="Dashboard"
@@ -1688,6 +1794,10 @@ Note: getFormFieldA11y() was removed in favor of useFormField() hook.
1688
1794
  onNavigate={(p) => router.push(p)}
1689
1795
  onLogout={handleLogout}
1690
1796
  notificationSlot={<NotificationCenter notifications={notifications} />}
1797
+ userMenuItems={[
1798
+ { label: 'Changelog', icon: <IconNews />, href: '/changelog', badge: '3' },
1799
+ { label: 'Shortcuts', icon: <IconKeyboard />, onClick: () => openModal() },
1800
+ ]}
1691
1801
  />
1692
1802
 
1693
1803
  ---
package/llms.txt CHANGED
@@ -65,6 +65,7 @@ Components with two-axis system: Button, Badge, Alert, Chip, Toast, Banner, Prog
65
65
  - SearchInput: size(sm|md|lg) + loading, onClear
66
66
  - NumberInput: value + onValueChange, min, max, step (controlled only)
67
67
  - Textarea: size(sm|md|lg) state(default|error|warning|success)
68
+ - ColorInput: value(hex string) onChange(value) presets(string[]) disabled
68
69
  - Checkbox: checked, onCheckedChange, error(boolean), indeterminate(boolean)
69
70
  - Switch: checked, onCheckedChange, error(boolean)
70
71
  - RadioGroup > RadioGroupItem(value)
@@ -87,7 +88,7 @@ NOTIFICATION SELECTION GUIDE:
87
88
  - Toast: transient notification triggered by user action (needs Toaster + useToast)
88
89
 
89
90
  ### Data Display
90
- - Badge: variant(subtle|solid|outline) color(default|info|success|error|warning|brand|accent + 7 category colors) size(sm|md|lg) + onDismiss
91
+ - Badge: variant(subtle|solid|outline) color(default|info|success|error|warning|brand|accent + 7 category colors) size(xs|sm|md|lg) + onDismiss
91
92
  - Chip: variant(subtle|outline) color(default|primary|success|error|warning|info + 7 category) size(sm|md|lg) label(string, REQUIRED) + onDismiss, onClick
92
93
  - Avatar: size(xs|sm|md|lg|xl) shape(circle|square|rounded) status(online|offline|busy|away) > AvatarImage + AvatarFallback
93
94
  - Card: variant(default|elevated|outline|flat) interactive(boolean) > CardHeader > CardTitle, CardDescription; CardContent; CardFooter
@@ -128,6 +129,7 @@ NOTIFICATION SELECTION GUIDE:
128
129
  - Wire accessibility: const { state, helperTextId } = useFormField(); then aria-describedby={helperTextId}, aria-invalid={state === 'error'}
129
130
 
130
131
  ### Composed Components
132
+ - ConfirmDialog: open, onOpenChange, title, description, onConfirm + confirmText, cancelText, color(default|error), loading
131
133
  - PageHeader: title, subtitle, breadcrumbs[], actions(ReactNode)
132
134
  - AvatarGroup: users[], max(number), size(sm|md|lg), showTooltip
133
135
  - StatusBadge: status(active|pending|approved|rejected|completed|blocked|cancelled|draft) color(success|warning|error|info|neutral) size(sm|md)
@@ -136,17 +138,18 @@ NOTIFICATION SELECTION GUIDE:
136
138
  - PriorityIndicator: priority(LOW|MEDIUM|HIGH|URGENT) display(compact|full)
137
139
  - SimpleTooltip: wraps Tooltip compound into single component
138
140
  - DatePicker, DateRangePicker, DateTimePicker, TimePicker
139
- - RichTextEditor, RichTextViewer
141
+ - RichTextEditor: Tiptap editor — bold/italic/underline/strike/highlight, headings, blockquote, lists (bullet/ordered/task), code, links, images (paste/drop/upload), file attachments, @mentions, emoji picker + :shortcode:, text alignment, HR. Props: onImageUpload?, onFileUpload?, mentions?, onMentionSearch?, onMentionSelect?
142
+ - RichTextViewer: read-only renderer for RichTextEditor HTML content (renders all above content types)
140
143
  - CommandPalette, MemberPicker
141
144
  - ErrorDisplay, GlobalLoading
142
145
  - Loading skeletons: CardSkeleton, TableSkeleton, BoardSkeleton, ListSkeleton, DashboardSkeleton, etc.
143
146
 
144
147
  ### Shell Components (app-level layout)
145
- - TopBar: pageTitle, user, onNavigate, onLogout, notificationSlot, mobileLogo
148
+ - TopBar: pageTitle, user, onNavigate, onLogout, notificationSlot, mobileLogo, userMenuItems?(UserMenuItem[] — custom items between Profile and theme toggle, supports icon, href, onClick, separator, badge, disabled, color)
146
149
  - AppSidebar: navigation tree with NavItem[], NavGroup[]
147
- - BottomNavbar: mobile navigation
148
- - NotificationCenter: notifications[], onDismiss, onRead
149
- - AppCommandPalette: search results, user info
150
+ - BottomNavbar: mobile navigation, user is optional (not required to render)
151
+ - NotificationCenter: notifications[], onMarkRead, onMarkAllRead, onNavigate, getNotificationRoute?(returns string|null, fallback null), footerSlot?, emptyState?, headerActions?, popoverClassName?, onDismiss?(id)
152
+ - AppCommandPalette: user, isAdmin, onNavigate, onSearch, searchResults, isSearching, onSearchResultSelect
150
153
 
151
154
  ### Hooks
152
155
  - useToast(): returns { toast, toasts, dismiss } — toast({ title, description, color })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devalok/shilp-sutra",
3
- "version": "0.6.2",
3
+ "version": "0.8.0",
4
4
  "description": "Devalok Design System — tokens, components, and patterns for Next.js",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -81,6 +81,10 @@
81
81
  "import": "./dist/ui/code.js",
82
82
  "types": "./dist/ui/code.d.ts"
83
83
  },
84
+ "./ui/color-input": {
85
+ "import": "./dist/ui/color-input.js",
86
+ "types": "./dist/ui/color-input.d.ts"
87
+ },
84
88
  "./ui/collapsible": {
85
89
  "import": "./dist/ui/collapsible.js",
86
90
  "types": "./dist/ui/collapsible.d.ts"
@@ -289,6 +293,10 @@
289
293
  "import": "./dist/composed/command-palette.js",
290
294
  "types": "./dist/composed/command-palette.d.ts"
291
295
  },
296
+ "./composed/confirm-dialog": {
297
+ "import": "./dist/composed/confirm-dialog.js",
298
+ "types": "./dist/composed/confirm-dialog.d.ts"
299
+ },
292
300
  "./composed/content-card": {
293
301
  "import": "./dist/composed/content-card.js",
294
302
  "types": "./dist/composed/content-card.d.ts"
@@ -398,6 +406,10 @@
398
406
  "import": "./dist/tailwind/index.js",
399
407
  "types": "./dist/tailwind/index.d.ts"
400
408
  },
409
+ "./utils": {
410
+ "import": "./dist/ui/lib/utils.js",
411
+ "types": "./dist/ui/lib/utils.d.ts"
412
+ },
401
413
  "./fonts/*": "./fonts/*"
402
414
  },
403
415
  "files": [
@@ -416,14 +428,23 @@
416
428
  "prepublishOnly": "pnpm build"
417
429
  },
418
430
  "peerDependencies": {
419
- "react": "^18 || ^19",
420
- "react-dom": "^18 || ^19",
431
+ "@emoji-mart/data": "^1.0.0",
432
+ "@emoji-mart/react": "^1.0.0",
421
433
  "@tabler/icons-react": "^3.0.0",
422
434
  "@tanstack/react-table": "^8.0.0",
423
435
  "@tanstack/react-virtual": "^3.0.0",
436
+ "@tiptap/extension-highlight": "^2.0.0",
437
+ "@tiptap/extension-image": "^2.0.0",
438
+ "@tiptap/extension-link": "^2.0.0",
439
+ "@tiptap/extension-mention": "^2.0.0",
440
+ "@tiptap/extension-placeholder": "^2.0.0",
441
+ "@tiptap/extension-task-item": "^2.0.0",
442
+ "@tiptap/extension-task-list": "^2.0.0",
443
+ "@tiptap/extension-text-align": "^2.0.0",
444
+ "@tiptap/extension-underline": "^2.0.0",
424
445
  "@tiptap/react": "^2.0.0",
425
446
  "@tiptap/starter-kit": "^2.0.0",
426
- "@tiptap/extension-placeholder": "^2.0.0",
447
+ "@tiptap/suggestion": "^2.0.0",
427
448
  "d3-array": "^3.0.0",
428
449
  "d3-axis": "^3.0.0",
429
450
  "d3-format": "^3.0.0",
@@ -435,12 +456,12 @@
435
456
  "d3-transition": "^3.0.0",
436
457
  "date-fns": "^4.0.0",
437
458
  "input-otp": "^1.0.0",
438
- "react-markdown": "^10.0.0"
459
+ "react": "^18 || ^19",
460
+ "react-dom": "^18 || ^19",
461
+ "react-markdown": "^10.0.0",
462
+ "tailwindcss": "^3.4.0"
439
463
  },
440
464
  "peerDependenciesMeta": {
441
- "@tabler/icons-react": {
442
- "optional": true
443
- },
444
465
  "@tanstack/react-table": {
445
466
  "optional": true
446
467
  },
@@ -453,9 +474,42 @@
453
474
  "@tiptap/starter-kit": {
454
475
  "optional": true
455
476
  },
477
+ "@tiptap/extension-highlight": {
478
+ "optional": true
479
+ },
480
+ "@tiptap/extension-image": {
481
+ "optional": true
482
+ },
483
+ "@tiptap/extension-link": {
484
+ "optional": true
485
+ },
486
+ "@tiptap/extension-mention": {
487
+ "optional": true
488
+ },
456
489
  "@tiptap/extension-placeholder": {
457
490
  "optional": true
458
491
  },
492
+ "@tiptap/extension-task-item": {
493
+ "optional": true
494
+ },
495
+ "@tiptap/extension-task-list": {
496
+ "optional": true
497
+ },
498
+ "@tiptap/extension-text-align": {
499
+ "optional": true
500
+ },
501
+ "@tiptap/extension-underline": {
502
+ "optional": true
503
+ },
504
+ "@tiptap/suggestion": {
505
+ "optional": true
506
+ },
507
+ "@emoji-mart/data": {
508
+ "optional": true
509
+ },
510
+ "@emoji-mart/react": {
511
+ "optional": true
512
+ },
459
513
  "d3-array": {
460
514
  "optional": true
461
515
  },
@@ -491,6 +545,9 @@
491
545
  },
492
546
  "react-markdown": {
493
547
  "optional": true
548
+ },
549
+ "tailwindcss": {
550
+ "optional": true
494
551
  }
495
552
  },
496
553
  "dependencies": {
@@ -502,12 +559,24 @@
502
559
  "tailwind-merge": "^3.0.1"
503
560
  },
504
561
  "devDependencies": {
562
+ "@emoji-mart/data": "^1.2.1",
563
+ "@emoji-mart/react": "^1.1.1",
505
564
  "@tabler/icons-react": "^3.37.1",
506
565
  "@tanstack/react-table": "^8.21.2",
507
566
  "@tanstack/react-virtual": "^3.13.19",
508
- "@tiptap/extension-placeholder": "^2.11.5",
509
- "@tiptap/react": "^2.11.5",
510
- "@tiptap/starter-kit": "^2.11.5",
567
+ "@tiptap/core": "^2.27.2",
568
+ "@tiptap/extension-highlight": "^2.27.2",
569
+ "@tiptap/extension-image": "^2.27.2",
570
+ "@tiptap/extension-link": "^2.27.2",
571
+ "@tiptap/extension-mention": "^2.27.2",
572
+ "@tiptap/extension-placeholder": "^2.27.2",
573
+ "@tiptap/extension-task-item": "^2.27.2",
574
+ "@tiptap/extension-task-list": "^2.27.2",
575
+ "@tiptap/extension-text-align": "^2.27.2",
576
+ "@tiptap/extension-underline": "^2.27.2",
577
+ "@tiptap/react": "^2.27.2",
578
+ "@tiptap/starter-kit": "^2.27.2",
579
+ "@tiptap/suggestion": "^2.27.2",
511
580
  "d3-array": "^3.2.4",
512
581
  "d3-axis": "^3.0.0",
513
582
  "d3-format": "^3.1.2",