@feeef.dev/cli 0.2.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.
Files changed (61) hide show
  1. package/LICENSE +6 -0
  2. package/README.md +94 -0
  3. package/dist/bin.js +2752 -0
  4. package/dist/bin.js.map +1 -0
  5. package/dist/index.d.ts +6 -0
  6. package/dist/index.js +2730 -0
  7. package/dist/index.js.map +1 -0
  8. package/package.json +67 -0
  9. package/scaffolds/blank/.cursor/rules/feeef-theme.mdc +34 -0
  10. package/scaffolds/blank/.cursor/rules/filterator.mdc +13 -0
  11. package/scaffolds/blank/.cursor/rules/order-form.mdc +17 -0
  12. package/scaffolds/blank/.cursor/rules/theme-source.mdc +32 -0
  13. package/scaffolds/blank/.cursor/skills/feeef-filterator/SKILL.md +15 -0
  14. package/scaffolds/blank/.cursor/skills/feeef-theme/SKILL.md +56 -0
  15. package/scaffolds/blank/.cursor/skills/feeef-theme/reference.md +73 -0
  16. package/scaffolds/blank/.vscode/extensions.json +3 -0
  17. package/scaffolds/blank/.vscode/settings.json +13 -0
  18. package/scaffolds/blank/AGENTS.md +104 -0
  19. package/scaffolds/blank/README.md +21 -0
  20. package/scaffolds/blank/docs/00-INDEX.md +33 -0
  21. package/scaffolds/blank/docs/03-CUSTOM-COMPONENTS.md +116 -0
  22. package/scaffolds/blank/docs/04-WORKFLOW.md +129 -0
  23. package/scaffolds/blank/docs/05-ANTI-PATTERNS.md +80 -0
  24. package/scaffolds/blank/docs/07-SHARED-COMPONENTS.md +144 -0
  25. package/scaffolds/blank/docs/08-ORDER-FORM.md +376 -0
  26. package/scaffolds/blank/docs/09-THEME-PORTING.md +211 -0
  27. package/scaffolds/blank/docs/10-SCHEMA-LIBRARY.md +127 -0
  28. package/scaffolds/blank/docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md +81 -0
  29. package/scaffolds/blank/docs/12-DARK-LIGHT-THEME.md +164 -0
  30. package/scaffolds/blank/docs/13-TEMPLATE-I18N.md +320 -0
  31. package/scaffolds/blank/docs/14-FILTERATOR.md +433 -0
  32. package/scaffolds/blank/docs/16-AUTHORING-TS-IMPORTS.md +73 -0
  33. package/scaffolds/blank/feeef.template.json +7 -0
  34. package/scaffolds/blank/locales/README.md +4 -0
  35. package/scaffolds/blank/locales/ar.json +10 -0
  36. package/scaffolds/blank/locales/en.json +10 -0
  37. package/scaffolds/blank/package-lock.json +1975 -0
  38. package/scaffolds/blank/package.json +23 -0
  39. package/scaffolds/blank/pages/home/components/hero.tsx +34 -0
  40. package/scaffolds/blank/pages/home/page.json +3 -0
  41. package/scaffolds/blank/props.json +6 -0
  42. package/scaffolds/blank/schema.ts +49 -0
  43. package/scaffolds/blank/tsconfig.json +24 -0
  44. package/scaffolds/blank/types/feeef-live-scope.d.ts +162 -0
  45. package/scaffolds/blank/types/feeef-template-schema.d.ts +84 -0
  46. package/vendor/template-kit/README.md +64 -0
  47. package/vendor/template-kit/bin/dev.mjs +61 -0
  48. package/vendor/template-kit/bin/feeef-template.mjs +212 -0
  49. package/vendor/template-kit/data/lithium-schema.json +4733 -0
  50. package/vendor/template-kit/lib/build.mjs +377 -0
  51. package/vendor/template-kit/lib/compile-component.mjs +188 -0
  52. package/vendor/template-kit/lib/component-meta.mjs +481 -0
  53. package/vendor/template-kit/lib/library.mjs +168 -0
  54. package/vendor/template-kit/lib/locales.mjs +68 -0
  55. package/vendor/template-kit/lib/paths.mjs +84 -0
  56. package/vendor/template-kit/lib/shared.mjs +268 -0
  57. package/vendor/template-kit/lib/theme-schema.mjs +300 -0
  58. package/vendor/template-kit/lib/unpack.mjs +324 -0
  59. package/vendor/template-kit/lib/validate.mjs +207 -0
  60. package/vendor/template-kit/schemas/component.schema.json +55 -0
  61. package/vendor/template-kit/schemas/template.schema.json +18 -0
@@ -0,0 +1,32 @@
1
+ ---
2
+ description: Rules when editing theme component source (tsx / json / slots).
3
+ globs: pages/**/*,shared/**/*,library/**/*
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Theme source folders
8
+
9
+ You are editing **theme source**, not a hand-maintained `dist/data.json`.
10
+
11
+ ## Structure
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
17
+ - 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`)
20
+
21
+ ## Rules
22
+
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).
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: feeef-filterator
3
+ description: >-
4
+ Feeef filterator + products/categories list APIs for PLPs, related products,
5
+ and search grids in theme custom components. Canonical: docs/14-FILTERATOR.md.
6
+ ---
7
+
8
+ # Feeef Filterator
9
+
10
+ Read **`docs/14-FILTERATOR.md`** before changing product/category fetch logic.
11
+
12
+ - Always pass `store_id`
13
+ - Prefer server `in_stock` / `price_min` / `filterator` over client-only filtering
14
+ - Related products = same category / random / sold — no dedicated related API
15
+ - `media` values are URL strings; link to `/products/…`
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: feeef-theme
3
+ description: >-
4
+ Author Feeef theme packages (pages/shared/library, custom react-live components,
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.
7
+ ---
8
+
9
+ # Feeef Theme Skill
10
+
11
+ ## First action
12
+
13
+ 1. `AGENTS.md`
14
+ 2. `docs/00-INDEX.md`
15
+ 3. Task-specific doc from the cheat-sheet
16
+ 4. Skim `docs/05-ANTI-PATTERNS.md` before writing JSON/JSX
17
+
18
+ ## Workflows
19
+
20
+ ### Edit a component
21
+
22
+ 1. Open the folder under `pages/…/components/` or `shared/components/`
23
+ 2. Edit `component.json` + `component.jsx` / `.tsx`
24
+ 3. `npm run build` && hard-refresh `npm run dev`
25
+
26
+ ### Shared chrome
27
+
28
+ 1. Canonical folder: `shared/components/<id>/`
29
+ 2. Placements: `{ "$ref": "shared.<id>", "instanceId": "…", "props": { } }`
30
+ 3. See `docs/07-SHARED-COMPONENTS.md`
31
+
32
+ ### Order / COD
33
+
34
+ 1. Read `docs/08-ORDER-FORM.md` first
35
+ 2. `POST /api/orders/create` only; draft + pending; geo rules; anti-abuse
36
+
37
+ ### Special pages
38
+
39
+ `docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md` — single `main` + slots.
40
+
41
+ ### Lists / PLP
42
+
43
+ `docs/14-FILTERATOR.md` + skill `feeef-filterator`.
44
+
45
+ ### TS / imports
46
+
47
+ `docs/16-AUTHORING-TS-IMPORTS.md` — build bundles into react-live `code`.
48
+
49
+ ## Invariants
50
+
51
+ - Top-level custom fields — never under `props`
52
+ - `function App()` in published `code`
53
+ - CSS vars for brand colors
54
+ - Stable `instanceId`
55
+ - Repeated UI → `shared/` + `$ref`
56
+ - Orders → create API + draft/pending contract
@@ -0,0 +1,73 @@
1
+ # Feeef Theme — Quick Reference
2
+
3
+ ## Commands (theme root)
4
+
5
+ | npm script | Effect |
6
+ |---|---|
7
+ | `build` | source → `dist/data.json` |
8
+ | `check` | validate |
9
+ | `dev` | preview |
10
+ | `publish` | upload (+ optional `--apply`) |
11
+
12
+ ## Custom component JSON
13
+
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
+ ```
28
+
29
+ ## JSX skeleton
30
+
31
+ ```jsx
32
+ function App() {
33
+ const storeCtx = useStore();
34
+ const store = storeCtx?.store;
35
+ return (
36
+ <section style={{ color: "hsl(var(--foreground))" }}>
37
+ <h1>{props.heading}</h1>
38
+ {props.slots?.body}
39
+ </section>
40
+ );
41
+ }
42
+ ```
43
+
44
+ ## Shared placement
45
+
46
+ ```json
47
+ {
48
+ "order": 0,
49
+ "$ref": "shared.footer",
50
+ "instanceId": "contact_footer_1",
51
+ "props": {}
52
+ }
53
+ ```
54
+
55
+ ## Order form (quick)
56
+
57
+ - `POST /api/orders/create` only
58
+ - Draft when phone digits === country length; pending reuses draft `id`
59
+ - See `docs/08-ORDER-FORM.md`
60
+
61
+ ## Pages
62
+
63
+ | Page | Path | Rule |
64
+ |---|---|---|
65
+ | product | `/products/:id` | `main` only — layout in slots |
66
+ | checkout | `/checkout` | `main` only |
67
+ | thank_you | `/thanks` | `main` only |
68
+
69
+ ## Colors / i18n / lists
70
+
71
+ - Colors: `hsl(var(--primary))` — `docs/12-DARK-LIGHT-THEME.md`
72
+ - Copy: `t('key')` + `locales/*.json` — `docs/13-TEMPLATE-I18N.md`
73
+ - Products: filterator / list params — `docs/14-FILTERATOR.md`
@@ -0,0 +1,3 @@
1
+ {
2
+ "recommendations": ["dbaeumer.vscode-eslint"]
3
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "typescript.tsdk": "node_modules/typescript/lib",
3
+ "typescript.enablePromptUseWorkspaceTsdk": true,
4
+ "typescript.tsserver.maxTsServerMemory": 3072,
5
+ "files.associations": {
6
+ "**/components/**/*.tsx": "typescriptreact",
7
+ "**/components/**/*.jsx": "javascriptreact",
8
+ "**/component.tsx": "typescriptreact",
9
+ "**/component.jsx": "javascriptreact"
10
+ },
11
+ "editor.defaultFormatter": null,
12
+ "js/ts.implicitProjectConfig.checkJs": false
13
+ }
@@ -0,0 +1,104 @@
1
+ # AGENTS — Feeef Theme (READ BEFORE EDITING)
2
+
3
+ You are editing a **Feeef theme package** (this folder). Mistakes break the merchant
4
+ editor, the storefront preview, and published stores. Follow this file exactly.
5
+
6
+ ## Mandatory mental model
7
+
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
+ 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
+ 3. **Theme 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.
12
+ 5. **`code` / `propsSchema` / `slotsSchema` / `slots` / `slotsLayout` are TOP-LEVEL** on the component object — never nest them under `props`.
13
+ 6. **Planes stay separate** — schema (editable fields) ≠ merchant content (`props`) ≠ renderer.
14
+
15
+ ## Before you change anything
16
+
17
+ 1. Read [`docs/00-INDEX.md`](./docs/00-INDEX.md) and the doc for your task.
18
+ 2. Custom JSX/TSX → [`docs/03-CUSTOM-COMPONENTS.md`](./docs/03-CUSTOM-COMPONENTS.md) + skim [`docs/05-ANTI-PATTERNS.md`](./docs/05-ANTI-PATTERNS.md).
19
+ 3. Order / COD / checkout forms → [`docs/08-ORDER-FORM.md`](./docs/08-ORDER-FORM.md) **first**.
20
+ 4. Folder layout / CLI → [`docs/04-WORKFLOW.md`](./docs/04-WORKFLOW.md).
21
+ 5. Shared chrome → [`docs/07-SHARED-COMPONENTS.md`](./docs/07-SHARED-COMPONENTS.md).
22
+ 6. Checkout / thanks / product pages → [`docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md`](./docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md).
23
+ 7. Dark/light → [`docs/12-DARK-LIGHT-THEME.md`](./docs/12-DARK-LIGHT-THEME.md).
24
+ 8. Multilang → [`docs/13-TEMPLATE-I18N.md`](./docs/13-TEMPLATE-I18N.md).
25
+ 9. Product grids / filters → [`docs/14-FILTERATOR.md`](./docs/14-FILTERATOR.md).
26
+ 10. After edits: `npm run build` (or `npm run check`), then hard-refresh `npm run dev`.
27
+
28
+ ## Hard rules (never violate)
29
+
30
+ | Rule | Why |
31
+ |---|---|
32
+ | Do not put `code` / `propsSchema` / `slots*` inside `props` | Breaks editor + renderer |
33
+ | Prefer `React.useState` (not bare `useState`) in custom code | Merchant editor scope |
34
+ | Prefer `hsl(var(--primary))` over decoration color ints | Dark/light CSS tokens |
35
+ | Use `Link` / `RouterNav` / `useRouter()` for in-app nav | Slot-context routers are stubs |
36
+ | Keep `instanceId` stable when editing existing components | Selection + React keys |
37
+ | `children` only for `grid` / `flex` / `container` | Other types use `slots` |
38
+ | 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
+ | Custom order forms → `docs/08-ORDER-FORM.md` | Draft, geo, create API, anti-abuse |
41
+ | Never re-bootstrap shipping on every `cartCtx` change | Wipes state/city |
42
+ | Add to cart = `addCurrentItemToCart` (or `cart.add`) | Not `updateCurrentItem({})` theater |
43
+ | Submit orders via `POST /api/orders/create` | Not browser `ff.orders.send` |
44
+ | Do not invent unknown registry `type` strings | Prefer `custom` or built-ins |
45
+ | Do not bypass order anti-abuse checks | Honeypot, dwell, in-flight lock |
46
+
47
+ ## Theme layout
48
+
49
+ ```
50
+ schema.ts # theme-owned schema overlay
51
+ props.json # default root props
52
+ pages/<page>/components/ # preferred — builds to sections.main
53
+ <name>.tsx
54
+ pages/<page>/sections/<id>/… # legacy multi-section (compat)
55
+ shared/components/<id>.tsx
56
+ library/components/<id>.tsx
57
+ locales/{en,ar,…}.json
58
+ feeef.template.json
59
+ dist/data.json # TemplateData
60
+ dist/schema.json # merged editor schema (not hand-edited)
61
+ ```
62
+
63
+ Prefer a single `main` stack + component **slots** for chrome. Do not mix flat `components/` and `sections/` on one page.
64
+
65
+ ## Local commands
66
+
67
+ ```bash
68
+ feeef signin
69
+ feeef use # bind a store
70
+ npm install # once — React/TS types for the editor
71
+
72
+ # Scaffold (prefer these over hand-creating folders)
73
+ feeef template add page <pageId> # pages/<id>/components/
74
+ feeef template add component <pageId> <name> # starter <name>.tsx
75
+ feeef template remove page <pageId> --yes
76
+ feeef template remove component <pageId> <name> --yes
77
+
78
+ npm run build # → dist/data.json
79
+ npm run check
80
+ npm run typecheck # optional IDE/tsc
81
+ npm run dev # preview
82
+ npm run publish -- --apply
83
+ ```
84
+
85
+ **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.
86
+
87
+ Editor: `tsconfig.json` + `types/feeef-live-scope.d.ts` + `types/feeef-template-schema.d.ts` explain react-live globals and `FeeefThemeSchema` to VS Code / Cursor.
88
+
89
+ ## Companion docs
90
+
91
+ | Doc | When |
92
+ |---|---|
93
+ | [`docs/03-CUSTOM-COMPONENTS.md`](./docs/03-CUSTOM-COMPONENTS.md) | JSX sandbox + scope |
94
+ | [`docs/04-WORKFLOW.md`](./docs/04-WORKFLOW.md) | Build / preview / publish |
95
+ | [`docs/05-ANTI-PATTERNS.md`](./docs/05-ANTI-PATTERNS.md) | Common AI mistakes |
96
+ | [`docs/07-SHARED-COMPONENTS.md`](./docs/07-SHARED-COMPONENTS.md) | `$ref` / shared |
97
+ | [`docs/08-ORDER-FORM.md`](./docs/08-ORDER-FORM.md) | COD / checkout contract |
98
+ | [`docs/09-THEME-PORTING.md`](./docs/09-THEME-PORTING.md) | Full-theme craft lessons |
99
+ | [`docs/10-SCHEMA-LIBRARY.md`](./docs/10-SCHEMA-LIBRARY.md) | Theme library catalog |
100
+ | [`docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md`](./docs/11-PAGES-CHECKOUT-THANKS-PRODUCT.md) | Special pages |
101
+ | [`docs/12-DARK-LIGHT-THEME.md`](./docs/12-DARK-LIGHT-THEME.md) | Theme mode + tokens |
102
+ | [`docs/13-TEMPLATE-I18N.md`](./docs/13-TEMPLATE-I18N.md) | `locales` + `t()` |
103
+ | [`docs/14-FILTERATOR.md`](./docs/14-FILTERATOR.md) | Product/category lists |
104
+ | [`docs/16-AUTHORING-TS-IMPORTS.md`](./docs/16-AUTHORING-TS-IMPORTS.md) | TSX + npm imports |
@@ -0,0 +1,21 @@
1
+ # Feeef theme
2
+
3
+ This folder is a **Node.js package** (see `package.json`). Scripts wrap the global `feeef` CLI — install it once (`npm link` from the Feeef `cli/` package, or `npm install -g @feeef.dev/cli`).
4
+
5
+ **AI / Cursor:** read [`AGENTS.md`](./AGENTS.md) and [`docs/00-INDEX.md`](./docs/00-INDEX.md) first. Rules and skills live under [`.cursor/`](./.cursor/).
6
+
7
+ 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).
8
+
9
+ 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.
10
+
11
+ ```bash
12
+ feeef signin
13
+ feeef use # or: feeef use <store-id-or-slug>
14
+
15
+ npm run build # → dist/data.json
16
+ npm run check
17
+ npm run dev # → http://{slug}.localhost.feeef.org:3456
18
+ npm run publish -- --apply
19
+ ```
20
+
21
+ See `feeef template --help`.
@@ -0,0 +1,33 @@
1
+ # Theme docs — index
2
+
3
+ Read [`../AGENTS.md`](../AGENTS.md) first. Jump by task below.
4
+
5
+ | # | Doc | Contents |
6
+ |---|---|---|
7
+ | 00 | This file | Navigation |
8
+ | 03 | [CUSTOM-COMPONENTS](./03-CUSTOM-COMPONENTS.md) | react-live, scope API, slots |
9
+ | 04 | [WORKFLOW](./04-WORKFLOW.md) | Build, preview, publish from this package |
10
+ | 05 | [ANTI-PATTERNS](./05-ANTI-PATTERNS.md) | What not to do (high signal) |
11
+ | 07 | [SHARED-COMPONENTS](./07-SHARED-COMPONENTS.md) | `shared/` + `$ref` |
12
+ | 08 | [ORDER-FORM](./08-ORDER-FORM.md) | COD / checkout contract |
13
+ | 09 | [THEME-PORTING](./09-THEME-PORTING.md) | Craft / cart / search / PLP lessons |
14
+ | 10 | [SCHEMA-LIBRARY](./10-SCHEMA-LIBRARY.md) | Drag-drop theme library |
15
+ | 11 | [PAGES](./11-PAGES-CHECKOUT-THANKS-PRODUCT.md) | checkout / thanks / product |
16
+ | 12 | [DARK-LIGHT](./12-DARK-LIGHT-THEME.md) | Dark / light / system |
17
+ | 13 | [I18N](./13-TEMPLATE-I18N.md) | `locales/*.json` + `t()` |
18
+ | 14 | [FILTERATOR](./14-FILTERATOR.md) | Product / category lists |
19
+ | 16 | [TS-IMPORTS](./16-AUTHORING-TS-IMPORTS.md) | TypeScript + npm imports |
20
+
21
+ ## Task cheat-sheet
22
+
23
+ | Task | Read |
24
+ |---|---|
25
+ | Edit custom JSX/TSX | 03, 05, 16 |
26
+ | Shared header/footer | **07** |
27
+ | Order / COD form | **08** |
28
+ | Checkout / thanks / PDP | **11** |
29
+ | Dark / light | **12** |
30
+ | Translations | **13** |
31
+ | Product grids / filters | **14** |
32
+ | Port / polish a full theme | **09** |
33
+ | Build / preview / publish | **04** |
@@ -0,0 +1,116 @@
1
+ # Custom Components (react-live)
2
+
3
+ > Theme package copy — paths assume this theme folder is the project root.
4
+
5
+ Full API: `docs/03-CUSTOM-COMPONENTS.md`.
6
+ Architecture: `docs/03-CUSTOM-COMPONENTS.md`.
7
+
8
+ ## What a custom component is
9
+
10
+ A `TemplateDataComponent` with:
11
+
12
+ ```json
13
+ {
14
+ "type": "custom",
15
+ "instanceId": "…",
16
+ "title": "…",
17
+ "code": "function App() { … }",
18
+ "propsSchema": { … },
19
+ "props": { … },
20
+ "slotsSchema": { … },
21
+ "slots": { … },
22
+ "slotsLayout": { … }
23
+ }
24
+ ```
25
+
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).
27
+
28
+ ## Required code shape
29
+
30
+ ```jsx
31
+ function App() {
32
+ const storeCtx = useStore();
33
+ // …
34
+ return <div>…</div>;
35
+ }
36
+ ```
37
+
38
+ - Entry must be **`function App()`** (warning if missing; may not render).
39
+ - Prefer **`React.useState` / `React.useEffect` / …** — merchant preview may not inject bare hooks.
40
+ - No `import` / `export` / `require`.
41
+
42
+ ## Injected scope (no imports needed)
43
+
44
+ | Symbol | Use |
45
+ |---|---|
46
+ | `React` | Hooks, Fragment |
47
+ | `props` | Instance props |
48
+ | `props.slots` | Pre-rendered slot children (`props.slots?.sections`) |
49
+ | `SlotContextBridge` | Provide context to slot children |
50
+ | `useSlotContext(key)` | Read parent slot context |
51
+ | `useStore()` | `{ store }` or null — **null-check** |
52
+ | `useFeeefCart()` | `{ cart, count, store }` or null |
53
+ | `useCurrentProduct()` | `{ product }` — product pages |
54
+ | `useFeeef` | SDK instance or null |
55
+ | `useTheme()` | next-themes |
56
+ | `useTemplate()` | read-only template state |
57
+ | `t(key, params?)` | Theme locales (`data.i18n`) — see [13-TEMPLATE-I18N.md](./13-TEMPLATE-I18N.md) |
58
+ | `useFeeefT()` / `useFeeefLocale()` | Theme i18n hooks |
59
+ | `useRouter` / `usePathname` / `useSearchParams` | next/navigation |
60
+ | `Link` | next/link — prefer over `<a>` |
61
+ | `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 |
63
+ | `dartColorToCssColor` | convert Flutter color ints from **props** |
64
+
65
+ For product markdown details use registry **`product_body`** (reads `product.body`), not CustomLive HTML injection.
66
+
67
+ ## Styling rules
68
+
69
+ - Brand colors: `hsl(var(--primary))`, `hsl(var(--primary-foreground))`, `hsl(var(--background))`, …
70
+ - Corners: `var(--corners-card)`, `var(--corners-buttons-large)`, …
71
+ - **Do not** assign `store.decoration.primary` directly (Flutter AARRGGBB int).
72
+ - 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();`
75
+
76
+ ## Slots in JSX
77
+
78
+ Parent:
79
+
80
+ ```jsx
81
+ <SlotContextBridge value={{ shell: { isOpen, setIsOpen } }}>
82
+ {props.slots?.sections}
83
+ </SlotContextBridge>
84
+ {props.slots?.footer}
85
+ ```
86
+
87
+ Child (in slot):
88
+
89
+ ```jsx
90
+ const shell = useSlotContext("shell");
91
+ ```
92
+
93
+ **Never** use slot context for navigation (`routerNav` stubs). Use `Link` / `RouterNav` / `useRouter()`.
94
+
95
+ ## Product media
96
+
97
+ - `product.photoUrl` — cover image string.
98
+ - `product.media` — **`string[]` of URLs**, not `{ url }[]`.
99
+
100
+ ## Cart
101
+
102
+ ```jsx
103
+ const cartCtx = useFeeefCart();
104
+ if (!cartCtx) return null;
105
+ cartCtx.cart.add({ product, quantity: 1, variantPath: "Color/Red" });
106
+ ```
107
+
108
+ ## Kit authoring
109
+
110
+ In `…/my-comp/`:
111
+
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
115
+
116
+ See [04-WORKFLOW.md](./04-WORKFLOW.md).
@@ -0,0 +1,129 @@
1
+ # Theme workflow (this package)
2
+
3
+ This folder is a **Node.js theme package**. Scripts wrap the Feeef CLI (`feeef`).
4
+
5
+ ## Setup (once)
6
+
7
+ ```bash
8
+ # Install Feeef CLI globally (or npm link from the Feeef cli package)
9
+ feeef signin
10
+ feeef use # pick one of your stores
11
+ ```
12
+
13
+ ## Everyday loop
14
+
15
+ 1. Add pages/components with the CLI (or edit under `pages/`, `shared/`, `library/`, `locales/`).
16
+ 2. `npm run build` → writes `dist/data.json` (+ locales).
17
+ 3. `npm run dev` → pushes a **draft** preview to your store and opens `https://{slug}.…/?preview=…` (live theme unchanged).
18
+ 4. Ship: `npm run publish -- --apply` (or `feeef template publish --apply`).
19
+
20
+ | Script / command | Effect |
21
+ |---|---|
22
+ | `feeef template add page <id>` | Create `pages/<id>/` + update `feeef.template.json` |
23
+ | `feeef template add component <page> <name>` | Starter `<name>.tsx` (meta + App) |
24
+ | `feeef template remove page <id>` | Delete page folder + manifest entry |
25
+ | `feeef template remove component <page> <name>` | Delete component file/folder |
26
+ | `npm run build` | Compile source → `dist/` |
27
+ | `npm run check` | Validate without relying on a dirty dist |
28
+ | `npm run dev` | Watch/build + remote draft preview (never overwrites live) |
29
+ | `npm run publish` | Upload template + locales (+ optional install) |
30
+
31
+ Exit draft preview in the browser via the banner (**Exit preview**) or `/?preview=0`.
32
+
33
+ ### Scaffold examples
34
+
35
+ ```bash
36
+ feeef template add page products
37
+ feeef template add component products grid --title "Product grid"
38
+ feeef template remove component products grid --yes
39
+ feeef template remove page products --yes
40
+ ```
41
+
42
+ Legacy themes that already use `sections/`: `add component` writes under `sections/main/components/` (or pass `--section header`).
43
+
44
+ ## Source layout
45
+
46
+ ```
47
+ feeef.template.json
48
+ schema.ts # theme-owned schema overlay (typed)
49
+ props.json # default root props (data)
50
+ pages/<page>/page.json
51
+ pages/<page>/components/ # preferred (→ published sections.main)
52
+ <name>.tsx # leaf: export const meta + App
53
+ <name>.json # leaf built-in / no code
54
+ <name>/ # only when slots/ or children/ needed
55
+ component.tsx
56
+ slots/… | children/…
57
+ pages/<page>/sections/<section>/components/ # legacy multi-section (still supported)
58
+ shared/components/<id>.tsx
59
+ library/components/<id>.tsx
60
+ locales/en.json
61
+ ```
62
+
63
+ Do **not** mix `pages/<page>/components/` and `pages/<page>/sections/` on the same page.
64
+
65
+ ### Theme schema (`schema.ts`)
66
+
67
+ Controls what the merchant editor sees for **this** theme (pages, layouts, root `propsSchema`). Build merges it with Lithium built-ins → `dist/schema.json` (publish uploads that as `StoreTemplate.schema`).
68
+
69
+ ```ts
70
+ export const schema = {
71
+ name: "my-theme",
72
+ version: "0.1.0",
73
+ schema: "1.0",
74
+ propsSchema: { theme: { type: "object", /* … */ } },
75
+ pages: {
76
+ home: {
77
+ name: "Home",
78
+ path: "/",
79
+ sections: { main: {} },
80
+ layout: { sm: [{ type: "column", children: ["main"] }] },
81
+ },
82
+ },
83
+ } as const satisfies FeeefThemeSchema;
84
+ ```
85
+
86
+ Types: `types/feeef-template-schema.d.ts`. Fallback: `schema.json` (same shape).
87
+
88
+ ## Custom components
89
+ locales/en.json
90
+ feeef.template.json
91
+ ```
92
+
93
+ Do **not** mix `pages/<page>/components/` and `pages/<page>/sections/` on the same page.
94
+
95
+ ## Custom components
96
+
97
+ - Prefer page-level `components/hero.tsx` — `export const meta` + `function App() { … }`
98
+ - Use a folder only when you need `slots/` or `children/` (or colocated helpers)
99
+ - Chrome / layout: use **slots** + `slotsLayout` on a shell component (not extra section keys)
100
+ - Type-safe props from schema:
101
+
102
+ ```tsx
103
+ const propsSchema = { heading: { type: "string" } } as const;
104
+
105
+ export const meta = {
106
+ type: "custom",
107
+ title: "Hero",
108
+ order: 0,
109
+ propsSchema,
110
+ props: { heading: "" },
111
+ } as const satisfies FeeefComponentMeta<typeof propsSchema>;
112
+
113
+ type Props = FeeefLivePropsOf<typeof propsSchema>;
114
+
115
+ function App() {
116
+ const p = props as Props; // p.heading: string
117
+ return <h1>{p.heading}</h1>;
118
+ }
119
+ ```
120
+
121
+ - Build strips `meta` and bundles into react-live `code` (see [16-AUTHORING-TS-IMPORTS.md](./16-AUTHORING-TS-IMPORTS.md))
122
+ - `react` stays provided by the storefront — do not bundle a second React
123
+
124
+ ## Do not
125
+
126
+ - Commit hand-tweaked `dist/data.json` as the only source of truth
127
+ - Put `code` / schemas under `props`
128
+ - Call `ff.orders.send` from custom checkout (use `POST /api/orders/create` — [08](./08-ORDER-FORM.md))
129
+ - Set production env overrides meant for local preview only