@actioneer/ads 0.1.0 → 0.2.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/bin/ads-init.mjs CHANGED
@@ -24,6 +24,7 @@
24
24
  import fs from "node:fs";
25
25
  import path from "node:path";
26
26
  import { execFileSync } from "node:child_process";
27
+ import { pathToFileURL } from "node:url";
27
28
 
28
29
  const PKG = "@actioneer/ads";
29
30
  const STYLE_IMPORT = `@import "${PKG}/styles.css";`;
@@ -309,6 +310,10 @@ function main() {
309
310
  }
310
311
 
311
312
  // Only run the applier when invoked as a CLI (keeps planInit importable/pure).
312
- if (import.meta.url === `file://${process.argv[1]}`) {
313
+ // Compare via pathToFileURL so an install path with spaces or non-ASCII (e.g.
314
+ // "/Users/My Name/…") still matches — import.meta.url is percent-encoded, so a
315
+ // raw `file://${process.argv[1]}` concat would silently fail to match and the
316
+ // CLI would no-op.
317
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
313
318
  main();
314
319
  }
package/llms.txt CHANGED
@@ -48,6 +48,95 @@ Reference semantic roles, never raw color/dimension literals (ads-lint rejects l
48
48
  - `ring`
49
49
  - `overlay`
50
50
 
51
+ ## Design principles
52
+
53
+ The house rules for every ADS UI. `[lint]` = `@actioneer/ads-lint` auto-checks it (pair with `lint_snippet`); `[judgment]` = you must self-apply it — the linter can't.
54
+
55
+ ### 1. Prefer fills & elevation over strokes — but keep a balance (~75/25) [judgment]
56
+
57
+ Delineate SURFACES (cards, panels, sidebars, page regions) with color contrast, elevation, and spacing — not borders. Aim for ~75% shadow/fill, 25% strokes: form controls and floating menus keep a subtle border so they read as interactive; surfaces do not.
58
+
59
+ - Do: Separate regions by fill color first: bg-background → bg-surface → bg-card/bg-elevated → bg-muted.
60
+ - Do: Keep a subtle border-input/border-border on form controls (input, select, textarea, checkbox, radio, segmented-control track) and floating menus (dropdown, popover, listboxes).
61
+ - Do: Keep strokes on focus rings, the outline Button/Badge/Chip variants, Kbd, Divider, the Tree connector rail, and functional color swatches.
62
+ - Don't: Add a border to a surface to separate or group it — use fill/elevation/spacing instead.
63
+ - Don't: Give a filled control no stroke on the tinted canvas — it disappears; it needs a crisp edge.
64
+
65
+ ### 2. Elevation = actionability [judgment]
66
+
67
+ The single shadow-elevation token is an affordance: it goes ONLY on surfaces the user can act on. Never elevate something that can't be clicked. There is no shadow scale.
68
+
69
+ - Do: Elevate actionable surfaces: pressable/hoverable cards, primary CTAs, control thumbs (Switch, Slider, active pills), and interactive floating layers (Modal, Drawer, Popover, Dropdown, listboxes, Toast).
70
+ - Do: Keep static surfaces flat: Panel, plain Card, Kbd, Navbar, headers, rails, docs boxes, Tooltip, InlineDrawer — they read by fill/color.
71
+ - Do: Ask 'can the user click this surface?' — if no, it's flat.
72
+ - Don't: Reintroduce a shadow scale (shadow-xs/sm/md/lg/xl) — there is one token only, shadow-elevation.
73
+ - Don't: Put a shadow on a non-interactive surface for decoration.
74
+
75
+ ### 3. Motion follows the design-engineering guide [lint: unbounded-transition, sluggish-easing, zero-scale-entrance, undersized-zoom-entrance]
76
+
77
+ Every easing/duration/scale flows from a token (--ease-*, --duration-*, --scale-press), mirrored for Motion in src/lib/motion.ts. UI animations stay under 300ms, exits run faster than enters, and reduced motion is respected everywhere.
78
+
79
+ - Do: Use strong curves only — the ease-out utility is the right default; overlays scale in origin-aware from their trigger.
80
+ - Do: Give pressable elements a --scale-press on :active (text/link exempt); start entrances ≥ scale 0.95 with opacity.
81
+ - Do: Respect reduced motion: keep opacity/color fades, drop movement.
82
+ - Don't: Use a slow-starting (accelerating) easing on UI, an unbounded all-property transition, a scale-from-zero entrance, or a UI duration at or over 300ms.
83
+ - Don't: Animate keyboard-initiated or 100×/day actions (e.g. a command-palette toggle).
84
+
85
+ ### 4. Icons: Hugeicons, stroke only [lint: icon-package-import]
86
+
87
+ All icons come from Hugeicons in the Stroke Rounded style only. Components import named icons from the @/lib/icons registry — never from an icon package directly — so a free→Pro swap or a restyle touches one file.
88
+
89
+ - Do: Import icons from the @/lib/icons registry; add a new one there (stroke variant) before using it.
90
+ - Do: Let icons default to size='1em' so they scale with text; size with a size prop or size-* class.
91
+ - Do: Keep stroke weight at the drawn 1.5; strokeWidth={2} is the one sanctioned emphasis step.
92
+ - Don't: Import from an icon package directly, or use solid/duotone/twotone/fill variants.
93
+ - Don't: Use a stroke weight thinner than 1.5.
94
+
95
+ ### 5. Demo screens: the shell owns the frame [judgment]
96
+
97
+ The demo shell applies the screen frame (inset on top/right/bottom, flush-left against the sidebar). Screens never add their own outer padding — a screen's root is flex h-full flex-col and fills the frame with Panel(s).
98
+
99
+ - Do: Make a screen root flex h-full flex-col and fill the frame with Panel(s).
100
+ - Do: Let one place (the shell) own the inset so every screen aligns to the rail.
101
+ - Don't: Add outer padding on a screen, leaving a tinted-canvas gap on the left.
102
+
103
+ ### 6. Status dots are square [judgment]
104
+
105
+ Indicator/status dots (Badge & Chip dot variants, ConnectionStatus, chart legend swatches, presence/pulse dots) are square — rounded-dot (2px), echoing the growth-mark's square cells — never round.
106
+
107
+ - Do: Use rounded-dot for every indicator/status dot.
108
+ - Don't: Use rounded-full on an indicator dot (the one exception is a Radio control's inner dot).
109
+
110
+ ### 7. ADS-first UI: use the library; extend only when asked [lint: deep-import, barrel-aliased-import, barrel-default-import, barrel-namespace-import, external-ui-import]
111
+
112
+ Every UI decision stays synchronized with ADS. Before making a new screen/control/pattern, check the ADS component suite first and use the exact exported name from the public barrel. Do not hand-roll, alias, deep-import, or import external UI libraries.
113
+
114
+ - Do: Use an existing ADS component by its exact exported name from the package barrel; compose existing components for layout-only patterns.
115
+ - Do: Ask the user before extending ADS; only an explicit request authorizes new library work.
116
+ - Do: When authorized, add the component to the right family, export its exact name through the barrel, and document it.
117
+ - Don't: Deep-import, alias, default/namespace-import, or hand-roll a local copy of a component.
118
+ - Don't: Import a visual component directly from the web or an npm UI library.
119
+
120
+ ### 8. Minimal information per screen [judgment]
121
+
122
+ A screen carries ONLY what the user needs to move forward: one title, at most one short supporting line, the inputs, one primary action. Never maximalist. Promote the one message that matters typographically instead of appending muted fine print.
123
+
124
+ - Do: Prefer more, smaller steps over dense ones; ask one thing at a time.
125
+ - Do: Derive instead of asking whenever possible (a name from a work email, the company from its domain).
126
+ - Do: Render multi-step flows full-screen — a single content container that holds the inputs and its own Back/Continue is fine.
127
+ - Don't: Add section eyebrows above a title that already names the screen, or helper text that restates the obvious / duplicates a disabled button's meaning.
128
+ - Don't: Nest panel/step-rail chrome inside a multi-step flow.
129
+
130
+ ### 9. Responsive = container-fluid components, shells own the width [judgment]
131
+
132
+ ADS targets landscape tablet (1024) → laptop (1440) → wide display (1920+); phone/portrait is out of scope. Components adapt to their CONTAINER via container queries; shells and pages decide pane widths through width tokens. Design against under-utilization, not cramping.
133
+
134
+ - Do: Use @container on the pane and @lg:/@xl: variants on children inside components.
135
+ - Do: Set pane widths in shells/pages through width tokens (--thread-max-width, --sidebar-width, --aside-width, --connector-card-min/-max).
136
+ - Do: Cap prose at its measure; let tables/charts/tool cards break out wider. Use auto-fill + minmax(min, 1fr) for grids.
137
+ - Don't: Use sm:/md: viewport variants inside src/components, or hardcode a pane width there.
138
+ - Don't: Cap a grid at a hard column count so it stops growing on wide displays.
139
+
51
140
  ## Components
52
141
 
53
142
  ### Primitives / utilities
@@ -300,6 +389,7 @@ Reference semantic roles, never raw color/dimension literals (ads-lint rejects l
300
389
  - [Alert] — Use for persistent inline status messaging on a page (not toasts) — a neutral surface where only the icon and title carry variant color. (variants: variant: default|success|warning|danger|info) [docs](https://ads.actioneer.dev/#/alert)
301
390
  - [AlertDescription] — component (variants: variant: default|success|warning|danger|info) [docs](https://ads.actioneer.dev/#/alert)
302
391
  - [AlertTitle] — component (variants: variant: default|success|warning|danger|info) [docs](https://ads.actioneer.dev/#/alert)
392
+ - [BrandLoader] — Use for a branded loading/generating indicator (inline in a text row or as a standalone full-screen moment) instead of a generic spinner. [docs](https://ads.actioneer.dev/#/brand-loader)
303
393
  - [BrandMark] — component [docs](https://ads.actioneer.dev/#/brand-loader)
304
394
  - [EmptyState] — Use as the centered placeholder inside a list, table, or panel that currently has nothing to show. [docs](https://ads.actioneer.dev/#/empty-state)
305
395
  - [PixelBlastSVG] — component [docs](https://ads.actioneer.dev/#/pixel-blast-svg)
@@ -307,6 +397,7 @@ Reference semantic roles, never raw color/dimension literals (ads-lint rejects l
307
397
  - [ProgressCircle] — Use for a compact circular loading/progress indicator (determinate or indeterminate) where a linear bar doesn't fit, e.g. inline with a caption or a small avatar-sized control. [docs](https://ads.actioneer.dev/#/progress-circle)
308
398
  - [Skeleton] — Placeholder the shape of content that's still loading — size it via className and pair with circle for avatars. [docs](https://ads.actioneer.dev/#/skeleton)
309
399
  - [AlertProps] — TypeScript type
400
+ - [BrandLoaderProps] — TypeScript type
310
401
  - [BrandMarkProps] — TypeScript type
311
402
  - [EmptyStateProps] — TypeScript type
312
403
  - [PixelBlastSVGProps] — TypeScript type
@@ -349,7 +440,6 @@ Reference semantic roles, never raw color/dimension literals (ads-lint rejects l
349
440
  - [SidebarProps] — TypeScript type
350
441
  - [SidebarSectionProps] — TypeScript type
351
442
  - [useSidebar] — React hook
352
- - [href] — utility
353
443
 
354
444
  ### Layout
355
445
 
@@ -531,7 +621,4 @@ Reference semantic roles, never raw color/dimension literals (ads-lint rejects l
531
621
  - [VoiceStatusDotProps] — TypeScript type
532
622
  - [VoiceVariant] — TypeScript type
533
623
  - [useReasoning] — React hook
534
- - [className] — utility
535
- - [defaultOpen] — utility
536
- - [safeVariant] — utility
537
624
  - [Tool] — utility
package/manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actioneer/ads",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "importPath": "@actioneer/ads",
5
5
  "styleImport": "@import \"@actioneer/ads/styles.css\";",
6
6
  "families": [
@@ -15,11 +15,11 @@
15
15
  "AI Elements"
16
16
  ],
17
17
  "counts": {
18
- "total": 459,
19
- "component": 219,
20
- "type": 216,
18
+ "total": 457,
19
+ "component": 220,
20
+ "type": 217,
21
21
  "hook": 3,
22
- "util": 21
22
+ "util": 17
23
23
  },
24
24
  "tokens": [
25
25
  {
@@ -3160,6 +3160,15 @@
3160
3160
  }
3161
3161
  }
3162
3162
  },
3163
+ {
3164
+ "name": "BrandLoader",
3165
+ "family": "Feedback",
3166
+ "kind": "component",
3167
+ "importPath": "@actioneer/ads",
3168
+ "module": "brand-loader",
3169
+ "description": "Use for a branded loading/generating indicator (inline in a text row or as a standalone full-screen moment) instead of a generic spinner.",
3170
+ "showcaseUrl": "https://ads.actioneer.dev/#/brand-loader"
3171
+ },
3163
3172
  {
3164
3173
  "name": "BrandMark",
3165
3174
  "family": "Feedback",
@@ -3265,6 +3274,13 @@
3265
3274
  "importPath": "@actioneer/ads",
3266
3275
  "module": "alert"
3267
3276
  },
3277
+ {
3278
+ "name": "BrandLoaderProps",
3279
+ "family": "Feedback",
3280
+ "kind": "type",
3281
+ "importPath": "@actioneer/ads",
3282
+ "module": "brand-loader"
3283
+ },
3268
3284
  {
3269
3285
  "name": "BrandMarkProps",
3270
3286
  "family": "Feedback",
@@ -3652,13 +3668,6 @@
3652
3668
  "importPath": "@actioneer/ads",
3653
3669
  "module": "sidebar"
3654
3670
  },
3655
- {
3656
- "name": "href",
3657
- "family": "Navigation",
3658
- "kind": "util",
3659
- "importPath": "@actioneer/ads",
3660
- "module": "breadcrumbs"
3661
- },
3662
3671
  {
3663
3672
  "name": "Collapsible",
3664
3673
  "family": "Layout",
@@ -5054,32 +5063,168 @@
5054
5063
  "module": "reasoning"
5055
5064
  },
5056
5065
  {
5057
- "name": "className",
5066
+ "name": "Tool",
5058
5067
  "family": "AI Elements",
5059
5068
  "kind": "util",
5060
5069
  "importPath": "@actioneer/ads",
5061
- "module": "queue"
5070
+ "module": "tool"
5071
+ }
5072
+ ],
5073
+ "principles": [
5074
+ {
5075
+ "id": "fills-over-strokes",
5076
+ "number": 1,
5077
+ "title": "Prefer fills & elevation over strokes — but keep a balance (~75/25)",
5078
+ "rule": "Delineate SURFACES (cards, panels, sidebars, page regions) with color contrast, elevation, and spacing — not borders. Aim for ~75% shadow/fill, 25% strokes: form controls and floating menus keep a subtle border so they read as interactive; surfaces do not.",
5079
+ "do": [
5080
+ "Separate regions by fill color first: bg-background → bg-surface → bg-card/bg-elevated → bg-muted.",
5081
+ "Keep a subtle border-input/border-border on form controls (input, select, textarea, checkbox, radio, segmented-control track) and floating menus (dropdown, popover, listboxes).",
5082
+ "Keep strokes on focus rings, the outline Button/Badge/Chip variants, Kbd, Divider, the Tree connector rail, and functional color swatches."
5083
+ ],
5084
+ "dont": [
5085
+ "Add a border to a surface to separate or group it — use fill/elevation/spacing instead.",
5086
+ "Give a filled control no stroke on the tinted canvas — it disappears; it needs a crisp edge."
5087
+ ],
5088
+ "enforcedByLint": false
5062
5089
  },
5063
5090
  {
5064
- "name": "defaultOpen",
5065
- "family": "AI Elements",
5066
- "kind": "util",
5067
- "importPath": "@actioneer/ads",
5068
- "module": "queue"
5091
+ "id": "elevation-is-actionability",
5092
+ "number": 2,
5093
+ "title": "Elevation = actionability",
5094
+ "rule": "The single shadow-elevation token is an affordance: it goes ONLY on surfaces the user can act on. Never elevate something that can't be clicked. There is no shadow scale.",
5095
+ "do": [
5096
+ "Elevate actionable surfaces: pressable/hoverable cards, primary CTAs, control thumbs (Switch, Slider, active pills), and interactive floating layers (Modal, Drawer, Popover, Dropdown, listboxes, Toast).",
5097
+ "Keep static surfaces flat: Panel, plain Card, Kbd, Navbar, headers, rails, docs boxes, Tooltip, InlineDrawer — they read by fill/color.",
5098
+ "Ask 'can the user click this surface?' — if no, it's flat."
5099
+ ],
5100
+ "dont": [
5101
+ "Reintroduce a shadow scale (shadow-xs/sm/md/lg/xl) — there is one token only, shadow-elevation.",
5102
+ "Put a shadow on a non-interactive surface for decoration."
5103
+ ],
5104
+ "enforcedByLint": false
5069
5105
  },
5070
5106
  {
5071
- "name": "safeVariant",
5072
- "family": "AI Elements",
5073
- "kind": "util",
5074
- "importPath": "@actioneer/ads",
5075
- "module": "voice"
5107
+ "id": "motion-follows-guide",
5108
+ "number": 3,
5109
+ "title": "Motion follows the design-engineering guide",
5110
+ "rule": "Every easing/duration/scale flows from a token (--ease-*, --duration-*, --scale-press), mirrored for Motion in src/lib/motion.ts. UI animations stay under 300ms, exits run faster than enters, and reduced motion is respected everywhere.",
5111
+ "do": [
5112
+ "Use strong curves only — the ease-out utility is the right default; overlays scale in origin-aware from their trigger.",
5113
+ "Give pressable elements a --scale-press on :active (text/link exempt); start entrances ≥ scale 0.95 with opacity.",
5114
+ "Respect reduced motion: keep opacity/color fades, drop movement."
5115
+ ],
5116
+ "dont": [
5117
+ "Use a slow-starting (accelerating) easing on UI, an unbounded all-property transition, a scale-from-zero entrance, or a UI duration at or over 300ms.",
5118
+ "Animate keyboard-initiated or 100×/day actions (e.g. a command-palette toggle)."
5119
+ ],
5120
+ "enforcedByLint": true,
5121
+ "lintRules": [
5122
+ "unbounded-transition",
5123
+ "sluggish-easing",
5124
+ "zero-scale-entrance",
5125
+ "undersized-zoom-entrance"
5126
+ ]
5076
5127
  },
5077
5128
  {
5078
- "name": "Tool",
5079
- "family": "AI Elements",
5080
- "kind": "util",
5081
- "importPath": "@actioneer/ads",
5082
- "module": "tool"
5129
+ "id": "icons-hugeicons-stroke",
5130
+ "number": 4,
5131
+ "title": "Icons: Hugeicons, stroke only",
5132
+ "rule": "All icons come from Hugeicons in the Stroke Rounded style only. Components import named icons from the @/lib/icons registry — never from an icon package directly — so a free→Pro swap or a restyle touches one file.",
5133
+ "do": [
5134
+ "Import icons from the @/lib/icons registry; add a new one there (stroke variant) before using it.",
5135
+ "Let icons default to size='1em' so they scale with text; size with a size prop or size-* class.",
5136
+ "Keep stroke weight at the drawn 1.5; strokeWidth={2} is the one sanctioned emphasis step."
5137
+ ],
5138
+ "dont": [
5139
+ "Import from an icon package directly, or use solid/duotone/twotone/fill variants.",
5140
+ "Use a stroke weight thinner than 1.5."
5141
+ ],
5142
+ "enforcedByLint": true,
5143
+ "lintRules": [
5144
+ "icon-package-import"
5145
+ ]
5146
+ },
5147
+ {
5148
+ "id": "shell-owns-the-frame",
5149
+ "number": 5,
5150
+ "title": "Demo screens: the shell owns the frame",
5151
+ "rule": "The demo shell applies the screen frame (inset on top/right/bottom, flush-left against the sidebar). Screens never add their own outer padding — a screen's root is flex h-full flex-col and fills the frame with Panel(s).",
5152
+ "do": [
5153
+ "Make a screen root flex h-full flex-col and fill the frame with Panel(s).",
5154
+ "Let one place (the shell) own the inset so every screen aligns to the rail."
5155
+ ],
5156
+ "dont": [
5157
+ "Add outer padding on a screen, leaving a tinted-canvas gap on the left."
5158
+ ],
5159
+ "enforcedByLint": false
5160
+ },
5161
+ {
5162
+ "id": "square-status-dots",
5163
+ "number": 6,
5164
+ "title": "Status dots are square",
5165
+ "rule": "Indicator/status dots (Badge & Chip dot variants, ConnectionStatus, chart legend swatches, presence/pulse dots) are square — rounded-dot (2px), echoing the growth-mark's square cells — never round.",
5166
+ "do": [
5167
+ "Use rounded-dot for every indicator/status dot."
5168
+ ],
5169
+ "dont": [
5170
+ "Use rounded-full on an indicator dot (the one exception is a Radio control's inner dot)."
5171
+ ],
5172
+ "enforcedByLint": false
5173
+ },
5174
+ {
5175
+ "id": "ads-first",
5176
+ "number": 7,
5177
+ "title": "ADS-first UI: use the library; extend only when asked",
5178
+ "rule": "Every UI decision stays synchronized with ADS. Before making a new screen/control/pattern, check the ADS component suite first and use the exact exported name from the public barrel. Do not hand-roll, alias, deep-import, or import external UI libraries.",
5179
+ "do": [
5180
+ "Use an existing ADS component by its exact exported name from the package barrel; compose existing components for layout-only patterns.",
5181
+ "Ask the user before extending ADS; only an explicit request authorizes new library work.",
5182
+ "When authorized, add the component to the right family, export its exact name through the barrel, and document it."
5183
+ ],
5184
+ "dont": [
5185
+ "Deep-import, alias, default/namespace-import, or hand-roll a local copy of a component.",
5186
+ "Import a visual component directly from the web or an npm UI library."
5187
+ ],
5188
+ "enforcedByLint": true,
5189
+ "lintRules": [
5190
+ "deep-import",
5191
+ "barrel-aliased-import",
5192
+ "barrel-default-import",
5193
+ "barrel-namespace-import",
5194
+ "external-ui-import"
5195
+ ]
5196
+ },
5197
+ {
5198
+ "id": "minimal-information",
5199
+ "number": 8,
5200
+ "title": "Minimal information per screen",
5201
+ "rule": "A screen carries ONLY what the user needs to move forward: one title, at most one short supporting line, the inputs, one primary action. Never maximalist. Promote the one message that matters typographically instead of appending muted fine print.",
5202
+ "do": [
5203
+ "Prefer more, smaller steps over dense ones; ask one thing at a time.",
5204
+ "Derive instead of asking whenever possible (a name from a work email, the company from its domain).",
5205
+ "Render multi-step flows full-screen — a single content container that holds the inputs and its own Back/Continue is fine."
5206
+ ],
5207
+ "dont": [
5208
+ "Add section eyebrows above a title that already names the screen, or helper text that restates the obvious / duplicates a disabled button's meaning.",
5209
+ "Nest panel/step-rail chrome inside a multi-step flow."
5210
+ ],
5211
+ "enforcedByLint": false
5212
+ },
5213
+ {
5214
+ "id": "responsive-container-fluid",
5215
+ "number": 9,
5216
+ "title": "Responsive = container-fluid components, shells own the width",
5217
+ "rule": "ADS targets landscape tablet (1024) → laptop (1440) → wide display (1920+); phone/portrait is out of scope. Components adapt to their CONTAINER via container queries; shells and pages decide pane widths through width tokens. Design against under-utilization, not cramping.",
5218
+ "do": [
5219
+ "Use @container on the pane and @lg:/@xl: variants on children inside components.",
5220
+ "Set pane widths in shells/pages through width tokens (--thread-max-width, --sidebar-width, --aside-width, --connector-card-min/-max).",
5221
+ "Cap prose at its measure; let tables/charts/tool cards break out wider. Use auto-fill + minmax(min, 1fr) for grids."
5222
+ ],
5223
+ "dont": [
5224
+ "Use sm:/md: viewport variants inside src/components, or hardcode a pane width there.",
5225
+ "Cap a grid at a hard column count so it stops growing on wide displays."
5226
+ ],
5227
+ "enforcedByLint": false
5083
5228
  }
5084
5229
  ]
5085
5230
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actioneer/ads",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Actioneer Design System 1.0 — React 19 + Tailwind v4 component library.",
5
5
  "type": "module",
6
6
  "sideEffects": [