@luna_ui/astra 0.17.0 → 0.17.1

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/bin/astra.js CHANGED
@@ -1,9 +1,58 @@
1
1
  #!/usr/bin/env node
2
- // Workspace dev shim. js/astra/bin/astra.js -> three levels up to
3
- // workspace root, then into _build/js/release/build/mizchi/astra/cmd/astra/astra.js.
2
+ // Entry point for the @luna_ui/astra npm wrapper.
4
3
  //
5
4
  // Primary install path is `moon install mizchi/astra/cmd/astra`; this
6
5
  // npm wrapper exists for users who already have node but not moon.
7
- // Published npm builds bundle the moonbit CLI output into ./dist/ via
8
- // js/astra/scripts/build-release.mjs (TODO).
9
- import "../../../_build/js/release/build/mizchi/astra/cmd/astra/astra.js";
6
+ //
7
+ // CLI resolution order:
8
+ // 1. ../dist/astra.js — populated by scripts/build-release.mjs at
9
+ // publish time. This is the path used in real npm installs.
10
+ // 2. ../../../_build/js/release/build/mizchi/astra/cmd/astra/astra.js
11
+ // — workspace fallback so the shim stays usable from a clean
12
+ // monorepo checkout, which is what tests/integration/* relies on.
13
+ //
14
+ // Asset resolution: astra's load_asset() tries a fixed list of
15
+ // cwd-relative paths to find styles/main.css etc. None of those resolve
16
+ // when the CLI is installed via npm, so we set globalThis.__sol_assets_dir
17
+ // to short-circuit the lookup. Bundled assets in dist/assets/ take
18
+ // precedence; the workspace path is the dev fallback.
19
+ import path from "node:path";
20
+ import { fileURLToPath } from "node:url";
21
+ import { existsSync } from "node:fs";
22
+
23
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
24
+ const distEntry = path.resolve(__dirname, "../dist/astra.js");
25
+ const workspaceEntry = path.resolve(
26
+ __dirname,
27
+ "../../../_build/js/release/build/mizchi/astra/cmd/astra/astra.js",
28
+ );
29
+ const distAssets = path.resolve(__dirname, "../dist/assets");
30
+ const workspaceAssets = path.resolve(__dirname, "../../../astra/src/assets");
31
+
32
+ const entry = existsSync(distEntry)
33
+ ? distEntry
34
+ : existsSync(workspaceEntry)
35
+ ? workspaceEntry
36
+ : null;
37
+
38
+ if (!entry) {
39
+ console.error(
40
+ "astra CLI binary not found. Tried:\n" +
41
+ ` ${distEntry}\n` +
42
+ ` ${workspaceEntry}\n` +
43
+ "If running from the luna.mbt monorepo, run " +
44
+ "`moon build --target js --release` first.",
45
+ );
46
+ process.exit(1);
47
+ }
48
+
49
+ const assetsDir = existsSync(distAssets)
50
+ ? distAssets
51
+ : existsSync(workspaceAssets)
52
+ ? workspaceAssets
53
+ : null;
54
+ if (assetsDir) {
55
+ globalThis.__sol_assets_dir = assetsDir;
56
+ }
57
+
58
+ await import(entry);
@@ -0,0 +1 @@
1
+ function e(e,t,n){if(t===`load`)document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>n(),{once:!0}):n();else if(t===`idle`)requestIdleCallback(()=>n());else if(t[0]===`v`)new IntersectionObserver((e,t)=>{e.some(e=>e.isIntersecting)&&(t.disconnect(),n())},{rootMargin:`50px`}).observe(e);else if(t[0]===`m`){let e=matchMedia(t.slice(6)),r=()=>{e.matches&&(e.removeEventListener(`change`,r),n())};e.matches?n():e.addEventListener(`change`,r)}}function t(e){document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,e,{once:!0}):e()}function n(e,t){new MutationObserver(n=>n.forEach(n=>n.addedNodes.forEach(n=>{n.nodeType===1&&e(n)&&t(n)}))).observe(document.body??document.documentElement,{childList:!0,subtree:!0})}function r(){let e=new Set;return{loaded:e,unload:t=>e.delete(t),clear:()=>e.clear()}}export{r as createLoadedTracker,n as observeAdditions,t as onReady,e as setupTrigger};
@@ -0,0 +1,170 @@
1
+ (function() {
2
+
3
+
4
+ //#region js/loader/src/lib.ts
5
+ /**
6
+ * Shared utilities for Luna loaders
7
+ */
8
+ /**
9
+ * Setup hydration trigger for an element
10
+ */
11
+ function setupTrigger(el, trigger, hydrate$1) {
12
+ if (trigger === "load") document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", () => hydrate$1(), { once: true }) : hydrate$1();
13
+ else if (trigger === "idle") requestIdleCallback(() => hydrate$1());
14
+ else if (trigger[0] === "v") new IntersectionObserver((entries, obs) => {
15
+ if (entries.some((e) => e.isIntersecting)) {
16
+ obs.disconnect();
17
+ hydrate$1();
18
+ }
19
+ }, { rootMargin: "50px" }).observe(el);
20
+ else if (trigger[0] === "m") {
21
+ const mq = matchMedia(trigger.slice(6));
22
+ const handler = () => {
23
+ if (mq.matches) {
24
+ mq.removeEventListener("change", handler);
25
+ hydrate$1();
26
+ }
27
+ };
28
+ mq.matches ? hydrate$1() : mq.addEventListener("change", handler);
29
+ }
30
+ }
31
+ /**
32
+ * Run function when DOM is ready
33
+ */
34
+ function onReady(fn) {
35
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", fn, { once: true }) : fn();
36
+ }
37
+ /**
38
+ * Watch for dynamically added elements matching a predicate
39
+ */
40
+ function observeAdditions(match, setup$1) {
41
+ new MutationObserver((mutations) => mutations.forEach((m) => m.addedNodes.forEach((n) => {
42
+ if (n.nodeType === 1 && match(n)) setup$1(n);
43
+ }))).observe(document.body ?? document.documentElement, {
44
+ childList: true,
45
+ subtree: true
46
+ });
47
+ }
48
+ /**
49
+ * Create a loaded tracker with unload utilities
50
+ */
51
+ function createLoadedTracker() {
52
+ const loadedEpoch = /* @__PURE__ */ new WeakMap();
53
+ let currentEpoch = 0;
54
+ const escapeSelector = (id) => {
55
+ const css = globalThis.CSS;
56
+ if (css && typeof css.escape === "function") return css.escape(id);
57
+ return id.replace(/[\\"]/g, "\\$&");
58
+ };
59
+ return {
60
+ isLoaded: (el) => loadedEpoch.get(el) === currentEpoch,
61
+ markLoaded: (el) => loadedEpoch.set(el, currentEpoch),
62
+ unload: (id) => {
63
+ if (!id) return;
64
+ document.querySelectorAll(`[luna\\:id="${escapeSelector(id)}"]`).forEach((el) => loadedEpoch.delete(el));
65
+ },
66
+ clear: () => {
67
+ currentEpoch += 1;
68
+ }
69
+ };
70
+ }
71
+
72
+ //#endregion
73
+ //#region js/loader/src/loader.ts
74
+ /*! luna loader v4 - minimal dispatcher */
75
+ const d = document;
76
+ const S = {};
77
+ const { isLoaded, markLoaded, unload, clear } = createLoadedTracker();
78
+ const normalizeAllowedEntries = (raw) => {
79
+ if (Array.isArray(raw)) return raw.map((v) => `${v}`.trim().toLowerCase()).filter(Boolean);
80
+ if (typeof raw === "string") return raw.split(",").map((v) => v.trim().toLowerCase()).filter(Boolean);
81
+ return [];
82
+ };
83
+ const getAllowedHostEntries = () => normalizeAllowedEntries(globalThis.__LUNA_ALLOWED_HOSTS__);
84
+ const isAllowedModuleUrl = (rawUrl) => {
85
+ if (!rawUrl) return;
86
+ let parsed;
87
+ try {
88
+ parsed = new URL(rawUrl, d.baseURI || location.href);
89
+ } catch {
90
+ console.warn(`[luna] Blocked invalid module URL: ${rawUrl}`);
91
+ return;
92
+ }
93
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
94
+ console.warn(`[luna] Blocked non-http(s) module URL: ${rawUrl}`);
95
+ return;
96
+ }
97
+ if (parsed.origin === location.origin) return parsed.href;
98
+ const allowed = getAllowedHostEntries();
99
+ const origin = parsed.origin.toLowerCase();
100
+ const host = parsed.hostname.toLowerCase();
101
+ const hostPort = parsed.host.toLowerCase();
102
+ if (allowed.includes(origin) || allowed.includes(host) || allowed.includes(hostPort)) return parsed.href;
103
+ console.warn(`[luna] Blocked cross-origin module URL: ${parsed.href}. Set window.__LUNA_ALLOWED_HOSTS__ to allow this host.`);
104
+ };
105
+ const setAllowedHosts = (hosts) => {
106
+ if (Array.isArray(hosts) || typeof hosts === "string") globalThis.__LUNA_ALLOWED_HOSTS__ = hosts;
107
+ else globalThis.__LUNA_ALLOWED_HOSTS__ = [];
108
+ };
109
+ const parseState = async (el) => {
110
+ const a = el.getAttribute("luna:state");
111
+ if (!a) return;
112
+ if (a[0] === "#") return JSON.parse(d.getElementById(a.slice(1))?.textContent ?? "null");
113
+ try {
114
+ return JSON.parse(a);
115
+ } catch {}
116
+ };
117
+ const hydrate = async (el) => {
118
+ const id = el.getAttribute("luna:id") ?? el.tagName.toLowerCase();
119
+ const url = isAllowedModuleUrl(el.getAttribute("luna:url"));
120
+ if (!url) return;
121
+ if (isLoaded(el)) return;
122
+ markLoaded(el);
123
+ S[id] = await parseState(el);
124
+ try {
125
+ const mod = await import(url);
126
+ const ex = el.getAttribute("luna:export");
127
+ (ex ? mod[ex] : mod.hydrate ?? mod.default)?.(el, S[id], id);
128
+ } catch (e) {
129
+ console.warn(`[luna] Failed to load ${url}:`, e);
130
+ }
131
+ };
132
+ const setup = (el) => {
133
+ setupTrigger(el, el.getAttribute("luna:trigger") ?? "load", () => hydrate(el));
134
+ };
135
+ const scan = () => {
136
+ d.querySelectorAll("[luna\\:url]").forEach(setup);
137
+ };
138
+ d.querySelectorAll("script[type=\"luna/json\"]").forEach((s) => {
139
+ if (s.id) S[s.id] = JSON.parse(s.textContent ?? "{}");
140
+ });
141
+ const scanDefer = () => {
142
+ d.querySelectorAll('[luna\\:defer]').forEach(el => {
143
+ const url = el.getAttribute('luna:defer');
144
+ if (!url) return;
145
+ el.removeAttribute('luna:defer');
146
+ fetch(url).then(r => r.ok ? r.text() : '').then(html => {
147
+ if (html) {
148
+ el.innerHTML = html;
149
+ scan();
150
+ }
151
+ }).catch(e => console.warn('[luna] defer fetch failed:', e));
152
+ });
153
+ };
154
+ onReady(scan);
155
+ onReady(scanDefer);
156
+ observeAdditions((el) => el.hasAttribute("luna:url") || el.hasAttribute("luna:defer"), (el) => {
157
+ if (el.hasAttribute("luna:url")) setup(el);
158
+ if (el.hasAttribute("luna:defer")) scanDefer();
159
+ });
160
+ const w = window;
161
+ w.__LUNA_STATE__ = S;
162
+ w.__LUNA_HYDRATE__ = hydrate;
163
+ w.__LUNA_SCAN__ = scan;
164
+ w.__LUNA_UNLOAD__ = unload;
165
+ w.__LUNA_CLEAR_LOADED__ = clear;
166
+ w.__LUNA_SET_ALLOWED_HOSTS__ = setAllowedHosts;
167
+ w.__LUNA_SCAN_DEFER__ = scanDefer;
168
+
169
+ //#endregion
170
+ })();
@@ -0,0 +1,29 @@
1
+ (function(){
2
+ var STORAGE_KEY = 'sol-sidebar-state';
3
+ function loadState() {
4
+ try { return JSON.parse(localStorage.getItem(STORAGE_KEY)) || {}; } catch { return {}; }
5
+ }
6
+ function saveState(state) {
7
+ try { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } catch {}
8
+ }
9
+ function initSidebar() {
10
+ var state = loadState();
11
+ document.querySelectorAll('[data-sidebar-group]').forEach(function(el) {
12
+ var key = el.dataset.sidebarGroup;
13
+ if (key && state[key] !== undefined) {
14
+ el.open = state[key];
15
+ }
16
+ el.addEventListener('toggle', function() {
17
+ var s = loadState();
18
+ s[key] = el.open;
19
+ saveState(s);
20
+ });
21
+ });
22
+ }
23
+ if (document.readyState === 'loading') {
24
+ document.addEventListener('DOMContentLoaded', initSidebar);
25
+ } else {
26
+ initSidebar();
27
+ }
28
+ window.__SOL_INIT_SIDEBAR__ = initSidebar;
29
+ })();
@@ -0,0 +1 @@
1
+ const e=e=>{let t=e.trim().toLowerCase();return t.startsWith(`javascript:`)||t.startsWith(`data:`)||t.startsWith(`vbscript:`)};((t,n)=>{let r=!1,i=new Map,a=(e,t)=>{let n=e.setHTMLUnsafe;n?n(t):e.innerHTML=t},o=(e,r=!1)=>{let i=new DOMParser().parseFromString(e,`text/html`),o=i.querySelectorAll(`template[data-sol-outlet]`);if(o.length>0){o.forEach(e=>{let r=e.dataset.solOutlet,i=t.querySelector(`[data-sol-outlet="${r}"]`);i&&(n.__LUNA_UNLOAD_ALL__?.(i),a(i,e.innerHTML))});let e=i.querySelector(`template[data-sol-title]`);e&&(t.title=e.textContent??``)}else{let e=i.querySelector(`#app`),r=t.querySelector(`#app`);e&&r&&(n.__LUNA_UNLOAD_ALL__?.(r),a(r,e.innerHTML));let o=i.querySelector(`title`);o&&(t.title=o.textContent??``)}r?n.__LUNA_RERENDER_ALL__?.():n.__LUNA_SCAN__?.(),n.__LUNA_WC_SCAN__?.()},s=async(e,t=!1)=>{if(!r){r=!0;try{let r=i.get(e);r&&(o(r,!1),t?n.history.replaceState({sol:!0},``,e):n.history.pushState({sol:!0},``,e),n.scrollTo(0,0));let a=await fetch(e,{headers:{"X-Sol-Fragment":`true`}}),s=await a.text();a.headers.get(`X-Sol-Fragment-Response`)&&(i.set(e,s),setTimeout(()=>i.delete(e),300*1e3)),r?s!==r&&o(s,!0):(o(s,!1),t?n.history.replaceState({sol:!0},``,e):n.history.pushState({sol:!0},``,e),n.scrollTo(0,0))}catch{n.location.href=e}finally{r=!1}}},c=e=>{i.has(e)||fetch(e,{headers:{"X-Sol-Fragment":`true`}}).then(e=>e.text()).then(t=>{i.set(e,t),setTimeout(()=>i.delete(e),300*1e3)}).catch(()=>{})};t.addEventListener(`click`,t=>{let n=t.target?.closest(`[data-sol-link]`);if(!n)return;let r=n.getAttribute(`href`);r&&(e(r)||r.startsWith(`http`)||r.startsWith(`//`)||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||(t.preventDefault(),s(r,n.hasAttribute(`data-sol-replace`))))}),t.addEventListener(`mouseenter`,t=>{let n=t.target;if(!n?.closest)return;let r=n.closest(`[data-sol-link][data-sol-prefetch]`);if(r){let t=r.getAttribute(`href`);t&&!e(t)&&!t.startsWith(`http`)&&!t.startsWith(`//`)&&c(t)}},{capture:!0}),n.addEventListener(`popstate`,e=>{(e.state?.sol||!e.state)&&s(n.location.href,!0)}),n.__SOL_NAVIGATE__=s,n.__SOL_PREFETCH__=c,n.__SOL_CACHE__=i})(document,window);
@@ -0,0 +1,25 @@
1
+ (function(){
2
+ var theme = localStorage.getItem('theme');
3
+ var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
4
+ var isDark = theme === 'dark' || (theme !== 'light' && prefersDark);
5
+ if (isDark) {
6
+ document.documentElement.classList.add('dark');
7
+ document.documentElement.classList.remove('light');
8
+ } else {
9
+ document.documentElement.classList.add('light');
10
+ document.documentElement.classList.remove('dark');
11
+ }
12
+ window.toggleTheme = function() {
13
+ var html = document.documentElement;
14
+ var wasDark = html.classList.contains('dark');
15
+ if (wasDark) {
16
+ html.classList.remove('dark');
17
+ html.classList.add('light');
18
+ localStorage.setItem('theme', 'light');
19
+ } else {
20
+ html.classList.add('dark');
21
+ html.classList.remove('light');
22
+ localStorage.setItem('theme', 'dark');
23
+ }
24
+ };
25
+ })();
@@ -0,0 +1,41 @@
1
+ (function(){
2
+ var observer = null;
3
+ var tocLinks = [];
4
+ var headings = [];
5
+ function initTocSpy() {
6
+ if (observer) observer.disconnect();
7
+ tocLinks = Array.from(document.querySelectorAll('.toc-item a'));
8
+ headings = tocLinks.map(function(link) {
9
+ var id = link.getAttribute('href')?.slice(1);
10
+ return id ? document.getElementById(id) : null;
11
+ }).filter(Boolean);
12
+ if (!headings.length) return;
13
+ var current = null;
14
+ observer = new IntersectionObserver(function(entries) {
15
+ entries.forEach(function(entry) {
16
+ if (entry.isIntersecting) current = entry.target;
17
+ });
18
+ if (!current) {
19
+ var scrollY = window.scrollY + 100;
20
+ for (var i = headings.length - 1; i >= 0; i--) {
21
+ if (headings[i].offsetTop <= scrollY) { current = headings[i]; break; }
22
+ }
23
+ }
24
+ tocLinks.forEach(function(link) {
25
+ var id = link.getAttribute('href')?.slice(1);
26
+ if (current && id === current.id) {
27
+ link.classList.add('active');
28
+ } else {
29
+ link.classList.remove('active');
30
+ }
31
+ });
32
+ }, { rootMargin: '-60px 0px -70% 0px', threshold: 0 });
33
+ headings.forEach(function(h) { observer.observe(h); });
34
+ }
35
+ if (document.readyState === 'loading') {
36
+ document.addEventListener('DOMContentLoaded', initTocSpy);
37
+ } else {
38
+ initTocSpy();
39
+ }
40
+ window.__SOL_INIT_TOC_SPY__ = initTocSpy;
41
+ })();
@@ -0,0 +1 @@
1
+ (function(){function e(e,t,n){if(t===`load`)document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,()=>n(),{once:!0}):n();else if(t===`idle`)requestIdleCallback(()=>n());else if(t[0]===`v`)new IntersectionObserver((e,t)=>{e.some(e=>e.isIntersecting)&&(t.disconnect(),n())},{rootMargin:`50px`}).observe(e);else if(t[0]===`m`){let e=matchMedia(t.slice(6)),r=()=>{e.matches&&(e.removeEventListener(`change`,r),n())};e.matches?n():e.addEventListener(`change`,r)}}function t(e){document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,e,{once:!0}):e()}function n(e,t){new MutationObserver(n=>n.forEach(n=>n.addedNodes.forEach(n=>{n.nodeType===1&&e(n)&&t(n)}))).observe(document.body??document.documentElement,{childList:!0,subtree:!0})}let r=document,i={},a=new Map,o=new Map,s=async e=>{let t=e.getAttribute(`luna:wc-state`);if(!t)return{};if(t[0]===`#`)try{return JSON.parse(r.getElementById(t.slice(1))?.textContent??`{}`)}catch{return{}}try{return JSON.parse(t.replace(/\\u003c/g,`<`).replace(/\\u003e/g,`>`).replace(/\\u0026/g,`&`))}catch{return{}}},c=async(e,t)=>{if(a.has(e))return a.get(e);if(o.has(e))return o.get(e);let n=import(t).then(t=>{let n=t.hydrate??t.default;if(typeof n==`function`)return a.set(e,n),n}).catch(()=>{}).finally(()=>o.delete(e));return o.set(e,n),n},l=async e=>{let t=e.tagName.toLowerCase(),n=await s(e);i[t]=n;let r=e.getAttribute(`luna:wc-url`);r&&(await c(t,r))?.(e,n,t)},u=t=>{let n=t;n.__lw||(n.__lw=1,e(t,t.getAttribute(`luna:wc-trigger`)??t.getAttribute(`luna:trigger`)??`load`,()=>l(t)))},d=()=>r.querySelectorAll(`[luna\\:wc-url]`).forEach(u);t(d),n(e=>e.hasAttribute(`luna:wc-url`),u);let f=window;f.__LUNA_WC_STATE__=i,f.__LUNA_WC_SCAN__=d,f.__LUNA_WC_HYDRATE__=l,f.__LUNA_WC_UNLOAD__=e=>a.delete(e),f.__LUNA_WC_CLEAR_LOADED__=()=>a.clear()})();