feat(appkit): /ui visual variant picker#476
Conversation
|
📦 Bundle size reportCompared against
|
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 791 KB (+7.5 KB) | 276 KB (+3.4 KB) |
| Type declarations | 285 KB (+329 B) | 97 KB (+127 B) |
| Source maps | 1.5 MB (+12 KB) | 515 KB (+5.0 KB) |
| Other | 11 KB | 3.7 KB |
| Total | 2.6 MB (+20 KB) | 892 KB (+8.5 KB) |
Per-entry composition (own code — deps external (as shipped))
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
. |
86 KB (+927 B) | 2.5 KB | 89 KB (+927 B) | external | 281 KB (+2.6 KB) |
./beta |
40 KB | 231 B | 40 KB | external | 119 KB |
./type-generator |
19 KB | 0 B | 19 KB | external | 54 KB |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
. |
index.js |
initial | 82 KB |
. |
utils.js |
initial | 4.0 KB |
. |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./beta |
beta.js |
initial | 30 KB |
./beta |
databricks.js |
initial | 5.8 KB |
./beta |
service-context.js |
initial | 3.2 KB |
./beta |
client-options.js |
initial | 220 B |
./beta |
databricks.js |
lazy | 128 B |
./beta |
index.js |
lazy | 103 B |
./type-generator |
index.js |
initial | 19 KB |
@databricks/appkit-ui
npm tarball (packed): 305 KB (+9.8 KB) — gzipped download (dist + bin; excludes release-only docs/NOTICE).
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 359 KB (+9.4 KB) | 119 KB (+3.6 KB) |
| Type declarations | 205 KB (+4.5 KB) | 74 KB (+2.1 KB) |
| Source maps | 685 KB (+16 KB) | 224 KB (+6.2 KB) |
| CSS | 16 KB | 3.3 KB |
| Total | 1.2 MB (+30 KB) | 421 KB (+12 KB) |
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
./js |
4.3 KB | 49 KB | 54 KB | 208 KB | 12 KB |
./js/beta |
20 B | 0 B | 20 B | 0 B | 0 B |
./react |
429 KB (+1.4 KB) | 49 KB | 478 KB (+1.4 KB) | 1.3 MB (+136 B) | 168 KB (+4.3 KB) |
./react/beta |
20 B | 0 B | 20 B | 0 B | 0 B |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
./js |
index.js |
initial | 4.2 KB |
./js |
chunk |
initial | 120 B |
./js |
apache-arrow |
lazy | 49 KB |
./js/beta |
beta.js |
initial | 20 B |
./react |
index.js |
initial | 427 KB |
./react |
tslib |
initial | 2.1 KB |
./react |
apache-arrow |
lazy | 49 KB |
./react/beta |
beta.js |
initial | 20 B |
06e5595 to
92b573b
Compare
Build a piece of app UI in several variants, pick one live in the running app, then finalize the chosen variant into source. - `<Variants>`/`<Variant>` (appkit-ui): inline switcher — hover-revealed controls, tick confirm, `accent` and `layout` props — that degrades to a plain viewer when the recorder is absent. The block identifier prop is `blockId` (a semantic key, not a DOM id). - `uiVariants()` recorder plugin (appkit): POST /api/ui-variants/confirm, dev-gated (403), keyed upsert into node_modules/.databricks/appkit/.appkit-ui-choices.jsonl via a swappable ChoiceSink (default FileChoiceSink). Register conditionally so it never mounts in production. - ast-grep lint rule flagging any <Variants> left in source before deploy. - dev-playground demo route + nav. - `/ui` command + guidance reference driving the author → pick → finalize loop. Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
62a6a2d to
c5187d6
Compare
Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
Introduce a declarative `devOnly` field on the plugin manifest. When set, createApp registers the plugin only when NODE_ENV === "development"; in any other environment it is skipped before resource collection (not constructed, no routes, resources not validated). This moves the dev-only guarantee from an app-author-written NODE_ENV ternary into the framework itself. Mark the ui-variants plugin devOnly and simplify the dev-playground registration to a plain uiVariants() call. The in-handler NODE_ENV 403 is retained as fail-safe defense against mount-anyway paths. Adds the field to the Zod schema (source of truth) and PluginManifest type, regenerates the published JSON schema, documents it in the manifest guide, and covers development/production/test/unset in bootstrap tests. Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
calvarjorge
left a comment
There was a problem hiding this comment.
Nice work! Took a first look and left some comments
| @@ -0,0 +1,106 @@ | |||
| --- | |||
There was a problem hiding this comment.
Is this the place where we want to place the skill? Maybe yes, but there is a difference with the rest of the skills in the dir -- the other skills are to be used by appkit developers, while this skilled is meant to be installed and used by appkit users
There was a problem hiding this comment.
Moved the skill into the appkit itself under the skills folder, with installation via appkit cli command (appkit skills install)
| @@ -0,0 +1,106 @@ | |||
| --- | |||
There was a problem hiding this comment.
Do we want to name it /ui? Can we align on this to avoid changing it later? Maybe this is to broad, other option could be /appkit-ui-variants
There was a problem hiding this comment.
I am proposing a name /ui-variants
There was a problem hiding this comment.
It is /appkit-ui-variants now
Match the appkit plugin dir name for cross-package consistency. Files and the public API are unchanged; only the internal directory moves. Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
Consolidate the /ui command and its variants guidance into a single self-contained skill shipped inside @databricks/appkit (skills/ui.md), and add an `appkit skills install` CLI command that symlinks shipped skills into a consuming project's .claude/commands/ (--copy for git/deploy portability, --dir, --force). `appkit setup --write` now auto-installs skills, and the dist tarball ships the skills/ dir. Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
Align the shipped skill's command name with the ui-variants naming used across the branch (plugin, dir, route). The install command derives the slash-command name from the filename, so this makes it install as /ui-variants. Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
createApp now skips devOnly plugins automatically, so the skill just says to add uiVariants() to the plugin list. Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
Installs as the /appkit-ui-variants slash command (name derived from the file). Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
| const [active, setActive] = useState(0); | ||
| const [confirmState, setConfirmState] = useState<ConfirmState>("idle"); | ||
|
|
||
| if (variants.length === 0) return null; |
There was a problem hiding this comment.
wdyt about a small prod safety net right after the length check (kept below the hooks):
| if (variants.length === 0) return null; | |
| if (variants.length === 0) return null; | |
| if (!import.meta.env.DEV) return <>{variants[0]}</>; |
so if a block ever ships without being finalized, users see real content instead of the picker chrome — variants[0] avoids the blank section that returning null would leave. not a security thing (the recorder is already server-gated), just belt-and-suspenders on top of the no-variants-in-prod lint. import.meta.env.DEV to match what we already do in use-query-hmr.ts 😄
non-blocking, just a thought
There was a problem hiding this comment.
Yes, thanks for noting that, added it
| type ChoiceSink, | ||
| FileChoiceSink, | ||
| type UiChoiceRecord, | ||
| uiVariants, |
There was a problem hiding this comment.
let's remove the export
createApp now injects the ui-variants recorder before the dev-only filter runs, so it is always alive in development and always stripped in production through the same guard as any devOnly plugin. Neither the app author nor their coding agent needs to register it by hand. Also drops the unused ChoiceSink abstraction (folded into an internal FileChoiceStore) and removes uiVariants and the sink types from the public API surface, since manual registration is no longer a path. Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
If a <Variants> block ever ships without being finalized, users saw the dev-only picker chrome. In a production build the component now drops the chrome and renders the first variant as plain content — a cosmetic safety net on top of the no-variants-in-prod lint; the recorder is already server-gated. Guard sits below the hooks and uses import.meta.env.DEV to match use-query-hmr. Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
Signed-off-by: Galymzhan <zhangazy2004@gmail.com>
/ui variant selector skill
Document
This PR is adding a new feature of /ui-variants skill, that makes agent create several design versions of the UI component and allows user to select it live on the web page, while agent could read it on the next turn and implement selected degisn.
How to test
pnpm --filter=dev-playground exec appkit skills install/ui-variantscommand via Isaac/Claude Code and type want you want to build in dev-playgroundnode_modules/.databricks/appkit/appkit-ui-choices.jsonlfileHow should it work for user
/ui-variantsskill is available right away