From b2d40ded0132d93fef049b3a504541cb1def5cdb Mon Sep 17 00:00:00 2001 From: HerbertJulio Date: Wed, 24 Jun 2026 17:51:32 -0300 Subject: [PATCH 1/2] docs(webkit): codify Show code pattern + flat-import rule storybook-write skill: document the copy-paste-ready 'Show code' transform, now in the current repo format (stories under stories/components, title Components//, direct `@aziontech/webkit/` imports, /i on the SFC-detector regex). Adds .claude/rules/imports.md codifying the flat public export name (category lives in the folder + story title, not the import). --- .claude/rules/imports.md | 46 ++++++++ .claude/skills/storybook-write/SKILL.md | 149 +++++++++++++++++------- 2 files changed, 154 insertions(+), 41 deletions(-) create mode 100644 .claude/rules/imports.md diff --git a/.claude/rules/imports.md b/.claude/rules/imports.md new file mode 100644 index 00000000..69cfc626 --- /dev/null +++ b/.claude/rules/imports.md @@ -0,0 +1,46 @@ +# Rule: imports — flat public name, category in the folder only + +Every webkit component is published under a **flat, single-segment public name**. The category (`feedback`, `content`, `inputs`, `data`, `actions`, …) organizes the **source folder** and the **Storybook tree**, but it never appears in the public import path or the `package.json` export key. + +## The rule + +> O export é **direto**: `@aziontech/webkit/`. **Nunca** com prefixo de categoria (`@aziontech/webkit/feedback/skeleton`). A categoria vive na pasta (`src/components///`) e no título da story (`Components//`), não no nome público. + +| Concern | Correct | Forbidden | +|---|---|---| +| `package.json#exports` key | `"./skeleton"` | `"./feedback/skeleton"` | +| `package.json#exports` value | `"./src/components/feedback/skeleton/skeleton.vue"` | — (folder keeps the category) | +| Consumer / story / spec import | `@aziontech/webkit/skeleton` | `@aziontech/webkit/feedback/skeleton` | +| Source folder | `src/components/feedback/skeleton/skeleton.vue` | `src/components/skeleton/skeleton.vue` | +| Story file location | `apps/storybook/src/stories/components/feedback/skeleton/Skeleton.stories.js` | `apps/storybook/src/stories/webkit/feedback/skeleton/…` | +| Story `title` | `Components/Feedback/Skeleton` | `Webkit/Feedback/Skeleton` | + +## Why + +- **Stable public surface.** Consumers import `@aziontech/webkit/skeleton`; moving a component between categories (e.g. `content` → `data`) is then an internal folder move, not a breaking import change. +- **One name per component.** A flat export key can't collide with a category segment and reads the same everywhere — export key, import, Code Connect. +- **Folder/tree still carry the category.** The source path (`src/components///`) and the Storybook title (`Components//`) keep the taxonomy visible without leaking it into the import. + +## What this means in practice + +When adding or migrating a component named `` in category ``: + +1. **Source** lives at `packages/webkit/src/components///.vue` with its local `package.json`. +2. **Export** in `packages/webkit/package.json#exports` is the flat key: + ```jsonc + "./": "./src/components///.vue" + ``` +3. **Story** lives at `apps/storybook/src/stories/components///.stories.js` and sets `title: 'Components//'`. +4. **Every import** — in the story, the spec's `## Usage` block, and any consumer — is `@aziontech/webkit/`. + +If the flat name is already taken by another component, that is a **naming** problem: rename the new component, do not fall back to a category-prefixed export. Emit `BLOCKED: export key "./" already in use` and resolve the name before shipping. + +## Migration note + +Components authored before this convention (or branched from an older layout) may carry `@aziontech/webkit//` imports, a `Webkit/…` story title, or a story under `stories/webkit/…`. When touching such a component, bring it to this rule: flatten the export key, retitle the story to `Components/…`, and move the story under `stories/components/…`. See [`migration.md`](./migration.md). + +## Enforcement + +- `validate-references.mjs` already rejects imports of any `@aziontech/webkit/*` path absent from `packages/webkit/package.json#exports` — a category-prefixed import therefore fails once the export key is flat. +- The [`storybook-write`](../skills/storybook-write/SKILL.md) skill emits flat imports, `Components//` titles, and `stories/components//…` locations by default. +- Keep the export list and the story tree consistent with this rule; a prefixed export key (`"./feedback/skeleton"`) is a review-blocking deviation. diff --git a/.claude/skills/storybook-write/SKILL.md b/.claude/skills/storybook-write/SKILL.md index fe3f146f..ccec3b92 100644 --- a/.claude/skills/storybook-write/SKILL.md +++ b/.claude/skills/storybook-write/SKILL.md @@ -1,15 +1,17 @@ --- name: storybook-write -description: Write a minimal `.stories.js` for a webkit component using the canonical Button.stories.js shape. Stories are Default + one composite story per multi-option axis (Types / Sizes / Icons / …) + one story per mutually-exclusive state (Loading / Disabled / Filled / Invalid) — never one-story-per-variant. Inject the spec's `## Usage` block into `parameters.docs.description.component` as a code snippet. +description: Write a minimal `.stories.js` for a webkit component using the canonical Button.stories.js shape. Stories are Default + one composite story per multi-option axis (Types / Sizes / Icons / …) + one story per mutually-exclusive state (Loading / Disabled / Filled / Invalid) — never one-story-per-variant. Give `parameters.docs.description.component` a short prose lead from `## Purpose`, and add a `docs.source.transform` + `docs.canvas.sourceState: 'shown'` so the Docs "Show code" panel emits a runnable, copy-paste-ready SFC. status: active -last_updated: 2026-06-15 +last_updated: 2026-06-24 --- # Skill: storybook-write ## Purpose -Generate `apps/storybook/src/stories/webkit///.stories.js` (or `apps/storybook/src/stories/webkit//.stories.js` for short-form locations) covering **only** the stories listed in the spec's "Stories (Storybook)" section. The canonical shape is the existing `Button.stories.js` — composite `Types` and `Sizes` stories plus state-specific stories (`Loading`, `Disabled`). The spec's `## Usage` block (import + minimal `', - '', - '', - '```' - ].join('\n') - } + component: + 'Interactive control for user actions. Supports label text, optional icon, loading state, and link rendering when `href` is set.' + }, + source: { + type: 'dynamic', + excludeDecorators: true, + transform: (code) => { + let src = String(code).trim() + // Composite stories pass a full-SFC `source.code` (see step 7) — leave it untouched. + if (/]/i.test(src)) return src + // Storybook sometimes already wraps arg-driven source in