@feeef.dev/cli 0.2.2 → 0.2.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feeef.dev/cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Feeef developer CLI — templates, auth, and cloud tools",
5
5
  "type": "module",
6
6
  "bin": {
@@ -51,7 +51,7 @@
51
51
  "commander": "^12.1.0",
52
52
  "dotenv": "^16.4.7",
53
53
  "esbuild": "^0.25.0",
54
- "feeef": "^0.12.1",
54
+ "feeef": "^0.12.2",
55
55
  "picocolors": "^1.1.1",
56
56
  "react": "^19.2.7",
57
57
  "react-dom": "^19.2.7"
@@ -13,22 +13,24 @@ Before editing theme source, read:
13
13
 
14
14
  ## Non-negotiables
15
15
 
16
+ - **Flat TSX for leaf customs** — `pages|shared|library/.../<name>.tsx` with `export const meta` + `function App()`.
17
+ - Folder form (`<name>/<name>.tsx` + `slots/`) **only** when slots/children are required.
18
+ - Never author new customs as `component.json` + `component.jsx`.
19
+ - Never invent deep nested shell trees when a flat sibling stack + `$ref` works.
16
20
  - `code`, `propsSchema`, `slotsSchema`, `slots`, `slotsLayout` are **top-level** — never under `props`.
17
- - Custom components expose `function App() {}`. Author `.jsx`/`.tsx`; build bundles imports (see `docs/16-AUTHORING-TS-IMPORTS.md`).
18
21
  - Prefer `React.useState` / `React.useEffect` in custom code.
19
- - Styles: `hsl(var(--primary))` etc. — not raw decoration ints.
22
+ - Styles: `hsl(var(--primary))` etc. — not raw decoration ints (`docs/12-DARK-LIGHT-THEME.md`).
20
23
  - Navigation: `Link` / `RouterNav` / `useRouter`.
21
- - Repeated UI → `shared/components/<id>/` + `$ref` (`docs/07-SHARED-COMPONENTS.md`).
22
- - Order / COD → `docs/08-ORDER-FORM.md` (draft, geo, `POST /api/orders/create`, anti-abuse).
23
- - Checkout / thanks / product → `docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md` (single `main` + slots).
24
- - Dark / light → `docs/12-DARK-LIGHT-THEME.md`.
24
+ - Repeated UI → `shared/components/<id>.tsx` + `$ref` (`docs/07-SHARED-COMPONENTS.md`).
25
+ - Order / COD → `docs/08-ORDER-FORM.md`.
26
+ - Checkout / thanks / product → `docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md`.
25
27
  - Multilang → `docs/13-TEMPLATE-I18N.md`.
26
28
  - Product lists → `docs/14-FILTERATOR.md`.
27
- - Never `useEffect([cartCtx])` that resets shipping `state` to null — bootstrap once; preserve address.
28
29
 
29
30
  ## After edits
30
31
 
31
32
  ```bash
32
33
  npm run build # or npm run check
34
+ npm run typecheck
33
35
  npm run dev # hard-refresh browser
34
36
  ```
@@ -8,25 +8,32 @@ alwaysApply: false
8
8
 
9
9
  You are editing **theme source**, not a hand-maintained `dist/data.json`.
10
10
 
11
- ## Structure
11
+ ## Structure (required)
12
12
 
13
- - Prefer page-level: `pages/<page>/components/hero.tsx` — builds to published `sections.main`
14
- - Legacy: `pages/<page>/sections/<id>/components/` still works (do not mix with flat `components/` on the same page)
15
- - Leaf file: `export const meta` (+ `propsSchema`) + `function App() { … }`
16
- - Folder layout (`hero/component.tsx` + `slots/` / `children/`) only when nesting or colocated helpers are needed
13
+ - **Flat TSX is mandatory for leaf customs:** `pages/<page>/components/<name>.tsx`
14
+ - Same for shared/library leaves: `shared/components/<id>.tsx`, `library/components/<id>.tsx`
15
+ - Leaf file = `export const meta` (+ `propsSchema`) + `function App() { … }`
17
16
  - Type props: `type Props = FeeefLivePropsOf<typeof propsSchema>` then `const p = props as Props`
18
- - `satisfies FeeefComponentMeta<typeof propsSchema>` keeps `meta.props` aligned with the schema
19
- - Prefer **slots** + `slotsLayout` for chrome instead of extra section keys (`header` / `footer`)
17
+ - `satisfies FeeefComponentMeta<typeof propsSchema>` keeps `meta.props` aligned
18
+ - **Folder only** when you need `slots/` / `children/` / colocated modules (`<name>/<name>.tsx`)
19
+ - `$ref` placements are leaf `.json` stubs (not duplicated JSX)
20
+ - Prefer a **flat sibling stack** on the page; use a shell folder only when slots are necessary
21
+ - Built-ins (`cart_order_form`, `product_body`, …) are leaf `.json` with `"type": "…"`
22
+
23
+ ## Forbidden
24
+
25
+ 1. `component.json` + `component.jsx` pairs for new customs
26
+ 2. Both `hero.tsx` and `hero/` for the same id
27
+ 3. Mixing `pages/<page>/components/` and `pages/<page>/sections/` on one page
28
+ 4. Inventing deep nested `*-shell/slots/**` trees when flat siblings + `$ref` work
29
+ 5. Putting JSX inside `.json` meta / `$ref` files
30
+ 6. Duplicating header/footer JSX — use `shared/components/<id>.tsx` + `$ref`
20
31
 
21
32
  ## Rules
22
33
 
23
- 1. Do not put JSX inside `.json` meta files.
24
- 2. Custom components: flat `<name>.tsx` with `export const meta` + `function App()` (legacy folder ok).
25
- 3. Set `"order"` so sibling order is deterministic.
26
- 4. Slot folder names must match `slotsSchema` keys.
27
- 5. After edits: `npm run build` (or rely on `npm run dev` watch).
28
- 6. Read `docs/03-CUSTOM-COMPONENTS.md` before writing JSX.
29
- 7. Read `docs/05-ANTI-PATTERNS.md` before inventing patterns.
30
- 8. If UI exists on another page, use `shared/components/<id>.tsx` — do not duplicate.
31
- 9. Do not mix `pages/<page>/components/` and `pages/<page>/sections/` on the same page.
32
- 10. Prefer `feeef template add page|component` / `remove` over hand-creating trees (keeps manifest + starter meta in sync).
34
+ 1. Set `"order"` so sibling order is deterministic.
35
+ 2. Slot folder names must match `slotsSchema` keys.
36
+ 3. After edits: `npm run build` (or rely on `npm run dev` watch).
37
+ 4. Read `docs/03-CUSTOM-COMPONENTS.md` before writing JSX.
38
+ 5. Read `docs/05-ANTI-PATTERNS.md` before inventing patterns.
39
+ 6. Prefer `feeef template add page|component` / `remove` over hand-creating trees.
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: feeef-theme
3
3
  description: >-
4
- Author Feeef theme packages (pages/shared/library, custom react-live components,
4
+ Author Feeef theme packages (pages/shared/library, flat TSX custom components,
5
5
  TemplateData build, order forms, i18n, filterator, dark/light). Use when editing
6
- this theme's component.json, component.jsx/tsx, locales, or publishing with feeef.
6
+ this theme's *.tsx, locales, or publishing with feeef.
7
7
  ---
8
8
 
9
9
  # Feeef Theme Skill
@@ -13,30 +13,42 @@ description: >-
13
13
  1. `AGENTS.md`
14
14
  2. `docs/00-INDEX.md`
15
15
  3. Task-specific doc from the cheat-sheet
16
- 4. Skim `docs/05-ANTI-PATTERNS.md` before writing JSON/JSX
16
+ 4. Skim `docs/05-ANTI-PATTERNS.md` before writing JSON/TSX
17
+
18
+ ## Authoring contract (required)
19
+
20
+ - **Flat TSX leaves:** `pages/<page>/components/<name>.tsx`
21
+ - `export const meta` (+ `propsSchema`) + `function App()`
22
+ - `type Props = FeeefLivePropsOf<typeof propsSchema>`; `const p = props as Props`
23
+ - `satisfies FeeefComponentMeta<typeof propsSchema>`
24
+ - **Folder only** for `slots/` / `children/` / colocated helpers
25
+ - Shared leaves: `shared/components/<id>.tsx` + placement `{ "$ref": "shared.<id>" }` as `.json`
26
+ - Prefer flat sibling stacks; do **not** invent nested `*-shell/slots/**` when siblings work
27
+ - Scaffold with `feeef template add page|component` — do not invent trees by hand
17
28
 
18
29
  ## Workflows
19
30
 
20
31
  ### Edit a component
21
32
 
22
- 1. Open the folder under `pages/…/components/` or `shared/components/`
23
- 2. Edit `component.json` + `component.jsx` / `.tsx`
33
+ 1. Open the flat `.tsx` (or `…/<name>.tsx` if it has slots)
34
+ 2. Edit `meta` + `App` — no parallel `component.json` for customs
24
35
  3. `npm run build` && hard-refresh `npm run dev`
25
36
 
26
37
  ### Shared chrome
27
38
 
28
- 1. Canonical folder: `shared/components/<id>/`
39
+ 1. Canonical leaf: `shared/components/<id>.tsx`
29
40
  2. Placements: `{ "$ref": "shared.<id>", "instanceId": "…", "props": { } }`
30
41
  3. See `docs/07-SHARED-COMPONENTS.md`
31
42
 
32
43
  ### Order / COD
33
44
 
34
45
  1. Read `docs/08-ORDER-FORM.md` first
35
- 2. `POST /api/orders/create` only; draft + pending; geo rules; anti-abuse
46
+ 2. Prefer native `product_order_form` / `cart_order_form` `.json` leaves
47
+ 3. Custom forms: `POST /api/orders/create` only; draft + pending; geo; anti-abuse
36
48
 
37
49
  ### Special pages
38
50
 
39
- `docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md` — single `main` + slots.
51
+ `docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md` — `main` via flat `components/`; slots when needed.
40
52
 
41
53
  ### Lists / PLP
42
54
 
@@ -50,7 +62,7 @@ description: >-
50
62
 
51
63
  - Top-level custom fields — never under `props`
52
64
  - `function App()` in published `code`
53
- - CSS vars for brand colors
65
+ - CSS vars for brand colors (`hsl(var(--…))`)
54
66
  - Stable `instanceId`
55
67
  - Repeated UI → `shared/` + `$ref`
56
68
  - Orders → create API + draft/pending contract
@@ -6,65 +6,70 @@
6
6
  |---|---|
7
7
  | `build` | source → `dist/data.json` |
8
8
  | `check` | validate |
9
- | `dev` | preview |
9
+ | `typecheck` | `tsc --noEmit` |
10
+ | `test` | smoke custom `App`s |
11
+ | `dev` | remote draft preview |
10
12
  | `publish` | upload (+ optional `--apply`) |
11
13
 
12
- ## Custom component JSON
14
+ ## Flat TSX leaf (required)
13
15
 
14
- ```json
15
- {
16
- "order": 0,
17
- "type": "custom",
18
- "instanceId": "custom_example",
19
- "title": "Example",
20
- "propsSchema": {
21
- "heading": { "type": "string" }
22
- },
23
- "props": { "heading": "Hello" },
24
- "slotsSchema": {},
25
- "slots": {}
26
- }
27
- ```
16
+ ```tsx
17
+ const propsSchema = {
18
+ heading: { type: "string", name: "Heading" },
19
+ } as const;
28
20
 
29
- ## JSX skeleton
21
+ export const meta = {
22
+ type: "custom",
23
+ title: "Hero",
24
+ order: 0,
25
+ propsSchema,
26
+ props: { heading: "" },
27
+ } as const satisfies FeeefComponentMeta<typeof propsSchema>;
28
+
29
+ type Props = FeeefLivePropsOf<typeof propsSchema>;
30
30
 
31
- ```jsx
32
31
  function App() {
33
- const storeCtx = useStore();
34
- const store = storeCtx?.store;
32
+ const p = props as Props;
35
33
  return (
36
34
  <section style={{ color: "hsl(var(--foreground))" }}>
37
- <h1>{props.heading}</h1>
38
- {props.slots?.body}
35
+ <h1>{p.heading || t("home.heroHeading")}</h1>
39
36
  </section>
40
37
  );
41
38
  }
42
39
  ```
43
40
 
41
+ Paths:
42
+
43
+ - `pages/<page>/components/<name>.tsx`
44
+ - `shared/components/<id>.tsx`
45
+ - `library/components/<id>.tsx`
46
+
47
+ Folder (`<name>/<name>.tsx` + `slots/`) **only** when nesting is required.
48
+
44
49
  ## Shared placement
45
50
 
46
51
  ```json
47
52
  {
48
53
  "order": 0,
49
- "$ref": "shared.footer",
50
- "instanceId": "contact_footer_1",
54
+ "$ref": "shared.header",
55
+ "instanceId": "home_header",
51
56
  "props": {}
52
57
  }
53
58
  ```
54
59
 
55
60
  ## Order form (quick)
56
61
 
57
- - `POST /api/orders/create` only
58
- - Draft when phone digits === country length; pending reuses draft `id`
59
- - See `docs/08-ORDER-FORM.md`
62
+ - Prefer native `cart_order_form` / `product_order_form` `.json`
63
+ - Custom: `POST /api/orders/create` only `docs/08-ORDER-FORM.md`
60
64
 
61
65
  ## Pages
62
66
 
63
67
  | Page | Path | Rule |
64
68
  |---|---|---|
65
- | product | `/products/:id` | `main` only layout in slots |
66
- | checkout | `/checkout` | `main` only |
67
- | thank_you | `/thanks` | `main` only |
69
+ | home / products / contact | flat `components/` stack | `$ref` chrome as siblings |
70
+ | product | `/products/:id` | shell folder + slots if needed |
71
+ | checkout | `/checkout` | `cart_order_form` leaf |
72
+ | thank_you | `/thanks` | body + chrome |
68
73
 
69
74
  ## Colors / i18n / lists
70
75
 
@@ -8,9 +8,10 @@ editor, the storefront preview, and published stores. Follow this file exactly.
8
8
  1. **One JSON contract** — `TemplateData` (built into `dist/data.json`) is what Feeef stores and renders. `dist/schema.json` is the editor schema.
9
9
  2. **Source vs dist** — edit `schema.ts`, `pages/`, `shared/`, `library/`, `locales/`, `props.json`; run `npm run build`. Do not hand-edit large `dist/*` as the source of truth.
10
10
  3. **Template schema is yours** — `schema.ts` (`satisfies FeeefThemeSchema`) controls pages/layouts/root `propsSchema`. Build merges Lithium built-ins into `dist/schema.json` for publish.
11
- 4. **`type: "custom"` is react-live** — published `code` is a **string** evaluated in a sandbox. It must expose top-level `function App() { … }`. Author with a flat file like `hero.tsx`: `export const meta` (include `propsSchema`) + `App`. Type props via `FeeefLivePropsOf<typeof propsSchema>`. Local/`npm` imports are **bundled at build time** (see `docs/16-AUTHORING-TS-IMPORTS.md`). Use a folder (`hero/component.tsx`) only when you need `slots/` / `children/` or colocated modules.
11
+ 4. **`type: "custom"` is react-live** — published `code` is a **string** evaluated in a sandbox. It must expose top-level `function App() { … }`. **Author flat TSX:** `pages/<page>/components/<name>.tsx` with `export const meta` (include `propsSchema`) + `App`. Type props via `FeeefLivePropsOf<typeof propsSchema>` and `satisfies FeeefComponentMeta<typeof propsSchema>`. Local/`npm` imports are **bundled at build time** (see `docs/16-AUTHORING-TS-IMPORTS.md`). Use a folder (`<name>/<name>.tsx`) **only** when you need `slots/` / `children/` or colocated modules. **Do not** author new customs as `component.json` + `component.jsx`.
12
12
  5. **`code` / `propsSchema` / `slotsSchema` / `slots` / `slotsLayout` are TOP-LEVEL** on the component object — never nest them under `props`.
13
13
  6. **Planes stay separate** — schema (editable fields) ≠ merchant content (`props`) ≠ renderer.
14
+ 7. **Prefer flat sibling stacks** — `header.json` (`$ref`) + `hero.tsx` + `footer.json` under `pages/<page>/components/`. Do **not** invent deep nested `*-shell/slots/**` trees when siblings work.
14
15
 
15
16
  ## Before you change anything
16
17
 
@@ -36,7 +37,9 @@ editor, the storefront preview, and published stores. Follow this file exactly.
36
37
  | Keep `instanceId` stable when editing existing components | Selection + React keys |
37
38
  | `children` only for `grid` / `flex` / `container` | Other types use `slots` |
38
39
  | Empty section **keys** optional; published JSON still has `sections` object | Flat disk → `sections.main`; legacy multi-section keys still work |
39
- | UI on 2+ pages → `shared/components/` + `$ref` | No duplicated chrome JSX |
40
+ | UI on 2+ pages → `shared/components/<id>.tsx` + `$ref` | No duplicated chrome JSX |
41
+ | Flat TSX leaves for customs — no `component.json`+`jsx` pairs | Meta in `export const meta` |
42
+ | No hand-built nested shell trees when flat stack works | Siblings under `components/` |
40
43
  | Custom order forms → `docs/08-ORDER-FORM.md` | Draft, geo, create API, anti-abuse |
41
44
  | Never re-bootstrap shipping on every `cartCtx` change | Wipes state/city |
42
45
  | Add to cart = `addCurrentItemToCart` (or `cart.add`) | Not `updateCurrentItem({})` theater |
@@ -60,7 +63,7 @@ dist/data.json # TemplateData
60
63
  dist/schema.json # merged editor schema (not hand-edited)
61
64
  ```
62
65
 
63
- Prefer a single `main` stack + component **slots** for chrome. Do not mix flat `components/` and `sections/` on one page.
66
+ Prefer a **flat sibling stack** under `pages/<page>/components/` (builds to `sections.main`). Use a shell folder + slots only when nesting is required (typical for product/checkout). Do not mix flat `components/` and `sections/` on one page.
64
67
 
65
68
  ## Local commands
66
69
 
@@ -85,7 +88,7 @@ npm run publish -- --apply
85
88
 
86
89
  **Preview:** `npm run dev` pushes `metadata.templatePreview` and opens `?preview=…`. Customers keep live `templateData`. Exit via banner or `/?preview=0`. Go live only with `publish --apply`.
87
90
 
88
- **AI / agents:** use `feeef template add page|component` (and `remove`) instead of inventing folder trees by hand. New pages are flat `components/` → published `sections.main`. Do not mix flat `components/` with `sections/` on the same page.
91
+ **AI / agents:** use `feeef template add page|component` (and `remove`) instead of inventing folder trees by hand. New pages are flat `components/*.tsx` → published `sections.main`. Shared chrome = flat `shared/components/<id>.tsx` + `$ref` `.json` placements. Do **not** mix flat `components/` with `sections/` on the same page. Do **not** invent deep `*-shell/slots/**` nests when a flat stack works.
89
92
 
90
93
  Editor: `tsconfig.json` + `types/feeef-live-scope.d.ts` + `types/feeef-template-schema.d.ts` explain react-live globals and `FeeefThemeSchema` (template schema type) to VS Code / Cursor.
91
94
 
@@ -8,7 +8,7 @@ npm install -g @feeef.dev/cli
8
8
 
9
9
  **AI / Cursor:** read [`AGENTS.md`](./AGENTS.md) and [`docs/00-INDEX.md`](./docs/00-INDEX.md) first. Rules and skills live under [`.cursor/`](./.cursor/).
10
10
 
11
- Author components under `pages/<page>/components/<name>.tsx` (`export const meta` + `function App()`). Build maps them to published `sections.main`. Legacy `sections/<id>/` still works. Local `import`s are bundled at `npm run build` into react-live `code` (`react` stays provided by the storefront).
11
+ Author components under `pages/<page>/components/<name>.tsx` (`export const meta` + `function App()`). **Flat TSX is required for leaf customs.** Build maps them to published `sections.main`. Use a folder only for `slots/` / `children/`. Shared chrome: `shared/components/<id>.tsx` + `$ref` `.json` placements. Local `import`s are bundled at `npm run build` into react-live `code` (`react` stays provided by the storefront).
12
12
 
13
13
  Editor: `tsconfig.json` + `types/feeef-live-scope.d.ts` teach VS Code / Cursor about live-scope globals (`props`, `t`, `useStore`, …). Run `npm install` once after init.
14
14
 
@@ -2,12 +2,11 @@
2
2
 
3
3
  > Theme package copy — paths assume this theme folder is the project root.
4
4
 
5
- Full API: `docs/03-CUSTOM-COMPONENTS.md`.
6
- Architecture: `docs/03-CUSTOM-COMPONENTS.md`.
5
+ Full API and authoring contract for `type: "custom"` components.
7
6
 
8
7
  ## What a custom component is
9
8
 
10
- A `TemplateDataComponent` with:
9
+ A `TemplateDataComponent` with top-level:
11
10
 
12
11
  ```json
13
12
  {
@@ -23,29 +22,68 @@ A `TemplateDataComponent` with:
23
22
  }
24
23
  ```
25
24
 
26
- `code` is executed by `CustomLive` (`components/system/custom-live.tsx`) via **react-live**. Authoring may use `component.tsx` and local/npm `import`s — the **theme build** (esbuild) emits a single `code` string. There is still **no browser bundler** at runtime: `react` / `react-dom` stay in the live scope (do not import them expecting a separate React copy).
25
+ `code` is executed by `CustomLive` via **react-live**. You author **TypeScript/TSX on disk**; `npm run build` (template-kit) emits the `code` string. There is **no browser bundler** at runtime: `react` / `react-dom` stay in the live scope.
27
26
 
28
- ## Required code shape
27
+ ## Required authoring shape (flat TSX)
28
+
29
+ **Prefer a single flat file** under the page (or shared/library):
30
+
31
+ ```
32
+ pages/home/components/hero.tsx
33
+ shared/components/header.tsx
34
+ library/components/promo-banner.tsx
35
+ ```
36
+
37
+ ```tsx
38
+ const propsSchema = {
39
+ heading: { type: "string", name: "Heading" },
40
+ } as const;
41
+
42
+ export const meta = {
43
+ type: "custom",
44
+ title: "Hero",
45
+ order: 0,
46
+ propsSchema,
47
+ props: { heading: "" },
48
+ } as const satisfies FeeefComponentMeta<typeof propsSchema>;
49
+
50
+ type Props = FeeefLivePropsOf<typeof propsSchema>;
29
51
 
30
- ```jsx
31
52
  function App() {
32
- const storeCtx = useStore();
33
- //
34
- return <div>…</div>;
53
+ const p = props as Props;
54
+ return <h1>{p.heading || t("home.heroHeading")}</h1>;
35
55
  }
36
56
  ```
37
57
 
38
- - Entry must be **`function App()`** (warning if missing; may not render).
58
+ Rules:
59
+
60
+ - Entry must be **`function App()`** (published `code` must expose it).
39
61
  - Prefer **`React.useState` / `React.useEffect` / …** — merchant preview may not inject bare hooks.
40
- - No `import` / `export` / `require`.
62
+ - **Do not** author a parallel `component.json` for customs — meta lives in `export const meta`.
63
+ - **Do not** put `import` / `export` / `require` in the *published* live string (build strips / bundles). Authoring **may** use local/`npm` imports — see [16-AUTHORING-TS-IMPORTS.md](./16-AUTHORING-TS-IMPORTS.md).
64
+ - Type props with `FeeefLivePropsOf<typeof propsSchema>`; cast `const p = props as Props`.
65
+
66
+ ### When to use a folder
41
67
 
42
- ## Injected scope (no imports needed)
68
+ Use a folder **only** when you need `slots/`, `children/`, or colocated modules:
69
+
70
+ ```
71
+ pages/product/components/product-shell/
72
+ product-shell.tsx # export const meta + App (includes slotsSchema)
73
+ slots/header/header.json # $ref or leaf
74
+ slots/body/gallery.tsx
75
+ slots/form/order.json # built-in type
76
+ ```
77
+
78
+ Never create both `hero.tsx` and `hero/` for the same id.
79
+
80
+ ## Injected scope (no imports needed at runtime)
43
81
 
44
82
  | Symbol | Use |
45
83
  |---|---|
46
84
  | `React` | Hooks, Fragment |
47
- | `props` | Instance props |
48
- | `props.slots` | Pre-rendered slot children (`props.slots?.sections`) |
85
+ | `props` | Instance props — cast with `FeeefLivePropsOf` |
86
+ | `props.slots` | Pre-rendered slot children |
49
87
  | `SlotContextBridge` | Provide context to slot children |
50
88
  | `useSlotContext(key)` | Read parent slot context |
51
89
  | `useStore()` | `{ store }` or null — **null-check** |
@@ -54,12 +92,12 @@ function App() {
54
92
  | `useFeeef` | SDK instance or null |
55
93
  | `useTheme()` | next-themes |
56
94
  | `useTemplate()` | read-only template state |
57
- | `t(key, params?)` | Theme locales (`data.i18n`) see [13-TEMPLATE-I18N.md](./13-TEMPLATE-I18N.md) |
95
+ | `t(key, params?)` | Theme locales — [13-TEMPLATE-I18N.md](./13-TEMPLATE-I18N.md) |
58
96
  | `useFeeefT()` / `useFeeefLocale()` | Theme i18n hooks |
59
97
  | `useRouter` / `usePathname` / `useSearchParams` | next/navigation |
60
- | `Link` | next/link — prefer over `<a>` |
98
+ | `Link` | next/link — prefer over `<a>` for in-app nav |
61
99
  | `RouterNav` | clickable block with stopPropagation for nested cards |
62
- | `SlotsLayout` | Renders `props.slotsLayout` (sm/md/lg row/column trees) with `props.slots` — prefer over hardcoding slot order |
100
+ | `SlotsLayout` | Renders `props.slotsLayout` with `props.slots` |
63
101
  | `dartColorToCssColor` | convert Flutter color ints from **props** |
64
102
 
65
103
  For product markdown details use registry **`product_body`** (reads `product.body`), not CustomLive HTML injection.
@@ -70,27 +108,19 @@ For product markdown details use registry **`product_body`** (reads `product.bod
70
108
  - Corners: `var(--corners-card)`, `var(--corners-buttons-large)`, …
71
109
  - **Do not** assign `store.decoration.primary` directly (Flutter AARRGGBB int).
72
110
  - Prefer store fields for chrome: `store.logoUrl`, `store.name`, `store.contacts`, …
73
- - **Dark / light:** ride native tokens (`:root` / `.dark`). Do not invent a parallel palette. Full contract: [12-DARK-LIGHT-THEME.md](./12-DARK-LIGHT-THEME.md).
74
- - Toggle: `const { resolvedTheme, setTheme } = useTheme();`
111
+ - **Dark / light:** ride native tokens (`:root` / `.dark`) [12-DARK-LIGHT-THEME.md](./12-DARK-LIGHT-THEME.md).
75
112
 
76
113
  ## Slots in JSX
77
114
 
78
- Parent:
79
-
80
- ```jsx
81
- <SlotContextBridge value={{ shell: { isOpen, setIsOpen } }}>
82
- {props.slots?.sections}
83
- </SlotContextBridge>
115
+ ```tsx
116
+ {props.slots?.header}
117
+ <main>{props.slots?.body}</main>
84
118
  {props.slots?.footer}
85
119
  ```
86
120
 
87
- Child (in slot):
88
-
89
- ```jsx
90
- const shell = useSlotContext("shell");
91
- ```
121
+ Or prefer `<SlotsLayout />` when `slotsLayout` is set.
92
122
 
93
- **Never** use slot context for navigation (`routerNav` stubs). Use `Link` / `RouterNav` / `useRouter()`.
123
+ **Never** use slot context for navigation. Use `Link` / `RouterNav` / `useRouter()`.
94
124
 
95
125
  ## Product media
96
126
 
@@ -99,18 +129,17 @@ const shell = useSlotContext("shell");
99
129
 
100
130
  ## Cart
101
131
 
102
- ```jsx
132
+ ```tsx
103
133
  const cartCtx = useFeeefCart();
104
134
  if (!cartCtx) return null;
105
135
  cartCtx.cart.add({ product, quantity: 1, variantPath: "Color/Red" });
106
136
  ```
107
137
 
108
- ## Kit authoring
109
-
110
- In `…/my-comp/`:
138
+ ## Kit authoring checklist
111
139
 
112
- - `component.json` meta (no `code` string when using jsx file)
113
- - `component.jsx` the `function App()` source compiled into `code`
114
- - `slots/<slotId>/<child>/` nested components
140
+ 1. Prefer `feeef template add component <page> <name>` flat `<name>.tsx`
141
+ 2. Put chrome reused on 2+ pages in `shared/components/<id>.tsx` + `$ref` placements ([07](./07-SHARED-COMPONENTS.md))
142
+ 3. Built-ins (order forms, `product_body`) stay as leaf `.json` with `type: "…"`
143
+ 4. `npm run build` then `npm run dev`
115
144
 
116
- See [04-WORKFLOW.md](./04-WORKFLOW.md).
145
+ See [04-WORKFLOW.md](./04-WORKFLOW.md) / [04-WORKFLOW.md](./04-WORKFLOW.md).
@@ -63,7 +63,7 @@ pages/<page>/components/ # preferred (→ published sections.main)
63
63
  <name>.tsx # leaf: export const meta + App
64
64
  <name>.json # leaf built-in / no code
65
65
  <name>/ # only when slots/ or children/ needed
66
- component.tsx
66
+ <name>.tsx
67
67
  slots/… | children/…
68
68
  pages/<page>/sections/<section>/components/ # legacy multi-section (still supported)
69
69
  shared/components/<id>.tsx
@@ -98,9 +98,9 @@ Types: `types/feeef-template-schema.d.ts`. Fallback: `schema.json` (same shape).
98
98
 
99
99
  ## Custom components
100
100
 
101
- - Prefer page-level `components/hero.tsx` — `export const meta` + `function App() { … }`
102
- - Use a folder only when you need `slots/` or `children/` (or colocated helpers)
103
- - Chrome / layout: use **slots** + `slotsLayout` on a shell component (not extra section keys)
101
+ - **Required:** page-level `components/hero.tsx` — `export const meta` + `function App() { … }`
102
+ - Use a folder **only** when you need `slots/` or `children/` (or colocated helpers)
103
+ - Prefer flat sibling stacks (`header.json` `$ref` + section `.tsx` + `footer.json`); shell folders only when slots are necessary
104
104
  - Type-safe props from schema:
105
105
 
106
106
  ```tsx
@@ -124,6 +124,7 @@ function App() {
124
124
 
125
125
  - Build strips `meta` and bundles into react-live `code` (see [16-AUTHORING-TS-IMPORTS.md](./16-AUTHORING-TS-IMPORTS.md))
126
126
  - `react` stays provided by the storefront — do not bundle a second React
127
+ - **Do not** author new customs as `component.json` + `component.jsx`
127
128
 
128
129
  ## Do not
129
130
 
@@ -132,3 +133,5 @@ function App() {
132
133
  - Call `ff.orders.send` from custom checkout (use `POST /api/orders/create` — [08](./08-ORDER-FORM.md))
133
134
  - Expect `npm run dev` to update what customers see (it does not)
134
135
  - Clone the Lithium storefront just to preview (remote draft is the default)
136
+ - Invent deep nested `*-shell/slots/**` trees when a flat `components/` stack works
137
+ - Create both `name.tsx` and `name/` for the same id
@@ -35,7 +35,7 @@ High-signal mistakes AIs and humans make in this system.
35
35
  | `<a href="/p/x">` for in-app nav | `<Link href="/p/x">` or `RouterNav` |
36
36
  | `useSlotContext('x').routerNav.push` | Real `useRouter` / `Link` / `RouterNav` |
37
37
  | Assuming `useStore()` non-null | Always null-check |
38
- | TypeScript / JSX types in published `code` | Author `component.tsx`; build strips types into `code` |
38
+ | TypeScript / JSX types in published `code` | Author `<name>.tsx` (or `<name>/<name>.tsx` with slots); build strips types into `code` |
39
39
  | Assuming raw `import` works inside react-live without build | Use theme `npm run build` — imports are bundled into `code` |
40
40
  | Bundling a second `react` into `code` | Mark react as external (build does this); use live scope |
41
41
 
@@ -46,12 +46,13 @@ High-signal mistakes AIs and humans make in this system.
46
46
  | Hand-edit `dist/data.json` as primary workflow | Edit `pages/` / `shared/`, then `npm run build` |
47
47
  | Use Node APIs inside component source | Use `utils/get-template.ts` |
48
48
  | Arbitrary filesystem preview paths | Only `feeef template dev` / CLI override |
49
- | Treating `npm run dev` as “go live” | Draft only — use `publish --apply` for customers |
50
- | Cloning Lithium storefront just to preview | Default is remote draft (`?preview=`) |
51
49
  | Expect Shopify reference dumps to render | They are not Feeef themes |
52
- | Skip `npm run check` after edits | Rebuild and refresh draft preview |
50
+ | Skip `npm run check` after edits | Rebuild and hard-refresh preview |
53
51
  | Commit `dist/` as source | Source is the folder tree |
54
- | Duplicate the same footer/navbar JSX on every page | Promote to `shared/components/<id>/` + `$ref` |
52
+ | Duplicate the same footer/navbar JSX on every page | Promote to `shared/components/<id>.tsx` + `$ref` |
53
+ | Author customs as `component.json` + `component.jsx` | Flat `<name>.tsx` with `export const meta` + `App` |
54
+ | Hand-build nested `*-shell/slots/**` when a flat stack works | Flat `pages/<page>/components/*` siblings + `$ref` |
55
+ | Both `hero.tsx` and `hero/` for the same id | Keep **one** entry (folder only if slots/children needed) |
55
56
  | Copy dawn-order-form as “complete” checkout | Follow `docs/08-ORDER-FORM.md` + native `order-form.tsx` |
56
57
  | `ff.orders.send` from custom JSX | `fetch("/api/orders/create")` |
57
58
  | Free-text wilaya/city without cascade/indices | Legacy 1-based indices or new state codes + city names |
@@ -66,7 +67,7 @@ High-signal mistakes AIs and humans make in this system.
66
67
 
67
68
  ## Registry / built-ins
68
69
 
69
- Prefer built-in types when they fit; otherwise `type: "custom"` with `component.jsx` / `.tsx`.
70
+ Prefer built-in types when they fit; otherwise `type: "custom"` with flat `.tsx` (`export const meta` + `App`).
70
71
 
71
72
  ## AI generation
72
73