@you-agent-factory/components 0.0.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.
Files changed (92) hide show
  1. package/README.md +223 -0
  2. package/docs/README.md +83 -0
  3. package/docs/button.md +119 -0
  4. package/docs/charts.md +325 -0
  5. package/docs/data-display-code-panel.md +120 -0
  6. package/docs/feedback-alert-panel.md +117 -0
  7. package/docs/feedback-skeleton.md +54 -0
  8. package/docs/forms-form-field.md +490 -0
  9. package/docs/forms-input-primitives.md +311 -0
  10. package/docs/forms-select-primitives.md +362 -0
  11. package/docs/graphs.md +250 -0
  12. package/docs/layout-display-primitives.md +211 -0
  13. package/docs/overlays.md +414 -0
  14. package/docs/table-data-table.md +331 -0
  15. package/docs/typography-roles.md +182 -0
  16. package/docs/widget-frame-recipes.md +273 -0
  17. package/package.json +161 -0
  18. package/src/category-paths.ts +20 -0
  19. package/src/charts/chart-state-panel.tsx +103 -0
  20. package/src/charts/chart.tsx +287 -0
  21. package/src/charts/index.ts +21 -0
  22. package/src/data-display/code-panel.tsx +67 -0
  23. package/src/data-display/data-table.tsx +180 -0
  24. package/src/data-display/description-list.tsx +24 -0
  25. package/src/data-display/index.ts +34 -0
  26. package/src/data-display/table-layout.ts +12 -0
  27. package/src/data-display/table.tsx +131 -0
  28. package/src/feedback/alert-panel-semantics.ts +75 -0
  29. package/src/feedback/alert-panel.tsx +187 -0
  30. package/src/feedback/index.ts +21 -0
  31. package/src/feedback/skeleton.tsx +16 -0
  32. package/src/forms/index.ts +73 -0
  33. package/src/forms/package-checkbox.tsx +50 -0
  34. package/src/forms/package-enum-select.tsx +185 -0
  35. package/src/forms/package-file-input.tsx +25 -0
  36. package/src/forms/package-form-field.tsx +202 -0
  37. package/src/forms/package-input.tsx +25 -0
  38. package/src/forms/package-native-select.tsx +25 -0
  39. package/src/forms/package-select.tsx +209 -0
  40. package/src/forms/package-textarea.tsx +35 -0
  41. package/src/forms/select-icons.tsx +35 -0
  42. package/src/graphs/graph-edge-path.ts +241 -0
  43. package/src/graphs/graph-edge.tsx +130 -0
  44. package/src/graphs/graph-interactive-example.tsx +187 -0
  45. package/src/graphs/graph-node-button.tsx +51 -0
  46. package/src/graphs/graph-node-handle-badge.tsx +108 -0
  47. package/src/graphs/graph-node-handle.ts +28 -0
  48. package/src/graphs/graph-node-shell.tsx +111 -0
  49. package/src/graphs/graph-node-state-indicator.tsx +47 -0
  50. package/src/graphs/graph-node-state.ts +111 -0
  51. package/src/graphs/graph-viewport-surface.tsx +27 -0
  52. package/src/graphs/index.ts +41 -0
  53. package/src/icons/index.ts +4 -0
  54. package/src/index.ts +209 -0
  55. package/src/layout/action-row.tsx +53 -0
  56. package/src/layout/index.ts +9 -0
  57. package/src/layout/surface-panel.tsx +91 -0
  58. package/src/navigation/index.ts +4 -0
  59. package/src/overlays/collapsible.tsx +22 -0
  60. package/src/overlays/dialog.tsx +148 -0
  61. package/src/overlays/index.ts +31 -0
  62. package/src/overlays/overlay-layout.ts +9 -0
  63. package/src/overlays/popover.tsx +29 -0
  64. package/src/overlays/scroll-area.tsx +78 -0
  65. package/src/primitives/button-link.tsx +22 -0
  66. package/src/primitives/button.tsx +258 -0
  67. package/src/primitives/icon-button-shell.tsx +49 -0
  68. package/src/primitives/index.ts +31 -0
  69. package/src/primitives/package-text.tsx +29 -0
  70. package/src/primitives/typography-roles.ts +12 -0
  71. package/src/primitives/typography.tsx +165 -0
  72. package/src/recipes/index.ts +61 -0
  73. package/src/recipes/widget-frame-content.tsx +114 -0
  74. package/src/recipes/widget-frame-disclosure.tsx +161 -0
  75. package/src/recipes/widget-frame-layout.ts +40 -0
  76. package/src/recipes/widget-frame-skeleton.tsx +16 -0
  77. package/src/recipes/widget-frame-states.tsx +99 -0
  78. package/src/recipes/widget-frame-typography.ts +19 -0
  79. package/src/recipes/widget-frame.tsx +84 -0
  80. package/src/styles/color-palette-presets.css +167 -0
  81. package/src/styles/color-role-tokens.css +163 -0
  82. package/src/styles/layout-role-tokens.css +27 -0
  83. package/src/styles/text-color-role-tokens.css +29 -0
  84. package/src/styles/typography-role-tokens.css +72 -0
  85. package/src/styles/typography-role-utilities.css +73 -0
  86. package/src/styles/typography-roles.css +53 -0
  87. package/src/styles.css +32 -0
  88. package/src/testing/index.ts +13 -0
  89. package/src/testing/render.tsx +16 -0
  90. package/src/tokens/index.ts +4 -0
  91. package/src/utilities/cn.ts +5 -0
  92. package/src/utilities/index.ts +6 -0
@@ -0,0 +1,273 @@
1
+ # Widget frame and layout recipes
2
+
3
+ Domain-free widget frame shells and layout recipes for dashboard-like panels.
4
+ Use these components when you need framed content regions with consistent
5
+ typography, state treatments, disclosure controls, and responsive layout helpers
6
+ without importing dashboard features, bento grids, API clients, or app state.
7
+
8
+ ## Required setup
9
+
10
+ Import package styles once in your host application before rendering recipes:
11
+
12
+ ```css
13
+ @import "@you-agent-factory/components/styles.css";
14
+ ```
15
+
16
+ Recipes depend on package role tokens (`--color-surface`, `--shadow-af-card`,
17
+ typography roles) and Tailwind utility classes compiled from those tokens. They
18
+ do not require dashboard `styles.css`, dashboard providers, generated OpenAPI
19
+ types, React Query, Zustand, or app localization context.
20
+
21
+ ## Import paths
22
+
23
+ Prefer the recipes category entrypoint for tree-shaking and explicit category
24
+ boundaries:
25
+
26
+ ```ts
27
+ import {
28
+ WidgetFrame,
29
+ WidgetSubtitle,
30
+ WidgetDetailCopy,
31
+ WidgetEmptyState,
32
+ WidgetEmptyStateTitle,
33
+ WidgetEmptyStateText,
34
+ WidgetLoadingState,
35
+ WidgetErrorState,
36
+ WidgetSuccessState,
37
+ WidgetFrameDisclosure,
38
+ WidgetFrameDisclosureTrigger,
39
+ WidgetFrameDisclosurePanel,
40
+ widgetFrameDetailCardClass,
41
+ } from "@you-agent-factory/components/recipes";
42
+ ```
43
+
44
+ The same exports are also available from the package root:
45
+
46
+ ```ts
47
+ import { WidgetFrame } from "@you-agent-factory/components";
48
+ ```
49
+
50
+ ## Host ownership
51
+
52
+ The package owns presentation markup, layout classes, and accessibility
53
+ semantics for frame shells. Host applications own everything domain-specific:
54
+
55
+ | Concern | Owner |
56
+ | --- | --- |
57
+ | User-visible copy (titles, messages, labels) | Host |
58
+ | Data fetching, caching, and error mapping | Host |
59
+ | Domain models (factory, work, session, provider) | Host |
60
+ | Collapsed/expanded boolean state | Host |
61
+ | Header and body action callbacks | Host |
62
+ | Bento grid composition, drag/resize, widget selection | Dashboard feature code |
63
+ | Durable cross-route or persisted UI state | Host |
64
+
65
+ Pass copy and state into recipe components as props and children. Do not expect
66
+ recipes to read from your routers, stores, or API layers.
67
+
68
+ ## Composition overview
69
+
70
+ A typical framed panel stacks:
71
+
72
+ 1. `WidgetFrame` — card shell with title, optional `headerAction`, and scrollable body.
73
+ 2. Content primitives — `WidgetSubtitle`, `WidgetDetailCopy`, or arbitrary host children.
74
+ 3. State shells — `WidgetLoadingState`, `WidgetErrorState`, `WidgetSuccessState`, or `WidgetEmptyState`.
75
+ 4. Optional disclosure — `WidgetFrameDisclosure` + controlled trigger/panel pair.
76
+
77
+ ```tsx
78
+ import { useState } from "react";
79
+ import {
80
+ WidgetDetailCopy,
81
+ WidgetEmptyStateText,
82
+ WidgetEmptyStateTitle,
83
+ WidgetFrame,
84
+ WidgetFrameDisclosure,
85
+ WidgetFrameDisclosurePanel,
86
+ WidgetFrameDisclosureTrigger,
87
+ WidgetLoadingState,
88
+ WidgetSubtitle,
89
+ } from "@you-agent-factory/components/recipes";
90
+
91
+ export function ExamplePanel({
92
+ loading,
93
+ title,
94
+ }: {
95
+ loading: boolean;
96
+ title: string;
97
+ }) {
98
+ const [expanded, setExpanded] = useState(false);
99
+ const panelID = "example-panel-details";
100
+
101
+ return (
102
+ <WidgetFrame
103
+ headerAction={
104
+ <button type="button" onClick={() => undefined}>
105
+ Refresh
106
+ </button>
107
+ }
108
+ title={title}
109
+ >
110
+ <WidgetSubtitle>42 host-provided items</WidgetSubtitle>
111
+ {loading ? (
112
+ <WidgetLoadingState>
113
+ <WidgetEmptyStateTitle>Loading content</WidgetEmptyStateTitle>
114
+ <WidgetEmptyStateText>Host-provided loading message.</WidgetEmptyStateText>
115
+ </WidgetLoadingState>
116
+ ) : (
117
+ <WidgetDetailCopy>Host-provided detail copy.</WidgetDetailCopy>
118
+ )}
119
+ <WidgetFrameDisclosure>
120
+ <WidgetFrameDisclosureTrigger
121
+ controlsID={panelID}
122
+ expanded={expanded}
123
+ onExpandedChange={setExpanded}
124
+ >
125
+ {expanded ? "Collapse details" : "Expand details"}
126
+ </WidgetFrameDisclosureTrigger>
127
+ <WidgetFrameDisclosurePanel expanded={expanded} id={panelID}>
128
+ <WidgetDetailCopy>Host-provided disclosure content.</WidgetDetailCopy>
129
+ </WidgetFrameDisclosurePanel>
130
+ </WidgetFrameDisclosure>
131
+ </WidgetFrame>
132
+ );
133
+ }
134
+ ```
135
+
136
+ ## Key props and layout helpers
137
+
138
+ ### `WidgetFrame`
139
+
140
+ | Prop | Purpose |
141
+ | --- | --- |
142
+ | `title` | Required accessible name (`aria-label` on the frame article). |
143
+ | `children` | Host content region inside the body grid. |
144
+ | `headerAction` | Optional header tools slot (buttons, menus). A spacer preserves header height when omitted. |
145
+ | `wide` | Applies minimum body height for wide dashboard columns. |
146
+ | `bodyScroll` | Enables scrollable body (`overflow-auto`). Defaults to `true`. |
147
+ | `className` / `bodyClassName` | Host layout overrides. Apply `widgetFrameDetailCardClass` via `className` when rendering description lists. |
148
+
149
+ Layout constants exported for host composition:
150
+
151
+ - `widgetFrameDetailCardClass` — description-list spacing inside framed detail cards.
152
+ - `WIDGET_FRAME_MIN_WIDTH_CLASS` — `min-w-0` shrink guard for grid parents.
153
+ - `WIDGET_FRAME_WIDE_BODY_CLASS` — minimum body height for wide layouts.
154
+ - `WIDGET_FRAME_RESPONSIVE_SHELL_CLASS` — full-width responsive shell helper.
155
+
156
+ ### State shells
157
+
158
+ | Component | Semantics | Host provides |
159
+ | --- | --- | --- |
160
+ | `WidgetLoadingState` | `role="status"`, `aria-busy="true"` | Loading copy via children; optional `placeholder` or `showDefaultPlaceholder={false}`. |
161
+ | `WidgetErrorState` | `role="alert"` | Error title and message via children. |
162
+ | `WidgetSuccessState` | `role="status"` | Success title and message via children. |
163
+ | `WidgetEmptyState` | Neutral dashed panel | Empty title/text via `WidgetEmptyStateTitle` / `WidgetEmptyStateText` or arbitrary children. |
164
+
165
+ State shells never invent domain-specific text. All user-visible strings come from
166
+ the host.
167
+
168
+ ### Disclosure (collapsed / expanded)
169
+
170
+ Use controlled state from the host:
171
+
172
+ - `WidgetFrameDisclosureTrigger` requires `controlsID`, `expanded`, and optional `onExpandedChange`.
173
+ - `WidgetFrameDisclosurePanel` requires matching `id` and `expanded`.
174
+ - Triggers expose `aria-expanded`, `aria-controls`, keyboard focus rings, and `type="button"`.
175
+ - Panels use the `hidden` attribute when collapsed.
176
+
177
+ Icon-only triggers must pass `aria-label`. Labeled triggers use visible button text.
178
+
179
+ ### Responsive layout helpers
180
+
181
+ For Storybook demos and host layout tests:
182
+
183
+ - `widgetFrameStoryShellStyle(maxWidth)` — bounded shell wrapper style object.
184
+ - `widgetFrameHasNoHorizontalOverflow(element)` — pure helper for overflow checks.
185
+ - `WIDGET_FRAME_STORY_SHELL_DATA_ATTR` — `data-widget-frame-story-shell` marker for test shells.
186
+
187
+ ## Accessibility expectations
188
+
189
+ - Frame title renders as a level-3 heading inside a landmark `article` labeled with the same title text.
190
+ - Loading, error, and success regions use appropriate live-region roles; do not nest conflicting roles.
191
+ - Disclosure triggers are keyboard operable buttons with visible `focus-visible` outlines.
192
+ - Header actions supplied by the host must include accessible names (`aria-label` or visible text).
193
+ - Host copy inside alerts and status regions should use heading + body structure for screen-reader scanability.
194
+
195
+ ## Storybook visual reference
196
+
197
+ Package Storybook lives under `Recipes/WidgetFrame`. Stories use package imports
198
+ and package token decorators only — no dashboard providers.
199
+
200
+ | Story | Storybook id | Demonstrates |
201
+ | --- | --- | --- |
202
+ | Success content | `recipes-widgetframe--success-content` | Default framed content |
203
+ | Empty state | `recipes-widgetframe--empty-state` | Host-provided empty copy |
204
+ | Loading state | `recipes-widgetframe--loading-state` | `WidgetLoadingState` + placeholder |
205
+ | Error state | `recipes-widgetframe--error-state` | `WidgetErrorState` alert treatment |
206
+ | Success state | `recipes-widgetframe--success-state` | `WidgetSuccessState` treatment |
207
+ | Collapsed disclosure | `recipes-widgetframe--collapsed-disclosure` | Controlled collapse + expand interaction |
208
+ | Expanded disclosure | `recipes-widgetframe--expanded-disclosure` | Expanded panel visibility |
209
+ | Responsive compact | `recipes-widgetframe--responsive-compact` | 360px bounded shell |
210
+ | Responsive medium | `recipes-widgetframe--responsive-medium` | 768px bounded shell |
211
+ | Responsive wide | `recipes-widgetframe--responsive-wide` | 1280px bounded shell |
212
+
213
+ Run package Storybook locally:
214
+
215
+ ```bash
216
+ cd ui/packages/components
217
+ bun run storybook
218
+ ```
219
+
220
+ Browser verification for documented stories:
221
+
222
+ ```bash
223
+ cd ui/packages/components
224
+ bun run verify:widget-frame-docs
225
+ ```
226
+
227
+ Responsive overflow checks (compact + wide at mobile and desktop viewports):
228
+
229
+ ```bash
230
+ cd ui/packages/components
231
+ bun run verify:widget-frame-responsive
232
+ ```
233
+
234
+ ## Allowed dependencies
235
+
236
+ Recipe source may import:
237
+
238
+ - Package utilities (`cn` from `@you-agent-factory/components/utilities`)
239
+ - Package token CSS via the host `styles.css` import
240
+ - React and `react-dom` peer dependencies
241
+
242
+ Recipe source must **not** import:
243
+
244
+ - Dashboard feature modules, routes, or bento grid (`react-grid-layout`)
245
+ - Generated OpenAPI clients or dashboard API adapters
246
+ - React Query, Zustand, Monaco, Sonner, or dashboard i18n/session providers
247
+ - Factory/work/session/provider domain types
248
+
249
+ `check:package-boundary` enforces these rules in CI.
250
+
251
+ ## Source-copy guidance
252
+
253
+ Teams may copy recipe files into a host repository to customize markup while
254
+ keeping the same token foundation:
255
+
256
+ 1. Import `@you-agent-factory/components/styles.css` in the host app.
257
+ 2. Copy only the recipe files you need from `src/recipes/`.
258
+ 3. Keep copied code on the package side of your boundary — do not pull dashboard
259
+ modules into copied recipe files.
260
+ 4. Retain host ownership of copy, data fetching, disclosure state, and action handlers.
261
+
262
+ **No source-copy CLI or generator ships with this package.** Copy-and-adapt
263
+ workflows are manual and maintained by the host application.
264
+
265
+ ## Dashboard integration note
266
+
267
+ The dashboard keeps bento composition (`AgentBentoCard`, grid layout, widget
268
+ picker) in feature code. Dashboard widgets import recipe content primitives from
269
+ `@you-agent-factory/components/recipes` while `DashboardWidgetFrame` remains a
270
+ dashboard-owned wrapper that applies bento-specific chrome.
271
+
272
+ When adopting recipes outside the dashboard, compose `WidgetFrame` directly and
273
+ supply your own header actions, state, and slot content.
package/package.json ADDED
@@ -0,0 +1,161 @@
1
+ {
2
+ "name": "@you-agent-factory/components",
3
+ "description": "Reusable presentation components, design tokens, and docs for You Agent Factory UIs.",
4
+ "version": "0.0.0",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "homepage": "https://github.com/portpowered/you-agent-factory#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/portpowered/you-agent-factory.git",
11
+ "directory": "ui/packages/components"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/portpowered/you-agent-factory/issues"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "files": [
20
+ "README.md",
21
+ "docs/**/*.md",
22
+ "src/**/*.css",
23
+ "src/**/*.ts",
24
+ "src/**/*.tsx",
25
+ "!src/**/*.test.ts",
26
+ "!src/**/*.test.tsx",
27
+ "!src/**/*.stories.ts",
28
+ "!src/**/*.stories.tsx",
29
+ "!src/**/*.harness.test.ts",
30
+ "!src/**/*.integration.test.tsx",
31
+ "!src/**/storybook-*.ts",
32
+ "!src/**/storybook-*.tsx",
33
+ "!src/**/package-*-story-support.tsx",
34
+ "!src/**/*story-fixtures.ts",
35
+ "!src/**/overlay-story*.ts",
36
+ "!src/**/compile-package-token-styles.ts",
37
+ "!src/**/package-token-fixture-usage.ts",
38
+ "!src/**/package-token-styles-fixture.css",
39
+ "!src/testing/package-browser-shims.ts",
40
+ "!src/testing/react-flow-test-shims.ts",
41
+ "!src/testing/vitest.setup.ts",
42
+ "!src/vite-aliases.ts"
43
+ ],
44
+ "sideEffects": [
45
+ "*.css",
46
+ "**/*.css"
47
+ ],
48
+ "exports": {
49
+ ".": {
50
+ "types": "./src/index.ts",
51
+ "default": "./src/index.ts"
52
+ },
53
+ "./styles.css": "./src/styles.css",
54
+ "./primitives": {
55
+ "types": "./src/primitives/index.ts",
56
+ "default": "./src/primitives/index.ts"
57
+ },
58
+ "./forms": {
59
+ "types": "./src/forms/index.ts",
60
+ "default": "./src/forms/index.ts"
61
+ },
62
+ "./layout": {
63
+ "types": "./src/layout/index.ts",
64
+ "default": "./src/layout/index.ts"
65
+ },
66
+ "./feedback": {
67
+ "types": "./src/feedback/index.ts",
68
+ "default": "./src/feedback/index.ts"
69
+ },
70
+ "./data-display": {
71
+ "types": "./src/data-display/index.ts",
72
+ "default": "./src/data-display/index.ts"
73
+ },
74
+ "./navigation": {
75
+ "types": "./src/navigation/index.ts",
76
+ "default": "./src/navigation/index.ts"
77
+ },
78
+ "./overlays": {
79
+ "types": "./src/overlays/index.ts",
80
+ "default": "./src/overlays/index.ts"
81
+ },
82
+ "./charts": {
83
+ "types": "./src/charts/index.ts",
84
+ "default": "./src/charts/index.ts"
85
+ },
86
+ "./graphs": {
87
+ "types": "./src/graphs/index.ts",
88
+ "default": "./src/graphs/index.ts"
89
+ },
90
+ "./recipes": {
91
+ "types": "./src/recipes/index.ts",
92
+ "default": "./src/recipes/index.ts"
93
+ },
94
+ "./icons": {
95
+ "types": "./src/icons/index.ts",
96
+ "default": "./src/icons/index.ts"
97
+ },
98
+ "./utilities": {
99
+ "types": "./src/utilities/index.ts",
100
+ "default": "./src/utilities/index.ts"
101
+ },
102
+ "./testing": {
103
+ "types": "./src/testing/index.ts",
104
+ "default": "./src/testing/index.ts"
105
+ },
106
+ "./tokens": {
107
+ "types": "./src/tokens/index.ts",
108
+ "default": "./src/tokens/index.ts"
109
+ }
110
+ },
111
+ "scripts": {
112
+ "build-storybook": "storybook build --loglevel warn",
113
+ "check:package-boundary": "node scripts/check-package-boundary.mjs",
114
+ "check:package-dependency-direction": "node scripts/check-package-dependency-direction.mjs",
115
+ "storybook": "storybook dev -p 6017",
116
+ "test": "bun run test:unit && bun run check:package-boundary && bun run check:package-dependency-direction",
117
+ "test:unit": "vitest run --config vitest.config.ts",
118
+ "typecheck": "tsc -b --noEmit --pretty false",
119
+ "verify": "bun run typecheck && bun run test:unit && bun run build-storybook && bun run check:package-boundary && bun run check:package-dependency-direction",
120
+ "verify:form-field-storybook-browser": "node scripts/verify-package-form-field-storybook-browser.mjs",
121
+ "verify:graph-storybook-viewport-browser": "node scripts/verify-graph-storybook-viewport-browser.mjs",
122
+ "verify:storybook-browser": "node scripts/verify-package-storybook-browser.mjs",
123
+ "verify:storybook-layout-responsive": "node scripts/run-package-layout-display-browser-check.mjs",
124
+ "verify:widget-frame-docs": "node scripts/verify-widget-frame-storybook-docs.mjs",
125
+ "verify:widget-frame-responsive": "node scripts/verify-widget-frame-storybook-responsive.mjs"
126
+ },
127
+ "dependencies": {
128
+ "@radix-ui/react-collapsible": "^1.1.12",
129
+ "@radix-ui/react-dialog": "^1.1.15",
130
+ "@radix-ui/react-popover": "^1.1.15",
131
+ "@radix-ui/react-scroll-area": "^1.2.10",
132
+ "@radix-ui/react-select": "^2.3.0",
133
+ "@radix-ui/react-slot": "^1.2.3",
134
+ "@xyflow/react": "^12.10.2",
135
+ "recharts": "^3.8.1"
136
+ },
137
+ "peerDependencies": {
138
+ "react": "^19.0.0",
139
+ "react-dom": "^19.0.0"
140
+ },
141
+ "devDependencies": {
142
+ "@storybook/react-vite": "^10.3.5",
143
+ "@tailwindcss/node": "^4.2.2",
144
+ "@tailwindcss/vite": "^4.2.2",
145
+ "@vitejs/plugin-react-swc": "^4.1.0",
146
+ "@testing-library/jest-dom": "^6.9.1",
147
+ "@testing-library/react": "^16.3.0",
148
+ "@testing-library/user-event": "^14.6.1",
149
+ "@types/react": "^19.2.2",
150
+ "@types/react-dom": "^19.2.2",
151
+ "happy-dom": "^20.9.0",
152
+ "jest-axe": "^10.0.0",
153
+ "react": "^19.0.0",
154
+ "react-dom": "^19.0.0",
155
+ "storybook": "^10.3.5",
156
+ "tailwindcss": "^4.2.2",
157
+ "typescript": "~5.9.3",
158
+ "vite": "^7.1.7",
159
+ "vitest": "4.1.3"
160
+ }
161
+ }
@@ -0,0 +1,20 @@
1
+ /** Planned deep import paths for `@you-agent-factory/components` category entrypoints. */
2
+ export const COMPONENT_CATEGORY_EXPORT_PATHS = [
3
+ "primitives",
4
+ "forms",
5
+ "layout",
6
+ "feedback",
7
+ "data-display",
8
+ "navigation",
9
+ "overlays",
10
+ "charts",
11
+ "graphs",
12
+ "recipes",
13
+ "icons",
14
+ "utilities",
15
+ "testing",
16
+ "tokens",
17
+ ] as const;
18
+
19
+ export type ComponentCategoryExportPath =
20
+ (typeof COMPONENT_CATEGORY_EXPORT_PATHS)[number];
@@ -0,0 +1,103 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+
3
+ import { cn } from "../utilities/cn";
4
+
5
+ import type { ChartPresentation } from "./chart";
6
+
7
+ export type ChartStateStatus = "empty" | "error" | "loading" | "success";
8
+
9
+ export interface ChartStatePanelProps extends HTMLAttributes<HTMLDivElement> {
10
+ action?: ReactNode;
11
+ description: string;
12
+ presentation?: ChartPresentation;
13
+ status: ChartStateStatus;
14
+ title: string;
15
+ }
16
+
17
+ // tailwind-exception: intrinsic-sizing
18
+ const CHART_STATE_PANEL_CLASS =
19
+ "flex h-full min-h-[14rem] min-w-0 w-full flex-1 flex-col justify-center";
20
+ // tailwind-exception: intrinsic-sizing
21
+ const CHART_STATE_PANEL_EMBEDDED_CLASS =
22
+ "grid min-h-[14rem] min-w-0 w-full flex-1 flex-col items-start justify-center gap-1.5 p-0 [&_h3]:m-0";
23
+ const CHART_STATE_PANEL_STANDALONE_SHELL_CLASS =
24
+ "grid min-h-60 items-start gap-1.5 rounded-2xl border border-dashed border-outline-variant bg-surface-container-low p-5 [&_h3]:m-0";
25
+ const CHART_STATE_PANEL_TITLE_CLASS =
26
+ "m-0 text-title-medium font-semibold text-on-surface";
27
+ const CHART_STATE_PANEL_DESCRIPTION_CLASS = "m-0 text-body-medium text-on-surface-variant";
28
+ const CHART_STATE_PANEL_SKELETON_CLASS = "animate-pulse rounded-xl bg-af-overlay";
29
+
30
+ function chartStateRole(status: ChartStateStatus): "alert" | "status" {
31
+ return status === "error" ? "alert" : "status";
32
+ }
33
+
34
+ function chartStateLive(status: ChartStateStatus): "assertive" | "polite" {
35
+ return status === "error" ? "assertive" : "polite";
36
+ }
37
+
38
+ export function ChartStatePanel({
39
+ action,
40
+ className,
41
+ description,
42
+ presentation = "standalone",
43
+ status,
44
+ title,
45
+ ...props
46
+ }: ChartStatePanelProps) {
47
+ const embedded = presentation === "embedded";
48
+ const role = chartStateRole(status);
49
+ const ariaLive = chartStateLive(status);
50
+ const loading = status === "loading";
51
+
52
+ const content = (
53
+ <>
54
+ {loading ? (
55
+ <div aria-hidden="true" className="grid w-full gap-3">
56
+ <div className={cn(CHART_STATE_PANEL_SKELETON_CLASS, "h-4 w-32")} />
57
+ <div className={cn(CHART_STATE_PANEL_SKELETON_CLASS, "h-28 w-full")} />
58
+ </div>
59
+ ) : null}
60
+ <h3 className={CHART_STATE_PANEL_TITLE_CLASS}>{title}</h3>
61
+ <p className={CHART_STATE_PANEL_DESCRIPTION_CLASS}>{description}</p>
62
+ {action ? <div className="mt-2">{action}</div> : null}
63
+ </>
64
+ );
65
+
66
+ if (!embedded) {
67
+ return (
68
+ <div
69
+ aria-busy={loading || undefined}
70
+ aria-live={ariaLive}
71
+ className={cn(
72
+ CHART_STATE_PANEL_STANDALONE_SHELL_CLASS,
73
+ CHART_STATE_PANEL_CLASS,
74
+ className,
75
+ )}
76
+ data-chart-presentation={presentation}
77
+ data-chart-state={status}
78
+ role={role}
79
+ {...props}
80
+ >
81
+ {content}
82
+ </div>
83
+ );
84
+ }
85
+
86
+ return (
87
+ <div
88
+ aria-busy={loading || undefined}
89
+ aria-live={ariaLive}
90
+ className={cn(
91
+ CHART_STATE_PANEL_EMBEDDED_CLASS,
92
+ CHART_STATE_PANEL_CLASS,
93
+ className,
94
+ )}
95
+ data-chart-presentation={presentation}
96
+ data-chart-state={status}
97
+ role={role}
98
+ {...props}
99
+ >
100
+ {content}
101
+ </div>
102
+ );
103
+ }