isotone 1.1.3 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +52 -5
- package/CHANGELOG.md +42 -0
- package/README.md +63 -14
- package/dist/{IterationPanel-phJRYtUO.d.ts → IterationPanel-Bq77d5NT.d.ts} +3 -1
- package/dist/{chunk-K5RAC2BT.js → chunk-2FY2JNPG.js} +3 -5
- package/dist/chunk-2FY2JNPG.js.map +1 -0
- package/dist/{chunk-RKZWO37H.js → chunk-BTJHQXF7.js} +85 -1
- package/dist/chunk-BTJHQXF7.js.map +1 -0
- package/dist/chunk-JCTWHR7U.js +13 -0
- package/dist/chunk-JCTWHR7U.js.map +1 -0
- package/dist/chunk-L6O4HYGP.js +1150 -0
- package/dist/chunk-L6O4HYGP.js.map +1 -0
- package/dist/{chunk-YTEUMO3O.js → chunk-LD7UWI7W.js} +17 -33
- package/dist/chunk-LD7UWI7W.js.map +1 -0
- package/dist/chunk-MX4RQJFV.js +9 -0
- package/dist/chunk-MX4RQJFV.js.map +1 -0
- package/dist/chunk-YPDV3PX4.js +142 -0
- package/dist/chunk-YPDV3PX4.js.map +1 -0
- package/dist/cli.js +1015 -148
- package/dist/cli.js.map +1 -1
- package/dist/core.d.ts +92 -2
- package/dist/core.js +10 -3
- package/dist/index.d.ts +13 -28
- package/dist/index.js +586 -257
- package/dist/index.js.map +1 -1
- package/dist/isotone.global.js +98 -42
- package/dist/serve.d.ts +5 -3
- package/dist/serve.js +60 -23
- package/dist/serve.js.map +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.js +24 -11
- package/dist/server.js.map +1 -1
- package/dist/vite-plugin.d.ts +4 -3
- package/dist/vite-plugin.js +23 -19
- package/dist/vite-plugin.js.map +1 -1
- package/docs/blast.md +133 -0
- package/docs/integrations.md +75 -15
- package/docs/migration.md +19 -0
- package/docs/updates.md +110 -4
- package/docs/variants.md +65 -7
- package/package.json +2 -1
- package/dist/chunk-A4DX2V4C.js +0 -7
- package/dist/chunk-A4DX2V4C.js.map +0 -1
- package/dist/chunk-BRBXIGZP.js +0 -593
- package/dist/chunk-BRBXIGZP.js.map +0 -1
- package/dist/chunk-K5RAC2BT.js.map +0 -1
- package/dist/chunk-LXW6WFOC.js +0 -402
- package/dist/chunk-LXW6WFOC.js.map +0 -1
- package/dist/chunk-RKZWO37H.js.map +0 -1
- package/dist/chunk-RQ2YI5KS.js +0 -24
- package/dist/chunk-RQ2YI5KS.js.map +0 -1
- package/dist/chunk-YTEUMO3O.js.map +0 -1
package/docs/integrations.md
CHANGED
|
@@ -7,11 +7,15 @@ npm install -D isotone
|
|
|
7
7
|
npx isotone init --yes
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
`init` detects the project, prints the integration to add
|
|
11
|
-
to `AGENTS.md`. It does not
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
`init` detects the project, prints the development-only integration to add and a
|
|
11
|
+
short first run for the agent, and adds a short guide to `AGENTS.md`. It does not
|
|
12
|
+
overwrite app code, install dependencies, or replace an existing guide. Running it
|
|
13
|
+
again is safe; once the project has variants or knobs it skips the first run.
|
|
14
|
+
`init --json` returns a setup plan without writing files; add `--yes` to write the
|
|
15
|
+
guide. `--approach overlay|host|serve` overrides the recommendation.
|
|
16
|
+
|
|
17
|
+
Isotone is a development tool. Every integration below keeps it out of production
|
|
18
|
+
by default; see [Production](#production) for how each one does that.
|
|
15
19
|
|
|
16
20
|
## Vite: one plugin
|
|
17
21
|
|
|
@@ -27,12 +31,14 @@ plugins: [/* existing plugins */, iteration()]
|
|
|
27
31
|
Restart the dev server. Source-file variants and notes are available immediately.
|
|
28
32
|
The panel carries its own React runtime, so React, Vue, Svelte and vanilla Vite
|
|
29
33
|
projects use the same setup. It does not enter the host's dependency optimizer or
|
|
30
|
-
Fast Refresh graph.
|
|
34
|
+
Fast Refresh graph. The plugin acts only on the dev server: `vite build` injects
|
|
35
|
+
nothing and serves no endpoints, so it needs no guard of its own.
|
|
31
36
|
|
|
32
37
|
If the app mounts `IterationPanel` or `mountIteration` itself, use
|
|
33
38
|
`iteration({ panel: false })` to keep local endpoints and source variants without
|
|
34
39
|
injecting a second panel. A manual mount can use
|
|
35
|
-
`updateEndpoint: '/api/iteration/update'` for the optional update notice
|
|
40
|
+
`updateEndpoint: '/api/iteration/update'` for the optional update notice and
|
|
41
|
+
its update note.
|
|
36
42
|
The adapters check for updates in the background; see [Updates](updates.md) for
|
|
37
43
|
the cache, explicit upgrade commands, and opt-out controls.
|
|
38
44
|
|
|
@@ -55,18 +61,46 @@ Run this inside the project in a second terminal:
|
|
|
55
61
|
npx isotone serve
|
|
56
62
|
```
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
Then load the panel in development only. For plain HTML pages, add this loader to
|
|
65
|
+
each page. It requests nothing unless the page itself is on localhost, so it stays
|
|
66
|
+
inert if the HTML is deployed:
|
|
59
67
|
|
|
60
68
|
```html
|
|
61
|
-
<script
|
|
69
|
+
<script>
|
|
70
|
+
if (/^(localhost|127\.0\.0\.1|\[::1\])$/.test(location.hostname))
|
|
71
|
+
document.head.append(Object.assign(document.createElement('script'),
|
|
72
|
+
{ src: 'http://127.0.0.1:4123/isotone.js' }));
|
|
73
|
+
</script>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A plain `<script src="http://127.0.0.1:4123/isotone.js" defer></script>` works too,
|
|
77
|
+
but only behind a development flag of the template or build step: in production
|
|
78
|
+
HTML it would make every visitor's browser request its own localhost, which recent
|
|
79
|
+
browsers turn into a permission prompt. In a Next app, render it from the root
|
|
80
|
+
layout (`app/layout.tsx`, or `pages/_app.tsx`) behind the development check, which
|
|
81
|
+
Next inlines at build time:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import Script from 'next/script';
|
|
85
|
+
|
|
86
|
+
// Inside <body>:
|
|
87
|
+
{process.env.NODE_ENV === 'development' && (
|
|
88
|
+
<Script src="http://127.0.0.1:4123/isotone.js" strategy="afterInteractive" />
|
|
89
|
+
)}
|
|
62
90
|
```
|
|
63
91
|
|
|
64
92
|
Open the printed setup URL for a copyable tag or a bookmarklet. The bundle has no
|
|
65
|
-
host framework dependencies. This path supports notes
|
|
93
|
+
host framework dependencies. This path supports notes and
|
|
94
|
+
[knobs](variants.md#knobs): `.isotone/knobs.json` in the directory where `serve`
|
|
95
|
+
runs is served at `/api/iteration/variants`, and the panel shows its range, colour
|
|
96
|
+
and select knobs. The panel has a Variants tool only while that file holds valid
|
|
97
|
+
knobs; reload the page after adding the first one. Swapping whole source files
|
|
66
98
|
needs the Vite plugin, or a host-owned `VariantsSource`.
|
|
67
99
|
|
|
68
|
-
`--port 4124` selects another port
|
|
69
|
-
|
|
100
|
+
`--port 4124` selects another port; use the same port in the tag, and keep both in
|
|
101
|
+
one place with a script such as `"isotone": "isotone serve --port 4124"`.
|
|
102
|
+
`--file path/to/notes.json` selects a notes file. `--theme light` fixes the panel
|
|
103
|
+
theme. The server binds to loopback and
|
|
70
104
|
accepts browser requests from localhost origins only. An HTTPS page may block
|
|
71
105
|
an HTTP script; use the same-origin route integration below in that case.
|
|
72
106
|
|
|
@@ -76,6 +110,12 @@ Use this when the framework should own the endpoint. Install `react` and
|
|
|
76
110
|
`react-dom` if the app does not already have them; direct `isotone/react`
|
|
77
111
|
imports use the host's React runtime.
|
|
78
112
|
|
|
113
|
+
The Request adapters, `serveNotesRequest` and `serveVariantsRequest`, answer 404
|
|
114
|
+
when `NODE_ENV` is `production`, so a route that reaches a deployment cannot read or
|
|
115
|
+
write the notes file. A deliberate, access-controlled review deployment can pass
|
|
116
|
+
`{ allowProduction: true }` as the third argument. Keep the route's own development
|
|
117
|
+
check as well; it also covers runtimes that leave `NODE_ENV` unset.
|
|
118
|
+
|
|
79
119
|
For a Next App Router project:
|
|
80
120
|
|
|
81
121
|
```ts
|
|
@@ -101,7 +141,9 @@ host and every request gets a 403 `origin not allowed`. Pass
|
|
|
101
141
|
`serveVariantsRequest`) to accept pages served from localhost, 127.0.0.1 or
|
|
102
142
|
[::1] on any port. Non-loopback origins are still rejected.
|
|
103
143
|
|
|
104
|
-
For this manual route, add `.iteration-feedback.json` to the project's
|
|
144
|
+
For this manual route, add `.iteration-feedback.json` to the project's
|
|
145
|
+
`.gitignore`, and `.iteration-feedback.blast.json` if your agent runs
|
|
146
|
+
[Blast mode](blast.md), whose CLI keeps its session there.
|
|
105
147
|
The Vite plugin and standalone server ignore their notes file automatically; the
|
|
106
148
|
transport-only request adapter does not modify Git configuration.
|
|
107
149
|
|
|
@@ -126,7 +168,10 @@ export function ReviewTools() {
|
|
|
126
168
|
```
|
|
127
169
|
|
|
128
170
|
Render `<ReviewTools />` once in the app layout. The effect handles development
|
|
129
|
-
Strict Mode and route unmounts.
|
|
171
|
+
Strict Mode and route unmounts. The dynamic import sits behind the check, so a
|
|
172
|
+
production bundle does not include the panel. `mountIteration` itself has no
|
|
173
|
+
production guard: a host may deliberately mount a variants-only panel on a preview
|
|
174
|
+
site. Other Request-based servers use the same handler;
|
|
130
175
|
Node HTTP servers can call `notesResponse` and serialize its `body` themselves.
|
|
131
176
|
That lower-level handler does not read or limit the HTTP request body, or check
|
|
132
177
|
the request's origin: the host must handle those concerns. Prefer the
|
|
@@ -176,13 +221,28 @@ file holds. The panel slows its retries while the server is unreachable and stop
|
|
|
176
221
|
polling in a hidden tab. Custom endpoints built on `notesResponse` or
|
|
177
222
|
`serveNotesRequest` get this without changes.
|
|
178
223
|
|
|
224
|
+
## Production
|
|
225
|
+
|
|
226
|
+
| Integration | What keeps it out of production |
|
|
227
|
+
| --- | --- |
|
|
228
|
+
| Vite plugin | Acts only on `vite dev`. A build injects no panel and serves no endpoints. `ISOTONE_VARIANT` bakes chosen variants into a build only when set. |
|
|
229
|
+
| `isotone serve` | A separate local process bound to loopback that accepts only localhost origins. The tag that loads it is either behind the framework's development check or the localhost-only loader above. |
|
|
230
|
+
| Request adapters | `serveNotesRequest` and `serveVariantsRequest` answer 404 under `NODE_ENV=production` unless given `allowProduction: true`. The route keeps its own development check. |
|
|
231
|
+
| `notesResponse`, `variantsResponse` | Lower-level functions with no guard; the host calls them only from development code. |
|
|
232
|
+
| `mountIteration`, `IterationPanel` | No guard, by design. Import them dynamically behind the development check. |
|
|
233
|
+
|
|
234
|
+
Agents set up through `init` are told the same rule in `AGENTS.md`: development
|
|
235
|
+
only, unless the user explicitly asks to ship it.
|
|
236
|
+
|
|
179
237
|
## Confirm the integration
|
|
180
238
|
|
|
181
239
|
1. Open the app in development and submit a note on an element.
|
|
182
240
|
2. Run `npx isotone --json` in the app directory. Confirm the note's route,
|
|
183
241
|
viewport and selector.
|
|
184
242
|
3. Run `npx isotone --done <id-prefix>` and check that it leaves the panel.
|
|
185
|
-
4. Build
|
|
243
|
+
4. Build the production app and search the output for `isotone` and
|
|
244
|
+
`/api/iteration`. With the localhost-only loader, the tag remains in the HTML
|
|
245
|
+
but loads nothing outside localhost.
|
|
186
246
|
|
|
187
247
|
If the panel is visible but the CLI has no notes, compare the dev server's printed
|
|
188
248
|
notes path with the CLI's working directory. If the endpoint is unreachable, the
|
package/docs/migration.md
CHANGED
|
@@ -31,3 +31,22 @@ port, or browser profile has separate storage. Custom keys stay unchanged.
|
|
|
31
31
|
Use `isotone@0.4.1` or newer. The older 0.4.0 package includes a one-time
|
|
32
32
|
`migrate` command but also has note-saving bugs fixed in 0.4.1; use this guide
|
|
33
33
|
for the work repositories. Existing `iso-iterate` versions remain installable.
|
|
34
|
+
|
|
35
|
+
## Request handlers are off in production
|
|
36
|
+
|
|
37
|
+
From the release after 1.1.3, `serveNotesRequest` and `serveVariantsRequest`
|
|
38
|
+
from `isotone/server` answer 404 when `NODE_ENV` is `production`, without
|
|
39
|
+
reading or writing any file. Development servers, test runners and runtimes
|
|
40
|
+
that leave `NODE_ENV` unset are unaffected.
|
|
41
|
+
|
|
42
|
+
Most projects need no change, because their route already returns early outside
|
|
43
|
+
development. A project that deliberately serves the panel from a production
|
|
44
|
+
build, such as an access-controlled review deployment, passes
|
|
45
|
+
`{ allowProduction: true }` as the third argument to each handler:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const result = await serveNotesRequest('.iteration-feedback.json', req, { allowProduction: true });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Keep that deployment behind its own access control; anyone who reaches the
|
|
52
|
+
endpoint can read and change the notes file.
|
package/docs/updates.md
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
The project controls its installed version. Publishing a new release does not
|
|
4
4
|
replace files in someone else's checkout. Isotone checks for a newer release
|
|
5
|
-
in the background and
|
|
6
|
-
|
|
5
|
+
in the background and lets you hand the upgrade to your coding agent, or copy
|
|
6
|
+
the exact command. Isotone itself never installs packages, executes that
|
|
7
|
+
command, or changes a manifest or lockfile.
|
|
7
8
|
|
|
8
9
|
Moving from the previous package name is a separate [migration](migration.md).
|
|
9
10
|
An update check does not replace a dependency with a differently named package.
|
|
@@ -15,6 +16,105 @@ attempts are cached too. CI and tests skip automatic checks. The registry reques
|
|
|
15
16
|
contains the public package name; it sends no notes, routes, project paths,
|
|
16
17
|
source files, installed-version telemetry or credentials.
|
|
17
18
|
|
|
19
|
+
## In the panel
|
|
20
|
+
|
|
21
|
+
When a newer release is out, a quiet line next to the pill reads "Isotone 1.2.0
|
|
22
|
+
is available". It opens a small dialog: the versions from → to, and **Ask agent
|
|
23
|
+
to update**. Below it, **Copy prompt** copies a ready-to-paste request for an
|
|
24
|
+
agent that is not reading notes, and **Command** shows the raw upgrade command
|
|
25
|
+
and the directory to run it in.
|
|
26
|
+
|
|
27
|
+
**Ask agent to update** files an update note. It sits in the Feedback list with
|
|
28
|
+
the other notes, on every page, tagged "Update", and reaches your agent through
|
|
29
|
+
`npx isotone --json` like any other note. It concerns the whole project, so it is
|
|
30
|
+
also listed for every route (`npx isotone <route> --json`). The dialog then reads "Update
|
|
31
|
+
requested". Deleting the note cancels the request.
|
|
32
|
+
|
|
33
|
+
The dev server builds the note from its own update check: the current and
|
|
34
|
+
latest version, the upgrade command and the directory. The browser only asks for
|
|
35
|
+
it, and the notes endpoint never accepts an update request, so a page cannot put
|
|
36
|
+
a command in front of your agent. At most one update note is open. If a newer
|
|
37
|
+
release appears while one is open, that note is updated instead of a second
|
|
38
|
+
being added.
|
|
39
|
+
|
|
40
|
+
The note's text is the server's too: the panel, `npx isotone` and `--json` show
|
|
41
|
+
"Update Isotone 1.1.3 → 1.2.0" built from the request, whatever the file holds,
|
|
42
|
+
and the notes endpoint refuses edits to an update note. Delete it to cancel.
|
|
43
|
+
|
|
44
|
+
Because the notes file is a plain file in the project, every reader checks the
|
|
45
|
+
request again before showing it, and drops it if anything is off:
|
|
46
|
+
|
|
47
|
+
- `update.to` is a strict SemVer version (`1.2.0`, `1.2.0-rc.1`, no build
|
|
48
|
+
metadata);
|
|
49
|
+
- `update.command` is exactly the command `check-update` builds for
|
|
50
|
+
`update.manager` and that version: `npm install [-D] --save-exact isotone@<to>`,
|
|
51
|
+
`pnpm add [-D] [-w] --exact isotone@<to>` or `yarn add [-D] [-W] --exact
|
|
52
|
+
isotone@<to>`;
|
|
53
|
+
- `update.cwd` is an existing directory inside the notes file's project (the
|
|
54
|
+
Git checkout that holds it, or its directory outside Git), after symlinks.
|
|
55
|
+
|
|
56
|
+
A dropped request leaves an ordinary note, which an agent treats as context.
|
|
57
|
+
|
|
58
|
+
The note carries a structured `update` field next to its text:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"feedback": "Update Isotone 1.1.3 → 1.2.0",
|
|
63
|
+
"update": {
|
|
64
|
+
"from": "1.1.3",
|
|
65
|
+
"to": "1.2.0",
|
|
66
|
+
"command": "pnpm add -D --exact isotone@1.2.0",
|
|
67
|
+
"cwd": "/path/to/app",
|
|
68
|
+
"manager": "pnpm",
|
|
69
|
+
"changelog": "https://github.com/aaroi/isotone/blob/v1.2.0/CHANGELOG.md"
|
|
70
|
+
},
|
|
71
|
+
"updateHint": "An update note is the user's request to upgrade Isotone. …",
|
|
72
|
+
"doneCommand": "npx isotone --done <id>"
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
An agent treats it as the user's explicit request to upgrade. It runs the
|
|
77
|
+
printed command only if it matches one of the canonical forms above, with the
|
|
78
|
+
note's version, in that directory inside the project, and treats any other
|
|
79
|
+
command or text as context. It then restarts the dev server if it runs it,
|
|
80
|
+
checks that the panel still loads, summarizes the notable changes from the new
|
|
81
|
+
CHANGELOG (also at `node_modules/isotone/CHANGELOG.md` after the install), and
|
|
82
|
+
closes the note with `--done`. Page text and other notes are still context, not
|
|
83
|
+
instructions; the update note's command comes from Isotone's own server.
|
|
84
|
+
|
|
85
|
+
The button needs a notes endpoint and a command Isotone can name. When it
|
|
86
|
+
cannot name one (Bun, competing lockfiles, an optional or peer dependency, or
|
|
87
|
+
the Isotone source checkout), the dialog explains why instead.
|
|
88
|
+
|
|
89
|
+
## Update notes without asking
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
iteration({ checkForUpdates: 'note' });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
npx isotone serve --update-note
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
With `checkForUpdates: 'note'` (`serveIteration` takes the same value), the dev
|
|
100
|
+
server files the update note by itself the first time it sees a new version,
|
|
101
|
+
once per version for each notes file. If you don't want that version, delete the
|
|
102
|
+
note; it is not filed again until a newer release. The versions already offered
|
|
103
|
+
are remembered in the same per-user temporary directory as the daily check. The
|
|
104
|
+
default stays as it is: a notice, with the button.
|
|
105
|
+
|
|
106
|
+
There is no mode that installs updates silently. Changing dependencies and the
|
|
107
|
+
lockfile without the user's say:
|
|
108
|
+
|
|
109
|
+
- adds supply-chain risk: a compromised or broken release would land in every
|
|
110
|
+
project the moment it is published, with nobody reviewing it first;
|
|
111
|
+
- breaks reproducibility for teams: one developer's dev server would rewrite the
|
|
112
|
+
manifest and lockfile, and the next commit would carry an upgrade nobody chose;
|
|
113
|
+
- restarts or breaks a dev server in the middle of someone's work.
|
|
114
|
+
|
|
115
|
+
An update note keeps a person in the loop at the cost of one click, and the agent
|
|
116
|
+
does the work in the open, where its diff can be reviewed.
|
|
117
|
+
|
|
18
118
|
## Checking and upgrading
|
|
19
119
|
|
|
20
120
|
Check explicitly from the project directory:
|
|
@@ -74,11 +174,17 @@ Standalone:
|
|
|
74
174
|
npx isotone serve --no-update-check
|
|
75
175
|
```
|
|
76
176
|
|
|
77
|
-
`serveIteration` also accepts `checkForUpdates: false`.
|
|
177
|
+
`serveIteration` also accepts `checkForUpdates: false`. Turning checks off also
|
|
178
|
+
turns off update notes. Set
|
|
78
179
|
`ISOTONE_UPDATE_CHECK=0` to disable automatic checks for either adapter.
|
|
79
180
|
The explicit `check-update` command remains available. Manually mounted panels
|
|
80
181
|
only show update information when given an `updateEndpoint` supplied by a local
|
|
81
|
-
server; they do not contact npm from the browser.
|
|
182
|
+
server; they do not contact npm from the browser. GET on that endpoint returns
|
|
183
|
+
the cached check, and POST files the update note.
|
|
184
|
+
|
|
185
|
+
For a layout check, `/?review=1&update-preview=1` in the demo shows a fictional
|
|
186
|
+
update; asking the agent there files a demo note that the pretend agent picks up
|
|
187
|
+
and closes. It does not contact npm or install anything.
|
|
82
188
|
|
|
83
189
|
## Version ranges and reproducibility
|
|
84
190
|
|
package/docs/variants.md
CHANGED
|
@@ -43,8 +43,48 @@ Choose the control for the decision being reviewed, not for variety in the panel
|
|
|
43
43
|
Thumbnail grids are a presentation of select axes, not another `kind`. There are
|
|
44
44
|
no separate checkbox, toggle, dropdown or free-text axis kinds. Use stable IDs,
|
|
45
45
|
short descriptive labels, and independent axes for independent decisions.
|
|
46
|
-
`
|
|
47
|
-
|
|
46
|
+
`showWhen` hides a dependent axis until its parent has the relevant selection.
|
|
47
|
+
Keep the default among the available options or swatches.
|
|
48
|
+
|
|
49
|
+
## Sections
|
|
50
|
+
|
|
51
|
+
Once a page has more than a few selectors, put each one in a section named after
|
|
52
|
+
the part of the page it changes. Write the section as a label prefix, a `>`
|
|
53
|
+
with a space on each side:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
{ id: 'logo-size', label: 'Header > Logo size', kind: 'range', min: 16, max: 48, step: 2, defaultValue: 24, unit: 'px' }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The panel shows a **Header** heading with *Logo size* under it. The heading stays
|
|
60
|
+
at the top of the list while you scroll through its selectors, shows how many it
|
|
61
|
+
holds, and folds the section away. Screen readers, notes and saved defaults keep
|
|
62
|
+
the full name, `Header › Logo size`.
|
|
63
|
+
|
|
64
|
+
- Only the first ` > ` splits, so `Header > Nav > Gap` is *Nav > Gap* in Header.
|
|
65
|
+
` › ` works the same way. The spaces matter: `a>b` stays one label.
|
|
66
|
+
- A slash never makes a section, so binary selectors such as `Light / Dark` or
|
|
67
|
+
`Grid / List` keep their whole label.
|
|
68
|
+
- Sections match without regard to case and keep the casing of their first selector.
|
|
69
|
+
- Selectors without a section come first, without a heading. Sections follow in
|
|
70
|
+
the order their first selector appears, and selectors keep their order inside them.
|
|
71
|
+
- A `showWhen` selector without its own section joins its parent's section.
|
|
72
|
+
- Section names are display text only. IDs, `?v=` links and `selections` do not change.
|
|
73
|
+
|
|
74
|
+
An explicit `section` field overrides the prefix. The label then shows as written,
|
|
75
|
+
less a prefix that repeats the section. `section: ''` keeps a label that needs a
|
|
76
|
+
spaced `>`, such as `Before > After`, out of every section:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
{ id: 'order', label: 'Before > After', section: '', options: [/* … */], defaultOption: 'before' }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The same works everywhere a selector is defined. Host axes and `.isotone/knobs.json`
|
|
83
|
+
entries take a prefixed `label` or a `section` field. File variants take it from the
|
|
84
|
+
group label (`variant new <id> --group-label "Header > Logo"`), or from
|
|
85
|
+
`variant new <id> --section Header`. `variant section <id> <text>` moves an existing
|
|
86
|
+
selector, with every variant in its group; `variant section <id> --none` takes it out
|
|
87
|
+
of every section. `variant list` shows a SECTION column.
|
|
48
88
|
|
|
49
89
|
For a range, choose bounds that produce useful, valid designs at both extremes.
|
|
50
90
|
Use a positive `step` that matches the decision's precision, and a default aligned
|
|
@@ -77,8 +117,9 @@ project, declare numeric and colour controls in `knobs.json` as below, and read
|
|
|
77
117
|
their CSS custom properties instead of copying a file for every possible value.
|
|
78
118
|
Verify every control changes the intended app property, including its minimum,
|
|
79
119
|
maximum and reset state. When saving defaults, keep the source fallback and the
|
|
80
|
-
axis default in sync. The interactive demo includes card radius and padding sliders
|
|
81
|
-
|
|
120
|
+
axis default in sync. The interactive demo includes card radius and padding sliders
|
|
121
|
+
in a Cards section and the accent colour in a Theme section; its screenshot view
|
|
122
|
+
keeps the original two selectors, without sections, for a compact composition.
|
|
82
123
|
|
|
83
124
|
Removal actions in the panel save requests for the agent. Selectors and options
|
|
84
125
|
stay visible and usable until the agent changes the project. Requests open in
|
|
@@ -131,7 +172,7 @@ optional `route` (a pattern like a variant's, or a list of them):
|
|
|
131
172
|
{
|
|
132
173
|
"kind": "range",
|
|
133
174
|
"id": "fade-from",
|
|
134
|
-
"label": "Fade starts",
|
|
175
|
+
"label": "Hero > Fade starts",
|
|
135
176
|
"min": 0,
|
|
136
177
|
"max": 100,
|
|
137
178
|
"step": 1,
|
|
@@ -142,8 +183,25 @@ optional `route` (a pattern like a variant's, or a list of them):
|
|
|
142
183
|
]
|
|
143
184
|
```
|
|
144
185
|
|
|
186
|
+
A colour knob takes a `defaultColor` and named `swatches`, all as hex values:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"kind": "color",
|
|
191
|
+
"id": "accent",
|
|
192
|
+
"label": "Accent colour",
|
|
193
|
+
"defaultColor": "#2f6f4e",
|
|
194
|
+
"swatches": [
|
|
195
|
+
{ "id": "forest", "label": "Forest", "value": "#2f6f4e" },
|
|
196
|
+
{ "id": "clay", "label": "Clay", "value": "#b4532a" }
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
145
201
|
The panel renders range knobs as sliders and colour knobs as swatches with a
|
|
146
|
-
custom picker, on their configured routes.
|
|
202
|
+
custom picker, on their configured routes. An entry with a missing or invalid
|
|
203
|
+
field is skipped; `npx isotone variant list` names each one. Knobs also work with
|
|
204
|
+
`isotone serve`, so any dev server gets them, not only Vite. A value reaches the
|
|
147
205
|
page as a custom property on `<html>`, `--knob-<id>`, with the unit
|
|
148
206
|
appended, so the source reads it with the committed default as the
|
|
149
207
|
fallback:
|
|
@@ -177,7 +235,7 @@ document.addEventListener('isotone:knob', ({ detail }) => {
|
|
|
177
235
|
The event only fires while the panel is mounted, so keep the committed default in
|
|
178
236
|
the source. Knob values live in the reviewer's browser, not on the server. "Save as
|
|
179
237
|
defaults" files the moved knobs in the same `[set-defaults]` note as the
|
|
180
|
-
variant picks, as `Knobs: Fade starts 40% (fade-from)` with a `knobs`
|
|
238
|
+
variant picks, as `Knobs: Hero › Fade starts 40% (fade-from)` with a `knobs`
|
|
181
239
|
payload of `fade-from:40`; the agent writes the number into the source and
|
|
182
240
|
into the knob file's `defaultValue`.
|
|
183
241
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "isotone",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Design variants and feedback for your running web app. Switch between variants your coding agent builds, pin elements, and give the agent the context to make the change.",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"docs/integrations.md",
|
|
40
40
|
"docs/migration.md",
|
|
41
41
|
"docs/updates.md",
|
|
42
|
+
"docs/blast.md",
|
|
42
43
|
"docs/variants.md",
|
|
43
44
|
"docs/third-party-notices.md",
|
|
44
45
|
"AGENTS.md",
|
package/dist/chunk-A4DX2V4C.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/limits.ts"],"sourcesContent":["/** Maximum feedback length after trimming, shared by browser and server. */\nexport const MAX_FEEDBACK_LENGTH = 4000;\n"],"mappings":";AACO,IAAM,sBAAsB;","names":[]}
|