@ikas/code-components-mcp 0.103.0 → 0.104.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.
@@ -35,7 +35,7 @@
35
35
  "prop-types": {
36
36
  "title": "Available Prop Types",
37
37
  "description": "All prop types that can be used in ikas.config.json",
38
- "content": "Props define what the store editor can configure for each component. Each prop has a `type` that determines the editor UI and the TypeScript type received in your component.\n\n| Type | Editor UI | TypeScript Type | Description |\n|------|-----------|----------------|-------------|\n| `TEXT` | Text input | `string` | Single-line text |\n| `RICH_TEXT` | Rich text editor | `string` | HTML rich text content |\n| `NUMBER` | Number input | `number` | Numeric value |\n| `BOOLEAN` | Toggle switch | `boolean` | True/false toggle |\n| `IMAGE` | Image picker | `IkasImage | null` | Image from editor. Use `getDefaultSrc(image)` for URL |\n| `IMAGE_LIST` | Image list picker | `IkasImageList` | Multiple images from editor |\n| `LINK` | Link editor | `IkasNavigationLink` | Navigation link with href, label, subLinks |\n| `LIST_OF_LINK` | Link list editor | `IkasNavigationLinkList` | List of navigation links |\n| `COLOR` | Color picker | `string` | CSS color value (hex, rgb, etc.) |\n| `PRODUCT` | Product picker | `IkasProduct` | Single product reference |\n| `PRODUCT_LIST` | Product list picker | `IkasProduct[]` | Multiple product references |\n| `CATEGORY` | Category picker | `IkasCategory` | Single category reference |\n| `CATEGORY_LIST` | Category list picker | `IkasCategory[]` | Multiple category references |\n| `BRAND` | Brand picker | `IkasBrand` | Single brand reference |\n| `BRAND_LIST` | Brand list picker | `IkasBrand[]` | Multiple brand references |\n| `BLOG` | Blog post picker | `IkasBlog` | Single blog post reference |\n| `BLOG_LIST` | Blog post list picker | `IkasBlog[]` | Multiple blog post references |\n| `BLOG_CATEGORY` | Blog category picker | `IkasBlogCategory` | Single blog category reference |\n| `BLOG_CATEGORY_LIST` | Blog category list picker | `IkasBlogCategoryList` | Multiple blog category references |\n| `FONT_STYLE_TYPE` | Font style editor | `IkasFontStyle` | Font family, size, weight, etc. |\n| `TYPE` | Type selector | Depends on typeId | Structured type (padding, margin, size, etc.). Available for both components and sections (sections have a restricted whitelist). |\n| `ENUM` | Dropdown selector | `string` | Enum-based style type (flex-direction, justify-content, align-items, etc.). Uses `enumTypeId`. Available for both components and sections. |\n| `COMPONENT` | Component slot | `any` | A single child component slot. Store owners can place a component in this slot from the editor. Render with `<IkasComponentRenderer>`. |\n| `COMPONENT_LIST` | Component list slot | `any` | A list of child components. Store owners can add multiple components from the editor. Render with `<IkasComponentRenderer>`. |\n\n### COMPONENT & COMPONENT_LIST props (child component slots)\n\nThese prop types enable **slot-based** architectures where store owners can drag child components into your section/component from the editor.\n\n- `COMPONENT` — a single child component slot\n- `COMPONENT_LIST` — a list of child components\n\n**Rendering:** Use the `<IkasComponentRenderer>` wrapper from `@ikas/bp-storefront`:\n```tsx\nimport { IkasComponentRenderer } from \"@ikas/bp-storefront\";\nimport { Props } from \"./types\";\n\nexport function MySection({ title, cardList, ...props }: Props) {\n return (\n <section>\n <h2>{title}</h2>\n <div className=\"cards\">\n {/* COMPONENT_LIST — render a list of child components */}\n <IkasComponentRenderer\n components={cardList as any[]}\n parentProps={props}\n />\n </div>\n </section>\n );\n}\nexport default MySection;\n```\n\n**Key rules:**\n- Always pass `parentProps={props}` so child components can access parent data via dynamic values\n- Cast the prop value: `components={myList as any[]}` for COMPONENT_LIST, `components={[myComp] as any[]}` for COMPONENT\n- `<IkasComponentRenderer>` handles rendering, styling, and reactivity of child components automatically\n\n**Config example (COMPONENT_LIST):**\n```json\n{\n \"name\": \"cardList\",\n \"displayName\": \"Card List\",\n \"type\": \"COMPONENT_LIST\"\n}\n```\n\n**Config example (COMPONENT):**\n```json\n{\n \"name\": \"headerSlot\",\n \"displayName\": \"Header Slot\",\n \"type\": \"COMPONENT\"\n}\n```\n\n### IMAGE type example:\n```json\n{\n \"name\": \"heroImage\",\n \"displayName\": \"Hero Image\",\n \"type\": \"IMAGE\",\n \"required\": false\n}\n```\nAccess in component: `getDefaultSrc(props.heroImage)` (import `getDefaultSrc` from `@ikas/bp-storefront`)\n\n### Prop grouping\nProps can be assigned to groups via `groupId` for organized editor sidebar display. See `get_framework_guide(\"prop-groups\")` for details.\n\n### Style Props: TYPE and ENUM\n\nThere are two prop types for style values:\n\n- **TYPE** — Structured types with numeric values and units (padding, margin, border-radius, sizes, etc.). Uses `typeId`.\n- **ENUM** — Enum types rendered as dropdown selectors (flex-direction, justify-content, align-items, etc.). Uses `enumTypeId`.\n\nBoth are available for components and sections. For sections, TYPE props are limited to a whitelist of style types. Use `list-types --component-type section` to see section-allowed types.\n\n### TYPE prop (structured types)\nThe `TYPE` prop lets you use structured storefront types like PaddingStyleType, MarginStyleType, SizeStyleType, etc. Available for both components and sections (sections have a restricted whitelist of style types).\n\n**Workflow:**\n1. Run `npx ikas-component config list-types` to get available types (requires dev server running with editor connected)\n2. Use the `typeId` from the output when adding the prop\n3. For sections: `npx ikas-component config list-types --component-type section` to see only section-allowed types\n\n**Example config:**\n```json\n{\n \"name\": \"spacing\",\n \"displayName\": \"Spacing\",\n \"type\": \"TYPE\",\n \"typeId\": \"@ikas/bp-storefront-models-PaddingStyleType\"\n}\n```\n\n**Array example** (append `_array` to typeId):\n```json\n{\n \"name\": \"margins\",\n \"displayName\": \"Margins\",\n \"type\": \"TYPE\",\n \"typeId\": \"@ikas/bp-storefront-models-MarginStyleType_array\"\n}\n```\nThis generates `margins?: MarginStyleType[]` in types.ts.\n\n**CLI command:**\n```bash\nnpx ikas-component config add-prop --component MyComp --name spacing --displayName Spacing --type TYPE --typeId \"@ikas/bp-storefront-models-PaddingStyleType\"\n```\n\n### ENUM prop (enum style types)\nThe `ENUM` prop lets you use enum-based types that render as dropdown selectors. All enum types from the editor are available (e.g. FlexDirectionStyleType, JustifyContentStyleType, AlignItemsStyleType, DirectionStyleType, TextAlignStyleType, ObjectFitStyleType, and custom enums).\n\n**Workflow:**\n1. Run `npx ikas-component config list-types` — enum types have `category: \"enum\"` in the output\n2. Use the `enumTypeId` from the output when adding the prop\n\n**Example config:**\n```json\n{\n \"name\": \"direction\",\n \"displayName\": \"Direction\",\n \"type\": \"ENUM\",\n \"enumTypeId\": \"@ikas/bp-storefront-models-FlexDirectionStyleType\"\n}\n```\nThis generates `direction?: string` in types.ts.\n\n**CLI command:**\n```bash\nnpx ikas-component config add-prop --component MyComp --name direction --displayName Direction --type ENUM --enumTypeId \"@ikas/bp-storefront-models-FlexDirectionStyleType\"\n```\n\n**Note:** The `list-types` command connects to the dev server WebSocket, which must have an editor connected for types to be available.",
38
+ "content": "Props define what the store editor can configure for each component. Each prop has a `type` that determines the editor UI and the TypeScript type received in your component.\n\n| Type | Editor UI | TypeScript Type | Description |\n|------|-----------|----------------|-------------|\n| `TEXT` | Text input | `string` | Single-line text |\n| `RICH_TEXT` | Rich text editor | `string` | HTML rich text content |\n| `NUMBER` | Number input | `number` | Numeric value |\n| `BOOLEAN` | Toggle switch | `boolean` | True/false toggle |\n| `IMAGE` | Image picker | `IkasImage | null` | Image from editor. Use `getDefaultSrc(image)` for URL |\n| `IMAGE_LIST` | Image list picker | `IkasImageList` | Multiple images from editor |\n| `LINK` | Link editor | `IkasNavigationLink` | Navigation link with href, label, subLinks |\n| `LIST_OF_LINK` | Link list editor | `IkasNavigationLinkList` | List of navigation links |\n| `COLOR` | Color picker | `string` | CSS color value (hex, rgb, etc.) |\n| `PRODUCT` | Product picker | `IkasProduct` | Single product reference |\n| `PRODUCT_LIST` | Product list picker | `IkasProductList` | Product list with `.data` (products array), `.filters`, `.sort`, `.page`, etc. |\n| `CATEGORY` | Category picker | `IkasCategory` | Single category reference |\n| `CATEGORY_LIST` | Category list picker | `IkasCategory[]` | Multiple category references |\n| `BRAND` | Brand picker | `IkasBrand` | Single brand reference |\n| `BRAND_LIST` | Brand list picker | `IkasBrand[]` | Multiple brand references |\n| `BLOG` | Blog post picker | `IkasBlog` | Single blog post reference |\n| `BLOG_LIST` | Blog post list picker | `IkasBlog[]` | Multiple blog post references |\n| `BLOG_CATEGORY` | Blog category picker | `IkasBlogCategory` | Single blog category reference |\n| `BLOG_CATEGORY_LIST` | Blog category list picker | `IkasBlogCategoryList` | Multiple blog category references |\n| `FONT_STYLE_TYPE` | Font style editor | `IkasFontStyle` | Font family, size, weight, etc. |\n| `TYPE` | Type selector | Depends on typeId | Structured type (padding, margin, size, etc.). Available for both components and sections (sections have a restricted whitelist). |\n| `ENUM` | Dropdown selector | `string` | Enum-based style type (flex-direction, justify-content, align-items, etc.). Uses `enumTypeId`. Available for both components and sections. |\n| `COMPONENT` | Component slot | `any` | A single child component slot. Store owners can place a component in this slot from the editor. Render with `<IkasComponentRenderer>`. |\n| `COMPONENT_LIST` | Component list slot | `any` | A list of child components. Store owners can add multiple components from the editor. Render with `<IkasComponentRenderer>`. |\n\n### COMPONENT & COMPONENT_LIST props (child component slots)\n\nThese prop types enable **slot-based** architectures where store owners can drag child components into your section/component from the editor.\n\n- `COMPONENT` — a single child component slot\n- `COMPONENT_LIST` — a list of child components\n\n**Rendering:** Use the `<IkasComponentRenderer>` wrapper from `@ikas/bp-storefront`:\n```tsx\nimport { IkasComponentRenderer } from \"@ikas/bp-storefront\";\nimport { Props } from \"./types\";\n\nexport function MySection({ title, cardList, ...props }: Props) {\n return (\n <section>\n <h2>{title}</h2>\n <div className=\"cards\">\n {/* COMPONENT_LIST — render a list of child components */}\n <IkasComponentRenderer\n id=\"card-list\"\n components={cardList as any[]}\n parentProps={props}\n />\n </div>\n </section>\n );\n}\nexport default MySection;\n```\n\n**Key rules:**\n- Always pass `parentProps={props}` so child components can access parent data via dynamic values\n- Cast the prop value: `components={myList as any[]}` for COMPONENT_LIST, `components={[myComp] as any[]}` for COMPONENT\n- `<IkasComponentRenderer>` handles rendering, styling, and reactivity of child components automatically\n\n**Config example (COMPONENT_LIST):**\n```json\n{\n \"name\": \"cardList\",\n \"displayName\": \"Card List\",\n \"type\": \"COMPONENT_LIST\"\n}\n```\n\n**Config example (COMPONENT):**\n```json\n{\n \"name\": \"headerSlot\",\n \"displayName\": \"Header Slot\",\n \"type\": \"COMPONENT\"\n}\n```\n\n### IMAGE type example:\n```json\n{\n \"name\": \"heroImage\",\n \"displayName\": \"Hero Image\",\n \"type\": \"IMAGE\",\n \"required\": false\n}\n```\nAccess in component: `getDefaultSrc(props.heroImage)` (import `getDefaultSrc` from `@ikas/bp-storefront`)\n\n### Prop grouping\nProps can be assigned to groups via `groupId` for organized editor sidebar display. See `get_framework_guide(\"prop-groups\")` for details.\n\n### Style Props: TYPE and ENUM\n\nThere are two prop types for style values:\n\n- **TYPE** — Structured types with numeric values and units (padding, margin, border-radius, sizes, etc.). Uses `typeId`.\n- **ENUM** — Enum types rendered as dropdown selectors (flex-direction, justify-content, align-items, etc.). Uses `enumTypeId`.\n\nBoth are available for components and sections. For sections, TYPE props are limited to a whitelist of style types. Use `list-types --component-type section` to see section-allowed types.\n\n### TYPE prop (structured types)\nThe `TYPE` prop lets you use structured storefront types like PaddingStyleType, MarginStyleType, SizeStyleType, etc. Available for both components and sections (sections have a restricted whitelist of style types).\n\n**Workflow:**\n1. Run `npx ikas-component config list-types` to get available types (requires dev server running with editor connected)\n2. Use the `typeId` from the output when adding the prop\n3. For sections: `npx ikas-component config list-types --component-type section` to see only section-allowed types\n\n**Example config:**\n```json\n{\n \"name\": \"spacing\",\n \"displayName\": \"Spacing\",\n \"type\": \"TYPE\",\n \"typeId\": \"@ikas/bp-storefront-models-PaddingStyleType\"\n}\n```\n\n**Array example** (append `_array` to typeId):\n```json\n{\n \"name\": \"margins\",\n \"displayName\": \"Margins\",\n \"type\": \"TYPE\",\n \"typeId\": \"@ikas/bp-storefront-models-MarginStyleType_array\"\n}\n```\nThis generates `margins?: MarginStyleType[]` in types.ts.\n\n**CLI command:**\n```bash\nnpx ikas-component config add-prop --component MyComp --name spacing --displayName Spacing --type TYPE --typeId \"@ikas/bp-storefront-models-PaddingStyleType\"\n```\n\n### ENUM prop (enum style types)\nThe `ENUM` prop lets you use enum-based types that render as dropdown selectors. There are two kinds of enum types:\n\n1. **Built-in enums** (prefix `@ikas/`): FlexDirectionStyleType, JustifyContentStyleType, AlignItemsStyleType, etc. Available from `list-types` when editor is connected.\n2. **Custom enums**: Created with `config add-enum`. Works offline, no editor needed.\n\n**IMPORTANT:** `add-prop --type ENUM` validates that the `enumTypeId` references an existing enum. You MUST create custom enums first with `config add-enum` before using them. The command will reject unknown enum IDs.\n\n**Custom enum workflow (recommended for AI-driven generation):**\n```bash\n# Step 1: Create the enum FIRST\nnpx ikas-component config add-enum --name \"AspectRatio\" --options '{\"Square\":\"1/1\",\"Landscape\":\"16/9\",\"Portrait\":\"3/4\"}'\n# Returns: {\"success\":true,\"enumId\":\"aBcDeFgHiJ\",...}\n\n# Step 2: Use the returned enumId in add-prop\nnpx ikas-component config add-prop --component MyComp --name aspectRatio --displayName \"Aspect Ratio\" --type ENUM --enumTypeId aBcDeFgHiJ\n```\n\n**Built-in enum workflow:**\n1. Run `npx ikas-component config list-types` — enum types have `category: \"enum\"` in the output\n2. Use the `enumTypeId` from the output when adding the prop\n\n**Example config (built-in enum):**\n```json\n{\n \"name\": \"direction\",\n \"displayName\": \"Direction\",\n \"type\": \"ENUM\",\n \"enumTypeId\": \"@ikas/bp-storefront-models-FlexDirectionStyleType\"\n}\n```\nThis generates `direction?: string` in types.ts.\n\n**CLI command (built-in enum):**\n```bash\nnpx ikas-component config add-prop --component MyComp --name direction --displayName Direction --type ENUM --enumTypeId \"@ikas/bp-storefront-models-FlexDirectionStyleType\"\n```\n\n**Note:** `list-types` requires dev server with editor connected. Custom enums (`config add-enum`) work offline.",
39
39
  "tags": [
40
40
  "props",
41
41
  "types",
@@ -244,25 +244,27 @@
244
244
  ]
245
245
  },
246
246
  "product-detail-patterns": {
247
- "title": "Product Detail Patterns",
248
- "description": "Variant selection, pricing, stock checks, add-to-cart, favorites, and image gallery patterns for product detail pages",
249
- "content": "## Product Detail Patterns\n\nA product detail section is one of the most complex sections in an e-commerce theme. It combines variant selection, pricing, stock checks, cart operations, favorites, and image display.\n\n### Core Flow\n\n1. Get the selected variant: `getSelectedProductVariant(product)`\n2. Display variant options: `getDisplayedProductVariantTypes(product)`\n3. Handle variant selection: `selectVariantValue(product, variantValue)` (mutates in place)\n4. Check stock: `hasProductVariantStock(variant)` or `hasProductStock(product)`\n5. Show pricing: `getProductVariantFormattedFinalPrice(variant)`, `getProductVariantFormattedSellPrice(variant)`\n6. Add to cart: `addItemToCart(variant, product, quantity)`\n7. Toggle favorite: `addIkasProductToFavorites(product)` / `removeIkasProductFromFavorites(product)`\n\n### Variant Selection Pattern\n\n```tsx\nimport {\n IkasProduct,\n getSelectedProductVariant,\n getDisplayedProductVariantTypes,\n selectVariantValue,\n hasProductVariantStock,\n getProductVariantFormattedFinalPrice,\n getProductVariantFormattedSellPrice,\n hasProductVariantDiscount,\n getProductVariantDiscountPercentage,\n} from \"@ikas/bp-storefront\";\n\n// In your component:\nconst variant = getSelectedProductVariant(product);\nconst variantTypes = getDisplayedProductVariantTypes(product);\n\n// Render variant options\n{variantTypes.map((dvt) => (\n <div key={dvt.variantType?.name}>\n <span>{dvt.variantType?.name}</span>\n {dvt.variantValues.map((dvv) => (\n <button\n key={dvv.variantValue?.name}\n className={dvv.isSelected ? \"selected\" : \"\"}\n disabled={!dvv.isSelectable}\n onClick={() => selectVariantValue(product, dvv.variantValue)}\n >\n {dvv.variantValue?.name}\n </button>\n ))}\n </div>\n))}\n```\n\n### Pricing Display\n\n```tsx\nconst hasDiscount = hasProductVariantDiscount(variant) as unknown as boolean;\nconst finalPrice = getProductVariantFormattedFinalPrice(variant) as unknown as string;\nconst originalPrice = getProductVariantFormattedSellPrice(variant) as unknown as string;\nconst discountPct = hasDiscount\n ? (getProductVariantDiscountPercentage(variant) as unknown as number)\n : 0;\n\n<div className=\"pricing\">\n <span className=\"final-price\">{finalPrice}</span>\n {hasDiscount && (\n <>\n <span className=\"original-price\">{originalPrice}</span>\n <span className=\"discount-badge\">-{Math.round(discountPct)}%</span>\n </>\n )}\n</div>\n```\n\n### Image Gallery Pattern\n\n```tsx\nimport { getDefaultSrc, createMediaSrcset, IkasImage } from \"@ikas/bp-storefront\";\n\nconst images: IkasImage[] = (variant?.images ?? [])\n .map((pi) => pi.image)\n .filter((img): img is IkasImage => img != null);\n\nconst [selectedIndex, setSelectedIndex] = useState(0);\nconst mainImage = images[selectedIndex];\n\n<div className=\"gallery\">\n {mainImage && (\n <img\n src={getDefaultSrc(mainImage)}\n srcSet={createMediaSrcset(mainImage)}\n sizes=\"(max-width: 768px) 100vw, 50vw\"\n alt={product.name}\n />\n )}\n <div className=\"thumbnails\">\n {images.map((img, i) => (\n <img\n key={i}\n src={getDefaultSrc(img)}\n className={i === selectedIndex ? \"active\" : \"\"}\n onClick={() => setSelectedIndex(i)}\n />\n ))}\n </div>\n</div>\n```\n\n### Add to Cart with Stock Check\n\n```tsx\nimport { addItemToCart, isAddToCartEnabled, hasProductVariantStock } from \"@ikas/bp-storefront\";\n\nconst inStock = hasProductVariantStock(variant) as unknown as boolean;\nconst canAdd = isAddToCartEnabled(product) as unknown as boolean;\n\nconst handleAddToCart = async () => {\n if (!variant || !canAdd) return;\n setIsLoading(true);\n try {\n await addItemToCart(variant, product, quantity);\n } finally {\n setIsLoading(false);\n }\n};\n\n<button disabled={!inStock || !canAdd || isLoading} onClick={handleAddToCart}>\n {!inStock ? \"Out of Stock\" : isLoading ? \"Adding...\" : \"Add to Cart\"}\n</button>\n```\n\n### Favorites Toggle\n\n```tsx\nimport {\n isFavoriteIkasProduct,\n addIkasProductToFavorites,\n removeIkasProductFromFavorites,\n} from \"@ikas/bp-storefront\";\n\nconst isFav = isFavoriteIkasProduct(product) as unknown as boolean;\n\nconst toggleFavorite = async () => {\n if (isFav) {\n await removeIkasProductFromFavorites(product);\n } else {\n await addIkasProductToFavorites(product);\n }\n};\n```\n\n### Key Functions Reference\n\n| Function | Purpose | Returns |\n|----------|---------|---------|\n| `getSelectedProductVariant(product)` | Get currently selected variant | `IkasProductVariant` |\n| `getDisplayedProductVariantTypes(product)` | Get variant type/value options | Array of variant types with values |\n| `selectVariantValue(product, value)` | Select a variant option | `void` (mutates) |\n| `hasProductVariantStock(variant)` | Check if variant is in stock | `boolean` (cast needed) |\n| `hasProductStock(product)` | Check if any variant in stock | `boolean` (cast needed) |\n| `isAddToCartEnabled(product)` | Check if add-to-cart is allowed | `boolean` (cast needed) |\n| `addItemToCart(variant, product, qty)` | Add to cart | Result object |\n| `getProductVariantFormattedFinalPrice(variant)` | Formatted final price | `string` (cast needed) |\n| `getProductVariantFormattedSellPrice(variant)` | Formatted original price | `string` (cast needed) |\n| `hasProductVariantDiscount(variant)` | Check for discount | `boolean` (cast needed) |\n| `getProductVariantDiscountPercentage(variant)` | Discount percentage | `number` (cast needed) |\n| `createMediaSrcset(image)` | Generate responsive srcset for all sizes (180–3840px) | `string` |",
247
+ "title": "Product Detail Patterns (Serel Reference)",
248
+ "description": "Serel ProductDetail with 12 child components in two COMPONENT_LIST slots, ProductGallery local component, Breadcrumb navigation, and component slot architecture",
249
+ "content": "## Product Detail Patterns (Serel Reference)\n\nThe serel ProductDetail section is the most complex section in the theme, with **12 child components** distributed across **two COMPONENT_LIST slots** (`components` and `bottomComponents`), plus a local `ProductGallery` component and Breadcrumb navigation.\n\n### Two-Slot Architecture\n\nThe section declares two separate COMPONENT_LIST props:\n\n```json\n{\n \"props\": [\n {\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\n \"nb34u3yu-product-detail-name-favorite\",\n \"nb34u3yu-product-detail-sku\",\n \"nb34u3yu-product-detail-prices\",\n \"nb34u3yu-product-detail-product-group\",\n \"nb34u3yu-product-detail-variant\",\n \"nb34u3yu-product-detail-add-to-cart\",\n \"nb34u3yu-product-detail-features\",\n \"nb34u3yu-product-detail-description\",\n \"nb34u3yu-product-detail-bundle-product\",\n \"nb34u3yu-product-detail-option-set\",\n \"nb34u3yu-product-detail-offer\",\n \"nb34u3yu-product-detail-bundle-furniture\"\n ]\n },\n {\n \"name\": \"bottomComponents\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\"nb34u3yu-product-detail-description\"]\n }\n ]\n}\n```\n\n### Section Layout\n\n```tsx\nimport { IkasComponentRenderer } from \"@ikas/bp-storefront\";\nimport Breadcrumb from \"../../sub-components/Breadcrumb\";\nimport ProductGallery from \"./ProductGallery\"; // local component\nimport { Props } from \"./types\";\n\nexport function ProductDetail({ product, components, bottomComponents, backgroundColor, ...props }: Props) {\n if (!product) return null;\n return (\n <section className=\"product-detail\" style={backgroundColor ? { backgroundColor } : undefined}>\n <Breadcrumb product={product} />\n <div className=\"product-detail-inner\">\n <div className=\"product-detail-gallery\">\n <ProductGallery product={product} />\n </div>\n <div className=\"product-detail-info\">\n <IkasComponentRenderer id=\"product-detail-components\" components={components} parentProps={props} />\n </div>\n </div>\n <div className=\"product-detail-bottom\">\n <IkasComponentRenderer id=\"product-detail-bottom-components\" components={bottomComponents} parentProps={props} />\n </div>\n </section>\n );\n}\nexport default ProductDetail;\n```\n\n### 12 Child Components\n\n| Child Component | Purpose |\n|-----------------|--------|\n| ProductDetailNameFavorite | Product name + favorites toggle |\n| ProductDetailSku | SKU display |\n| ProductDetailPrices | Price display with discounts |\n| ProductDetailProductGroup | Product group/collection links |\n| ProductDetailVariant | Variant selector (size, color) |\n| ProductDetailAddToCart | Quantity selector + add-to-cart button |\n| ProductDetailFeatures | Feature list (uses FeatureItem children) |\n| ProductDetailDescription | Collapsible description (uses CollapsibleContent children) |\n| ProductDetailBundleProduct | Bundle product display |\n| ProductDetailBundleFurniture | Bundle furniture configuration |\n| ProductDetailOptionSet | Custom option sets |\n| ProductDetailOffer | Special offer display |\n\n### ProductGallery (Local Component)\n\nProductGallery is defined locally within the ProductDetail folder (not a registered component or sub-component). It handles image display with thumbnail navigation, zoom, and responsive srcset:\n\n```tsx\nconst images = (variant?.images ?? [])\n .map((pi) => pi.image)\n .filter((img): img is IkasImage => img != null);\n```\n\n### Breadcrumb Navigation\n\nThe Breadcrumb sub-component (from `src/sub-components/Breadcrumb/`) renders category path navigation:\n\n```tsx\nimport { getProductCategoryPath, getIkasCategoryHref } from \"@ikas/bp-storefront\";\nconst categoryPath = getProductCategoryPath(product);\n```\n\n### Key Pattern: Multiple COMPONENT_LIST Slots\n\nUsing two slots (`components` and `bottomComponents`) allows the store owner to arrange child components differently:\n- `components` displayed next to the gallery in a side panel\n- `bottomComponents` displayed full-width below the gallery\n\nThis pattern can be applied to any section that needs multiple layout regions.",
250
250
  "tags": [
251
251
  "product",
252
252
  "detail",
253
253
  "variant",
254
254
  "pricing",
255
- "stock",
256
- "cart",
257
- "favorites",
258
255
  "gallery",
259
- "images"
256
+ "breadcrumb",
257
+ "COMPONENT_LIST",
258
+ "slots",
259
+ "IkasComponentRenderer",
260
+ "bundle",
261
+ "serel"
260
262
  ]
261
263
  },
262
264
  "product-list-patterns": {
263
265
  "title": "Product List & Filtering Patterns",
264
266
  "description": "Category pages, product filtering with display-type-aware rendering (swatch, number range, checkbox), sorting, pagination, and search patterns",
265
- "content": "## Product List & Filtering Patterns\n\nProduct list sections power category pages, search results, and collection displays. They combine filtering, sorting, and pagination.\n\n### Product List Prop Setup\n\nIn `ikas.config.json`, use the `PRODUCT_LIST` prop type:\n```json\n{\n \"name\": \"productList\",\n \"displayName\": \"Product List\",\n \"type\": \"PRODUCT_LIST\",\n \"required\": true\n}\n```\n\nThis provides an `IkasProductList` object with products, filters, sorting, and pagination data.\n\n### Displaying Products\n\n```tsx\nimport {\n IkasProductList,\n getSelectedProductVariant,\n getProductVariantFormattedFinalPrice,\n getProductVariantMainImage,\n getSelectedProductVariantHref,\n getDefaultSrc,\n} from \"@ikas/bp-storefront\";\n\n// In your component:\nconst products = productList?.data ?? [];\n\n{products.map((product) => {\n const variant = getSelectedProductVariant(product);\n const productImage = getProductVariantMainImage(variant);\n const image = productImage?.image ?? null;\n const price = getProductVariantFormattedFinalPrice(variant) as unknown as string;\n const href = getSelectedProductVariantHref(product);\n\n return (\n <a key={product.id} href={href} className=\"product-card\">\n {image && <img src={getDefaultSrc(image)} alt={product.name} />}\n <h3>{product.name}</h3>\n <span>{price}</span>\n </a>\n );\n})}\n```\n\n### Filtering\n\nFilters let customers narrow down products by attributes (size, color, price, etc.). Each filter has a `displayType` that determines how it should be rendered. **Always check the display type and render accordingly** — do not render all filters as checkboxes.\n\n#### Display Types\n\n- **BOX / LIST** — Standard checkbox filters (size, brand, etc.)\n- **SWATCH** — Color/pattern swatches with `fv.colorCode` or thumbnail images\n- **NUMBER_RANGE_LIST** — Predefined price/number range buttons (e.g., $0-$50, $50-$100)\n\n#### Universal Data Pattern\n\nThe data flow is the same for all display types:\n- `getFilterDisplayedValues(filter)` — get sorted filter values (works for ALL types)\n- `handleFilterValueClick(productList, filter, filterValue)` — toggle selection + auto-refetch (works for BOX/LIST/SWATCH)\n- `handleNumberRangeOptionClick(productList, filter, option)` — toggle a range option + auto-refetch (for NUMBER_RANGE_LIST)\n\n#### Imports\n\n```tsx\nimport {\n getFilterDisplayedValues,\n handleFilterValueClick,\n handleNumberRangeOptionClick,\n getProductListFilterCategories,\n isBoxFilter,\n isListFilter,\n isSwatchFilter,\n getIkasFilterThumbnailImage,\n getDefaultSrc,\n IkasProductList,\n IkasProductFilter,\n} from \"@ikas/bp-storefront\";\n```\n\n#### Display-Type-Aware Rendering\n\n```tsx\nconst filters = productList.filters ?? [];\n\n{filters.map((filter) => {\n const values = getFilterDisplayedValues(filter);\n if (values.length === 0 && !filter.numberRangeListOptions?.length) return null;\n\n return (\n <div key={filter.id}>\n <h4>{filter.name}</h4>\n\n {/* SWATCH: render color circles / thumbnail images */}\n {isSwatchFilter(filter) ? (\n <div className=\"swatch-grid\">\n {values.map((fv) => {\n const thumbnail = getIkasFilterThumbnailImage(fv);\n return (\n <button\n key={fv.name}\n className={fv.isSelected === true ? \"swatch selected\" : \"swatch\"}\n onClick={() => handleFilterValueClick(productList, filter, fv)}\n title={fv.name}\n >\n {thumbnail ? (\n <img src={getDefaultSrc(thumbnail)} alt={fv.name} />\n ) : (\n <span\n className=\"swatch-color\"\n style={{ backgroundColor: fv.colorCode ?? \"#ccc\" }}\n />\n )}\n </button>\n );\n })}\n </div>\n ) : (\n /* BOX / LIST: render checkboxes */\n values.map((fv) => (\n <label key={fv.name}>\n <input\n type=\"checkbox\"\n checked={fv.isSelected === true}\n onChange={() => handleFilterValueClick(productList, filter, fv)}\n />\n {fv.name} {fv.count != null && `(${fv.count})`}\n </label>\n ))\n )}\n\n {/* NUMBER_RANGE_LIST: render predefined range buttons */}\n {filter.numberRangeListOptions?.map((option) => (\n <button\n key={`${option.from}-${option.to}`}\n className={option.isSelected ? \"range-btn selected\" : \"range-btn\"}\n onClick={() => handleNumberRangeOptionClick(productList, filter, option)}\n >\n {option.from} - {option.to ?? \"+\"}\n </button>\n ))}\n </div>\n );\n})}\n```\n\n### Sorting\n\n```tsx\nimport { getProductListSortOptions, setSortType, IkasProductListSortType } from \"@ikas/bp-storefront\";\n\nconst sortOptions = getProductListSortOptions(productList);\n\n<select\n value={productList.sort}\n onChange={(e) => {\n setSortType(productList, (e.target as HTMLSelectElement).value as IkasProductListSortType);\n }}\n>\n {sortOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n</select>\n```\n\n### Pagination\n\n```tsx\nimport {\n hasProductListNextPage,\n hasProductListPrevPage,\n getProductListNextPage,\n getProductListPrevPage,\n} from \"@ikas/bp-storefront\";\n\nconst hasNext = hasProductListNextPage(productList);\nconst hasPrev = hasProductListPrevPage(productList);\n\n<div className=\"pagination\">\n <button disabled={!hasPrev} onClick={() => getProductListPrevPage(productList)}>\n Previous\n </button>\n <button disabled={!hasNext} onClick={() => getProductListNextPage(productList)}>\n Next\n </button>\n</div>\n```\n\n### Key Functions Reference\n\n| Function | Purpose |\n|----------|---------|\n| `getProductListFilterCategories(list)` | Get available filter categories |\n| `getFilterDisplayedValues(filter)` | Get sorted filter values — works for ALL display types |\n| `handleFilterValueClick(list, filter, value)` | Toggle a filter value + auto-refetch (BOX/LIST/SWATCH) |\n| `handleNumberRangeOptionClick(list, filter, option)` | Toggle a range option + auto-refetch (NUMBER_RANGE_LIST) |\n| `isBoxFilter(filter)` | Check if filter displayType is BOX |\n| `isListFilter(filter)` | Check if filter displayType is LIST |\n| `isSwatchFilter(filter)` | Check if filter displayType is SWATCH |\n| `isCustomValueFilter(filter)` | Check if filter displayType is CUSTOM_VALUE |\n| `getIkasFilterThumbnailImage(fv)` | Get swatch thumbnail IkasImage from a filter value |\n| `getProductListSortOptions(list)` | Get sort dropdown options |\n| `hasProductListNextPage(list)` / `getProductListNextPage(list)` | Next page |\n| `hasProductListPrevPage(list)` / `getProductListPrevPage(list)` | Previous page |",
267
+ "content": "## Product List & Filtering Patterns\n\nProduct list sections power category pages, search results, and collection displays. They combine filtering, sorting, and pagination.\n\n### Product List Prop Setup\n\nIn `ikas.config.json`, use the `PRODUCT_LIST` prop type:\n```json\n{\n \"name\": \"productList\",\n \"displayName\": \"Product List\",\n \"type\": \"PRODUCT_LIST\",\n \"required\": true\n}\n```\n\nThis provides an `IkasProductList` object with products, filters, sorting, and pagination data.\n\n### Displaying Products\n\n```tsx\nimport {\n IkasProductList,\n getSelectedProductVariant,\n getProductVariantFormattedFinalPrice,\n getProductVariantMainImage,\n getSelectedProductVariantHref,\n getDefaultSrc,\n} from \"@ikas/bp-storefront\";\n\n// In your component:\nconst products = productList?.data ?? [];\n\n{products.map((product) => {\n const variant = getSelectedProductVariant(product);\n const productImage = getProductVariantMainImage(variant);\n const image = productImage?.image ?? null;\n const price = getProductVariantFormattedFinalPrice(variant) as unknown as string;\n const href = getSelectedProductVariantHref(product);\n\n return (\n <a key={product.id} href={href} className=\"product-card\">\n {image && <img src={getDefaultSrc(image)} alt={product.name} />}\n <h3>{product.name}</h3>\n <span>{price}</span>\n </a>\n );\n})}\n```\n\n### Filtering\n\nFilters let customers narrow down products by attributes (size, color, price, etc.). Each filter has a `displayType` that determines how it should be rendered. **Always check the display type and render accordingly** — do not render all filters as checkboxes.\n\n#### Display Types\n\n- **BOX / LIST** — Standard checkbox filters (size, brand, etc.)\n- **SWATCH** — Color/pattern swatches with `fv.colorCode` or thumbnail images\n- **NUMBER_RANGE_LIST** — Predefined price/number range buttons (e.g., $0-$50, $50-$100)\n\n#### Universal Data Pattern\n\nThe data flow is the same for all display types:\n- `getFilterDisplayedValues(filter)` — get sorted filter values (works for ALL types)\n- `handleFilterValueClick(productList, filter, filterValue)` — toggle selection + auto-refetch (works for BOX/LIST/SWATCH)\n- `handleNumberRangeOptionClick(productList, filter, option)` — toggle a range option + auto-refetch (for NUMBER_RANGE_LIST)\n\n#### Imports\n\n```tsx\nimport {\n getFilterDisplayedValues,\n handleFilterValueClick,\n handleNumberRangeOptionClick,\n getProductListFilterCategories,\n isBoxFilter,\n isListFilter,\n isSwatchFilter,\n getIkasFilterThumbnailImage,\n getDefaultSrc,\n IkasProductList,\n IkasProductFilter,\n} from \"@ikas/bp-storefront\";\n```\n\n#### Display-Type-Aware Rendering\n\n```tsx\nconst filters = productList.filters ?? [];\n\n{filters.map((filter) => {\n const values = getFilterDisplayedValues(filter);\n if (values.length === 0 && !filter.numberRangeListOptions?.length) return null;\n\n return (\n <div key={filter.id}>\n <h4>{filter.name}</h4>\n\n {/* SWATCH: render color circles / thumbnail images */}\n {isSwatchFilter(filter) ? (\n <div className=\"swatch-grid\">\n {values.map((fv) => {\n const thumbnail = getIkasFilterThumbnailImage(fv);\n return (\n <button\n key={fv.name}\n className={fv.isSelected === true ? \"swatch selected\" : \"swatch\"}\n onClick={() => handleFilterValueClick(productList, filter, fv)}\n title={fv.name}\n >\n {thumbnail ? (\n <img src={getDefaultSrc(thumbnail)} alt={fv.name} />\n ) : (\n <span\n className=\"swatch-color\"\n style={{ backgroundColor: fv.colorCode ?? \"#ccc\" }}\n />\n )}\n </button>\n );\n })}\n </div>\n ) : (\n /* BOX / LIST: render checkboxes */\n values.map((fv) => (\n <label key={fv.name}>\n <input\n type=\"checkbox\"\n checked={fv.isSelected === true}\n onChange={() => handleFilterValueClick(productList, filter, fv)}\n />\n {fv.name} {fv.resultCount != null && `(${fv.resultCount})`}\n </label>\n ))\n )}\n\n {/* NUMBER_RANGE_LIST: render predefined range buttons */}\n {filter.numberRangeListOptions?.map((option) => (\n <button\n key={`${option.from}-${option.to}`}\n className={option.isSelected ? \"range-btn selected\" : \"range-btn\"}\n onClick={() => handleNumberRangeOptionClick(productList, filter, option)}\n >\n {option.from} - {option.to ?? \"+\"}\n </button>\n ))}\n </div>\n );\n})}\n```\n\n### Sorting\n\n```tsx\nimport { getProductListSortOptions, setSortType, IkasProductListSortType } from \"@ikas/bp-storefront\";\n\nconst sortOptions = getProductListSortOptions(productList);\n\n<select\n value={productList.sort}\n onChange={(e) => {\n setSortType(productList, (e.target as HTMLSelectElement).value as IkasProductListSortType);\n }}\n>\n {sortOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n</select>\n```\n\n### Pagination\n\n```tsx\nimport {\n hasProductListNextPage,\n hasProductListPrevPage,\n getProductListNextPage,\n getProductListPrevPage,\n} from \"@ikas/bp-storefront\";\n\nconst hasNext = hasProductListNextPage(productList);\nconst hasPrev = hasProductListPrevPage(productList);\n\n<div className=\"pagination\">\n <button disabled={!hasPrev} onClick={() => getProductListPrevPage(productList)}>\n Previous\n </button>\n <button disabled={!hasNext} onClick={() => getProductListNextPage(productList)}>\n Next\n </button>\n</div>\n```\n\n### Key Functions Reference\n\n| Function | Purpose |\n|----------|---------|\n| `getProductListFilterCategories(list)` | Get available filter categories |\n| `getFilterDisplayedValues(filter)` | Get sorted filter values — works for ALL display types |\n| `handleFilterValueClick(list, filter, value)` | Toggle a filter value + auto-refetch (BOX/LIST/SWATCH) |\n| `handleNumberRangeOptionClick(list, filter, option)` | Toggle a range option + auto-refetch (NUMBER_RANGE_LIST) |\n| `isBoxFilter(filter)` | Check if filter displayType is BOX |\n| `isListFilter(filter)` | Check if filter displayType is LIST |\n| `isSwatchFilter(filter)` | Check if filter displayType is SWATCH |\n| `isCustomValueFilter(filter)` | Check if filter displayType is CUSTOM_VALUE |\n| `getIkasFilterThumbnailImage(fv)` | Get swatch thumbnail IkasImage from a filter value |\n| `getProductListSortOptions(list)` | Get sort dropdown options |\n| `hasProductListNextPage(list)` / `getProductListNextPage(list)` | Next page |\n| `hasProductListPrevPage(list)` / `getProductListPrevPage(list)` | Previous page |",
266
268
  "tags": [
267
269
  "product-list",
268
270
  "filtering",
@@ -276,17 +278,19 @@
276
278
  ]
277
279
  },
278
280
  "cart-patterns": {
279
- "title": "Cart Management Patterns",
280
- "description": "Cart display, quantity changes, item removal, coupon codes, and checkout navigation",
281
- "content": "## Cart Management Patterns\n\nCart management involves displaying cart items, updating quantities, removing items, applying coupons, and navigating to checkout.\n\n### Accessing Cart Data\n\n```tsx\nimport { cartStore } from \"@ikas/bp-storefront\";\n\n// In your component:\nconst cart = cartStore.cart;\nconst lineItems = cart?.orderLineItems ?? [];\nconst isEmpty = lineItems.length === 0;\n```\n\n### Cart Item Display\n\n```tsx\nimport {\n getOrderLineItemFormattedFinalPrice,\n getOrderLineItemFormattedUnitPrice,\n getIkasOrderLineVariantMainImage,\n getDefaultSrc,\n IkasOrderLineItem,\n} from \"@ikas/bp-storefront\";\n\n{lineItems.map((item: IkasOrderLineItem) => {\n const image = item.variant ? getIkasOrderLineVariantMainImage(item.variant) : null;\n return (\n <div key={item.id}>\n {image && <img src={getDefaultSrc(image)} alt={item.variant?.name} />}\n <span>{item.variant?.name}</span>\n <span>Unit: {getOrderLineItemFormattedUnitPrice(item)}</span>\n <span>Qty: {item.quantity}</span>\n <span>Total: {getOrderLineItemFormattedFinalPrice(item)}</span>\n </div>\n );\n})}\n```\n\n### Quantity Changes & Removal\n\n```tsx\nimport { changeItemQuantity, removeItem } from \"@ikas/bp-storefront\";\n\nconst handleQuantityChange = async (item: IkasOrderLineItem, delta: number) => {\n const newQty = item.quantity + delta;\n if (newQty < 1) return;\n await changeItemQuantity(item, newQty);\n};\n\nconst handleRemove = async (item: IkasOrderLineItem) => {\n await removeItem(item);\n};\n```\n\n### Cart Totals\n\n```tsx\nimport {\n getIkasOrderFormattedTotalFinalPrice,\n getIkasOrderFormattedTotalPrice,\n} from \"@ikas/bp-storefront\";\n\n<div className=\"totals\">\n <span>Subtotal: {getIkasOrderFormattedTotalPrice(cart!)}</span>\n <span>Total: {getIkasOrderFormattedTotalFinalPrice(cart!)}</span>\n</div>\n```\n\n### Coupon Codes\n\n```tsx\nimport {\n initCouponCodeForm,\n setCouponCode,\n submitCouponCodeForm,\n} from \"@ikas/bp-storefront\";\n\n// Initialize coupon form\ninitCouponCodeForm(cart);\n\n// Set coupon code\nsetCouponCode(cart, couponValue);\n\n// Submit coupon\nconst success = await submitCouponCodeForm(cart);\n```\n\n### Checkout Navigation\n\n```tsx\nimport { Router, getCheckoutUrlFromCartStore } from \"@ikas/bp-storefront\";\n\n// Navigate to checkout page\nRouter.navigateToPage(\"CHECKOUT\");\n\n// Or get checkout URL directly\nconst checkoutUrl = getCheckoutUrlFromCartStore();\n```\n\n### Free Shipping Bar Pattern\n\nA common pattern from production themes is showing progress toward free shipping:\n\n```tsx\nconst freeShippingThreshold = 500; // configurable via props\nconst cartTotal = cart?.totalFinalPrice ?? 0;\nconst remaining = Math.max(0, freeShippingThreshold - cartTotal);\nconst progress = Math.min(100, (cartTotal / freeShippingThreshold) * 100);\n\n<div className=\"shipping-bar\">\n {remaining > 0\n ? `Add ${formatPrice(remaining)} more for free shipping!`\n : \"You qualify for free shipping!\"}\n <div className=\"progress\" style={{ width: `${progress}%` }} />\n</div>\n```",
281
+ "title": "Cart Management Patterns (Serel Reference)",
282
+ "description": "Serel CartPage section with CartItem sub-component, OrderSummary/CouponCode/EmptyState local components, cartStore patterns, and checkout flow",
283
+ "content": "## Cart Management Patterns (Serel Reference)\n\nThe serel CartPage is a section that uses local internal components (OrderSummary, CouponCode, EmptyState) and the shared `CartItem` sub-component from `src/sub-components/CartItem/`. Unlike most sections, CartPage does NOT use IkasComponentRenderer — it directly composes its UI from sub-components.\n\n### CartPage Section Structure\n\n```tsx\nimport { cartStore } from \"@ikas/bp-storefront\";\nimport CartItem from \"../../sub-components/CartItem\";\nimport { Props } from \"./types\";\n\nexport function CartPage({ backgroundColor, emptyCartText, ...props }: Props) {\n const cart = cartStore.cart;\n const lineItems = cart?.orderLineItems ?? [];\n const isEmpty = lineItems.length === 0;\n\n if (isEmpty) return <EmptyState text={emptyCartText} />;\n\n return (\n <section className=\"cart-page\" style={backgroundColor ? { backgroundColor } : undefined}>\n <div className=\"cart-page-inner\">\n <div className=\"cart-items\">\n {lineItems.map((item) => (\n <CartItem key={item.id} item={item} />\n ))}\n </div>\n <div className=\"cart-sidebar\">\n <CouponCode cart={cart} />\n <OrderSummary cart={cart} />\n </div>\n </div>\n </section>\n );\n}\nexport default CartPage;\n```\n\n### CartItem Sub-Component\n\nThe `CartItem` sub-component (in `src/sub-components/CartItem/`) displays a single line item with image, variant name, quantity controls, price, and remove button:\n\n```tsx\nimport {\n getOrderLineItemFormattedFinalPrice,\n getOrderLineItemFormattedUnitPrice,\n getIkasOrderLineVariantMainImage,\n getDefaultSrc,\n changeItemQuantity,\n removeItem,\n IkasOrderLineItem,\n} from \"@ikas/bp-storefront\";\nimport QuantitySelector from \"../QuantitySelector\";\n\ninterface Props { item: IkasOrderLineItem; }\n\nexport default function CartItem({ item }: Props) {\n const image = item.variant ? getIkasOrderLineVariantMainImage(item.variant) : null;\n\n return (\n <div className=\"cart-item\">\n {image && <img src={getDefaultSrc(image)} alt={item.variant?.name} />}\n <div className=\"cart-item-info\">\n <span>{item.variant?.name}</span>\n <span>{getOrderLineItemFormattedUnitPrice(item)}</span>\n </div>\n <QuantitySelector\n quantity={item.quantity}\n onIncrement={() => changeItemQuantity(item, item.quantity + 1)}\n onDecrement={() => changeItemQuantity(item, Math.max(1, item.quantity - 1))}\n />\n <span>{getOrderLineItemFormattedFinalPrice(item)}</span>\n <button onClick={() => removeItem(item)}>Remove</button>\n </div>\n );\n}\n```\n\n### OrderSummary Local Component\n\nDisplays cart totals using `getIkasOrderFormattedTotalFinalPrice(cart)` and `getIkasOrderFormattedTotalPrice(cart)`, plus a checkout button:\n\n```tsx\nimport { Router, getIkasOrderFormattedTotalFinalPrice } from \"@ikas/bp-storefront\";\n\nfunction OrderSummary({ cart }) {\n return (\n <div className=\"order-summary\">\n <span>Total: {getIkasOrderFormattedTotalFinalPrice(cart)}</span>\n <button onClick={() => Router.navigateToPage(\"CHECKOUT\")}>Checkout</button>\n </div>\n );\n}\n```\n\n### CouponCode Local Component\n\nHandles coupon code input and submission:\n\n```tsx\nimport { initCouponCodeForm, setCouponCode, submitCouponCodeForm } from \"@ikas/bp-storefront\";\n\nfunction CouponCode({ cart }) {\n useEffect(() => { initCouponCodeForm(cart); }, []);\n const [code, setCode] = useState(\"\");\n\n const handleApply = async () => {\n setCouponCode(cart, code);\n await submitCouponCodeForm(cart);\n };\n\n return (\n <div className=\"coupon\">\n <input value={code} onInput={(e) => setCode((e.target as HTMLInputElement).value)} />\n <button onClick={handleApply}>Apply</button>\n </div>\n );\n}\n```\n\n### cartStore Usage Patterns\n\nThe `cartStore` is a MobX store available globally. Root components are automatically reactive via autorun, so reads from `cartStore.cart` trigger re-renders:\n\n```tsx\nimport { cartStore } from \"@ikas/bp-storefront\";\n\n// Always null-safe:\nconst cart = cartStore.cart;\nconst lineItems = cart?.orderLineItems ?? [];\nconst itemCount = lineItems.length;\nconst isEmpty = itemCount === 0;\n```\n\n### Key Pattern: Section Without IkasComponentRenderer\n\nCartPage demonstrates that not all sections need COMPONENT_LIST slots. Simple sections can directly compose sub-components and local components when the layout is fixed and does not need editor-level child component placement.",
282
284
  "tags": [
283
285
  "cart",
284
286
  "checkout",
287
+ "CartItem",
288
+ "OrderSummary",
289
+ "CouponCode",
290
+ "cartStore",
285
291
  "quantity",
286
- "coupon",
287
- "shipping",
288
- "remove",
289
- "line-items"
292
+ "sub-component",
293
+ "serel"
290
294
  ]
291
295
  },
292
296
  "account-patterns": {
@@ -304,19 +308,23 @@
304
308
  ]
305
309
  },
306
310
  "header-footer-patterns": {
307
- "title": "Header & Footer Patterns",
308
- "description": "Navigation links, logo, mobile menu, announcement bar, footer columns, and social links",
309
- "content": "## Header & Footer Patterns\n\nHeaders and footers appear on virtually every page (36/37 pages in a typical theme). They use `IkasNavigationLink` for navigation. Cart/customer state is automatically reactive in root components via the ikas runtime's `autorun()`.\n\n### Marking Header & Footer Sections\n\nTo designate a code component section as the store's header or footer, add `isHeader: true` or `isFooter: true` in `ikas.config.json`:\n\n```json\n{\n \"components\": [\n {\n \"id\": \"header\",\n \"name\": \"Header\",\n \"type\": \"section\",\n \"isHeader\": true,\n \"entry\": \"./src/components/Header/index.tsx\",\n \"styles\": \"./src/components/Header/styles.css\",\n \"props\": [...]\n },\n {\n \"id\": \"footer\",\n \"name\": \"Footer\",\n \"type\": \"section\",\n \"isFooter\": true,\n \"entry\": \"./src/components/Footer/index.tsx\",\n \"styles\": \"./src/components/Footer/styles.css\",\n \"props\": [...]\n }\n ]\n}\n```\n\nThese flags tell the editor to treat the wrapper section as a common header/footer, which means it will appear on all pages automatically. Only one component should have `isHeader: true` and one should have `isFooter: true`.\n\n### Header Section Structure\n\nA production header typically includes:\n1. Announcement bar (optional, with slider)\n2. Logo + navigation links + utility icons (cart, account, search)\n3. Mobile menu overlay\n\n### Navigation Links\n\nUse the `LIST_OF_LINK` prop type for navigation:\n\n```json\n{\n \"name\": \"navigationLinks\",\n \"displayName\": \"Navigation Links\",\n \"type\": \"LIST_OF_LINK\"\n}\n```\n\nRender links:\n```tsx\nimport { IkasNavigationLink, IkasNavigationLinkList } from \"@ikas/bp-storefront\";\n\ninterface Props {\n navigationLinks?: IkasNavigationLinkList;\n}\n\n{(navigationLinks?.links ?? []).map((link: IkasNavigationLink, i: number) => (\n <a key={i} href={link.href} target={link.openInNewTab ? \"_blank\" : undefined}>\n {link.label}\n </a>\n))}\n```\n\n### Cart Badge & Customer State\n\n```tsx\nimport { cartStore, customerStore, hasCustomer, Router } from \"@ikas/bp-storefront\";\n\n// In your component:\nconst itemCount = cartStore.cart?.orderLineItems.length ?? 0;\nconst isLoggedIn = hasCustomer(customerStore) as unknown as boolean;\n\n<div className=\"header-icons\">\n <button onClick={() => Router.navigateToPage(isLoggedIn ? \"ACCOUNT\" : \"LOGIN\")}>\n Account\n </button>\n <button onClick={() => Router.navigateToPage(\"CART\")}>\n Cart ({itemCount})\n </button>\n</div>\n```\n\n### Mobile Menu Overlay\n\nUse `useState` with a plain `<div>` overlay for mobile menus. Note: `IkasThemeOverlay` is a state management type (`{ visible: boolean; show: () => void; hide: () => void; }`), NOT a JSX component.\n\n```tsx\nimport { useState } from \"preact/hooks\";\n\nconst [menuOpen, setMenuOpen] = useState(false);\n\n<button className=\"hamburger\" onClick={() => setMenuOpen(true)}>Menu</button>\n\n{menuOpen && (\n <div className=\"mobile-overlay\">\n <div className=\"mobile-backdrop\" onClick={() => setMenuOpen(false)} />\n <div className=\"mobile-menu\">\n <button className=\"close\" onClick={() => setMenuOpen(false)}>Close</button>\n <nav>\n {(navigationLinks?.links ?? []).map((link, i) => (\n <a key={i} href={link.href} onClick={() => setMenuOpen(false)}>\n {link.label}\n </a>\n ))}\n </nav>\n </div>\n </div>\n)}\n```\n\n### Footer Section Structure\n\nA production footer includes:\n1. Logo and description\n2. Link columns (using `LIST_OF_LINK` or `COMPONENT_LIST` props)\n3. Contact information\n4. Social media links\n5. Copyright text\n\n```tsx\ninterface Props {\n logo?: { src: string; alt?: string };\n linkColumns?: IkasNavigationLinkList;\n copyright?: string;\n socialLinks?: Array<{ icon: string; url: string }>;\n}\n\n<footer className=\"footer-section\">\n <div className=\"footer-inner\">\n <div className=\"footer-brand\">\n {logo?.src && <img src={logo.src} alt={logo.alt || \"Logo\"} />}\n </div>\n <div className=\"footer-links\">\n {(linkColumns?.links ?? []).map((link, i) => (\n <a key={i} href={link.href}>{link.label}</a>\n ))}\n </div>\n <div className=\"footer-copyright\">\n <p>{copyright}</p>\n </div>\n </div>\n</footer>\n```\n\n### Key Patterns\n\n- Headers and footers are **sections** (`\"type\": \"section\"` in config)\n- Root exports are automatically reactive (reads from `cartStore` and `customerStore` are tracked by `autorun()`)\n- Use `LIST_OF_LINK` for navigation that store owners can edit\n- Mobile menu uses `useState` + a plain overlay div for slide-in drawer\n- Announcement bars use `IkasThemeSlider` for rotating messages",
311
+ "title": "Header & Footer Patterns (Serel Reference)",
312
+ "description": "IkasComponentRenderer-based Header with Navbar/Announcements/CookieBar children, Footer with SocialMediaIcon children, Toast system, isHeader/isFooter flags",
313
+ "content": "## Header & Footer Patterns (Serel Reference)\n\nIn the serel theme, the Header and Footer are sections that use `IkasComponentRenderer` to render child components. This is the recommended production pattern.\n\n### Header Architecture\n\nThe serel Header section declares a `COMPONENT_LIST` prop with `filteredComponentIds` restricting it to three child components: **Navbar**, **Announcements**, and **CookieBar**.\n\n```tsx\nimport { IkasComponentRenderer } from \"@ikas/bp-storefront\";\nimport { Props } from \"./types\";\n\nexport function Header({ components, backgroundColor, ...props }: Props) {\n return (\n <header className=\"header\" style={backgroundColor ? { backgroundColor } : undefined}>\n <IkasComponentRenderer id=\"header-components\" components={components} parentProps={props} />\n <ToastContainer />\n </header>\n );\n}\nexport default Header;\n```\n\nConfig setup with `isHeader: true` and `filteredComponentIds`:\n```json\n{\n \"id\": \"nb34u3yu-header\",\n \"name\": \"Header\",\n \"type\": \"section\",\n \"isHeader\": true,\n \"props\": [\n {\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\"nb34u3yu-navbar\", \"nb34u3yu-announcements\", \"nb34u3yu-cookie-bar\"]\n }\n ]\n}\n```\n\nThe `isHeader: true` flag ensures this section appears on every page automatically.\n\n### Toast Notification System\n\nThe serel Header hosts a `ToastContainer` component. The `useToast` hook provides a global notification system:\n\n```tsx\nimport { useToast } from \"../../hooks/useToast\";\n\n// In any component:\nconst { showToast } = useToast();\nshowToast({ message: \"Added to cart!\", type: \"success\" });\n```\n\nThe ToastContainer renders as a portal to ensure toasts appear above all content. Toasts stack vertically and auto-dismiss after a timeout.\n\n### Navbar Child Component\n\nThe Navbar child component handles: logo display, navigation links (`LIST_OF_LINK`), cart badge (reads `cartStore`), account icon (reads `customerStore`), search functionality, and a mobile hamburger menu. It also has its own `COMPONENT_LIST` slot for product search results using CardProductName/CardProductVariants/CardProductPrice with `privateVarMap` for the product variable.\n\n### Announcements Child Component\n\nThe Announcements child component uses `IkasThemeSlider` for a rotating announcement bar. It has its own child component slot for individual Announcement items.\n\n### CookieBar Child Component\n\nThe CookieBar manages cookie consent with accept/decline actions and persists the choice to localStorage.\n\n### Footer Architecture\n\nThe serel Footer section uses `IkasComponentRenderer` with a `COMPONENT_LIST` filtered to **SocialMediaIcon** children:\n\n```tsx\nimport { IkasComponentRenderer } from \"@ikas/bp-storefront\";\nimport { Props } from \"./types\";\n\nexport function Footer({ components, backgroundColor, ...props }: Props) {\n return (\n <footer className=\"footer\" style={backgroundColor ? { backgroundColor } : undefined}>\n <div className=\"footer-inner\">\n {/* Logo, link columns, contact info */}\n <div className=\"footer-social\">\n <IkasComponentRenderer id=\"footer-components\" components={components} parentProps={props} />\n </div>\n {/* Copyright */}\n </div>\n </footer>\n );\n}\nexport default Footer;\n```\n\nConfig with `isFooter: true`:\n```json\n{\n \"id\": \"nb34u3yu-footer\",\n \"name\": \"Footer\",\n \"type\": \"section\",\n \"isFooter\": true,\n \"props\": [\n {\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\"nb34u3yu-social-media-icon\"]\n }\n ]\n}\n```\n\n### Key Patterns\n\n- Headers and footers use `IkasComponentRenderer` with `filteredComponentIds` for controlled child composition\n- `isHeader: true` / `isFooter: true` flags in config make them appear on all pages\n- Root exports are automatically reactive (cartStore/customerStore tracked by autorun)\n- Toast system lives in the Header for global accessibility\n- `parentProps` passes section data to child components\n- The Navbar child component itself nests additional child components via its own COMPONENT_LIST",
310
314
  "tags": [
311
315
  "header",
312
316
  "footer",
313
317
  "navigation",
314
318
  "menu",
315
- "mobile",
316
- "overlay",
317
- "links",
318
- "logo",
319
- "social"
319
+ "IkasComponentRenderer",
320
+ "filteredComponentIds",
321
+ "isHeader",
322
+ "isFooter",
323
+ "toast",
324
+ "navbar",
325
+ "announcements",
326
+ "cookie-bar",
327
+ "social-media"
320
328
  ]
321
329
  },
322
330
  "review-patterns": {
@@ -333,17 +341,22 @@
333
341
  ]
334
342
  },
335
343
  "slider-overlay-patterns": {
336
- "title": "Slider & Overlay Patterns",
337
- "description": "IkasThemeSlider for carousels, IkasThemeOverlay for modals/drawers, IkasThemeInfiniteScroller for lazy loading",
338
- "content": "## Slider & Overlay Patterns\n\nikas provides built-in UI components for common interactive patterns.\n\n### IkasThemeSlider\n\nA carousel/slider component for rotating content (announcements, product images, banners).\n\n```tsx\nimport { IkasThemeSlider } from \"@ikas/bp-storefront\";\n\n<IkasThemeSlider\n autoplay={true}\n autoplayInterval={5000}\n loop={true}\n>\n {(sliderProps) => {\n const { current, index, goTo, dotCount, itemCount } = sliderProps;\n\n return (\n <div className=\"slider\">\n <div className=\"slider-track\">\n {items.map((item, i) => (\n <div key={i} className={`slide ${i === current ? \"active\" : \"\"}`}>\n {item.content}\n </div>\n ))}\n </div>\n\n {/* Navigation arrows */}\n <button onClick={() => goTo(current - 1)}>Previous</button>\n <button onClick={() => goTo(current + 1)}>Next</button>\n\n {/* Dot indicators */}\n <div className=\"dots\">\n {Array.from({ length: dotCount }).map((_, i) => (\n <button\n key={i}\n className={i === current ? \"active\" : \"\"}\n onClick={() => goTo(i)}\n />\n ))}\n </div>\n </div>\n );\n }}\n</IkasThemeSlider>\n```\n\n### Slider Props\n\n| Prop | Type | Description |\n|------|------|-------------|\n| `current` | `number` | Currently visible slide index |\n| `index` | `number` | Internal index (may differ with loop) |\n| `goTo(index)` | `function` | Navigate to specific slide |\n| `dotCount` | `number` | Total number of dots/pages |\n| `itemCount` | `number` | Total number of items |\n\n### IkasThemeOverlay\n\n**Note:** `IkasThemeOverlay` is a state management type, NOT a renderable JSX component. It has the shape:\n\n```typescript\ninterface IkasThemeOverlay {\n visible: boolean;\n show: () => void;\n hide: () => void;\n}\n```\n\nFor modal/drawer overlays, use `useState` with plain `<div>` elements:\n\n```tsx\nimport { useState } from \"preact/hooks\";\n\nconst [isVisible, setIsVisible] = useState(false);\n\n<button onClick={() => setIsVisible(true)}>Open Menu</button>\n\n{isVisible && (\n <div className=\"overlay\">\n <div className=\"overlay-backdrop\" onClick={() => setIsVisible(false)} />\n <div className=\"overlay-content\">\n <button className=\"close-btn\" onClick={() => setIsVisible(false)}>×</button>\n {/* Overlay content */}\n </div>\n </div>\n)}\n```\n\nImplement body scroll lock and backdrop behavior with CSS:\n- Use `position: fixed; inset: 0;` for the overlay container\n- Add a backdrop div for click-to-close\n- Use `overflow: hidden` on body when overlay is open\n\n### IkasThemeInfiniteScroller\n\nA component for infinite scroll / lazy loading patterns.\n\n```tsx\nimport { IkasThemeInfiniteScroller } from \"@ikas/bp-storefront\";\n\n<IkasThemeInfiniteScroller\n hasMore={hasNextPage}\n onLoadMore={async () => {\n await getProductListNextPage(productList);\n }}\n>\n {products.map((product) => (\n <ProductCard key={product.id} product={product} />\n ))}\n</IkasThemeInfiniteScroller>\n```\n\n### Common Usage Patterns\n\n- **Announcement bar**: `IkasThemeSlider` with autoplay for rotating promotional messages\n- **Mobile menu**: `useState` + plain div overlay as a full-screen or side drawer\n- **Product image gallery**: `IkasThemeSlider` for main product images\n- **Quick view modal**: `useState` + plain div overlay showing product details\n- **Product list infinite scroll**: `IkasThemeInfiniteScroller` for seamless pagination\n- **Filter drawer (mobile)**: `useState` + plain div overlay for filter panel on mobile",
344
+ "title": "Slider & Overlay Patterns (Serel Reference)",
345
+ "description": "Serel HeroSlider + HeroSliderItem pattern with IkasComponentRenderer, IkasThemeSlider for carousels, SliderArrow sub-component, IkasThemeOverlay, IkasThemeInfiniteScroller",
346
+ "content": "## Slider & Overlay Patterns (Serel Reference)\n\n### Serel HeroSlider + HeroSliderItem Pattern\n\nThe serel HeroSlider section uses `IkasComponentRenderer` to render `HeroSliderItem` child components inside an `IkasThemeSlider` carousel. This combines the component slot system with the slider API.\n\n**HeroSlider section:**\n```tsx\nimport { IkasComponentRenderer, IkasThemeSlider } from \"@ikas/bp-storefront\";\nimport SliderArrow from \"../../sub-components/SliderArrow\";\nimport { Props } from \"./types\";\n\nexport function HeroSlider({ components, backgroundColor, ...props }: Props) {\n return (\n <section className=\"hero-slider\" style={backgroundColor ? { backgroundColor } : undefined}>\n <IkasThemeSlider autoplay={true} autoplayInterval={5000} loop={true}>\n {(sliderProps) => {\n const { current, goTo, dotCount } = sliderProps;\n return (\n <div className=\"hero-slider-track\">\n <IkasComponentRenderer id=\"hero-slider-components\" components={components} parentProps={{ ...props, current }} />\n <SliderArrow direction=\"prev\" onClick={() => goTo(current - 1)} />\n <SliderArrow direction=\"next\" onClick={() => goTo(current + 1)} />\n <div className=\"hero-slider-dots\">\n {Array.from({ length: dotCount }).map((_, i) => (\n <button key={i} className={i === current ? \"active\" : \"\"} onClick={() => goTo(i)} />\n ))}\n </div>\n </div>\n );\n }}\n </IkasThemeSlider>\n </section>\n );\n}\nexport default HeroSlider;\n```\n\n**Config:**\n```json\n{\n \"id\": \"nb34u3yu-hero-slider\",\n \"name\": \"HeroSlider\",\n \"type\": \"section\",\n \"props\": [\n {\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\"nb34u3yu-hero-slider-item\"]\n }\n ]\n}\n```\n\n**HeroSliderItem child component:** Each slide item receives props from the editor (IMAGE for background, TEXT for heading/subtitle, LINK for CTA button).\n\n### SliderArrow Sub-Component\n\nThe `SliderArrow` sub-component (in `src/sub-components/SliderArrow/`) renders prev/next navigation arrows with consistent styling across all slider sections.\n\n### IkasThemeSlider API\n\nRender function receives:\n\n| Prop | Type | Description |\n|------|------|-------------|\n| `current` | `number` | Currently visible slide index |\n| `goTo(index)` | `function` | Navigate to specific slide |\n| `dotCount` | `number` | Total number of dots/pages |\n| `itemCount` | `number` | Total number of items |\n\nConfiguration props: `autoplay`, `autoplayInterval`, `loop`.\n\n### IkasThemeOverlay\n\n`IkasThemeOverlay` is a state management type, NOT a JSX component:\n\n```typescript\ninterface IkasThemeOverlay {\n visible: boolean;\n show: () => void;\n hide: () => void;\n}\n```\n\nFor overlays, use `useState` with plain `<div>` elements and CSS `position: fixed; inset: 0;`. The serel theme uses the `useScrollLock` hook to prevent body scrolling when overlays are open.\n\n### IkasThemeInfiniteScroller\n\nUsed in the serel CategoryList section for infinite scroll product loading:\n\n```tsx\nimport { IkasThemeInfiniteScroller } from \"@ikas/bp-storefront\";\n\n<IkasThemeInfiniteScroller\n hasMore={hasProductListNextPage(productList)}\n onLoadMore={async () => { await getProductListNextPage(productList); }}\n>\n {products.map((product) => (\n <ProductCard key={product.id} product={product} />\n ))}\n</IkasThemeInfiniteScroller>\n```\n\nThe serel theme also provides a `useInfiniteScroll` custom hook as an alternative to the built-in component.\n\n### Common Serel Usage\n\n- **HeroSlider**: IkasThemeSlider + IkasComponentRenderer for editor-managed slides\n- **ProductSlider**: IkasThemeSlider for product card carousels\n- **Announcements**: IkasThemeSlider with autoplay for rotating announcement bar\n- **CategoryList**: IkasThemeInfiniteScroller or useInfiniteScroll hook\n- **Mobile menu, modals**: useState + div overlay + useScrollLock hook\n- **ImagePreviewModal**: Sub-component for full-screen image zoom in product gallery",
339
347
  "tags": [
340
348
  "slider",
341
349
  "carousel",
350
+ "HeroSlider",
351
+ "HeroSliderItem",
352
+ "SliderArrow",
342
353
  "overlay",
343
354
  "modal",
344
- "drawer",
345
355
  "infinite-scroll",
346
- "lazy-loading"
356
+ "useInfiniteScroll",
357
+ "useScrollLock",
358
+ "IkasComponentRenderer",
359
+ "serel"
347
360
  ]
348
361
  },
349
362
  "blog-patterns": {
@@ -362,7 +375,7 @@
362
375
  "navigation-patterns": {
363
376
  "title": "Navigation & Routing Patterns",
364
377
  "description": "Router.navigate, page navigation, href getters, breadcrumbs, and query parameters",
365
- "content": "## Navigation & Routing Patterns\n\nikas provides a `Router` utility and various href getter functions for navigation.\n\n### Basic Navigation\n\n```tsx\nimport { Router } from \"@ikas/bp-storefront\";\n\n// Navigate to a URL\nRouter.navigate(\"/products\");\n\n// Navigate to a named page\nRouter.navigateToPage(\"LOGIN\");\nRouter.navigateToPage(\"REGISTER\");\nRouter.navigateToPage(\"FORGOT_PASSWORD\");\nRouter.navigateToPage(\"ACCOUNT\");\nRouter.navigateToPage(\"CART\");\nRouter.navigateToPage(\"CHECKOUT\");\n\n// Navigate with options\nRouter.navigateToPage(\"CATEGORY\", {\n queryParams: { sort: \"price_asc\" },\n shallow: false,\n newTab: false,\n});\n\n// Go back\nRouter.goBack();\n```\n\n### Page Type Constants\n\nAvailable page types for `navigateToPage()`:\n- `INDEX` — Home page\n- `CATEGORY` — Category listing\n- `PRODUCT_DETAIL` — Product detail\n- `BLOG` — Blog listing\n- `BLOG` — Blog post detail\n- `CART` — Shopping cart\n- `CHECKOUT` — Checkout flow\n- `LOGIN` — Login page\n- `REGISTER` — Registration page\n- `FORGOT_PASSWORD` — Password recovery\n- `ACCOUNT` — Customer account\n- `SEARCH` — Search results\n- `CUSTOM` — Custom pages\n\n### Href Getter Functions\n\nThese return URL strings for use in `<a href>` tags:\n\n```tsx\nimport {\n getSelectedProductVariantHref,\n getIkasCategoryHref,\n getIkasOrderHref,\n getIkasBlogHref,\n getIkasBrandHref,\n} from \"@ikas/bp-storefront\";\n\n// Product link\n<a href={getSelectedProductVariantHref(product)}>{product.name}</a>\n\n// Category link\n<a href={getIkasCategoryHref(category)}>{category.name}</a>\n\n// Order link\n<a href={getIkasOrderHref(order)}>Order #{order.orderNumber}</a>\n\n// Blog link\n<a href={getIkasBlogHref(blog)}>{blog.title}</a>\n\n// Brand link\n<a href={getIkasBrandHref(brand)}>{brand.name}</a>\n```\n\n### Breadcrumbs\n\n```tsx\nimport {\n getCategoryPath,\n getProductCategoryPath,\n getIkasCategoryHref,\n} from \"@ikas/bp-storefront\";\n\n// For category pages\nconst categoryPath = getCategoryPath(category);\n\n// For product pages\nconst productPath = getProductCategoryPath(product);\n\n<nav className=\"breadcrumbs\">\n <a href=\"/\">Home</a>\n {categoryPath?.map((cat, i) => (\n <span key={cat.id}>\n <span className=\"separator\">/</span>\n <a href={getIkasCategoryHref(cat)}>{cat.name}</a>\n </span>\n ))}\n</nav>\n```\n\n### Using Links vs Navigation\n\n- Use `<a href={getXxxHref(...)}>` for standard links (SEO-friendly, right-click works)\n- Use `Router.navigate()` for programmatic navigation after form submission or actions\n- Use `Router.navigateToPage()` for navigating to known page types\n- Use `Router.goBack()` for back buttons",
378
+ "content": "## Navigation & Routing Patterns\n\nikas provides a `Router` utility and various href getter functions for navigation.\n\n### Basic Navigation\n\n```tsx\nimport { Router } from \"@ikas/bp-storefront\";\n\n// Navigate to a URL\nRouter.navigate(\"/products\");\n\n// Navigate with options\nRouter.navigate(\"/products\", true); // shallow navigation (no full page reload)\nRouter.navigate(\"/products\", false, true); // open in new tab\n// Signature: Router.navigate(path: string, shallow?: boolean, openInNewTab?: boolean)\n\n// Navigate to a named page\nRouter.navigateToPage(\"LOGIN\");\nRouter.navigateToPage(\"REGISTER\");\nRouter.navigateToPage(\"FORGOT_PASSWORD\");\nRouter.navigateToPage(\"ACCOUNT\");\nRouter.navigateToPage(\"CART\");\nRouter.navigateToPage(\"CHECKOUT\");\n\n// Navigate with options\nRouter.navigateToPage(\"CATEGORY\", {\n queryParams: { sort: \"price_asc\" },\n shallow: false,\n newTab: false,\n});\n\n// Go back\nRouter.goBack();\n```\n\n### Page Type Constants\n\nAvailable page types for `navigateToPage()`:\n- `INDEX` — Home page\n- `CATEGORY` — Category listing\n- `PRODUCT_DETAIL` — Product detail\n- `BLOG` — Blog listing\n- `BLOG` — Blog post detail\n- `CART` — Shopping cart\n- `CHECKOUT` — Checkout flow\n- `LOGIN` — Login page\n- `REGISTER` — Registration page\n- `FORGOT_PASSWORD` — Password recovery\n- `ACCOUNT` — Customer account\n- `SEARCH` — Search results\n- `CUSTOM` — Custom pages\n\n### Href Getter Functions\n\nThese return URL strings for use in `<a href>` tags:\n\n```tsx\nimport {\n getSelectedProductVariantHref,\n getIkasCategoryHref,\n getIkasOrderHref,\n getIkasBlogHref,\n getIkasBrandHref,\n} from \"@ikas/bp-storefront\";\n\n// Product link\n<a href={getSelectedProductVariantHref(product)}>{product.name}</a>\n\n// Category link\n<a href={getIkasCategoryHref(category)}>{category.name}</a>\n\n// Order link\n<a href={getIkasOrderHref(order)}>Order #{order.orderNumber}</a>\n\n// Blog link\n<a href={getIkasBlogHref(blog)}>{blog.title}</a>\n\n// Brand link\n<a href={getIkasBrandHref(brand)}>{brand.name}</a>\n```\n\n### Breadcrumbs\n\n```tsx\nimport {\n getCategoryPath,\n getProductCategoryPath,\n getIkasCategoryHref,\n} from \"@ikas/bp-storefront\";\n\n// For category pages\nconst categoryPath = getCategoryPath(category);\n\n// For product pages\nconst productPath = getProductCategoryPath(product);\n\n<nav className=\"breadcrumbs\">\n <a href=\"/\">Home</a>\n {categoryPath?.map((cat, i) => (\n <span key={cat.id}>\n <span className=\"separator\">/</span>\n <a href={getIkasCategoryHref(cat)}>{cat.name}</a>\n </span>\n ))}\n</nav>\n```\n\n### Using Links vs Navigation\n\n- Use `<a href={getXxxHref(...)}>` for standard links (SEO-friendly, right-click works)\n- Use `Router.navigate()` for programmatic navigation after form submission or actions\n- Use `Router.navigateToPage()` for navigating to known page types\n- Use `Router.goBack()` for back buttons",
366
379
  "tags": [
367
380
  "navigation",
368
381
  "router",
@@ -374,18 +387,21 @@
374
387
  ]
375
388
  },
376
389
  "real-world-architecture": {
377
- "title": "Real-World Theme Architecture",
378
- "description": "How production themes are structured: page types, section composition, component reuse, and prop design patterns",
379
- "content": "## Real-World Theme Architecture\n\nThis guide describes how a production ikas theme is structured, based on analysis of real deployed themes.\n\n### Page Types\n\nA complete theme typically has these page types:\n\n| Page Type | Purpose | Common Sections |\n|-----------|---------|------------------|\n| `INDEX` | Home page | Header, Hero Banner, Featured Products, Categories, Footer |\n| `CATEGORY` | Category listing | Header, Product List, Footer |\n| `PRODUCT_DETAIL` | Product page | Header, Product Detail, Reviews, Related Products, Footer |\n| `BLOG` | Blog listing | Header, Blog List, Footer |\n| `BLOG` | Blog article | Header, Blog Post Detail, Footer |\n| `CART` | Shopping cart | Header, Cart Section, Footer |\n| `CHECKOUT` | Checkout flow | Minimal Header, Checkout Form |\n| `LOGIN` | Sign in | Header, Login Form, Footer |\n| `REGISTER` | Sign up | Header, Register Form, Footer |\n| `FORGOT_PASSWORD` | Password recovery | Header, Forgot Password Form, Footer |\n| `ACCOUNT` | Customer dashboard | Header, Account Section, Footer |\n| `SEARCH` | Search results | Header, Product List (search mode), Footer |\n| `CUSTOM` | Custom pages (About, Contact, FAQ) | Header, Custom Content, Footer |\n| `NOT_FOUND` | 404 page | Header, 404 Message, Footer |\n\n### Section Composition Pattern\n\nEvery page follows: **Header Content Section(s) → Footer**\n\n- Header and Footer are shared across 36/37 pages (all except checkout)\n- Content sections are page-specific\n- Some sections are reused across multiple pages (FAQ on 10 pages, Rich Text on 9)\n\n### Section Reuse Strategy\n\nDesign sections to be reusable:\n\n| Section | Reuse Count | Strategy |\n|---------|-------------|----------|\n| Header | 36 pages | Single section, all navigation |\n| Footer | 36 pages | Single section, all links |\n| FAQ | 10 pages | Generic accordion, content via props |\n| Rich Text / HTML | 9 pages | Generic content block |\n| Product Detail | 1 page | Highly specialized |\n| Cart | 1 page | Highly specialized |\n\n### Component Hierarchy\n\nProduction sections have sub-components:\n\n```\nHeader Section (section)\n├── AnnouncementBar (component)\n├── NavigationBar (component)\n│ ├── Logo\n│ ├── NavLinks\n│ └── CartIcon / AccountIcon\n└── MobileMenu (component)\n\nProduct Detail Section (section)\n├── ImageGallery (component)\n├── VariantSelector (component)\n├── PriceDisplay (component)\n├── AddToCartButton (component)\n└── ProductDescription (component)\n```\n\n### Prop Design Patterns\n\nCommon prop patterns seen in production:\n\n1. **Content props**: `TEXT` for headings, descriptions, button labels\n2. **Style props**: `COLOR` for backgrounds, text colors, accents. **Every section MUST have a `backgroundColor` COLOR prop** (default `#ffffff`). Consider `textColor` for text directly on the background\n3. **Toggle props**: `BOOLEAN` for show/hide sections, features\n4. **Layout props**: `ENUM` for layout variants (grid/list, left/center/right)\n5. **Navigation props**: `LIST_OF_LINK` for editable nav menus\n6. **Data props**: `PRODUCT`, `PRODUCT_LIST`, `BLOG_LIST` for dynamic data\n7. **Media props**: `IMAGE` for logos, banners, icons\n\n### Responsive Design\n\nProduction themes target these breakpoints:\n- Desktop: 1200px+ (max-width container)\n- Tablet: 768px-1199px\n- Mobile: <768px\n\nCommon responsive patterns:\n```css\n.section { width: 100%; padding: 64px 24px; }\n.section-inner { max-width: 1200px; margin: 0 auto; }\n\n@media (max-width: 768px) {\n .section { padding: 32px 16px; }\n .grid { grid-template-columns: 1fr; }\n}\n```\n\n### Essential Sections Checklist\n\nEvery complete theme needs at minimum:\n- [ ] Header (with mobile menu)\n- [ ] Footer\n- [ ] Hero Banner / Home content\n- [ ] Product List (category page)\n- [ ] Product Detail\n- [ ] Cart\n- [ ] Login / Register / Forgot Password\n- [ ] Account (orders, addresses)\n- [ ] 404 Page\n- [ ] Contact Form (optional but common)\n- [ ] FAQ (optional but common)\n- [ ] Blog List + Blog Post (optional)",
390
+ "title": "Real-World Theme Architecture (Serel Reference)",
391
+ "description": "Production theme architecture based on the serel theme: 20 sections, 30 child components, 35 sub-components, 8 hooks, 9 utils — three-tier component hierarchy",
392
+ "content": "## Real-World Theme Architecture (Serel Reference)\n\nThis guide describes the architecture of the **serel** production theme (project ID: `nb34u3yu`), a complete e-commerce storefront with 20 sections, 30 child components, 35 sub-components, 8 custom hooks, and 9 utility modules.\n\n### Three-Tier Component Hierarchy\n\nikas themes use a strict three-tier architecture:\n\n**Tier 1 Sections (20):** Page-level containers registered in `ikas.config.json` with `type: \"section\"`. They own the layout, declare COMPONENT_LIST slots, and render via `<IkasComponentRenderer>`. Examples: Header, HeroSlider, ProductDetail, CartPage, Footer.\n\n**Tier 2 — Child Components (30):** Registered in `ikas.config.json` without `type` (default `\"component\"`). Placed inside sections via COMPONENT_LIST slots. The editor controls which children go in which section via `filteredComponentIds`. Examples: Navbar, HeroSliderItem, CardProductName, ProductDetailAddToCart.\n\n**Tier 3 — Sub-Components (35):** Internal helpers in `src/sub-components/`. NOT registered in config. Shared across multiple sections and child components. Examples: Button, Input, Modal, ProductCard, Pagination, Toast.\n\n### Section Inventory (20 sections)\n\n| Section | Purpose | Child Component Count |\n|---------|---------|----------------------|\n| Header | Global navigation | 3 (Navbar, Announcements, CookieBar) |\n| HeroSlider | Homepage banner carousel | 1 (HeroSliderItem) |\n| CategoryImages | Category image grid | 1 (CategoryImageItem) |\n| Footer | Global footer | 1 (SocialMediaIcon) |\n| ProductSlider | Product carousel | 3 (CardProductName, CardProductVariants, CardProductPrice) |\n| CategoryList | Product listing/filtering | 3 (same card components) |\n| ProductDetail | Product page | 12 child components in 2 slots |\n| Features | Feature icon grid | 1 (FeatureItem) |\n| AccountInfo | Customer dashboard | 5 (AccountInfoContent, AccountOrders, AccountAddresses, AccountFavorites, AccountOrderDetail) |\n| CartPage | Shopping cart | 0 (uses sub-components directly) |\n| Login, Register, ForgotPassword, RecoverPassword | Auth pages | 0 each |\n| BlogHome, BlogPost | Blog pages | 0 each |\n| RichText | Generic content block | 0 |\n| ProductDetailReviews | Product reviews | 0 |\n| CustomerEmailVerification | Email verification | 0 |\n| NotFound | 404 page | 0 |\n\n### Child Component Reuse via privateVarMap\n\nSeveral sections share the same card child components (CardProductName, CardProductVariants, CardProductPrice) using `privateVarMap` to expose a `product` variable of type `IkasProduct`. This pattern is used by ProductSlider, CategoryList, AccountFavorites, and Navbar.\n\n### Custom Hooks (8)\n\n- `useBundleProducts` bundle product logic\n- `useColumnPreference` — grid column preference state\n- `useInfiniteScroll` — scroll-based pagination\n- `usePageTracking` — analytics page tracking\n- `usePayWithIkas` — ikas payment integration\n- `useRedirectIfLoggedIn` — auth redirect guard\n- `useScrollLock` body scroll locking for modals\n- `useToast` — toast notification system\n\n### Utility Modules (9)\n\n`bundle.ts`, `cx.ts` (classname helper), `fullName.ts`, `media.ts`, `optionPrice.ts`, `optionSet.ts`, `orderStatus.ts`, `pagination.ts`, `toast.ts`\n\n### Prop Design Patterns\n\n1. **Content props**: `TEXT` for all user-visible text (headings, buttons, labels)\n2. **Style props**: `COLOR` for backgrounds and text colors. Every section has `backgroundColor`\n3. **Component slots**: `COMPONENT_LIST` for child component areas\n4. **Navigation props**: `LIST_OF_LINK` for editable nav menus\n5. **Data props**: `PRODUCT_LIST`, `BLOG_LIST` for dynamic data\n6. **Media props**: `IMAGE` for logos, banners, icons\n7. **Toggle props**: `BOOLEAN` for show/hide features\n\n### Responsive Design\n\nProduction themes target: Desktop 1200px+, Tablet 768-1199px, Mobile <768px.\n\n```css\n.section { width: 100%; padding: 64px 24px; }\n.section-inner { max-width: 1200px; margin: 0 auto; }\n@media (max-width: 768px) { .section { padding: 32px 16px; } }\n```",
380
393
  "tags": [
381
394
  "architecture",
382
395
  "theme",
383
- "pages",
396
+ "serel",
384
397
  "sections",
385
- "composition",
386
- "reuse",
387
- "responsive",
388
- "production"
398
+ "components",
399
+ "sub-components",
400
+ "hooks",
401
+ "utils",
402
+ "production",
403
+ "hierarchy",
404
+ "privateVarMap"
389
405
  ]
390
406
  },
391
407
  "prop-groups": {
@@ -401,6 +417,114 @@
401
417
  "propGroups",
402
418
  "groupId"
403
419
  ]
420
+ },
421
+ "component-renderer-patterns": {
422
+ "title": "IkasComponentRenderer — Component Slot Architecture",
423
+ "description": "How sections declare COMPONENT_LIST slots, filteredComponentIds to restrict children, parentProps for data passing, and multiple slot patterns from the serel theme",
424
+ "content": "## IkasComponentRenderer — Component Slot Architecture\n\n`IkasComponentRenderer` is the core mechanism for sections to render child components. It enables store owners to add, remove, and reorder child components within a section from the editor UI.\n\n### Basic Usage\n\nA section declares a `COMPONENT_LIST` prop, then renders it with `IkasComponentRenderer`:\n\n```tsx\nimport { IkasComponentRenderer } from \"@ikas/bp-storefront\";\nimport { Props } from \"./types\";\n\nexport function MySection({ components, backgroundColor, ...props }: Props) {\n return (\n <section style={backgroundColor ? { backgroundColor } : undefined}>\n <IkasComponentRenderer id=\"section-components\" components={components} parentProps={props} />\n </section>\n );\n}\nexport default MySection;\n```\n\n**Config:**\n```json\n{\n \"name\": \"components\",\n \"displayName\": \"Components\",\n \"type\": \"COMPONENT_LIST\"\n}\n```\n\n### filteredComponentIds — Restricting Allowed Children\n\nBy default, any child component can be placed in a COMPONENT_LIST slot. Use `filteredComponentIds` to restrict which components are allowed:\n\n```json\n{\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\n \"nb34u3yu-navbar\",\n \"nb34u3yu-announcements\",\n \"nb34u3yu-cookie-bar\"\n ]\n}\n```\n\nThis ensures only Navbar, Announcements, and CookieBar can be placed in the Header's component slot.\n\n### parentProps — Passing Data to Children\n\nAlways spread remaining props into `parentProps` so child components can access section-level data:\n\n```tsx\nexport function ProductSlider({ components, product, ...props }: Props) {\n return (\n <div>\n <IkasComponentRenderer id=\"product-slider-components\" components={components} parentProps={props} />\n </div>\n );\n}\n```\n\nChild components automatically receive data from `parentProps`. Combined with `privateVarMap`, this is how sections expose data (like a product object) to their children.\n\n### Multiple COMPONENT_LIST Slots\n\nSections can have multiple slots for different layout regions. The serel ProductDetail section uses two:\n\n```json\n{\n \"props\": [\n {\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\"...12 product detail children...\"]\n },\n {\n \"name\": \"bottomComponents\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\"nb34u3yu-product-detail-description\"]\n }\n ]\n}\n```\n\n```tsx\nexport function ProductDetail({ product, components, bottomComponents, ...props }: Props) {\n return (\n <section>\n <div className=\"detail-side-panel\">\n <IkasComponentRenderer id=\"detail-components\" components={components} parentProps={props} />\n </div>\n <div className=\"detail-bottom\">\n <IkasComponentRenderer id=\"detail-bottom-components\" components={bottomComponents} parentProps={props} />\n </div>\n </section>\n );\n}\n```\n\n### Serel Examples of Section-to-Child Relationships\n\n| Section | COMPONENT_LIST children | Notes |\n|---------|------------------------|-------|\n| Header | Navbar, Announcements, CookieBar | `isHeader: true` |\n| HeroSlider | HeroSliderItem | Inside IkasThemeSlider |\n| CategoryImages | CategoryImageItem | Grid layout |\n| Footer | SocialMediaIcon | `isFooter: true` |\n| ProductSlider | CardProductName, CardProductVariants, CardProductPrice | Uses `privateVarMap` for product |\n| CategoryList | CardProductName, CardProductVariants, CardProductPrice | Uses `privateVarMap` for product |\n| ProductDetail | 12 children in 2 slots | Most complex section |\n| Features | FeatureItem | Simple repeating items |\n| AccountInfo | 5 account tab children | Dashboard tabs |\n\n### Key Rules\n\n1. Always pass `parentProps={props}` (spread remaining props after destructuring COMPONENT_LIST)\n2. Cast if needed: `components={components as any[]}`\n3. `filteredComponentIds` uses the full component ID (project prefix + kebab-case name)\n4. Multiple COMPONENT_LIST slots enable multi-region layouts\n5. Sections without COMPONENT_LIST (CartPage, Login, etc.) compose sub-components directly",
425
+ "tags": [
426
+ "IkasComponentRenderer",
427
+ "COMPONENT_LIST",
428
+ "filteredComponentIds",
429
+ "parentProps",
430
+ "slots",
431
+ "children",
432
+ "component-renderer",
433
+ "composition"
434
+ ]
435
+ },
436
+ "private-var-map": {
437
+ "title": "privateVarMap — Passing Data from Sections to Children",
438
+ "description": "How sections expose typed data to child components via privateVarMap config, enabling component reuse across multiple sections with different data sources",
439
+ "content": "## privateVarMap — Passing Data from Sections to Children\n\n`privateVarMap` is a config mechanism that lets a section expose a typed variable to its child components. This enables the same child component to be reused across multiple sections that provide the same data type.\n\n### The Problem It Solves\n\nIn the serel theme, `CardProductName`, `CardProductVariants`, and `CardProductPrice` are used in 4 different sections (ProductSlider, CategoryList, AccountFavorites, Navbar). Each section has a different product data source, but the card components need a `product` object to render. `privateVarMap` bridges this gap.\n\n### Config Syntax\n\nAdd `privateVarMap` to a `COMPONENT_LIST` prop definition:\n\n```json\n{\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\n \"nb34u3yu-card-product-name\",\n \"nb34u3yu-card-product-variants\",\n \"nb34u3yu-card-product-price\"\n ],\n \"privateVarMap\": {\n \"product\": {\n \"id\": \"nb34u3yu-product-slider-product\",\n \"typeId\": \"@ikas/bp-storefront-models-IkasProduct\"\n }\n }\n}\n```\n\n### How It Works\n\n1. The section declares a `privateVarMap` on its COMPONENT_LIST prop\n2. Each key in the map (e.g., `\"product\"`) is the variable name exposed to children\n3. `id` is a unique identifier for this variable binding (project prefix + section name + variable name)\n4. `typeId` references the model type using the format `@ikas/bp-storefront-models-TypeName`\n5. Child components automatically receive this variable without explicit prop passing\n\n### Type Reference Format\n\nThe `typeId` field uses the pattern `@ikas/bp-storefront-models-TypeName`. Common types:\n\n| typeId | TypeScript Type |\n|--------|----------------|\n| `@ikas/bp-storefront-models-IkasProduct` | `IkasProduct` |\n| `@ikas/bp-storefront-models-IkasCategory` | `IkasCategory` |\n| `@ikas/bp-storefront-models-IkasBlog` | `IkasBlog` |\n| `@ikas/bp-storefront-models-IkasOrder` | `IkasOrder` |\n| `@ikas/bp-storefront-models-IkasCustomer` | `IkasCustomer` |\n\n### Real Serel Examples\n\n**ProductSlider** exposes `product` to card children:\n```json\n{\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\"nb34u3yu-card-product-name\", \"nb34u3yu-card-product-variants\", \"nb34u3yu-card-product-price\"],\n \"privateVarMap\": {\n \"product\": {\n \"id\": \"nb34u3yu-product-slider-product\",\n \"typeId\": \"@ikas/bp-storefront-models-IkasProduct\"\n }\n }\n}\n```\n\n**CategoryList** exposes the same `product` variable to the same card children:\n```json\n{\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\"nb34u3yu-card-product-name\", \"nb34u3yu-card-product-variants\", \"nb34u3yu-card-product-price\"],\n \"privateVarMap\": {\n \"product\": {\n \"id\": \"nb34u3yu-category-list-product\",\n \"typeId\": \"@ikas/bp-storefront-models-IkasProduct\"\n }\n }\n}\n```\n\nNotice: `id` is different per section, but `typeId` is the same. The child components (CardProductName, etc.) work identically in both contexts.\n\n### Sections Using privateVarMap in Serel\n\n| Section | Variable | Type | Child Components |\n|---------|----------|------|------------------|\n| ProductSlider | `product` | `IkasProduct` | CardProductName, CardProductVariants, CardProductPrice |\n| CategoryList | `product` | `IkasProduct` | CardProductName, CardProductVariants, CardProductPrice |\n| AccountFavorites | `product` | `IkasProduct` | CardProductName, CardProductVariants, CardProductPrice |\n| Navbar | `product` | `IkasProduct` | CardProductName, CardProductVariants, CardProductPrice |\n\n### Key Rules\n\n1. `privateVarMap` goes on the COMPONENT_LIST prop, not the section itself\n2. `id` must be unique per section-variable combination (use project prefix + section name + var name)\n3. `typeId` uses the `@ikas/bp-storefront-models-` prefix\n4. Children receive the variable automatically — no explicit prop passing needed\n5. The same child component works across different sections that expose the same typeId",
440
+ "tags": [
441
+ "privateVarMap",
442
+ "data-passing",
443
+ "COMPONENT_LIST",
444
+ "typeId",
445
+ "product",
446
+ "component-reuse",
447
+ "sections",
448
+ "children",
449
+ "variable"
450
+ ]
451
+ },
452
+ "page-composition": {
453
+ "title": "Page Composition — Which Sections Compose Each Page",
454
+ "description": "How the serel theme composes pages from sections: home, product detail, category, cart, account, blog, auth, and error pages",
455
+ "content": "## Page Composition — Which Sections Compose Each Page\n\nEvery page in the serel theme follows the pattern: **Header → Content Section(s) → Footer**. The Header (`isHeader: true`) and Footer (`isFooter: true`) appear on all pages automatically.\n\n### Home Page (INDEX)\n\n```\nHeader (global)\nHeroSlider — full-width carousel with HeroSliderItem children\nCategoryImages — category image grid with CategoryImageItem children\nProductSlider — product carousel with card children (privateVarMap: product)\nFeatures — feature icon grid with FeatureItem children\nFooter (global)\n```\n\n### Product Detail Page (PRODUCT_DETAIL)\n\n```\nHeader (global)\nProductDetail — 12 child components in 2 COMPONENT_LIST slots\n Gallery, name, SKU, prices, variants, add-to-cart,\n features, description, bundles, option sets, offers\nProductDetailReviews — customer review display and submission form\nFooter (global)\n```\n\n### Category / Product List Page (CATEGORY)\n\n```\nHeader (global)\nCategoryList — product grid with filtering, sorting, pagination\n Card children via privateVarMap: product\nFooter (global)\n```\n\n### Cart Page (CART)\n\n```\nHeader (global)\nCartPage — cart items, order summary, coupon codes\n Uses CartItem sub-component directly (no IkasComponentRenderer)\nFooter (global)\n```\n\n### Account Dashboard (ACCOUNT)\n\n```\nHeader (global)\nAccountInfo — 5 child components for tab-based dashboard:\n AccountInfoContent, AccountOrders, AccountAddresses,\n AccountFavorites, AccountOrderDetail\nFooter (global)\n```\n\n### Blog Home (BLOG listing)\n\n```\nHeader (global)\nBlogHome — blog post list with pagination\nFooter (global)\n```\n\n### Blog Post Detail (BLOG post)\n\n```\nHeader (global)\nBlogPost — single blog post content\nFooter (global)\n```\n\n### Auth Pages\n\n```\nHeader (global)\nLogin / Register / ForgotPassword / RecoverPassword — single auth form section\nFooter (global)\n```\n\nEach auth page uses one of: Login, Register, ForgotPassword, or RecoverPassword sections.\n\n### Email Verification (CUSTOMER_EMAIL_VERIFICATION)\n\n```\nHeader (global)\nCustomerEmailVerification — verification status display\nFooter (global)\n```\n\n### 404 Not Found (NOT_FOUND)\n\n```\nHeader (global)\nNotFound — 404 message and navigation back\nFooter (global)\n```\n\n### Section Count Summary\n\nThe 20 sections cover all essential page types:\n- **Global (2):** Header, Footer\n- **Home (4):** HeroSlider, CategoryImages, ProductSlider, Features\n- **Product (2):** ProductDetail, ProductDetailReviews\n- **Category (1):** CategoryList\n- **Cart (1):** CartPage\n- **Account (1):** AccountInfo (with 5 child tab components)\n- **Blog (2):** BlogHome, BlogPost\n- **Auth (4):** Login, Register, ForgotPassword, RecoverPassword\n- **Utility (3):** RichText, CustomerEmailVerification, NotFound\n\n### Design Principles\n\n1. **Header/Footer on every page** via `isHeader`/`isFooter` flags\n2. **One section per concern** — product detail, reviews, cart are separate sections\n3. **Complex pages use COMPONENT_LIST** — ProductDetail has 12 children, AccountInfo has 5\n4. **Simple pages use direct composition** — Login, CartPage compose sub-components without IkasComponentRenderer\n5. **Reusable content sections** — RichText can appear on any custom page",
456
+ "tags": [
457
+ "pages",
458
+ "composition",
459
+ "home",
460
+ "product-detail",
461
+ "category",
462
+ "cart",
463
+ "account",
464
+ "blog",
465
+ "auth",
466
+ "404",
467
+ "serel",
468
+ "layout"
469
+ ]
470
+ },
471
+ "sub-component-catalog": {
472
+ "title": "Sub-Component Catalog — 35+ Reusable Internal Components",
473
+ "description": "Complete catalog of shared sub-components in the serel theme: UI primitives, layout, product, reviews, feedback, auth, media, and icons",
474
+ "content": "## Sub-Component Catalog — 35+ Reusable Internal Components\n\nThe serel theme has 35+ sub-components in `src/sub-components/`. These are internal helpers NOT registered in `ikas.config.json`. They are imported by sections and child components via relative paths.\n\n### UI Primitives\n\n**Button** — Multi-variant button with sizes and states:\n- Variants: `primary`, `secondary`, `dangerous`\n- Sizes: `xs`, `s`, `m`\n- States: loading (with SpinnerIcon), disabled\n- Usage: `<Button variant=\"primary\" size=\"m\" loading={isSubmitting}>Submit</Button>`\n\n**Input** — Text input with label, error display, and optional icon. Handles Preact `onInput` events.\n\n**Select** — Dropdown select with label and error display.\n\n**Checkbox** — Styled checkbox with label text.\n\n**Toggle** — On/off toggle switch.\n\n**Textarea** — Multi-line text input with label and error.\n\n**Tag** — Small label/tag component for categories, filters, etc.\n\n**Badge** — Status badge for product labels (sale, new, etc.).\n\n**ColorInput** — Color swatch input for variant color selection.\n\n### Layout Components\n\n**Breadcrumb** — Category path navigation using `getProductCategoryPath()` / `getCategoryPath()`. Used in ProductDetail and CategoryList.\n\n**Pagination** — Page navigation with prev/next and page numbers. Used with the `pagination.ts` utility.\n\n**CollapsibleGroup** — Accordion-style expandable content sections. Used for product description, FAQ, filters.\n\n**PageLoader** — Full-page loading spinner for route transitions.\n\n**SkeletonField** — Placeholder loading skeleton for content that has not yet loaded.\n\n**SliderArrow** — Left/right navigation arrows for slider components. Used in HeroSlider and ProductSlider.\n\n### Product Components\n\n**ProductCard** — Product card with image, name, price, and variant info. Core building block for product grids.\n\n**CartItem** — Single cart line item with image, name, quantity controls, price, and remove button.\n\n**QuantitySelector** — Increment/decrement quantity input. Used in CartItem and ProductDetailAddToCart.\n\n**VariantBadge** — Visual badge for variant options (color swatches, size labels).\n\n**BundleMedia** — Media display for bundle products.\n\n**BundleQuantityBox** — Quantity selector for bundle product items.\n\n### Review Components\n\n**ReviewCard** — Single review display with star rating, title, comment, author, and date.\n\n**ReviewForm** — Review submission form with star rating input, title, and comment fields.\n\n**ReviewSummary** — Aggregate review statistics (average rating, rating distribution).\n\n**StarRating** — Star rating display (1-5 stars, filled/empty). Used in both ReviewCard and ReviewForm.\n\n### Feedback Components\n\n**Toast** — Portal-based notification system with stacking. Renders via `createPortal` to document.body. Supports multiple concurrent toasts with auto-dismiss. Used with the `useToast` hook and `toast.ts` utility.\n\n**ConfirmModal** — Confirmation dialog with cancel/confirm actions. Used for destructive operations (delete address, remove item).\n\n**SpinnerIcon** — Loading spinner SVG animation. Used inside Button loading state.\n\n### Auth Components\n\n**SocialLoginButton** — Social authentication buttons (Google, Facebook, etc.) with provider icons.\n\n### Media Components\n\n**ImagePreviewModal** — Full-screen image zoom/preview overlay. Used in product gallery for detailed image viewing.\n\n### Form Components\n\n**FormItem** — Form field wrapper with label, input slot, and error message display. Standardizes form layout across all forms.\n\n### Modal Component\n\n**Modal** — Generic modal overlay with backdrop, close button, scroll lock (uses `useScrollLock`), and portal rendering.\n\n### Icons Directory\n\nThe `src/sub-components/icons/` directory contains 35+ SVG icon components exported as Preact functional components. Examples: ChevronLeft, ChevronRight, Close, Search, Cart, Heart, User, Plus, Minus, Trash, etc.\n\n### CSS Import Pattern\n\nParent components import sub-component styles via CSS `@import`:\n\n```css\n/* src/components/CartPage/styles.css */\n@import \"../../sub-components/CartItem/styles.css\";\n@import \"../../sub-components/QuantitySelector/styles.css\";\n@import \"../../sub-components/Button/styles.css\";\n\n.cart-page { /* section-specific styles */ }\n```\n\nAll imported CSS gets scoped with the parent's `.cc_{componentId}` prefix.",
475
+ "tags": [
476
+ "sub-components",
477
+ "catalog",
478
+ "Button",
479
+ "Input",
480
+ "Modal",
481
+ "Toast",
482
+ "ProductCard",
483
+ "CartItem",
484
+ "Pagination",
485
+ "Breadcrumb",
486
+ "ReviewCard",
487
+ "StarRating",
488
+ "icons",
489
+ "serel"
490
+ ]
491
+ },
492
+ "config-advanced-features": {
493
+ "title": "Advanced ikas.config.json Features",
494
+ "description": "filteredComponentIds, privateVarMap, isHeader/isFooter, propGroups, custom enum types, typeId/enumTypeId for advanced config patterns",
495
+ "content": "## Advanced ikas.config.json Features\n\nBeyond basic component and prop definitions, `ikas.config.json` supports advanced features for complex theme architectures.\n\n### filteredComponentIds — Restricting Component Slots\n\n`filteredComponentIds` on a `COMPONENT_LIST` prop limits which child components can be placed in that slot. Without it, any component can be added.\n\n```json\n{\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\n \"nb34u3yu-navbar\",\n \"nb34u3yu-announcements\",\n \"nb34u3yu-cookie-bar\"\n ]\n}\n```\n\nThe IDs use the full component ID format: `{projectId}-{kebab-case-name}`. Check your component IDs with `npx ikas-component config list`.\n\n### privateVarMap — Section-to-Child Data Passing\n\nExposes a typed variable from a section to its child components. Children receive the data automatically without explicit props.\n\n```json\n{\n \"name\": \"components\",\n \"type\": \"COMPONENT_LIST\",\n \"filteredComponentIds\": [\"nb34u3yu-card-product-price\"],\n \"privateVarMap\": {\n \"product\": {\n \"id\": \"nb34u3yu-product-slider-product\",\n \"typeId\": \"@ikas/bp-storefront-models-IkasProduct\"\n }\n }\n}\n```\n\n- `product` = variable name children receive\n- `id` = unique identifier (project-section-variable format)\n- `typeId` = model type reference (`@ikas/bp-storefront-models-TypeName`)\n\nSee `get_framework_guide(\"private-var-map\")` for full details.\n\n### isHeader / isFooter — Global Sections\n\nMark a section to appear on every page:\n\n```json\n{\n \"id\": \"header\",\n \"name\": \"Header\",\n \"type\": \"section\",\n \"isHeader\": true,\n \"props\": [...]\n}\n```\n\nRules:\n- Only one component can have `isHeader: true`\n- Only one component can have `isFooter: true`\n- Only applies to `type: \"section\"` components\n- The editor automatically adds these to all pages\n\nCLI:\n```bash\nnpx ikas-component config add-component --name \"Header\" --type section --isHeader --props '[...]'\nnpx ikas-component config add-component --name \"Footer\" --type section --isFooter --props '[...]'\n```\n\n### propGroups — Organizing Props\n\nGroup props into collapsible sections in the editor sidebar:\n\n```json\n{\n \"propGroups\": [\n { \"id\": \"content\", \"name\": \"Content\" },\n {\n \"id\": \"style\", \"name\": \"Style\",\n \"children\": [\n { \"id\": \"style.colors\", \"name\": \"Colors\" }\n ]\n }\n ],\n \"props\": [\n { \"name\": \"title\", \"type\": \"TEXT\", \"groupId\": \"content\" },\n { \"name\": \"bgColor\", \"type\": \"COLOR\", \"groupId\": \"style.colors\" }\n ]\n}\n```\n\nCLI:\n```bash\nnpx ikas-component config add-prop-group --component \"MySection\" --id content --name \"Content\"\nnpx ikas-component config add-prop-group --component \"MySection\" --id colors --name \"Colors\" --parent style\nnpx ikas-component config update-prop --component \"MySection\" --prop title --group content\n```\n\nSee `get_framework_guide(\"prop-groups\")` for full details.\n\n### TYPE Props — Structured Style Types\n\nThe `TYPE` prop type uses `typeId` to reference structured style types (padding, margin, border-radius, etc.):\n\n```json\n{\n \"name\": \"spacing\",\n \"type\": \"TYPE\",\n \"typeId\": \"@ikas/bp-storefront-models-PaddingStyleType\"\n}\n```\n\nAppend `_array` for array types: `\"@ikas/bp-storefront-models-MarginStyleType_array\"`\n\nDiscover available types:\n```bash\nnpx ikas-component config list-types # all types\nnpx ikas-component config list-types --component-type section # section-allowed types only\n```\n\n### ENUM Props — Enum Style Types\n\nThe `ENUM` prop type uses `enumTypeId` for dropdown selectors:\n\n```json\n{\n \"name\": \"direction\",\n \"type\": \"ENUM\",\n \"enumTypeId\": \"@ikas/bp-storefront-models-FlexDirectionStyleType\"\n}\n```\n\nCommon enum types: FlexDirectionStyleType, JustifyContentStyleType, AlignItemsStyleType, TextAlignStyleType, ObjectFitStyleType.\n\nCLI:\n```bash\nnpx ikas-component config add-prop --component MyComp --name direction --displayName Direction --type ENUM --enumTypeId \"@ikas/bp-storefront-models-FlexDirectionStyleType\"\n```\n\n### CLI Config Commands Reference\n\n| Command | Purpose |\n|---------|--------|\n| `config add-component --name X --type section --props '[...]'` | Create component with props |\n| `config add-prop --component X --name y --type TYPE --typeId Z` | Add structured type prop |\n| `config add-prop --component X --name y --type ENUM --enumTypeId Z` | Add enum prop |\n| `config add-prop-group --component X --id g --name \"Group\"` | Create prop group |\n| `config update-prop --component X --prop y --group g` | Assign prop to group |\n| `config list-types` | List available TYPE and ENUM types |\n| `config list` | List all components and props |",
496
+ "tags": [
497
+ "config",
498
+ "filteredComponentIds",
499
+ "privateVarMap",
500
+ "isHeader",
501
+ "isFooter",
502
+ "propGroups",
503
+ "typeId",
504
+ "enumTypeId",
505
+ "TYPE",
506
+ "ENUM",
507
+ "advanced",
508
+ "CLI"
509
+ ]
510
+ },
511
+ "custom-enums": {
512
+ "title": "Custom Enum Types",
513
+ "description": "Create and manage custom enum types for ENUM props without needing an editor connection",
514
+ "content": "## Custom Enum Types\n\nCustom enums let you define project-specific dropdown options for ENUM props. Unlike built-in enums (FlexDirectionStyleType, etc.), custom enums are stored in `ikas.config.json` and work offline — no editor connection required.\n\n### Creating a Custom Enum\n\n```bash\nnpx ikas-component config add-enum --name \"Size\" --options '{\"Small\":\"sm\",\"Medium\":\"md\",\"Large\":\"lg\"}'\n```\n\nOutput:\n```json\n{\"success\":true,\"enumId\":\"aBcDeFgHiJ\",\"enumName\":\"Size\",\"enumOptions\":{\"Small\":\"sm\",\"Medium\":\"md\",\"Large\":\"lg\"}}\n```\n\nThe `enumId` is a generated 10-character ID. Use it when adding ENUM props.\n\n### Using a Custom Enum with a Prop\n\n```bash\nnpx ikas-component config add-prop --component MyComp --name size --displayName \"Size\" --type ENUM --enumTypeId aBcDeFgHiJ\n```\n\nThis generates in `types.ts`:\n```typescript\nexport type Size = \"sm\" | \"md\" | \"lg\";\nexport interface MyCompProps { size?: Size; }\n```\n\n### Listing Custom Enums\n\n```bash\nnpx ikas-component config list-enums\n```\n\n### Updating a Custom Enum\n\n```bash\nnpx ikas-component config update-enum --id aBcDeFgHiJ --name \"ProductSize\" --options '{\"XS\":\"xs\",\"S\":\"s\",\"M\":\"m\",\"L\":\"l\",\"XL\":\"xl\"}'\n```\n\nBoth `--name` and `--options` are optional — provide only what you want to change.\n\n### Removing a Custom Enum\n\n```bash\nnpx ikas-component config remove-enum --id aBcDeFgHiJ\n```\n\nThis fails if any component prop references the enum. Remove or update the prop first.\n\n### Workflow: Complete Example\n\n```bash\n# 1. Create the enum\nnpx ikas-component config add-enum --name \"AspectRatio\" --options '{\"Square\":\"1/1\",\"Landscape\":\"16/9\",\"Portrait\":\"3/4\"}'\n# Returns: {\"enumId\":\"xYz123AbCd\"}\n\n# 2. Use it in a prop\nnpx ikas-component config add-prop --component ImageGrid --name aspectRatio --displayName \"Aspect Ratio\" --type ENUM --enumTypeId xYz123AbCd\n\n# 3. The generated types.ts will have:\n# export type AspectRatio = \"1/1\" | \"16/9\" | \"3/4\";\n# export interface ImageGridProps { aspectRatio?: AspectRatio; }\n```\n\n### Storage\n\nCustom enums are stored in `ikas.config.json` under `customTypes`:\n```json\n{\n \"customTypes\": [\n {\n \"id\": \"aBcDeFgHiJ\",\n \"name\": \"Size\",\n \"type\": \"enum\",\n \"enumOptions\": {\"Small\":\"sm\",\"Medium\":\"md\",\"Large\":\"lg\"},\n \"isDynamic\": false\n }\n ]\n}\n```\n\n### Built-in vs Custom Enums\n\n- **Built-in enums** (e.g. `@ikas/bp-storefront-models-FlexDirectionStyleType`) come from the editor and require `list-types` with a connected editor.\n- **Custom enums** are defined in `ikas.config.json` and work offline. Use `config add-enum` to create them.\n\nFor automated/AI-driven component generation, custom enums are the recommended approach since they don't require an editor connection.",
515
+ "tags": [
516
+ "enum",
517
+ "custom-enum",
518
+ "add-enum",
519
+ "remove-enum",
520
+ "update-enum",
521
+ "list-enums",
522
+ "ENUM",
523
+ "enumTypeId",
524
+ "customTypes",
525
+ "offline",
526
+ "CLI"
527
+ ]
404
528
  }
405
529
  }
406
530
  }