---
name: ibgib-create-component
description: Scaffolds a new reusable ibgib UI component. Generates the component logic (Meta and Instance classes), HTML template, and CSS stylesheet.
---

# ibgib-create-component

This skill scaffolds a new UI component for an ibgib application. Components are implemented as Web Components (Custom Elements with Shadow DOM) using the `@ibgib/web-gib` framework, which provides deep integration with ibgib timelines, content addressing, and real-time reactive updates.

For more documentation, refer to:
- [web-gib Component README](../../../libs/web-gib/src/ui/component/README.md)
- [web-gib Component Architecture](../../../libs/web-gib/src/ui/component/ARCHITECTURE.md)
- [Space-Gib Paneled Component Architecture](../../../docs/design/SPACE_GIB_PANELED_COMPONENT_ARCHITECTURE.md)

## Goal
To create a standard, reactive UI component that can be registered with the `ibgib-component-service` and dynamically injected into an app shell container.

## Parameters
Wait for the user to provide or confirm these tokens:
- `{{COMPONENT_NAME}}`: e.g. `cosmos-explorer` (kebab-case directory name)
- `{{COMPONENT_TAG_NAME}}`: e.g. `space-gib-cosmos-explorer` (must be kebab-case, custom element name containing at least one hyphen)
- `{{COMPONENT_CLASS_PREFIX}}`: e.g. `CosmosExplorer` (PascalCase class prefix)
- `{{APP_DIR_NAME}}`: e.g. `space-gib`
- `{{APP_CLASS_PREFIX}}`: e.g. `SpaceGib` (for helper/shell imports)
- `{{BASE_CLASS}}`: `IbGibDynamicComponentInstanceBase` (general display/interaction) or `IbGibFormInstanceBase` (forms, validation, loading states)

## Output Files
The skill will generate:
1. `src/components/{{COMPONENT_NAME}}/IMPLEMENTATION.md` (Design spec, requirements, and checklist)
2. `src/components/{{COMPONENT_NAME}}/{{COMPONENT_NAME}}.mts`
3. `src/components/{{COMPONENT_NAME}}/{{COMPONENT_NAME}}.html`
4. `src/components/{{COMPONENT_NAME}}/{{COMPONENT_NAME}}.css`
5. `src/components/{{COMPONENT_NAME}}/index.mts` (barrel exports)

## Architectural Core Rules & Pitfalls to Avoid

### 1. `ROOT_ADDR` is the Null Object Pattern, NOT a Root Directory
- `ROOT_ADDR` is literally `"ib^gib"`.
- Use it **only** as a default placeholder for uninitialized components or pure UI widgets that require no persistent backing model.
- **Never** pass `ROOT_ADDR` when you intend to reference a repository root, project folder, or topic. Always resolve an authentic `B2tFSItemIbGib_V1` or `CosmosIbGib_V1`.

### 2. Authentic `IbGibAddr` vs. Route Paths
- An `IbGibAddr` is strictly `ib^gib`.
- **Never** pass a URL or route path (e.g. `topics/code-1/dev^tip` or `topic dev^tip`) into `activateIbGib({ ibGibAddr })` or `getIbAndGib()`. Doing so triggers delimiter warnings and breaks timeline lookups.
- Always resolve living models using route helpers (e.g. `getMetatextItemFromRoute()`) and pass `activateIbGib({ ibGib: item })`.

### 3. Dynamic Injection vs. Static HTML / `display: none`
- Dynamic components are **never** declared directly as custom element tags in static HTML (`<space-gib-cosmos-explorer>`).
- Dynamic components are **never** toggled using static `<div>` containers with CSS `style="display: none"`. Doing so keeps event listeners and proxy subscriptions active, causing memory leaks and invisible rendering.
- Always declare a generic host container in your layout (e.g. `<div id="left-panel-content"></div>`), then instantiate and mount dynamically via `componentSvc.inject()`.

### 4. Shadow DOM Encapsulation & Custom Events
- All internal elements must be queried within `this.shadowRoot` (e.g. `this.shadowRoot.getElementById('btn-action')`).
- Never query outer shell elements directly via `document.getElementById(...)`.
- To notify parent components or the shell of user actions, dispatch standard bubbling, composed Custom Events:
  ```typescript
  this.dispatchEvent(new CustomEvent('ibgib-item-selected', {
      detail: { item: this.ibGib, addr: this.ibGibAddr },
      bubbles: true,
      composed: true,
  }));
  ```

---

## Component Lifecycle Reference

- **`initialize(opts)`**: Called by the Meta factory before DOM connection. Sets `ibGibAddr`, `meta`, `html`, and `css`, and attaches the open Shadow DOM root.
- **`connectedCallback()`**: Web component attached to the DOM. Base class appends template and styles to Shadow DOM, then invokes `created()`.
- **`created()`**: Abstract hook called after Shadow DOM is ready. This is where you:
  1. Query elements within `this.shadowRoot`.
  2. Bind event listeners.
  3. Load backing model via `if (this.ibGibAddr && !this.ibGib) { await this.loadIbGib(); }`.
  4. Call `await this.renderUI();`.
- **`handleContextUpdated()`**: Called automatically by `LiveProxyIbGib` when the observed timeline evolves. In your override:
  ```typescript
  override async handleContextUpdated(): Promise<void> {
      await super.handleContextUpdated();
      await this.renderUI();
  }
  ```
- **`renderUI()`**: Updates Shadow DOM elements based on `this.ibGib`. The base class automatically calculates deterministic color variables (`--ibgib-color`, `--tjp-color`) based on the item's cryptographic hash.
- **`disconnected()`**: Called when the component is unmounted from the DOM via `componentSvc.inject()`. Unbind any global window listeners or non-proxy subscriptions here.

---

## Form Handling Reference (`IbGibFormInstanceBase`)

When building forms with input validation and loading states, extend `IbGibFormInstanceBase`:
- **`validateForm(formSelector?: string): boolean`**: Checks HTML5 Constraint Validation.
- **`validateInputPattern(opts)`**: Validates an input against a JS `RegExp`, adding/removing the `.invalid` CSS class and browser validation tooltips.
- **`setLoading(loading: boolean, submitBtnSelector?: string)`**: Toggles the `disabled` state and `data-loading` attribute on the submit button.
- **`setStatus(msg: string, type: 'info' | 'success' | 'error')`**: Shows/hides status banners in the component template.
- **Input Clearing Pattern**: Always listen to `input` events on validated fields to remove the `.invalid` class as the user types.

---

## Mounting Example

```typescript
import { getComponentSvc } from "@ibgib/web-gib/dist/ui/component/ibgib-component-service.mjs";

const componentSvc = await getComponentSvc();
const component = await componentSvc.getComponentInstance({
    path: '{{COMPONENT_TAG_NAME}}',
    ibGibAddr: targetAddr,
    useRegExpPrefilter: true,
});

const container = document.getElementById('my-container');
if (container && component) {
    await componentSvc.inject({
        parentEl: container,
        componentToInject: component,
    });
}
```
