Skip to main content

atomico

Core entry-point router, orchestrator, and reference manual for all Atomico.js tasks. Contains coding standards, API cheat sheets, architectural guidelines, and validation rules.

インストールへ移動

ソース情報

リポジトリ
atomicojs/atomico
ソースの最終更新活動
2026年7月18日 21:24
検出された SKILL.md の言語
英語
スター
1,278
フォーク
44

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
13 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
atomico
description
Core entry-point router, orchestrator, and reference manual for all Atomico.js tasks. Contains coding standards, API cheat sheets, architectural guidelines, and validation rules.
license
MIT
compatibility
Atomico >=2.0, TypeScript >=5.0
metadata
{"category":"core","priority":"highest"}
# Atomico.js — Consolidated Development & Validation Guide Unified reference for building, auditing, and validating Atomico.js web components. > **AGENT CONTRACT**: You may not respond to a code generation request > without completing the Validation Report in §7. > If any check fails, fix the code before responding — do not report > failures as acceptable output. --- ## 1. Hello World Component Every Atomico component is defined with `c()` and **must** return a `<host>` root element. ```tsx import { c, useProp, css } from "atomico"; export const MyCounter = c(({ label }) => { const [value, setValue] = useProp<number>("value"); return ( <host shadowDom> <button onclick={() => setValue(value + 1)}> {label}: {value} </button> </host> ); }, { props: { label: { type: String, value: () => "Increment" }, size: { type: String, reflect: true, value: (): "normal" | "small" => "normal" }, value: { type: Number, value: () => 0 } }, styles: css` :host { --font-size: 1em; } :host([size="small"]) { --font-size: .5em; } ` }); ``` --- ## 2. Architectural Rules 1. **Modular by Default**: Avoid monolithic files. Split complex views into a `components/` folder. 2. **Reuse First**: Audit existing workspace components before generating new ones. 3. **Prop-Driven Communication**: Pass data down via props, dispatch events up. 4. **Separate Registration**: NEVER call `customElements.define` inside the component file. Centralize all registrations in an index file. ```tsx // components/index.ts <- the ONLY place where elements are registered import { MyCounter } from "./my-counter.js"; customElements.define("my-counter", MyCounter); ``` --- ## 3. Props ### Type system ```ts // Valid constructors for the `type:` field in props type AtomicoPropType = | StringConstructor // type: String | NumberConstructor // type: Number | BooleanConstructor // type: Boolean | ArrayConstructor // type: Array -> requires value: (): T[] => [] | ObjectConstructor // type: Object -> requires value: (): T => ({...}) | MapConstructor | SetConstructor | PromiseConstructor | (new (...args: any[]) => HTMLElement); // HTMLElement or any subclass // Short form - prop without default or reflect type PropShorthand = AtomicoPropType; // Long form - prop with default or reflect interface PropConfig<T> { type: AtomicoPropType; value?: () => T; // MUST be a factory callback - never a static value reflect?: boolean; // only String | Number | Boolean } ``` ### Declaration syntax Use the simplest form that satisfies the requirement: ```tsx props: { // Shorthand: no default, no reflect label: String, // Config object: only when a default value is needed count: { type: Number, value: () => 0 }, // Reflect: only to control CSS via attribute selectors variant: { type: String, reflect: true, value: (): "primary" | "danger" => "primary" } } ``` **Forbidden:** ```tsx props: { name: { type: String }, // Verbose config with no default or reflect - use shorthand count: { type: Number, value: 0 } // Static value - must be a factory callback } // Manual type on destructured render argument: // ({ label }: { label: string }) => ... Atomico infers types automatically from props block ``` ### Arrays & Objects — strict return-type annotation Without an explicit return type, TypeScript resolves `Array` to `never[]` and `Object` to `{}`. Annotate the factory return type to guarantee correct inference in TSX: ```tsx interface Option { value: string; label: string; } interface Config { theme: "light" | "dark"; debug: boolean; } props: { // Return type annotation on the factory - inferred as Option[] in TSX options: { type: Array, value: (): Option[] => [] }, config: { type: Object, value: (): Config => ({ theme: "light", debug: false }) } } ``` ### Reflect rules `reflect: true` is only for **visual / CSS states**. Allowed types: `String`, `Number`, `Boolean`. ```tsx props: { disabled: { type: Boolean, reflect: true }, variant: { type: String, reflect: true, value: () => "primary" } }, styles: css` :host([disabled]) { opacity: 0.5; pointer-events: none; } :host([variant="danger"]) { background: red; } ` ``` Never use `reflect: true` on `Array` or `Object` — it triggers expensive DOM serialization. ### Events & Callbacks ```ts // event<Detail>() - Fire-and-Forget // Name WITHOUT "on" prefix. The JSX consumer receives it as "on<propName>" // Calling props.myEvent(detail) dispatches CustomEvent with event.detail = detail declare function event<Detail = void>(options?: { bubbles?: boolean; composed?: boolean; cancelable?: boolean; }): EventDescriptor<Detail>; // callback<Fn>() - Request-Response // Fn MUST NOT return void - if no return value is needed, use event() instead declare function callback< Fn extends (...args: any[]) => NonNullable<unknown> >(): Fn | undefined; ``` ```tsx export const ActionButton = c((props) => ( <host> <button onclick={() => props.action({ id: 42 })}>Fire</button> </host> ), { props: { // No "on" prefix - Atomico maps it as "onaction" automatically in JSX action: event<{ id: number }>({ bubbles: true, composed: true }) } }); ``` > **Shadow DOM boundary rule**: Native events like `change` and `submit` have `composed: false` > and **cannot cross the Shadow DOM boundary**. Always declare a custom `event()` with > `{ bubbles: true, composed: true }` and dispatch it explicitly. ```tsx export const UiSelect = c(({ change, options }) => ( <host shadowDom> <select onchange={(e) => change(e.currentTarget.value as string)}> {options.map(o => <option value={o.value}>{o.label}</option>)} </select> </host> ), { props: { options: { type: Array, value: (): { value: string; label: string }[] => [] }, change: event<string>({ bubbles: true, composed: true }) } }); ``` ```tsx export const TextEditor = c(({ content, save }) => ( <host shadowDom> <button onclick={async () => { if (save) { const ok = await save(content); if (ok) console.log("Saved!"); } }}> Save </button> </host> ), { props: { content: { type: String, value: () => "" }, // callback MUST return a value - if no return is needed, use event() instead save: callback<(content: string) => Promise<boolean>>() } }); ``` **Forbidden:** ```tsx // "on" prefix in event or callback name props: { onChange: event() } // Atomico treats "on*" props as native event subscriptions // callback returning void - use event() instead props: { save: callback<() => void>() } // Re-dispatching native events that already bubble const dispatchInput = useEvent("input"); // "input" already bubbles causes double-fire ``` --- ## 4. State Management ```ts // Signature reference declare function useProp<T>(name: string): [T, (val: T) => void]; declare function useState<T>(init: T | (() => T)): [T, (val: T) => void]; declare function useObjectState<T extends object>( init: T ): [T, (partial: Partial<T>) => void]; ``` ### Decision tree ``` Does the state need to be read from outside (parent / CSS)? +- YES -> declare it in props | +- Does the child also write to it? -> useProp<T>() | +- Read-only? -> direct destructuring ({ myProp }) +- NO -> private state +- Single value (boolean, string)? -> useState +- Two or more related values? -> useObjectState<T> ``` ### Correct patterns ```tsx // Read-only prop - direct destructuring, full auto-inference export const Badge = c(({ label, variant }) => ( <host shadowDom><span class={variant}>{label}</span></host> ), { props: { label: String, variant: { type: String, reflect: true, value: () => "info" } } }); // Internally mutable prop - useProp with explicit generic export const Counter = c(({ label }) => { const [count, setCount] = useProp<number>("count"); return <host><button onclick={() => setCount(count + 1)}>{label}: {count}</button></host>; }, { props: { label: String, count: { type: Number, value: () => 0 } } }); // Grouped private state - useObjectState export const SearchBar = c(() => { const [state, setState] = useObjectState({ query: "", filter: "all" }); return ( <host shadowDom> <input value={state.query} oninput={(e) => setState({ query: e.currentTarget.value as string })} /> </host> ); }); ``` **Forbidden:** ```tsx // useProp for read-only - use direct destructuring instead const [label] = useProp("label"); // Multiple useState for related values - use useObjectState const [query, setQuery] = useState(""); const [filter, setFilter] = useState("all"); // useMemo on small lists - direct computation is cheaper const filtered = useMemo(() => items.filter(isActive), [items]); // Correct: const filtered = items.filter(isActive); const done = items.length - filtered.length; // math deduction, no second iteration ``` --- ## 5. JSX ### Handlers — Always Inline The TSX compiler automatically infers the event target type when handlers are **inline**. ```ts // With inline handler, Atomico JSX infers automatically: // oninput -> e: { currentTarget: HTMLInputElement } // onchange -> e: { currentTarget: HTMLSelectElement } // e.currentTarget.value -> string | number requires `as string` when passing to setState ``` ```tsx // Inline: e.currentTarget typed as HTMLInputElement - zero manual castings <input oninput={(e) => setState({ query: e.currentTarget.value as string })} /> // Extracted: forces `any`, breaks auto-inference const handleInput = (e: any) => setState({ query: e.currentTarget.value }); <input oninput={handleInput} /> ``` > **Rule**: Single-use handlers go inline. Extract only if the **exact same function** is > shared across multiple elements. ### `useRef` — no null initialization ```ts declare function useRef<T>(): { current: T | undefined }; ``` ```tsx // Parameterless - typed as T | undefined, no null needed const inputRef = useRef<HTMLInputElement>(); if (inputRef.current) inputRef.current.focus(); // guard is mandatory // Reference to another Atomico constructor const btnRef = useRef<typeof MyButton>();
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る