@lukas_holdings/castdom 1.0.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +707 -0
  3. package/bin/castdom.js +2 -0
  4. package/dist/astro.cjs +86 -0
  5. package/dist/astro.cjs.map +1 -0
  6. package/dist/astro.d.cts +88 -0
  7. package/dist/astro.d.ts +88 -0
  8. package/dist/astro.js +80 -0
  9. package/dist/astro.js.map +1 -0
  10. package/dist/chunk-COLESJ66.js +57 -0
  11. package/dist/chunk-COLESJ66.js.map +1 -0
  12. package/dist/chunk-EJRNKHL5.js +31 -0
  13. package/dist/chunk-EJRNKHL5.js.map +1 -0
  14. package/dist/chunk-JRQ6EVQP.cjs +35 -0
  15. package/dist/chunk-JRQ6EVQP.cjs.map +1 -0
  16. package/dist/chunk-KGLTVTHU.js +73 -0
  17. package/dist/chunk-KGLTVTHU.js.map +1 -0
  18. package/dist/chunk-O4OOMGGM.cjs +198 -0
  19. package/dist/chunk-O4OOMGGM.cjs.map +1 -0
  20. package/dist/chunk-ONS533CQ.js +104 -0
  21. package/dist/chunk-ONS533CQ.js.map +1 -0
  22. package/dist/chunk-ORY4OMZ5.cjs +110 -0
  23. package/dist/chunk-ORY4OMZ5.cjs.map +1 -0
  24. package/dist/chunk-QLEBTZIB.cjs +64 -0
  25. package/dist/chunk-QLEBTZIB.cjs.map +1 -0
  26. package/dist/chunk-XS5HAU5E.cjs +109 -0
  27. package/dist/chunk-XS5HAU5E.cjs.map +1 -0
  28. package/dist/chunk-YDT4TPB7.cjs +84 -0
  29. package/dist/chunk-YDT4TPB7.cjs.map +1 -0
  30. package/dist/chunk-ZBJB7WVV.js +193 -0
  31. package/dist/chunk-ZBJB7WVV.js.map +1 -0
  32. package/dist/chunk-ZWZ5ZLJE.js +103 -0
  33. package/dist/chunk-ZWZ5ZLJE.js.map +1 -0
  34. package/dist/cli.js +135 -0
  35. package/dist/index.cjs +540 -0
  36. package/dist/index.cjs.map +1 -0
  37. package/dist/index.d.cts +176 -0
  38. package/dist/index.d.ts +176 -0
  39. package/dist/index.js +440 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/next.cjs +65 -0
  42. package/dist/next.cjs.map +1 -0
  43. package/dist/next.d.cts +72 -0
  44. package/dist/next.d.ts +72 -0
  45. package/dist/next.js +48 -0
  46. package/dist/next.js.map +1 -0
  47. package/dist/react.cjs +30 -0
  48. package/dist/react.cjs.map +1 -0
  49. package/dist/react.d.cts +70 -0
  50. package/dist/react.d.ts +70 -0
  51. package/dist/react.js +7 -0
  52. package/dist/react.js.map +1 -0
  53. package/dist/renderer-B1R7u2wm.d.ts +30 -0
  54. package/dist/renderer-Bfzjr6l9.d.cts +30 -0
  55. package/dist/ssr.cjs +46 -0
  56. package/dist/ssr.cjs.map +1 -0
  57. package/dist/ssr.d.cts +83 -0
  58. package/dist/ssr.d.ts +83 -0
  59. package/dist/ssr.js +5 -0
  60. package/dist/ssr.js.map +1 -0
  61. package/dist/types-ChD5jENU.d.cts +105 -0
  62. package/dist/types-ChD5jENU.d.ts +105 -0
  63. package/dist/vite.cjs +83 -0
  64. package/dist/vite.cjs.map +1 -0
  65. package/dist/vite.d.cts +81 -0
  66. package/dist/vite.d.ts +81 -0
  67. package/dist/vite.js +77 -0
  68. package/dist/vite.js.map +1 -0
  69. package/package.json +130 -0
package/dist/astro.cjs ADDED
@@ -0,0 +1,86 @@
1
+ 'use strict';
2
+
3
+ var chunkYDT4TPB7_cjs = require('./chunk-YDT4TPB7.cjs');
4
+ var chunkQLEBTZIB_cjs = require('./chunk-QLEBTZIB.cjs');
5
+ var chunkXS5HAU5E_cjs = require('./chunk-XS5HAU5E.cjs');
6
+ require('./chunk-JRQ6EVQP.cjs');
7
+
8
+ // src/adapters/astro.ts
9
+ function castdomIntegration(options) {
10
+ return {
11
+ name: "castdom",
12
+ hooks: {
13
+ "astro:config:setup"({ injectScript }) {
14
+ const manifestPath = options?.manifestPath ?? ".castdom/manifest.json";
15
+ injectScript(
16
+ "page-ssr",
17
+ `import manifest from "${manifestPath}" with { type: "json" };
18
+ import { loadManifest } from "castdom";
19
+ loadManifest(manifest);`
20
+ );
21
+ },
22
+ "astro:build:done"() {
23
+ }
24
+ }
25
+ };
26
+ }
27
+ function skeleton(name, config) {
28
+ const entry = chunkYDT4TPB7_cjs.get(name);
29
+ if (!entry) {
30
+ return { html: "", css: "", exists: false };
31
+ }
32
+ const html = chunkQLEBTZIB_cjs.renderSkeleton(entry.data, { config });
33
+ const css = chunkXS5HAU5E_cjs.generateCriticalCSS([entry.data], config);
34
+ return { html, css, exists: true };
35
+ }
36
+ function generateAstroComponent(name, config) {
37
+ return `---
38
+ import { skeleton } from "castdom/astro";
39
+ const { html, css } = skeleton("${name}");
40
+ ---
41
+
42
+ <style set:html={css}></style>
43
+ <div data-castdom="${name}">
44
+ <Fragment set:html={html} />
45
+ <slot />
46
+ </div>
47
+
48
+ <script>
49
+ // Hydration: remove skeleton when slot content renders
50
+ const wrapper = document.querySelector('[data-castdom="${name}"]');
51
+ if (wrapper) {
52
+ const skeleton = wrapper.querySelector('.castdom-skeleton');
53
+ if (skeleton && wrapper.children.length > 1) {
54
+ skeleton.remove();
55
+ }
56
+ }
57
+ </script>
58
+ `;
59
+ }
60
+ function viewTransitionProps(name) {
61
+ return {
62
+ "transition:persist": "",
63
+ "data-castdom": name,
64
+ "transition:name": `castdom-${name}`
65
+ };
66
+ }
67
+ function head(skeletonNames, config) {
68
+ const skeletons = [];
69
+ for (const name of skeletonNames) {
70
+ const entry = chunkYDT4TPB7_cjs.get(name);
71
+ if (entry) skeletons.push(entry.data);
72
+ }
73
+ if (skeletons.length === 0) return "";
74
+ return [
75
+ chunkQLEBTZIB_cjs.renderCriticalStyleTag(skeletons, config),
76
+ chunkQLEBTZIB_cjs.renderHydrationScript()
77
+ ].join("\n");
78
+ }
79
+
80
+ exports.castdomIntegration = castdomIntegration;
81
+ exports.generateAstroComponent = generateAstroComponent;
82
+ exports.head = head;
83
+ exports.skeleton = skeleton;
84
+ exports.viewTransitionProps = viewTransitionProps;
85
+ //# sourceMappingURL=astro.cjs.map
86
+ //# sourceMappingURL=astro.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/astro.ts"],"names":["get","renderSkeleton","generateCriticalCSS","renderCriticalStyleTag","renderHydrationScript"],"mappings":";;;;;;;;AA0CO,SAAS,mBAAmB,OAAA,EAGhC;AACD,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,SAAA;AAAA,IACN,KAAA,EAAO;AAAA,MACL,oBAAA,CAAqB,EAAE,YAAA,EAAa,EAA+D;AAEjG,QAAA,MAAM,YAAA,GAAe,SAAS,YAAA,IAAgB,wBAAA;AAC9C,QAAA,YAAA;AAAA,UACE,UAAA;AAAA,UACA,yBAAyB,YAAY,CAAA;AAAA;AAAA,uBAAA;AAAA,SACvC;AAAA,MACF,CAAA;AAAA,MAEA,kBAAA,GAAqB;AAAA,MAErB;AAAA;AACF,GACF;AACF;AAcO,SAAS,QAAA,CACd,MACA,MAAA,EACgD;AAChD,EAAA,MAAM,KAAA,GAAQA,sBAAgB,IAAI,CAAA;AAElC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAO,EAAE,IAAA,EAAM,EAAA,EAAI,GAAA,EAAK,EAAA,EAAI,QAAQ,KAAA,EAAM;AAAA,EAC5C;AAEA,EAAA,MAAM,OAAOC,gCAAA,CAAe,KAAA,CAAM,IAAA,EAAM,EAAE,QAAQ,CAAA;AAClD,EAAA,MAAM,MAAMC,qCAAA,CAAoB,CAAC,KAAA,CAAM,IAAI,GAAG,MAAM,CAAA;AAEpD,EAAA,OAAO,EAAE,IAAA,EAAM,GAAA,EAAK,MAAA,EAAQ,IAAA,EAAK;AACnC;AAMO,SAAS,sBAAA,CACd,MACA,MAAA,EACQ;AACR,EAAA,OAAO,CAAA;AAAA;AAAA,gCAAA,EAEyB,IAAI,CAAA;AAAA;;AAAA;AAAA,mBAAA,EAIjB,IAAI,CAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,yDAAA,EAOkC,IAAI,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAS/D;AAWO,SAAS,oBAAoB,IAAA,EAAsC;AACxE,EAAA,OAAO;AAAA,IACL,oBAAA,EAAsB,EAAA;AAAA,IACtB,cAAA,EAAgB,IAAA;AAAA,IAChB,iBAAA,EAAmB,WAAW,IAAI,CAAA;AAAA,GACpC;AACF;AAMO,SAAS,IAAA,CACd,eACA,MAAA,EACQ;AACR,EAAA,MAAM,YAA4B,EAAC;AAEnC,EAAA,KAAA,MAAW,QAAQ,aAAA,EAAe;AAChC,IAAA,MAAM,KAAA,GAAQF,sBAAgB,IAAI,CAAA;AAClC,IAAA,IAAI,KAAA,EAAO,SAAA,CAAU,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAAA,EACtC;AAEA,EAAA,IAAI,SAAA,CAAU,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA;AAEnC,EAAA,OAAO;AAAA,IACLG,wCAAA,CAAuB,WAAW,MAAM,CAAA;AAAA,IACxCC,uCAAA;AAAsB,GACxB,CAAE,KAAK,IAAI,CAAA;AACb","file":"astro.cjs","sourcesContent":["import type { SkeletonData, CastDOMConfig } from \"../core/types.js\";\nimport { renderSkeleton, renderCriticalStyleTag, renderHydrationScript } from \"../seo/ssr.js\";\nimport { get as getFromRegistry, loadManifest } from \"../core/registry.js\";\nimport { generateCriticalCSS } from \"../core/renderer.js\";\nimport { renderStandalone } from \"../core/renderer.js\";\n\n/**\n * Astro adapter for CastDOM.\n *\n * Supports:\n * - Astro components (SSG and SSR)\n * - Island-aware skeletons (client:load, client:idle, client:visible)\n * - Automatic <style> injection\n * - View Transitions integration\n *\n * Usage:\n * ```astro\n * ---\n * // src/components/UserCard.astro\n * import { skeleton } from \"castdom/astro\";\n * const { html, css } = skeleton(\"user-card\");\n * ---\n *\n * <style set:html={css}></style>\n * <div class=\"user-card-wrapper\" data-castdom=\"user-card\">\n * <Fragment set:html={html} />\n * </div>\n * ```\n */\n\n/**\n * Astro integration for CastDOM.\n * Add to your astro.config.mjs:\n *\n * ```js\n * import { castdomIntegration } from \"castdom/astro\";\n *\n * export default defineConfig({\n * integrations: [castdomIntegration()],\n * });\n * ```\n */\nexport function castdomIntegration(options?: {\n manifestPath?: string;\n config?: Partial<CastDOMConfig>;\n}) {\n return {\n name: \"castdom\",\n hooks: {\n \"astro:config:setup\"({ injectScript }: { injectScript: (stage: string, content: string) => void }) {\n // Inject the registry loader on the client side\n const manifestPath = options?.manifestPath ?? \".castdom/manifest.json\";\n injectScript(\n \"page-ssr\",\n `import manifest from \"${manifestPath}\" with { type: \"json\" };\\nimport { loadManifest } from \"castdom\";\\nloadManifest(manifest);`\n );\n },\n\n \"astro:build:done\"() {\n // Could run extraction here if dev server is available\n },\n },\n };\n}\n\n/**\n * Get skeleton HTML and CSS for use in Astro components.\n *\n * ```astro\n * ---\n * import { skeleton } from \"castdom/astro\";\n * const sk = skeleton(\"user-card\");\n * ---\n *\n * {sk.html && <Fragment set:html={sk.html} />}\n * ```\n */\nexport function skeleton(\n name: string,\n config?: Partial<CastDOMConfig>\n): { html: string; css: string; exists: boolean } {\n const entry = getFromRegistry(name);\n\n if (!entry) {\n return { html: \"\", css: \"\", exists: false };\n }\n\n const html = renderSkeleton(entry.data, { config });\n const css = generateCriticalCSS([entry.data], config);\n\n return { html, css, exists: true };\n}\n\n/**\n * Generate a complete Astro component string for a skeleton.\n * Useful for programmatic component generation.\n */\nexport function generateAstroComponent(\n name: string,\n config?: Partial<CastDOMConfig>\n): string {\n return `---\nimport { skeleton } from \"castdom/astro\";\nconst { html, css } = skeleton(\"${name}\");\n---\n\n<style set:html={css}></style>\n<div data-castdom=\"${name}\">\n <Fragment set:html={html} />\n <slot />\n</div>\n\n<script>\n // Hydration: remove skeleton when slot content renders\n const wrapper = document.querySelector('[data-castdom=\"${name}\"]');\n if (wrapper) {\n const skeleton = wrapper.querySelector('.castdom-skeleton');\n if (skeleton && wrapper.children.length > 1) {\n skeleton.remove();\n }\n }\n</script>\n`;\n}\n\n/**\n * View Transitions helper — preserves skeleton state during navigation.\n *\n * ```astro\n * <div transition:persist data-castdom=\"sidebar\">\n * <Fragment set:html={skeleton(\"sidebar\").html} />\n * </div>\n * ```\n */\nexport function viewTransitionProps(name: string): Record<string, string> {\n return {\n \"transition:persist\": \"\",\n \"data-castdom\": name,\n \"transition:name\": `castdom-${name}`,\n };\n}\n\n/**\n * Generate <head> content for Astro pages.\n * Include in your Layout component.\n */\nexport function head(\n skeletonNames: string[],\n config?: Partial<CastDOMConfig>\n): string {\n const skeletons: SkeletonData[] = [];\n\n for (const name of skeletonNames) {\n const entry = getFromRegistry(name);\n if (entry) skeletons.push(entry.data);\n }\n\n if (skeletons.length === 0) return \"\";\n\n return [\n renderCriticalStyleTag(skeletons, config),\n renderHydrationScript(),\n ].join(\"\\n\");\n}\n"]}
@@ -0,0 +1,88 @@
1
+ import { C as CastDOMConfig } from './types-ChD5jENU.cjs';
2
+
3
+ /**
4
+ * Astro adapter for CastDOM.
5
+ *
6
+ * Supports:
7
+ * - Astro components (SSG and SSR)
8
+ * - Island-aware skeletons (client:load, client:idle, client:visible)
9
+ * - Automatic <style> injection
10
+ * - View Transitions integration
11
+ *
12
+ * Usage:
13
+ * ```astro
14
+ * ---
15
+ * // src/components/UserCard.astro
16
+ * import { skeleton } from "castdom/astro";
17
+ * const { html, css } = skeleton("user-card");
18
+ * ---
19
+ *
20
+ * <style set:html={css}></style>
21
+ * <div class="user-card-wrapper" data-castdom="user-card">
22
+ * <Fragment set:html={html} />
23
+ * </div>
24
+ * ```
25
+ */
26
+ /**
27
+ * Astro integration for CastDOM.
28
+ * Add to your astro.config.mjs:
29
+ *
30
+ * ```js
31
+ * import { castdomIntegration } from "castdom/astro";
32
+ *
33
+ * export default defineConfig({
34
+ * integrations: [castdomIntegration()],
35
+ * });
36
+ * ```
37
+ */
38
+ declare function castdomIntegration(options?: {
39
+ manifestPath?: string;
40
+ config?: Partial<CastDOMConfig>;
41
+ }): {
42
+ name: string;
43
+ hooks: {
44
+ "astro:config:setup"({ injectScript }: {
45
+ injectScript: (stage: string, content: string) => void;
46
+ }): void;
47
+ "astro:build:done"(): void;
48
+ };
49
+ };
50
+ /**
51
+ * Get skeleton HTML and CSS for use in Astro components.
52
+ *
53
+ * ```astro
54
+ * ---
55
+ * import { skeleton } from "castdom/astro";
56
+ * const sk = skeleton("user-card");
57
+ * ---
58
+ *
59
+ * {sk.html && <Fragment set:html={sk.html} />}
60
+ * ```
61
+ */
62
+ declare function skeleton(name: string, config?: Partial<CastDOMConfig>): {
63
+ html: string;
64
+ css: string;
65
+ exists: boolean;
66
+ };
67
+ /**
68
+ * Generate a complete Astro component string for a skeleton.
69
+ * Useful for programmatic component generation.
70
+ */
71
+ declare function generateAstroComponent(name: string, config?: Partial<CastDOMConfig>): string;
72
+ /**
73
+ * View Transitions helper — preserves skeleton state during navigation.
74
+ *
75
+ * ```astro
76
+ * <div transition:persist data-castdom="sidebar">
77
+ * <Fragment set:html={skeleton("sidebar").html} />
78
+ * </div>
79
+ * ```
80
+ */
81
+ declare function viewTransitionProps(name: string): Record<string, string>;
82
+ /**
83
+ * Generate <head> content for Astro pages.
84
+ * Include in your Layout component.
85
+ */
86
+ declare function head(skeletonNames: string[], config?: Partial<CastDOMConfig>): string;
87
+
88
+ export { castdomIntegration, generateAstroComponent, head, skeleton, viewTransitionProps };
@@ -0,0 +1,88 @@
1
+ import { C as CastDOMConfig } from './types-ChD5jENU.js';
2
+
3
+ /**
4
+ * Astro adapter for CastDOM.
5
+ *
6
+ * Supports:
7
+ * - Astro components (SSG and SSR)
8
+ * - Island-aware skeletons (client:load, client:idle, client:visible)
9
+ * - Automatic <style> injection
10
+ * - View Transitions integration
11
+ *
12
+ * Usage:
13
+ * ```astro
14
+ * ---
15
+ * // src/components/UserCard.astro
16
+ * import { skeleton } from "castdom/astro";
17
+ * const { html, css } = skeleton("user-card");
18
+ * ---
19
+ *
20
+ * <style set:html={css}></style>
21
+ * <div class="user-card-wrapper" data-castdom="user-card">
22
+ * <Fragment set:html={html} />
23
+ * </div>
24
+ * ```
25
+ */
26
+ /**
27
+ * Astro integration for CastDOM.
28
+ * Add to your astro.config.mjs:
29
+ *
30
+ * ```js
31
+ * import { castdomIntegration } from "castdom/astro";
32
+ *
33
+ * export default defineConfig({
34
+ * integrations: [castdomIntegration()],
35
+ * });
36
+ * ```
37
+ */
38
+ declare function castdomIntegration(options?: {
39
+ manifestPath?: string;
40
+ config?: Partial<CastDOMConfig>;
41
+ }): {
42
+ name: string;
43
+ hooks: {
44
+ "astro:config:setup"({ injectScript }: {
45
+ injectScript: (stage: string, content: string) => void;
46
+ }): void;
47
+ "astro:build:done"(): void;
48
+ };
49
+ };
50
+ /**
51
+ * Get skeleton HTML and CSS for use in Astro components.
52
+ *
53
+ * ```astro
54
+ * ---
55
+ * import { skeleton } from "castdom/astro";
56
+ * const sk = skeleton("user-card");
57
+ * ---
58
+ *
59
+ * {sk.html && <Fragment set:html={sk.html} />}
60
+ * ```
61
+ */
62
+ declare function skeleton(name: string, config?: Partial<CastDOMConfig>): {
63
+ html: string;
64
+ css: string;
65
+ exists: boolean;
66
+ };
67
+ /**
68
+ * Generate a complete Astro component string for a skeleton.
69
+ * Useful for programmatic component generation.
70
+ */
71
+ declare function generateAstroComponent(name: string, config?: Partial<CastDOMConfig>): string;
72
+ /**
73
+ * View Transitions helper — preserves skeleton state during navigation.
74
+ *
75
+ * ```astro
76
+ * <div transition:persist data-castdom="sidebar">
77
+ * <Fragment set:html={skeleton("sidebar").html} />
78
+ * </div>
79
+ * ```
80
+ */
81
+ declare function viewTransitionProps(name: string): Record<string, string>;
82
+ /**
83
+ * Generate <head> content for Astro pages.
84
+ * Include in your Layout component.
85
+ */
86
+ declare function head(skeletonNames: string[], config?: Partial<CastDOMConfig>): string;
87
+
88
+ export { castdomIntegration, generateAstroComponent, head, skeleton, viewTransitionProps };
package/dist/astro.js ADDED
@@ -0,0 +1,80 @@
1
+ import { get } from './chunk-KGLTVTHU.js';
2
+ import { renderSkeleton, renderCriticalStyleTag, renderHydrationScript } from './chunk-COLESJ66.js';
3
+ import { generateCriticalCSS } from './chunk-ZWZ5ZLJE.js';
4
+ import './chunk-EJRNKHL5.js';
5
+
6
+ // src/adapters/astro.ts
7
+ function castdomIntegration(options) {
8
+ return {
9
+ name: "castdom",
10
+ hooks: {
11
+ "astro:config:setup"({ injectScript }) {
12
+ const manifestPath = options?.manifestPath ?? ".castdom/manifest.json";
13
+ injectScript(
14
+ "page-ssr",
15
+ `import manifest from "${manifestPath}" with { type: "json" };
16
+ import { loadManifest } from "castdom";
17
+ loadManifest(manifest);`
18
+ );
19
+ },
20
+ "astro:build:done"() {
21
+ }
22
+ }
23
+ };
24
+ }
25
+ function skeleton(name, config) {
26
+ const entry = get(name);
27
+ if (!entry) {
28
+ return { html: "", css: "", exists: false };
29
+ }
30
+ const html = renderSkeleton(entry.data, { config });
31
+ const css = generateCriticalCSS([entry.data], config);
32
+ return { html, css, exists: true };
33
+ }
34
+ function generateAstroComponent(name, config) {
35
+ return `---
36
+ import { skeleton } from "castdom/astro";
37
+ const { html, css } = skeleton("${name}");
38
+ ---
39
+
40
+ <style set:html={css}></style>
41
+ <div data-castdom="${name}">
42
+ <Fragment set:html={html} />
43
+ <slot />
44
+ </div>
45
+
46
+ <script>
47
+ // Hydration: remove skeleton when slot content renders
48
+ const wrapper = document.querySelector('[data-castdom="${name}"]');
49
+ if (wrapper) {
50
+ const skeleton = wrapper.querySelector('.castdom-skeleton');
51
+ if (skeleton && wrapper.children.length > 1) {
52
+ skeleton.remove();
53
+ }
54
+ }
55
+ </script>
56
+ `;
57
+ }
58
+ function viewTransitionProps(name) {
59
+ return {
60
+ "transition:persist": "",
61
+ "data-castdom": name,
62
+ "transition:name": `castdom-${name}`
63
+ };
64
+ }
65
+ function head(skeletonNames, config) {
66
+ const skeletons = [];
67
+ for (const name of skeletonNames) {
68
+ const entry = get(name);
69
+ if (entry) skeletons.push(entry.data);
70
+ }
71
+ if (skeletons.length === 0) return "";
72
+ return [
73
+ renderCriticalStyleTag(skeletons, config),
74
+ renderHydrationScript()
75
+ ].join("\n");
76
+ }
77
+
78
+ export { castdomIntegration, generateAstroComponent, head, skeleton, viewTransitionProps };
79
+ //# sourceMappingURL=astro.js.map
80
+ //# sourceMappingURL=astro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/astro.ts"],"names":[],"mappings":";;;;;;AA0CO,SAAS,mBAAmB,OAAA,EAGhC;AACD,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,SAAA;AAAA,IACN,KAAA,EAAO;AAAA,MACL,oBAAA,CAAqB,EAAE,YAAA,EAAa,EAA+D;AAEjG,QAAA,MAAM,YAAA,GAAe,SAAS,YAAA,IAAgB,wBAAA;AAC9C,QAAA,YAAA;AAAA,UACE,UAAA;AAAA,UACA,yBAAyB,YAAY,CAAA;AAAA;AAAA,uBAAA;AAAA,SACvC;AAAA,MACF,CAAA;AAAA,MAEA,kBAAA,GAAqB;AAAA,MAErB;AAAA;AACF,GACF;AACF;AAcO,SAAS,QAAA,CACd,MACA,MAAA,EACgD;AAChD,EAAA,MAAM,KAAA,GAAQ,IAAgB,IAAI,CAAA;AAElC,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAO,EAAE,IAAA,EAAM,EAAA,EAAI,GAAA,EAAK,EAAA,EAAI,QAAQ,KAAA,EAAM;AAAA,EAC5C;AAEA,EAAA,MAAM,OAAO,cAAA,CAAe,KAAA,CAAM,IAAA,EAAM,EAAE,QAAQ,CAAA;AAClD,EAAA,MAAM,MAAM,mBAAA,CAAoB,CAAC,KAAA,CAAM,IAAI,GAAG,MAAM,CAAA;AAEpD,EAAA,OAAO,EAAE,IAAA,EAAM,GAAA,EAAK,MAAA,EAAQ,IAAA,EAAK;AACnC;AAMO,SAAS,sBAAA,CACd,MACA,MAAA,EACQ;AACR,EAAA,OAAO,CAAA;AAAA;AAAA,gCAAA,EAEyB,IAAI,CAAA;AAAA;;AAAA;AAAA,mBAAA,EAIjB,IAAI,CAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,yDAAA,EAOkC,IAAI,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAS/D;AAWO,SAAS,oBAAoB,IAAA,EAAsC;AACxE,EAAA,OAAO;AAAA,IACL,oBAAA,EAAsB,EAAA;AAAA,IACtB,cAAA,EAAgB,IAAA;AAAA,IAChB,iBAAA,EAAmB,WAAW,IAAI,CAAA;AAAA,GACpC;AACF;AAMO,SAAS,IAAA,CACd,eACA,MAAA,EACQ;AACR,EAAA,MAAM,YAA4B,EAAC;AAEnC,EAAA,KAAA,MAAW,QAAQ,aAAA,EAAe;AAChC,IAAA,MAAM,KAAA,GAAQ,IAAgB,IAAI,CAAA;AAClC,IAAA,IAAI,KAAA,EAAO,SAAA,CAAU,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAAA,EACtC;AAEA,EAAA,IAAI,SAAA,CAAU,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA;AAEnC,EAAA,OAAO;AAAA,IACL,sBAAA,CAAuB,WAAW,MAAM,CAAA;AAAA,IACxC,qBAAA;AAAsB,GACxB,CAAE,KAAK,IAAI,CAAA;AACb","file":"astro.js","sourcesContent":["import type { SkeletonData, CastDOMConfig } from \"../core/types.js\";\nimport { renderSkeleton, renderCriticalStyleTag, renderHydrationScript } from \"../seo/ssr.js\";\nimport { get as getFromRegistry, loadManifest } from \"../core/registry.js\";\nimport { generateCriticalCSS } from \"../core/renderer.js\";\nimport { renderStandalone } from \"../core/renderer.js\";\n\n/**\n * Astro adapter for CastDOM.\n *\n * Supports:\n * - Astro components (SSG and SSR)\n * - Island-aware skeletons (client:load, client:idle, client:visible)\n * - Automatic <style> injection\n * - View Transitions integration\n *\n * Usage:\n * ```astro\n * ---\n * // src/components/UserCard.astro\n * import { skeleton } from \"castdom/astro\";\n * const { html, css } = skeleton(\"user-card\");\n * ---\n *\n * <style set:html={css}></style>\n * <div class=\"user-card-wrapper\" data-castdom=\"user-card\">\n * <Fragment set:html={html} />\n * </div>\n * ```\n */\n\n/**\n * Astro integration for CastDOM.\n * Add to your astro.config.mjs:\n *\n * ```js\n * import { castdomIntegration } from \"castdom/astro\";\n *\n * export default defineConfig({\n * integrations: [castdomIntegration()],\n * });\n * ```\n */\nexport function castdomIntegration(options?: {\n manifestPath?: string;\n config?: Partial<CastDOMConfig>;\n}) {\n return {\n name: \"castdom\",\n hooks: {\n \"astro:config:setup\"({ injectScript }: { injectScript: (stage: string, content: string) => void }) {\n // Inject the registry loader on the client side\n const manifestPath = options?.manifestPath ?? \".castdom/manifest.json\";\n injectScript(\n \"page-ssr\",\n `import manifest from \"${manifestPath}\" with { type: \"json\" };\\nimport { loadManifest } from \"castdom\";\\nloadManifest(manifest);`\n );\n },\n\n \"astro:build:done\"() {\n // Could run extraction here if dev server is available\n },\n },\n };\n}\n\n/**\n * Get skeleton HTML and CSS for use in Astro components.\n *\n * ```astro\n * ---\n * import { skeleton } from \"castdom/astro\";\n * const sk = skeleton(\"user-card\");\n * ---\n *\n * {sk.html && <Fragment set:html={sk.html} />}\n * ```\n */\nexport function skeleton(\n name: string,\n config?: Partial<CastDOMConfig>\n): { html: string; css: string; exists: boolean } {\n const entry = getFromRegistry(name);\n\n if (!entry) {\n return { html: \"\", css: \"\", exists: false };\n }\n\n const html = renderSkeleton(entry.data, { config });\n const css = generateCriticalCSS([entry.data], config);\n\n return { html, css, exists: true };\n}\n\n/**\n * Generate a complete Astro component string for a skeleton.\n * Useful for programmatic component generation.\n */\nexport function generateAstroComponent(\n name: string,\n config?: Partial<CastDOMConfig>\n): string {\n return `---\nimport { skeleton } from \"castdom/astro\";\nconst { html, css } = skeleton(\"${name}\");\n---\n\n<style set:html={css}></style>\n<div data-castdom=\"${name}\">\n <Fragment set:html={html} />\n <slot />\n</div>\n\n<script>\n // Hydration: remove skeleton when slot content renders\n const wrapper = document.querySelector('[data-castdom=\"${name}\"]');\n if (wrapper) {\n const skeleton = wrapper.querySelector('.castdom-skeleton');\n if (skeleton && wrapper.children.length > 1) {\n skeleton.remove();\n }\n }\n</script>\n`;\n}\n\n/**\n * View Transitions helper — preserves skeleton state during navigation.\n *\n * ```astro\n * <div transition:persist data-castdom=\"sidebar\">\n * <Fragment set:html={skeleton(\"sidebar\").html} />\n * </div>\n * ```\n */\nexport function viewTransitionProps(name: string): Record<string, string> {\n return {\n \"transition:persist\": \"\",\n \"data-castdom\": name,\n \"transition:name\": `castdom-${name}`,\n };\n}\n\n/**\n * Generate <head> content for Astro pages.\n * Include in your Layout component.\n */\nexport function head(\n skeletonNames: string[],\n config?: Partial<CastDOMConfig>\n): string {\n const skeletons: SkeletonData[] = [];\n\n for (const name of skeletonNames) {\n const entry = getFromRegistry(name);\n if (entry) skeletons.push(entry.data);\n }\n\n if (skeletons.length === 0) return \"\";\n\n return [\n renderCriticalStyleTag(skeletons, config),\n renderHydrationScript(),\n ].join(\"\\n\");\n}\n"]}
@@ -0,0 +1,57 @@
1
+ import { renderStandalone, renderResponsiveHTML, generateCriticalCSS } from './chunk-ZWZ5ZLJE.js';
2
+
3
+ // src/seo/ssr.ts
4
+ function renderSkeleton(skeleton, options) {
5
+ const inlineCSS = options?.inlineCSS ?? true;
6
+ const hydrationAttrs = options?.hydrationAttrs ?? true;
7
+ let html;
8
+ if (inlineCSS) {
9
+ html = renderStandalone(skeleton, options?.config);
10
+ } else {
11
+ html = renderResponsiveHTML(skeleton, options?.config);
12
+ }
13
+ if (hydrationAttrs) {
14
+ html = html.replace(
15
+ /class="castdom-skeleton/,
16
+ `data-castdom-ssr="true" data-castdom-name="${skeleton.name}" data-castdom-hash="${skeleton.hash}" class="castdom-skeleton`
17
+ );
18
+ }
19
+ if (options?.noscript) {
20
+ html = `<noscript>${html}</noscript>`;
21
+ }
22
+ return html;
23
+ }
24
+ function renderSkeletons(skeletons, options) {
25
+ const css = generateCriticalCSS(skeletons, options?.config);
26
+ const html = {};
27
+ for (const skeleton of skeletons) {
28
+ html[skeleton.name] = renderSkeleton(skeleton, {
29
+ ...options,
30
+ inlineCSS: false
31
+ // CSS is shared
32
+ });
33
+ }
34
+ return { css, html };
35
+ }
36
+ function renderCriticalStyleTag(skeletons, config) {
37
+ const css = generateCriticalCSS(skeletons, config);
38
+ return `<style data-castdom="critical">${css}</style>`;
39
+ }
40
+ function renderHydrationScript() {
41
+ return `<script data-castdom="hydration">(function(){if(typeof window==='undefined')return;function r(){document.querySelectorAll('[data-castdom-ssr]').forEach(function(el){if(el.nextElementSibling&&!el.nextElementSibling.hasAttribute('data-castdom-ssr')){el.remove()}})}if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',r)}else{setTimeout(r,0)}})()</script>`;
42
+ }
43
+ function renderSSRFragment(skeletons, options) {
44
+ const { css, html } = renderSkeletons(skeletons, options);
45
+ const head = [
46
+ `<style data-castdom="critical">${css}</style>`,
47
+ renderHydrationScript()
48
+ ].join("\n");
49
+ return { head, body: html };
50
+ }
51
+ function renderPreloadHints() {
52
+ return "";
53
+ }
54
+
55
+ export { renderCriticalStyleTag, renderHydrationScript, renderPreloadHints, renderSSRFragment, renderSkeleton, renderSkeletons };
56
+ //# sourceMappingURL=chunk-COLESJ66.js.map
57
+ //# sourceMappingURL=chunk-COLESJ66.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/seo/ssr.ts"],"names":[],"mappings":";;;AAyCO,SAAS,cAAA,CACd,UACA,OAAA,EACQ;AACR,EAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,IAAA;AACxC,EAAA,MAAM,cAAA,GAAiB,SAAS,cAAA,IAAkB,IAAA;AAElD,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,IAAA,GAAO,gBAAA,CAAiB,QAAA,EAAU,OAAA,EAAS,MAAM,CAAA;AAAA,EACnD,CAAA,MAAO;AACL,IAAA,IAAA,GAAO,oBAAA,CAAqB,QAAA,EAAU,OAAA,EAAS,MAAM,CAAA;AAAA,EACvD;AAGA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,IAAA,GAAO,IAAA,CAAK,OAAA;AAAA,MACV,yBAAA;AAAA,MACA,CAAA,2CAAA,EAA8C,QAAA,CAAS,IAAI,CAAA,qBAAA,EAAwB,SAAS,IAAI,CAAA,yBAAA;AAAA,KAClG;AAAA,EACF;AAGA,EAAA,IAAI,SAAS,QAAA,EAAU;AACrB,IAAA,IAAA,GAAO,aAAa,IAAI,CAAA,WAAA,CAAA;AAAA,EAC1B;AAEA,EAAA,OAAO,IAAA;AACT;AAQO,SAAS,eAAA,CACd,WACA,OAAA,EAC+C;AAC/C,EAAA,MAAM,GAAA,GAAM,mBAAA,CAAoB,SAAA,EAAW,OAAA,EAAS,MAAM,CAAA;AAE1D,EAAA,MAAM,OAA+B,EAAC;AACtC,EAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,IAAA,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,GAAI,cAAA,CAAe,QAAA,EAAU;AAAA,MAC7C,GAAG,OAAA;AAAA,MACH,SAAA,EAAW;AAAA;AAAA,KACZ,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,EAAE,KAAK,IAAA,EAAK;AACrB;AAMO,SAAS,sBAAA,CACd,WACA,MAAA,EACQ;AACR,EAAA,MAAM,GAAA,GAAM,mBAAA,CAAoB,SAAA,EAAW,MAAM,CAAA;AACjD,EAAA,OAAO,kCAAkC,GAAG,CAAA,QAAA,CAAA;AAC9C;AAaO,SAAS,qBAAA,GAAgC;AAC9C,EAAA,OAAO,CAAA,6XAAA,CAAA;AACT;AAQO,SAAS,iBAAA,CACd,WACA,OAAA,EACgD;AAChD,EAAA,MAAM,EAAE,GAAA,EAAK,IAAA,EAAK,GAAI,eAAA,CAAgB,WAAW,OAAO,CAAA;AAExD,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,kCAAkC,GAAG,CAAA,QAAA,CAAA;AAAA,IACrC,qBAAA;AAAsB,GACxB,CAAE,KAAK,IAAI,CAAA;AAEX,EAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAK;AAC5B;AAMO,SAAS,kBAAA,GAA6B;AAG3C,EAAA,OAAO,EAAA;AACT","file":"chunk-COLESJ66.js","sourcesContent":["import type { SkeletonData, CastDOMConfig } from \"../core/types.js\";\nimport { renderStandalone, renderResponsiveHTML, generateCriticalCSS } from \"../core/renderer.js\";\nimport { DEFAULTS } from \"../core/types.js\";\n\n/**\n * SSR (Server-Side Rendering) utilities for CastDOM.\n *\n * These functions generate HTML that can be embedded directly in\n * server-rendered pages. The skeletons render as pure CSS —\n * no JavaScript is needed on the client to display them.\n *\n * Benefits for SEO:\n * - Crawlers see structured placeholder content instead of blank areas\n * - Zero CLS (Cumulative Layout Shift) — skeletons match exact dimensions\n * - Instant visual feedback — no FOUC (Flash of Unstyled Content)\n * - Proper ARIA attributes for accessibility\n */\n\nexport interface SSRRenderOptions {\n /** Include <style> tag with critical CSS (default: true) */\n inlineCSS?: boolean;\n /** Wrap in a <noscript> fallback (default: false) */\n noscript?: boolean;\n /** Add data attributes for hydration (default: true) */\n hydrationAttrs?: boolean;\n /** Custom config overrides */\n config?: Partial<CastDOMConfig>;\n}\n\n/**\n * Render a skeleton to an HTML string for SSR.\n * Includes inline critical CSS for immediate rendering.\n *\n * ```ts\n * // In your server handler / getServerSideProps / loader:\n * import { renderSkeleton } from 'castdom/ssr';\n *\n * const skeletonHTML = renderSkeleton(skeletonData);\n * // Embed in your page HTML\n * ```\n */\nexport function renderSkeleton(\n skeleton: SkeletonData,\n options?: SSRRenderOptions\n): string {\n const inlineCSS = options?.inlineCSS ?? true;\n const hydrationAttrs = options?.hydrationAttrs ?? true;\n\n let html: string;\n if (inlineCSS) {\n html = renderStandalone(skeleton, options?.config);\n } else {\n html = renderResponsiveHTML(skeleton, options?.config);\n }\n\n // Add hydration data attributes\n if (hydrationAttrs) {\n html = html.replace(\n /class=\"castdom-skeleton/,\n `data-castdom-ssr=\"true\" data-castdom-name=\"${skeleton.name}\" data-castdom-hash=\"${skeleton.hash}\" class=\"castdom-skeleton`\n );\n }\n\n // Wrap in noscript if requested\n if (options?.noscript) {\n html = `<noscript>${html}</noscript>`;\n }\n\n return html;\n}\n\n/**\n * Render multiple skeletons with shared CSS (deduplicates the critical CSS).\n *\n * More efficient than calling renderSkeleton() multiple times\n * when you have several skeletons on one page.\n */\nexport function renderSkeletons(\n skeletons: SkeletonData[],\n options?: SSRRenderOptions\n): { css: string; html: Record<string, string> } {\n const css = generateCriticalCSS(skeletons, options?.config);\n\n const html: Record<string, string> = {};\n for (const skeleton of skeletons) {\n html[skeleton.name] = renderSkeleton(skeleton, {\n ...options,\n inlineCSS: false, // CSS is shared\n });\n }\n\n return { css, html };\n}\n\n/**\n * Generate a <style> tag with critical CSS for given skeletons.\n * Place in <head> for optimal rendering performance.\n */\nexport function renderCriticalStyleTag(\n skeletons: SkeletonData[],\n config?: Partial<CastDOMConfig>\n): string {\n const css = generateCriticalCSS(skeletons, config);\n return `<style data-castdom=\"critical\">${css}</style>`;\n}\n\n/**\n * Generate a hydration script that removes SSR skeletons\n * once the client-side app takes over.\n *\n * This is a tiny (~200 byte) inline script that:\n * 1. Waits for DOMContentLoaded\n * 2. Finds all [data-castdom-ssr] elements\n * 3. Removes them once the real content renders\n *\n * The script is safe to inline — no external dependencies.\n */\nexport function renderHydrationScript(): string {\n return `<script data-castdom=\"hydration\">(function(){if(typeof window==='undefined')return;function r(){document.querySelectorAll('[data-castdom-ssr]').forEach(function(el){if(el.nextElementSibling&&!el.nextElementSibling.hasAttribute('data-castdom-ssr')){el.remove()}})}if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',r)}else{setTimeout(r,0)}})()</script>`;\n}\n\n/**\n * Generate a complete SSR skeleton page fragment.\n * Includes: critical CSS + skeleton HTML + hydration script.\n *\n * Designed to be dropped directly into your HTML template.\n */\nexport function renderSSRFragment(\n skeletons: SkeletonData[],\n options?: SSRRenderOptions\n): { head: string; body: Record<string, string> } {\n const { css, html } = renderSkeletons(skeletons, options);\n\n const head = [\n `<style data-castdom=\"critical\">${css}</style>`,\n renderHydrationScript(),\n ].join(\"\\n\");\n\n return { head, body: html };\n}\n\n/**\n * Preload hint generator for skeleton assets.\n * Generates <link> tags for optimal loading.\n */\nexport function renderPreloadHints(): string {\n // CastDOM is CSS-only at runtime, so no assets to preload.\n // This function exists for API consistency and future-proofing.\n return \"\";\n}\n\n// Re-export core utilities for convenience\nexport { generateCriticalCSS } from \"../core/renderer.js\";\nexport { renderStandalone, renderResponsiveHTML } from \"../core/renderer.js\";\n"]}
@@ -0,0 +1,31 @@
1
+ // src/core/types.ts
2
+ var DEFAULTS = {
3
+ outDir: ".castdom",
4
+ breakpoints: [375, 768, 1280],
5
+ color: "#e0e0e0",
6
+ shimmerColor: "#f0f0f0",
7
+ animationDuration: 1500,
8
+ contentAware: true,
9
+ minBoneSize: 4,
10
+ classPrefix: "castdom",
11
+ inlineStyles: false,
12
+ ssr: true
13
+ };
14
+ var BONE_KIND_INDEX = {
15
+ text: 1,
16
+ heading: 2,
17
+ image: 3,
18
+ avatar: 4,
19
+ button: 5,
20
+ input: 6,
21
+ icon: 7,
22
+ divider: 8,
23
+ block: 0
24
+ };
25
+ var BONE_KIND_FROM_INDEX = Object.fromEntries(
26
+ Object.entries(BONE_KIND_INDEX).map(([k, v]) => [v, k])
27
+ );
28
+
29
+ export { BONE_KIND_FROM_INDEX, BONE_KIND_INDEX, DEFAULTS };
30
+ //# sourceMappingURL=chunk-EJRNKHL5.js.map
31
+ //# sourceMappingURL=chunk-EJRNKHL5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/types.ts"],"names":[],"mappings":";AAqHO,IAAM,QAAA,GAcT;AAAA,EACF,MAAA,EAAQ,UAAA;AAAA,EACR,WAAA,EAAa,CAAC,GAAA,EAAK,GAAA,EAAK,IAAI,CAAA;AAAA,EAC5B,KAAA,EAAO,SAAA;AAAA,EACP,YAAA,EAAc,SAAA;AAAA,EACd,iBAAA,EAAmB,IAAA;AAAA,EACnB,YAAA,EAAc,IAAA;AAAA,EACd,WAAA,EAAa,CAAA;AAAA,EACb,WAAA,EAAa,SAAA;AAAA,EACb,YAAA,EAAc,KAAA;AAAA,EACd,GAAA,EAAK;AACP;AAGO,IAAM,eAAA,GAA4C;AAAA,EACvD,IAAA,EAAM,CAAA;AAAA,EACN,OAAA,EAAS,CAAA;AAAA,EACT,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,MAAA,EAAQ,CAAA;AAAA,EACR,KAAA,EAAO,CAAA;AAAA,EACP,IAAA,EAAM,CAAA;AAAA,EACN,OAAA,EAAS,CAAA;AAAA,EACT,KAAA,EAAO;AACT;AAEO,IAAM,uBAAiD,MAAA,CAAO,WAAA;AAAA,EACnE,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,CAAC,CAAA,EAAG,CAAa,CAAC;AACpE","file":"chunk-EJRNKHL5.js","sourcesContent":["/** A single bone — one rectangular skeleton element */\nexport interface Bone {\n /** X position relative to container (px) */\n x: number;\n /** Y position relative to container (px) */\n y: number;\n /** Width (px) */\n w: number;\n /** Height (px) */\n h: number;\n /** Border radius (px). 9999 = circle */\n r: number;\n /** Element type hint for content-aware rendering */\n kind?: BoneKind;\n}\n\nexport type BoneKind =\n | \"text\"\n | \"heading\"\n | \"image\"\n | \"avatar\"\n | \"button\"\n | \"input\"\n | \"icon\"\n | \"divider\"\n | \"block\";\n\n/** Bone data for a single breakpoint */\nexport interface BreakpointData {\n /** Viewport width this was captured at */\n viewport: number;\n /** Container width at capture time */\n containerWidth: number;\n /** Container height at capture time */\n containerHeight: number;\n /** All bones at this breakpoint */\n bones: Bone[];\n}\n\n/** Complete skeleton definition for a named component */\nexport interface SkeletonData {\n /** Unique name for this skeleton */\n name: string;\n /** Version hash for cache busting */\n hash: string;\n /** Breakpoint data, sorted ascending by viewport width */\n breakpoints: BreakpointData[];\n /** Timestamp of last extraction */\n extractedAt: number;\n}\n\n/** Configuration for CastDOM */\nexport interface CastDOMConfig {\n /** Directory to output generated skeleton data */\n outDir?: string;\n /** Breakpoint widths to capture at (default: [375, 768, 1280]) */\n breakpoints?: number[];\n /** Base color for skeleton bones (default: \"#e0e0e0\") */\n color?: string;\n /** Shimmer highlight color (default: \"#f0f0f0\") */\n shimmerColor?: string;\n /** Animation duration in ms (default: 1500) */\n animationDuration?: number;\n /** Enable content-aware bone detection (default: true) */\n contentAware?: boolean;\n /** Minimum bone size to include in px (default: 4) */\n minBoneSize?: number;\n /** CSS class prefix (default: \"castdom\") */\n classPrefix?: string;\n /** Generate inline styles instead of class-based (default: false) */\n inlineStyles?: boolean;\n /** Enable SSR rendering (default: true) */\n ssr?: boolean;\n /** URL or path to dev server for extraction */\n devServer?: string;\n /** Routes to snapshot for extraction */\n routes?: string[];\n /** Playwright launch options */\n playwright?: {\n headless?: boolean;\n timeout?: number;\n };\n}\n\n/** Registry entry used at runtime */\nexport interface RegistryEntry {\n data: SkeletonData;\n css: string;\n html: Record<number, string>;\n}\n\n/** Extraction target — what to snapshot */\nexport interface ExtractionTarget {\n name: string;\n selector: string;\n route?: string;\n}\n\n/** Result from the extraction process */\nexport interface ExtractionResult {\n target: ExtractionTarget;\n skeleton: SkeletonData;\n}\n\n/** Compressed bone format for wire/storage (delta-encoded) */\nexport interface CompressedBones {\n /** Version of compression format */\n v: 1;\n /** Viewport width */\n vw: number;\n /** Container dimensions [w, h] */\n c: [number, number];\n /** Flat array: [x, y, w, h, r, kind, ...] per bone. kind is enum index. */\n d: number[];\n}\n\n/** Default configuration values */\nexport const DEFAULTS: Required<\n Pick<\n CastDOMConfig,\n | \"outDir\"\n | \"breakpoints\"\n | \"color\"\n | \"shimmerColor\"\n | \"animationDuration\"\n | \"contentAware\"\n | \"minBoneSize\"\n | \"classPrefix\"\n | \"inlineStyles\"\n | \"ssr\"\n >\n> = {\n outDir: \".castdom\",\n breakpoints: [375, 768, 1280],\n color: \"#e0e0e0\",\n shimmerColor: \"#f0f0f0\",\n animationDuration: 1500,\n contentAware: true,\n minBoneSize: 4,\n classPrefix: \"castdom\",\n inlineStyles: false,\n ssr: true,\n};\n\n/** Map bone kind to numeric index for compression */\nexport const BONE_KIND_INDEX: Record<BoneKind, number> = {\n text: 1,\n heading: 2,\n image: 3,\n avatar: 4,\n button: 5,\n input: 6,\n icon: 7,\n divider: 8,\n block: 0,\n};\n\nexport const BONE_KIND_FROM_INDEX: Record<number, BoneKind> = Object.fromEntries(\n Object.entries(BONE_KIND_INDEX).map(([k, v]) => [v, k as BoneKind])\n) as Record<number, BoneKind>;\n"]}
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ // src/core/types.ts
4
+ var DEFAULTS = {
5
+ outDir: ".castdom",
6
+ breakpoints: [375, 768, 1280],
7
+ color: "#e0e0e0",
8
+ shimmerColor: "#f0f0f0",
9
+ animationDuration: 1500,
10
+ contentAware: true,
11
+ minBoneSize: 4,
12
+ classPrefix: "castdom",
13
+ inlineStyles: false,
14
+ ssr: true
15
+ };
16
+ var BONE_KIND_INDEX = {
17
+ text: 1,
18
+ heading: 2,
19
+ image: 3,
20
+ avatar: 4,
21
+ button: 5,
22
+ input: 6,
23
+ icon: 7,
24
+ divider: 8,
25
+ block: 0
26
+ };
27
+ var BONE_KIND_FROM_INDEX = Object.fromEntries(
28
+ Object.entries(BONE_KIND_INDEX).map(([k, v]) => [v, k])
29
+ );
30
+
31
+ exports.BONE_KIND_FROM_INDEX = BONE_KIND_FROM_INDEX;
32
+ exports.BONE_KIND_INDEX = BONE_KIND_INDEX;
33
+ exports.DEFAULTS = DEFAULTS;
34
+ //# sourceMappingURL=chunk-JRQ6EVQP.cjs.map
35
+ //# sourceMappingURL=chunk-JRQ6EVQP.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/types.ts"],"names":[],"mappings":";;;AAqHO,IAAM,QAAA,GAcT;AAAA,EACF,MAAA,EAAQ,UAAA;AAAA,EACR,WAAA,EAAa,CAAC,GAAA,EAAK,GAAA,EAAK,IAAI,CAAA;AAAA,EAC5B,KAAA,EAAO,SAAA;AAAA,EACP,YAAA,EAAc,SAAA;AAAA,EACd,iBAAA,EAAmB,IAAA;AAAA,EACnB,YAAA,EAAc,IAAA;AAAA,EACd,WAAA,EAAa,CAAA;AAAA,EACb,WAAA,EAAa,SAAA;AAAA,EACb,YAAA,EAAc,KAAA;AAAA,EACd,GAAA,EAAK;AACP;AAGO,IAAM,eAAA,GAA4C;AAAA,EACvD,IAAA,EAAM,CAAA;AAAA,EACN,OAAA,EAAS,CAAA;AAAA,EACT,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,MAAA,EAAQ,CAAA;AAAA,EACR,KAAA,EAAO,CAAA;AAAA,EACP,IAAA,EAAM,CAAA;AAAA,EACN,OAAA,EAAS,CAAA;AAAA,EACT,KAAA,EAAO;AACT;AAEO,IAAM,uBAAiD,MAAA,CAAO,WAAA;AAAA,EACnE,MAAA,CAAO,OAAA,CAAQ,eAAe,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,CAAC,CAAA,EAAG,CAAa,CAAC;AACpE","file":"chunk-JRQ6EVQP.cjs","sourcesContent":["/** A single bone — one rectangular skeleton element */\nexport interface Bone {\n /** X position relative to container (px) */\n x: number;\n /** Y position relative to container (px) */\n y: number;\n /** Width (px) */\n w: number;\n /** Height (px) */\n h: number;\n /** Border radius (px). 9999 = circle */\n r: number;\n /** Element type hint for content-aware rendering */\n kind?: BoneKind;\n}\n\nexport type BoneKind =\n | \"text\"\n | \"heading\"\n | \"image\"\n | \"avatar\"\n | \"button\"\n | \"input\"\n | \"icon\"\n | \"divider\"\n | \"block\";\n\n/** Bone data for a single breakpoint */\nexport interface BreakpointData {\n /** Viewport width this was captured at */\n viewport: number;\n /** Container width at capture time */\n containerWidth: number;\n /** Container height at capture time */\n containerHeight: number;\n /** All bones at this breakpoint */\n bones: Bone[];\n}\n\n/** Complete skeleton definition for a named component */\nexport interface SkeletonData {\n /** Unique name for this skeleton */\n name: string;\n /** Version hash for cache busting */\n hash: string;\n /** Breakpoint data, sorted ascending by viewport width */\n breakpoints: BreakpointData[];\n /** Timestamp of last extraction */\n extractedAt: number;\n}\n\n/** Configuration for CastDOM */\nexport interface CastDOMConfig {\n /** Directory to output generated skeleton data */\n outDir?: string;\n /** Breakpoint widths to capture at (default: [375, 768, 1280]) */\n breakpoints?: number[];\n /** Base color for skeleton bones (default: \"#e0e0e0\") */\n color?: string;\n /** Shimmer highlight color (default: \"#f0f0f0\") */\n shimmerColor?: string;\n /** Animation duration in ms (default: 1500) */\n animationDuration?: number;\n /** Enable content-aware bone detection (default: true) */\n contentAware?: boolean;\n /** Minimum bone size to include in px (default: 4) */\n minBoneSize?: number;\n /** CSS class prefix (default: \"castdom\") */\n classPrefix?: string;\n /** Generate inline styles instead of class-based (default: false) */\n inlineStyles?: boolean;\n /** Enable SSR rendering (default: true) */\n ssr?: boolean;\n /** URL or path to dev server for extraction */\n devServer?: string;\n /** Routes to snapshot for extraction */\n routes?: string[];\n /** Playwright launch options */\n playwright?: {\n headless?: boolean;\n timeout?: number;\n };\n}\n\n/** Registry entry used at runtime */\nexport interface RegistryEntry {\n data: SkeletonData;\n css: string;\n html: Record<number, string>;\n}\n\n/** Extraction target — what to snapshot */\nexport interface ExtractionTarget {\n name: string;\n selector: string;\n route?: string;\n}\n\n/** Result from the extraction process */\nexport interface ExtractionResult {\n target: ExtractionTarget;\n skeleton: SkeletonData;\n}\n\n/** Compressed bone format for wire/storage (delta-encoded) */\nexport interface CompressedBones {\n /** Version of compression format */\n v: 1;\n /** Viewport width */\n vw: number;\n /** Container dimensions [w, h] */\n c: [number, number];\n /** Flat array: [x, y, w, h, r, kind, ...] per bone. kind is enum index. */\n d: number[];\n}\n\n/** Default configuration values */\nexport const DEFAULTS: Required<\n Pick<\n CastDOMConfig,\n | \"outDir\"\n | \"breakpoints\"\n | \"color\"\n | \"shimmerColor\"\n | \"animationDuration\"\n | \"contentAware\"\n | \"minBoneSize\"\n | \"classPrefix\"\n | \"inlineStyles\"\n | \"ssr\"\n >\n> = {\n outDir: \".castdom\",\n breakpoints: [375, 768, 1280],\n color: \"#e0e0e0\",\n shimmerColor: \"#f0f0f0\",\n animationDuration: 1500,\n contentAware: true,\n minBoneSize: 4,\n classPrefix: \"castdom\",\n inlineStyles: false,\n ssr: true,\n};\n\n/** Map bone kind to numeric index for compression */\nexport const BONE_KIND_INDEX: Record<BoneKind, number> = {\n text: 1,\n heading: 2,\n image: 3,\n avatar: 4,\n button: 5,\n input: 6,\n icon: 7,\n divider: 8,\n block: 0,\n};\n\nexport const BONE_KIND_FROM_INDEX: Record<number, BoneKind> = Object.fromEntries(\n Object.entries(BONE_KIND_INDEX).map(([k, v]) => [v, k as BoneKind])\n) as Record<number, BoneKind>;\n"]}
@@ -0,0 +1,73 @@
1
+ import { generateCSS, renderBonesHTML } from './chunk-ZWZ5ZLJE.js';
2
+ import { DEFAULTS } from './chunk-EJRNKHL5.js';
3
+
4
+ // src/core/registry.ts
5
+ var store = /* @__PURE__ */ new Map();
6
+ var globalConfig = {
7
+ color: DEFAULTS.color,
8
+ shimmerColor: DEFAULTS.shimmerColor,
9
+ animationDuration: DEFAULTS.animationDuration,
10
+ classPrefix: DEFAULTS.classPrefix,
11
+ inlineStyles: DEFAULTS.inlineStyles
12
+ };
13
+ function configure(config) {
14
+ globalConfig = { ...globalConfig, ...config };
15
+ for (const [name, entry] of store) {
16
+ const updated = buildEntry(entry.data);
17
+ store.set(name, updated);
18
+ }
19
+ }
20
+ function buildEntry(data) {
21
+ const css = generateCSS(data, globalConfig);
22
+ const html = {};
23
+ for (const bp of data.breakpoints) {
24
+ html[bp.viewport] = renderBonesHTML(data.name, bp, globalConfig);
25
+ }
26
+ return { data, css, html };
27
+ }
28
+ function register(data) {
29
+ store.set(data.name, buildEntry(data));
30
+ }
31
+ function registerAll(skeletons) {
32
+ for (const data of skeletons) {
33
+ register(data);
34
+ }
35
+ }
36
+ function loadManifest(manifest) {
37
+ registerAll(manifest.skeletons);
38
+ }
39
+ function get(name) {
40
+ return store.get(name);
41
+ }
42
+ function has(name) {
43
+ return store.has(name);
44
+ }
45
+ function names() {
46
+ return [...store.keys()];
47
+ }
48
+ function remove(name) {
49
+ return store.delete(name);
50
+ }
51
+ function clear() {
52
+ store.clear();
53
+ }
54
+ function getAllCSS() {
55
+ const parts = [];
56
+ const seen = /* @__PURE__ */ new Set();
57
+ const prefix = globalConfig.classPrefix;
58
+ parts.push(getBaseCSS(prefix));
59
+ for (const entry of store.values()) {
60
+ if (!seen.has(entry.data.name)) {
61
+ parts.push(entry.css);
62
+ seen.add(entry.data.name);
63
+ }
64
+ }
65
+ return parts.join("\n");
66
+ }
67
+ function getBaseCSS(prefix, config) {
68
+ return `@keyframes ${prefix}-shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}@media(prefers-reduced-motion:reduce){.${prefix}-bone{animation:none!important}}`;
69
+ }
70
+
71
+ export { clear, configure, get, getAllCSS, has, loadManifest, names, register, registerAll, remove };
72
+ //# sourceMappingURL=chunk-KGLTVTHU.js.map
73
+ //# sourceMappingURL=chunk-KGLTVTHU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/registry.ts"],"names":[],"mappings":";;;;AAWA,IAAM,KAAA,uBAAY,GAAA,EAA2B;AAC7C,IAAI,YAAA,GAEA;AAAA,EACF,OAAO,QAAA,CAAS,KAAA;AAAA,EAChB,cAAc,QAAA,CAAS,YAAA;AAAA,EACvB,mBAAmB,QAAA,CAAS,iBAAA;AAAA,EAC5B,aAAa,QAAA,CAAS,WAAA;AAAA,EACtB,cAAc,QAAA,CAAS;AACzB,CAAA;AAGO,SAAS,UACd,MAAA,EACM;AACN,EAAA,YAAA,GAAe,EAAE,GAAG,YAAA,EAAc,GAAG,MAAA,EAAO;AAE5C,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,KAAK,CAAA,IAAK,KAAA,EAAO;AACjC,IAAA,MAAM,OAAA,GAAU,UAAA,CAAW,KAAA,CAAM,IAAI,CAAA;AACrC,IAAA,KAAA,CAAM,GAAA,CAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AACF;AAGA,SAAS,WAAW,IAAA,EAAmC;AACrD,EAAA,MAAM,GAAA,GAAM,WAAA,CAAY,IAAA,EAAM,YAAY,CAAA;AAC1C,EAAA,MAAM,OAA+B,EAAC;AACtC,EAAA,KAAA,MAAW,EAAA,IAAM,KAAK,WAAA,EAAa;AACjC,IAAA,IAAA,CAAK,GAAG,QAAQ,CAAA,GAAI,gBAAgB,IAAA,CAAK,IAAA,EAAM,IAAI,YAAY,CAAA;AAAA,EACjE;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,GAAA,EAAK,IAAA,EAAK;AAC3B;AAGO,SAAS,SAAS,IAAA,EAA0B;AACjD,EAAA,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,UAAA,CAAW,IAAI,CAAC,CAAA;AACvC;AAGO,SAAS,YAAY,SAAA,EAAiC;AAC3D,EAAA,KAAA,MAAW,QAAQ,SAAA,EAAW;AAC5B,IAAA,QAAA,CAAS,IAAI,CAAA;AAAA,EACf;AACF;AAGO,SAAS,aAAa,QAAA,EAA+C;AAC1E,EAAA,WAAA,CAAY,SAAS,SAAS,CAAA;AAChC;AAGO,SAAS,IAAI,IAAA,EAAyC;AAC3D,EAAA,OAAO,KAAA,CAAM,IAAI,IAAI,CAAA;AACvB;AAGO,SAAS,IAAI,IAAA,EAAuB;AACzC,EAAA,OAAO,KAAA,CAAM,IAAI,IAAI,CAAA;AACvB;AAGO,SAAS,KAAA,GAAkB;AAChC,EAAA,OAAO,CAAC,GAAG,KAAA,CAAM,IAAA,EAAM,CAAA;AACzB;AAGO,SAAS,OAAO,IAAA,EAAuB;AAC5C,EAAA,OAAO,KAAA,CAAM,OAAO,IAAI,CAAA;AAC1B;AAGO,SAAS,KAAA,GAAc;AAC5B,EAAA,KAAA,CAAM,KAAA,EAAM;AACd;AAGO,SAAS,SAAA,GAAoB;AAClC,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAG7B,EAAA,MAAM,SAAS,YAAA,CAAa,WAAA;AAC5B,EAAA,KAAA,CAAM,IAAA,CAAK,UAAA,CAAW,MAAoB,CAAC,CAAA;AAE3C,EAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,MAAA,EAAO,EAAG;AAClC,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,EAAG;AAC9B,MAAA,KAAA,CAAM,IAAA,CAAK,MAAM,GAAG,CAAA;AACpB,MAAA,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAGA,SAAS,UAAA,CACP,QACA,MAAA,EACQ;AACR,EAAA,OAAO,CAAA,WAAA,EAAc,MAAM,CAAA,gHAAA,EAAmH,MAAM,CAAA,gCAAA,CAAA;AACtJ","file":"chunk-KGLTVTHU.js","sourcesContent":["import type { RegistryEntry, SkeletonData, CastDOMConfig } from \"./types.js\";\nimport { generateCSS } from \"./renderer.js\";\nimport { renderBonesHTML } from \"./renderer.js\";\nimport { DEFAULTS } from \"./types.js\";\n\n/**\n * Global skeleton registry.\n * Stores all registered skeleton data and provides lookup by name.\n * Import once at app entry — all <CastDOM> components auto-resolve from here.\n */\n\nconst store = new Map<string, RegistryEntry>();\nlet globalConfig: Required<\n Pick<CastDOMConfig, \"color\" | \"shimmerColor\" | \"animationDuration\" | \"classPrefix\" | \"inlineStyles\">\n> = {\n color: DEFAULTS.color,\n shimmerColor: DEFAULTS.shimmerColor,\n animationDuration: DEFAULTS.animationDuration,\n classPrefix: DEFAULTS.classPrefix,\n inlineStyles: DEFAULTS.inlineStyles,\n};\n\n/** Configure global registry settings */\nexport function configure(\n config: Partial<typeof globalConfig>\n): void {\n globalConfig = { ...globalConfig, ...config };\n // Re-generate CSS/HTML for all registered skeletons\n for (const [name, entry] of store) {\n const updated = buildEntry(entry.data);\n store.set(name, updated);\n }\n}\n\n/** Build a registry entry from skeleton data */\nfunction buildEntry(data: SkeletonData): RegistryEntry {\n const css = generateCSS(data, globalConfig);\n const html: Record<number, string> = {};\n for (const bp of data.breakpoints) {\n html[bp.viewport] = renderBonesHTML(data.name, bp, globalConfig);\n }\n return { data, css, html };\n}\n\n/** Register a single skeleton */\nexport function register(data: SkeletonData): void {\n store.set(data.name, buildEntry(data));\n}\n\n/** Register multiple skeletons at once */\nexport function registerAll(skeletons: SkeletonData[]): void {\n for (const data of skeletons) {\n register(data);\n }\n}\n\n/** Load and register skeletons from a generated manifest file */\nexport function loadManifest(manifest: { skeletons: SkeletonData[] }): void {\n registerAll(manifest.skeletons);\n}\n\n/** Get a registered skeleton by name */\nexport function get(name: string): RegistryEntry | undefined {\n return store.get(name);\n}\n\n/** Check if a skeleton is registered */\nexport function has(name: string): boolean {\n return store.has(name);\n}\n\n/** Get all registered skeleton names */\nexport function names(): string[] {\n return [...store.keys()];\n}\n\n/** Remove a skeleton from the registry */\nexport function remove(name: string): boolean {\n return store.delete(name);\n}\n\n/** Clear all registered skeletons */\nexport function clear(): void {\n store.clear();\n}\n\n/** Get the combined CSS for all registered skeletons */\nexport function getAllCSS(): string {\n const parts: string[] = [];\n const seen = new Set<string>();\n\n // Add base animation CSS once\n const prefix = globalConfig.classPrefix;\n parts.push(getBaseCSS(prefix, globalConfig));\n\n for (const entry of store.values()) {\n if (!seen.has(entry.data.name)) {\n parts.push(entry.css);\n seen.add(entry.data.name);\n }\n }\n\n return parts.join(\"\\n\");\n}\n\n/** Get base CSS (keyframes + shared styles) */\nfunction getBaseCSS(\n prefix: string,\n config: typeof globalConfig\n): string {\n return `@keyframes ${prefix}-shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}@media(prefers-reduced-motion:reduce){.${prefix}-bone{animation:none!important}}`;\n}\n"]}