@vegastack/design 0.1.1 → 0.3.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/dist/index.cjs ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ FLOATING: () => FLOATING,
24
+ TIMINGS: () => TIMINGS,
25
+ cn: () => cn
26
+ });
27
+ module.exports = __toCommonJS(src_exports);
28
+ var import_clsx = require("clsx");
29
+ var import_tailwind_merge = require("tailwind-merge");
30
+ var twMerge = (0, import_tailwind_merge.extendTailwindMerge)({
31
+ extend: {
32
+ classGroups: {
33
+ "font-size": [
34
+ {
35
+ text: [
36
+ "h1",
37
+ "h2",
38
+ "h3",
39
+ "h4",
40
+ "label",
41
+ "label-sm",
42
+ "code",
43
+ "code-sm",
44
+ "mono-label",
45
+ "display-sm",
46
+ "display-md",
47
+ "display-lg",
48
+ "display-xl"
49
+ ]
50
+ }
51
+ ]
52
+ }
53
+ }
54
+ });
55
+ function cn(...inputs) {
56
+ return twMerge((0, import_clsx.clsx)(inputs));
57
+ }
58
+ var TIMINGS = {
59
+ /** How long transient success feedback holds before reverting (CopyButton "Copied ✓"). */
60
+ feedbackRevertMs: 1500,
61
+ /** Debounce before auto-persisting a text field (AutoSaveInput). */
62
+ autoSaveDebounceMs: 800,
63
+ /** Hover delay before a rich preview (HoverCard) opens — guards accidental opens. */
64
+ hoverOpenDelayMs: 700,
65
+ /** Hover delay before a rich preview closes — lets the pointer travel into the card. */
66
+ hoverCloseDelayMs: 300
67
+ };
68
+ var FLOATING = {
69
+ sideOffsetAttached: 4,
70
+ sideOffsetDetached: 8,
71
+ collisionPadding: 8
72
+ };
73
+ // Annotate the CommonJS export names for ESM import in node:
74
+ 0 && (module.exports = {
75
+ FLOATING,
76
+ TIMINGS,
77
+ cn
78
+ });
@@ -0,0 +1,56 @@
1
+ import { ClassValue } from 'clsx';
2
+ export { ClassValue } from 'clsx';
3
+
4
+ /**
5
+ * Merges Tailwind CSS class names with intelligent conflict resolution.
6
+ *
7
+ * Combines `clsx` for conditional classes and `tailwind-merge` to handle
8
+ * conflicting Tailwind utilities (e.g., `px-2` and `px-4` → keeps last one).
9
+ *
10
+ * @param inputs - Class names, objects, arrays, or conditional values
11
+ * @returns Merged and deduplicated class string
12
+ *
13
+ * @example
14
+ * cn('px-2 py-1', 'px-4') // 'py-1 px-4'
15
+ * cn('text-foreground', isError && 'text-destructive')
16
+ */
17
+ declare function cn(...inputs: ClassValue[]): string;
18
+
19
+ /**
20
+ * @internal Registry theme-scope plumbing lives at `@vegastack/design/theme-scope`, NOT here.
21
+ * It calls `React.createContext()` at module scope, which is `undefined` under the `react-server`
22
+ * condition — re-exporting it from this entry would make every Server Component that imports
23
+ * `cn` crash on import. This entry stays server-safe by contract (see tsup.config.ts).
24
+ * Product code should use `MarketingSurface` rather than either symbol.
25
+ */
26
+ /**
27
+ * Interaction timing constants (ms) — design decisions, not magic numbers (register P2-14).
28
+ * Single source for every JS-driven delay in the registry; change one value and every
29
+ * component that expresses that role follows.
30
+ */
31
+ declare const TIMINGS: {
32
+ /** How long transient success feedback holds before reverting (CopyButton "Copied ✓"). */
33
+ readonly feedbackRevertMs: 1500;
34
+ /** Debounce before auto-persisting a text field (AutoSaveInput). */
35
+ readonly autoSaveDebounceMs: 800;
36
+ /** Hover delay before a rich preview (HoverCard) opens — guards accidental opens. */
37
+ readonly hoverOpenDelayMs: 700;
38
+ /** Hover delay before a rich preview closes — lets the pointer travel into the card. */
39
+ readonly hoverCloseDelayMs: 300;
40
+ };
41
+ /**
42
+ * Floating-surface positioning constants (px) — the unified sideOffset/collisionPadding
43
+ * pair (register P2-14). Two offset roles, one collision padding:
44
+ * - `sideOffsetAttached` (4): menu-like popups that read as attached to their trigger
45
+ * (dropdown, context menu, select, emoji picker).
46
+ * - `sideOffsetDetached` (8): floating panels that read as detached (popover, hover-card,
47
+ * tooltip).
48
+ * Submenus deliberately use 0 (flush) and are not part of this contract.
49
+ */
50
+ declare const FLOATING: {
51
+ readonly sideOffsetAttached: 4;
52
+ readonly sideOffsetDetached: 8;
53
+ readonly collisionPadding: 8;
54
+ };
55
+
56
+ export { FLOATING, TIMINGS, cn };
package/dist/index.d.ts CHANGED
@@ -16,6 +16,13 @@ export { ClassValue } from 'clsx';
16
16
  */
17
17
  declare function cn(...inputs: ClassValue[]): string;
18
18
 
19
+ /**
20
+ * @internal Registry theme-scope plumbing lives at `@vegastack/design/theme-scope`, NOT here.
21
+ * It calls `React.createContext()` at module scope, which is `undefined` under the `react-server`
22
+ * condition — re-exporting it from this entry would make every Server Component that imports
23
+ * `cn` crash on import. This entry stays server-safe by contract (see tsup.config.ts).
24
+ * Product code should use `MarketingSurface` rather than either symbol.
25
+ */
19
26
  /**
20
27
  * Interaction timing constants (ms) — design decisions, not magic numbers (register P2-14).
21
28
  * Single source for every JS-driven delay in the registry; change one value and every
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/preset.ts
21
+ var preset_exports = {};
22
+ __export(preset_exports, {
23
+ vegastackPreset: () => vegastackPreset
24
+ });
25
+ module.exports = __toCommonJS(preset_exports);
26
+ var vegastackPreset = {
27
+ /** The token package this preset is bound to. */
28
+ tokens: "@vegastack/design-tokens",
29
+ /** CSS entry consumers import to get the full setup. */
30
+ css: "@vegastack/design/preset.css",
31
+ /** Tailwind major version this preset targets. */
32
+ tailwind: 4
33
+ };
34
+ // Annotate the CommonJS export names for ESM import in node:
35
+ 0 && (module.exports = {
36
+ vegastackPreset
37
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `@vegastack/design/preset` — Tailwind v4 setup metadata for VegaStack.
3
+ *
4
+ * Tailwind v4 is CSS-first (no JS `presets` array), so the real "preset" is the
5
+ * shipped `preset.css` (`@import "@vegastack/design/preset.css"`), which
6
+ * wires Tailwind + tw-animate-css + the VegaStack token theme + base reset in one
7
+ * import. This module exposes machine-readable metadata for tooling/agents.
8
+ */
9
+ declare const vegastackPreset: {
10
+ /** The token package this preset is bound to. */
11
+ readonly tokens: "@vegastack/design-tokens";
12
+ /** CSS entry consumers import to get the full setup. */
13
+ readonly css: "@vegastack/design/preset.css";
14
+ /** Tailwind major version this preset targets. */
15
+ readonly tailwind: 4;
16
+ };
17
+ type VegastackPreset = typeof vegastackPreset;
18
+
19
+ export { type VegastackPreset, vegastackPreset };
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ "use client";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/theme-scope.tsx
32
+ var theme_scope_exports = {};
33
+ __export(theme_scope_exports, {
34
+ InternalThemeScopeProvider: () => InternalThemeScopeProvider,
35
+ useInternalThemeScope: () => useInternalThemeScope
36
+ });
37
+ module.exports = __toCommonJS(theme_scope_exports);
38
+ var React = __toESM(require("react"), 1);
39
+ var import_jsx_runtime = require("react/jsx-runtime");
40
+ var InternalThemeScopeContext = React.createContext(
41
+ void 0
42
+ );
43
+ function InternalThemeScopeProvider({
44
+ children,
45
+ scope
46
+ }) {
47
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InternalThemeScopeContext.Provider, { value: scope, children });
48
+ }
49
+ function useInternalThemeScope() {
50
+ return React.useContext(InternalThemeScopeContext);
51
+ }
52
+ // Annotate the CommonJS export names for ESM import in node:
53
+ 0 && (module.exports = {
54
+ InternalThemeScopeProvider,
55
+ useInternalThemeScope
56
+ });
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * Carries a semantic theme-scope class through React's tree, including across
5
+ * portals whose DOM nodes are mounted outside the scoped source subtree.
6
+ *
7
+ * @internal Registry infrastructure only. This is not a consumer-facing
8
+ * theming API; use `MarketingSurface` to establish the supported scope.
9
+ */
10
+ declare function InternalThemeScopeProvider({ children, scope, }: {
11
+ children: React.ReactNode;
12
+ scope: string;
13
+ }): React.JSX.Element;
14
+ /**
15
+ * Reads the nearest semantic theme-scope class so portaled surfaces can apply
16
+ * it to their actual DOM roots instead of falling back to the page theme.
17
+ *
18
+ * @internal Registry infrastructure only. Components outside the canonical
19
+ * overlay implementations must not depend on this hook.
20
+ */
21
+ declare function useInternalThemeScope(): string | undefined;
22
+
23
+ export { InternalThemeScopeProvider, useInternalThemeScope };
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * Carries a semantic theme-scope class through React's tree, including across
5
+ * portals whose DOM nodes are mounted outside the scoped source subtree.
6
+ *
7
+ * @internal Registry infrastructure only. This is not a consumer-facing
8
+ * theming API; use `MarketingSurface` to establish the supported scope.
9
+ */
10
+ declare function InternalThemeScopeProvider({ children, scope, }: {
11
+ children: React.ReactNode;
12
+ scope: string;
13
+ }): React.JSX.Element;
14
+ /**
15
+ * Reads the nearest semantic theme-scope class so portaled surfaces can apply
16
+ * it to their actual DOM roots instead of falling back to the page theme.
17
+ *
18
+ * @internal Registry infrastructure only. Components outside the canonical
19
+ * overlay implementations must not depend on this hook.
20
+ */
21
+ declare function useInternalThemeScope(): string | undefined;
22
+
23
+ export { InternalThemeScopeProvider, useInternalThemeScope };
@@ -0,0 +1,21 @@
1
+ "use client";
2
+
3
+ // src/theme-scope.tsx
4
+ import * as React from "react";
5
+ import { jsx } from "react/jsx-runtime";
6
+ var InternalThemeScopeContext = React.createContext(
7
+ void 0
8
+ );
9
+ function InternalThemeScopeProvider({
10
+ children,
11
+ scope
12
+ }) {
13
+ return /* @__PURE__ */ jsx(InternalThemeScopeContext.Provider, { value: scope, children });
14
+ }
15
+ function useInternalThemeScope() {
16
+ return React.useContext(InternalThemeScopeContext);
17
+ }
18
+ export {
19
+ InternalThemeScopeProvider,
20
+ useInternalThemeScope
21
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vegastack/design",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "VegaStack design system — cn utility, icon runtime, Tailwind v4 preset, and the vegastack-design CLI (tokens ship separately as @vegastack/design-tokens)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,6 +8,9 @@
8
8
  "url": "git+https://github.com/VegaStack/vegastack-design.git",
9
9
  "directory": "packages/design"
10
10
  },
11
+ "engines": {
12
+ "node": ">=24.14.0"
13
+ },
11
14
  "type": "module",
12
15
  "sideEffects": [
13
16
  "**/*.css"
@@ -16,6 +19,7 @@
16
19
  "dist",
17
20
  "bin",
18
21
  "css",
22
+ "skills",
19
23
  "preset.css"
20
24
  ],
21
25
  "bin": {
@@ -24,37 +28,57 @@
24
28
  "exports": {
25
29
  ".": {
26
30
  "types": "./dist/index.d.ts",
27
- "import": "./dist/index.js"
31
+ "import": "./dist/index.js",
32
+ "require": "./dist/index.cjs",
33
+ "default": "./dist/index.js"
28
34
  },
29
35
  "./icons": {
30
36
  "types": "./dist/icons/index.d.ts",
31
- "import": "./dist/icons/index.js"
37
+ "import": "./dist/icons/index.js",
38
+ "require": "./dist/icons/index.cjs",
39
+ "default": "./dist/icons/index.js"
40
+ },
41
+ "./theme-scope": {
42
+ "types": "./dist/theme-scope.d.ts",
43
+ "import": "./dist/theme-scope.js",
44
+ "require": "./dist/theme-scope.cjs",
45
+ "default": "./dist/theme-scope.js"
32
46
  },
33
47
  "./preset": {
34
48
  "types": "./dist/preset.d.ts",
35
- "import": "./dist/preset.js"
49
+ "import": "./dist/preset.js",
50
+ "require": "./dist/preset.cjs",
51
+ "default": "./dist/preset.js"
36
52
  },
37
53
  "./preset.css": "./preset.css",
38
54
  "./theme.css": "./css/theme.css",
39
55
  "./base.css": "./css/base.css",
40
- "./utilities.css": "./css/utilities.css"
56
+ "./utilities.css": "./css/utilities.css",
57
+ "./package.json": "./package.json"
41
58
  },
42
59
  "dependencies": {
43
60
  "clsx": "^2.1.1",
44
- "lucide-react": "^1.24.0",
45
61
  "tailwind-merge": "^3.6.0",
46
- "thesvg": "^3.2.6",
62
+ "tsconfig-paths": "^4.2.0",
47
63
  "tw-animate-css": "^1.4.0",
48
- "@vegastack/design-tokens": "0.1.0"
64
+ "@vegastack/design-tokens": "^0.2.0"
49
65
  },
50
66
  "peerDependencies": {
51
67
  "react": "^19.0.0",
52
68
  "react-dom": "^19.0.0",
69
+ "lucide-react": "^1.24.0",
70
+ "thesvg": "^3.2.6",
53
71
  "tailwindcss": "^4.3.2"
54
72
  },
55
73
  "peerDependenciesMeta": {
56
74
  "tailwindcss": {
57
75
  "optional": true
76
+ },
77
+ "lucide-react": {
78
+ "optional": true
79
+ },
80
+ "thesvg": {
81
+ "optional": true
58
82
  }
59
83
  },
60
84
  "devDependencies": {
@@ -63,23 +87,24 @@
63
87
  "@types/react": "^19.2.17",
64
88
  "@types/react-dom": "^19.2.3",
65
89
  "eslint": "^10.7.0",
66
- "react": "^19.2.7",
67
- "react-dom": "^19.2.7",
90
+ "lucide-react": "^1.24.0",
91
+ "react": "^19.2.8",
92
+ "react-dom": "^19.2.8",
68
93
  "tailwindcss": "^4.3.2",
94
+ "thesvg": "^3.2.6",
69
95
  "tw-animate-css": "^1.4.0",
70
96
  "typescript": "^6.0.3",
71
- "@vegastack/typescript-config": "0.0.0",
72
- "@vegastack/eslint-config": "0.0.0"
97
+ "@vegastack/eslint-config": "0.0.0",
98
+ "@vegastack/typescript-config": "0.0.0"
73
99
  },
74
100
  "publishConfig": {
75
- "access": "public",
76
- "provenance": true
101
+ "access": "public"
77
102
  },
78
103
  "scripts": {
79
104
  "build": "tsup",
80
105
  "lint": "eslint . && pnpm run verify",
81
106
  "verify": "node ../../tooling/verify-preset-source.mjs",
82
107
  "typecheck": "tsc --noEmit",
83
- "test": "node test/compare.test.mjs && node test/check-updates.test.mjs"
108
+ "test": "node test/compare.test.mjs && node test/check-updates.test.mjs && node test/skills-install.test.mjs"
84
109
  }
85
110
  }
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: vegastack-brand
3
+ description: VegaStack marketing and external visual identity — logo usage, brand colour, and marketing typography, distinct from the product design system. Currently a deliberate stub with no assets. Use when asked about VegaStack branding, logo usage, marketing colours, or external-facing visual identity.
4
+ ---
5
+
6
+ # VegaStack brand
7
+
8
+ **This skill is a deliberate stub.** Marketing has not yet provided the brand assets (logo,
9
+ marketing palette, marketing typography), so there is nothing here to apply yet.
10
+
11
+ ## What to do today
12
+
13
+ For product UI, use the `vegastack-design-system` skill. Its OKLCH semantic tokens are the only
14
+ locked visual identity VegaStack currently has.
15
+
16
+ **Do not invent a marketing palette, logo treatment, or brand typography.** If a task needs one, say
17
+ that the brand layer is not defined yet and ask, rather than generating something plausible that
18
+ will later conflict with the real assets.
19
+
20
+ Brand marks for external and marketing surfaces are rendered through `BrandIcon` from
21
+ `@vegastack/design/icons` (backed by `thesvg`), which is available now.
22
+
23
+ ## Scope once populated
24
+
25
+ - Logo usage: variants, clear-space, minimum sizes, prohibited treatments.
26
+ - Brand colour and marketing typography — a separate layer from the product tokens, never a
27
+ replacement for them.
28
+ - Marketing surface patterns, which in the component library are scoped to `.vs-marketing` and must
29
+ never appear in product UI.
@@ -0,0 +1,182 @@
1
+ ---
2
+ name: vegastack-consume
3
+ description: Set up a project to consume the VegaStack design system — install the public npm layer, wire the Tailwind v4 CSS and the provider, configure registry access, add components through the fail-closed integrity flow, override tokens, and keep copies up to date. Use when initialising a new project on VegaStack, adding the first component, fixing setup or registry-auth problems, or wiring the provider.
4
+ ---
5
+
6
+ # Consume VegaStack
7
+
8
+ Once setup is done, use the `vegastack-design-system` skill for day-to-day UI work.
9
+
10
+ ## 1. Install the public layer
11
+
12
+ ```bash
13
+ npm i @vegastack/design
14
+ ```
15
+
16
+ No credentials needed. It pulls in `@vegastack/design-tokens` as a dependency and provides `cn()`,
17
+ the icon runtime, the Tailwind v4 preset, and the `vegastack-design` CLI.
18
+
19
+ **Invoking the CLI.** The bin is `vegastack-design` but the package is `@vegastack/design`, so a
20
+ bare `npx vegastack-design …` in a project that does not already have it installed would try to
21
+ fetch an unrelated, unscoped package from npm. Use one of these instead — the first once it is a
22
+ local dependency (it resolves from `node_modules` and never contacts the registry), the second for a
23
+ standalone one-off:
24
+
25
+ ```bash
26
+ pnpm exec vegastack-design <command>
27
+ npx --package=@vegastack/design vegastack-design <command>
28
+ ```
29
+
30
+ `@vegastack/ui` is private and is never installed downstream — components arrive by copy-in.
31
+
32
+ ## 2. Tailwind v4 CSS
33
+
34
+ You must be on Tailwind v4.
35
+
36
+ ```css
37
+ @import "tailwindcss";
38
+ @import "@vegastack/design/theme.css"; /* :root + .dark + the @theme inline bridge */
39
+ @import "@vegastack/design/base.css"; /* border-border, body bg, :focus-visible, pointer cursor
40
+ on interactive controls, reduced-motion, and
41
+ body { isolation: isolate } — see step 3 */
42
+ ```
43
+
44
+ Or one import that bundles all of it plus tw-animate:
45
+
46
+ ```css
47
+ @import "@vegastack/design/preset.css";
48
+ ```
49
+
50
+ **No manual `@source` is required.** The preset already declares `@source` for the classes that live
51
+ inside the published builds — the icon runtime, and the provider/Toaster classNames (sonner emits
52
+ `group-[.toaster]:bg-popover`-style classes that Tailwind must be told to generate). Your own
53
+ application and component source is scanned by Tailwind as usual.
54
+
55
+ ## 3. Wrap the app root in the provider
56
+
57
+ ```bash
58
+ npx shadcn@latest add @vegastack/provider
59
+ ```
60
+
61
+ This copies `VegaStackProvider` and `useVegaStackTheme` into your project, composing the `sonner`
62
+ Toaster item.
63
+
64
+ ```tsx
65
+ import { VegaStackProvider } from "@/components/ui/provider";
66
+
67
+ // <html suppressHydrationWarning> — next-themes mutates it
68
+ <body className="isolate">
69
+ <VegaStackProvider>{children}</VegaStackProvider>
70
+ </body>;
71
+ ```
72
+
73
+ It bundles theme (next-themes, class-based dark), the Sonner toaster, and the Base UI tooltip and
74
+ direction providers.
75
+
76
+ **The `isolate` is required, not cosmetic.** Overlay components (Dialog, Sheet, Popover, Tooltip,
77
+ Select, menus) portal to `<body>` and depend on a root stacking context to render above page
78
+ content. Get it from `@vegastack/design/base.css` (which sets `body { isolation: isolate }`) or by
79
+ putting `className="isolate"` on your `<body>` yourself. Without it, popups can render _under_ app
80
+ chrome or mis-position in stacking-context-heavy layouts.
81
+
82
+ ## 4. Configure registry access
83
+
84
+ Components come from a private registry behind Cloudflare Access service tokens.
85
+
86
+ If the project has no `components.json` yet, create one first — pick the **base** style, never
87
+ `radix`, because VegaStack components are Base UI:
88
+
89
+ ```bash
90
+ pnpm dlx shadcn@latest init --base base
91
+ ```
92
+
93
+ Then add the registry block to `components.json`:
94
+
95
+ ```json
96
+ {
97
+ "registries": {
98
+ "@vegastack": {
99
+ "url": "https://design.vegastack.com/r/{name}.json",
100
+ "headers": {
101
+ "CF-Access-Client-Id": "${CF_ACCESS_CLIENT_ID}",
102
+ "CF-Access-Client-Secret": "${CF_ACCESS_CLIENT_SECRET}"
103
+ }
104
+ }
105
+ }
106
+ }
107
+ ```
108
+
109
+ Put the credentials in `.env.local`. Inspect before writing anything:
110
+
111
+ ```bash
112
+ pnpm dlx shadcn@latest add @vegastack/button --dry-run
113
+ ```
114
+
115
+ External and client projects are **tokenless** — components are copied in during development, and
116
+ the shipped application holds zero VegaStack credentials.
117
+
118
+ ## 5. Add a component (fail-closed, three steps)
119
+
120
+ This is the only safe way to add a component. Do not collapse it to a bare `shadcn add`: that leaves
121
+ a time-of-check/time-of-use gap, because `shadcn add` re-fetches the item after any preflight.
122
+
123
+ ```bash
124
+ # Create a private directory and choose a NEW file path inside it. The verifier refuses an
125
+ # existing path or a symlink rather than overwriting or following it.
126
+ DIR="$(mktemp -d "${TMPDIR:-/tmp}/vegastack-verify.XXXXXX")"; ITEM="$DIR/button.json"
127
+
128
+ # 1) PRE-WRITE — verify signature + hash, and save the trusted bytes for step 3.
129
+ npx --package=@vegastack/design vegastack-design verify --save "$ITEM" button
130
+
131
+ # Retain the verified digest in the parent shell BEFORE shadcn or dependency code runs.
132
+ EXPECTED="$(node -e 'process.stdout.write(JSON.parse(require("node:fs").readFileSync(process.argv[1],"utf8")).meta.integrity)' "$ITEM")"
133
+
134
+ # 2) COPY-IN — shadcn writes the files, rewriting import aliases per your components.json.
135
+ pnpm dlx shadcn@latest add @vegastack/button
136
+
137
+ # 3) POST-WRITE — prove the copied files match the SAVED item. Exits 1 on any tampering.
138
+ npx --package=@vegastack/design vegastack-design verify \
139
+ --post-write --item "$ITEM" --expected-integrity "$EXPECTED" --target-dir .
140
+ ```
141
+
142
+ Add `--hash-only` to step 1 only for local development or before the signed manifest is deployed —
143
+ it skips `cosign` and therefore does **not** prove provenance.
144
+
145
+ What each step guarantees, what it deliberately does not, and every flag and environment variable:
146
+ [references/registry-integrity.md](references/registry-integrity.md).
147
+
148
+ ## 6. Override tokens
149
+
150
+ One file, one variable, and every component repaints in both themes:
151
+
152
+ ```css
153
+ :root {
154
+ --primary: oklch(0.55 0.2 264);
155
+ }
156
+ ```
157
+
158
+ Never override a `--color-*` variable — that is the build-inlined bridge, not the runtime contract.
159
+
160
+ ## 7. Stay current
161
+
162
+ Copy-in means no automatic updates.
163
+
164
+ ```bash
165
+ npx --package=@vegastack/design vegastack-design check-updates # ⬆ update · ≈ drift · ✓ up to date
166
+ ```
167
+
168
+ Then per stale component: `shadcn add @vegastack/<name> --diff` to review, `--overwrite` to apply,
169
+ and re-run the step-3 post-write verification. Details and CI wiring:
170
+ [references/registry-integrity.md](references/registry-integrity.md).
171
+
172
+ Add the Renovate preset `github>VegaStack/renovate-config` so additive token bumps arrive as PRs.
173
+
174
+ ## Install the agent skills
175
+
176
+ If this project's agents do not already have them:
177
+
178
+ ```bash
179
+ npx --package=@vegastack/design vegastack-design skills install
180
+ ```
181
+
182
+ Writes the public VegaStack skills into `.claude/skills/` and `.agents/skills/`.