@petrarca/sonnet-playground 0.3.0 → 0.4.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/README.md +142 -0
- package/dist/{PlayCoreComponents-F2OFSQZK.js → PlayCoreComponents-GXFMB24T.js} +2 -2
- package/dist/{PlayDataComponents-BA3NA225.js → PlayDataComponents-M4SJ4XEL.js} +2 -2
- package/dist/{PlayFormComponents-MZC7CNES.js → PlayFormComponents-4E2A2Y2W.js} +2 -2
- package/dist/PlayGraph-3F56PREG.js +7 -0
- package/dist/{PlayShellApi-3T4FZPEV.js → PlayShellApi-5O6VYR2X.js} +2 -2
- package/dist/{chunk-MT4ILA37.js → chunk-32DDRRWU.js} +63 -9
- package/dist/chunk-32DDRRWU.js.map +1 -0
- package/dist/{chunk-4S2ITDB3.js → chunk-CQ6PGFRV.js} +21 -2
- package/dist/chunk-CQ6PGFRV.js.map +1 -0
- package/dist/{chunk-SBKZRIJC.js → chunk-VOC5VZG2.js} +48 -5
- package/dist/chunk-VOC5VZG2.js.map +1 -0
- package/dist/{chunk-DKLALDHR.js → chunk-YEBK2TUW.js} +2 -2
- package/dist/chunk-YEBK2TUW.js.map +1 -0
- package/dist/{chunk-QCK2M4KD.js → chunk-YOOWJORD.js} +28 -1
- package/dist/chunk-YOOWJORD.js.map +1 -0
- package/dist/index.js +5 -5
- package/dist/pages/index.js +5 -5
- package/package.json +6 -6
- package/dist/PlayGraph-RHFIDAS3.js +0 -7
- package/dist/chunk-4S2ITDB3.js.map +0 -1
- package/dist/chunk-DKLALDHR.js.map +0 -1
- package/dist/chunk-MT4ILA37.js.map +0 -1
- package/dist/chunk-QCK2M4KD.js.map +0 -1
- package/dist/chunk-SBKZRIJC.js.map +0 -1
- /package/dist/{PlayCoreComponents-F2OFSQZK.js.map → PlayCoreComponents-GXFMB24T.js.map} +0 -0
- /package/dist/{PlayDataComponents-BA3NA225.js.map → PlayDataComponents-M4SJ4XEL.js.map} +0 -0
- /package/dist/{PlayFormComponents-MZC7CNES.js.map → PlayFormComponents-4E2A2Y2W.js.map} +0 -0
- /package/dist/{PlayGraph-RHFIDAS3.js.map → PlayGraph-3F56PREG.js.map} +0 -0
- /package/dist/{PlayShellApi-3T4FZPEV.js.map → PlayShellApi-5O6VYR2X.js.map} +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# @petrarca/sonnet-playground
|
|
2
|
+
|
|
3
|
+
Playground framework and built-in component demos for the Petrarca Sonnet
|
|
4
|
+
component library.
|
|
5
|
+
|
|
6
|
+
## What's included
|
|
7
|
+
|
|
8
|
+
**Playground framework** — Registry, overview tile grid, and `createPlaygroundModule()`
|
|
9
|
+
factory. Wire a playground into any `sonnet-shell` app with a few lines.
|
|
10
|
+
|
|
11
|
+
**Built-in demos** — Pre-built showcase pages for all Sonnet components:
|
|
12
|
+
Typography, Color Palette, Core UI, Advanced Components, JSON Editor, Forms,
|
|
13
|
+
Form Components, Form Widgets, Data Components, Graph Visualization, Shell API.
|
|
14
|
+
|
|
15
|
+
**PlaygroundSection** — Shared section wrapper (`default` and `card` variants)
|
|
16
|
+
used by all playground pages.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm add @petrarca/sonnet-playground
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Peer dependencies: `react`, `react-dom`, `@petrarca/sonnet-shell`,
|
|
27
|
+
`@petrarca/sonnet-ui`, `@petrarca/sonnet-forms`, `@petrarca/sonnet-graph`.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Basic usage
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// src/modules/playground/index.ts
|
|
35
|
+
import {
|
|
36
|
+
createPlaygroundRegistry,
|
|
37
|
+
createPlaygroundModule,
|
|
38
|
+
} from "@petrarca/sonnet-playground";
|
|
39
|
+
|
|
40
|
+
const registry = createPlaygroundRegistry();
|
|
41
|
+
|
|
42
|
+
// Optionally add app-specific pages:
|
|
43
|
+
registry.register({
|
|
44
|
+
id: "app.my-page",
|
|
45
|
+
title: "My Page",
|
|
46
|
+
description: "Custom demo page.",
|
|
47
|
+
icon: SomeIcon,
|
|
48
|
+
color: "teal",
|
|
49
|
+
path: "my-page",
|
|
50
|
+
component: React.lazy(() => import("./pages/MyPage")),
|
|
51
|
+
group: "App",
|
|
52
|
+
order: 0,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export default createPlaygroundModule(registry);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// src/modules/registry.ts
|
|
60
|
+
import { createModuleRegistry } from "@petrarca/sonnet-shell";
|
|
61
|
+
import home from "./home";
|
|
62
|
+
import playground from "./playground";
|
|
63
|
+
|
|
64
|
+
export const registry = createModuleRegistry([
|
|
65
|
+
home,
|
|
66
|
+
playground, // pinBottom: true is set automatically by createPlaygroundModule
|
|
67
|
+
]);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`createPlaygroundModule` returns a `ShellModule` — pass it directly to
|
|
71
|
+
`createModuleRegistry` alongside your app's own modules.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Adding app-specific pages
|
|
76
|
+
|
|
77
|
+
Register your own pages alongside the built-in demos by calling
|
|
78
|
+
`registry.register()` before passing the registry to `createPlaygroundModule`.
|
|
79
|
+
Pages appear in the overview tile grid grouped under your chosen `group` label.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// src/modules/playground/index.ts
|
|
83
|
+
import { lazy } from "react";
|
|
84
|
+
import { Search } from "lucide-react";
|
|
85
|
+
import {
|
|
86
|
+
createPlaygroundRegistry,
|
|
87
|
+
createPlaygroundModule,
|
|
88
|
+
} from "@petrarca/sonnet-playground";
|
|
89
|
+
|
|
90
|
+
const registry = createPlaygroundRegistry();
|
|
91
|
+
|
|
92
|
+
// Register app-specific pages
|
|
93
|
+
registry.register({
|
|
94
|
+
id: "app.my-widget",
|
|
95
|
+
title: "My Widget",
|
|
96
|
+
description: "Interactive demo of MyWidget with live configuration.",
|
|
97
|
+
icon: Search,
|
|
98
|
+
color: "teal",
|
|
99
|
+
path: "my-widget",
|
|
100
|
+
component: lazy(() => import("./pages/PlayMyWidget")),
|
|
101
|
+
group: "App Components", // appears as a group heading in the overview
|
|
102
|
+
order: 0,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
export default createPlaygroundModule(registry);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Pages are lazy-loaded automatically — wrap the component in `React.lazy()`
|
|
109
|
+
as shown above. The framework handles the `Suspense` boundary.
|
|
110
|
+
|
|
111
|
+
`group` is optional. Pages without a group appear under the default group in
|
|
112
|
+
the overview. Pages with the same `group` string are grouped together.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Pages subpath
|
|
117
|
+
|
|
118
|
+
Individual built-in pages are available at `@petrarca/sonnet-playground/pages`
|
|
119
|
+
for consumers who want to cherry-pick or re-export them:
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import { PlayTypography, PlayColorPalette } from "@petrarca/sonnet-playground/pages";
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## createPlaygroundModule options
|
|
128
|
+
|
|
129
|
+
| Option | Type | Default |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| `icon` | `LucideIcon` | `FlaskConical` |
|
|
132
|
+
| `label` | `string` | `"Playground"` |
|
|
133
|
+
| `basePath` | `string` | `"/playground"` |
|
|
134
|
+
| `overviewTitle` | `string` | `"Developer Playground"` |
|
|
135
|
+
| `overviewSubtitle` | `string` | `""` |
|
|
136
|
+
| `grouped` | `boolean` | `true` |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
See [LICENSE.md](../../LICENSE.md).
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PlayCoreComponents
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YOOWJORD.js";
|
|
4
4
|
import "./chunk-C2EZ2ECG.js";
|
|
5
5
|
export {
|
|
6
6
|
PlayCoreComponents as default
|
|
7
7
|
};
|
|
8
|
-
//# sourceMappingURL=PlayCoreComponents-
|
|
8
|
+
//# sourceMappingURL=PlayCoreComponents-GXFMB24T.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PlayDataComponents
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YEBK2TUW.js";
|
|
4
4
|
import "./chunk-C2EZ2ECG.js";
|
|
5
5
|
export {
|
|
6
6
|
PlayDataComponents as default
|
|
7
7
|
};
|
|
8
|
-
//# sourceMappingURL=PlayDataComponents-
|
|
8
|
+
//# sourceMappingURL=PlayDataComponents-M4SJ4XEL.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PlayFormComponents
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-32DDRRWU.js";
|
|
4
4
|
import "./chunk-C2EZ2ECG.js";
|
|
5
5
|
export {
|
|
6
6
|
PlayFormComponents as default
|
|
7
7
|
};
|
|
8
|
-
//# sourceMappingURL=PlayFormComponents-
|
|
8
|
+
//# sourceMappingURL=PlayFormComponents-4E2A2Y2W.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PlayShellApi
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CQ6PGFRV.js";
|
|
4
4
|
import "./chunk-C2EZ2ECG.js";
|
|
5
5
|
export {
|
|
6
6
|
PlayShellApi as default
|
|
7
7
|
};
|
|
8
|
-
//# sourceMappingURL=PlayShellApi-
|
|
8
|
+
//# sourceMappingURL=PlayShellApi-5O6VYR2X.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-C2EZ2ECG.js";
|
|
4
4
|
|
|
5
5
|
// src/pages/PlayFormComponents.tsx
|
|
6
|
-
import { useState } from "react";
|
|
6
|
+
import { useState, useCallback, useRef } from "react";
|
|
7
7
|
import { SimpleStack, Card } from "@petrarca/sonnet-ui";
|
|
8
8
|
import {
|
|
9
9
|
FormInput,
|
|
@@ -18,8 +18,16 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
18
18
|
function PlayFormComponents() {
|
|
19
19
|
const [textValue, setTextValue] = useState("");
|
|
20
20
|
const [emailValue, setEmailValue] = useState("");
|
|
21
|
+
const [emailError, setEmailError] = useState("");
|
|
21
22
|
const [passwordValue, setPasswordValue] = useState("");
|
|
22
|
-
const
|
|
23
|
+
const validateEmail = useCallback((value) => {
|
|
24
|
+
if (!value) {
|
|
25
|
+
setEmailError("");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
29
|
+
setEmailError(valid ? "" : "Invalid email address");
|
|
30
|
+
}, []);
|
|
23
31
|
const [textareaValue, setTextareaValue] = useState("");
|
|
24
32
|
const [textareaError, setTextareaError] = useState("");
|
|
25
33
|
const [numberValue, setNumberValue] = useState(void 0);
|
|
@@ -27,6 +35,19 @@ function PlayFormComponents() {
|
|
|
27
35
|
const [decimalValue, setDecimalValue] = useState(
|
|
28
36
|
void 0
|
|
29
37
|
);
|
|
38
|
+
const [rangeValidated, setRangeValidated] = useState(
|
|
39
|
+
void 0
|
|
40
|
+
);
|
|
41
|
+
const [rangeError, setRangeError] = useState("");
|
|
42
|
+
const rangeValidatedRef = useRef(void 0);
|
|
43
|
+
const validateRange = useCallback((value) => {
|
|
44
|
+
if (value === void 0) {
|
|
45
|
+
setRangeError("");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (value < 1 || value > 10) setRangeError("Must be between 1 and 10");
|
|
49
|
+
else setRangeError("");
|
|
50
|
+
}, []);
|
|
30
51
|
const [checkboxValue, setCheckboxValue] = useState(false);
|
|
31
52
|
const [checkboxIndeterminate, setCheckboxIndeterminate] = useState("indeterminate");
|
|
32
53
|
const [selectValue, setSelectValue] = useState("");
|
|
@@ -88,7 +109,7 @@ function PlayFormComponents() {
|
|
|
88
109
|
placeholder: "john@example.com"
|
|
89
110
|
}
|
|
90
111
|
) }),
|
|
91
|
-
/* @__PURE__ */ jsx(ExampleBlock, { label: "
|
|
112
|
+
/* @__PURE__ */ jsx(ExampleBlock, { label: "WITH ERROR (STATIC)", children: /* @__PURE__ */ jsx(
|
|
92
113
|
FormInput,
|
|
93
114
|
{
|
|
94
115
|
label: "Email",
|
|
@@ -98,6 +119,21 @@ function PlayFormComponents() {
|
|
|
98
119
|
placeholder: "john@example.com"
|
|
99
120
|
}
|
|
100
121
|
) }),
|
|
122
|
+
/* @__PURE__ */ jsx(ExampleBlock, { label: "Email (on-blur validation)", children: /* @__PURE__ */ jsx(
|
|
123
|
+
FormInput,
|
|
124
|
+
{
|
|
125
|
+
label: "Email",
|
|
126
|
+
type: "email",
|
|
127
|
+
value: emailValue,
|
|
128
|
+
onChange: (e) => {
|
|
129
|
+
setEmailValue(e.target.value);
|
|
130
|
+
if (emailError) validateEmail(e.target.value);
|
|
131
|
+
},
|
|
132
|
+
onBlur: (e) => validateEmail(e.target.value),
|
|
133
|
+
error: emailError,
|
|
134
|
+
placeholder: "user@example.com"
|
|
135
|
+
}
|
|
136
|
+
) }),
|
|
101
137
|
/* @__PURE__ */ jsx(ExampleBlock, { label: "Password", children: /* @__PURE__ */ jsx(
|
|
102
138
|
FormInput,
|
|
103
139
|
{
|
|
@@ -249,7 +285,7 @@ function PlayFormComponents() {
|
|
|
249
285
|
placeholder: "0"
|
|
250
286
|
}
|
|
251
287
|
) }),
|
|
252
|
-
/* @__PURE__ */ jsx(ExampleBlock, { label: "
|
|
288
|
+
/* @__PURE__ */ jsx(ExampleBlock, { label: "WITH ERROR (STATIC)", children: /* @__PURE__ */ jsx(
|
|
253
289
|
FormNumberInput,
|
|
254
290
|
{
|
|
255
291
|
label: "Invalid Input",
|
|
@@ -257,6 +293,24 @@ function PlayFormComponents() {
|
|
|
257
293
|
onChange: setNumberValue,
|
|
258
294
|
error: "Value must be greater than 0"
|
|
259
295
|
}
|
|
296
|
+
) }),
|
|
297
|
+
/* @__PURE__ */ jsx(ExampleBlock, { label: "Range (on-blur validation)", children: /* @__PURE__ */ jsx(
|
|
298
|
+
FormNumberInput,
|
|
299
|
+
{
|
|
300
|
+
label: "Rating (1\u201310)",
|
|
301
|
+
value: rangeValidated,
|
|
302
|
+
onChange: (v) => {
|
|
303
|
+
setRangeValidated(v);
|
|
304
|
+
rangeValidatedRef.current = v;
|
|
305
|
+
if (rangeError) validateRange(v);
|
|
306
|
+
},
|
|
307
|
+
onBlur: () => validateRange(rangeValidatedRef.current),
|
|
308
|
+
error: rangeError,
|
|
309
|
+
min: 1,
|
|
310
|
+
max: 10,
|
|
311
|
+
step: 1,
|
|
312
|
+
placeholder: "1\u201310"
|
|
313
|
+
}
|
|
260
314
|
) })
|
|
261
315
|
] }),
|
|
262
316
|
/* @__PURE__ */ jsx("pre", { className: "text-xs bg-muted p-2 rounded overflow-x-auto", children: /* @__PURE__ */ jsx("code", { children: `<FormNumberInput
|
|
@@ -322,7 +376,7 @@ function PlayFormComponents() {
|
|
|
322
376
|
disabled: true
|
|
323
377
|
}
|
|
324
378
|
) }),
|
|
325
|
-
/* @__PURE__ */ jsx(ExampleBlock, { label: "
|
|
379
|
+
/* @__PURE__ */ jsx(ExampleBlock, { label: "WITH ERROR (STATIC)", children: /* @__PURE__ */ jsx(
|
|
326
380
|
FormCheckbox,
|
|
327
381
|
{
|
|
328
382
|
label: "Required checkbox",
|
|
@@ -392,7 +446,7 @@ function PlayFormComponents() {
|
|
|
392
446
|
placeholder: "Cannot change"
|
|
393
447
|
}
|
|
394
448
|
) }),
|
|
395
|
-
/* @__PURE__ */ jsx(ExampleBlock, { label: "
|
|
449
|
+
/* @__PURE__ */ jsx(ExampleBlock, { label: "WITH ERROR (STATIC)", children: /* @__PURE__ */ jsx(
|
|
396
450
|
FormSelect,
|
|
397
451
|
{
|
|
398
452
|
label: "Invalid Selection",
|
|
@@ -460,7 +514,7 @@ function PlayFormComponents() {
|
|
|
460
514
|
placeholder: "Select at least one skill"
|
|
461
515
|
}
|
|
462
516
|
) }),
|
|
463
|
-
/* @__PURE__ */ jsx(ExampleBlock, { label: "
|
|
517
|
+
/* @__PURE__ */ jsx(ExampleBlock, { label: "WITH ERROR (STATIC)", children: /* @__PURE__ */ jsx(
|
|
464
518
|
FormMultiSelect,
|
|
465
519
|
{
|
|
466
520
|
label: "Categories",
|
|
@@ -518,7 +572,7 @@ function PlayFormComponents() {
|
|
|
518
572
|
placeholder: "Add at least one keyword"
|
|
519
573
|
}
|
|
520
574
|
) }),
|
|
521
|
-
/* @__PURE__ */ jsx(ExampleBlock, { label: "
|
|
575
|
+
/* @__PURE__ */ jsx(ExampleBlock, { label: "WITH ERROR (STATIC)", children: /* @__PURE__ */ jsx(
|
|
522
576
|
FormTagsInput,
|
|
523
577
|
{
|
|
524
578
|
label: "Tags",
|
|
@@ -560,4 +614,4 @@ function PlayFormComponents() {
|
|
|
560
614
|
export {
|
|
561
615
|
PlayFormComponents
|
|
562
616
|
};
|
|
563
|
-
//# sourceMappingURL=chunk-
|
|
617
|
+
//# sourceMappingURL=chunk-32DDRRWU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pages/PlayFormComponents.tsx"],"sourcesContent":["/**\n * Playground page for testing Form components\n * Accessible at /playground/form-components\n *\n * Tests all custom Form wrapper components that provide consistent\n * label, description, and error handling around base UI components.\n */\n\nimport { useState, useCallback, useRef } from \"react\";\nimport { SimpleStack, Card } from \"@petrarca/sonnet-ui\";\nimport { ExampleBlock } from \"../PlaygroundSection\";\nimport {\n FormInput,\n FormTextarea,\n FormNumberInput,\n FormCheckbox,\n FormSelect,\n FormMultiSelect,\n FormTagsInput,\n} from \"@petrarca/sonnet-forms\";\n\nexport default function PlayFormComponents() {\n // FormInput states\n const [textValue, setTextValue] = useState(\"\");\n const [emailValue, setEmailValue] = useState(\"\");\n const [emailError, setEmailError] = useState(\"\");\n const [passwordValue, setPasswordValue] = useState(\"\");\n\n const validateEmail = useCallback((value: string) => {\n if (!value) {\n setEmailError(\"\");\n return;\n }\n const valid = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\n setEmailError(valid ? \"\" : \"Invalid email address\");\n }, []);\n\n // FormTextarea states\n const [textareaValue, setTextareaValue] = useState(\"\");\n const [textareaError, setTextareaError] = useState(\"\");\n\n // FormNumberInput states\n const [numberValue, setNumberValue] = useState<number | undefined>(undefined);\n const [rangeValue, setRangeValue] = useState<number | undefined>(5);\n const [decimalValue, setDecimalValue] = useState<number | undefined>(\n undefined,\n );\n const [rangeValidated, setRangeValidated] = useState<number | undefined>(\n undefined,\n );\n const [rangeError, setRangeError] = useState(\"\");\n const rangeValidatedRef = useRef<number | undefined>(undefined);\n\n const validateRange = useCallback((value: number | undefined) => {\n if (value === undefined) {\n setRangeError(\"\");\n return;\n }\n if (value < 1 || value > 10) setRangeError(\"Must be between 1 and 10\");\n else setRangeError(\"\");\n }, []);\n\n // FormCheckbox states\n const [checkboxValue, setCheckboxValue] = useState(false);\n const [checkboxIndeterminate, setCheckboxIndeterminate] = useState<\n boolean | \"indeterminate\"\n >(\"indeterminate\");\n\n // FormSelect states\n const [selectValue, setSelectValue] = useState(\"\");\n const [selectRequired, setSelectRequired] = useState(\"\");\n\n // FormMultiSelect states\n const [multiSelectValue, setMultiSelectValue] = useState<string[]>([]);\n\n // FormTagsInput states\n const [tagsValue, setTagsValue] = useState<string[]>([\"react\", \"typescript\"]);\n\n // Options for selects\n const colorOptions = [\n { label: \"Red\", value: \"red\" },\n { label: \"Green\", value: \"green\" },\n { label: \"Blue\", value: \"blue\" },\n { label: \"Yellow\", value: \"yellow\" },\n { label: \"Purple\", value: \"purple\" },\n ];\n\n const countryOptions = [\n { label: \"United States\", value: \"us\" },\n { label: \"Canada\", value: \"ca\" },\n { label: \"United Kingdom\", value: \"uk\" },\n { label: \"Germany\", value: \"de\" },\n { label: \"France\", value: \"fr\" },\n { label: \"Japan\", value: \"jp\" },\n { label: \"Australia\", value: \"au\" },\n ];\n\n return (\n <div className=\"w-full max-w-4xl space-y-6\">\n <div>\n <h1>Form Components Playground</h1>\n <p className=\"text-sm text-muted-foreground mb-3\">\n Test all custom Form wrapper components with labels, descriptions, and\n error states\n </p>\n </div>\n\n <div>\n <SimpleStack gap=\"md\" style={{ maxWidth: \"900px\" }}>\n {/* FormInput */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>FormInput</h2>\n <p className=\"text-sm text-muted-foreground\">\n Text input wrapper with label, description, and error support.\n Supports all HTML input types.\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Basic\">\n <FormInput\n label=\"Username\"\n value={textValue}\n onChange={(e) => setTextValue(e.target.value)}\n placeholder=\"Enter username\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"With description\">\n <FormInput\n label=\"Full Name\"\n description=\"Your first and last name\"\n value={textValue}\n onChange={(e) => setTextValue(e.target.value)}\n placeholder=\"John Doe\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Required\">\n <FormInput\n label=\"Email\"\n required\n value={emailValue}\n onChange={(e) => setEmailValue(e.target.value)}\n placeholder=\"john@example.com\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"WITH ERROR (STATIC)\">\n <FormInput\n label=\"Email\"\n value={emailValue}\n onChange={(e) => setEmailValue(e.target.value)}\n error=\"Invalid email format\"\n placeholder=\"john@example.com\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Email (on-blur validation)\">\n <FormInput\n label=\"Email\"\n type=\"email\"\n value={emailValue}\n onChange={(e) => {\n setEmailValue(e.target.value);\n if (emailError) validateEmail(e.target.value);\n }}\n onBlur={(e) => validateEmail(e.target.value)}\n error={emailError}\n placeholder=\"user@example.com\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Password\">\n <FormInput\n label=\"Password\"\n type=\"password\"\n value={passwordValue}\n onChange={(e) => setPasswordValue(e.target.value)}\n placeholder=\"••••••••\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Disabled\">\n <FormInput\n label=\"Readonly Field\"\n value=\"Cannot edit this\"\n onChange={() => {}}\n disabled\n />\n </ExampleBlock>\n </div>\n\n <pre className=\"text-xs bg-muted p-2 rounded overflow-x-auto\">\n <code>{`<FormInput\n label=\"Username\"\n value={textValue}\n onChange={(e) => setTextValue(e.target.value)}\n placeholder=\"Enter username\"\n description=\"Optional description\"\n error=\"Optional error message\"\n required={false}\n disabled={false}\n/>`}</code>\n </pre>\n\n <p className=\"text-xs text-muted-foreground\">\n Current value: {textValue || \"(empty)\"}\n </p>\n </SimpleStack>\n </Card>\n\n {/* FormTextarea */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>FormTextarea</h2>\n <p className=\"text-sm text-muted-foreground\">\n Multi-line text input with label, description, and error\n support.\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Basic\">\n <FormTextarea\n label=\"Description\"\n value={textareaValue}\n onChange={(e) => setTextareaValue(e.target.value)}\n placeholder=\"Enter a detailed description...\"\n rows={4}\n />\n </ExampleBlock>\n <ExampleBlock label=\"With description\">\n <FormTextarea\n label=\"Bio\"\n description=\"Tell us about yourself (max 500 characters)\"\n value={textareaValue}\n onChange={(e) => setTextareaValue(e.target.value)}\n placeholder=\"I am a...\"\n rows={3}\n />\n </ExampleBlock>\n <ExampleBlock label=\"With error validation\">\n <FormTextarea\n label=\"Comments\"\n value={textareaValue}\n onChange={(e) => {\n setTextareaValue(e.target.value);\n setTextareaError(\n e.target.value.length > 100\n ? \"Maximum 100 characters allowed\"\n : \"\",\n );\n }}\n error={textareaError}\n placeholder=\"Enter your comments...\"\n rows={3}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Disabled\">\n <FormTextarea\n label=\"Readonly Text\"\n value=\"This cannot be edited\"\n onChange={() => {}}\n disabled\n rows={2}\n />\n </ExampleBlock>\n </div>\n\n <pre className=\"text-xs bg-muted p-2 rounded overflow-x-auto\">\n <code>{`<FormTextarea\n label=\"Description\"\n value={textareaValue}\n onChange={(e) => setTextareaValue(e.target.value)}\n placeholder=\"Enter text...\"\n rows={4}\n description=\"Optional description\"\n error=\"Optional error message\"\n/>`}</code>\n </pre>\n\n <p className=\"text-xs text-muted-foreground\">\n Current value: {textareaValue || \"(empty)\"}\n </p>\n </SimpleStack>\n </Card>\n\n {/* FormNumberInput */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>FormNumberInput</h2>\n <p className=\"text-sm text-muted-foreground\">\n Number input with min/max validation and step control.\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Basic\">\n <FormNumberInput\n label=\"Age\"\n value={numberValue}\n onChange={setNumberValue}\n placeholder=\"Enter age\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"With min/max/step\">\n <FormNumberInput\n label=\"Rating (1-10)\"\n value={rangeValue}\n onChange={setRangeValue}\n min={1}\n max={10}\n step={1}\n description=\"Rate from 1 to 10\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Decimal\">\n <FormNumberInput\n label=\"Price\"\n value={decimalValue}\n onChange={setDecimalValue}\n allowDecimal={true}\n step={0.01}\n placeholder=\"0.00\"\n description=\"Enter price with cents\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Required\">\n <FormNumberInput\n label=\"Quantity\"\n required\n value={numberValue}\n onChange={setNumberValue}\n min={0}\n placeholder=\"0\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"WITH ERROR (STATIC)\">\n <FormNumberInput\n label=\"Invalid Input\"\n value={numberValue}\n onChange={setNumberValue}\n error=\"Value must be greater than 0\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Range (on-blur validation)\">\n <FormNumberInput\n label=\"Rating (1–10)\"\n value={rangeValidated}\n onChange={(v) => {\n setRangeValidated(v);\n rangeValidatedRef.current = v;\n if (rangeError) validateRange(v);\n }}\n onBlur={() => validateRange(rangeValidatedRef.current)}\n error={rangeError}\n min={1}\n max={10}\n step={1}\n placeholder=\"1–10\"\n />\n </ExampleBlock>\n </div>\n\n <pre className=\"text-xs bg-muted p-2 rounded overflow-x-auto\">\n <code>{`<FormNumberInput\n label=\"Age\"\n value={numberValue}\n onChange={setNumberValue}\n min={0}\n max={120}\n step={1}\n allowDecimal={false}\n/>`}</code>\n </pre>\n\n <p className=\"text-xs text-muted-foreground\">\n Current value: {numberValue ?? \"(empty)\"}\n </p>\n </SimpleStack>\n </Card>\n\n {/* FormCheckbox */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>FormCheckbox</h2>\n <p className=\"text-sm text-muted-foreground\">\n Checkbox with label, description, and indeterminate state\n support.\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Basic\">\n <FormCheckbox\n label=\"Accept terms and conditions\"\n checked={checkboxValue}\n onChange={(checked) => setCheckboxValue(checked === true)}\n />\n </ExampleBlock>\n <ExampleBlock label=\"With description\">\n <FormCheckbox\n label=\"Subscribe to newsletter\"\n description=\"Receive weekly updates about new features\"\n checked={checkboxValue}\n onChange={(checked) => setCheckboxValue(checked === true)}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Required\">\n <FormCheckbox\n label=\"I agree to the privacy policy\"\n required\n checked={checkboxValue}\n onChange={(checked) => setCheckboxValue(checked === true)}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Indeterminate\">\n <FormCheckbox\n label=\"Select all items\"\n description=\"Some items are selected\"\n checked={checkboxIndeterminate}\n onChange={setCheckboxIndeterminate}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Disabled\">\n <FormCheckbox\n label=\"Cannot change this\"\n checked={true}\n onChange={() => {}}\n disabled\n />\n </ExampleBlock>\n <ExampleBlock label=\"WITH ERROR (STATIC)\">\n <FormCheckbox\n label=\"Required checkbox\"\n checked={checkboxValue}\n onChange={(checked) => setCheckboxValue(checked === true)}\n error=\"You must accept to continue\"\n />\n </ExampleBlock>\n </div>\n\n <pre className=\"text-xs bg-muted p-2 rounded overflow-x-auto\">\n <code>{`<FormCheckbox\n label=\"Accept terms\"\n checked={checkboxValue}\n onChange={(checked) => setCheckboxValue(checked === true)}\n description=\"Optional description\"\n required={false}\n/>`}</code>\n </pre>\n\n <p className=\"text-xs text-muted-foreground\">\n Current value: {String(checkboxValue)}\n </p>\n </SimpleStack>\n </Card>\n\n {/* FormSelect */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>FormSelect</h2>\n <p className=\"text-sm text-muted-foreground\">\n Searchable single-select dropdown with label and error support.\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Basic\">\n <FormSelect\n label=\"Favorite Color\"\n value={selectValue}\n onChange={(value) => setSelectValue(value || \"\")}\n options={colorOptions}\n placeholder=\"Choose a color\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"With description\">\n <FormSelect\n label=\"Country\"\n description=\"Select your country of residence\"\n value={selectValue}\n onChange={(value) => setSelectValue(value || \"\")}\n options={countryOptions}\n placeholder=\"Select country\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Required\">\n <FormSelect\n label=\"Required Selection\"\n required\n value={selectRequired}\n onChange={(value) => setSelectRequired(value || \"\")}\n options={colorOptions}\n placeholder=\"Must select one\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Disabled\">\n <FormSelect\n label=\"Disabled Select\"\n value=\"blue\"\n onChange={() => {}}\n options={colorOptions}\n disabled\n placeholder=\"Cannot change\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"WITH ERROR (STATIC)\">\n <FormSelect\n label=\"Invalid Selection\"\n value={selectValue}\n onChange={(value) => setSelectValue(value || \"\")}\n options={colorOptions}\n error=\"This field is required\"\n placeholder=\"Select option\"\n />\n </ExampleBlock>\n </div>\n\n <pre className=\"text-xs bg-muted p-2 rounded overflow-x-auto\">\n <code>{`<FormSelect\n label=\"Country\"\n value={selectValue}\n onChange={(value) => setSelectValue(value || '')}\n options={[\n { label: 'USA', value: 'us' },\n { label: 'UK', value: 'uk' }\n ]}\n placeholder=\"Select...\"\n/>`}</code>\n </pre>\n\n <p className=\"text-xs text-muted-foreground\">\n Current value: {selectValue || \"(none selected)\"}\n </p>\n </SimpleStack>\n </Card>\n\n {/* FormMultiSelect */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>FormMultiSelect</h2>\n <p className=\"text-sm text-muted-foreground\">\n Searchable multi-select dropdown with badges.\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Basic\">\n <FormMultiSelect\n label=\"Favorite Colors\"\n value={multiSelectValue}\n onChange={setMultiSelectValue}\n options={colorOptions}\n placeholder=\"Select multiple colors\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"With description\">\n <FormMultiSelect\n label=\"Visited Countries\"\n description=\"Select all countries you've visited\"\n value={multiSelectValue}\n onChange={setMultiSelectValue}\n options={countryOptions}\n placeholder=\"Select countries\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Required\">\n <FormMultiSelect\n label=\"Skills\"\n required\n value={multiSelectValue}\n onChange={setMultiSelectValue}\n options={[\n { label: \"JavaScript\", value: \"js\" },\n { label: \"TypeScript\", value: \"ts\" },\n { label: \"Python\", value: \"py\" },\n { label: \"Java\", value: \"java\" },\n ]}\n placeholder=\"Select at least one skill\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"WITH ERROR (STATIC)\">\n <FormMultiSelect\n label=\"Categories\"\n value={multiSelectValue}\n onChange={setMultiSelectValue}\n options={colorOptions}\n error=\"Please select at least 2 categories\"\n placeholder=\"Select categories\"\n />\n </ExampleBlock>\n </div>\n\n <pre className=\"text-xs bg-muted p-2 rounded overflow-x-auto\">\n <code>{`<FormMultiSelect\n label=\"Skills\"\n value={multiSelectValue}\n onChange={setMultiSelectValue}\n options={skillOptions}\n placeholder=\"Select skills\"\n/>`}</code>\n </pre>\n\n <p className=\"text-xs text-muted-foreground\">\n Current value:{\" \"}\n {multiSelectValue.length > 0\n ? multiSelectValue.join(\", \")\n : \"(none selected)\"}\n </p>\n </SimpleStack>\n </Card>\n\n {/* FormTagsInput */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>FormTagsInput</h2>\n <p className=\"text-sm text-muted-foreground\">\n Free-text tag input with creation and deletion.\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Basic\">\n <FormTagsInput\n label=\"Technologies\"\n value={tagsValue}\n onChange={setTagsValue}\n placeholder=\"Type and press Enter to add tags\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"With description\">\n <FormTagsInput\n label=\"Skills\"\n description=\"Add your programming skills (press Enter after each)\"\n value={tagsValue}\n onChange={setTagsValue}\n placeholder=\"e.g., React, Node.js\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Required\">\n <FormTagsInput\n label=\"Keywords\"\n required\n value={tagsValue}\n onChange={setTagsValue}\n placeholder=\"Add at least one keyword\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"WITH ERROR (STATIC)\">\n <FormTagsInput\n label=\"Tags\"\n value={tagsValue}\n onChange={setTagsValue}\n error=\"Maximum 5 tags allowed\"\n placeholder=\"Add tags\"\n />\n </ExampleBlock>\n <ExampleBlock label=\"Disabled\">\n <FormTagsInput\n label=\"Fixed Tags\"\n value={[\"readonly\", \"tags\"]}\n onChange={() => {}}\n disabled\n placeholder=\"Cannot edit\"\n />\n </ExampleBlock>\n </div>\n\n <pre className=\"text-xs bg-muted p-2 rounded overflow-x-auto\">\n <code>{`<FormTagsInput\n label=\"Technologies\"\n value={tagsValue}\n onChange={setTagsValue}\n placeholder=\"Type and press Enter\"\n description=\"Optional description\"\n/>`}</code>\n </pre>\n\n <p className=\"text-xs text-muted-foreground\">\n Current tags:{\" \"}\n {tagsValue.length > 0 ? tagsValue.join(\", \") : \"(none)\"}\n </p>\n </SimpleStack>\n </Card>\n </SimpleStack>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -229,7 +229,26 @@ function PlayShellApi() {
|
|
|
229
229
|
children: "open() \u2014 full coverage"
|
|
230
230
|
}
|
|
231
231
|
),
|
|
232
|
-
/* @__PURE__ */ jsx(
|
|
232
|
+
/* @__PURE__ */ jsx(
|
|
233
|
+
Button,
|
|
234
|
+
{
|
|
235
|
+
variant: "outline",
|
|
236
|
+
size: "sm",
|
|
237
|
+
onClick: () => panel.open({
|
|
238
|
+
title: "Resizable Panel",
|
|
239
|
+
description: "Drag the left edge to resize. Double-click to reset.",
|
|
240
|
+
content: /* @__PURE__ */ jsxs("div", { className: "p-4 space-y-3", children: [
|
|
241
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Resizable panel" }),
|
|
242
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "resizable=true \xB7 defaultWidth=640 \xB7 minWidth=320 \xB7 maxWidth=1000" })
|
|
243
|
+
] }),
|
|
244
|
+
width: "default",
|
|
245
|
+
resizable: true,
|
|
246
|
+
minWidth: 320,
|
|
247
|
+
maxWidth: 1e3
|
|
248
|
+
}),
|
|
249
|
+
children: "open() \u2014 resizable"
|
|
250
|
+
}
|
|
251
|
+
)
|
|
233
252
|
] })
|
|
234
253
|
}
|
|
235
254
|
),
|
|
@@ -319,4 +338,4 @@ function PlayShellApi() {
|
|
|
319
338
|
export {
|
|
320
339
|
PlayShellApi
|
|
321
340
|
};
|
|
322
|
-
//# sourceMappingURL=chunk-
|
|
341
|
+
//# sourceMappingURL=chunk-CQ6PGFRV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pages/PlayShellApi.tsx"],"sourcesContent":["import { Button } from \"@petrarca/sonnet-ui\";\nimport {\n notification,\n dialog,\n navigation,\n panel,\n sidePane,\n} from \"@petrarca/sonnet-shell\";\nimport { PlaygroundSection } from \"../PlaygroundSection\";\n\n/**\n * PlayShellApi -- playground page that exercises the shell API surface.\n *\n * Covers: notification, dialog, navigation, panel, sidePane,\n * and the command menu (Cmd+K).\n */\nexport default function PlayShellApi() {\n return (\n <div className=\"space-y-6\">\n {/* ── notification ─────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"notification\"\n description=\"Toasts via the shell notification API — wraps Sonner.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.success(\"Operation completed.\")}\n >\n success()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.error(\"Something went wrong.\")}\n >\n error()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.warning(\"Proceed with caution.\")}\n >\n warning()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.info(\"Here is some information.\")}\n >\n info()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n notification.promise(\n new Promise((resolve) => setTimeout(resolve, 2000)),\n {\n loading: \"Loading...\",\n success: \"Done!\",\n error: \"Failed.\",\n },\n )\n }\n >\n promise()\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => notification.dismiss()}\n >\n dismiss()\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── dialog ───────────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"dialog\"\n description=\"Confirmation dialog via the shell dialog API.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={async () => {\n const confirmed = await dialog.confirm({\n title: \"Delete Resource\",\n description:\n \"This will permanently delete the resource. Are you sure?\",\n confirmLabel: \"Delete\",\n variant: \"destructive\",\n });\n notification.info(\n confirmed ? \"User confirmed.\" : \"User cancelled.\",\n );\n }}\n >\n confirm() — destructive\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={async () => {\n const confirmed = await dialog.confirm({\n title: \"Save Changes\",\n description: \"Do you want to save your changes?\",\n });\n notification.info(\n confirmed ? \"User confirmed.\" : \"User cancelled.\",\n );\n }}\n >\n confirm() — default\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── navigation ───────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"navigation\"\n description=\"Programmatic navigation via the shell navigation API.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigation.goTo(\"/home\")}\n >\n goTo(\"/home\")\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigation.goTo(\"/playground\")}\n >\n goTo(\"/playground\")\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigation.openCommandMenu()}\n >\n openCommandMenu()\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => navigation.back()}>\n back()\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── panel ────────────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"panel\"\n description=\"Shell-managed slide-over panel — renders content inside a Sheet owned by the shell.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n panel.open({\n title: \"Panel Demo\",\n description: \"This is a shell-managed slide-over panel.\",\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm\">\n This content is rendered inside the shell's Sheet\n component.\n </p>\n <p className=\"text-xs text-muted-foreground\">\n Use <code>panel.open()</code> to show any React content in\n a slide-over panel.\n </p>\n </div>\n ),\n })\n }\n >\n open() — narrow\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n panel.open({\n title: \"Wide Panel\",\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Wide panel (default)</p>\n <p className=\"text-xs text-muted-foreground\">\n width=\"default\" gives a wider panel for more complex\n content.\n </p>\n </div>\n ),\n width: \"default\",\n })\n }\n >\n open() — default width\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n panel.open({\n title: \"Full Coverage\",\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Full coverage panel</p>\n <p className=\"text-xs text-muted-foreground\">\n coverage=\"full\" overlays the entire content area.\n </p>\n </div>\n ),\n width: \"default\",\n coverage: \"full\",\n })\n }\n >\n open() — full coverage\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n panel.open({\n title: \"Resizable Panel\",\n description:\n \"Drag the left edge to resize. Double-click to reset.\",\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Resizable panel</p>\n <p className=\"text-xs text-muted-foreground\">\n resizable=true · defaultWidth=640 · minWidth=320 ·\n maxWidth=1000\n </p>\n </div>\n ),\n width: \"default\",\n resizable: true,\n minWidth: 320,\n maxWidth: 1000,\n })\n }\n >\n open() — resizable\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── sidePane ─────────────────────────────────────────────── */}\n <PlaygroundSection\n title=\"sidePane\"\n description=\"Persistent inline resizable panel. Sits beside the content area — the main view shrinks rather than being overlaid. Drag the edge to resize; double-click to reset.\"\n variant=\"card\"\n >\n <div className=\"flex flex-wrap gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n sidePane.open({\n moduleId: \"shell-demo-narrow\",\n defaultWidth: 240,\n minWidth: 180,\n maxWidth: 400,\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Narrow pane (240px)</p>\n <p className=\"text-xs text-muted-foreground\">\n defaultWidth=240 minWidth=180 maxWidth=400\n </p>\n </div>\n ),\n })\n }\n >\n open() — narrow\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n sidePane.open({\n moduleId: \"shell-demo-wide\",\n defaultWidth: 480,\n minWidth: 320,\n maxWidth: 800,\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Wide pane (480px)</p>\n <p className=\"text-xs text-muted-foreground\">\n defaultWidth=480 minWidth=320 maxWidth=800\n </p>\n </div>\n ),\n })\n }\n >\n open() — wide\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n sidePane.toggle({\n moduleId: \"shell-demo-toggle\",\n defaultWidth: 320,\n content: (\n <div className=\"p-4 space-y-3\">\n <p className=\"text-sm font-medium\">Toggle pane</p>\n <p className=\"text-xs text-muted-foreground\">\n Click again to close. Same moduleId toggles.\n </p>\n </div>\n ),\n })\n }\n >\n toggle()\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => sidePane.close()}>\n close()\n </Button>\n </div>\n </PlaygroundSection>\n\n {/* ── CommandMenu (Cmd+K) ──────────────────────────────────── */}\n <PlaygroundSection\n title=\"CommandMenu (Cmd+K)\"\n description=\"Open the command palette programmatically. Modules can register commands that appear here via the commands array in their ShellModule definition.\"\n variant=\"card\"\n >\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigation.openCommandMenu()}\n >\n Open CommandMenu\n </Button>\n </PlaygroundSection>\n </div>\n );\n}\n"],"mappings":";;;;;AAAA,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAkBC,SACE,KADF;AATO,SAAR,eAAgC;AACrC,SACE,qBAAC,SAAI,WAAU,aAEb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SAAQ;AAAA,QAER,+BAAC,SAAI,WAAU,wBACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,aAAa,QAAQ,sBAAsB;AAAA,cAC3D;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,aAAa,MAAM,uBAAuB;AAAA,cAC1D;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,aAAa,QAAQ,uBAAuB;AAAA,cAC5D;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,aAAa,KAAK,2BAA2B;AAAA,cAC7D;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MACP,aAAa;AAAA,gBACX,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AAAA,gBAClD;AAAA,kBACE,SAAS;AAAA,kBACT,SAAS;AAAA,kBACT,OAAO;AAAA,gBACT;AAAA,cACF;AAAA,cAEH;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,aAAa,QAAQ;AAAA,cACrC;AAAA;AAAA,UAED;AAAA,WACF;AAAA;AAAA,IACF;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SAAQ;AAAA,QAER,+BAAC,SAAI,WAAU,wBACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,YAAY;AACnB,sBAAM,YAAY,MAAM,OAAO,QAAQ;AAAA,kBACrC,OAAO;AAAA,kBACP,aACE;AAAA,kBACF,cAAc;AAAA,kBACd,SAAS;AAAA,gBACX,CAAC;AACD,6BAAa;AAAA,kBACX,YAAY,oBAAoB;AAAA,gBAClC;AAAA,cACF;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,YAAY;AACnB,sBAAM,YAAY,MAAM,OAAO,QAAQ;AAAA,kBACrC,OAAO;AAAA,kBACP,aAAa;AAAA,gBACf,CAAC;AACD,6BAAa;AAAA,kBACX,YAAY,oBAAoB;AAAA,gBAClC;AAAA,cACF;AAAA,cACD;AAAA;AAAA,UAED;AAAA,WACF;AAAA;AAAA,IACF;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SAAQ;AAAA,QAER,+BAAC,SAAI,WAAU,wBACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,WAAW,KAAK,OAAO;AAAA,cACvC;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,WAAW,KAAK,aAAa;AAAA,cAC7C;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM,WAAW,gBAAgB;AAAA,cAC3C;AAAA;AAAA,UAED;AAAA,UACA,oBAAC,UAAO,SAAQ,WAAU,MAAK,MAAK,SAAS,MAAM,WAAW,KAAK,GAAG,oBAEtE;AAAA,WACF;AAAA;AAAA,IACF;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SAAQ;AAAA,QAER,+BAAC,SAAI,WAAU,wBACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MACP,MAAM,KAAK;AAAA,gBACT,OAAO;AAAA,gBACP,aAAa;AAAA,gBACb,SACE,qBAAC,SAAI,WAAU,iBACb;AAAA,sCAAC,OAAE,WAAU,WAAU,0EAGvB;AAAA,kBACA,qBAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,oBACvC,oBAAC,UAAK,0BAAY;AAAA,oBAAO;AAAA,qBAE/B;AAAA,mBACF;AAAA,cAEJ,CAAC;AAAA,cAEJ;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MACP,MAAM,KAAK;AAAA,gBACT,OAAO;AAAA,gBACP,SACE,qBAAC,SAAI,WAAU,iBACb;AAAA,sCAAC,OAAE,WAAU,uBAAsB,kCAAoB;AAAA,kBACvD,oBAAC,OAAE,WAAU,iCAAgC,2EAG7C;AAAA,mBACF;AAAA,gBAEF,OAAO;AAAA,cACT,CAAC;AAAA,cAEJ;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MACP,MAAM,KAAK;AAAA,gBACT,OAAO;AAAA,gBACP,SACE,qBAAC,SAAI,WAAU,iBACb;AAAA,sCAAC,OAAE,WAAU,uBAAsB,iCAAmB;AAAA,kBACtD,oBAAC,OAAE,WAAU,iCAAgC,+DAE7C;AAAA,mBACF;AAAA,gBAEF,OAAO;AAAA,gBACP,UAAU;AAAA,cACZ,CAAC;AAAA,cAEJ;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MACP,MAAM,KAAK;AAAA,gBACT,OAAO;AAAA,gBACP,aACE;AAAA,gBACF,SACE,qBAAC,SAAI,WAAU,iBACb;AAAA,sCAAC,OAAE,WAAU,uBAAsB,6BAAe;AAAA,kBAClD,oBAAC,OAAE,WAAU,iCAAgC,uFAG7C;AAAA,mBACF;AAAA,gBAEF,OAAO;AAAA,gBACP,WAAW;AAAA,gBACX,UAAU;AAAA,gBACV,UAAU;AAAA,cACZ,CAAC;AAAA,cAEJ;AAAA;AAAA,UAED;AAAA,WACF;AAAA;AAAA,IACF;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SAAQ;AAAA,QAER,+BAAC,SAAI,WAAU,wBACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MACP,SAAS,KAAK;AAAA,gBACZ,UAAU;AAAA,gBACV,cAAc;AAAA,gBACd,UAAU;AAAA,gBACV,UAAU;AAAA,gBACV,SACE,qBAAC,SAAI,WAAU,iBACb;AAAA,sCAAC,OAAE,WAAU,uBAAsB,iCAAmB;AAAA,kBACtD,oBAAC,OAAE,WAAU,iCAAgC,wDAE7C;AAAA,mBACF;AAAA,cAEJ,CAAC;AAAA,cAEJ;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MACP,SAAS,KAAK;AAAA,gBACZ,UAAU;AAAA,gBACV,cAAc;AAAA,gBACd,UAAU;AAAA,gBACV,UAAU;AAAA,gBACV,SACE,qBAAC,SAAI,WAAU,iBACb;AAAA,sCAAC,OAAE,WAAU,uBAAsB,+BAAiB;AAAA,kBACpD,oBAAC,OAAE,WAAU,iCAAgC,wDAE7C;AAAA,mBACF;AAAA,cAEJ,CAAC;AAAA,cAEJ;AAAA;AAAA,UAED;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MACP,SAAS,OAAO;AAAA,gBACd,UAAU;AAAA,gBACV,cAAc;AAAA,gBACd,SACE,qBAAC,SAAI,WAAU,iBACb;AAAA,sCAAC,OAAE,WAAU,uBAAsB,yBAAW;AAAA,kBAC9C,oBAAC,OAAE,WAAU,iCAAgC,0DAE7C;AAAA,mBACF;AAAA,cAEJ,CAAC;AAAA,cAEJ;AAAA;AAAA,UAED;AAAA,UACA,oBAAC,UAAO,SAAQ,WAAU,MAAK,MAAK,SAAS,MAAM,SAAS,MAAM,GAAG,qBAErE;AAAA,WACF;AAAA;AAAA,IACF;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,aAAY;AAAA,QACZ,SAAQ;AAAA,QAER;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,MAAM,WAAW,gBAAgB;AAAA,YAC3C;AAAA;AAAA,QAED;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// src/pages/PlayGraph.tsx
|
|
2
|
-
import { useCallback, useState } from "react";
|
|
2
|
+
import { useCallback, useRef, useState } from "react";
|
|
3
3
|
import {
|
|
4
4
|
GraphVisualizer,
|
|
5
5
|
ActionPanel,
|
|
6
|
+
GraphA11yList,
|
|
6
7
|
GraphRendererProvider,
|
|
7
8
|
GraphStoresContext,
|
|
8
9
|
createGraphDataStore,
|
|
@@ -21,7 +22,8 @@ import {
|
|
|
21
22
|
Tabs,
|
|
22
23
|
TabsContent,
|
|
23
24
|
TabsList,
|
|
24
|
-
TabsTrigger
|
|
25
|
+
TabsTrigger,
|
|
26
|
+
ResizeHandle
|
|
25
27
|
} from "@petrarca/sonnet-ui";
|
|
26
28
|
import { Play, RotateCcw } from "lucide-react";
|
|
27
29
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -238,6 +240,23 @@ function PlayGraph() {
|
|
|
238
240
|
() => serializeGraphData(INITIAL_DATA)
|
|
239
241
|
);
|
|
240
242
|
const [parseError, setParseError] = useState(null);
|
|
243
|
+
const [panelWidth, setPanelWidth] = useState(300);
|
|
244
|
+
const rowRef = useRef(null);
|
|
245
|
+
const startResize = useCallback((e) => {
|
|
246
|
+
e.preventDefault();
|
|
247
|
+
const target = e.currentTarget;
|
|
248
|
+
target.setPointerCapture(e.pointerId);
|
|
249
|
+
const move = (ev) => {
|
|
250
|
+
const right = rowRef.current?.getBoundingClientRect().right ?? 0;
|
|
251
|
+
setPanelWidth(Math.min(560, Math.max(200, right - ev.clientX)));
|
|
252
|
+
};
|
|
253
|
+
const up = () => {
|
|
254
|
+
window.removeEventListener("pointermove", move);
|
|
255
|
+
window.removeEventListener("pointerup", up);
|
|
256
|
+
};
|
|
257
|
+
window.addEventListener("pointermove", move);
|
|
258
|
+
window.addEventListener("pointerup", up);
|
|
259
|
+
}, []);
|
|
241
260
|
const handleApply = useCallback(() => {
|
|
242
261
|
let parsed;
|
|
243
262
|
try {
|
|
@@ -278,9 +297,33 @@ function PlayGraph() {
|
|
|
278
297
|
/* @__PURE__ */ jsx(TabsTrigger, { value: "graph", children: "Graph" }),
|
|
279
298
|
/* @__PURE__ */ jsx(TabsTrigger, { value: "data", children: "Data" })
|
|
280
299
|
] }),
|
|
281
|
-
/* @__PURE__ */ jsx(TabsContent, { value: "graph", className: "mt-0", children: /* @__PURE__ */ jsx(GraphRendererProvider, { defaultRenderer: "cytoscape", children: /* @__PURE__ */ jsxs("div", { className: "flex
|
|
300
|
+
/* @__PURE__ */ jsx(TabsContent, { value: "graph", className: "mt-0", children: /* @__PURE__ */ jsx(GraphRendererProvider, { defaultRenderer: "cytoscape", children: /* @__PURE__ */ jsxs("div", { ref: rowRef, className: "flex overflow-hidden h-[600px]", children: [
|
|
282
301
|
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(GraphVisualizer, {}) }),
|
|
283
|
-
/* @__PURE__ */ jsx(
|
|
302
|
+
/* @__PURE__ */ jsx(
|
|
303
|
+
ResizeHandle,
|
|
304
|
+
{
|
|
305
|
+
orientation: "vertical",
|
|
306
|
+
"aria-valuenow": panelWidth,
|
|
307
|
+
"aria-valuemin": 200,
|
|
308
|
+
"aria-valuemax": 560,
|
|
309
|
+
onPointerDown: startResize,
|
|
310
|
+
onDoubleClick: () => setPanelWidth(300)
|
|
311
|
+
}
|
|
312
|
+
),
|
|
313
|
+
/* @__PURE__ */ jsxs(
|
|
314
|
+
"div",
|
|
315
|
+
{
|
|
316
|
+
style: { width: panelWidth },
|
|
317
|
+
className: "flex-shrink-0 flex flex-col min-h-0",
|
|
318
|
+
children: [
|
|
319
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsx(ActionPanel, {}) }),
|
|
320
|
+
/* @__PURE__ */ jsxs("div", { className: "shrink-0 px-4 pb-4 pt-2", children: [
|
|
321
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2", children: "Accessible list (demo)" }),
|
|
322
|
+
/* @__PURE__ */ jsx(GraphA11yList, { visible: true, maxHeight: 160 })
|
|
323
|
+
] })
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
)
|
|
284
327
|
] }) }) }),
|
|
285
328
|
/* @__PURE__ */ jsx(TabsContent, { value: "data", className: "mt-0", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
286
329
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -313,4 +356,4 @@ function PlayGraph() {
|
|
|
313
356
|
export {
|
|
314
357
|
PlayGraph
|
|
315
358
|
};
|
|
316
|
-
//# sourceMappingURL=chunk-
|
|
359
|
+
//# sourceMappingURL=chunk-VOC5VZG2.js.map
|