@devalok/shilp-sutra 0.50.0 → 0.52.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 +1 -1
- package/MIGRATION.md +12 -0
- package/dist/tokens/semantic.css +20 -1
- package/dist/ui/button-group.js +2 -0
- package/dist/ui/button-group.js.map +1 -1
- package/dist/ui/button-processing.d.ts.map +1 -1
- package/dist/ui/button-processing.js +1 -0
- package/dist/ui/button-processing.js.map +1 -1
- package/dist/ui/button.d.ts +3 -3
- package/dist/ui/button.d.ts.map +1 -1
- package/dist/ui/button.js +26 -0
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.d.ts +5 -4
- package/dist/ui/card.d.ts.map +1 -1
- package/dist/ui/card.js +1 -1
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/color-input.d.ts.map +1 -1
- package/dist/ui/color-input.js +82 -82
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/icon.d.ts +2 -0
- package/dist/ui/icon.d.ts.map +1 -1
- package/dist/ui/icon.js +31 -26
- package/dist/ui/icon.js.map +1 -1
- package/dist/ui/search-input.d.ts.map +1 -1
- package/dist/ui/search-input.js +1 -0
- package/dist/ui/search-input.js.map +1 -1
- package/dist/ui/segmented-control.d.ts +28 -6
- package/dist/ui/segmented-control.d.ts.map +1 -1
- package/dist/ui/segmented-control.js +61 -43
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/split-button.d.ts.map +1 -1
- package/dist/ui/split-button.js +7 -0
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.d.ts +3 -3
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js.map +1 -1
- package/docs/components/ui/button.md +2 -2
- package/docs/components/ui/segmented-control.md +31 -11
- package/docs/components/ui/stat-card.md +1 -1
- package/docs/recipes/install-remix.md +3 -3
- package/docs/recipes/install-vite.md +3 -3
- package/docs/recipes/server-components.md +2 -2
- package/llms.txt +1 -1
- package/make-kit/components/card.md +4 -4
- package/make-kit/foundations/color.md +20 -0
- package/make-kit/foundations/dark-mode.md +6 -9
- package/make-kit/foundations/icons.md +3 -3
- package/make-kit/setup.md +4 -4
- package/mcp-manifest.json +62 -11
- package/package.json +1 -1
- package/scripts/welcome.mjs +59 -1
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +1 -1
- package/skill/references/server-components.md +2 -2
- package/skill/references/setup-remix.md +3 -3
- package/skill/references/setup-vite.md +3 -3
|
@@ -17,7 +17,7 @@ import { Icon } from '@devalok/shilp-sutra/ui/icon'
|
|
|
17
17
|
import { IconHome, IconUser, IconSettings } from '@tabler/icons-react'
|
|
18
18
|
|
|
19
19
|
<Icon icon={IconHome} />
|
|
20
|
-
<Icon icon={IconUser} size=
|
|
20
|
+
<Icon icon={IconUser} size="lg" />
|
|
21
21
|
<Icon icon={IconSettings} className="text-fg-muted" />
|
|
22
22
|
```
|
|
23
23
|
|
|
@@ -55,7 +55,7 @@ Don't add `className="h-4 w-4"` on every Icon. Wrap a subtree:
|
|
|
55
55
|
```tsx
|
|
56
56
|
import { IconProvider } from '@devalok/shilp-sutra/ui/icon-context'
|
|
57
57
|
|
|
58
|
-
<IconProvider size=
|
|
58
|
+
<IconProvider size="sm">
|
|
59
59
|
<NavSection>
|
|
60
60
|
<Icon icon={IconHome} />
|
|
61
61
|
<Icon icon={IconUser} />
|
|
@@ -64,7 +64,7 @@ import { IconProvider } from '@devalok/shilp-sutra/ui/icon-context'
|
|
|
64
64
|
</IconProvider>
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
Override per-icon with `<Icon icon={...} size=
|
|
67
|
+
Override per-icon with `<Icon icon={...} size="xl" />`.
|
|
68
68
|
|
|
69
69
|
Default sizes by component context:
|
|
70
70
|
|
package/make-kit/setup.md
CHANGED
|
@@ -53,7 +53,7 @@ import { IconProvider } from '@devalok/shilp-sutra/ui/icon-context'
|
|
|
53
53
|
export default function App({ children }) {
|
|
54
54
|
return (
|
|
55
55
|
<MotionProvider reducedMotion="user">
|
|
56
|
-
<IconProvider size=
|
|
56
|
+
<IconProvider size="sm">
|
|
57
57
|
{children}
|
|
58
58
|
<Toaster />
|
|
59
59
|
</IconProvider>
|
|
@@ -63,7 +63,7 @@ export default function App({ children }) {
|
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
- `MotionProvider` — required. `reducedMotion="user"` respects OS preference. Without this provider, motion primitives still work but reduced-motion is ignored.
|
|
66
|
-
- `IconProvider` — optional but recommended. Sets default icon size for all `<Icon>` children. Override per-call with `<Icon size=
|
|
66
|
+
- `IconProvider` — optional but recommended. Sets default icon size for all `<Icon>` children. Size is a tier (`"xs" | "sm" | "md" | "lg" | "xl" | "2xl"`), not a pixel number. Override per-call with `<Icon size="lg" />`.
|
|
67
67
|
- `Toaster` — only needed if the app calls `toast(...)`. Mount exactly once.
|
|
68
68
|
|
|
69
69
|
## Dark mode toggle
|
|
@@ -74,9 +74,9 @@ Add the `.dark` class on `<html>` or `<body>` to flip the entire token system to
|
|
|
74
74
|
import { useColorMode } from '@devalok/shilp-sutra/hooks/use-color-mode'
|
|
75
75
|
|
|
76
76
|
function ThemeToggle() {
|
|
77
|
-
const {
|
|
77
|
+
const { colorMode, setColorMode } = useColorMode() // 'light' | 'dark' | 'system'
|
|
78
78
|
return (
|
|
79
|
-
<Button onClick={() =>
|
|
79
|
+
<Button onClick={() => setColorMode(colorMode === 'dark' ? 'light' : 'dark')}>
|
|
80
80
|
Toggle theme
|
|
81
81
|
</Button>
|
|
82
82
|
)
|
package/mcp-manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "./mcp-manifest.schema.json",
|
|
3
3
|
"manifestVersion": "1.2.0",
|
|
4
4
|
"package": "@devalok/shilp-sutra",
|
|
5
|
-
"packageVersion": "0.
|
|
5
|
+
"packageVersion": "0.52.0",
|
|
6
6
|
"components": {
|
|
7
7
|
"accordion": {
|
|
8
8
|
"displayName": "Accordion",
|
|
@@ -1192,6 +1192,7 @@
|
|
|
1192
1192
|
"error",
|
|
1193
1193
|
"success",
|
|
1194
1194
|
"warning",
|
|
1195
|
+
"info",
|
|
1195
1196
|
"neutral"
|
|
1196
1197
|
]
|
|
1197
1198
|
},
|
|
@@ -1302,6 +1303,7 @@
|
|
|
1302
1303
|
"error",
|
|
1303
1304
|
"success",
|
|
1304
1305
|
"warning",
|
|
1306
|
+
"info",
|
|
1305
1307
|
"neutral"
|
|
1306
1308
|
]
|
|
1307
1309
|
},
|
|
@@ -5250,7 +5252,7 @@
|
|
|
5250
5252
|
"type": {
|
|
5251
5253
|
"name": "enum",
|
|
5252
5254
|
"value": [
|
|
5253
|
-
"
|
|
5255
|
+
"soft",
|
|
5254
5256
|
"solid"
|
|
5255
5257
|
]
|
|
5256
5258
|
},
|
|
@@ -5263,16 +5265,24 @@
|
|
|
5263
5265
|
},
|
|
5264
5266
|
"required": true
|
|
5265
5267
|
},
|
|
5266
|
-
"
|
|
5268
|
+
"value": {
|
|
5267
5269
|
"type": {
|
|
5268
|
-
"name": "
|
|
5270
|
+
"name": "object",
|
|
5271
|
+
"raw": "string // controlled"
|
|
5269
5272
|
},
|
|
5270
|
-
"required":
|
|
5273
|
+
"required": false
|
|
5271
5274
|
},
|
|
5272
|
-
"
|
|
5275
|
+
"defaultValue": {
|
|
5276
|
+
"type": {
|
|
5277
|
+
"name": "object",
|
|
5278
|
+
"raw": "string // uncontrolled initial"
|
|
5279
|
+
},
|
|
5280
|
+
"required": false
|
|
5281
|
+
},
|
|
5282
|
+
"onValueChange": {
|
|
5273
5283
|
"type": {
|
|
5274
5284
|
"name": "function",
|
|
5275
|
-
"raw": "(id: string) => void
|
|
5285
|
+
"raw": "(id: string) => void"
|
|
5276
5286
|
},
|
|
5277
5287
|
"required": false
|
|
5278
5288
|
},
|
|
@@ -5281,6 +5291,26 @@
|
|
|
5281
5291
|
"name": "boolean"
|
|
5282
5292
|
},
|
|
5283
5293
|
"required": false
|
|
5294
|
+
},
|
|
5295
|
+
"fullWidth": {
|
|
5296
|
+
"type": {
|
|
5297
|
+
"name": "boolean"
|
|
5298
|
+
},
|
|
5299
|
+
"required": false
|
|
5300
|
+
},
|
|
5301
|
+
"selectedId": {
|
|
5302
|
+
"type": {
|
|
5303
|
+
"name": "object",
|
|
5304
|
+
"raw": "string // @deprecated — use value"
|
|
5305
|
+
},
|
|
5306
|
+
"required": false
|
|
5307
|
+
},
|
|
5308
|
+
"onSelect": {
|
|
5309
|
+
"type": {
|
|
5310
|
+
"name": "function",
|
|
5311
|
+
"raw": "(id: string) => void // @deprecated — use onValueChange"
|
|
5312
|
+
},
|
|
5313
|
+
"required": false
|
|
5284
5314
|
}
|
|
5285
5315
|
},
|
|
5286
5316
|
"composition": {
|
|
@@ -5288,20 +5318,29 @@
|
|
|
5288
5318
|
"**Data-driven, not compound** — unlike Tabs/ToggleGroup, SegmentedControl takes an `options` array rather than children. This makes it easier to render from a list but harder to customize per-option styling; use Tabs if you need compound children.",
|
|
5289
5319
|
"**When to use vs Tabs:** SegmentedControl is for mutually-exclusive VIEW-MODE toggles (List/Grid/Kanban) — short labels, no associated content panel. Tabs is for content switching where each tab has a corresponding TabsContent. SegmentedControl renders `role=\"radiogroup\"` with `role=\"radio\"` segments (a panel-less single-select); Tabs renders `role=\"tablist\"`.",
|
|
5290
5320
|
"**Option icons** auto-size based on the `size` prop — don't set explicit icon sizes.",
|
|
5291
|
-
"
|
|
5321
|
+
"**`fullWidth`** switches segments from content-hug (default) to equal-fill: each segment takes an equal share of the container (a 2-item toggle splits 50/50, a 3-item switcher gives each a third). Use for view switchers and toolbar toggles that should fill their column; leave off for compact inline toolbars.",
|
|
5322
|
+
"**Visual model:** a rounded-rect track (not a full pill) — a translucent recessed groove with a single soft-shadowed sliding thumb. The track has no border/inset shadow; the thumb carries the only edge. Elevation inverts in dark so the groove stays visible.",
|
|
5323
|
+
"**Controlled or uncontrolled** — pass `value` + `onValueChange` to control it, or `defaultValue` (optional; falls back to the first option) to let it own state. Matches the Tabs/ToggleGroup vocabulary. `selectedId`/`onSelect` are deprecated aliases that still work.",
|
|
5324
|
+
"**Option labels accept `ReactNode`** — a segment can hold a count badge or custom node, not just a string. `text` is optional: omit it for an **icon-only** segment and set `ariaLabel` so the segment still has an accessible name.",
|
|
5325
|
+
"**Touch targets** — each segment has a 44px minimum hit area (via `touch-target`) even though the visual height stays dense.",
|
|
5326
|
+
"**RTL** — Arrow-key navigation tracks reading order: in a right-to-left context `ArrowLeft` moves to the next option and `ArrowRight` to the previous (detected from the nearest `dir` attribute).",
|
|
5292
5327
|
"Built from scratch (no Radix primitive) — standard HTML buttons with `role=\"radio\"` + `aria-checked` and roving tabindex."
|
|
5293
5328
|
]
|
|
5294
5329
|
},
|
|
5295
5330
|
"docPath": "docs/components/ui/segmented-control.md",
|
|
5296
5331
|
"examples": [
|
|
5297
|
-
"<SegmentedControl\n size=\"md\"\n variant=\"
|
|
5332
|
+
"<SegmentedControl\n size=\"md\"\n variant=\"soft\"\n options={[\n { id: 'list', text: 'List' },\n { id: 'grid', text: 'Grid' },\n ]}\n value={viewMode}\n onValueChange={setViewMode}\n/>"
|
|
5298
5333
|
],
|
|
5299
5334
|
"gotchas": [
|
|
5300
|
-
"Controlled
|
|
5335
|
+
"Controlled (`value`) or uncontrolled (`defaultValue`) — `selectedId`/`onSelect` are deprecated aliases",
|
|
5301
5336
|
"Uses data-driven API (options prop), not compound children",
|
|
5302
5337
|
"Use Tabs (not SegmentedControl) when you need associated content panels per option"
|
|
5303
5338
|
],
|
|
5304
5339
|
"changes": [
|
|
5340
|
+
{
|
|
5341
|
+
"version": "0.52.0",
|
|
5342
|
+
"summary": "**Changed** Visual rebuild — rounded-rect track (was full pill), translucent recessed track with no border/inset, single ring-less soft-shadow thumb. Dark-mode elevation inverts so the groove stays visible. New tokens: `--color-segment-track`, `--color-segment-thumb`, `--shadow-segment`."
|
|
5343
|
+
},
|
|
5305
5344
|
{
|
|
5306
5345
|
"version": "0.38.0",
|
|
5307
5346
|
"summary": "**Removed** (BREAKING) deprecated `variant=\"accent\"` alias. Use `variant=\"solid\"`."
|
|
@@ -6418,7 +6457,7 @@
|
|
|
6418
6457
|
"variant": {
|
|
6419
6458
|
"type": {
|
|
6420
6459
|
"name": "union",
|
|
6421
|
-
"raw": "\"default\" | \"elevated\" | \"outline\" | \"flat\" (default =
|
|
6460
|
+
"raw": "\"default\" | \"elevated\" | \"outline\" | \"flat\" (default = tonal border-card hairline, no shadow; elevated = shadow, no border; outline = strong border, no shadow; flat = filled, no edge) — delegated to Card"
|
|
6422
6461
|
},
|
|
6423
6462
|
"required": false
|
|
6424
6463
|
},
|
|
@@ -13279,6 +13318,14 @@
|
|
|
13279
13318
|
"name": "--color-backdrop",
|
|
13280
13319
|
"value": "Canvas"
|
|
13281
13320
|
},
|
|
13321
|
+
{
|
|
13322
|
+
"name": "--color-segment-track",
|
|
13323
|
+
"value": "color-mix(in oklch, oklch(1 0 0) 7%, transparent)"
|
|
13324
|
+
},
|
|
13325
|
+
{
|
|
13326
|
+
"name": "--color-segment-thumb",
|
|
13327
|
+
"value": "var(--neutral-3)"
|
|
13328
|
+
},
|
|
13282
13329
|
{
|
|
13283
13330
|
"name": "--color-overlay",
|
|
13284
13331
|
"value": "Canvas"
|
|
@@ -13933,6 +13980,10 @@
|
|
|
13933
13980
|
"name": "--shadow-raised-hover",
|
|
13934
13981
|
"value": "var(--shadow-sm-internal)"
|
|
13935
13982
|
},
|
|
13983
|
+
{
|
|
13984
|
+
"name": "--shadow-segment",
|
|
13985
|
+
"value": "0 1px 2px -0.5px oklch(var(--shadow-color) / calc(0.10 * var(--shadow-strength))), 0 3px 8px -2px oklch(var(--shadow-color) / calc(0.09 * var(--shadow-strength)))"
|
|
13986
|
+
},
|
|
13936
13987
|
{
|
|
13937
13988
|
"name": "--shadow-floating",
|
|
13938
13989
|
"value": "var(--shadow-md-internal)"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devalok/shilp-sutra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.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>",
|
package/scripts/welcome.mjs
CHANGED
|
@@ -183,7 +183,7 @@ function buildFullBanner(version, prevVersion) {
|
|
|
183
183
|
lines.push(row(` ${colour('https://shilp-sutra.devalok.in/themer', DIM)}`))
|
|
184
184
|
lines.push(colour(EMPTY, PINK_DIM))
|
|
185
185
|
lines.push(row(` ${colour('▸', PINK)} Wire your AI agent (Claude Code / Cursor / Codex):`))
|
|
186
|
-
lines.push(row(` ${colour('
|
|
186
|
+
lines.push(row(` ${colour('live docs MCP added to .mcp.json — approve it to enable', DIM)}`))
|
|
187
187
|
lines.push(row(` ${colour('(version-exact setup + peer preflight; beats guessing)', DIM)}`))
|
|
188
188
|
lines.push(row(` ${colour('or copy the skill: cp -r node_modules/@devalok/shilp-sutra/skill \\', DIM)}`))
|
|
189
189
|
lines.push(row(` ${colour('~/.claude/skills/shilp-sutra', DIM)}`))
|
|
@@ -215,6 +215,59 @@ function buildCompactBanner(version, prevVersion) {
|
|
|
215
215
|
].join('\n')
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
// ── MCP auto-discovery ───────────────────────────────────────────────────────
|
|
219
|
+
// Write a project-scoped `.mcp.json` pointing at the hosted docs MCP so an AI
|
|
220
|
+
// coding agent DISCOVERS it right after install. This runs even when stdout is
|
|
221
|
+
// piped (unlike the banner) — a config file is not console noise, and the agent
|
|
222
|
+
// that just ran `install` is exactly who should find it. It is never silent-
|
|
223
|
+
// forced: Claude Code (and peers) still PROMPT the user to approve a project
|
|
224
|
+
// MCP server before enabling it. Safety: additive merge (never clobbers other
|
|
225
|
+
// servers or an existing shilp-sutra entry), skips CI and dev installs, honours
|
|
226
|
+
// opt-out, and a write-once sentinel so a user who deletes it is not re-nagged.
|
|
227
|
+
const SEP = process.platform === 'win32' ? '\\' : '/'
|
|
228
|
+
const MCP_URL = 'https://shilp-sutra.devalok.in/mcp'
|
|
229
|
+
|
|
230
|
+
function tryWriteMcpConfig() {
|
|
231
|
+
try {
|
|
232
|
+
if (process.env.SHILP_SUTRA_NO_WELCOME === '1' || process.env.SHILP_SUTRA_NO_WELCOME === 'true') return
|
|
233
|
+
if (process.env.SHILP_SUTRA_NO_MCP === '1' || process.env.SHILP_SUTRA_NO_MCP === 'true') return
|
|
234
|
+
if (process.env.CI) return // writing agent config into a CI checkout is pointless/unwanted
|
|
235
|
+
|
|
236
|
+
const initCwd = process.env.INIT_CWD
|
|
237
|
+
const cwd = process.cwd()
|
|
238
|
+
const isInsideNodeModules = cwd.includes(`${SEP}node_modules${SEP}`) || cwd.includes('/node_modules/')
|
|
239
|
+
if (!isInsideNodeModules) return // dev install inside the DS repo itself
|
|
240
|
+
if (!initCwd || initCwd === cwd) return // no consumer root → unusual context
|
|
241
|
+
|
|
242
|
+
// Write-once-ever sentinel (survives re-installs; respects user deletion of .mcp.json)
|
|
243
|
+
const parts = PKG_DIR.split(/[/\\]/)
|
|
244
|
+
const nmIdx = parts.lastIndexOf('node_modules')
|
|
245
|
+
const sentinel = nmIdx === -1 ? null : join(parts.slice(0, nmIdx + 1).join(SEP), '.shilp-sutra-mcp-written')
|
|
246
|
+
if (sentinel && existsSync(sentinel)) return
|
|
247
|
+
|
|
248
|
+
const target = join(initCwd, '.mcp.json')
|
|
249
|
+
let config = { mcpServers: {} }
|
|
250
|
+
if (existsSync(target)) {
|
|
251
|
+
try {
|
|
252
|
+
config = JSON.parse(readFileSync(target, 'utf-8'))
|
|
253
|
+
} catch {
|
|
254
|
+
return // existing but unparseable — never clobber a hand-authored config
|
|
255
|
+
}
|
|
256
|
+
if (!config || typeof config !== 'object') return
|
|
257
|
+
if (!config.mcpServers || typeof config.mcpServers !== 'object') config.mcpServers = {}
|
|
258
|
+
if (config.mcpServers['shilp-sutra']) {
|
|
259
|
+
if (sentinel) writeFileSync(sentinel, MCP_URL + '\n')
|
|
260
|
+
return // already declared — leave the consumer's version untouched
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
config.mcpServers['shilp-sutra'] = { type: 'http', url: MCP_URL }
|
|
264
|
+
writeFileSync(target, JSON.stringify(config, null, 2) + '\n')
|
|
265
|
+
if (sentinel) writeFileSync(sentinel, MCP_URL + '\n')
|
|
266
|
+
} catch {
|
|
267
|
+
// Never break the consumer install — a failed config write is a no-op.
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
218
271
|
// ── Main ────────────────────────────────────────────────────────────────────
|
|
219
272
|
function main() {
|
|
220
273
|
// --preview / --compact bypass all guards. Used by maintainers + by the
|
|
@@ -223,6 +276,11 @@ function main() {
|
|
|
223
276
|
const preview = process.argv.includes('--preview')
|
|
224
277
|
const forceCompact = process.argv.includes('--compact')
|
|
225
278
|
|
|
279
|
+
// MCP auto-discovery runs regardless of TTY — an agent-run (piped) install is
|
|
280
|
+
// precisely when the agent should discover the docs MCP. Must come before the
|
|
281
|
+
// TTY skip below, which only governs the human-facing banner.
|
|
282
|
+
if (!preview) tryWriteMcpConfig()
|
|
283
|
+
|
|
226
284
|
if (!preview) {
|
|
227
285
|
const skipReason = shouldSkip()
|
|
228
286
|
if (skipReason) return // silent
|
package/skill/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: shilp-sutra
|
|
|
3
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.52.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
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# @devalok/shilp-sutra
|
|
4
4
|
|
|
5
|
-
> Radix UI + Tailwind 4 (CSS-first) + CVA design system for Devalok apps, v0.
|
|
5
|
+
> Radix UI + Tailwind 4 (CSS-first) + CVA design system for Devalok apps, v0.52.0.
|
|
6
6
|
> Built on the same primitives as shadcn/ui but with DIFFERENT prop APIs — never guess from shadcn knowledge; verify every prop.
|
|
7
7
|
> This file is a ROUTER: it tells you what exists and where to get details. Do not look for prop tables here — fetch them per component (MCP tool or per-component doc file below).
|
|
8
8
|
|
|
@@ -153,8 +153,8 @@ Both `<Suspense>` and `<LoadingSkeleton>` are server-safe.
|
|
|
153
153
|
import { useColorMode } from "@devalok/shilp-sutra/hooks/use-color-mode";
|
|
154
154
|
|
|
155
155
|
export default function ServerPage() {
|
|
156
|
-
const {
|
|
157
|
-
return <div>{
|
|
156
|
+
const { colorMode } = useColorMode(); // breaks
|
|
157
|
+
return <div>{colorMode}</div>;
|
|
158
158
|
}
|
|
159
159
|
```
|
|
160
160
|
|
|
@@ -129,10 +129,10 @@ For runtime toggling inside React components, use `useColorMode`:
|
|
|
129
129
|
import { useColorMode } from "@devalok/shilp-sutra/hooks/use-color-mode";
|
|
130
130
|
|
|
131
131
|
export function ThemeToggle() {
|
|
132
|
-
const {
|
|
132
|
+
const { colorMode, toggleColorMode } = useColorMode();
|
|
133
133
|
return (
|
|
134
|
-
<button onClick={
|
|
135
|
-
{
|
|
134
|
+
<button onClick={toggleColorMode} aria-label="Toggle theme">
|
|
135
|
+
{colorMode === "dark" ? "☀" : "☾"}
|
|
136
136
|
</button>
|
|
137
137
|
);
|
|
138
138
|
}
|
|
@@ -123,10 +123,10 @@ Wire the runtime hook from anywhere in the app (e.g., a header button):
|
|
|
123
123
|
import { useColorMode } from "@devalok/shilp-sutra/hooks/use-color-mode";
|
|
124
124
|
|
|
125
125
|
export function ThemeToggle() {
|
|
126
|
-
const {
|
|
126
|
+
const { colorMode, toggleColorMode } = useColorMode();
|
|
127
127
|
return (
|
|
128
|
-
<button onClick={
|
|
129
|
-
{
|
|
128
|
+
<button onClick={toggleColorMode} aria-label="Toggle theme">
|
|
129
|
+
{colorMode === "dark" ? "☀" : "☾"}
|
|
130
130
|
</button>
|
|
131
131
|
);
|
|
132
132
|
}
|