# Design docs These describe how `leaflet-components` is built and why — the load-bearing decisions, in their current form. They are not a usage guide (that's the top-level [`README.md`](../README.md)) and not a working cheat-sheet (that's [`CLAUDE.md`](../CLAUDE.md)). | Doc | Covers | | ------------------------------------------------------------ | --------------------------------------------------------------------------------------- | | [01 — Architecture](./01-architecture.md) | Element-per-Leaflet-object, the `WithProps` mixin, the lifecycle it owns | | [02 — Props & attributes](./02-props-and-attributes.md) | The `PropDef` model, the codec factories, two-way attribute↔object sync | | [03 — Component tree & registration](./03-component-tree.md) | The `leaflet-register` bubbling protocol, `attach` modes, the other announcement events | | [04 — Events](./04-events.md) | Re-emitting Leaflet events as `leaflet:`, and how they're typed | | [05 — Per-component special cases](./05-special-cases.md) | Where a component does something the mixin can't express generically | | [06 — Load order](./06-load-order.md) | Why the export order in `src/index.ts` is load-bearing | | [07 — Tooling & build](./07-tooling-and-build.md) | TypeScript 7, oxlint, oxfmt, Vitest, the no-bundle build, dual publish | ## The one-paragraph version Each `leaflet-*` custom element wraps exactly one Leaflet object. A mixin (`WithProps`) generates the element class from a table of property descriptors: it derives `observedAttributes`, builds the Leaflet options object from the current attributes, calls the component's `createLeafletObject()`, keeps attributes and the live object in sync in both directions, and re-fires every Leaflet event on the element. Components join each other through a DOM-event registration protocol that bubbles up to `` at the root — no component ever reads another component's state or queries the DOM for its relatives. The build is `tsc` with no bundler; Leaflet is always external.