@devalok/shilp-sutra 0.39.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +151 -0
- package/MIGRATION.md +137 -0
- package/README.md +3 -0
- package/dist/_chunks/badge-group.js +75 -74
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/chart-container.js +50 -0
- package/dist/_chunks/chart-container.js.map +1 -0
- package/dist/_chunks/chat.js +231 -223
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/colors.js +30 -0
- package/dist/_chunks/colors.js.map +1 -0
- package/dist/_chunks/emoji-data.js +45 -0
- package/dist/_chunks/emoji-data.js.map +1 -0
- package/dist/_chunks/grid-lines.js +72 -0
- package/dist/_chunks/grid-lines.js.map +1 -0
- package/dist/_chunks/mention-suggestion.js +31 -259
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/normalize-icon.js +18 -0
- package/dist/_chunks/normalize-icon.js.map +1 -0
- package/dist/_chunks/oauth-button.js +227 -0
- package/dist/_chunks/oauth-button.js.map +1 -0
- package/dist/_chunks/primitives.js +107 -107
- package/dist/_chunks/primitives.js.map +1 -1
- package/dist/_chunks/{text.js → success.js} +24 -61
- package/dist/_chunks/success.js.map +1 -0
- package/dist/_chunks/tiptap.js +1952 -1949
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/_chunks/tooltip.js +58 -0
- package/dist/_chunks/tooltip.js.map +1 -0
- package/dist/_chunks/tree-view.js +101 -96
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/ai/ai-command-provider.d.ts +3 -2
- package/dist/ai/ai-command-provider.d.ts.map +1 -1
- package/dist/ai/ai-command-provider.js.map +1 -1
- package/dist/ai/block-renderer.js +11 -9
- package/dist/ai/block-renderer.js.map +1 -1
- package/dist/ai/blocks/error.js +31 -0
- package/dist/ai/blocks/error.js.map +1 -0
- package/dist/ai/blocks/index.d.ts +0 -2
- package/dist/ai/blocks/index.d.ts.map +1 -1
- package/dist/ai/blocks/index.js +2 -2
- package/dist/ai/blocks/text.js +19 -0
- package/dist/ai/blocks/text.js.map +1 -0
- package/dist/ai/command-bar.d.ts.map +1 -1
- package/dist/ai/command-bar.js +192 -187
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.d.ts +2 -1
- package/dist/ai/conversation.d.ts.map +1 -1
- package/dist/ai/conversation.js +88 -83
- package/dist/ai/conversation.js.map +1 -1
- package/dist/ai/index.d.ts +0 -4
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +45 -46
- package/dist/ai/index.js.map +1 -1
- package/dist/composed/activity-feed.d.ts +2 -1
- package/dist/composed/activity-feed.d.ts.map +1 -1
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/bulk-action-bar.d.ts +2 -2
- package/dist/composed/bulk-action-bar.d.ts.map +1 -1
- package/dist/composed/bulk-action-bar.js +11 -11
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.d.ts +2 -1
- package/dist/composed/command-palette.d.ts.map +1 -1
- package/dist/composed/command-palette.js +103 -98
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/date-picker/index.js +747 -3
- package/dist/composed/date-picker/index.js.map +1 -0
- package/dist/composed/empty-state.d.ts +3 -3
- package/dist/composed/empty-state.d.ts.map +1 -1
- package/dist/composed/empty-state.js +40 -31
- package/dist/composed/empty-state.js.map +1 -1
- package/dist/composed/extensions/emoji-node.js +81 -0
- package/dist/composed/extensions/emoji-node.js.map +1 -0
- package/dist/composed/extensions/emoji-suggestion.js +117 -0
- package/dist/composed/extensions/emoji-suggestion.js.map +1 -0
- package/dist/composed/file-preview.js +498 -2
- package/dist/{_chunks → composed}/file-preview.js.map +1 -1
- package/dist/composed/index.d.ts +0 -15
- package/dist/composed/index.d.ts.map +1 -1
- package/dist/composed/index.js +16 -24
- package/dist/composed/rich-chat-input.js +2073 -2
- package/dist/{_chunks → composed}/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +64 -61
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/status-badge.d.ts +3 -2
- package/dist/composed/status-badge.d.ts.map +1 -1
- package/dist/composed/status-badge.js +58 -53
- package/dist/composed/status-badge.js.map +1 -1
- package/dist/shell/app-command-palette.d.ts +2 -1
- package/dist/shell/app-command-palette.d.ts.map +1 -1
- package/dist/shell/app-command-palette.js.map +1 -1
- package/dist/shell/bottom-navbar.d.ts +3 -1
- package/dist/shell/bottom-navbar.d.ts.map +1 -1
- package/dist/shell/bottom-navbar.js +90 -82
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/command-registry.d.ts +2 -1
- package/dist/shell/command-registry.d.ts.map +1 -1
- package/dist/shell/command-registry.js.map +1 -1
- package/dist/shell/sidebar.d.ts +7 -4
- package/dist/shell/sidebar.d.ts.map +1 -1
- package/dist/shell/sidebar.js +143 -129
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.d.ts +4 -3
- package/dist/shell/top-bar.d.ts.map +1 -1
- package/dist/shell/top-bar.js +114 -106
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/ui/badge.d.ts +3 -2
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/button.d.ts +3 -2
- package/dist/ui/button.d.ts.map +1 -1
- package/dist/ui/button.js +54 -53
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/charts/area-chart.js +177 -0
- package/dist/ui/charts/area-chart.js.map +1 -0
- package/dist/ui/charts/bar-chart.js +127 -0
- package/dist/ui/charts/bar-chart.js.map +1 -0
- package/dist/ui/charts/chart-container.js +3 -0
- package/dist/ui/charts/gauge-chart.js +72 -0
- package/dist/ui/charts/gauge-chart.js.map +1 -0
- package/dist/ui/charts/index.js +10 -1035
- package/dist/ui/charts/line-chart.js +135 -0
- package/dist/ui/charts/line-chart.js.map +1 -0
- package/dist/ui/charts/pie-chart.js +111 -0
- package/dist/ui/charts/pie-chart.js.map +1 -0
- package/dist/ui/charts/radar-chart.js +170 -0
- package/dist/ui/charts/radar-chart.js.map +1 -0
- package/dist/ui/charts/sparkline.js +119 -0
- package/dist/ui/charts/sparkline.js.map +1 -0
- package/dist/ui/chat/message.d.ts +3 -3
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/chat/system-message.d.ts +2 -1
- package/dist/ui/chat/system-message.d.ts.map +1 -1
- package/dist/ui/combobox.d.ts +2 -1
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +97 -92
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/container.d.ts +6 -1
- package/dist/ui/container.d.ts.map +1 -1
- package/dist/ui/container.js +2 -1
- package/dist/ui/container.js.map +1 -1
- package/dist/ui/icon-button.d.ts +9 -2
- package/dist/ui/icon-button.d.ts.map +1 -1
- package/dist/ui/icon-button.js +14 -13
- package/dist/ui/icon-button.js.map +1 -1
- package/dist/ui/index.d.ts +1 -3
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +31 -33
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/lib/icon-input.d.ts +42 -0
- package/dist/ui/lib/icon-input.d.ts.map +1 -0
- package/dist/ui/lib/normalize-icon.d.ts +39 -0
- package/dist/ui/lib/normalize-icon.d.ts.map +1 -0
- package/dist/ui/oauth-button/index.d.ts +3 -0
- package/dist/ui/oauth-button/index.d.ts.map +1 -0
- package/dist/ui/oauth-button/index.js +3 -0
- package/dist/ui/oauth-button/oauth-button.d.ts +208 -0
- package/dist/ui/oauth-button/oauth-button.d.ts.map +1 -0
- package/dist/ui/progress.js +1 -1
- package/dist/ui/segmented-control.d.ts +3 -4
- package/dist/ui/segmented-control.d.ts.map +1 -1
- package/dist/ui/segmented-control.js +53 -45
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/stack.d.ts +6 -1
- package/dist/ui/stack.d.ts.map +1 -1
- package/dist/ui/stack.js +2 -1
- package/dist/ui/stack.js.map +1 -1
- package/dist/ui/stat-card.d.ts +2 -3
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +117 -115
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stepper.d.ts +2 -1
- package/dist/ui/stepper.d.ts.map +1 -1
- package/dist/ui/stepper.js +74 -69
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/text.d.ts +7 -2
- package/dist/ui/text.d.ts.map +1 -1
- package/dist/ui/text.js +2 -1
- package/dist/ui/text.js.map +1 -1
- package/dist/ui/toaster.d.ts +11 -2
- package/dist/ui/toaster.d.ts.map +1 -1
- package/dist/ui/toaster.js.map +1 -1
- package/dist/ui/tooltip.js +12 -12
- package/dist/ui/tree-view/tree-item.d.ts +3 -2
- package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
- package/dist/ui/tree-view/use-tree.d.ts +2 -1
- package/dist/ui/tree-view/use-tree.d.ts.map +1 -1
- package/docs/components/ui/oauth-button.md +86 -0
- package/docs/recipes/customize-brand.md +15 -0
- package/docs/recipes/index.md +5 -1
- package/docs/recipes/install-astro.md +15 -0
- package/docs/recipes/install-next-app-router.md +21 -5
- package/docs/recipes/install-next-pages.md +2 -0
- package/docs/recipes/install-remix.md +15 -0
- package/docs/recipes/install-tanstack-start.md +15 -0
- package/docs/recipes/install-vite.md +15 -0
- package/docs/recipes/troubleshoot.md +22 -0
- package/llms-full.txt +87 -1
- package/llms-quick.txt +247 -0
- package/llms.txt +107 -2
- package/package.json +79 -2
- package/scripts/welcome.mjs +219 -0
- package/skill/SKILL.md +22 -3
- package/skill/references/components-full.md +87 -1
- package/skill/references/components.md +107 -2
- package/skill/references/customize-brand.md +15 -0
- package/skill/references/setup-astro.md +15 -0
- package/skill/references/setup-next-app-router.md +21 -5
- package/skill/references/setup-next-pages.md +2 -0
- package/skill/references/setup-remix.md +15 -0
- package/skill/references/setup-tanstack-start.md +15 -0
- package/skill/references/setup-vite.md +15 -0
- package/skill/references/troubleshoot.md +22 -0
- package/dist/_chunks/date-picker.js +0 -748
- package/dist/_chunks/date-picker.js.map +0 -1
- package/dist/_chunks/file-preview.js +0 -499
- package/dist/_chunks/rich-chat-input.js +0 -2071
- package/dist/_chunks/text.js.map +0 -1
- package/dist/ui/charts/index.js.map +0 -1
package/llms.txt
CHANGED
|
@@ -26,8 +26,34 @@ Other recipes:
|
|
|
26
26
|
- `server-components.md` — RSC-safety matrix and import patterns
|
|
27
27
|
- `troubleshoot.md` — decision tree for the 8 most common breakages
|
|
28
28
|
|
|
29
|
+
## The Themer (fast path for branding)
|
|
30
|
+
|
|
31
|
+
Before hand-writing CSS variables, point the user at **https://shilp-sutra.devalok.in/themer** — one funnel, four doors. Each door drops the user at a result page with install commands + a copy-pasteable CSS block (role tokens + 12-step OKLCH accent ramp) + a shareable URL.
|
|
32
|
+
|
|
33
|
+
| User context | URL |
|
|
34
|
+
|---|---|
|
|
35
|
+
| "Make it look like Linear / Stripe / Apple / Material / Notion / Vercel / Devalok" | `/themer/archetypes` |
|
|
36
|
+
| "Here's our brand color: `#…`" | `/themer/brand` |
|
|
37
|
+
| "Not sure" | `/themer/wizard` |
|
|
38
|
+
| "Show me a sample result" | `/themer/result?archetype=devalok` |
|
|
39
|
+
|
|
40
|
+
Paste the snippet *after* `@import "@devalok/shilp-sutra/css";` in the global stylesheet. No `tailwind.config.ts`, no theme provider, no JS bundle. Fall through to `customize-brand.md` only for tokens the Themer doesn't expose yet (font stack, spacing scale, focus ring).
|
|
41
|
+
|
|
29
42
|
The repo URL for these files is `https://github.com/devalok-design/shilp-sutra/tree/main/packages/core/docs/recipes`. Consumer projects should also have an `AGENTS.md` at their root with the rules above pre-loaded — read that first if it exists.
|
|
30
43
|
|
|
44
|
+
## NEW (v0.40.0)
|
|
45
|
+
|
|
46
|
+
- **OAuthButton.** Brand-aware social/login buttons. Subpath: `@devalok/shilp-sutra/ui/oauth-button`. 13 providers (`google` `apple` `github` `microsoft` `x` `linkedin` `facebook` `discord` `slack` `gitlab` `sso` `email` `passkey`). Props: `provider`, `intent` (`continue|signin|signup`), `appearance` (`brand|outline|dark`), `icon` (override default glyph), `iconOnly`, `compact` (renders just "Google" instead of "Continue with Google"; aria-label keeps long form), `lastUsed` (inline right-edge pill inside button), `helperText`. Inherits Button async/loading/sizes. Siblings: `OAuthGroup` (with `reorderLastUsedFirst` for Stripe-style ordering), `OAuthDivider`, `OAuthConnectionRow` (settings-page linked state). Default glyphs from Tabler peer dep; pass `icon` to drop in a brand's official multicolour SVG. In dark mode every brand appearance lands on the same DS surface — brand identity comes from the glyph, not the bg, so rows stay visually coherent.
|
|
47
|
+
- **Icon API unification.** Every icon-accepting prop (`startIcon`, `endIcon`, `icon`, `leftIcon`, `rightIcon`) across 22 components now takes one type: **`IconInput`**. Pass a rendered element (`<Icon icon={IconPlus} />` or `<IconPlus />`), a component ref (`IconPlus`), or any custom node — all four shapes work interchangeably. Type widening only; every call that compiled before still compiles. Helpers exported for your own wrappers: `import type { IconInput } from '@devalok/shilp-sutra/ui/lib/icon-input'` + `import { normalizeIcon } from '@devalok/shilp-sutra/ui/lib/normalize-icon'`. `IconProvider` now sizes icons via context — delete `className="h-4 w-4"` overrides.
|
|
48
|
+
- **Polymorphic `Text` / `Stack` / `Container`.** The `as` prop now widens accepted attributes to the rendered element: `<Text as="label" htmlFor="email">`, `<Text as="a" href="/x">`, `<Stack as="ul" role="list">`, `<Container as="main" aria-label>` all typecheck. Default element behavior unchanged.
|
|
49
|
+
- **Agent-friendly install experience.** `AGENTS.md` now ships in the tarball (`node_modules/@devalok/shilp-sutra/AGENTS.md`), discoverable by 25+ agent tools. `package.json` declares an `agents` field (npm-agentskills convention) so `pnpm dlx @codemcp/agentskills export` auto-installs the bundled skill. New postinstall welcome banner (silent in CI / non-TTY / `SHILP_SUTRA_NO_WELCOME=1`). `troubleshoot.md` gained peer-cliff symptom entries.
|
|
50
|
+
- **`llms-quick.txt`.** New ≤15K-token fast-path summary in the tarball — fits in one Read on any agent. Read order is now `llms-quick.txt` → `llms.txt` → `llms-full.txt`.
|
|
51
|
+
- **Companion package `@devalok/eslint-plugin-shilp-sutra`** (first release). 12 rules — deprecated-API catches, peer-cliff barrel-import detection, TW3→TW4 classname autofixes. `pnpm add -D @devalok/eslint-plugin-shilp-sutra`, then `shilpSutra.configs['flat/recommended']`. Three presets: `recommended`, `strict`, `migration` (one-shot codemod).
|
|
52
|
+
|
|
53
|
+
## BREAKING CHANGES (v0.40.0)
|
|
54
|
+
|
|
55
|
+
- **Barrel peer-cliff cleanup.** 12 symbols that statically import optional peers were removed from their parent barrels (`/ui`, `/composed`, `/ai`, `/ai/blocks`) — they now import ONLY via per-component subpath. Affected: `Toaster`/`toast` (→ `/ui/toaster`, `/ui/toast`), `InputOTP*` (→ `/ui/input-otp`), `DatePicker*` (→ `/composed/date-picker`), `EmojiPicker*` (→ `/composed/emoji-picker`), `FilePreview` (→ `/composed/file-preview`), `MarkdownViewer` (→ `/composed/markdown-viewer`), `RichTextEditor*`/`RichChatInput*` (→ their subpaths), `BlockRenderer`/`ErrorBlock`/`TextBlock` (→ `/ai/*`). Fixes `Module not found: Can't resolve 'sonner'`/etc. at consumer build time. Full before/after table in `MIGRATION.md → v0.40.0`. Per-chart subpaths (`/ui/charts/bar-chart`, etc.) added non-breaking alongside.
|
|
56
|
+
|
|
31
57
|
## NEW (v0.39.0)
|
|
32
58
|
|
|
33
59
|
- **Shape presets (`[data-shape]`).** Set on `<html>` (or any subtree) to re-skin roundness across the whole UI. Three ship by default: `sharp` (technical, 2/4/6 px), `slightly-rounded` (default, 6/10/16 px), `rounded` (consumer, 10/16/24 px). Pill shapes (Badge, Switch, Radio, Avatar circle) stay pill regardless.
|
|
@@ -441,6 +467,85 @@ import { useColorMode } from '@devalok/shilp-sutra/hooks/use-color-mode'
|
|
|
441
467
|
// CSS tokens (import once at app root — already included in /css):
|
|
442
468
|
import '@devalok/shilp-sutra/css'
|
|
443
469
|
|
|
470
|
+
## IMPORT PATH CHEATSHEET (don't guess — these subpaths are NOT always the kebab-case of the component name)
|
|
471
|
+
|
|
472
|
+
> **0.40.0 — barrel peer-cliff cleanup.** Components below marked `MANDATORY per-component` were removed from their parent barrel (`/ui`, `/composed`, `/ai`, `/ai/blocks`) because they statically import optional peers (`input-otp`, `sonner`, `date-fns`, `@emoji-mart/*`, `react-pdf`, `react-zoom-pan-pinch`, `react-markdown`, `remark-gfm`, `react-syntax-highlighter`, `@tiptap/*`). Fresh consumers using the barrel were getting `Module not found` at build time. The per-component subpath is now the ONLY way to import them. See MIGRATION.md → "v0.40.0 — barrel peer-cliff cleanup" for the full before/after.
|
|
473
|
+
|
|
474
|
+
Common confusions to memorize:
|
|
475
|
+
|
|
476
|
+
| Component / API | Exact import path |
|
|
477
|
+
|------------------------------------------------|----------------------------------------------------------------|
|
|
478
|
+
| `FormField`, `FormHelperText`, `useFormField` | `@devalok/shilp-sutra/ui/form` (NOT `ui/form-field`)|
|
|
479
|
+
| `Label` | `@devalok/shilp-sutra/ui/label` |
|
|
480
|
+
| `AppSidebar` | `@devalok/shilp-sutra/shell/sidebar` (NOT `shell/app-sidebar`)|
|
|
481
|
+
| `TopBar`, `TopBar.*` | `@devalok/shilp-sutra/shell/top-bar` |
|
|
482
|
+
| `BottomNavbar` | `@devalok/shilp-sutra/shell/bottom-navbar` |
|
|
483
|
+
| `AppCommandPalette` | `@devalok/shilp-sutra/shell/app-command-palette` |
|
|
484
|
+
| `CommandRegistryProvider`, `useCommandRegistry`| `@devalok/shilp-sutra/shell/command-registry` |
|
|
485
|
+
| `NotificationCenter` | `@devalok/shilp-sutra/shell/notification-center` |
|
|
486
|
+
| `NotificationPreferences` | `@devalok/shilp-sutra/shell/notification-preferences` |
|
|
487
|
+
| `LinkProvider`, `useLink` | `@devalok/shilp-sutra/shell/link-context` |
|
|
488
|
+
| `CommandPalette` (lower-level palette) | `@devalok/shilp-sutra/composed/command-palette` |
|
|
489
|
+
| `BarChart`, `LineChart`, `AreaChart`, `PieChart`, `RadarChart`, `GaugeChart`, `Sparkline`, `ChartContainer`, `Legend` | `@devalok/shilp-sutra/ui/charts` (full barrel, pulls all 9 d3-\* peers) — **prefer per-chart subpath when possible: `/ui/charts/bar-chart`, `/ui/charts/line-chart`, `/ui/charts/area-chart`, `/ui/charts/pie-chart`, `/ui/charts/radar-chart`, `/ui/charts/gauge-chart`, `/ui/charts/sparkline`, `/ui/charts/chart-container`** (each pulls only the d3-\* peers it needs — BarChart needs `d3-scale` + `d3-axis` + `d3-selection`; PieChart/RadarChart need only `d3-shape`) |
|
|
490
|
+
| `DataTable` | `@devalok/shilp-sutra/ui/data-table` |
|
|
491
|
+
| `DataTableToolbar` | `@devalok/shilp-sutra/ui/data-table-toolbar` |
|
|
492
|
+
| `DatePicker`, `DateRangePicker`, `DateTimePicker`, `TimePicker`, `CalendarGrid`, `YearPicker`, `MonthPicker`, `Presets`, `useCalendar` | `@devalok/shilp-sutra/composed/date-picker` **MANDATORY per-component (0.40.0+)** — pulls `date-fns` |
|
|
493
|
+
| `Toaster` | `@devalok/shilp-sutra/ui/toaster` **MANDATORY per-component (0.40.0+)** — pulls `sonner` |
|
|
494
|
+
| `toast` | `@devalok/shilp-sutra/ui/toast` **MANDATORY per-component (0.40.0+)** — pulls `sonner` |
|
|
495
|
+
| `InputOTP`, `InputOTPGroup`, `InputOTPSeparator`, `InputOTPSlot` | `@devalok/shilp-sutra/ui/input-otp` **MANDATORY per-component (0.40.0+)** — pulls `input-otp` |
|
|
496
|
+
| `EmojiPicker`, `EmojiPickerPopover`, `EmojiData`, `EmojiSet` | `@devalok/shilp-sutra/composed/emoji-picker` **MANDATORY per-component (0.40.0+)** — pulls `@emoji-mart/data` + `@emoji-mart/react` |
|
|
497
|
+
| `EmojiNode`, `EmojiNodeAttrs` | `@devalok/shilp-sutra/composed/extensions/emoji-node` **MANDATORY per-component (0.40.0+)** — pulls `@tiptap/*` |
|
|
498
|
+
| `createEmojiSuggestion` | `@devalok/shilp-sutra/composed/extensions/emoji-suggestion` **MANDATORY per-component (0.40.0+)** — pulls `@tiptap/*` |
|
|
499
|
+
| `FilePreview`, `FilePreviewProps` | `@devalok/shilp-sutra/composed/file-preview` **MANDATORY per-component (0.40.0+)** — pulls `react-pdf` + `react-zoom-pan-pinch` |
|
|
500
|
+
| `MarkdownViewer` | `@devalok/shilp-sutra/composed/markdown-viewer` **MANDATORY per-component (0.40.0+)** — pulls `react-markdown` + `react-syntax-highlighter` + `remark-gfm` |
|
|
501
|
+
| `RichChatInput`, `AudioPlayer`, `AudioWaveform`, `useVoiceRecorder` | `@devalok/shilp-sutra/composed/rich-chat-input` **MANDATORY per-component (0.40.0+)** — pulls `@tiptap/*` |
|
|
502
|
+
| `RichTextEditor`, `RichTextViewer`, `MentionItem`, `ToolbarItem` | `@devalok/shilp-sutra/composed/rich-text-editor` **MANDATORY per-component (0.40.0+)** — pulls `@tiptap/*` |
|
|
503
|
+
| `MessageList`, `Message`, `SystemMessage`, `MessageInput`, `DateSeparator`, `UnreadSeparator`, `TypingIndicator` | `@devalok/shilp-sutra/ui/chat` |
|
|
504
|
+
| `CommandBar` | `@devalok/shilp-sutra/ai/command-bar` (also re-exported from `/ai`) |
|
|
505
|
+
| `AIConversation` | `@devalok/shilp-sutra/ai/conversation` |
|
|
506
|
+
| `BlockRenderer` | `@devalok/shilp-sutra/ai/block-renderer` **MANDATORY per-component (0.40.0+)** — transitively pulls `react-markdown` + `remark-gfm` via ErrorBlock/TextBlock |
|
|
507
|
+
| `AICommandProvider` | `@devalok/shilp-sutra/ai/ai-command-provider` |
|
|
508
|
+
| `DevadootIcon` | `@devalok/shilp-sutra/ai` |
|
|
509
|
+
| `ErrorBlock` | `@devalok/shilp-sutra/ai/blocks/error` **MANDATORY per-component (0.40.0+)** — pulls `react-markdown` + `remark-gfm` |
|
|
510
|
+
| `TextBlock` | `@devalok/shilp-sutra/ai/blocks/text` **MANDATORY per-component (0.40.0+)** — pulls `react-markdown` + `remark-gfm` |
|
|
511
|
+
| `BlockTable`, `ConfirmBlock`, `DividerBlock`, `InfoBlock`, `LoadingBlock`, `StatRowBlock`, `SuccessBlock` | `@devalok/shilp-sutra/ai/blocks` (barrel — these 7 are peer-cliff-free) |
|
|
512
|
+
| `useColorMode` | `@devalok/shilp-sutra/hooks/use-color-mode` |
|
|
513
|
+
| `useMobile` | `@devalok/shilp-sutra/hooks/use-mobile` |
|
|
514
|
+
| `MotionProvider`, `springs`, `tweens`, `stagger`, `useMotion` | `@devalok/shilp-sutra/motion` |
|
|
515
|
+
| `MotionFade`, `MotionScale`, `MotionPop`, `MotionSlide`, `MotionCollapse`, `MotionStagger`, `MotionStaggerItem` | `@devalok/shilp-sutra/motion/primitives` |
|
|
516
|
+
|
|
517
|
+
Components named directly after their file (`Button` → `ui/button`, `Card` → `ui/card`, `Avatar` → `ui/avatar`, `Stack` → `ui/stack`, `Text` → `ui/text`, etc.) follow the kebab-case-of-name rule. The table above is for the ones that DON'T.
|
|
518
|
+
|
|
519
|
+
**When in doubt:** `cat node_modules/@devalok/shilp-sutra/package.json | jq '.exports | keys'` lists every available subpath in the installed version.
|
|
520
|
+
|
|
521
|
+
## ICON API — one shape across every component (v0.40.0+)
|
|
522
|
+
|
|
523
|
+
Every icon-accepting prop in the design system (`startIcon`, `endIcon`, `icon`, etc. — see list below) takes the **`IconInput`** type. Pass any of these four shapes interchangeably:
|
|
524
|
+
|
|
525
|
+
```tsx
|
|
526
|
+
import { IconPlus } from '@tabler/icons-react'
|
|
527
|
+
import { Icon } from '@devalok/shilp-sutra/ui/icon'
|
|
528
|
+
|
|
529
|
+
<Button startIcon={<Icon icon={IconPlus} />}>Add</Button> // canonical
|
|
530
|
+
<Button startIcon={<IconPlus />}>Add</Button> // raw Tabler element
|
|
531
|
+
<Button startIcon={IconPlus}>Add</Button> // component ref
|
|
532
|
+
<Button startIcon={<span>+</span>}>Add</Button> // custom node
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
All four work identically at the call site. The component wraps its icon slot in `<IconProvider size={...}>` so size + stroke flow via React context — no `className="h-4 w-4"` overrides needed.
|
|
536
|
+
|
|
537
|
+
**Components on the unified API:** Button, IconButton, Badge, Combobox, SegmentedControl, Stepper, StatCard, TreeItem (TreeNode.icon), OAuthButton (icon + linkedIcon), Chat.Message.Avatar, Chat.Message.Action, Chat.SystemMessage, AIConversation (agent.icon), AICommandProvider (agent.icon), CommandBar (item.icon), EmptyState (kills the dual ReactNode|ComponentType signature), BulkActionBar (action.icon), ActivityFeed (item.icon), CommandPalette (item.icon), TopBar (UserMenuItem.icon, TopBar.IconButton.icon), Sidebar (NavItem.icon, NavSubItem.icon, footer.promo.icon), BottomNavbar (item.icon), AppCommandPalette (SearchResult.icon), CommandRegistry (CommandPageItem.icon).
|
|
538
|
+
|
|
539
|
+
**Internals** (`<Toaster>`, `<Toast>`'s success/error icons) use Sonner's own type contract and don't accept consumer-passed icons — that's by design.
|
|
540
|
+
|
|
541
|
+
**When to use which shape:**
|
|
542
|
+
- `<Icon icon={IconX} />` when you want explicit size/stroke control (size flows from context if not set)
|
|
543
|
+
- `<IconX />` when you trust the surrounding `IconProvider` and don't need stroke control
|
|
544
|
+
- `IconX` (raw ref) when you want the helper to do the wrapping for you (auto-wraps to `<Icon icon={IconX} />`)
|
|
545
|
+
- Custom node when the "icon" is actually `<span>$</span>` or an emoji
|
|
546
|
+
|
|
547
|
+
**Migration:** zero consumer changes needed if you were already passing valid React content. Components that previously took strict `IconProps['icon']` (BulkActionBar, Message.Action) or `ComponentType<{className}>` (SegmentedControl) now also accept the other three shapes. Strict-to-loose type widening — no breaking calls.
|
|
548
|
+
|
|
444
549
|
## CRITICAL: Differences from shadcn/ui
|
|
445
550
|
|
|
446
551
|
If you have shadcn/ui knowledge, these are the differences that WILL trip you up:
|
|
@@ -478,7 +583,7 @@ Components with two-axis system: Button, Badge, Alert, Banner, Progress, StatusB
|
|
|
478
583
|
|
|
479
584
|
### Inputs & Controls
|
|
480
585
|
- Button: variant(solid|soft|outline|ghost|link) color(accent|error|success|warning|neutral) size(xs|sm|md|lg|compact-xs|compact-sm|compact-md|icon-xs|icon-sm|icon-md|icon-lg) shape(default|pill) weight(semibold|normal) + loading, startIcon, endIcon, asChild, processing?('ambient'|'working'|'urgent'|boolean — marching ants SVG border, forces soft variant), processingColor?('accent'|'error'|'success'|'warning'|'neutral'), processingDisabled?(boolean, default true — set false for cancel-by-click). onClickAsync auto-activates processing='working' during loading phase. Layout animation always on. Deprecated aliases still work: variant="default"→solid, variant="destructive"→solid+error, color="default"→accent
|
|
481
|
-
- IconButton: icon(ReactNode, required) shape(square|circle) size(sm|md|lg) + aria-label required
|
|
586
|
+
- IconButton: icon(ReactNode, required as PROP — NOT children) shape(square|circle) size(sm|md|lg) + aria-label required. **Children rejected by type** (`Omit<ButtonProps, 'children'>`); pass the icon via `icon=` prop. Correct: `<IconButton icon={<Icon icon={IconArrowRight} />} aria-label="Submit" />`. Wrong: `<IconButton><Icon icon={IconArrowRight} /></IconButton>` (TS error). Wrap with `<Icon icon={…} />` (not raw Tabler `<IconX />`) so the size context cascades.
|
|
482
587
|
- SplitButton: [Action | ▼] button with dropdown. Props: variant(solid|soft|outline), color, size(xs|sm|md|icon-xs|icon-sm|icon-md), triggerSide(left|right, default right), triggerWidth?(number|string), placement?(Floating UI Placement, default top-end), dropdownContent(ReactNode), open?, onOpenChange?, dropdownLabel?, dropdownIcon?. ARIA: role="group", aria-haspopup="menu", aria-expanded.
|
|
483
588
|
- ButtonGroup: Visually merges adjacent Buttons. Props: variant, color, size, disabled (propagates), orientation(horizontal|vertical), attached(true|false, default true), fullWidth. Compound pattern: Button reads position from context, applies radius + border-removal inline. Tonal dividers for solid/soft/ghost. Focus z-index isolation.
|
|
484
589
|
- Icon: `<Icon icon={IconPlus} />` — context-aware wrapper for Tabler icons. Size tiers: xs(14px) sm(16px) md(18px) lg(20px) xl(24px) 2xl(32px). Default: md. Stroke: light(1.5) regular(2) bold(2.5). Default: regular. Scales per size tier. Reads size from parent Button/IconGroup via IconContext. Explicit props override. Accessibility: aria-hidden by default. Pass label="Add item" for accessible icons. Animation: animate="spin|pulse|bounce|draw". `draw` renders SVG path-draw animation (check/X icons draw progressively via pathLength; other icons fall back to static). State machine: state="idle|loading|success|error". Button integration: startIcon={<Icon icon={IconPlus} />} (NOT raw <IconPlus />). IconGroup: <IconGroup size="sm" gap="tight"> for toolbar patterns.
|
|
@@ -636,7 +741,7 @@ Import: `@devalok/shilp-sutra/ui/chat`
|
|
|
636
741
|
- Old Fade/Collapse/Grow/Slide from @devalok/shilp-sutra/ui/transitions are REMOVED — use Motion* equivalents
|
|
637
742
|
|
|
638
743
|
### Hooks
|
|
639
|
-
- toast: imperative API — import { toast } from '@devalok/shilp-sutra/ui/toast'. Methods: toast.success/error/warning/info/loading/message/undo/promise/upload/custom/dismiss. useToast() is deprecated.
|
|
744
|
+
- toast: imperative API — import { toast } from '@devalok/shilp-sutra/ui/toast'. **Signature is `(message: string, options?: { description?, duration?, action?, … })`** (sonner-style positional, NOT object-first). Examples: `toast.success('Saved')`, `toast.error('Failed to fetch', { description: 'Check your network', duration: 7000 })`, `toast.promise(fn, { loading: '…', success: '…', error: '…' })`, `toast.upload(file, { onProgress, onComplete })`. Methods: toast.success/error/warning/info/loading/message/undo/promise/upload/custom/dismiss. useToast() is deprecated. Mount `<Toaster />` at layout root or `toast()` calls are no-ops + log a dev warning.
|
|
640
745
|
- useColorMode(): returns { colorMode, setColorMode, toggleColorMode }
|
|
641
746
|
- useMobile(): returns boolean (true if viewport < 768px)
|
|
642
747
|
- useLink(): returns router-agnostic Link component from LinkProvider context (shell/link-context)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devalok/shilp-sutra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "Devalok Design System — accessible React components, OKLCH design tokens, and Tailwind 4 CSS-first setup. Ships with AI-agent setup recipes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Devalok Design & Strategy Studios <shilp-sutra@devalok.in>",
|
|
@@ -275,6 +275,11 @@
|
|
|
275
275
|
"import": "./dist/ui/number-input.js",
|
|
276
276
|
"default": "./dist/ui/number-input.js"
|
|
277
277
|
},
|
|
278
|
+
"./ui/oauth-button": {
|
|
279
|
+
"types": "./dist/ui/oauth-button/index.d.ts",
|
|
280
|
+
"import": "./dist/ui/oauth-button/index.js",
|
|
281
|
+
"default": "./dist/ui/oauth-button/index.js"
|
|
282
|
+
},
|
|
278
283
|
"./ui/pagination": {
|
|
279
284
|
"types": "./dist/ui/pagination.d.ts",
|
|
280
285
|
"import": "./dist/ui/pagination.js",
|
|
@@ -435,6 +440,46 @@
|
|
|
435
440
|
"import": "./dist/ui/charts/index.js",
|
|
436
441
|
"default": "./dist/ui/charts/index.js"
|
|
437
442
|
},
|
|
443
|
+
"./ui/charts/area-chart": {
|
|
444
|
+
"types": "./dist/ui/charts/area-chart.d.ts",
|
|
445
|
+
"import": "./dist/ui/charts/area-chart.js",
|
|
446
|
+
"default": "./dist/ui/charts/area-chart.js"
|
|
447
|
+
},
|
|
448
|
+
"./ui/charts/bar-chart": {
|
|
449
|
+
"types": "./dist/ui/charts/bar-chart.d.ts",
|
|
450
|
+
"import": "./dist/ui/charts/bar-chart.js",
|
|
451
|
+
"default": "./dist/ui/charts/bar-chart.js"
|
|
452
|
+
},
|
|
453
|
+
"./ui/charts/chart-container": {
|
|
454
|
+
"types": "./dist/ui/charts/chart-container.d.ts",
|
|
455
|
+
"import": "./dist/ui/charts/chart-container.js",
|
|
456
|
+
"default": "./dist/ui/charts/chart-container.js"
|
|
457
|
+
},
|
|
458
|
+
"./ui/charts/gauge-chart": {
|
|
459
|
+
"types": "./dist/ui/charts/gauge-chart.d.ts",
|
|
460
|
+
"import": "./dist/ui/charts/gauge-chart.js",
|
|
461
|
+
"default": "./dist/ui/charts/gauge-chart.js"
|
|
462
|
+
},
|
|
463
|
+
"./ui/charts/line-chart": {
|
|
464
|
+
"types": "./dist/ui/charts/line-chart.d.ts",
|
|
465
|
+
"import": "./dist/ui/charts/line-chart.js",
|
|
466
|
+
"default": "./dist/ui/charts/line-chart.js"
|
|
467
|
+
},
|
|
468
|
+
"./ui/charts/pie-chart": {
|
|
469
|
+
"types": "./dist/ui/charts/pie-chart.d.ts",
|
|
470
|
+
"import": "./dist/ui/charts/pie-chart.js",
|
|
471
|
+
"default": "./dist/ui/charts/pie-chart.js"
|
|
472
|
+
},
|
|
473
|
+
"./ui/charts/radar-chart": {
|
|
474
|
+
"types": "./dist/ui/charts/radar-chart.d.ts",
|
|
475
|
+
"import": "./dist/ui/charts/radar-chart.js",
|
|
476
|
+
"default": "./dist/ui/charts/radar-chart.js"
|
|
477
|
+
},
|
|
478
|
+
"./ui/charts/sparkline": {
|
|
479
|
+
"types": "./dist/ui/charts/sparkline.d.ts",
|
|
480
|
+
"import": "./dist/ui/charts/sparkline.js",
|
|
481
|
+
"default": "./dist/ui/charts/sparkline.js"
|
|
482
|
+
},
|
|
438
483
|
"./ui/tree-view": {
|
|
439
484
|
"types": "./dist/ui/tree-view/index.d.ts",
|
|
440
485
|
"import": "./dist/ui/tree-view/index.js",
|
|
@@ -515,6 +560,16 @@
|
|
|
515
560
|
"import": "./dist/composed/file-preview.js",
|
|
516
561
|
"default": "./dist/composed/file-preview.js"
|
|
517
562
|
},
|
|
563
|
+
"./composed/extensions/emoji-node": {
|
|
564
|
+
"types": "./dist/composed/extensions/emoji-node.d.ts",
|
|
565
|
+
"import": "./dist/composed/extensions/emoji-node.js",
|
|
566
|
+
"default": "./dist/composed/extensions/emoji-node.js"
|
|
567
|
+
},
|
|
568
|
+
"./composed/extensions/emoji-suggestion": {
|
|
569
|
+
"types": "./dist/composed/extensions/emoji-suggestion.d.ts",
|
|
570
|
+
"import": "./dist/composed/extensions/emoji-suggestion.js",
|
|
571
|
+
"default": "./dist/composed/extensions/emoji-suggestion.js"
|
|
572
|
+
},
|
|
518
573
|
"./composed/filter-bar": {
|
|
519
574
|
"types": "./dist/composed/filter-bar.d.ts",
|
|
520
575
|
"import": "./dist/composed/filter-bar.js",
|
|
@@ -721,6 +776,16 @@
|
|
|
721
776
|
"import": "./dist/ai/blocks/index.js",
|
|
722
777
|
"default": "./dist/ai/blocks/index.js"
|
|
723
778
|
},
|
|
779
|
+
"./ai/blocks/error": {
|
|
780
|
+
"types": "./dist/ai/blocks/error.d.ts",
|
|
781
|
+
"import": "./dist/ai/blocks/error.js",
|
|
782
|
+
"default": "./dist/ai/blocks/error.js"
|
|
783
|
+
},
|
|
784
|
+
"./ai/blocks/text": {
|
|
785
|
+
"types": "./dist/ai/blocks/text.d.ts",
|
|
786
|
+
"import": "./dist/ai/blocks/text.js",
|
|
787
|
+
"default": "./dist/ai/blocks/text.js"
|
|
788
|
+
},
|
|
724
789
|
"./ai/types": {
|
|
725
790
|
"types": "./dist/ai/types.d.ts",
|
|
726
791
|
"import": "./dist/ai/types.js",
|
|
@@ -735,11 +800,22 @@
|
|
|
735
800
|
"docs/rollback.md",
|
|
736
801
|
"fonts",
|
|
737
802
|
"skill",
|
|
803
|
+
"scripts/welcome.mjs",
|
|
804
|
+
"AGENTS.md",
|
|
738
805
|
"MIGRATION.md",
|
|
739
806
|
"README.md",
|
|
740
807
|
"llms.txt",
|
|
808
|
+
"llms-quick.txt",
|
|
741
809
|
"llms-full.txt"
|
|
742
810
|
],
|
|
811
|
+
"agents": {
|
|
812
|
+
"skills": [
|
|
813
|
+
{
|
|
814
|
+
"name": "shilp-sutra",
|
|
815
|
+
"path": "./skill"
|
|
816
|
+
}
|
|
817
|
+
]
|
|
818
|
+
},
|
|
743
819
|
"peerDependencies": {
|
|
744
820
|
"@emoji-mart/data": "^1.0.0",
|
|
745
821
|
"@emoji-mart/react": "^1.0.0",
|
|
@@ -890,6 +966,7 @@
|
|
|
890
966
|
"typecheck": "tsc --noEmit",
|
|
891
967
|
"lint": "eslint src/",
|
|
892
968
|
"test": "vitest run",
|
|
893
|
-
"test:coverage": "vitest run --coverage"
|
|
969
|
+
"test:coverage": "vitest run --coverage",
|
|
970
|
+
"postinstall": "node scripts/welcome.mjs || true"
|
|
894
971
|
}
|
|
895
972
|
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Postinstall welcome banner for @devalok/shilp-sutra.
|
|
4
|
+
*
|
|
5
|
+
* Runs once per major.minor version on consumer install. Silent under CI,
|
|
6
|
+
* non-TTY environments, NO_COLOR, npm silent loglevel, or when the
|
|
7
|
+
* SHILP_SUTRA_NO_WELCOME env var is set. Falls back to a compact 6-line
|
|
8
|
+
* text block if the terminal is narrower than 70 columns or shorter than
|
|
9
|
+
* 28 rows. Never throws — wrapped in a try/catch so an internal error can
|
|
10
|
+
* never break the consumer install.
|
|
11
|
+
*
|
|
12
|
+
* Safety guards (industry best practice — see research notes in
|
|
13
|
+
* .changeset/wave-4-install-experience.md):
|
|
14
|
+
*
|
|
15
|
+
* - process.env.CI → silent (avoid log noise on CI)
|
|
16
|
+
* - process.env.SHILP_SUTRA_NO_WELCOME=1 → silent (user opt-out)
|
|
17
|
+
* - process.env.NO_COLOR → plain text, no ANSI
|
|
18
|
+
* - process.stdout.isTTY === false → silent (piped builds, Docker)
|
|
19
|
+
* - npm_config_loglevel === 'silent' → silent (respect pkg manager)
|
|
20
|
+
* - !INIT_CWD || INIT_CWD inside the package → silent (dev install, not consumer)
|
|
21
|
+
* - Sentinel file with current version → silent on re-install of same ver
|
|
22
|
+
* - try/catch around everything → always exit 0
|
|
23
|
+
*
|
|
24
|
+
* The sentinel encodes the version (`node_modules/.shilp-sutra-welcomed`)
|
|
25
|
+
* so version bumps re-fire the banner once.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
29
|
+
import { dirname, join, resolve } from 'node:path'
|
|
30
|
+
import { fileURLToPath } from 'node:url'
|
|
31
|
+
|
|
32
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
33
|
+
const PKG_DIR = resolve(__dirname, '..')
|
|
34
|
+
|
|
35
|
+
// ── Guard rails — bail out early if any condition says "silent". ────────────
|
|
36
|
+
function shouldSkip() {
|
|
37
|
+
if (process.env.CI) return 'CI environment'
|
|
38
|
+
if (process.env.SHILP_SUTRA_NO_WELCOME === '1' || process.env.SHILP_SUTRA_NO_WELCOME === 'true') return 'SHILP_SUTRA_NO_WELCOME set'
|
|
39
|
+
if (process.env.npm_config_loglevel === 'silent') return 'npm silent loglevel'
|
|
40
|
+
if (!process.stdout.isTTY) return 'not a TTY (piped/Docker/etc.)'
|
|
41
|
+
// Dev install — we're inside the design-system repo itself, not a consumer
|
|
42
|
+
const initCwd = process.env.INIT_CWD || process.cwd()
|
|
43
|
+
const cwd = process.cwd()
|
|
44
|
+
const isInsideNodeModules = cwd.includes(`${process.platform === 'win32' ? '\\' : '/'}node_modules${process.platform === 'win32' ? '\\' : '/'}`) || cwd.includes('/node_modules/')
|
|
45
|
+
if (!isInsideNodeModules) return 'dev install (not running from node_modules/)'
|
|
46
|
+
// INIT_CWD points at the consumer's project root. If absent → odd setup; skip.
|
|
47
|
+
if (!initCwd || initCwd === cwd) return 'no INIT_CWD set (unusual install context)'
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function readPkgVersion() {
|
|
52
|
+
try {
|
|
53
|
+
const pkg = JSON.parse(readFileSync(join(PKG_DIR, 'package.json'), 'utf-8'))
|
|
54
|
+
return pkg.version
|
|
55
|
+
} catch {
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Sentinel: re-fire only on version change. Stored at the workspace root's
|
|
61
|
+
// node_modules/.shilp-sutra-welcomed so it survives pnpm dedupe rebuilds.
|
|
62
|
+
function getSentinelPath() {
|
|
63
|
+
// Walk up from PKG_DIR (node_modules/@devalok/shilp-sutra/) to the
|
|
64
|
+
// enclosing node_modules/ root, then write inside it.
|
|
65
|
+
const parts = PKG_DIR.split(/[/\\]/)
|
|
66
|
+
const nmIdx = parts.lastIndexOf('node_modules')
|
|
67
|
+
if (nmIdx === -1) return null
|
|
68
|
+
const nmRoot = parts.slice(0, nmIdx + 1).join(process.platform === 'win32' ? '\\' : '/')
|
|
69
|
+
return join(nmRoot, '.shilp-sutra-welcomed')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function alreadyWelcomed(version) {
|
|
73
|
+
const sentinel = getSentinelPath()
|
|
74
|
+
if (!sentinel) return false
|
|
75
|
+
try {
|
|
76
|
+
if (!existsSync(sentinel)) return false
|
|
77
|
+
const previousVersion = readFileSync(sentinel, 'utf-8').trim()
|
|
78
|
+
return previousVersion === version
|
|
79
|
+
} catch {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function markWelcomed(version) {
|
|
85
|
+
const sentinel = getSentinelPath()
|
|
86
|
+
if (!sentinel) return
|
|
87
|
+
try {
|
|
88
|
+
mkdirSync(dirname(sentinel), { recursive: true })
|
|
89
|
+
writeFileSync(sentinel, version + '\n')
|
|
90
|
+
} catch {
|
|
91
|
+
// ignored — banner already printed, sentinel write is best-effort
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── ANSI rendering ──────────────────────────────────────────────────────────
|
|
96
|
+
const useColor = !process.env.NO_COLOR && process.stdout.isTTY
|
|
97
|
+
|
|
98
|
+
// Devalok pink #d946a6 = RGB(217, 70, 166)
|
|
99
|
+
const PINK = useColor ? '\x1b[38;2;217;70;166m' : ''
|
|
100
|
+
const PINK_DIM = useColor ? '\x1b[38;2;167;55;128m' : ''
|
|
101
|
+
const BOLD = useColor ? '\x1b[1m' : ''
|
|
102
|
+
const DIM = useColor ? '\x1b[2m' : ''
|
|
103
|
+
const RESET = useColor ? '\x1b[0m' : ''
|
|
104
|
+
|
|
105
|
+
function colour(text, code) {
|
|
106
|
+
return useColor ? `${code}${text}${RESET}` : text
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Lotus — 13 rows × 30 cols Braille. Centered in a 63-col inner box (16 left,
|
|
110
|
+
// 17 right padding).
|
|
111
|
+
const LOTUS = [
|
|
112
|
+
'⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
|
|
113
|
+
'⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⠟⠹⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
|
|
114
|
+
'⠀⠀⠀⠀⠀⠀⠀⠀⣷⣦⣄⣠⣿⠃⢠⣄⠈⢻⣆⣠⣴⡞⡆⠀⠀⠀⠀⠀⠀⠀',
|
|
115
|
+
'⠀⠀⠀⠀⠀⢀⣀⣀⣿⠀⠈⢻⣇⢀⣾⢟⡄⣸⡿⠋⠀⡇⣇⣀⣀⠀⠀⠀⠀⠀',
|
|
116
|
+
'⠀⣤⣤⣤⣀⣱⢻⠚⠻⣧⣀⠀⢹⡿⠃⠈⢻⣟⠀⢀⣤⠧⠓⣹⣟⣀⣤⣤⣤⡀',
|
|
117
|
+
'⠀⠈⠻⣧⠉⠛⣽⠀⠀⠀⠙⣷⡿⠁⠀⠀⠀⢻⣶⠛⠁⠀⠀⡟⠟⠉⣵⡟⠁⠀',
|
|
118
|
+
'⠀⠀⠀⠹⣧⡀⠏⡇⠀⠀⠀⣿⠁⠀⠀⠀⠀⠀⣿⡄⠀⠀⢠⢷⠀⣼⡟⠀⠀⠀',
|
|
119
|
+
'⠀⠀⠀⠀⠙⣟⢼⡹⡄⠀⠀⣿⡄⠀⠀⠀⠀⢀⣿⡇⠀⢀⣞⣦⢾⠟⠀⠀⠀⠀',
|
|
120
|
+
'⠀⠠⢶⣿⣛⠛⢒⣭⢻⣶⣤⣹⣿⣤⣀⣀⣠⣾⣟⣠⣔⡛⢫⣐⠛⢛⣻⣶⠆⠀',
|
|
121
|
+
'⠀⠀⠀⠉⣻⡽⠛⠉⠁⠀⠉⢙⣿⠖⠒⠛⠻⣿⡋⠉⠁⠈⠉⠙⢿⣿⠉⠀⠀⠀',
|
|
122
|
+
'⠀⠀⠀⠸⠿⠷⠒⣦⣤⣴⣶⢿⣿⡀⠀⠀⠀⣽⡿⢷⣦⠤⢤⡖⠶⠿⠧⠀⠀⠀',
|
|
123
|
+
'⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⢿⣦⣴⡾⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
|
|
124
|
+
'⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
const TOP = '╭───────────────────────────────────────────────────────────────╮'
|
|
128
|
+
const BOTTOM = '╰───────────────────────────────────────────────────────────────╯'
|
|
129
|
+
const EMPTY = '│ │'
|
|
130
|
+
const INNER_WIDTH = 63
|
|
131
|
+
|
|
132
|
+
function row(content) {
|
|
133
|
+
// content is a string of visible chars (ANSI-stripped width assumed equal to char count for ASCII)
|
|
134
|
+
// We can't easily measure visible width when ANSI codes are present, so always pad based on the
|
|
135
|
+
// PASSED visibleWidth in callers that contain colour. For plain rows, fall back to .length.
|
|
136
|
+
const visible = content.replace(/\x1b\[[0-9;]*m/g, '')
|
|
137
|
+
const padLen = Math.max(0, INNER_WIDTH - visible.length)
|
|
138
|
+
return `│${content}${' '.repeat(padLen)}│`
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function centeredLotusRow(braille) {
|
|
142
|
+
// 30-col Braille row, 16-left + 17-right padding
|
|
143
|
+
return `│ ${colour(braille, PINK)} │`
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function buildFullBanner(version) {
|
|
147
|
+
const lines = []
|
|
148
|
+
lines.push(colour(TOP, PINK_DIM))
|
|
149
|
+
lines.push(colour(EMPTY, PINK_DIM))
|
|
150
|
+
for (const lotusRow of LOTUS) {
|
|
151
|
+
lines.push(`${colour('│', PINK_DIM)} ${colour(lotusRow, PINK)} ${colour('│', PINK_DIM)}`)
|
|
152
|
+
}
|
|
153
|
+
lines.push(colour(EMPTY, PINK_DIM))
|
|
154
|
+
lines.push(row(` ${colour('✦', PINK)} ${colour('@devalok/shilp-sutra', BOLD)} ${version}`))
|
|
155
|
+
lines.push(row(` ${colour('Tailwind 4 design system · 110+ components · RSC-safe', DIM)}`))
|
|
156
|
+
lines.push(colour(EMPTY, PINK_DIM))
|
|
157
|
+
lines.push(row(` ${colour('▸', PINK)} Setup recipe (pick your framework):`))
|
|
158
|
+
lines.push(row(` ${colour('node_modules/@devalok/shilp-sutra/docs/recipes/', DIM)}`))
|
|
159
|
+
lines.push(colour(EMPTY, PINK_DIM))
|
|
160
|
+
lines.push(row(` ${colour('▸', PINK)} Theme it in 30 seconds:`))
|
|
161
|
+
lines.push(row(` ${colour('https://shilp-sutra.devalok.in/themer', DIM)}`))
|
|
162
|
+
lines.push(colour(EMPTY, PINK_DIM))
|
|
163
|
+
lines.push(row(` ${colour('▸', PINK)} Wire your AI agent (Claude Code / Cursor / Codex):`))
|
|
164
|
+
lines.push(row(` ${colour('cp -r node_modules/@devalok/shilp-sutra/skill \\', DIM)}`))
|
|
165
|
+
lines.push(row(` ${colour('~/.claude/skills/shilp-sutra', DIM)}`))
|
|
166
|
+
lines.push(colour(EMPTY, PINK_DIM))
|
|
167
|
+
lines.push(row(` ${colour('Disable this banner: SHILP_SUTRA_NO_WELCOME=1', DIM)}`))
|
|
168
|
+
lines.push(colour(EMPTY, PINK_DIM))
|
|
169
|
+
lines.push(row(` ${colour('Built by Devalok · devalok.in', PINK)}`))
|
|
170
|
+
lines.push(colour(EMPTY, PINK_DIM))
|
|
171
|
+
lines.push(colour(BOTTOM, PINK_DIM))
|
|
172
|
+
return lines.join('\n')
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function buildCompactBanner(version) {
|
|
176
|
+
return [
|
|
177
|
+
'',
|
|
178
|
+
`${colour('✦', PINK)} ${colour('@devalok/shilp-sutra', BOLD)} ${version} ${colour('· Tailwind 4 design system', DIM)}`,
|
|
179
|
+
` ${colour('▸', PINK)} Setup: ${colour('node_modules/@devalok/shilp-sutra/docs/recipes/', DIM)}`,
|
|
180
|
+
` ${colour('▸', PINK)} Theme: ${colour('https://shilp-sutra.devalok.in/themer', DIM)}`,
|
|
181
|
+
` ${colour('▸', PINK)} AI: ${colour('cp -r node_modules/@devalok/shilp-sutra/skill ~/.claude/skills/shilp-sutra', DIM)}`,
|
|
182
|
+
` ${colour('Built by Devalok · devalok.in', PINK)} ${colour('(SHILP_SUTRA_NO_WELCOME=1 to disable)', DIM)}`,
|
|
183
|
+
'',
|
|
184
|
+
].join('\n')
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ── Main ────────────────────────────────────────────────────────────────────
|
|
188
|
+
function main() {
|
|
189
|
+
// --preview / --compact bypass all guards. Used by maintainers + by the
|
|
190
|
+
// pre-publish-audit gate to verify the banner renders without ever
|
|
191
|
+
// shipping a broken one. Compose only — never writes the sentinel.
|
|
192
|
+
const preview = process.argv.includes('--preview')
|
|
193
|
+
const forceCompact = process.argv.includes('--compact')
|
|
194
|
+
|
|
195
|
+
if (!preview) {
|
|
196
|
+
const skipReason = shouldSkip()
|
|
197
|
+
if (skipReason) return // silent
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const version = readPkgVersion() || '0.0.0-preview'
|
|
201
|
+
|
|
202
|
+
if (!preview && alreadyWelcomed(version)) return
|
|
203
|
+
|
|
204
|
+
const cols = process.stdout.columns || 80
|
|
205
|
+
const rows = process.stdout.rows || 40
|
|
206
|
+
const fitsFull = !forceCompact && cols >= 70 && rows >= 28
|
|
207
|
+
|
|
208
|
+
const banner = fitsFull ? buildFullBanner(version) : buildCompactBanner(version)
|
|
209
|
+
process.stdout.write('\n' + banner + '\n')
|
|
210
|
+
|
|
211
|
+
if (!preview) markWelcomed(version)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
main()
|
|
216
|
+
} catch {
|
|
217
|
+
// Never crash the consumer install. A failure here is a UX bug, not a
|
|
218
|
+
// blocker — pretend nothing happened.
|
|
219
|
+
}
|
package/skill/SKILL.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: shilp-sutra
|
|
3
|
-
description: Add, configure, and use components from Devalok's shilp-sutra design system (@devalok/shilp-sutra) — a Tailwind 4 + React 19 + CVA library with 110+ accessible components, OKLCH design tokens, framer-motion animations, and per-component RSC-safe entry points. Use this skill whenever the user mentions shilp-sutra, Devalok, the @devalok npm scope, or asks to install/add/style/theme UI in any React project that already depends on the package — even if they don't name it explicitly. Use it instead of generic shadcn/ui, MUI, or Chakra knowledge when shilp-sutra is in the project. Covers Next.js (App + Pages), Vite, Astro, Remix, TanStack Start setup playbooks; component API and variant reference; brand token customization; Server Component import patterns; and a troubleshoot tree for the
|
|
3
|
+
description: Add, configure, and use components from Devalok's shilp-sutra design system (@devalok/shilp-sutra) — a Tailwind 4 + React 19 + CVA library with 110+ accessible components, OKLCH design tokens, framer-motion animations, and per-component RSC-safe entry points. Use this skill whenever the user mentions shilp-sutra, Devalok, the @devalok npm scope, or asks to install/add/style/theme UI in any React project that already depends on the package — even if they don't name it explicitly. Use it instead of generic shadcn/ui, MUI, or Chakra knowledge when shilp-sutra is in the project. Covers Next.js (App + Pages), Vite, Astro, Remix, TanStack Start setup playbooks; component API and variant reference; brand token customization; Server Component import patterns; and a troubleshoot tree for the thirteen most common breakages.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.40.0"
|
|
7
7
|
author: Devalok Design & Strategy Studios
|
|
8
8
|
homepage: https://github.com/devalok-design/shilp-sutra
|
|
9
9
|
npm: https://www.npmjs.com/package/@devalok/shilp-sutra
|
|
@@ -96,7 +96,26 @@ Putting `bg-surface-base` on a card is a bug — cards belong on `surface-raised
|
|
|
96
96
|
|
|
97
97
|
## Theming and brand customization
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
### Step 0 — Send the user to the Themer
|
|
100
|
+
|
|
101
|
+
Before hand-rolling CSS variables, send the user to **[shilp-sutra.devalok.in/themer](https://shilp-sutra.devalok.in/themer)**. One funnel, four doors:
|
|
102
|
+
|
|
103
|
+
| User context | Door |
|
|
104
|
+
|---|---|
|
|
105
|
+
| "Make it look like Linear / Stripe / Apple / Notion / Vercel / Material" | `/themer/archetypes` |
|
|
106
|
+
| "Here is our brand color: `#…`" | `/themer/brand` |
|
|
107
|
+
| "Not sure what we want yet" | `/themer/wizard` |
|
|
108
|
+
| "Just show me what we'd ship away with" | `/themer/result?archetype=devalok` |
|
|
109
|
+
|
|
110
|
+
Every door drops them at `/themer/result` with: a copy-pasteable CSS block (role tokens + 12-step OKLCH accent ramp), install commands for their package manager, a live preview, and a share URL that encodes the theme (`?archetype=…&hue=…&chroma=…&density=…`).
|
|
111
|
+
|
|
112
|
+
Your job once they have the snippet: paste it into their global stylesheet **after** the `@import "@devalok/shilp-sutra/css";` line. That is it — no `tailwind.config.ts`, no provider, no JS bundle.
|
|
113
|
+
|
|
114
|
+
If the user is in a hurry and asks you to just pick something, default to `archetype=devalok` (the studio's own preset, balanced for most apps) and use their brand hex if they have one, else `hue=340 chroma=0.19`.
|
|
115
|
+
|
|
116
|
+
### Step 1 — Hand-roll fallback
|
|
117
|
+
|
|
118
|
+
`references/customize-brand.md` covers what the Themer doesn't expose yet: font swap, spacing scale, focus-ring overrides, dark-mode mapping nuance. Customization is CSS-only: override CSS custom properties under `:root` and `.dark`. There is no theme provider component.
|
|
100
119
|
|
|
101
120
|
For the Devalok logo and other brand assets, the sibling package `@devalok/shilp-sutra-brand` ships SVG + PNG. Install it separately.
|
|
102
121
|
|