@devalok/shilp-sutra 0.38.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 +255 -0
- package/README.md +3 -0
- package/dist/_chunks/badge-group.js +76 -75
- 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 +236 -228
- 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/document-preview.js +2 -2
- package/dist/_chunks/document-preview.js.map +1 -1
- 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/image-preview.js +2 -2
- package/dist/_chunks/image-preview.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +35 -263
- 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/popover.js +3 -3
- package/dist/_chunks/popover.js.map +1 -1
- package/dist/_chunks/primitives.js +107 -107
- package/dist/_chunks/primitives.js.map +1 -1
- package/dist/_chunks/shared.js +5 -5
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/{text.js → success.js} +26 -63
- 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/_chunks/use-calendar.js +5 -5
- package/dist/_chunks/use-calendar.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 +198 -193
- 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 +92 -87
- 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 +5 -5
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/avatar-group.js +4 -4
- package/dist/composed/avatar-group.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 +12 -12
- 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 +106 -101
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.js +1 -1
- package/dist/composed/content-card.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/emoji-picker.js +4 -4
- package/dist/composed/emoji-picker.js.map +1 -1
- 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/error-boundary.js +3 -3
- package/dist/composed/error-boundary.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/composed/file-preview.js.map +1 -0
- package/dist/composed/filter-bar.js +1 -1
- package/dist/composed/filter-bar.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/inline-edit.js +1 -1
- package/dist/composed/inline-edit.js.map +1 -1
- package/dist/composed/loading-skeleton.js +9 -9
- package/dist/composed/loading-skeleton.js.map +1 -1
- package/dist/composed/markdown-viewer.js +3 -3
- package/dist/composed/markdown-viewer.js.map +1 -1
- package/dist/composed/multi-select-popover.js +1 -1
- package/dist/composed/multi-select-popover.js.map +1 -1
- package/dist/composed/page-header.js +1 -1
- package/dist/composed/page-header.js.map +1 -1
- package/dist/composed/page-skeletons.js +15 -15
- package/dist/composed/page-skeletons.js.map +1 -1
- package/dist/composed/priority-indicator.js +3 -3
- package/dist/composed/priority-indicator.js.map +1 -1
- package/dist/composed/rich-chat-input.js +2073 -2
- package/dist/composed/rich-chat-input.js.map +1 -0
- package/dist/composed/rich-text-editor.js +75 -72
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.js +3 -3
- package/dist/composed/schedule-view.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 +94 -86
- 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/notification-center.js +8 -8
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/notification-preferences.js +1 -1
- package/dist/shell/notification-preferences.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 +148 -134
- 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 +116 -108
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/semantic.css +82 -9
- package/dist/ui/accordion.js +1 -1
- package/dist/ui/accordion.js.map +1 -1
- package/dist/ui/alert-dialog.js +3 -3
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/alert.js +2 -2
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/autocomplete.js +2 -2
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/avatar.js +11 -11
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/badge-indicator.js +1 -1
- package/dist/ui/badge-indicator.js.map +1 -1
- package/dist/ui/badge.d.ts +3 -2
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/banner.js +1 -1
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/breadcrumb.js +1 -1
- package/dist/ui/breadcrumb.js.map +1 -1
- package/dist/ui/button.d.ts +5 -4
- package/dist/ui/button.d.ts.map +1 -1
- package/dist/ui/button.js +66 -65
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.js +5 -5
- package/dist/ui/card.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/checkbox.js +1 -1
- package/dist/ui/checkbox.js.map +1 -1
- package/dist/ui/code.js +2 -2
- package/dist/ui/code.js.map +1 -1
- package/dist/ui/color-input.js +10 -10
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/color-swatch.js +3 -3
- package/dist/ui/color-swatch.js.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 +100 -95
- 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/context-menu.js +6 -6
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-body.js +1 -1
- package/dist/ui/data-table-body.js.map +1 -1
- package/dist/ui/data-table-bulk-actions.js +2 -2
- package/dist/ui/data-table-bulk-actions.js.map +1 -1
- package/dist/ui/data-table-card.js +2 -2
- package/dist/ui/data-table-card.js.map +1 -1
- package/dist/ui/data-table-header.js +2 -2
- package/dist/ui/data-table-header.js.map +1 -1
- package/dist/ui/data-table-pagination.js +3 -3
- package/dist/ui/data-table-pagination.js.map +1 -1
- package/dist/ui/data-table-toolbar.js +1 -1
- package/dist/ui/data-table-toolbar.js.map +1 -1
- package/dist/ui/data-table.js +1 -1
- package/dist/ui/data-table.js.map +1 -1
- package/dist/ui/devalok-grain.d.ts +1 -1
- package/dist/ui/devalok-grain.js.map +1 -1
- package/dist/ui/dialog.js +2 -2
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dropdown-menu.js +6 -6
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/file-upload.js +4 -4
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/hover-card.js +1 -1
- package/dist/ui/hover-card.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/input-otp.js +1 -1
- package/dist/ui/input-otp.js.map +1 -1
- package/dist/ui/input.js +2 -2
- package/dist/ui/input.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/link.js +1 -1
- package/dist/ui/link.js.map +1 -1
- package/dist/ui/menubar.js +8 -8
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.js +3 -3
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/number-input.js +3 -3
- package/dist/ui/number-input.js.map +1 -1
- 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/pagination.js +1 -1
- package/dist/ui/pagination.js.map +1 -1
- package/dist/ui/progress.js +2 -2
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/radio.js +1 -1
- package/dist/ui/radio.js.map +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/select.js +3 -3
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sheet.js +2 -2
- package/dist/ui/sheet.js.map +1 -1
- package/dist/ui/sidebar.js +11 -11
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/skeleton.js +9 -9
- package/dist/ui/skeleton.js.map +1 -1
- package/dist/ui/slider.js +2 -2
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/split-button.js +7 -7
- package/dist/ui/split-button.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 +118 -116
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/status-dot.js +2 -2
- package/dist/ui/status-dot.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/switch.js +2 -2
- package/dist/ui/switch.js.map +1 -1
- package/dist/ui/tabs.js +3 -3
- package/dist/ui/tabs.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/textarea.js +1 -1
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast.js +8 -8
- package/dist/ui/toast.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/toggle.js +1 -1
- package/dist/ui/toggle.js.map +1 -1
- package/dist/ui/tooltip.js +12 -12
- package/dist/ui/tooltip.js.map +1 -1
- 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/_header.md +90 -1
- package/docs/components/ui/oauth-button.md +86 -0
- package/docs/recipes/customize-brand.md +100 -4
- 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 +177 -2
- package/llms-quick.txt +247 -0
- package/llms.txt +116 -3
- package/package.json +80 -2
- package/scripts/welcome.mjs +219 -0
- package/skill/README.md +99 -0
- package/skill/SKILL.md +163 -0
- package/skill/install.sh +59 -0
- package/skill/references/components-full.md +7083 -0
- package/skill/references/components.md +778 -0
- package/skill/references/customize-brand.md +314 -0
- package/skill/references/server-components.md +211 -0
- package/skill/references/setup-astro.md +195 -0
- package/skill/references/setup-next-app-router.md +248 -0
- package/skill/references/setup-next-pages.md +127 -0
- package/skill/references/setup-remix.md +188 -0
- package/skill/references/setup-tanstack-start.md +160 -0
- package/skill/references/setup-vite.md +187 -0
- package/skill/references/troubleshoot.md +241 -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/file-preview.js.map +0 -1
- package/dist/_chunks/rich-chat-input.js +0 -2071
- package/dist/_chunks/rich-chat-input.js.map +0 -1
- package/dist/_chunks/text.js.map +0 -1
- package/dist/ui/charts/index.js.map +0 -1
- /package/{LICENSE → skill/LICENSE} +0 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
<!-- Source: packages/core/docs/recipes/customize-brand.md — do not edit directly. Regenerate with `node scripts/build-skill.mjs`. -->
|
|
2
|
+
|
|
3
|
+
# Customize: Brand & Tokens
|
|
4
|
+
|
|
5
|
+
Override colors, radius, fonts, and spacing without forking the package. All customization happens through CSS custom properties — no JS configuration.
|
|
6
|
+
|
|
7
|
+
## The fast path: use the Themer
|
|
8
|
+
|
|
9
|
+
Before hand-writing variables, try **[shilp-sutra.devalok.in/themer](https://shilp-sutra.devalok.in/themer)**. It is one funnel with four entry doors:
|
|
10
|
+
|
|
11
|
+
- **Pick an archetype** — Linear, Stripe, Apple, Material, Notion, Vercel, or Devalok. Click → result page.
|
|
12
|
+
- **Use my brand color** — paste a hex or dial OKLCH. Auto-generates the 12-step ramp and suggests an archetype.
|
|
13
|
+
- **Walk me through it** — five-question wizard composes the answers into a theme.
|
|
14
|
+
- **Just exploring** — land on a sample result page to see what you ship away with.
|
|
15
|
+
|
|
16
|
+
Every door drops you at the same result screen: a copy-pasteable CSS block (role tokens + 12-step OKLCH accent ramp), install commands for your package manager, and a share URL that encodes the theme.
|
|
17
|
+
|
|
18
|
+
Paste the snippet into your global stylesheet *after* the `@import "@devalok/shilp-sutra/css";` line. That's the whole flow — no `tailwind.config.ts`, no theme provider, no JS bundle.
|
|
19
|
+
|
|
20
|
+
The rest of this doc covers what to do if the Themer doesn't expose a token you need to override (font stack, spacing scale, focus ring) — fall through to the hand-written cases below.
|
|
21
|
+
|
|
22
|
+
## How tokens layer
|
|
23
|
+
|
|
24
|
+
Shilp Sutra's tokens are organized in three tiers:
|
|
25
|
+
|
|
26
|
+
1. **Primitives** (`primitives.css`) — raw OKLCH palette values. Private. You should not need to touch these.
|
|
27
|
+
2. **Semantic** (`semantic.css`) — intent-based mappings (`--color-accent-9`, `--color-surface-2`, `--font-sans`). Public, exposed to Tailwind 4's `@theme`.
|
|
28
|
+
3. **Utility output** — Tailwind generates classes (`bg-accent-9`, `text-surface-fg`, `font-sans`) from the semantic layer.
|
|
29
|
+
|
|
30
|
+
To override a token, redefine it AFTER the design-system import. The cascade does the rest.
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
@import "tailwindcss";
|
|
34
|
+
@import "@devalok/shilp-sutra/css";
|
|
35
|
+
|
|
36
|
+
@theme {
|
|
37
|
+
/* Overrides go here */
|
|
38
|
+
--color-accent-9: oklch(0.55 0.22 195);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`@theme` is the Tailwind 4 directive that registers a CSS variable AND auto-generates the matching utility (so `bg-accent-9` picks up the override).
|
|
43
|
+
|
|
44
|
+
## Common overrides
|
|
45
|
+
|
|
46
|
+
### Change the accent color
|
|
47
|
+
|
|
48
|
+
The accent scale runs from `--color-accent-1` (lightest) to `--color-accent-12` (darkest). Step 9 is the saturated default-button background, step 11 is on-tint text.
|
|
49
|
+
|
|
50
|
+
To swap to teal:
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
@theme {
|
|
54
|
+
--color-accent-1: oklch(0.985 0.005 195);
|
|
55
|
+
--color-accent-2: oklch(0.96 0.012 195);
|
|
56
|
+
--color-accent-3: oklch(0.92 0.025 195);
|
|
57
|
+
--color-accent-4: oklch(0.88 0.04 195);
|
|
58
|
+
--color-accent-5: oklch(0.82 0.07 195);
|
|
59
|
+
--color-accent-6: oklch(0.74 0.10 195);
|
|
60
|
+
--color-accent-7: oklch(0.66 0.14 195);
|
|
61
|
+
--color-accent-8: oklch(0.60 0.17 195);
|
|
62
|
+
--color-accent-9: oklch(0.54 0.22 195);
|
|
63
|
+
--color-accent-10: oklch(0.49 0.21 195);
|
|
64
|
+
--color-accent-11: oklch(0.42 0.16 195);
|
|
65
|
+
--color-accent-12: oklch(0.20 0.05 195);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.dark {
|
|
69
|
+
--color-accent-9: oklch(0.62 0.21 195);
|
|
70
|
+
/* ...override remaining steps for dark mode */
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For a quick swap without redoing the full scale, only override step 9 (background) and step 11 (foreground). Other steps will still reference the original chroma — visually mismatched but functional.
|
|
75
|
+
|
|
76
|
+
### Shape presets (`[data-shape]`)
|
|
77
|
+
|
|
78
|
+
The simplest way to change roundness for the whole UI is to set a `data-shape` attribute on the document (or any subtree). Three presets ship by default — `sharp`, `slightly-rounded` (the default if no attribute), and `rounded`. Pill shapes (Badge, Switch, Slider, Avatar circle) stay pill in every preset.
|
|
79
|
+
|
|
80
|
+
```html
|
|
81
|
+
<!-- Whole-app, sharp/technical feel -->
|
|
82
|
+
<html data-shape="sharp">
|
|
83
|
+
|
|
84
|
+
<!-- Whole-app, soft/consumer feel -->
|
|
85
|
+
<html data-shape="rounded">
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
You can scope it to a subtree if a particular section wants different shape language than the rest:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<div data-shape="sharp">
|
|
92
|
+
<DeveloperConsole />
|
|
93
|
+
</div>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Visual feel:
|
|
97
|
+
|
|
98
|
+
| Preset | Identity | Comparable to |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| `sharp` | Technical, precise, "serious software" | Vercel, Linear, terminal UIs |
|
|
101
|
+
| `slightly-rounded` (default) | Modern SaaS neutral | shadcn default, Stripe, Notion sidebar |
|
|
102
|
+
| `rounded` | Friendly, soft, consumer | iOS, Notion content, modern startup landings |
|
|
103
|
+
|
|
104
|
+
### Custom radius — override a role token
|
|
105
|
+
|
|
106
|
+
If a preset doesn't fit, you can override any semantic radius role token directly. Components reference these role tokens (not the primitive scale), so a single override propagates everywhere.
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
/* Tighten controls only; leave overlays / surfaces alone */
|
|
110
|
+
:root {
|
|
111
|
+
--radius-control: 4px;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Or scoped to a subtree */
|
|
115
|
+
.checkout {
|
|
116
|
+
--radius-control: 8px;
|
|
117
|
+
--radius-surface: 20px;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The role tokens (defaults shown — the "slightly-rounded" preset):
|
|
122
|
+
|
|
123
|
+
| Token | Default | Used by |
|
|
124
|
+
|--------------------------|---------|---------|
|
|
125
|
+
| `--radius-control` | 6px | Button, Input, Select, Tabs trigger, Toggle, Code block |
|
|
126
|
+
| `--radius-control-inner` | 2px | Checkbox box, ±/close buttons, inline Code |
|
|
127
|
+
| `--radius-surface` | 10px | Card, Alert, Accordion |
|
|
128
|
+
| `--radius-overlay-sm` | 6px | Tooltip, Toast |
|
|
129
|
+
| `--radius-overlay` | 10px | Popover, HoverCard, DropdownMenu / ContextMenu / Menubar content, listboxes |
|
|
130
|
+
| `--radius-overlay-lg` | 16px | Dialog, AlertDialog, Sheet, BottomSheet, ColorInput picker |
|
|
131
|
+
| `--radius-pill` | 9999px | Badge, StatusDot, Radio, Switch, Slider, Progress, Avatar circle |
|
|
132
|
+
| `--radius-bubble` | 24px | ChatMessage bubble |
|
|
133
|
+
|
|
134
|
+
### Build your own preset
|
|
135
|
+
|
|
136
|
+
Define your own `[data-shape="…"]` block and swap to it whenever you want:
|
|
137
|
+
|
|
138
|
+
```css
|
|
139
|
+
[data-shape="brand-soft"] {
|
|
140
|
+
--radius-control: 8px;
|
|
141
|
+
--radius-control-inner: 3px;
|
|
142
|
+
--radius-surface: 14px;
|
|
143
|
+
--radius-overlay-sm: 8px;
|
|
144
|
+
--radius-overlay: 14px;
|
|
145
|
+
--radius-overlay-lg: 20px;
|
|
146
|
+
--radius-pill: 9999px;
|
|
147
|
+
--radius-bubble: 28px;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```html
|
|
152
|
+
<html data-shape="brand-soft">
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Change the primitive radius scale (advanced)
|
|
156
|
+
|
|
157
|
+
If you're rebuilding the entire system rather than just rebranding, you can also override the primitive scale that the role tokens reference:
|
|
158
|
+
|
|
159
|
+
```css
|
|
160
|
+
@theme {
|
|
161
|
+
--radius-ds-sm: 0.25rem;
|
|
162
|
+
--radius-ds-md: 0.5rem;
|
|
163
|
+
--radius-ds-lg: 0.75rem;
|
|
164
|
+
--radius-ds-xl: 1rem;
|
|
165
|
+
--radius: 0.5rem; /* unsuffixed — generates bare `rounded` */
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Most consumers should NOT touch this — overriding the role tokens above is the cleaner path.
|
|
170
|
+
|
|
171
|
+
### Change fonts
|
|
172
|
+
|
|
173
|
+
The design system uses three font families, each backed by a CSS variable:
|
|
174
|
+
|
|
175
|
+
- `--font-sans` — Inter (body)
|
|
176
|
+
- `--font-display` — Ranade (headings)
|
|
177
|
+
- `--font-mono` — JetBrains Mono (code)
|
|
178
|
+
|
|
179
|
+
To swap with `next/font`:
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
// app/layout.tsx (Next.js App Router)
|
|
183
|
+
import { Inter, Plus_Jakarta_Sans, JetBrains_Mono } from "next/font/google";
|
|
184
|
+
|
|
185
|
+
const fontSans = Plus_Jakarta_Sans({ subsets: ["latin"], variable: "--font-sans" });
|
|
186
|
+
const fontDisplay = Plus_Jakarta_Sans({ subsets: ["latin"], weight: "700", variable: "--font-display" });
|
|
187
|
+
const fontMono = JetBrains_Mono({ subsets: ["latin"], variable: "--font-mono" });
|
|
188
|
+
|
|
189
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
190
|
+
return (
|
|
191
|
+
<html lang="en" className={`${fontSans.variable} ${fontDisplay.variable} ${fontMono.variable}`}>
|
|
192
|
+
<body>{children}</body>
|
|
193
|
+
</html>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
For Vite/Remix/Astro/TanStack, drop the `@font-face` declarations into the global CSS and override the variables:
|
|
199
|
+
|
|
200
|
+
```css
|
|
201
|
+
@font-face {
|
|
202
|
+
font-family: "Plus Jakarta Sans";
|
|
203
|
+
src: url("/fonts/PlusJakartaSans-Variable.woff2") format("woff2");
|
|
204
|
+
font-weight: 100 900;
|
|
205
|
+
font-display: swap;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
@theme {
|
|
209
|
+
--font-sans: "Plus Jakarta Sans", system-ui, sans-serif;
|
|
210
|
+
--font-display: "Plus Jakarta Sans", system-ui, sans-serif;
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Change the spacing scale
|
|
215
|
+
|
|
216
|
+
The DS spacing scale runs `--spacing-ds-00` (0) to `--spacing-ds-12` (highest). Each step roughly doubles. The Tailwind classes are `p-ds-04`, `m-ds-08`, `gap-ds-03`, etc.
|
|
217
|
+
|
|
218
|
+
```css
|
|
219
|
+
@theme {
|
|
220
|
+
--spacing-ds-00: 0;
|
|
221
|
+
--spacing-ds-01: 0.125rem;
|
|
222
|
+
--spacing-ds-02: 0.25rem;
|
|
223
|
+
--spacing-ds-03: 0.5rem;
|
|
224
|
+
--spacing-ds-04: 0.75rem;
|
|
225
|
+
--spacing-ds-05: 1rem;
|
|
226
|
+
/* etc. */
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Most consumers should not touch this. The DS scale is tuned for the typography rhythm; changing one step without re-tuning typography looks visually off.
|
|
231
|
+
|
|
232
|
+
### Change a single shadow
|
|
233
|
+
|
|
234
|
+
```css
|
|
235
|
+
@theme {
|
|
236
|
+
--shadow-raised: 0 1px 2px oklch(0 0 0 / 0.06), 0 2px 4px oklch(0 0 0 / 0.04);
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Available shadows: `--shadow-raised`, `--shadow-overlay`, `--shadow-floating`, `--shadow-brand`. Each is a multi-layer composite — overriding one without considering its layers usually produces flat-looking shadows.
|
|
241
|
+
|
|
242
|
+
## Light + dark in lockstep
|
|
243
|
+
|
|
244
|
+
Every override should consider both modes. Pattern:
|
|
245
|
+
|
|
246
|
+
```css
|
|
247
|
+
@theme {
|
|
248
|
+
--color-accent-9: oklch(0.54 0.22 195);
|
|
249
|
+
--color-accent-fg: oklch(0.99 0 0);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* Dark mode override */
|
|
253
|
+
.dark {
|
|
254
|
+
--color-accent-9: oklch(0.62 0.21 195);
|
|
255
|
+
--color-accent-fg: oklch(0.10 0 0);
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
`.dark` is a regular class selector — its specificity is higher than `:root`/`@theme` body, so dark-mode overrides win when the class is active.
|
|
260
|
+
|
|
261
|
+
## Forced colors (Windows high-contrast)
|
|
262
|
+
|
|
263
|
+
If you override semantic colors, the `@media (forced-colors: active)` block in `semantic.css` continues to remap to system keywords. Your override is ignored when the user is in high-contrast mode — this is the correct behavior.
|
|
264
|
+
|
|
265
|
+
If you need a custom forced-colors mapping, override inside `@media (forced-colors: active)`:
|
|
266
|
+
|
|
267
|
+
```css
|
|
268
|
+
@media (forced-colors: active) {
|
|
269
|
+
:root {
|
|
270
|
+
--color-accent-9: Highlight;
|
|
271
|
+
--color-accent-fg: HighlightText;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Per-route theming
|
|
277
|
+
|
|
278
|
+
Apply a class on a wrapper element to scope token overrides:
|
|
279
|
+
|
|
280
|
+
```css
|
|
281
|
+
.theme-karm {
|
|
282
|
+
--color-accent-9: oklch(0.55 0.22 195);
|
|
283
|
+
}
|
|
284
|
+
.theme-karm.dark,
|
|
285
|
+
.dark .theme-karm {
|
|
286
|
+
--color-accent-9: oklch(0.62 0.21 195);
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Then:
|
|
291
|
+
|
|
292
|
+
```tsx
|
|
293
|
+
<div className="theme-karm">
|
|
294
|
+
<Button>Karm-themed</Button>
|
|
295
|
+
</div>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## What you cannot override via CSS variables
|
|
299
|
+
|
|
300
|
+
- The component DOM structure (use the `asChild` pattern or wrap the component to insert)
|
|
301
|
+
- The vendored Radix primitives' behavior
|
|
302
|
+
- Animation keyframes (override the `--animate-*` references via `@theme` — but the keyframe definitions themselves are package-private)
|
|
303
|
+
|
|
304
|
+
For deeper changes, fork the source or use the `className` prop with arbitrary Tailwind utilities to layer styling on top.
|
|
305
|
+
|
|
306
|
+
## Verifying an override
|
|
307
|
+
|
|
308
|
+
Open DevTools, inspect a component, and check the Computed tab for the variable's resolved value. The cascade origin column shows where the value came from — your override should appear there, not the package's default.
|
|
309
|
+
|
|
310
|
+
If the override isn't winning, check:
|
|
311
|
+
|
|
312
|
+
1. The `@theme` override comes AFTER `@import "@devalok/shilp-sutra/css";` in source order
|
|
313
|
+
2. There's no `!important` in the package overriding you (there isn't — file an issue if you find one)
|
|
314
|
+
3. The selector specificity matches the target (`.dark` class is on a parent of the inspected element, etc.)
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
<!-- Source: packages/core/docs/recipes/server-components.md — do not edit directly. Regenerate with `node scripts/build-skill.mjs`. -->
|
|
2
|
+
|
|
3
|
+
# Server vs Client Components
|
|
4
|
+
|
|
5
|
+
Reference for using `@devalok/shilp-sutra` correctly inside React Server Components (Next.js App Router, TanStack Start, Remix v3+, Astro, future RSC frameworks).
|
|
6
|
+
|
|
7
|
+
## TL;DR
|
|
8
|
+
|
|
9
|
+
- **Always use per-component imports** (`@devalok/shilp-sutra/ui/button`, NOT `@devalok/shilp-sutra/ui`) — barrels drag in client-only siblings and trip the RSC barrel-import error.
|
|
10
|
+
- **Importing a client component into a Server Component is fine.** The client component renders as a client island at that point. The Server Component shell stays server-rendered.
|
|
11
|
+
- **What actually breaks RSC**, in order of frequency: (a) calling a client hook in a server file; (b) passing functions or class instances as props from server → client; (c) reading `window`/`document` in a server module's top-level body.
|
|
12
|
+
- The matrix below tells you which components have NO `"use client"` (so they SSR without hydration cost) vs. which become client islands (still importable, just hydrate).
|
|
13
|
+
|
|
14
|
+
## RSC-safety matrix
|
|
15
|
+
|
|
16
|
+
The list is generated from the `// @server-safe` source annotation. Components without the annotation get `"use client"` injected at build time and ship as client islands.
|
|
17
|
+
|
|
18
|
+
### `@devalok/shilp-sutra/ui`
|
|
19
|
+
|
|
20
|
+
| Server-safe (renders without hydration) | Everything else |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `Text` | All other UI primitives become client islands when rendered |
|
|
23
|
+
| `Stack` | |
|
|
24
|
+
| `Container` | |
|
|
25
|
+
| `Skeleton` | |
|
|
26
|
+
| `Table` (and child components: `TableHeader`, `TableRow`, `TableCell`) | |
|
|
27
|
+
| `Code` | |
|
|
28
|
+
| `VisuallyHidden` | |
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
// ✅ Server Component — Text/Stack/Container/etc. SSR with zero hydration cost
|
|
32
|
+
import { Text } from "@devalok/shilp-sutra/ui/text";
|
|
33
|
+
import { Stack } from "@devalok/shilp-sutra/ui/stack";
|
|
34
|
+
|
|
35
|
+
export default function ServerPage() {
|
|
36
|
+
return (
|
|
37
|
+
<Stack className="p-ds-08">
|
|
38
|
+
<Text variant="heading-2xl">Server-rendered</Text>
|
|
39
|
+
</Stack>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
// ✅ Also fine — Button is a client component, but importing one into a Server
|
|
46
|
+
// Component just creates a client island at that boundary. No wrapper needed.
|
|
47
|
+
import { Button } from "@devalok/shilp-sutra/ui/button";
|
|
48
|
+
|
|
49
|
+
export default function ServerPage() {
|
|
50
|
+
return <Button>Click</Button>;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// ❌ NOT fine — passing a function as a prop from server → client.
|
|
56
|
+
// Functions are not serializable across the RSC boundary.
|
|
57
|
+
import { Button } from "@devalok/shilp-sutra/ui/button";
|
|
58
|
+
|
|
59
|
+
export default function ServerPage() {
|
|
60
|
+
return <Button onClick={() => console.log("hi")}>Click</Button>;
|
|
61
|
+
// ^^^^^^^ — define handler inside a "use client" wrapper instead
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
When you need an event handler, define it inside a client component:
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
// app/components/MyButton.tsx
|
|
69
|
+
"use client";
|
|
70
|
+
import { Button } from "@devalok/shilp-sutra/ui/button";
|
|
71
|
+
|
|
72
|
+
export function MyButton() {
|
|
73
|
+
return <Button onClick={() => console.log("hi")}>Click</Button>;
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `@devalok/shilp-sutra/composed`
|
|
78
|
+
|
|
79
|
+
| Server-safe (renders without hydration) | Everything else |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `ContentCard` | All other composed components become client islands when rendered |
|
|
82
|
+
| `PageHeader` | |
|
|
83
|
+
| `LoadingSkeleton` | |
|
|
84
|
+
| `PageSkeletons` | |
|
|
85
|
+
|
|
86
|
+
### `@devalok/shilp-sutra/shell`
|
|
87
|
+
|
|
88
|
+
All shell components are client islands. They manage state (open/close, active route, viewport detection) and require hydration.
|
|
89
|
+
|
|
90
|
+
### `@devalok/shilp-sutra/ai`
|
|
91
|
+
|
|
92
|
+
All AI components are client islands. They manage conversation state, streaming responses, and command bar focus.
|
|
93
|
+
|
|
94
|
+
### `@devalok/shilp-sutra/hooks`
|
|
95
|
+
|
|
96
|
+
All hooks (`useColorMode`, `useIsMobile`, etc.) are client-only by definition (React hooks).
|
|
97
|
+
|
|
98
|
+
### `@devalok/shilp-sutra/utils`, `/ui/lib/utils`, `/ui/lib/motion`, `/ui/lib/date-utils`
|
|
99
|
+
|
|
100
|
+
Pure functions. Server-safe.
|
|
101
|
+
|
|
102
|
+
## Why barrel imports break RSC
|
|
103
|
+
|
|
104
|
+
The barrel re-exports every component in a layer. When a Server Component imports anything from `@devalok/shilp-sutra/ui`, the bundler walks the barrel and pulls in code from sibling components. If any sibling has `"use client"`, the bundler complains:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
You're importing a component that needs useState.
|
|
108
|
+
It only works in a Client Component.
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Per-component imports avoid this — the bundler only walks the imported file's module graph.
|
|
112
|
+
|
|
113
|
+
This is also why **per-component imports tree-shake better** even in non-RSC frameworks. They're the recommended pattern everywhere.
|
|
114
|
+
|
|
115
|
+
## "use client" propagation
|
|
116
|
+
|
|
117
|
+
A component is server-safe only if:
|
|
118
|
+
|
|
119
|
+
1. It has no `"use client"` directive at the top of its source file
|
|
120
|
+
2. None of its imports have `"use client"` either (transitively)
|
|
121
|
+
|
|
122
|
+
We mark sources `// @server-safe` and a build-time check verifies the import graph stays clean. The `"use client"` directive is injected automatically during the build for components without that annotation.
|
|
123
|
+
|
|
124
|
+
If you fork the source and remove `"use client"` from a component that uses `useState`, the build will still inject it back unless you also remove the React-hook usage. Don't fight the system — wrap in a client component instead.
|
|
125
|
+
|
|
126
|
+
## Streaming and Suspense
|
|
127
|
+
|
|
128
|
+
All shilp-sutra components SSR cleanly. They have no client-only side effects at module top-level — no `window.*`, `document.*`, or `localStorage.*` access during render. Side effects happen in `useEffect`, which runs after hydration.
|
|
129
|
+
|
|
130
|
+
Use `<Suspense>` boundaries normally:
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { Suspense } from "react";
|
|
134
|
+
import { LoadingSkeleton } from "@devalok/shilp-sutra/composed/loading-skeleton";
|
|
135
|
+
|
|
136
|
+
export default function Page() {
|
|
137
|
+
return (
|
|
138
|
+
<Suspense fallback={<LoadingSkeleton variant="page" />}>
|
|
139
|
+
<ClientHeavyComponent />
|
|
140
|
+
</Suspense>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Both `<Suspense>` and `<LoadingSkeleton>` are server-safe.
|
|
146
|
+
|
|
147
|
+
## Common RSC mistakes
|
|
148
|
+
|
|
149
|
+
### Mistake 1: Calling a client hook in a Server Component
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
// ❌ — useColorMode is a React hook; hooks only run in client components
|
|
153
|
+
import { useColorMode } from "@devalok/shilp-sutra/hooks/use-color-mode";
|
|
154
|
+
|
|
155
|
+
export default function ServerPage() {
|
|
156
|
+
const { mode } = useColorMode(); // breaks
|
|
157
|
+
return <div>{mode}</div>;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Fix: use the hook inside a `"use client"` component.
|
|
162
|
+
|
|
163
|
+
### Mistake 2: Reading `window.*` in a server module's top level
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
// ❌ — window is undefined on the server
|
|
167
|
+
const w = window.innerWidth;
|
|
168
|
+
|
|
169
|
+
export default function ServerPage() {
|
|
170
|
+
return <p>{w}px</p>;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Fix: read inside a `useEffect` of a client component, or use `useIsMobile` in a client wrapper.
|
|
175
|
+
|
|
176
|
+
### Mistake 3: Passing functions as props from a Server Component to a client island
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
// ❌ — function props are not serializable across the RSC boundary
|
|
180
|
+
import { Button } from "@devalok/shilp-sutra/ui/button";
|
|
181
|
+
|
|
182
|
+
export default function ServerPage() {
|
|
183
|
+
return <Button onClick={() => console.log("hi")}>Click</Button>;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Fix: define the handler inside the client island, or use a Server Action and pass the action reference (Server Actions ARE serializable).
|
|
188
|
+
|
|
189
|
+
### Mistake 4: Barrel-importing into a Server Component
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
// ❌ — pulls every UI primitive's module graph into the server file,
|
|
193
|
+
// and any sibling with "use client" trips the bundler error.
|
|
194
|
+
import { Text } from "@devalok/shilp-sutra/ui";
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Fix: per-component import.
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
// ✅
|
|
201
|
+
import { Text } from "@devalok/shilp-sutra/ui/text";
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## When in doubt
|
|
205
|
+
|
|
206
|
+
If you're unsure whether a component is server-safe, look at the source:
|
|
207
|
+
|
|
208
|
+
- `packages/core/src/ui/<name>.tsx` — top of file. The `// @server-safe` annotation marks components that ship without `"use client"`.
|
|
209
|
+
- `packages/core/src/composed/<name>/index.tsx` — same.
|
|
210
|
+
|
|
211
|
+
The matrix in this file is the authoritative public list. If you find a discrepancy, file an issue.
|