klods-js 1.0.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  KlodsNode: () => KlodsNode,
24
24
  alert: () => alert,
25
25
  badge: () => badge,
26
+ box: () => box,
26
27
  builder: () => builder,
27
28
  button: () => button,
28
29
  card: () => card,
@@ -32,11 +33,13 @@ __export(index_exports, {
32
33
  center: () => center,
33
34
  classNames: () => classNames,
34
35
  cluster: () => cluster,
36
+ codeBlock: () => codeBlock,
35
37
  content: () => content,
36
38
  el: () => el,
37
39
  footer: () => footer,
38
40
  grid: () => grid,
39
41
  header: () => header,
42
+ inlineCode: () => inlineCode,
40
43
  lead: () => lead,
41
44
  mergeClasses: () => mergeClasses,
42
45
  muted: () => muted,
@@ -50,7 +53,13 @@ __export(index_exports, {
50
53
  sidebar: () => sidebar,
51
54
  spread: () => spread,
52
55
  stack: () => stack,
53
- text: () => text
56
+ table: () => table,
57
+ tbody: () => tbody,
58
+ td: () => td,
59
+ text: () => text,
60
+ th: () => th,
61
+ thead: () => thead,
62
+ tr: () => tr
54
63
  });
55
64
  module.exports = __toCommonJS(index_exports);
56
65
 
@@ -276,6 +285,26 @@ function alert(props, children) {
276
285
  var prose = builder({ tag: "div", base: "klods-prose" });
277
286
  var muted = builder({ tag: "span", base: "klods-muted" });
278
287
  var lead = builder({ tag: "p", base: "klods-lead" });
288
+ var table = builder({
289
+ tag: "table",
290
+ base: "klods-table",
291
+ modifiers: {
292
+ striped: "klods-table--striped",
293
+ dense: "klods-table--dense"
294
+ }
295
+ });
296
+ var thead = (attrs, children) => el("thead", attrs ?? {}, children);
297
+ var tbody = (attrs, children) => el("tbody", attrs ?? {}, children);
298
+ var tr = (attrs, children) => el("tr", attrs ?? {}, children);
299
+ var th = (attrs, children) => el("th", attrs ?? {}, children);
300
+ var td = (attrs, children) => el("td", attrs ?? {}, children);
301
+ function codeBlock(attrs, content2) {
302
+ return el("pre", attrs ?? {}, el("code", {}, content2));
303
+ }
304
+ function inlineCode(attrs, content2) {
305
+ return el("code", attrs ?? {}, content2);
306
+ }
307
+ var box = builder({ tag: "div", base: "klods-box" });
279
308
 
280
309
  // src/layout.ts
281
310
  var page = builder({
@@ -283,7 +312,8 @@ var page = builder({
283
312
  base: "klods-page",
284
313
  modifiers: {
285
314
  sidebar: "klods-page--with-sidebar",
286
- sidebarRight: "klods-page--sidebar-right"
315
+ sidebarRight: "klods-page--sidebar-right",
316
+ stickyHeader: "klods-page--sticky-header"
287
317
  }
288
318
  });
289
319
  var header = builder({ tag: "header", base: "klods-header" });
@@ -329,6 +359,7 @@ function text(value) {
329
359
  KlodsNode,
330
360
  alert,
331
361
  badge,
362
+ box,
332
363
  builder,
333
364
  button,
334
365
  card,
@@ -338,11 +369,13 @@ function text(value) {
338
369
  center,
339
370
  classNames,
340
371
  cluster,
372
+ codeBlock,
341
373
  content,
342
374
  el,
343
375
  footer,
344
376
  grid,
345
377
  header,
378
+ inlineCode,
346
379
  lead,
347
380
  mergeClasses,
348
381
  muted,
@@ -356,6 +389,12 @@ function text(value) {
356
389
  sidebar,
357
390
  spread,
358
391
  stack,
359
- text
392
+ table,
393
+ tbody,
394
+ td,
395
+ text,
396
+ th,
397
+ thead,
398
+ tr
360
399
  });
361
400
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core.ts","../src/components.ts","../src/layout.ts"],"sourcesContent":["// Public API surface for the `klods` package.\n\nexport * from \"./components.js\";\nexport * from \"./core.js\";\nexport * from \"./layout.js\";\n","// Core — a tiny VDOM-ish node with two faces:\n// - .render(target?) → HTMLElement (uses real DOM)\n// - .toString() → HTML string (works in Node / Rails / SSR)\n//\n// Both are produced from the same KlodsNode tree, so the docs site can show the\n// TS source, the rendered HTML and the live preview from one source of truth.\n\nexport type KlodsChild = string | number | bigint | boolean | null | undefined | KlodsNode | Node | KlodsChild[];\n\nexport type KlodsAttrs = {\n class?: string | string[] | Record<string, boolean | undefined> | undefined;\n id?: string | undefined;\n style?: string | Partial<CSSStyleDeclaration> | undefined;\n [key: `data-${string}`]: string | number | boolean | undefined;\n [key: `aria-${string}`]: string | number | boolean | undefined;\n // Allow any other HTML attribute or DOM event handler (onClick, onInput, …).\n [key: string]: unknown;\n};\n\nconst VOID_TAGS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n \"track\",\n \"wbr\",\n]);\n\nconst RAW = Symbol(\"klods.raw\");\n\ntype RawHtml = { [RAW]: true; html: string };\n\n/** Mark a string as already-escaped HTML; pass it as a child to inject as-is. */\nexport function raw(html: string): RawHtml {\n return { [RAW]: true, html };\n}\n\nfunction isRaw(value: unknown): value is RawHtml {\n return typeof value === \"object\" && value !== null && (value as { [RAW]?: unknown })[RAW] === true;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction escapeAttr(str: string): string {\n return str.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\");\n}\n\n/** Normalise a `class` value (string | array | record) into a clean string. */\nexport function classNames(input: KlodsAttrs[\"class\"]): string {\n if (!input) return \"\";\n if (typeof input === \"string\") return input.trim();\n if (Array.isArray(input)) return input.filter(Boolean).join(\" \").trim();\n return Object.entries(input)\n .filter(([, v]) => Boolean(v))\n .map(([k]) => k)\n .join(\" \")\n .trim();\n}\n\n/** Merge two class values (used internally to combine builder defaults + user-supplied). */\nexport function mergeClasses(...inputs: Array<KlodsAttrs[\"class\"]>): string {\n return inputs\n .map((c) => classNames(c))\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction styleToString(style: string | Partial<CSSStyleDeclaration>): string {\n if (typeof style === \"string\") return style;\n return Object.entries(style)\n .filter(([, v]) => v !== undefined && v !== null && v !== \"\")\n .map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}:${String(v)}`)\n .join(\";\");\n}\n\nfunction flattenChildren(children: KlodsChild | KlodsChild[]): Array<Exclude<KlodsChild, KlodsChild[]>> {\n const out: Array<Exclude<KlodsChild, KlodsChild[]>> = [];\n const stack: KlodsChild[] = Array.isArray(children) ? [...children] : [children];\n while (stack.length) {\n const next = stack.shift();\n if (Array.isArray(next)) stack.unshift(...next);\n else if (next !== null && next !== undefined && next !== false && next !== true) out.push(next);\n }\n return out;\n}\n\nexport class KlodsNode {\n readonly tag: string;\n readonly attrs: KlodsAttrs;\n readonly children: KlodsChild[];\n\n constructor(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []) {\n this.tag = tag;\n this.attrs = attrs;\n this.children = Array.isArray(children) ? children : [children];\n }\n\n /** Render to a real DOM element. If `target` is given, append to it. */\n render(target?: Element | null): HTMLElement {\n const el = document.createElement(this.tag);\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) el.setAttribute(\"class\", cls);\n continue;\n }\n if (name === \"style\") {\n el.setAttribute(\"style\", styleToString(value as string | Partial<CSSStyleDeclaration>));\n continue;\n }\n if (name.startsWith(\"on\") && typeof value === \"function\") {\n el.addEventListener(name.slice(2).toLowerCase(), value as EventListener);\n continue;\n }\n if (value === true) {\n el.setAttribute(name, \"\");\n continue;\n }\n el.setAttribute(name, String(value));\n }\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) el.appendChild(child.render());\n else if (typeof child === \"object\" && child !== null && \"nodeType\" in child) {\n el.appendChild(child as Node);\n } else if (isRaw(child)) {\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = child.html;\n el.appendChild(tpl.content);\n } else {\n el.appendChild(document.createTextNode(String(child)));\n }\n }\n if (target) target.appendChild(el);\n return el;\n }\n\n /** Render to a string of HTML. */\n toString(): string {\n const parts: string[] = [`<${this.tag}`];\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name.startsWith(\"on\") && typeof value === \"function\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) parts.push(` class=\"${escapeAttr(cls)}\"`);\n continue;\n }\n if (name === \"style\") {\n parts.push(` style=\"${escapeAttr(styleToString(value as string | Partial<CSSStyleDeclaration>))}\"`);\n continue;\n }\n if (value === true) {\n parts.push(` ${name}`);\n continue;\n }\n parts.push(` ${name}=\"${escapeAttr(String(value))}\"`);\n }\n if (VOID_TAGS.has(this.tag)) {\n parts.push(\" />\");\n return parts.join(\"\");\n }\n parts.push(\">\");\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) parts.push(child.toString());\n else if (isRaw(child)) parts.push(child.html);\n else if (typeof child === \"object\" && child !== null && \"outerHTML\" in child) {\n parts.push((child as Element).outerHTML);\n } else {\n parts.push(escapeHtml(String(child)));\n }\n }\n parts.push(`</${this.tag}>`);\n return parts.join(\"\");\n }\n}\n\n/**\n * Generic element builder. Most consumers use the named builders (page, header, …)\n * rather than calling `el` directly, but it's exported as an escape hatch.\n */\nexport function el(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []): KlodsNode {\n return new KlodsNode(tag, attrs, children);\n}\n\n/**\n * Factory that produces a typed builder for a tag with a base class. Modifier\n * props are converted into `--modifier` BEM classes and stripped from the output\n * attributes; everything else passes through untouched, so consumers can attach\n * arbitrary `id`, `data-*`, `aria-*`, event handlers, `style`, etc.\n */\nexport function builder<P extends Record<string, unknown> = Record<string, never>>(options: {\n tag: string;\n base: string;\n /** Map of prop name → class (or function returning a class) when the prop is truthy. */\n modifiers?: { [K in keyof P]?: string | ((value: P[K]) => string | undefined) };\n}): (props?: (P & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]) => KlodsNode {\n const { tag, base, modifiers = {} } = options;\n const modifierMap = modifiers as Record<string, string | ((value: unknown) => string | undefined) | undefined>;\n return (props, children) => {\n const userProps = (props ?? {}) as P & KlodsAttrs;\n const modClasses: string[] = [];\n const passthrough: KlodsAttrs = {};\n for (const [key, value] of Object.entries(userProps)) {\n const m = modifierMap[key];\n if (m !== undefined) {\n if (typeof m === \"function\") {\n const c = m(value);\n if (c) modClasses.push(c);\n } else if (value) {\n modClasses.push(m);\n }\n } else {\n passthrough[key] = value;\n }\n }\n const finalClass = mergeClasses(base, ...modClasses, userProps.class);\n const resolvedChildren =\n children !== undefined ? children : ((userProps.children as KlodsChild | KlodsChild[] | undefined) ?? []);\n delete passthrough.children;\n return new KlodsNode(tag, { ...passthrough, class: finalClass || undefined }, resolvedChildren);\n };\n}\n","// First wave of components: nav, card, button, badge, alert, prose helpers.\n// All match the BEM classes shipped by klods-css.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, el, KlodsNode } from \"./core.js\";\n\n// ── Nav ──────────────────────────────────────────────────────────────────\nexport const nav = builder({ tag: \"nav\", base: \"klods-nav\" });\nexport const navList = builder({ tag: \"ul\", base: \"klods-nav__list\" });\n\nexport type NavLinkProps = {\n href?: string;\n active?: boolean;\n};\nconst navLinkBuilder = builder<NavLinkProps>({\n tag: \"a\",\n base: \"klods-nav__link\",\n modifiers: { active: \"klods-nav__link--active\" },\n});\nexport function navLink(props?: (NavLinkProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Wrap each link in <li> so it's idiomatic inside <ul class=\"klods-nav__list\">.\n return el(\"li\", {}, [navLinkBuilder(props ?? null, children)]);\n}\n\n// ── Card ─────────────────────────────────────────────────────────────────\nexport type CardProps = {\n elevated?: boolean;\n};\nexport const card = builder<CardProps>({\n tag: \"div\",\n base: \"klods-card\",\n modifiers: { elevated: \"klods-card--elevated\" },\n});\nexport const cardTitle = builder({ tag: \"h3\", base: \"klods-card__title\" });\nexport const cardBody = builder({ tag: \"div\", base: \"klods-card__body\" });\nexport const cardFooter = builder({ tag: \"div\", base: \"klods-card__footer\" });\n\n// ── Button ───────────────────────────────────────────────────────────────\nexport type ButtonProps = {\n variant?: \"default\" | \"primary\" | \"danger\" | \"ghost\";\n type?: \"button\" | \"submit\" | \"reset\";\n};\nconst buttonBase = builder<ButtonProps>({\n tag: \"button\",\n base: \"klods-button\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-button--${v}` : undefined),\n },\n});\nexport function button(props?: (ButtonProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Default `type=\"button\"` so it never accidentally submits a form.\n const merged = { type: \"button\", ...(props ?? {}) } as ButtonProps & KlodsAttrs;\n return buttonBase(merged, children);\n}\n\n// ── Badge ────────────────────────────────────────────────────────────────\nexport type BadgeProps = {\n variant?: \"default\" | \"accent\" | \"success\" | \"danger\";\n};\nexport const badge = builder<BadgeProps>({\n tag: \"span\",\n base: \"klods-badge\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-badge--${v}` : undefined),\n },\n});\n\n// ── Alert ────────────────────────────────────────────────────────────────\nexport type AlertProps = {\n variant?: \"default\" | \"info\" | \"success\" | \"warning\" | \"danger\";\n};\nconst alertBase = builder<AlertProps>({\n tag: \"div\",\n base: \"klods-alert\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-alert--${v}` : undefined),\n },\n});\nexport function alert(props?: (AlertProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // role=alert by default for assistive tech, overridable.\n const merged = { role: \"alert\", ...(props ?? {}) } as AlertProps & KlodsAttrs;\n return alertBase(merged, children);\n}\n\n// ── Prose helpers ────────────────────────────────────────────────────────\nexport const prose = builder({ tag: \"div\", base: \"klods-prose\" });\nexport const muted = builder({ tag: \"span\", base: \"klods-muted\" });\nexport const lead = builder({ tag: \"p\", base: \"klods-lead\" });\n","// Layout builders — the four corners and the \"I-always-forget\" utilities.\n// Each builder is a thin wrapper around `builder()` from core.ts.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, KlodsNode } from \"./core.js\";\n\n// ── Page ─────────────────────────────────────────────────────────────────\nexport type PageProps = {\n /** Render with a sidebar column. */\n sidebar?: boolean;\n /** Place the sidebar on the right (only meaningful with `sidebar: true`). */\n sidebarRight?: boolean;\n};\n\nexport const page = builder<PageProps>({\n tag: \"div\",\n base: \"klods-page\",\n modifiers: {\n sidebar: \"klods-page--with-sidebar\",\n sidebarRight: \"klods-page--sidebar-right\",\n },\n});\n\n// ── Page slots ───────────────────────────────────────────────────────────\nexport const header = builder({ tag: \"header\", base: \"klods-header\" });\nexport const sidebar = builder({ tag: \"aside\", base: \"klods-sidebar\" });\n\nexport type ContentProps = {\n /** Cap content width to --klods-content-max and centre it. */\n narrow?: boolean;\n};\nexport const content = builder<ContentProps>({\n tag: \"main\",\n base: \"klods-content\",\n modifiers: { narrow: \"klods-content--narrow\" },\n});\n\nexport const footer = builder({ tag: \"footer\", base: \"klods-footer\" });\n\n// ── Layout utilities ─────────────────────────────────────────────────────\ntype GapProp = { gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 };\n\nconst gapModifier = (prefix: string) => (v: number | undefined) =>\n v === undefined ? undefined : `${prefix}--gap-${v}`;\n\nexport const stack = builder<GapProp>({\n tag: \"div\",\n base: \"klods-stack\",\n modifiers: { gap: gapModifier(\"klods-stack\") },\n});\n\nexport const cluster = builder<GapProp>({\n tag: \"div\",\n base: \"klods-cluster\",\n modifiers: { gap: gapModifier(\"klods-cluster\") },\n});\n\nexport const row = builder<GapProp>({\n tag: \"div\",\n base: \"klods-row\",\n modifiers: { gap: gapModifier(\"klods-row\") },\n});\n\nexport type GridProps = GapProp & {\n cols?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Auto-fit responsive columns; pair with `--klods-grid-min` if you want a custom minimum. */\n fit?: boolean;\n};\nexport const grid = builder<GridProps>({\n tag: \"div\",\n base: \"klods-grid\",\n modifiers: {\n gap: gapModifier(\"klods-grid\"),\n cols: (v) => (v === undefined ? undefined : `klods-grid--cols-${v}`),\n fit: \"klods-grid--fit\",\n },\n});\n\nexport const center = builder({ tag: \"div\", base: \"klods-center\" });\nexport const spread = builder({ tag: \"div\", base: \"klods-spread\" });\n\n// ── Convenience: empty fragment-ish wrapper for quick text + nodes ──────\nexport function text(value: string | number): KlodsNode {\n // Wrap loose text in a span so it composes anywhere a KlodsNode is expected.\n return new KlodsNode(\"span\", {}, [String(value)]);\n}\n\n// Re-export attribute / child types so consumers can extend a builder neatly.\nexport type { KlodsAttrs, KlodsChild };\n"],"mappings":"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","names":["stack","el"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core.ts","../src/components.ts","../src/layout.ts"],"sourcesContent":["// Public API surface for the `klods` package.\n\nexport * from \"./components.js\";\nexport * from \"./core.js\";\nexport * from \"./layout.js\";\n","// Core — a tiny VDOM-ish node with two faces:\n// - .render(target?) → HTMLElement (uses real DOM)\n// - .toString() → HTML string (works in Node / Rails / SSR)\n//\n// Both are produced from the same KlodsNode tree, so the docs site can show the\n// TS source, the rendered HTML and the live preview from one source of truth.\n\nexport type KlodsChild = string | number | bigint | boolean | null | undefined | KlodsNode | Node | KlodsChild[];\n\nexport type KlodsAttrs = {\n class?: string | string[] | Record<string, boolean | undefined> | undefined;\n id?: string | undefined;\n style?: string | Partial<CSSStyleDeclaration> | undefined;\n [key: `data-${string}`]: string | number | boolean | undefined;\n [key: `aria-${string}`]: string | number | boolean | undefined;\n // Allow any other HTML attribute or DOM event handler (onClick, onInput, …).\n [key: string]: unknown;\n};\n\nconst VOID_TAGS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n \"track\",\n \"wbr\",\n]);\n\nconst RAW = Symbol(\"klods.raw\");\n\ntype RawHtml = { [RAW]: true; html: string };\n\n/** Mark a string as already-escaped HTML; pass it as a child to inject as-is. */\nexport function raw(html: string): RawHtml {\n return { [RAW]: true, html };\n}\n\nfunction isRaw(value: unknown): value is RawHtml {\n return typeof value === \"object\" && value !== null && (value as { [RAW]?: unknown })[RAW] === true;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction escapeAttr(str: string): string {\n return str.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\");\n}\n\n/** Normalise a `class` value (string | array | record) into a clean string. */\nexport function classNames(input: KlodsAttrs[\"class\"]): string {\n if (!input) return \"\";\n if (typeof input === \"string\") return input.trim();\n if (Array.isArray(input)) return input.filter(Boolean).join(\" \").trim();\n return Object.entries(input)\n .filter(([, v]) => Boolean(v))\n .map(([k]) => k)\n .join(\" \")\n .trim();\n}\n\n/** Merge two class values (used internally to combine builder defaults + user-supplied). */\nexport function mergeClasses(...inputs: Array<KlodsAttrs[\"class\"]>): string {\n return inputs\n .map((c) => classNames(c))\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction styleToString(style: string | Partial<CSSStyleDeclaration>): string {\n if (typeof style === \"string\") return style;\n return Object.entries(style)\n .filter(([, v]) => v !== undefined && v !== null && v !== \"\")\n .map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}:${String(v)}`)\n .join(\";\");\n}\n\nfunction flattenChildren(children: KlodsChild | KlodsChild[]): Array<Exclude<KlodsChild, KlodsChild[]>> {\n const out: Array<Exclude<KlodsChild, KlodsChild[]>> = [];\n const stack: KlodsChild[] = Array.isArray(children) ? [...children] : [children];\n while (stack.length) {\n const next = stack.shift();\n if (Array.isArray(next)) stack.unshift(...next);\n else if (next !== null && next !== undefined && next !== false && next !== true) out.push(next);\n }\n return out;\n}\n\nexport class KlodsNode {\n readonly tag: string;\n readonly attrs: KlodsAttrs;\n readonly children: KlodsChild[];\n\n constructor(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []) {\n this.tag = tag;\n this.attrs = attrs;\n this.children = Array.isArray(children) ? children : [children];\n }\n\n /** Render to a real DOM element. If `target` is given, append to it. */\n render(target?: Element | null): HTMLElement {\n const el = document.createElement(this.tag);\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) el.setAttribute(\"class\", cls);\n continue;\n }\n if (name === \"style\") {\n el.setAttribute(\"style\", styleToString(value as string | Partial<CSSStyleDeclaration>));\n continue;\n }\n if (name.startsWith(\"on\") && typeof value === \"function\") {\n el.addEventListener(name.slice(2).toLowerCase(), value as EventListener);\n continue;\n }\n if (value === true) {\n el.setAttribute(name, \"\");\n continue;\n }\n el.setAttribute(name, String(value));\n }\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) el.appendChild(child.render());\n else if (typeof child === \"object\" && child !== null && \"nodeType\" in child) {\n el.appendChild(child as Node);\n } else if (isRaw(child)) {\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = child.html;\n el.appendChild(tpl.content);\n } else {\n el.appendChild(document.createTextNode(String(child)));\n }\n }\n if (target) target.appendChild(el);\n return el;\n }\n\n /** Render to a string of HTML. */\n toString(): string {\n const parts: string[] = [`<${this.tag}`];\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name.startsWith(\"on\") && typeof value === \"function\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) parts.push(` class=\"${escapeAttr(cls)}\"`);\n continue;\n }\n if (name === \"style\") {\n parts.push(` style=\"${escapeAttr(styleToString(value as string | Partial<CSSStyleDeclaration>))}\"`);\n continue;\n }\n if (value === true) {\n parts.push(` ${name}`);\n continue;\n }\n parts.push(` ${name}=\"${escapeAttr(String(value))}\"`);\n }\n if (VOID_TAGS.has(this.tag)) {\n parts.push(\" />\");\n return parts.join(\"\");\n }\n parts.push(\">\");\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) parts.push(child.toString());\n else if (isRaw(child)) parts.push(child.html);\n else if (typeof child === \"object\" && child !== null && \"outerHTML\" in child) {\n parts.push((child as Element).outerHTML);\n } else {\n parts.push(escapeHtml(String(child)));\n }\n }\n parts.push(`</${this.tag}>`);\n return parts.join(\"\");\n }\n}\n\n/**\n * Generic element builder. Most consumers use the named builders (page, header, …)\n * rather than calling `el` directly, but it's exported as an escape hatch.\n */\nexport function el(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []): KlodsNode {\n return new KlodsNode(tag, attrs, children);\n}\n\n/**\n * Factory that produces a typed builder for a tag with a base class. Modifier\n * props are converted into `--modifier` BEM classes and stripped from the output\n * attributes; everything else passes through untouched, so consumers can attach\n * arbitrary `id`, `data-*`, `aria-*`, event handlers, `style`, etc.\n */\nexport function builder<P extends Record<string, unknown> = Record<never, never>>(options: {\n tag: string;\n base: string;\n /** Map of prop name → class (or function returning a class) when the prop is truthy. */\n modifiers?: { [K in keyof P]?: string | ((value: P[K]) => string | undefined) };\n}): (props?: (P & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]) => KlodsNode {\n const { tag, base, modifiers = {} } = options;\n const modifierMap = modifiers as Record<string, string | ((value: unknown) => string | undefined) | undefined>;\n return (props, children) => {\n const userProps = (props ?? {}) as P & KlodsAttrs;\n const modClasses: string[] = [];\n const passthrough: KlodsAttrs = {};\n for (const [key, value] of Object.entries(userProps)) {\n const m = modifierMap[key];\n if (m !== undefined) {\n if (typeof m === \"function\") {\n const c = m(value);\n if (c) modClasses.push(c);\n } else if (value) {\n modClasses.push(m);\n }\n } else {\n passthrough[key] = value;\n }\n }\n const finalClass = mergeClasses(base, ...modClasses, userProps.class);\n const resolvedChildren =\n children !== undefined ? children : ((userProps.children as KlodsChild | KlodsChild[] | undefined) ?? []);\n delete passthrough.children;\n return new KlodsNode(tag, { ...passthrough, class: finalClass || undefined }, resolvedChildren);\n };\n}\n","// First wave of components: nav, card, button, badge, alert, prose helpers.\n// All match the BEM classes shipped by klods-css.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, el, KlodsNode } from \"./core.js\";\n\n// ── Nav ──────────────────────────────────────────────────────────────────\nexport const nav = builder({ tag: \"nav\", base: \"klods-nav\" });\nexport const navList = builder({ tag: \"ul\", base: \"klods-nav__list\" });\n\nexport type NavLinkProps = {\n href?: string;\n active?: boolean;\n};\nconst navLinkBuilder = builder<NavLinkProps>({\n tag: \"a\",\n base: \"klods-nav__link\",\n modifiers: { active: \"klods-nav__link--active\" },\n});\nexport function navLink(props?: (NavLinkProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Wrap each link in <li> so it's idiomatic inside <ul class=\"klods-nav__list\">.\n return el(\"li\", {}, [navLinkBuilder(props ?? null, children)]);\n}\n\n// ── Card ─────────────────────────────────────────────────────────────────\nexport type CardProps = {\n elevated?: boolean;\n};\nexport const card = builder<CardProps>({\n tag: \"div\",\n base: \"klods-card\",\n modifiers: { elevated: \"klods-card--elevated\" },\n});\nexport const cardTitle = builder({ tag: \"h3\", base: \"klods-card__title\" });\nexport const cardBody = builder({ tag: \"div\", base: \"klods-card__body\" });\nexport const cardFooter = builder({ tag: \"div\", base: \"klods-card__footer\" });\n\n// ── Button ───────────────────────────────────────────────────────────────\nexport type ButtonProps = {\n variant?: \"default\" | \"primary\" | \"danger\" | \"ghost\";\n type?: \"button\" | \"submit\" | \"reset\";\n};\nconst buttonBase = builder<ButtonProps>({\n tag: \"button\",\n base: \"klods-button\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-button--${v}` : undefined),\n },\n});\nexport function button(props?: (ButtonProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Default `type=\"button\"` so it never accidentally submits a form.\n const merged = { type: \"button\", ...(props ?? {}) } as ButtonProps & KlodsAttrs;\n return buttonBase(merged, children);\n}\n\n// ── Badge ────────────────────────────────────────────────────────────────\nexport type BadgeProps = {\n variant?: \"default\" | \"accent\" | \"success\" | \"danger\";\n};\nexport const badge = builder<BadgeProps>({\n tag: \"span\",\n base: \"klods-badge\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-badge--${v}` : undefined),\n },\n});\n\n// ── Alert ────────────────────────────────────────────────────────────────\nexport type AlertProps = {\n variant?: \"default\" | \"info\" | \"success\" | \"warning\" | \"danger\";\n};\nconst alertBase = builder<AlertProps>({\n tag: \"div\",\n base: \"klods-alert\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-alert--${v}` : undefined),\n },\n});\nexport function alert(props?: (AlertProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // role=alert by default for assistive tech, overridable.\n const merged = { role: \"alert\", ...(props ?? {}) } as AlertProps & KlodsAttrs;\n return alertBase(merged, children);\n}\n\n// ── Prose helpers ────────────────────────────────────────────────────────\nexport const prose = builder({ tag: \"div\", base: \"klods-prose\" });\nexport const muted = builder({ tag: \"span\", base: \"klods-muted\" });\nexport const lead = builder({ tag: \"p\", base: \"klods-lead\" });\n\n// ── Table ────────────────────────────────────────────────────────────────\nexport type TableProps = {\n striped?: boolean;\n dense?: boolean;\n};\nexport const table = builder<TableProps>({\n tag: \"table\",\n base: \"klods-table\",\n modifiers: {\n striped: \"klods-table--striped\",\n dense: \"klods-table--dense\",\n },\n});\nexport const thead = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"thead\", attrs ?? {}, children);\nexport const tbody = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"tbody\", attrs ?? {}, children);\nexport const tr = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"tr\", attrs ?? {}, children);\nexport const th = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"th\", attrs ?? {}, children);\nexport const td = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"td\", attrs ?? {}, children);\n\n// ── Code ─────────────────────────────────────────────────────────────────\nexport function codeBlock(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode {\n return el(\"pre\", attrs ?? {}, el(\"code\", {}, content));\n}\nexport function inlineCode(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode {\n return el(\"code\", attrs ?? {}, content);\n}\n\n// ── Box ──────────────────────────────────────────────────────────────────\nexport const box = builder({ tag: \"div\", base: \"klods-box\" });\n","// Layout builders — the four corners and the \"I-always-forget\" utilities.\n// Each builder is a thin wrapper around `builder()` from core.ts.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, KlodsNode } from \"./core.js\";\n\n// ── Page ─────────────────────────────────────────────────────────────────\nexport type PageProps = {\n /** Render with a sidebar column. */\n sidebar?: boolean;\n /** Place the sidebar on the right (only meaningful with `sidebar: true`). */\n sidebarRight?: boolean;\n /** Keep the header pinned to the top of the viewport while the page scrolls. */\n stickyHeader?: boolean;\n};\n\nexport const page = builder<PageProps>({\n tag: \"div\",\n base: \"klods-page\",\n modifiers: {\n sidebar: \"klods-page--with-sidebar\",\n sidebarRight: \"klods-page--sidebar-right\",\n stickyHeader: \"klods-page--sticky-header\",\n },\n});\n\n// ── Page slots ───────────────────────────────────────────────────────────\nexport const header = builder({ tag: \"header\", base: \"klods-header\" });\nexport const sidebar = builder({ tag: \"aside\", base: \"klods-sidebar\" });\n\nexport type ContentProps = {\n /** Cap content width to --klods-content-max and centre it. */\n narrow?: boolean;\n};\nexport const content = builder<ContentProps>({\n tag: \"main\",\n base: \"klods-content\",\n modifiers: { narrow: \"klods-content--narrow\" },\n});\n\nexport const footer = builder({ tag: \"footer\", base: \"klods-footer\" });\n\n// ── Layout utilities ─────────────────────────────────────────────────────\ntype GapProp = { gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 };\n\nconst gapModifier = (prefix: string) => (v: number | undefined) =>\n v === undefined ? undefined : `${prefix}--gap-${v}`;\n\nexport const stack = builder<GapProp>({\n tag: \"div\",\n base: \"klods-stack\",\n modifiers: { gap: gapModifier(\"klods-stack\") },\n});\n\nexport const cluster = builder<GapProp>({\n tag: \"div\",\n base: \"klods-cluster\",\n modifiers: { gap: gapModifier(\"klods-cluster\") },\n});\n\nexport const row = builder<GapProp>({\n tag: \"div\",\n base: \"klods-row\",\n modifiers: { gap: gapModifier(\"klods-row\") },\n});\n\nexport type GridProps = GapProp & {\n cols?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Auto-fit responsive columns; pair with `--klods-grid-min` if you want a custom minimum. */\n fit?: boolean;\n};\nexport const grid = builder<GridProps>({\n tag: \"div\",\n base: \"klods-grid\",\n modifiers: {\n gap: gapModifier(\"klods-grid\"),\n cols: (v) => (v === undefined ? undefined : `klods-grid--cols-${v}`),\n fit: \"klods-grid--fit\",\n },\n});\n\nexport const center = builder({ tag: \"div\", base: \"klods-center\" });\nexport const spread = builder({ tag: \"div\", base: \"klods-spread\" });\n\n// ── Convenience: empty fragment-ish wrapper for quick text + nodes ──────\nexport function text(value: string | number): KlodsNode {\n // Wrap loose text in a span so it composes anywhere a KlodsNode is expected.\n return new KlodsNode(\"span\", {}, [String(value)]);\n}\n\n// Re-export attribute / child types so consumers can extend a builder neatly.\nexport type { KlodsAttrs, KlodsChild };\n"],"mappings":"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","names":["stack","el","content"]}
package/dist/index.d.cts CHANGED
@@ -39,7 +39,7 @@ declare function el(tag: string, attrs?: KlodsAttrs, children?: KlodsChild | Klo
39
39
  * attributes; everything else passes through untouched, so consumers can attach
40
40
  * arbitrary `id`, `data-*`, `aria-*`, event handlers, `style`, etc.
41
41
  */
42
- declare function builder<P extends Record<string, unknown> = Record<string, never>>(options: {
42
+ declare function builder<P extends Record<string, unknown> = Record<never, never>>(options: {
43
43
  tag: string;
44
44
  base: string;
45
45
  /** Map of prop name → class (or function returning a class) when the prop is truthy. */
@@ -48,8 +48,8 @@ declare function builder<P extends Record<string, unknown> = Record<string, neve
48
48
  };
49
49
  }): (props?: (P & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
50
50
 
51
- declare const nav: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
52
- declare const navList: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
51
+ declare const nav: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
52
+ declare const navList: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
53
53
  type NavLinkProps = {
54
54
  href?: string;
55
55
  active?: boolean;
@@ -59,9 +59,9 @@ type CardProps = {
59
59
  elevated?: boolean;
60
60
  };
61
61
  declare const card: (props?: (CardProps & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
62
- declare const cardTitle: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
63
- declare const cardBody: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
64
- declare const cardFooter: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
62
+ declare const cardTitle: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
63
+ declare const cardBody: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
64
+ declare const cardFooter: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
65
65
  type ButtonProps = {
66
66
  variant?: "default" | "primary" | "danger" | "ghost";
67
67
  type?: "button" | "submit" | "reset";
@@ -75,25 +75,40 @@ type AlertProps = {
75
75
  variant?: "default" | "info" | "success" | "warning" | "danger";
76
76
  };
77
77
  declare function alert(props?: (AlertProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode;
78
- declare const prose: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
79
- declare const muted: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
80
- declare const lead: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
78
+ declare const prose: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
79
+ declare const muted: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
80
+ declare const lead: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
81
+ type TableProps = {
82
+ striped?: boolean;
83
+ dense?: boolean;
84
+ };
85
+ declare const table: (props?: (TableProps & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
86
+ declare const thead: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
87
+ declare const tbody: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
88
+ declare const tr: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
89
+ declare const th: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
90
+ declare const td: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
91
+ declare function codeBlock(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode;
92
+ declare function inlineCode(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode;
93
+ declare const box: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
81
94
 
82
95
  type PageProps = {
83
96
  /** Render with a sidebar column. */
84
97
  sidebar?: boolean;
85
98
  /** Place the sidebar on the right (only meaningful with `sidebar: true`). */
86
99
  sidebarRight?: boolean;
100
+ /** Keep the header pinned to the top of the viewport while the page scrolls. */
101
+ stickyHeader?: boolean;
87
102
  };
88
103
  declare const page: (props?: (PageProps & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
89
- declare const header: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
90
- declare const sidebar: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
104
+ declare const header: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
105
+ declare const sidebar: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
91
106
  type ContentProps = {
92
107
  /** Cap content width to --klods-content-max and centre it. */
93
108
  narrow?: boolean;
94
109
  };
95
110
  declare const content: (props?: (ContentProps & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
96
- declare const footer: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
111
+ declare const footer: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
97
112
  type GapProp = {
98
113
  gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
99
114
  };
@@ -110,8 +125,8 @@ declare const grid: (props?: (GapProp & {
110
125
  /** Auto-fit responsive columns; pair with `--klods-grid-min` if you want a custom minimum. */
111
126
  fit?: boolean;
112
127
  } & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
113
- declare const center: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
114
- declare const spread: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
128
+ declare const center: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
129
+ declare const spread: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
115
130
  declare function text(value: string | number): KlodsNode;
116
131
 
117
- export { type AlertProps, type BadgeProps, type ButtonProps, type CardProps, type ContentProps, type GridProps, type KlodsAttrs, type KlodsChild, KlodsNode, type NavLinkProps, type PageProps, alert, badge, builder, button, card, cardBody, cardFooter, cardTitle, center, classNames, cluster, content, el, footer, grid, header, lead, mergeClasses, muted, nav, navLink, navList, page, prose, raw, row, sidebar, spread, stack, text };
132
+ export { type AlertProps, type BadgeProps, type ButtonProps, type CardProps, type ContentProps, type GridProps, type KlodsAttrs, type KlodsChild, KlodsNode, type NavLinkProps, type PageProps, type TableProps, alert, badge, box, builder, button, card, cardBody, cardFooter, cardTitle, center, classNames, cluster, codeBlock, content, el, footer, grid, header, inlineCode, lead, mergeClasses, muted, nav, navLink, navList, page, prose, raw, row, sidebar, spread, stack, table, tbody, td, text, th, thead, tr };
package/dist/index.d.ts CHANGED
@@ -39,7 +39,7 @@ declare function el(tag: string, attrs?: KlodsAttrs, children?: KlodsChild | Klo
39
39
  * attributes; everything else passes through untouched, so consumers can attach
40
40
  * arbitrary `id`, `data-*`, `aria-*`, event handlers, `style`, etc.
41
41
  */
42
- declare function builder<P extends Record<string, unknown> = Record<string, never>>(options: {
42
+ declare function builder<P extends Record<string, unknown> = Record<never, never>>(options: {
43
43
  tag: string;
44
44
  base: string;
45
45
  /** Map of prop name → class (or function returning a class) when the prop is truthy. */
@@ -48,8 +48,8 @@ declare function builder<P extends Record<string, unknown> = Record<string, neve
48
48
  };
49
49
  }): (props?: (P & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
50
50
 
51
- declare const nav: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
52
- declare const navList: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
51
+ declare const nav: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
52
+ declare const navList: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
53
53
  type NavLinkProps = {
54
54
  href?: string;
55
55
  active?: boolean;
@@ -59,9 +59,9 @@ type CardProps = {
59
59
  elevated?: boolean;
60
60
  };
61
61
  declare const card: (props?: (CardProps & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
62
- declare const cardTitle: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
63
- declare const cardBody: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
64
- declare const cardFooter: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
62
+ declare const cardTitle: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
63
+ declare const cardBody: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
64
+ declare const cardFooter: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
65
65
  type ButtonProps = {
66
66
  variant?: "default" | "primary" | "danger" | "ghost";
67
67
  type?: "button" | "submit" | "reset";
@@ -75,25 +75,40 @@ type AlertProps = {
75
75
  variant?: "default" | "info" | "success" | "warning" | "danger";
76
76
  };
77
77
  declare function alert(props?: (AlertProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode;
78
- declare const prose: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
79
- declare const muted: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
80
- declare const lead: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
78
+ declare const prose: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
79
+ declare const muted: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
80
+ declare const lead: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
81
+ type TableProps = {
82
+ striped?: boolean;
83
+ dense?: boolean;
84
+ };
85
+ declare const table: (props?: (TableProps & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
86
+ declare const thead: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
87
+ declare const tbody: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
88
+ declare const tr: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
89
+ declare const th: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
90
+ declare const td: (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]) => KlodsNode;
91
+ declare function codeBlock(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode;
92
+ declare function inlineCode(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode;
93
+ declare const box: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
81
94
 
82
95
  type PageProps = {
83
96
  /** Render with a sidebar column. */
84
97
  sidebar?: boolean;
85
98
  /** Place the sidebar on the right (only meaningful with `sidebar: true`). */
86
99
  sidebarRight?: boolean;
100
+ /** Keep the header pinned to the top of the viewport while the page scrolls. */
101
+ stickyHeader?: boolean;
87
102
  };
88
103
  declare const page: (props?: (PageProps & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
89
- declare const header: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
90
- declare const sidebar: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
104
+ declare const header: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
105
+ declare const sidebar: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
91
106
  type ContentProps = {
92
107
  /** Cap content width to --klods-content-max and centre it. */
93
108
  narrow?: boolean;
94
109
  };
95
110
  declare const content: (props?: (ContentProps & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
96
- declare const footer: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
111
+ declare const footer: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
97
112
  type GapProp = {
98
113
  gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
99
114
  };
@@ -110,8 +125,8 @@ declare const grid: (props?: (GapProp & {
110
125
  /** Auto-fit responsive columns; pair with `--klods-grid-min` if you want a custom minimum. */
111
126
  fit?: boolean;
112
127
  } & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
113
- declare const center: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
114
- declare const spread: (props?: (Record<string, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
128
+ declare const center: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
129
+ declare const spread: (props?: (Record<never, never> & KlodsAttrs) | null | undefined, children?: KlodsChild | KlodsChild[]) => KlodsNode;
115
130
  declare function text(value: string | number): KlodsNode;
116
131
 
117
- export { type AlertProps, type BadgeProps, type ButtonProps, type CardProps, type ContentProps, type GridProps, type KlodsAttrs, type KlodsChild, KlodsNode, type NavLinkProps, type PageProps, alert, badge, builder, button, card, cardBody, cardFooter, cardTitle, center, classNames, cluster, content, el, footer, grid, header, lead, mergeClasses, muted, nav, navLink, navList, page, prose, raw, row, sidebar, spread, stack, text };
132
+ export { type AlertProps, type BadgeProps, type ButtonProps, type CardProps, type ContentProps, type GridProps, type KlodsAttrs, type KlodsChild, KlodsNode, type NavLinkProps, type PageProps, type TableProps, alert, badge, box, builder, button, card, cardBody, cardFooter, cardTitle, center, classNames, cluster, codeBlock, content, el, footer, grid, header, inlineCode, lead, mergeClasses, muted, nav, navLink, navList, page, prose, raw, row, sidebar, spread, stack, table, tbody, td, text, th, thead, tr };
package/dist/index.js CHANGED
@@ -220,6 +220,26 @@ function alert(props, children) {
220
220
  var prose = builder({ tag: "div", base: "klods-prose" });
221
221
  var muted = builder({ tag: "span", base: "klods-muted" });
222
222
  var lead = builder({ tag: "p", base: "klods-lead" });
223
+ var table = builder({
224
+ tag: "table",
225
+ base: "klods-table",
226
+ modifiers: {
227
+ striped: "klods-table--striped",
228
+ dense: "klods-table--dense"
229
+ }
230
+ });
231
+ var thead = (attrs, children) => el("thead", attrs ?? {}, children);
232
+ var tbody = (attrs, children) => el("tbody", attrs ?? {}, children);
233
+ var tr = (attrs, children) => el("tr", attrs ?? {}, children);
234
+ var th = (attrs, children) => el("th", attrs ?? {}, children);
235
+ var td = (attrs, children) => el("td", attrs ?? {}, children);
236
+ function codeBlock(attrs, content2) {
237
+ return el("pre", attrs ?? {}, el("code", {}, content2));
238
+ }
239
+ function inlineCode(attrs, content2) {
240
+ return el("code", attrs ?? {}, content2);
241
+ }
242
+ var box = builder({ tag: "div", base: "klods-box" });
223
243
 
224
244
  // src/layout.ts
225
245
  var page = builder({
@@ -227,7 +247,8 @@ var page = builder({
227
247
  base: "klods-page",
228
248
  modifiers: {
229
249
  sidebar: "klods-page--with-sidebar",
230
- sidebarRight: "klods-page--sidebar-right"
250
+ sidebarRight: "klods-page--sidebar-right",
251
+ stickyHeader: "klods-page--sticky-header"
231
252
  }
232
253
  });
233
254
  var header = builder({ tag: "header", base: "klods-header" });
@@ -272,6 +293,7 @@ export {
272
293
  KlodsNode,
273
294
  alert,
274
295
  badge,
296
+ box,
275
297
  builder,
276
298
  button,
277
299
  card,
@@ -281,11 +303,13 @@ export {
281
303
  center,
282
304
  classNames,
283
305
  cluster,
306
+ codeBlock,
284
307
  content,
285
308
  el,
286
309
  footer,
287
310
  grid,
288
311
  header,
312
+ inlineCode,
289
313
  lead,
290
314
  mergeClasses,
291
315
  muted,
@@ -299,6 +323,12 @@ export {
299
323
  sidebar,
300
324
  spread,
301
325
  stack,
302
- text
326
+ table,
327
+ tbody,
328
+ td,
329
+ text,
330
+ th,
331
+ thead,
332
+ tr
303
333
  };
304
334
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts","../src/components.ts","../src/layout.ts"],"sourcesContent":["// Core — a tiny VDOM-ish node with two faces:\n// - .render(target?) → HTMLElement (uses real DOM)\n// - .toString() → HTML string (works in Node / Rails / SSR)\n//\n// Both are produced from the same KlodsNode tree, so the docs site can show the\n// TS source, the rendered HTML and the live preview from one source of truth.\n\nexport type KlodsChild = string | number | bigint | boolean | null | undefined | KlodsNode | Node | KlodsChild[];\n\nexport type KlodsAttrs = {\n class?: string | string[] | Record<string, boolean | undefined> | undefined;\n id?: string | undefined;\n style?: string | Partial<CSSStyleDeclaration> | undefined;\n [key: `data-${string}`]: string | number | boolean | undefined;\n [key: `aria-${string}`]: string | number | boolean | undefined;\n // Allow any other HTML attribute or DOM event handler (onClick, onInput, …).\n [key: string]: unknown;\n};\n\nconst VOID_TAGS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n \"track\",\n \"wbr\",\n]);\n\nconst RAW = Symbol(\"klods.raw\");\n\ntype RawHtml = { [RAW]: true; html: string };\n\n/** Mark a string as already-escaped HTML; pass it as a child to inject as-is. */\nexport function raw(html: string): RawHtml {\n return { [RAW]: true, html };\n}\n\nfunction isRaw(value: unknown): value is RawHtml {\n return typeof value === \"object\" && value !== null && (value as { [RAW]?: unknown })[RAW] === true;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction escapeAttr(str: string): string {\n return str.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\");\n}\n\n/** Normalise a `class` value (string | array | record) into a clean string. */\nexport function classNames(input: KlodsAttrs[\"class\"]): string {\n if (!input) return \"\";\n if (typeof input === \"string\") return input.trim();\n if (Array.isArray(input)) return input.filter(Boolean).join(\" \").trim();\n return Object.entries(input)\n .filter(([, v]) => Boolean(v))\n .map(([k]) => k)\n .join(\" \")\n .trim();\n}\n\n/** Merge two class values (used internally to combine builder defaults + user-supplied). */\nexport function mergeClasses(...inputs: Array<KlodsAttrs[\"class\"]>): string {\n return inputs\n .map((c) => classNames(c))\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction styleToString(style: string | Partial<CSSStyleDeclaration>): string {\n if (typeof style === \"string\") return style;\n return Object.entries(style)\n .filter(([, v]) => v !== undefined && v !== null && v !== \"\")\n .map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}:${String(v)}`)\n .join(\";\");\n}\n\nfunction flattenChildren(children: KlodsChild | KlodsChild[]): Array<Exclude<KlodsChild, KlodsChild[]>> {\n const out: Array<Exclude<KlodsChild, KlodsChild[]>> = [];\n const stack: KlodsChild[] = Array.isArray(children) ? [...children] : [children];\n while (stack.length) {\n const next = stack.shift();\n if (Array.isArray(next)) stack.unshift(...next);\n else if (next !== null && next !== undefined && next !== false && next !== true) out.push(next);\n }\n return out;\n}\n\nexport class KlodsNode {\n readonly tag: string;\n readonly attrs: KlodsAttrs;\n readonly children: KlodsChild[];\n\n constructor(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []) {\n this.tag = tag;\n this.attrs = attrs;\n this.children = Array.isArray(children) ? children : [children];\n }\n\n /** Render to a real DOM element. If `target` is given, append to it. */\n render(target?: Element | null): HTMLElement {\n const el = document.createElement(this.tag);\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) el.setAttribute(\"class\", cls);\n continue;\n }\n if (name === \"style\") {\n el.setAttribute(\"style\", styleToString(value as string | Partial<CSSStyleDeclaration>));\n continue;\n }\n if (name.startsWith(\"on\") && typeof value === \"function\") {\n el.addEventListener(name.slice(2).toLowerCase(), value as EventListener);\n continue;\n }\n if (value === true) {\n el.setAttribute(name, \"\");\n continue;\n }\n el.setAttribute(name, String(value));\n }\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) el.appendChild(child.render());\n else if (typeof child === \"object\" && child !== null && \"nodeType\" in child) {\n el.appendChild(child as Node);\n } else if (isRaw(child)) {\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = child.html;\n el.appendChild(tpl.content);\n } else {\n el.appendChild(document.createTextNode(String(child)));\n }\n }\n if (target) target.appendChild(el);\n return el;\n }\n\n /** Render to a string of HTML. */\n toString(): string {\n const parts: string[] = [`<${this.tag}`];\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name.startsWith(\"on\") && typeof value === \"function\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) parts.push(` class=\"${escapeAttr(cls)}\"`);\n continue;\n }\n if (name === \"style\") {\n parts.push(` style=\"${escapeAttr(styleToString(value as string | Partial<CSSStyleDeclaration>))}\"`);\n continue;\n }\n if (value === true) {\n parts.push(` ${name}`);\n continue;\n }\n parts.push(` ${name}=\"${escapeAttr(String(value))}\"`);\n }\n if (VOID_TAGS.has(this.tag)) {\n parts.push(\" />\");\n return parts.join(\"\");\n }\n parts.push(\">\");\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) parts.push(child.toString());\n else if (isRaw(child)) parts.push(child.html);\n else if (typeof child === \"object\" && child !== null && \"outerHTML\" in child) {\n parts.push((child as Element).outerHTML);\n } else {\n parts.push(escapeHtml(String(child)));\n }\n }\n parts.push(`</${this.tag}>`);\n return parts.join(\"\");\n }\n}\n\n/**\n * Generic element builder. Most consumers use the named builders (page, header, …)\n * rather than calling `el` directly, but it's exported as an escape hatch.\n */\nexport function el(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []): KlodsNode {\n return new KlodsNode(tag, attrs, children);\n}\n\n/**\n * Factory that produces a typed builder for a tag with a base class. Modifier\n * props are converted into `--modifier` BEM classes and stripped from the output\n * attributes; everything else passes through untouched, so consumers can attach\n * arbitrary `id`, `data-*`, `aria-*`, event handlers, `style`, etc.\n */\nexport function builder<P extends Record<string, unknown> = Record<string, never>>(options: {\n tag: string;\n base: string;\n /** Map of prop name → class (or function returning a class) when the prop is truthy. */\n modifiers?: { [K in keyof P]?: string | ((value: P[K]) => string | undefined) };\n}): (props?: (P & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]) => KlodsNode {\n const { tag, base, modifiers = {} } = options;\n const modifierMap = modifiers as Record<string, string | ((value: unknown) => string | undefined) | undefined>;\n return (props, children) => {\n const userProps = (props ?? {}) as P & KlodsAttrs;\n const modClasses: string[] = [];\n const passthrough: KlodsAttrs = {};\n for (const [key, value] of Object.entries(userProps)) {\n const m = modifierMap[key];\n if (m !== undefined) {\n if (typeof m === \"function\") {\n const c = m(value);\n if (c) modClasses.push(c);\n } else if (value) {\n modClasses.push(m);\n }\n } else {\n passthrough[key] = value;\n }\n }\n const finalClass = mergeClasses(base, ...modClasses, userProps.class);\n const resolvedChildren =\n children !== undefined ? children : ((userProps.children as KlodsChild | KlodsChild[] | undefined) ?? []);\n delete passthrough.children;\n return new KlodsNode(tag, { ...passthrough, class: finalClass || undefined }, resolvedChildren);\n };\n}\n","// First wave of components: nav, card, button, badge, alert, prose helpers.\n// All match the BEM classes shipped by klods-css.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, el, KlodsNode } from \"./core.js\";\n\n// ── Nav ──────────────────────────────────────────────────────────────────\nexport const nav = builder({ tag: \"nav\", base: \"klods-nav\" });\nexport const navList = builder({ tag: \"ul\", base: \"klods-nav__list\" });\n\nexport type NavLinkProps = {\n href?: string;\n active?: boolean;\n};\nconst navLinkBuilder = builder<NavLinkProps>({\n tag: \"a\",\n base: \"klods-nav__link\",\n modifiers: { active: \"klods-nav__link--active\" },\n});\nexport function navLink(props?: (NavLinkProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Wrap each link in <li> so it's idiomatic inside <ul class=\"klods-nav__list\">.\n return el(\"li\", {}, [navLinkBuilder(props ?? null, children)]);\n}\n\n// ── Card ─────────────────────────────────────────────────────────────────\nexport type CardProps = {\n elevated?: boolean;\n};\nexport const card = builder<CardProps>({\n tag: \"div\",\n base: \"klods-card\",\n modifiers: { elevated: \"klods-card--elevated\" },\n});\nexport const cardTitle = builder({ tag: \"h3\", base: \"klods-card__title\" });\nexport const cardBody = builder({ tag: \"div\", base: \"klods-card__body\" });\nexport const cardFooter = builder({ tag: \"div\", base: \"klods-card__footer\" });\n\n// ── Button ───────────────────────────────────────────────────────────────\nexport type ButtonProps = {\n variant?: \"default\" | \"primary\" | \"danger\" | \"ghost\";\n type?: \"button\" | \"submit\" | \"reset\";\n};\nconst buttonBase = builder<ButtonProps>({\n tag: \"button\",\n base: \"klods-button\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-button--${v}` : undefined),\n },\n});\nexport function button(props?: (ButtonProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Default `type=\"button\"` so it never accidentally submits a form.\n const merged = { type: \"button\", ...(props ?? {}) } as ButtonProps & KlodsAttrs;\n return buttonBase(merged, children);\n}\n\n// ── Badge ────────────────────────────────────────────────────────────────\nexport type BadgeProps = {\n variant?: \"default\" | \"accent\" | \"success\" | \"danger\";\n};\nexport const badge = builder<BadgeProps>({\n tag: \"span\",\n base: \"klods-badge\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-badge--${v}` : undefined),\n },\n});\n\n// ── Alert ────────────────────────────────────────────────────────────────\nexport type AlertProps = {\n variant?: \"default\" | \"info\" | \"success\" | \"warning\" | \"danger\";\n};\nconst alertBase = builder<AlertProps>({\n tag: \"div\",\n base: \"klods-alert\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-alert--${v}` : undefined),\n },\n});\nexport function alert(props?: (AlertProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // role=alert by default for assistive tech, overridable.\n const merged = { role: \"alert\", ...(props ?? {}) } as AlertProps & KlodsAttrs;\n return alertBase(merged, children);\n}\n\n// ── Prose helpers ────────────────────────────────────────────────────────\nexport const prose = builder({ tag: \"div\", base: \"klods-prose\" });\nexport const muted = builder({ tag: \"span\", base: \"klods-muted\" });\nexport const lead = builder({ tag: \"p\", base: \"klods-lead\" });\n","// Layout builders — the four corners and the \"I-always-forget\" utilities.\n// Each builder is a thin wrapper around `builder()` from core.ts.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, KlodsNode } from \"./core.js\";\n\n// ── Page ─────────────────────────────────────────────────────────────────\nexport type PageProps = {\n /** Render with a sidebar column. */\n sidebar?: boolean;\n /** Place the sidebar on the right (only meaningful with `sidebar: true`). */\n sidebarRight?: boolean;\n};\n\nexport const page = builder<PageProps>({\n tag: \"div\",\n base: \"klods-page\",\n modifiers: {\n sidebar: \"klods-page--with-sidebar\",\n sidebarRight: \"klods-page--sidebar-right\",\n },\n});\n\n// ── Page slots ───────────────────────────────────────────────────────────\nexport const header = builder({ tag: \"header\", base: \"klods-header\" });\nexport const sidebar = builder({ tag: \"aside\", base: \"klods-sidebar\" });\n\nexport type ContentProps = {\n /** Cap content width to --klods-content-max and centre it. */\n narrow?: boolean;\n};\nexport const content = builder<ContentProps>({\n tag: \"main\",\n base: \"klods-content\",\n modifiers: { narrow: \"klods-content--narrow\" },\n});\n\nexport const footer = builder({ tag: \"footer\", base: \"klods-footer\" });\n\n// ── Layout utilities ─────────────────────────────────────────────────────\ntype GapProp = { gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 };\n\nconst gapModifier = (prefix: string) => (v: number | undefined) =>\n v === undefined ? undefined : `${prefix}--gap-${v}`;\n\nexport const stack = builder<GapProp>({\n tag: \"div\",\n base: \"klods-stack\",\n modifiers: { gap: gapModifier(\"klods-stack\") },\n});\n\nexport const cluster = builder<GapProp>({\n tag: \"div\",\n base: \"klods-cluster\",\n modifiers: { gap: gapModifier(\"klods-cluster\") },\n});\n\nexport const row = builder<GapProp>({\n tag: \"div\",\n base: \"klods-row\",\n modifiers: { gap: gapModifier(\"klods-row\") },\n});\n\nexport type GridProps = GapProp & {\n cols?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Auto-fit responsive columns; pair with `--klods-grid-min` if you want a custom minimum. */\n fit?: boolean;\n};\nexport const grid = builder<GridProps>({\n tag: \"div\",\n base: \"klods-grid\",\n modifiers: {\n gap: gapModifier(\"klods-grid\"),\n cols: (v) => (v === undefined ? undefined : `klods-grid--cols-${v}`),\n fit: \"klods-grid--fit\",\n },\n});\n\nexport const center = builder({ tag: \"div\", base: \"klods-center\" });\nexport const spread = builder({ tag: \"div\", base: \"klods-spread\" });\n\n// ── Convenience: empty fragment-ish wrapper for quick text + nodes ──────\nexport function text(value: string | number): KlodsNode {\n // Wrap loose text in a span so it composes anywhere a KlodsNode is expected.\n return new KlodsNode(\"span\", {}, [String(value)]);\n}\n\n// Re-export attribute / child types so consumers can extend a builder neatly.\nexport type { KlodsAttrs, KlodsChild };\n"],"mappings":"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","names":["stack","el"]}
1
+ {"version":3,"sources":["../src/core.ts","../src/components.ts","../src/layout.ts"],"sourcesContent":["// Core — a tiny VDOM-ish node with two faces:\n// - .render(target?) → HTMLElement (uses real DOM)\n// - .toString() → HTML string (works in Node / Rails / SSR)\n//\n// Both are produced from the same KlodsNode tree, so the docs site can show the\n// TS source, the rendered HTML and the live preview from one source of truth.\n\nexport type KlodsChild = string | number | bigint | boolean | null | undefined | KlodsNode | Node | KlodsChild[];\n\nexport type KlodsAttrs = {\n class?: string | string[] | Record<string, boolean | undefined> | undefined;\n id?: string | undefined;\n style?: string | Partial<CSSStyleDeclaration> | undefined;\n [key: `data-${string}`]: string | number | boolean | undefined;\n [key: `aria-${string}`]: string | number | boolean | undefined;\n // Allow any other HTML attribute or DOM event handler (onClick, onInput, …).\n [key: string]: unknown;\n};\n\nconst VOID_TAGS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n \"track\",\n \"wbr\",\n]);\n\nconst RAW = Symbol(\"klods.raw\");\n\ntype RawHtml = { [RAW]: true; html: string };\n\n/** Mark a string as already-escaped HTML; pass it as a child to inject as-is. */\nexport function raw(html: string): RawHtml {\n return { [RAW]: true, html };\n}\n\nfunction isRaw(value: unknown): value is RawHtml {\n return typeof value === \"object\" && value !== null && (value as { [RAW]?: unknown })[RAW] === true;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction escapeAttr(str: string): string {\n return str.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\");\n}\n\n/** Normalise a `class` value (string | array | record) into a clean string. */\nexport function classNames(input: KlodsAttrs[\"class\"]): string {\n if (!input) return \"\";\n if (typeof input === \"string\") return input.trim();\n if (Array.isArray(input)) return input.filter(Boolean).join(\" \").trim();\n return Object.entries(input)\n .filter(([, v]) => Boolean(v))\n .map(([k]) => k)\n .join(\" \")\n .trim();\n}\n\n/** Merge two class values (used internally to combine builder defaults + user-supplied). */\nexport function mergeClasses(...inputs: Array<KlodsAttrs[\"class\"]>): string {\n return inputs\n .map((c) => classNames(c))\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction styleToString(style: string | Partial<CSSStyleDeclaration>): string {\n if (typeof style === \"string\") return style;\n return Object.entries(style)\n .filter(([, v]) => v !== undefined && v !== null && v !== \"\")\n .map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}:${String(v)}`)\n .join(\";\");\n}\n\nfunction flattenChildren(children: KlodsChild | KlodsChild[]): Array<Exclude<KlodsChild, KlodsChild[]>> {\n const out: Array<Exclude<KlodsChild, KlodsChild[]>> = [];\n const stack: KlodsChild[] = Array.isArray(children) ? [...children] : [children];\n while (stack.length) {\n const next = stack.shift();\n if (Array.isArray(next)) stack.unshift(...next);\n else if (next !== null && next !== undefined && next !== false && next !== true) out.push(next);\n }\n return out;\n}\n\nexport class KlodsNode {\n readonly tag: string;\n readonly attrs: KlodsAttrs;\n readonly children: KlodsChild[];\n\n constructor(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []) {\n this.tag = tag;\n this.attrs = attrs;\n this.children = Array.isArray(children) ? children : [children];\n }\n\n /** Render to a real DOM element. If `target` is given, append to it. */\n render(target?: Element | null): HTMLElement {\n const el = document.createElement(this.tag);\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) el.setAttribute(\"class\", cls);\n continue;\n }\n if (name === \"style\") {\n el.setAttribute(\"style\", styleToString(value as string | Partial<CSSStyleDeclaration>));\n continue;\n }\n if (name.startsWith(\"on\") && typeof value === \"function\") {\n el.addEventListener(name.slice(2).toLowerCase(), value as EventListener);\n continue;\n }\n if (value === true) {\n el.setAttribute(name, \"\");\n continue;\n }\n el.setAttribute(name, String(value));\n }\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) el.appendChild(child.render());\n else if (typeof child === \"object\" && child !== null && \"nodeType\" in child) {\n el.appendChild(child as Node);\n } else if (isRaw(child)) {\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = child.html;\n el.appendChild(tpl.content);\n } else {\n el.appendChild(document.createTextNode(String(child)));\n }\n }\n if (target) target.appendChild(el);\n return el;\n }\n\n /** Render to a string of HTML. */\n toString(): string {\n const parts: string[] = [`<${this.tag}`];\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name.startsWith(\"on\") && typeof value === \"function\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) parts.push(` class=\"${escapeAttr(cls)}\"`);\n continue;\n }\n if (name === \"style\") {\n parts.push(` style=\"${escapeAttr(styleToString(value as string | Partial<CSSStyleDeclaration>))}\"`);\n continue;\n }\n if (value === true) {\n parts.push(` ${name}`);\n continue;\n }\n parts.push(` ${name}=\"${escapeAttr(String(value))}\"`);\n }\n if (VOID_TAGS.has(this.tag)) {\n parts.push(\" />\");\n return parts.join(\"\");\n }\n parts.push(\">\");\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) parts.push(child.toString());\n else if (isRaw(child)) parts.push(child.html);\n else if (typeof child === \"object\" && child !== null && \"outerHTML\" in child) {\n parts.push((child as Element).outerHTML);\n } else {\n parts.push(escapeHtml(String(child)));\n }\n }\n parts.push(`</${this.tag}>`);\n return parts.join(\"\");\n }\n}\n\n/**\n * Generic element builder. Most consumers use the named builders (page, header, …)\n * rather than calling `el` directly, but it's exported as an escape hatch.\n */\nexport function el(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []): KlodsNode {\n return new KlodsNode(tag, attrs, children);\n}\n\n/**\n * Factory that produces a typed builder for a tag with a base class. Modifier\n * props are converted into `--modifier` BEM classes and stripped from the output\n * attributes; everything else passes through untouched, so consumers can attach\n * arbitrary `id`, `data-*`, `aria-*`, event handlers, `style`, etc.\n */\nexport function builder<P extends Record<string, unknown> = Record<never, never>>(options: {\n tag: string;\n base: string;\n /** Map of prop name → class (or function returning a class) when the prop is truthy. */\n modifiers?: { [K in keyof P]?: string | ((value: P[K]) => string | undefined) };\n}): (props?: (P & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]) => KlodsNode {\n const { tag, base, modifiers = {} } = options;\n const modifierMap = modifiers as Record<string, string | ((value: unknown) => string | undefined) | undefined>;\n return (props, children) => {\n const userProps = (props ?? {}) as P & KlodsAttrs;\n const modClasses: string[] = [];\n const passthrough: KlodsAttrs = {};\n for (const [key, value] of Object.entries(userProps)) {\n const m = modifierMap[key];\n if (m !== undefined) {\n if (typeof m === \"function\") {\n const c = m(value);\n if (c) modClasses.push(c);\n } else if (value) {\n modClasses.push(m);\n }\n } else {\n passthrough[key] = value;\n }\n }\n const finalClass = mergeClasses(base, ...modClasses, userProps.class);\n const resolvedChildren =\n children !== undefined ? children : ((userProps.children as KlodsChild | KlodsChild[] | undefined) ?? []);\n delete passthrough.children;\n return new KlodsNode(tag, { ...passthrough, class: finalClass || undefined }, resolvedChildren);\n };\n}\n","// First wave of components: nav, card, button, badge, alert, prose helpers.\n// All match the BEM classes shipped by klods-css.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, el, KlodsNode } from \"./core.js\";\n\n// ── Nav ──────────────────────────────────────────────────────────────────\nexport const nav = builder({ tag: \"nav\", base: \"klods-nav\" });\nexport const navList = builder({ tag: \"ul\", base: \"klods-nav__list\" });\n\nexport type NavLinkProps = {\n href?: string;\n active?: boolean;\n};\nconst navLinkBuilder = builder<NavLinkProps>({\n tag: \"a\",\n base: \"klods-nav__link\",\n modifiers: { active: \"klods-nav__link--active\" },\n});\nexport function navLink(props?: (NavLinkProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Wrap each link in <li> so it's idiomatic inside <ul class=\"klods-nav__list\">.\n return el(\"li\", {}, [navLinkBuilder(props ?? null, children)]);\n}\n\n// ── Card ─────────────────────────────────────────────────────────────────\nexport type CardProps = {\n elevated?: boolean;\n};\nexport const card = builder<CardProps>({\n tag: \"div\",\n base: \"klods-card\",\n modifiers: { elevated: \"klods-card--elevated\" },\n});\nexport const cardTitle = builder({ tag: \"h3\", base: \"klods-card__title\" });\nexport const cardBody = builder({ tag: \"div\", base: \"klods-card__body\" });\nexport const cardFooter = builder({ tag: \"div\", base: \"klods-card__footer\" });\n\n// ── Button ───────────────────────────────────────────────────────────────\nexport type ButtonProps = {\n variant?: \"default\" | \"primary\" | \"danger\" | \"ghost\";\n type?: \"button\" | \"submit\" | \"reset\";\n};\nconst buttonBase = builder<ButtonProps>({\n tag: \"button\",\n base: \"klods-button\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-button--${v}` : undefined),\n },\n});\nexport function button(props?: (ButtonProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Default `type=\"button\"` so it never accidentally submits a form.\n const merged = { type: \"button\", ...(props ?? {}) } as ButtonProps & KlodsAttrs;\n return buttonBase(merged, children);\n}\n\n// ── Badge ────────────────────────────────────────────────────────────────\nexport type BadgeProps = {\n variant?: \"default\" | \"accent\" | \"success\" | \"danger\";\n};\nexport const badge = builder<BadgeProps>({\n tag: \"span\",\n base: \"klods-badge\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-badge--${v}` : undefined),\n },\n});\n\n// ── Alert ────────────────────────────────────────────────────────────────\nexport type AlertProps = {\n variant?: \"default\" | \"info\" | \"success\" | \"warning\" | \"danger\";\n};\nconst alertBase = builder<AlertProps>({\n tag: \"div\",\n base: \"klods-alert\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-alert--${v}` : undefined),\n },\n});\nexport function alert(props?: (AlertProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // role=alert by default for assistive tech, overridable.\n const merged = { role: \"alert\", ...(props ?? {}) } as AlertProps & KlodsAttrs;\n return alertBase(merged, children);\n}\n\n// ── Prose helpers ────────────────────────────────────────────────────────\nexport const prose = builder({ tag: \"div\", base: \"klods-prose\" });\nexport const muted = builder({ tag: \"span\", base: \"klods-muted\" });\nexport const lead = builder({ tag: \"p\", base: \"klods-lead\" });\n\n// ── Table ────────────────────────────────────────────────────────────────\nexport type TableProps = {\n striped?: boolean;\n dense?: boolean;\n};\nexport const table = builder<TableProps>({\n tag: \"table\",\n base: \"klods-table\",\n modifiers: {\n striped: \"klods-table--striped\",\n dense: \"klods-table--dense\",\n },\n});\nexport const thead = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"thead\", attrs ?? {}, children);\nexport const tbody = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"tbody\", attrs ?? {}, children);\nexport const tr = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"tr\", attrs ?? {}, children);\nexport const th = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"th\", attrs ?? {}, children);\nexport const td = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"td\", attrs ?? {}, children);\n\n// ── Code ─────────────────────────────────────────────────────────────────\nexport function codeBlock(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode {\n return el(\"pre\", attrs ?? {}, el(\"code\", {}, content));\n}\nexport function inlineCode(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode {\n return el(\"code\", attrs ?? {}, content);\n}\n\n// ── Box ──────────────────────────────────────────────────────────────────\nexport const box = builder({ tag: \"div\", base: \"klods-box\" });\n","// Layout builders — the four corners and the \"I-always-forget\" utilities.\n// Each builder is a thin wrapper around `builder()` from core.ts.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, KlodsNode } from \"./core.js\";\n\n// ── Page ─────────────────────────────────────────────────────────────────\nexport type PageProps = {\n /** Render with a sidebar column. */\n sidebar?: boolean;\n /** Place the sidebar on the right (only meaningful with `sidebar: true`). */\n sidebarRight?: boolean;\n /** Keep the header pinned to the top of the viewport while the page scrolls. */\n stickyHeader?: boolean;\n};\n\nexport const page = builder<PageProps>({\n tag: \"div\",\n base: \"klods-page\",\n modifiers: {\n sidebar: \"klods-page--with-sidebar\",\n sidebarRight: \"klods-page--sidebar-right\",\n stickyHeader: \"klods-page--sticky-header\",\n },\n});\n\n// ── Page slots ───────────────────────────────────────────────────────────\nexport const header = builder({ tag: \"header\", base: \"klods-header\" });\nexport const sidebar = builder({ tag: \"aside\", base: \"klods-sidebar\" });\n\nexport type ContentProps = {\n /** Cap content width to --klods-content-max and centre it. */\n narrow?: boolean;\n};\nexport const content = builder<ContentProps>({\n tag: \"main\",\n base: \"klods-content\",\n modifiers: { narrow: \"klods-content--narrow\" },\n});\n\nexport const footer = builder({ tag: \"footer\", base: \"klods-footer\" });\n\n// ── Layout utilities ─────────────────────────────────────────────────────\ntype GapProp = { gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 };\n\nconst gapModifier = (prefix: string) => (v: number | undefined) =>\n v === undefined ? undefined : `${prefix}--gap-${v}`;\n\nexport const stack = builder<GapProp>({\n tag: \"div\",\n base: \"klods-stack\",\n modifiers: { gap: gapModifier(\"klods-stack\") },\n});\n\nexport const cluster = builder<GapProp>({\n tag: \"div\",\n base: \"klods-cluster\",\n modifiers: { gap: gapModifier(\"klods-cluster\") },\n});\n\nexport const row = builder<GapProp>({\n tag: \"div\",\n base: \"klods-row\",\n modifiers: { gap: gapModifier(\"klods-row\") },\n});\n\nexport type GridProps = GapProp & {\n cols?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Auto-fit responsive columns; pair with `--klods-grid-min` if you want a custom minimum. */\n fit?: boolean;\n};\nexport const grid = builder<GridProps>({\n tag: \"div\",\n base: \"klods-grid\",\n modifiers: {\n gap: gapModifier(\"klods-grid\"),\n cols: (v) => (v === undefined ? undefined : `klods-grid--cols-${v}`),\n fit: \"klods-grid--fit\",\n },\n});\n\nexport const center = builder({ tag: \"div\", base: \"klods-center\" });\nexport const spread = builder({ tag: \"div\", base: \"klods-spread\" });\n\n// ── Convenience: empty fragment-ish wrapper for quick text + nodes ──────\nexport function text(value: string | number): KlodsNode {\n // Wrap loose text in a span so it composes anywhere a KlodsNode is expected.\n return new KlodsNode(\"span\", {}, [String(value)]);\n}\n\n// Re-export attribute / child types so consumers can extend a builder neatly.\nexport type { KlodsAttrs, KlodsChild };\n"],"mappings":"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","names":["stack","el","content"]}
package/dist/klods.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var Klods=(()=>{var a=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var B=(t,e,s)=>e in t?a(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var R=(t,e)=>{for(var s in e)a(t,s,{get:e[s],enumerable:!0})},_=(t,e,s,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of N(e))!L.call(t,n)&&n!==s&&a(t,n,{get:()=>e[n],enumerable:!(o=j(e,n))||o.enumerable});return t};var E=t=>_(a({},"__esModule",{value:!0}),t);var c=(t,e,s)=>B(t,typeof e!="symbol"?e+"":e,s);var ft={};R(ft,{KlodsNode:()=>i,alert:()=>U,badge:()=>J,builder:()=>r,button:()=>z,card:()=>q,cardBody:()=>I,cardFooter:()=>V,cardTitle:()=>F,center:()=>ct,classNames:()=>u,cluster:()=>dt,content:()=>rt,el:()=>k,footer:()=>nt,grid:()=>at,header:()=>st,lead:()=>tt,mergeClasses:()=>w,muted:()=>Y,nav:()=>M,navLink:()=>W,navList:()=>O,page:()=>et,prose:()=>X,raw:()=>G,row:()=>lt,sidebar:()=>ot,spread:()=>ut,stack:()=>it,text:()=>pt});var T=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]),v=Symbol("klods.raw");function G(t){return{[v]:!0,html:t}}function C(t){return typeof t=="object"&&t!==null&&t[v]===!0}function H(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function m(t){return t.replace(/&/g,"&amp;").replace(/"/g,"&quot;")}function u(t){return t?typeof t=="string"?t.trim():Array.isArray(t)?t.filter(Boolean).join(" ").trim():Object.entries(t).filter(([,e])=>!!e).map(([e])=>e).join(" ").trim():""}function w(...t){return t.map(e=>u(e)).filter(Boolean).join(" ")}function A(t){return typeof t=="string"?t:Object.entries(t).filter(([,e])=>e!=null&&e!=="").map(([e,s])=>`${e.replace(/[A-Z]/g,o=>`-${o.toLowerCase()}`)}:${String(s)}`).join(";")}function P(t){let e=[],s=Array.isArray(t)?[...t]:[t];for(;s.length;){let o=s.shift();Array.isArray(o)?s.unshift(...o):o!=null&&o!==!1&&o!==!0&&e.push(o)}return e}var i=class t{constructor(e,s={},o=[]){c(this,"tag");c(this,"attrs");c(this,"children");this.tag=e,this.attrs=s,this.children=Array.isArray(o)?o:[o]}render(e){let s=document.createElement(this.tag);for(let[o,n]of Object.entries(this.attrs))if(!(n==null||n===!1)&&o!=="children"){if(o==="class"){let d=u(n);d&&s.setAttribute("class",d);continue}if(o==="style"){s.setAttribute("style",A(n));continue}if(o.startsWith("on")&&typeof n=="function"){s.addEventListener(o.slice(2).toLowerCase(),n);continue}if(n===!0){s.setAttribute(o,"");continue}s.setAttribute(o,String(n))}for(let o of P(this.children))if(o instanceof t)s.appendChild(o.render());else if(typeof o=="object"&&o!==null&&"nodeType"in o)s.appendChild(o);else if(C(o)){let n=document.createElement("template");n.innerHTML=o.html,s.appendChild(n.content)}else s.appendChild(document.createTextNode(String(o)));return e&&e.appendChild(s),s}toString(){let e=[`<${this.tag}`];for(let[s,o]of Object.entries(this.attrs))if(!(o==null||o===!1)&&s!=="children"&&!(s.startsWith("on")&&typeof o=="function")){if(s==="class"){let n=u(o);n&&e.push(` class="${m(n)}"`);continue}if(s==="style"){e.push(` style="${m(A(o))}"`);continue}if(o===!0){e.push(` ${s}`);continue}e.push(` ${s}="${m(String(o))}"`)}if(T.has(this.tag))return e.push(" />"),e.join("");e.push(">");for(let s of P(this.children))s instanceof t?e.push(s.toString()):C(s)?e.push(s.html):typeof s=="object"&&s!==null&&"outerHTML"in s?e.push(s.outerHTML):e.push(H(String(s)));return e.push(`</${this.tag}>`),e.join("")}};function k(t,e={},s=[]){return new i(t,e,s)}function r(t){let{tag:e,base:s,modifiers:o={}}=t,n=o;return(d,y)=>{let f=d??{},g=[],h={};for(let[K,b]of Object.entries(f)){let l=n[K];if(l!==void 0)if(typeof l=="function"){let x=l(b);x&&g.push(x)}else b&&g.push(l);else h[K]=b}let S=w(s,...g,f.class),$=y!==void 0?y:f.children??[];return delete h.children,new i(e,{...h,class:S||void 0},$)}}var M=r({tag:"nav",base:"klods-nav"}),O=r({tag:"ul",base:"klods-nav__list"}),D=r({tag:"a",base:"klods-nav__link",modifiers:{active:"klods-nav__link--active"}});function W(t,e){return k("li",{},[D(t??null,e)])}var q=r({tag:"div",base:"klods-card",modifiers:{elevated:"klods-card--elevated"}}),F=r({tag:"h3",base:"klods-card__title"}),I=r({tag:"div",base:"klods-card__body"}),V=r({tag:"div",base:"klods-card__footer"}),Z=r({tag:"button",base:"klods-button",modifiers:{variant:t=>t&&t!=="default"?`klods-button--${t}`:void 0}});function z(t,e){let s={type:"button",...t??{}};return Z(s,e)}var J=r({tag:"span",base:"klods-badge",modifiers:{variant:t=>t&&t!=="default"?`klods-badge--${t}`:void 0}}),Q=r({tag:"div",base:"klods-alert",modifiers:{variant:t=>t&&t!=="default"?`klods-alert--${t}`:void 0}});function U(t,e){let s={role:"alert",...t??{}};return Q(s,e)}var X=r({tag:"div",base:"klods-prose"}),Y=r({tag:"span",base:"klods-muted"}),tt=r({tag:"p",base:"klods-lead"});var et=r({tag:"div",base:"klods-page",modifiers:{sidebar:"klods-page--with-sidebar",sidebarRight:"klods-page--sidebar-right"}}),st=r({tag:"header",base:"klods-header"}),ot=r({tag:"aside",base:"klods-sidebar"}),rt=r({tag:"main",base:"klods-content",modifiers:{narrow:"klods-content--narrow"}}),nt=r({tag:"footer",base:"klods-footer"}),p=t=>e=>e===void 0?void 0:`${t}--gap-${e}`,it=r({tag:"div",base:"klods-stack",modifiers:{gap:p("klods-stack")}}),dt=r({tag:"div",base:"klods-cluster",modifiers:{gap:p("klods-cluster")}}),lt=r({tag:"div",base:"klods-row",modifiers:{gap:p("klods-row")}}),at=r({tag:"div",base:"klods-grid",modifiers:{gap:p("klods-grid"),cols:t=>t===void 0?void 0:`klods-grid--cols-${t}`,fit:"klods-grid--fit"}}),ct=r({tag:"div",base:"klods-center"}),ut=r({tag:"div",base:"klods-spread"});function pt(t){return new i("span",{},[String(t)])}return E(ft);})();
1
+ "use strict";var Klods=(()=>{var c=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var L=(t,e,s)=>e in t?c(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var R=(t,e)=>{for(var s in e)c(t,s,{get:e[s],enumerable:!0})},T=(t,e,s,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of j(e))!B.call(t,n)&&n!==s&&c(t,n,{get:()=>e[n],enumerable:!(o=$(e,n))||o.enumerable});return t};var _=t=>T(c({},"__esModule",{value:!0}),t);var p=(t,e,s)=>L(t,typeof e!="symbol"?e+"":e,s);var Ct={};R(Ct,{KlodsNode:()=>l,alert:()=>U,badge:()=>J,box:()=>at,builder:()=>r,button:()=>z,card:()=>q,cardBody:()=>I,cardFooter:()=>V,cardTitle:()=>F,center:()=>kt,classNames:()=>u,cluster:()=>bt,codeBlock:()=>lt,content:()=>ft,el:()=>d,footer:()=>gt,grid:()=>mt,header:()=>pt,inlineCode:()=>it,lead:()=>tt,mergeClasses:()=>w,muted:()=>Y,nav:()=>M,navLink:()=>W,navList:()=>O,page:()=>ct,prose:()=>X,raw:()=>E,row:()=>Kt,sidebar:()=>ut,spread:()=>xt,stack:()=>ht,table:()=>et,tbody:()=>ot,td:()=>dt,text:()=>yt,th:()=>nt,thead:()=>st,tr:()=>rt});var H=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]),v=Symbol("klods.raw");function E(t){return{[v]:!0,html:t}}function C(t){return typeof t=="object"&&t!==null&&t[v]===!0}function G(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function m(t){return t.replace(/&/g,"&amp;").replace(/"/g,"&quot;")}function u(t){return t?typeof t=="string"?t.trim():Array.isArray(t)?t.filter(Boolean).join(" ").trim():Object.entries(t).filter(([,e])=>!!e).map(([e])=>e).join(" ").trim():""}function w(...t){return t.map(e=>u(e)).filter(Boolean).join(" ")}function A(t){return typeof t=="string"?t:Object.entries(t).filter(([,e])=>e!=null&&e!=="").map(([e,s])=>`${e.replace(/[A-Z]/g,o=>`-${o.toLowerCase()}`)}:${String(s)}`).join(";")}function P(t){let e=[],s=Array.isArray(t)?[...t]:[t];for(;s.length;){let o=s.shift();Array.isArray(o)?s.unshift(...o):o!=null&&o!==!1&&o!==!0&&e.push(o)}return e}var l=class t{constructor(e,s={},o=[]){p(this,"tag");p(this,"attrs");p(this,"children");this.tag=e,this.attrs=s,this.children=Array.isArray(o)?o:[o]}render(e){let s=document.createElement(this.tag);for(let[o,n]of Object.entries(this.attrs))if(!(n==null||n===!1)&&o!=="children"){if(o==="class"){let i=u(n);i&&s.setAttribute("class",i);continue}if(o==="style"){s.setAttribute("style",A(n));continue}if(o.startsWith("on")&&typeof n=="function"){s.addEventListener(o.slice(2).toLowerCase(),n);continue}if(n===!0){s.setAttribute(o,"");continue}s.setAttribute(o,String(n))}for(let o of P(this.children))if(o instanceof t)s.appendChild(o.render());else if(typeof o=="object"&&o!==null&&"nodeType"in o)s.appendChild(o);else if(C(o)){let n=document.createElement("template");n.innerHTML=o.html,s.appendChild(n.content)}else s.appendChild(document.createTextNode(String(o)));return e&&e.appendChild(s),s}toString(){let e=[`<${this.tag}`];for(let[s,o]of Object.entries(this.attrs))if(!(o==null||o===!1)&&s!=="children"&&!(s.startsWith("on")&&typeof o=="function")){if(s==="class"){let n=u(o);n&&e.push(` class="${m(n)}"`);continue}if(s==="style"){e.push(` style="${m(A(o))}"`);continue}if(o===!0){e.push(` ${s}`);continue}e.push(` ${s}="${m(String(o))}"`)}if(H.has(this.tag))return e.push(" />"),e.join("");e.push(">");for(let s of P(this.children))s instanceof t?e.push(s.toString()):C(s)?e.push(s.html):typeof s=="object"&&s!==null&&"outerHTML"in s?e.push(s.outerHTML):e.push(G(String(s)));return e.push(`</${this.tag}>`),e.join("")}};function d(t,e={},s=[]){return new l(t,e,s)}function r(t){let{tag:e,base:s,modifiers:o={}}=t,n=o;return(i,k)=>{let g=i??{},h=[],b={};for(let[x,K]of Object.entries(g)){let a=n[x];if(a!==void 0)if(typeof a=="function"){let y=a(K);y&&h.push(y)}else K&&h.push(a);else b[x]=K}let S=w(s,...h,g.class),N=k!==void 0?k:g.children??[];return delete b.children,new l(e,{...b,class:S||void 0},N)}}var M=r({tag:"nav",base:"klods-nav"}),O=r({tag:"ul",base:"klods-nav__list"}),D=r({tag:"a",base:"klods-nav__link",modifiers:{active:"klods-nav__link--active"}});function W(t,e){return d("li",{},[D(t??null,e)])}var q=r({tag:"div",base:"klods-card",modifiers:{elevated:"klods-card--elevated"}}),F=r({tag:"h3",base:"klods-card__title"}),I=r({tag:"div",base:"klods-card__body"}),V=r({tag:"div",base:"klods-card__footer"}),Z=r({tag:"button",base:"klods-button",modifiers:{variant:t=>t&&t!=="default"?`klods-button--${t}`:void 0}});function z(t,e){let s={type:"button",...t??{}};return Z(s,e)}var J=r({tag:"span",base:"klods-badge",modifiers:{variant:t=>t&&t!=="default"?`klods-badge--${t}`:void 0}}),Q=r({tag:"div",base:"klods-alert",modifiers:{variant:t=>t&&t!=="default"?`klods-alert--${t}`:void 0}});function U(t,e){let s={role:"alert",...t??{}};return Q(s,e)}var X=r({tag:"div",base:"klods-prose"}),Y=r({tag:"span",base:"klods-muted"}),tt=r({tag:"p",base:"klods-lead"}),et=r({tag:"table",base:"klods-table",modifiers:{striped:"klods-table--striped",dense:"klods-table--dense"}}),st=(t,e)=>d("thead",t??{},e),ot=(t,e)=>d("tbody",t??{},e),rt=(t,e)=>d("tr",t??{},e),nt=(t,e)=>d("th",t??{},e),dt=(t,e)=>d("td",t??{},e);function lt(t,e){return d("pre",t??{},d("code",{},e))}function it(t,e){return d("code",t??{},e)}var at=r({tag:"div",base:"klods-box"});var ct=r({tag:"div",base:"klods-page",modifiers:{sidebar:"klods-page--with-sidebar",sidebarRight:"klods-page--sidebar-right",stickyHeader:"klods-page--sticky-header"}}),pt=r({tag:"header",base:"klods-header"}),ut=r({tag:"aside",base:"klods-sidebar"}),ft=r({tag:"main",base:"klods-content",modifiers:{narrow:"klods-content--narrow"}}),gt=r({tag:"footer",base:"klods-footer"}),f=t=>e=>e===void 0?void 0:`${t}--gap-${e}`,ht=r({tag:"div",base:"klods-stack",modifiers:{gap:f("klods-stack")}}),bt=r({tag:"div",base:"klods-cluster",modifiers:{gap:f("klods-cluster")}}),Kt=r({tag:"div",base:"klods-row",modifiers:{gap:f("klods-row")}}),mt=r({tag:"div",base:"klods-grid",modifiers:{gap:f("klods-grid"),cols:t=>t===void 0?void 0:`klods-grid--cols-${t}`,fit:"klods-grid--fit"}}),kt=r({tag:"div",base:"klods-center"}),xt=r({tag:"div",base:"klods-spread"});function yt(t){return new l("span",{},[String(t)])}return _(Ct);})();
2
2
  //# sourceMappingURL=klods.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core.ts","../src/components.ts","../src/layout.ts"],"sourcesContent":["// Public API surface for the `klods` package.\n\nexport * from \"./components.js\";\nexport * from \"./core.js\";\nexport * from \"./layout.js\";\n","// Core — a tiny VDOM-ish node with two faces:\n// - .render(target?) → HTMLElement (uses real DOM)\n// - .toString() → HTML string (works in Node / Rails / SSR)\n//\n// Both are produced from the same KlodsNode tree, so the docs site can show the\n// TS source, the rendered HTML and the live preview from one source of truth.\n\nexport type KlodsChild = string | number | bigint | boolean | null | undefined | KlodsNode | Node | KlodsChild[];\n\nexport type KlodsAttrs = {\n class?: string | string[] | Record<string, boolean | undefined> | undefined;\n id?: string | undefined;\n style?: string | Partial<CSSStyleDeclaration> | undefined;\n [key: `data-${string}`]: string | number | boolean | undefined;\n [key: `aria-${string}`]: string | number | boolean | undefined;\n // Allow any other HTML attribute or DOM event handler (onClick, onInput, …).\n [key: string]: unknown;\n};\n\nconst VOID_TAGS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n \"track\",\n \"wbr\",\n]);\n\nconst RAW = Symbol(\"klods.raw\");\n\ntype RawHtml = { [RAW]: true; html: string };\n\n/** Mark a string as already-escaped HTML; pass it as a child to inject as-is. */\nexport function raw(html: string): RawHtml {\n return { [RAW]: true, html };\n}\n\nfunction isRaw(value: unknown): value is RawHtml {\n return typeof value === \"object\" && value !== null && (value as { [RAW]?: unknown })[RAW] === true;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction escapeAttr(str: string): string {\n return str.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\");\n}\n\n/** Normalise a `class` value (string | array | record) into a clean string. */\nexport function classNames(input: KlodsAttrs[\"class\"]): string {\n if (!input) return \"\";\n if (typeof input === \"string\") return input.trim();\n if (Array.isArray(input)) return input.filter(Boolean).join(\" \").trim();\n return Object.entries(input)\n .filter(([, v]) => Boolean(v))\n .map(([k]) => k)\n .join(\" \")\n .trim();\n}\n\n/** Merge two class values (used internally to combine builder defaults + user-supplied). */\nexport function mergeClasses(...inputs: Array<KlodsAttrs[\"class\"]>): string {\n return inputs\n .map((c) => classNames(c))\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction styleToString(style: string | Partial<CSSStyleDeclaration>): string {\n if (typeof style === \"string\") return style;\n return Object.entries(style)\n .filter(([, v]) => v !== undefined && v !== null && v !== \"\")\n .map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}:${String(v)}`)\n .join(\";\");\n}\n\nfunction flattenChildren(children: KlodsChild | KlodsChild[]): Array<Exclude<KlodsChild, KlodsChild[]>> {\n const out: Array<Exclude<KlodsChild, KlodsChild[]>> = [];\n const stack: KlodsChild[] = Array.isArray(children) ? [...children] : [children];\n while (stack.length) {\n const next = stack.shift();\n if (Array.isArray(next)) stack.unshift(...next);\n else if (next !== null && next !== undefined && next !== false && next !== true) out.push(next);\n }\n return out;\n}\n\nexport class KlodsNode {\n readonly tag: string;\n readonly attrs: KlodsAttrs;\n readonly children: KlodsChild[];\n\n constructor(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []) {\n this.tag = tag;\n this.attrs = attrs;\n this.children = Array.isArray(children) ? children : [children];\n }\n\n /** Render to a real DOM element. If `target` is given, append to it. */\n render(target?: Element | null): HTMLElement {\n const el = document.createElement(this.tag);\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) el.setAttribute(\"class\", cls);\n continue;\n }\n if (name === \"style\") {\n el.setAttribute(\"style\", styleToString(value as string | Partial<CSSStyleDeclaration>));\n continue;\n }\n if (name.startsWith(\"on\") && typeof value === \"function\") {\n el.addEventListener(name.slice(2).toLowerCase(), value as EventListener);\n continue;\n }\n if (value === true) {\n el.setAttribute(name, \"\");\n continue;\n }\n el.setAttribute(name, String(value));\n }\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) el.appendChild(child.render());\n else if (typeof child === \"object\" && child !== null && \"nodeType\" in child) {\n el.appendChild(child as Node);\n } else if (isRaw(child)) {\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = child.html;\n el.appendChild(tpl.content);\n } else {\n el.appendChild(document.createTextNode(String(child)));\n }\n }\n if (target) target.appendChild(el);\n return el;\n }\n\n /** Render to a string of HTML. */\n toString(): string {\n const parts: string[] = [`<${this.tag}`];\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name.startsWith(\"on\") && typeof value === \"function\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) parts.push(` class=\"${escapeAttr(cls)}\"`);\n continue;\n }\n if (name === \"style\") {\n parts.push(` style=\"${escapeAttr(styleToString(value as string | Partial<CSSStyleDeclaration>))}\"`);\n continue;\n }\n if (value === true) {\n parts.push(` ${name}`);\n continue;\n }\n parts.push(` ${name}=\"${escapeAttr(String(value))}\"`);\n }\n if (VOID_TAGS.has(this.tag)) {\n parts.push(\" />\");\n return parts.join(\"\");\n }\n parts.push(\">\");\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) parts.push(child.toString());\n else if (isRaw(child)) parts.push(child.html);\n else if (typeof child === \"object\" && child !== null && \"outerHTML\" in child) {\n parts.push((child as Element).outerHTML);\n } else {\n parts.push(escapeHtml(String(child)));\n }\n }\n parts.push(`</${this.tag}>`);\n return parts.join(\"\");\n }\n}\n\n/**\n * Generic element builder. Most consumers use the named builders (page, header, …)\n * rather than calling `el` directly, but it's exported as an escape hatch.\n */\nexport function el(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []): KlodsNode {\n return new KlodsNode(tag, attrs, children);\n}\n\n/**\n * Factory that produces a typed builder for a tag with a base class. Modifier\n * props are converted into `--modifier` BEM classes and stripped from the output\n * attributes; everything else passes through untouched, so consumers can attach\n * arbitrary `id`, `data-*`, `aria-*`, event handlers, `style`, etc.\n */\nexport function builder<P extends Record<string, unknown> = Record<string, never>>(options: {\n tag: string;\n base: string;\n /** Map of prop name → class (or function returning a class) when the prop is truthy. */\n modifiers?: { [K in keyof P]?: string | ((value: P[K]) => string | undefined) };\n}): (props?: (P & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]) => KlodsNode {\n const { tag, base, modifiers = {} } = options;\n const modifierMap = modifiers as Record<string, string | ((value: unknown) => string | undefined) | undefined>;\n return (props, children) => {\n const userProps = (props ?? {}) as P & KlodsAttrs;\n const modClasses: string[] = [];\n const passthrough: KlodsAttrs = {};\n for (const [key, value] of Object.entries(userProps)) {\n const m = modifierMap[key];\n if (m !== undefined) {\n if (typeof m === \"function\") {\n const c = m(value);\n if (c) modClasses.push(c);\n } else if (value) {\n modClasses.push(m);\n }\n } else {\n passthrough[key] = value;\n }\n }\n const finalClass = mergeClasses(base, ...modClasses, userProps.class);\n const resolvedChildren =\n children !== undefined ? children : ((userProps.children as KlodsChild | KlodsChild[] | undefined) ?? []);\n delete passthrough.children;\n return new KlodsNode(tag, { ...passthrough, class: finalClass || undefined }, resolvedChildren);\n };\n}\n","// First wave of components: nav, card, button, badge, alert, prose helpers.\n// All match the BEM classes shipped by klods-css.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, el, KlodsNode } from \"./core.js\";\n\n// ── Nav ──────────────────────────────────────────────────────────────────\nexport const nav = builder({ tag: \"nav\", base: \"klods-nav\" });\nexport const navList = builder({ tag: \"ul\", base: \"klods-nav__list\" });\n\nexport type NavLinkProps = {\n href?: string;\n active?: boolean;\n};\nconst navLinkBuilder = builder<NavLinkProps>({\n tag: \"a\",\n base: \"klods-nav__link\",\n modifiers: { active: \"klods-nav__link--active\" },\n});\nexport function navLink(props?: (NavLinkProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Wrap each link in <li> so it's idiomatic inside <ul class=\"klods-nav__list\">.\n return el(\"li\", {}, [navLinkBuilder(props ?? null, children)]);\n}\n\n// ── Card ─────────────────────────────────────────────────────────────────\nexport type CardProps = {\n elevated?: boolean;\n};\nexport const card = builder<CardProps>({\n tag: \"div\",\n base: \"klods-card\",\n modifiers: { elevated: \"klods-card--elevated\" },\n});\nexport const cardTitle = builder({ tag: \"h3\", base: \"klods-card__title\" });\nexport const cardBody = builder({ tag: \"div\", base: \"klods-card__body\" });\nexport const cardFooter = builder({ tag: \"div\", base: \"klods-card__footer\" });\n\n// ── Button ───────────────────────────────────────────────────────────────\nexport type ButtonProps = {\n variant?: \"default\" | \"primary\" | \"danger\" | \"ghost\";\n type?: \"button\" | \"submit\" | \"reset\";\n};\nconst buttonBase = builder<ButtonProps>({\n tag: \"button\",\n base: \"klods-button\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-button--${v}` : undefined),\n },\n});\nexport function button(props?: (ButtonProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Default `type=\"button\"` so it never accidentally submits a form.\n const merged = { type: \"button\", ...(props ?? {}) } as ButtonProps & KlodsAttrs;\n return buttonBase(merged, children);\n}\n\n// ── Badge ────────────────────────────────────────────────────────────────\nexport type BadgeProps = {\n variant?: \"default\" | \"accent\" | \"success\" | \"danger\";\n};\nexport const badge = builder<BadgeProps>({\n tag: \"span\",\n base: \"klods-badge\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-badge--${v}` : undefined),\n },\n});\n\n// ── Alert ────────────────────────────────────────────────────────────────\nexport type AlertProps = {\n variant?: \"default\" | \"info\" | \"success\" | \"warning\" | \"danger\";\n};\nconst alertBase = builder<AlertProps>({\n tag: \"div\",\n base: \"klods-alert\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-alert--${v}` : undefined),\n },\n});\nexport function alert(props?: (AlertProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // role=alert by default for assistive tech, overridable.\n const merged = { role: \"alert\", ...(props ?? {}) } as AlertProps & KlodsAttrs;\n return alertBase(merged, children);\n}\n\n// ── Prose helpers ────────────────────────────────────────────────────────\nexport const prose = builder({ tag: \"div\", base: \"klods-prose\" });\nexport const muted = builder({ tag: \"span\", base: \"klods-muted\" });\nexport const lead = builder({ tag: \"p\", base: \"klods-lead\" });\n","// Layout builders — the four corners and the \"I-always-forget\" utilities.\n// Each builder is a thin wrapper around `builder()` from core.ts.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, KlodsNode } from \"./core.js\";\n\n// ── Page ─────────────────────────────────────────────────────────────────\nexport type PageProps = {\n /** Render with a sidebar column. */\n sidebar?: boolean;\n /** Place the sidebar on the right (only meaningful with `sidebar: true`). */\n sidebarRight?: boolean;\n};\n\nexport const page = builder<PageProps>({\n tag: \"div\",\n base: \"klods-page\",\n modifiers: {\n sidebar: \"klods-page--with-sidebar\",\n sidebarRight: \"klods-page--sidebar-right\",\n },\n});\n\n// ── Page slots ───────────────────────────────────────────────────────────\nexport const header = builder({ tag: \"header\", base: \"klods-header\" });\nexport const sidebar = builder({ tag: \"aside\", base: \"klods-sidebar\" });\n\nexport type ContentProps = {\n /** Cap content width to --klods-content-max and centre it. */\n narrow?: boolean;\n};\nexport const content = builder<ContentProps>({\n tag: \"main\",\n base: \"klods-content\",\n modifiers: { narrow: \"klods-content--narrow\" },\n});\n\nexport const footer = builder({ tag: \"footer\", base: \"klods-footer\" });\n\n// ── Layout utilities ─────────────────────────────────────────────────────\ntype GapProp = { gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 };\n\nconst gapModifier = (prefix: string) => (v: number | undefined) =>\n v === undefined ? undefined : `${prefix}--gap-${v}`;\n\nexport const stack = builder<GapProp>({\n tag: \"div\",\n base: \"klods-stack\",\n modifiers: { gap: gapModifier(\"klods-stack\") },\n});\n\nexport const cluster = builder<GapProp>({\n tag: \"div\",\n base: \"klods-cluster\",\n modifiers: { gap: gapModifier(\"klods-cluster\") },\n});\n\nexport const row = builder<GapProp>({\n tag: \"div\",\n base: \"klods-row\",\n modifiers: { gap: gapModifier(\"klods-row\") },\n});\n\nexport type GridProps = GapProp & {\n cols?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Auto-fit responsive columns; pair with `--klods-grid-min` if you want a custom minimum. */\n fit?: boolean;\n};\nexport const grid = builder<GridProps>({\n tag: \"div\",\n base: \"klods-grid\",\n modifiers: {\n gap: gapModifier(\"klods-grid\"),\n cols: (v) => (v === undefined ? undefined : `klods-grid--cols-${v}`),\n fit: \"klods-grid--fit\",\n },\n});\n\nexport const center = builder({ tag: \"div\", base: \"klods-center\" });\nexport const spread = builder({ tag: \"div\", base: \"klods-spread\" });\n\n// ── Convenience: empty fragment-ish wrapper for quick text + nodes ──────\nexport function text(value: string | number): KlodsNode {\n // Wrap loose text in a span so it composes anywhere a KlodsNode is expected.\n return new KlodsNode(\"span\", {}, [String(value)]);\n}\n\n// Re-export attribute / child types so consumers can extend a builder neatly.\nexport type { KlodsAttrs, KlodsChild };\n"],"mappings":"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","names":["src_exports","__export","KlodsNode","alert","badge","builder","button","card","cardBody","cardFooter","cardTitle","center","classNames","cluster","content","el","footer","grid","header","lead","mergeClasses","muted","nav","navLink","navList","page","prose","raw","row","sidebar","spread","stack","text","VOID_TAGS","RAW","raw","html","isRaw","value","escapeHtml","str","escapeAttr","classNames","input","v","k","mergeClasses","inputs","c","styleToString","style","m","flattenChildren","children","out","stack","next","KlodsNode","_KlodsNode","tag","attrs","__publicField","target","el","name","cls","child","tpl","parts","builder","options","base","modifiers","modifierMap","props","userProps","modClasses","passthrough","key","finalClass","resolvedChildren","nav","builder","navList","navLinkBuilder","navLink","props","children","el","card","cardTitle","cardBody","cardFooter","buttonBase","v","button","merged","badge","alertBase","alert","prose","muted","lead","page","builder","header","sidebar","content","footer","gapModifier","prefix","v","stack","cluster","row","grid","center","spread","text","value","KlodsNode"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core.ts","../src/components.ts","../src/layout.ts"],"sourcesContent":["// Public API surface for the `klods` package.\n\nexport * from \"./components.js\";\nexport * from \"./core.js\";\nexport * from \"./layout.js\";\n","// Core — a tiny VDOM-ish node with two faces:\n// - .render(target?) → HTMLElement (uses real DOM)\n// - .toString() → HTML string (works in Node / Rails / SSR)\n//\n// Both are produced from the same KlodsNode tree, so the docs site can show the\n// TS source, the rendered HTML and the live preview from one source of truth.\n\nexport type KlodsChild = string | number | bigint | boolean | null | undefined | KlodsNode | Node | KlodsChild[];\n\nexport type KlodsAttrs = {\n class?: string | string[] | Record<string, boolean | undefined> | undefined;\n id?: string | undefined;\n style?: string | Partial<CSSStyleDeclaration> | undefined;\n [key: `data-${string}`]: string | number | boolean | undefined;\n [key: `aria-${string}`]: string | number | boolean | undefined;\n // Allow any other HTML attribute or DOM event handler (onClick, onInput, …).\n [key: string]: unknown;\n};\n\nconst VOID_TAGS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"source\",\n \"track\",\n \"wbr\",\n]);\n\nconst RAW = Symbol(\"klods.raw\");\n\ntype RawHtml = { [RAW]: true; html: string };\n\n/** Mark a string as already-escaped HTML; pass it as a child to inject as-is. */\nexport function raw(html: string): RawHtml {\n return { [RAW]: true, html };\n}\n\nfunction isRaw(value: unknown): value is RawHtml {\n return typeof value === \"object\" && value !== null && (value as { [RAW]?: unknown })[RAW] === true;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction escapeAttr(str: string): string {\n return str.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\");\n}\n\n/** Normalise a `class` value (string | array | record) into a clean string. */\nexport function classNames(input: KlodsAttrs[\"class\"]): string {\n if (!input) return \"\";\n if (typeof input === \"string\") return input.trim();\n if (Array.isArray(input)) return input.filter(Boolean).join(\" \").trim();\n return Object.entries(input)\n .filter(([, v]) => Boolean(v))\n .map(([k]) => k)\n .join(\" \")\n .trim();\n}\n\n/** Merge two class values (used internally to combine builder defaults + user-supplied). */\nexport function mergeClasses(...inputs: Array<KlodsAttrs[\"class\"]>): string {\n return inputs\n .map((c) => classNames(c))\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction styleToString(style: string | Partial<CSSStyleDeclaration>): string {\n if (typeof style === \"string\") return style;\n return Object.entries(style)\n .filter(([, v]) => v !== undefined && v !== null && v !== \"\")\n .map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}:${String(v)}`)\n .join(\";\");\n}\n\nfunction flattenChildren(children: KlodsChild | KlodsChild[]): Array<Exclude<KlodsChild, KlodsChild[]>> {\n const out: Array<Exclude<KlodsChild, KlodsChild[]>> = [];\n const stack: KlodsChild[] = Array.isArray(children) ? [...children] : [children];\n while (stack.length) {\n const next = stack.shift();\n if (Array.isArray(next)) stack.unshift(...next);\n else if (next !== null && next !== undefined && next !== false && next !== true) out.push(next);\n }\n return out;\n}\n\nexport class KlodsNode {\n readonly tag: string;\n readonly attrs: KlodsAttrs;\n readonly children: KlodsChild[];\n\n constructor(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []) {\n this.tag = tag;\n this.attrs = attrs;\n this.children = Array.isArray(children) ? children : [children];\n }\n\n /** Render to a real DOM element. If `target` is given, append to it. */\n render(target?: Element | null): HTMLElement {\n const el = document.createElement(this.tag);\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) el.setAttribute(\"class\", cls);\n continue;\n }\n if (name === \"style\") {\n el.setAttribute(\"style\", styleToString(value as string | Partial<CSSStyleDeclaration>));\n continue;\n }\n if (name.startsWith(\"on\") && typeof value === \"function\") {\n el.addEventListener(name.slice(2).toLowerCase(), value as EventListener);\n continue;\n }\n if (value === true) {\n el.setAttribute(name, \"\");\n continue;\n }\n el.setAttribute(name, String(value));\n }\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) el.appendChild(child.render());\n else if (typeof child === \"object\" && child !== null && \"nodeType\" in child) {\n el.appendChild(child as Node);\n } else if (isRaw(child)) {\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = child.html;\n el.appendChild(tpl.content);\n } else {\n el.appendChild(document.createTextNode(String(child)));\n }\n }\n if (target) target.appendChild(el);\n return el;\n }\n\n /** Render to a string of HTML. */\n toString(): string {\n const parts: string[] = [`<${this.tag}`];\n for (const [name, value] of Object.entries(this.attrs)) {\n if (value === undefined || value === null || value === false) continue;\n if (name === \"children\") continue;\n if (name.startsWith(\"on\") && typeof value === \"function\") continue;\n if (name === \"class\") {\n const cls = classNames(value as KlodsAttrs[\"class\"]);\n if (cls) parts.push(` class=\"${escapeAttr(cls)}\"`);\n continue;\n }\n if (name === \"style\") {\n parts.push(` style=\"${escapeAttr(styleToString(value as string | Partial<CSSStyleDeclaration>))}\"`);\n continue;\n }\n if (value === true) {\n parts.push(` ${name}`);\n continue;\n }\n parts.push(` ${name}=\"${escapeAttr(String(value))}\"`);\n }\n if (VOID_TAGS.has(this.tag)) {\n parts.push(\" />\");\n return parts.join(\"\");\n }\n parts.push(\">\");\n for (const child of flattenChildren(this.children)) {\n if (child instanceof KlodsNode) parts.push(child.toString());\n else if (isRaw(child)) parts.push(child.html);\n else if (typeof child === \"object\" && child !== null && \"outerHTML\" in child) {\n parts.push((child as Element).outerHTML);\n } else {\n parts.push(escapeHtml(String(child)));\n }\n }\n parts.push(`</${this.tag}>`);\n return parts.join(\"\");\n }\n}\n\n/**\n * Generic element builder. Most consumers use the named builders (page, header, …)\n * rather than calling `el` directly, but it's exported as an escape hatch.\n */\nexport function el(tag: string, attrs: KlodsAttrs = {}, children: KlodsChild | KlodsChild[] = []): KlodsNode {\n return new KlodsNode(tag, attrs, children);\n}\n\n/**\n * Factory that produces a typed builder for a tag with a base class. Modifier\n * props are converted into `--modifier` BEM classes and stripped from the output\n * attributes; everything else passes through untouched, so consumers can attach\n * arbitrary `id`, `data-*`, `aria-*`, event handlers, `style`, etc.\n */\nexport function builder<P extends Record<string, unknown> = Record<never, never>>(options: {\n tag: string;\n base: string;\n /** Map of prop name → class (or function returning a class) when the prop is truthy. */\n modifiers?: { [K in keyof P]?: string | ((value: P[K]) => string | undefined) };\n}): (props?: (P & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]) => KlodsNode {\n const { tag, base, modifiers = {} } = options;\n const modifierMap = modifiers as Record<string, string | ((value: unknown) => string | undefined) | undefined>;\n return (props, children) => {\n const userProps = (props ?? {}) as P & KlodsAttrs;\n const modClasses: string[] = [];\n const passthrough: KlodsAttrs = {};\n for (const [key, value] of Object.entries(userProps)) {\n const m = modifierMap[key];\n if (m !== undefined) {\n if (typeof m === \"function\") {\n const c = m(value);\n if (c) modClasses.push(c);\n } else if (value) {\n modClasses.push(m);\n }\n } else {\n passthrough[key] = value;\n }\n }\n const finalClass = mergeClasses(base, ...modClasses, userProps.class);\n const resolvedChildren =\n children !== undefined ? children : ((userProps.children as KlodsChild | KlodsChild[] | undefined) ?? []);\n delete passthrough.children;\n return new KlodsNode(tag, { ...passthrough, class: finalClass || undefined }, resolvedChildren);\n };\n}\n","// First wave of components: nav, card, button, badge, alert, prose helpers.\n// All match the BEM classes shipped by klods-css.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, el, KlodsNode } from \"./core.js\";\n\n// ── Nav ──────────────────────────────────────────────────────────────────\nexport const nav = builder({ tag: \"nav\", base: \"klods-nav\" });\nexport const navList = builder({ tag: \"ul\", base: \"klods-nav__list\" });\n\nexport type NavLinkProps = {\n href?: string;\n active?: boolean;\n};\nconst navLinkBuilder = builder<NavLinkProps>({\n tag: \"a\",\n base: \"klods-nav__link\",\n modifiers: { active: \"klods-nav__link--active\" },\n});\nexport function navLink(props?: (NavLinkProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Wrap each link in <li> so it's idiomatic inside <ul class=\"klods-nav__list\">.\n return el(\"li\", {}, [navLinkBuilder(props ?? null, children)]);\n}\n\n// ── Card ─────────────────────────────────────────────────────────────────\nexport type CardProps = {\n elevated?: boolean;\n};\nexport const card = builder<CardProps>({\n tag: \"div\",\n base: \"klods-card\",\n modifiers: { elevated: \"klods-card--elevated\" },\n});\nexport const cardTitle = builder({ tag: \"h3\", base: \"klods-card__title\" });\nexport const cardBody = builder({ tag: \"div\", base: \"klods-card__body\" });\nexport const cardFooter = builder({ tag: \"div\", base: \"klods-card__footer\" });\n\n// ── Button ───────────────────────────────────────────────────────────────\nexport type ButtonProps = {\n variant?: \"default\" | \"primary\" | \"danger\" | \"ghost\";\n type?: \"button\" | \"submit\" | \"reset\";\n};\nconst buttonBase = builder<ButtonProps>({\n tag: \"button\",\n base: \"klods-button\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-button--${v}` : undefined),\n },\n});\nexport function button(props?: (ButtonProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // Default `type=\"button\"` so it never accidentally submits a form.\n const merged = { type: \"button\", ...(props ?? {}) } as ButtonProps & KlodsAttrs;\n return buttonBase(merged, children);\n}\n\n// ── Badge ────────────────────────────────────────────────────────────────\nexport type BadgeProps = {\n variant?: \"default\" | \"accent\" | \"success\" | \"danger\";\n};\nexport const badge = builder<BadgeProps>({\n tag: \"span\",\n base: \"klods-badge\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-badge--${v}` : undefined),\n },\n});\n\n// ── Alert ────────────────────────────────────────────────────────────────\nexport type AlertProps = {\n variant?: \"default\" | \"info\" | \"success\" | \"warning\" | \"danger\";\n};\nconst alertBase = builder<AlertProps>({\n tag: \"div\",\n base: \"klods-alert\",\n modifiers: {\n variant: (v) => (v && v !== \"default\" ? `klods-alert--${v}` : undefined),\n },\n});\nexport function alert(props?: (AlertProps & KlodsAttrs) | null, children?: KlodsChild | KlodsChild[]): KlodsNode {\n // role=alert by default for assistive tech, overridable.\n const merged = { role: \"alert\", ...(props ?? {}) } as AlertProps & KlodsAttrs;\n return alertBase(merged, children);\n}\n\n// ── Prose helpers ────────────────────────────────────────────────────────\nexport const prose = builder({ tag: \"div\", base: \"klods-prose\" });\nexport const muted = builder({ tag: \"span\", base: \"klods-muted\" });\nexport const lead = builder({ tag: \"p\", base: \"klods-lead\" });\n\n// ── Table ────────────────────────────────────────────────────────────────\nexport type TableProps = {\n striped?: boolean;\n dense?: boolean;\n};\nexport const table = builder<TableProps>({\n tag: \"table\",\n base: \"klods-table\",\n modifiers: {\n striped: \"klods-table--striped\",\n dense: \"klods-table--dense\",\n },\n});\nexport const thead = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"thead\", attrs ?? {}, children);\nexport const tbody = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"tbody\", attrs ?? {}, children);\nexport const tr = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"tr\", attrs ?? {}, children);\nexport const th = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"th\", attrs ?? {}, children);\nexport const td = (attrs?: KlodsAttrs | null, children?: KlodsChild | KlodsChild[]): KlodsNode =>\n el(\"td\", attrs ?? {}, children);\n\n// ── Code ─────────────────────────────────────────────────────────────────\nexport function codeBlock(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode {\n return el(\"pre\", attrs ?? {}, el(\"code\", {}, content));\n}\nexport function inlineCode(attrs?: KlodsAttrs | null, content?: KlodsChild | KlodsChild[]): KlodsNode {\n return el(\"code\", attrs ?? {}, content);\n}\n\n// ── Box ──────────────────────────────────────────────────────────────────\nexport const box = builder({ tag: \"div\", base: \"klods-box\" });\n","// Layout builders — the four corners and the \"I-always-forget\" utilities.\n// Each builder is a thin wrapper around `builder()` from core.ts.\n\nimport type { KlodsAttrs, KlodsChild } from \"./core.js\";\nimport { builder, KlodsNode } from \"./core.js\";\n\n// ── Page ─────────────────────────────────────────────────────────────────\nexport type PageProps = {\n /** Render with a sidebar column. */\n sidebar?: boolean;\n /** Place the sidebar on the right (only meaningful with `sidebar: true`). */\n sidebarRight?: boolean;\n /** Keep the header pinned to the top of the viewport while the page scrolls. */\n stickyHeader?: boolean;\n};\n\nexport const page = builder<PageProps>({\n tag: \"div\",\n base: \"klods-page\",\n modifiers: {\n sidebar: \"klods-page--with-sidebar\",\n sidebarRight: \"klods-page--sidebar-right\",\n stickyHeader: \"klods-page--sticky-header\",\n },\n});\n\n// ── Page slots ───────────────────────────────────────────────────────────\nexport const header = builder({ tag: \"header\", base: \"klods-header\" });\nexport const sidebar = builder({ tag: \"aside\", base: \"klods-sidebar\" });\n\nexport type ContentProps = {\n /** Cap content width to --klods-content-max and centre it. */\n narrow?: boolean;\n};\nexport const content = builder<ContentProps>({\n tag: \"main\",\n base: \"klods-content\",\n modifiers: { narrow: \"klods-content--narrow\" },\n});\n\nexport const footer = builder({ tag: \"footer\", base: \"klods-footer\" });\n\n// ── Layout utilities ─────────────────────────────────────────────────────\ntype GapProp = { gap?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 };\n\nconst gapModifier = (prefix: string) => (v: number | undefined) =>\n v === undefined ? undefined : `${prefix}--gap-${v}`;\n\nexport const stack = builder<GapProp>({\n tag: \"div\",\n base: \"klods-stack\",\n modifiers: { gap: gapModifier(\"klods-stack\") },\n});\n\nexport const cluster = builder<GapProp>({\n tag: \"div\",\n base: \"klods-cluster\",\n modifiers: { gap: gapModifier(\"klods-cluster\") },\n});\n\nexport const row = builder<GapProp>({\n tag: \"div\",\n base: \"klods-row\",\n modifiers: { gap: gapModifier(\"klods-row\") },\n});\n\nexport type GridProps = GapProp & {\n cols?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Auto-fit responsive columns; pair with `--klods-grid-min` if you want a custom minimum. */\n fit?: boolean;\n};\nexport const grid = builder<GridProps>({\n tag: \"div\",\n base: \"klods-grid\",\n modifiers: {\n gap: gapModifier(\"klods-grid\"),\n cols: (v) => (v === undefined ? undefined : `klods-grid--cols-${v}`),\n fit: \"klods-grid--fit\",\n },\n});\n\nexport const center = builder({ tag: \"div\", base: \"klods-center\" });\nexport const spread = builder({ tag: \"div\", base: \"klods-spread\" });\n\n// ── Convenience: empty fragment-ish wrapper for quick text + nodes ──────\nexport function text(value: string | number): KlodsNode {\n // Wrap loose text in a span so it composes anywhere a KlodsNode is expected.\n return new KlodsNode(\"span\", {}, [String(value)]);\n}\n\n// Re-export attribute / child types so consumers can extend a builder neatly.\nexport type { KlodsAttrs, KlodsChild };\n"],"mappings":"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","names":["src_exports","__export","KlodsNode","alert","badge","box","builder","button","card","cardBody","cardFooter","cardTitle","center","classNames","cluster","codeBlock","content","el","footer","grid","header","inlineCode","lead","mergeClasses","muted","nav","navLink","navList","page","prose","raw","row","sidebar","spread","stack","table","tbody","td","text","th","thead","tr","VOID_TAGS","RAW","raw","html","isRaw","value","escapeHtml","str","escapeAttr","classNames","input","v","k","mergeClasses","inputs","c","styleToString","style","m","flattenChildren","children","out","stack","next","KlodsNode","_KlodsNode","tag","attrs","__publicField","target","el","name","cls","child","tpl","parts","builder","options","base","modifiers","modifierMap","props","userProps","modClasses","passthrough","key","finalClass","resolvedChildren","nav","builder","navList","navLinkBuilder","navLink","props","children","el","card","cardTitle","cardBody","cardFooter","buttonBase","v","button","merged","badge","alertBase","alert","prose","muted","lead","table","thead","attrs","tbody","tr","th","td","codeBlock","content","inlineCode","box","page","builder","header","sidebar","content","footer","gapModifier","prefix","v","stack","cluster","row","grid","center","spread","text","value","KlodsNode"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klods-js",
3
- "version": "1.0.3",
3
+ "version": "1.2.0",
4
4
  "description": "Tiny, typed, lego-like builder API for klods components.",
5
5
  "license": "MIT",
6
6
  "author": "Drue Wilding",