@willa-ui/shared 0.0.1-alpha.8d8fe96

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/README.md ADDED
@@ -0,0 +1 @@
1
+ # @willa-ui/shared
package/dist/index.cjs ADDED
@@ -0,0 +1,101 @@
1
+ /*!
2
+ * @willa-ui/shared.js v0.0.1-alpha.8d8fe96
3
+ * (c) 2026 chentao.arthur
4
+ */
5
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
6
+ let react = require("react");
7
+ let aidly = require("aidly");
8
+ //#region src/clipboard.ts
9
+ async function copyToClipboard(text) {
10
+ if (!text) return false;
11
+ try {
12
+ await navigator.clipboard.writeText(text);
13
+ return true;
14
+ } catch {
15
+ try {
16
+ const el = document.createElement("textarea");
17
+ el.value = text;
18
+ el.style.position = "fixed";
19
+ el.style.left = "-9999px";
20
+ el.style.top = "0";
21
+ document.body.appendChild(el);
22
+ el.focus();
23
+ el.select();
24
+ const ok = document.execCommand("copy");
25
+ document.body.removeChild(el);
26
+ return ok;
27
+ } catch {
28
+ return false;
29
+ }
30
+ }
31
+ }
32
+ //#endregion
33
+ //#region src/nodes.ts
34
+ const toNodeArray = (children) => {
35
+ return ((0, aidly.isArray)(children) ? children : [children]).filter((item) => {
36
+ if ((0, aidly.isNil)(item) || typeof item === "boolean") return false;
37
+ if ((0, aidly.isString)(item)) return item.trim().length > 0;
38
+ return true;
39
+ });
40
+ };
41
+ function isMediaOnlyParagraph(children) {
42
+ const nodes = toNodeArray(children);
43
+ if (nodes.length !== 1) return false;
44
+ const node = nodes[0];
45
+ if (!(0, react.isValidElement)(node)) return false;
46
+ if (node.type === "img") return true;
47
+ return Boolean(node.type.__willaMediaElement);
48
+ }
49
+ //#endregion
50
+ //#region src/heading.ts
51
+ const toHeadingSlug = (value) => {
52
+ return value.trim().replace(/\[[^\]]*\]\([^)]*\)/g, (m) => {
53
+ return /^\[([^\]]*)\]/.exec(m)?.[1] ?? "";
54
+ }).replace(/`+/g, "").replace(/[*_~]/g, "").replace(/<[^>]+>/g, "").toLowerCase().replace(/\s+/g, "-").replace(/[^\p{L}\p{N}-]+/gu, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
55
+ };
56
+ function flattenText(node) {
57
+ if ((0, aidly.isNil)(node)) return "";
58
+ if (typeof node === "string" || typeof node === "number") return String(node);
59
+ if ((0, aidly.isArray)(node)) return node.map(flattenText).join("");
60
+ if (typeof node === "object" && "props" in node) return flattenText(node.props?.children);
61
+ return "";
62
+ }
63
+ function createHeadingIdFactory() {
64
+ const counts = /* @__PURE__ */ new Map();
65
+ return (text) => {
66
+ const base = toHeadingSlug(text) || "section";
67
+ const next = (counts.get(base) ?? 0) + 1;
68
+ counts.set(base, next);
69
+ return next === 1 ? base : `${base}-${next}`;
70
+ };
71
+ }
72
+ function extractHeadings(source) {
73
+ const nextId = createHeadingIdFactory();
74
+ const headings = [];
75
+ const lines = source.split(/\r?\n/);
76
+ let inFence = false;
77
+ for (const line of lines) {
78
+ if (/^```/.test(line.trim())) {
79
+ inFence = !inFence;
80
+ continue;
81
+ }
82
+ if (inFence) continue;
83
+ const match = /^(#{2,3})\s+(.+?)\s*$/.exec(line);
84
+ if (!match) continue;
85
+ const level = match[1].length;
86
+ const raw = match[2].replace(/\s+#+\s*$/, "").trim();
87
+ if (!raw) continue;
88
+ headings.push({
89
+ level,
90
+ text: raw,
91
+ id: nextId(raw)
92
+ });
93
+ }
94
+ return headings;
95
+ }
96
+ //#endregion
97
+ exports.copyToClipboard = copyToClipboard;
98
+ exports.createHeadingIdFactory = createHeadingIdFactory;
99
+ exports.extractHeadings = extractHeadings;
100
+ exports.flattenText = flattenText;
101
+ exports.isMediaOnlyParagraph = isMediaOnlyParagraph;
@@ -0,0 +1,40 @@
1
+ /*!
2
+ * @willa-ui/shared.js v0.0.1-alpha.8d8fe96
3
+ * (c) 2026 chentao.arthur
4
+ */
5
+ import { ReactNode } from "react";
6
+
7
+ //#region src/clipboard.d.ts
8
+ declare function copyToClipboard(text: string): Promise<boolean>;
9
+ //#endregion
10
+ //#region src/nodes.d.ts
11
+ declare function isMediaOnlyParagraph(children: ReactNode): boolean;
12
+ //#endregion
13
+ //#region src/types.d.ts
14
+ type Heading = {
15
+ level: 2 | 3;
16
+ text: string;
17
+ id: string;
18
+ };
19
+ type LightboxImage = {
20
+ src: string;
21
+ alt?: string;
22
+ caption?: string;
23
+ id?: string;
24
+ };
25
+ type LightboxState = {
26
+ images: Array<LightboxImage>;
27
+ currentIndex: number;
28
+ selectedIndex?: number;
29
+ selectedId?: string;
30
+ selectedImage?: LightboxImage;
31
+ };
32
+ type OpenLightbox = (state: LightboxState | null) => void;
33
+ type ResolveAssetUrl = (articleSourcePath: string, assetPath: string) => string | undefined;
34
+ //#endregion
35
+ //#region src/heading.d.ts
36
+ declare function flattenText(node: unknown): string;
37
+ declare function createHeadingIdFactory(): (text: string) => string;
38
+ declare function extractHeadings(source: string): Heading[];
39
+ //#endregion
40
+ export { type Heading, type LightboxImage, type LightboxState, type OpenLightbox, type ResolveAssetUrl, copyToClipboard, createHeadingIdFactory, extractHeadings, flattenText, isMediaOnlyParagraph };
@@ -0,0 +1,123 @@
1
+ /*!
2
+ * @willa-ui/shared.js v0.0.1-alpha.8d8fe96
3
+ * (c) 2026 chentao.arthur
4
+ */
5
+ var WillaUiShared = (function (exports, react) {
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ //#region src/clipboard.ts
8
+ async function copyToClipboard(text) {
9
+ if (!text) return false;
10
+ try {
11
+ await navigator.clipboard.writeText(text);
12
+ return true;
13
+ } catch {
14
+ try {
15
+ const el = document.createElement("textarea");
16
+ el.value = text;
17
+ el.style.position = "fixed";
18
+ el.style.left = "-9999px";
19
+ el.style.top = "0";
20
+ document.body.appendChild(el);
21
+ el.focus();
22
+ el.select();
23
+ const ok = document.execCommand("copy");
24
+ document.body.removeChild(el);
25
+ return ok;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ }
31
+ //#endregion
32
+ //#region ../../node_modules/.pnpm/aidly@1.37.0/node_modules/aidly/dist/aidly.esm-bundler.js
33
+ const isArray = /* @__PURE__ */ (() => Array.isArray)();
34
+ const isNil = (val) => {
35
+ return val === void 0 || val === null;
36
+ };
37
+ const isString = (val) => {
38
+ return typeof val === "string";
39
+ };
40
+ //#endregion
41
+ //#region src/nodes.ts
42
+ const toNodeArray = (children) => {
43
+ return (isArray(children) ? children : [children]).filter((item) => {
44
+ if (isNil(item) || typeof item === "boolean") return false;
45
+ if (isString(item)) return item.trim().length > 0;
46
+ return true;
47
+ });
48
+ };
49
+ function isMediaOnlyParagraph(children) {
50
+ const nodes = toNodeArray(children);
51
+ if (nodes.length !== 1) return false;
52
+ const node = nodes[0];
53
+ if (!(0, react.isValidElement)(node)) return false;
54
+ if (node.type === "img") return true;
55
+ return Boolean(node.type.__willaMediaElement);
56
+ }
57
+ //#endregion
58
+ //#region src/heading.ts
59
+ const toHeadingSlug = (value) => {
60
+ return value
61
+ .trim()
62
+ .replace(/\[[^\]]*\]\([^)]*\)/g, (m) => {
63
+ return /^\[([^\]]*)\]/.exec(m)?.[1] ?? "";
64
+ })
65
+ .replace(/`+/g, "")
66
+ .replace(/[*_~]/g, "")
67
+ .replace(/<[^>]+>/g, "")
68
+ .toLowerCase()
69
+ .replace(/\s+/g, "-")
70
+ .replace(/[^\p{L}\p{N}-]+/gu, "")
71
+ .replace(/-+/g, "-")
72
+ .replace(/^-|-$/g, "");
73
+ };
74
+ function flattenText(node) {
75
+ if (isNil(node)) return "";
76
+ if (typeof node === "string" || typeof node === "number")
77
+ return String(node);
78
+ if (isArray(node)) return node.map(flattenText).join("");
79
+ if (typeof node === "object" && "props" in node)
80
+ return flattenText(node.props?.children);
81
+ return "";
82
+ }
83
+ function createHeadingIdFactory() {
84
+ const counts = /* @__PURE__ */ new Map();
85
+ return (text) => {
86
+ const base = toHeadingSlug(text) || "section";
87
+ const next = (counts.get(base) ?? 0) + 1;
88
+ counts.set(base, next);
89
+ return next === 1 ? base : `${base}-${next}`;
90
+ };
91
+ }
92
+ function extractHeadings(source) {
93
+ const nextId = createHeadingIdFactory();
94
+ const headings = [];
95
+ const lines = source.split(/\r?\n/);
96
+ let inFence = false;
97
+ for (const line of lines) {
98
+ if (/^```/.test(line.trim())) {
99
+ inFence = !inFence;
100
+ continue;
101
+ }
102
+ if (inFence) continue;
103
+ const match = /^(#{2,3})\s+(.+?)\s*$/.exec(line);
104
+ if (!match) continue;
105
+ const level = match[1].length;
106
+ const raw = match[2].replace(/\s+#+\s*$/, "").trim();
107
+ if (!raw) continue;
108
+ headings.push({
109
+ level,
110
+ text: raw,
111
+ id: nextId(raw),
112
+ });
113
+ }
114
+ return headings;
115
+ }
116
+ //#endregion
117
+ exports.copyToClipboard = copyToClipboard;
118
+ exports.createHeadingIdFactory = createHeadingIdFactory;
119
+ exports.extractHeadings = extractHeadings;
120
+ exports.flattenText = flattenText;
121
+ exports.isMediaOnlyParagraph = isMediaOnlyParagraph;
122
+ return exports;
123
+ })({}, React);
package/dist/index.js ADDED
@@ -0,0 +1,113 @@
1
+ /*!
2
+ * @willa-ui/shared.js v0.0.1-alpha.8d8fe96
3
+ * (c) 2026 chentao.arthur
4
+ */
5
+ import { isValidElement } from "react";
6
+ import { isArray, isNil, isString } from "aidly";
7
+ //#region src/clipboard.ts
8
+ async function copyToClipboard(text) {
9
+ if (!text) return false;
10
+ try {
11
+ await navigator.clipboard.writeText(text);
12
+ return true;
13
+ } catch {
14
+ try {
15
+ const el = document.createElement("textarea");
16
+ el.value = text;
17
+ el.style.position = "fixed";
18
+ el.style.left = "-9999px";
19
+ el.style.top = "0";
20
+ document.body.appendChild(el);
21
+ el.focus();
22
+ el.select();
23
+ const ok = document.execCommand("copy");
24
+ document.body.removeChild(el);
25
+ return ok;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ }
31
+ //#endregion
32
+ //#region src/nodes.ts
33
+ const toNodeArray = (children) => {
34
+ return (isArray(children) ? children : [children]).filter((item) => {
35
+ if (isNil(item) || typeof item === "boolean") return false;
36
+ if (isString(item)) return item.trim().length > 0;
37
+ return true;
38
+ });
39
+ };
40
+ function isMediaOnlyParagraph(children) {
41
+ const nodes = toNodeArray(children);
42
+ if (nodes.length !== 1) return false;
43
+ const node = nodes[0];
44
+ if (!isValidElement(node)) return false;
45
+ if (node.type === "img") return true;
46
+ return Boolean(node.type.__willaMediaElement);
47
+ }
48
+ //#endregion
49
+ //#region src/heading.ts
50
+ const toHeadingSlug = (value) => {
51
+ return value
52
+ .trim()
53
+ .replace(/\[[^\]]*\]\([^)]*\)/g, (m) => {
54
+ return /^\[([^\]]*)\]/.exec(m)?.[1] ?? "";
55
+ })
56
+ .replace(/`+/g, "")
57
+ .replace(/[*_~]/g, "")
58
+ .replace(/<[^>]+>/g, "")
59
+ .toLowerCase()
60
+ .replace(/\s+/g, "-")
61
+ .replace(/[^\p{L}\p{N}-]+/gu, "")
62
+ .replace(/-+/g, "-")
63
+ .replace(/^-|-$/g, "");
64
+ };
65
+ function flattenText(node) {
66
+ if (isNil(node)) return "";
67
+ if (typeof node === "string" || typeof node === "number") return String(node);
68
+ if (isArray(node)) return node.map(flattenText).join("");
69
+ if (typeof node === "object" && "props" in node)
70
+ return flattenText(node.props?.children);
71
+ return "";
72
+ }
73
+ function createHeadingIdFactory() {
74
+ const counts = /* @__PURE__ */ new Map();
75
+ return (text) => {
76
+ const base = toHeadingSlug(text) || "section";
77
+ const next = (counts.get(base) ?? 0) + 1;
78
+ counts.set(base, next);
79
+ return next === 1 ? base : `${base}-${next}`;
80
+ };
81
+ }
82
+ function extractHeadings(source) {
83
+ const nextId = createHeadingIdFactory();
84
+ const headings = [];
85
+ const lines = source.split(/\r?\n/);
86
+ let inFence = false;
87
+ for (const line of lines) {
88
+ if (/^```/.test(line.trim())) {
89
+ inFence = !inFence;
90
+ continue;
91
+ }
92
+ if (inFence) continue;
93
+ const match = /^(#{2,3})\s+(.+?)\s*$/.exec(line);
94
+ if (!match) continue;
95
+ const level = match[1].length;
96
+ const raw = match[2].replace(/\s+#+\s*$/, "").trim();
97
+ if (!raw) continue;
98
+ headings.push({
99
+ level,
100
+ text: raw,
101
+ id: nextId(raw),
102
+ });
103
+ }
104
+ return headings;
105
+ }
106
+ //#endregion
107
+ export {
108
+ copyToClipboard,
109
+ createHeadingIdFactory,
110
+ extractHeadings,
111
+ flattenText,
112
+ isMediaOnlyParagraph,
113
+ };
package/dist/index.mjs ADDED
@@ -0,0 +1,96 @@
1
+ /*!
2
+ * @willa-ui/shared.js v0.0.1-alpha.8d8fe96
3
+ * (c) 2026 chentao.arthur
4
+ */
5
+ import { isValidElement } from "react";
6
+ import { isArray, isNil, isString } from "aidly";
7
+ //#region src/clipboard.ts
8
+ async function copyToClipboard(text) {
9
+ if (!text) return false;
10
+ try {
11
+ await navigator.clipboard.writeText(text);
12
+ return true;
13
+ } catch {
14
+ try {
15
+ const el = document.createElement("textarea");
16
+ el.value = text;
17
+ el.style.position = "fixed";
18
+ el.style.left = "-9999px";
19
+ el.style.top = "0";
20
+ document.body.appendChild(el);
21
+ el.focus();
22
+ el.select();
23
+ const ok = document.execCommand("copy");
24
+ document.body.removeChild(el);
25
+ return ok;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ }
31
+ //#endregion
32
+ //#region src/nodes.ts
33
+ const toNodeArray = (children) => {
34
+ return (isArray(children) ? children : [children]).filter((item) => {
35
+ if (isNil(item) || typeof item === "boolean") return false;
36
+ if (isString(item)) return item.trim().length > 0;
37
+ return true;
38
+ });
39
+ };
40
+ function isMediaOnlyParagraph(children) {
41
+ const nodes = toNodeArray(children);
42
+ if (nodes.length !== 1) return false;
43
+ const node = nodes[0];
44
+ if (!isValidElement(node)) return false;
45
+ if (node.type === "img") return true;
46
+ return Boolean(node.type.__willaMediaElement);
47
+ }
48
+ //#endregion
49
+ //#region src/heading.ts
50
+ const toHeadingSlug = (value) => {
51
+ return value.trim().replace(/\[[^\]]*\]\([^)]*\)/g, (m) => {
52
+ return /^\[([^\]]*)\]/.exec(m)?.[1] ?? "";
53
+ }).replace(/`+/g, "").replace(/[*_~]/g, "").replace(/<[^>]+>/g, "").toLowerCase().replace(/\s+/g, "-").replace(/[^\p{L}\p{N}-]+/gu, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
54
+ };
55
+ function flattenText(node) {
56
+ if (isNil(node)) return "";
57
+ if (typeof node === "string" || typeof node === "number") return String(node);
58
+ if (isArray(node)) return node.map(flattenText).join("");
59
+ if (typeof node === "object" && "props" in node) return flattenText(node.props?.children);
60
+ return "";
61
+ }
62
+ function createHeadingIdFactory() {
63
+ const counts = /* @__PURE__ */ new Map();
64
+ return (text) => {
65
+ const base = toHeadingSlug(text) || "section";
66
+ const next = (counts.get(base) ?? 0) + 1;
67
+ counts.set(base, next);
68
+ return next === 1 ? base : `${base}-${next}`;
69
+ };
70
+ }
71
+ function extractHeadings(source) {
72
+ const nextId = createHeadingIdFactory();
73
+ const headings = [];
74
+ const lines = source.split(/\r?\n/);
75
+ let inFence = false;
76
+ for (const line of lines) {
77
+ if (/^```/.test(line.trim())) {
78
+ inFence = !inFence;
79
+ continue;
80
+ }
81
+ if (inFence) continue;
82
+ const match = /^(#{2,3})\s+(.+?)\s*$/.exec(line);
83
+ if (!match) continue;
84
+ const level = match[1].length;
85
+ const raw = match[2].replace(/\s+#+\s*$/, "").trim();
86
+ if (!raw) continue;
87
+ headings.push({
88
+ level,
89
+ text: raw,
90
+ id: nextId(raw)
91
+ });
92
+ }
93
+ return headings;
94
+ }
95
+ //#endregion
96
+ export { copyToClipboard, createHeadingIdFactory, extractHeadings, flattenText, isMediaOnlyParagraph };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@willa-ui/shared",
3
+ "version": "0.0.1-alpha.8d8fe96",
4
+ "description": "Shared utilities and types for Willa UI.",
5
+ "author": "chentao.arthur",
6
+ "license": "MIT",
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./dist/index.d.cts",
11
+ "default": "./dist/index.mjs"
12
+ },
13
+ "require": {
14
+ "types": "./dist/index.d.cts",
15
+ "default": "./dist/index.cjs"
16
+ }
17
+ }
18
+ },
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.mjs",
21
+ "unpkg": "./dist/index.global.js",
22
+ "types": "./dist/index.d.cts",
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "dependencies": {
27
+ "aidly": "1.37.0"
28
+ },
29
+ "peerDependencies": {
30
+ "react": "19.2.6"
31
+ },
32
+ "devDependencies": {
33
+ "@types/react": "19.2.14",
34
+ "@vitest/coverage-v8": "1.6.0",
35
+ "auklet": "0.0.29",
36
+ "vitest": "1.6.0",
37
+ "typescript": "6.0.3"
38
+ },
39
+ "scripts": {
40
+ "dev": "auk dev",
41
+ "build": "auk build",
42
+ "test": "vitest run",
43
+ "test:coverage": "vitest run --coverage"
44
+ }
45
+ }