@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 +1 -0
- package/dist/index.cjs +101 -0
- package/dist/index.d.cts +40 -0
- package/dist/index.global.js +123 -0
- package/dist/index.js +113 -0
- package/dist/index.mjs +96 -0
- package/package.json +45 -0
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;
|
package/dist/index.d.cts
ADDED
|
@@ -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
|
+
}
|