@agentaily/design-system 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DESIGN.md CHANGED
@@ -93,13 +93,13 @@ Examples — ✓ "Rate limited. Retry in 18s." ✗ "Oops! Something went wrong
93
93
  | `components/feedback/` | Spinner, Toast, Tooltip, Dialog, Alert |
94
94
  | `components/overlay/` | Popover, DropdownMenu, Command, Sheet, **HoverCard, ContextMenu, Menubar, NavigationMenu, AlertDialog** |
95
95
  | `components/layout/` | **AspectRatio, ScrollArea, Resizable, Sidebar, AppShell, DesignerShell, DocsLayout, SettingsPage** — incl. full-page shells/frames |
96
- | `components/chat/` | Message, Composer, CodeBlock, **ConversationThread** |
96
+ | `components/chat/` | Message, Composer, CodeBlock, **ConversationThread, Markdown** |
97
97
  | `components/ai/` | Reasoning, ToolCall, Sources + Citation, Suggestion/Suggestions, ModelSelector, Attachments, Shimmer, **Conversation, Task, Plan, Context, Confirmation, Checkpoint, Queue** |
98
98
  | `components/code/` | **Terminal, FileTree, Snippet, StackTrace, TestResults, Artifact, WebPreview, Agent, Commit, EnvironmentVariables, PackageInfo, Sandbox, SchemaDisplay, JSXPreview** |
99
99
  | `components/voice/` | **AudioPlayer, MicSelector, VoiceSelector, SpeechInput, Transcription, Persona** |
100
100
  | `components/workflow/` | **Flow (Canvas), Canvas, Node, Edge, Connection, Controls, Panel, Toolbar** |
101
101
  | `components/utilities/` | **Image, OpenInChat, Icon (unified Lucide set), BrandMark, RotatingTagline** |
102
- | `components/settings/` | **TestRow, HelpSteps, IntegrationSettings** — connection-card primitives + the DeepSeek/Feishu integration modal |
102
+ | `components/settings/` | **TestRow, HelpSteps, DeepSeekCard, FeishuCard** — connection-card primitives + two pure-display service cards (state belongs to the caller) |
103
103
  | `components/auth/` | **AuthDialog (+ AuthDialog.useAuth), AccountControl, SignInPage** — sign-in/register modal + persisted session + top-bar account menu + full-page sign-in |
104
104
  | `components/review/` | **MarkupLayer** — point-at-an-element review overlay (`data-mk-label`) |
105
105
  | **Hooks** (headless) | `Queue.useQueue`, `AuthDialog.useAuth`, `Form.useForm` / `Form.useFieldArray` — logic without UI, exposed as statics on the paired component |
@@ -108,7 +108,7 @@ Examples — ✓ "Rate limited. Retry in 18s." ✗ "Oops! Something went wrong
108
108
  | `ui_kits/docs/` | Documentation site (interactive) |
109
109
  | `SKILL.md` | Agent-skill entry point |
110
110
 
111
- Every component ships `<Name>.jsx` + `<Name>.d.ts` (props) + `<Name>.prompt.md` (usage) — **146 component exports** across the primitive categories (buttons, inputs, display, feedback, overlay, layout, chat, ai, code, voice, workflow, utilities) plus product-domain layers (**settings, auth, review**). Full-page frames — `AppShell` / `DesignerShell` / `DocsLayout` / `SettingsPage` (layout), `ConversationThread` (chat), `SignInPage` (auth) — are **live components, not copy-templates**: change one, every consuming project benefits on re-sync. Consume via the compiled bundle: `window.AxiomDesignSystem_7fc962`. Read each component's `.prompt.md` for copy-paste usage.
111
+ Every component ships `<Name>.jsx` + `<Name>.d.ts` (props) + `<Name>.prompt.md` (usage) — **148 component exports** across the primitive categories (buttons, inputs, display, feedback, overlay, layout, chat, ai, code, voice, workflow, utilities) plus product-domain layers (**settings, auth, review**). Full-page frames — `AppShell` / `DesignerShell` / `DocsLayout` / `SettingsPage` (layout), `ConversationThread` (chat), `SignInPage` (auth) — are **live components, not copy-templates**: change one, every consuming project benefits on re-sync. Consume via the compiled bundle: `window.AxiomDesignSystem_7fc962`. Read each component's `.prompt.md` for copy-paste usage.
112
112
 
113
113
  **Forms are layered, not monolithic.** Presentational controls (Input/Select/Field…) own layout and never depend on a form engine. `Form` + `FormActions` add pure structure. `Form.useForm` is an **optional**, zero-dependency orchestration hook (values/errors/touched/validate/submit) exposed off the capitalized `Form` export — drop it for react-hook-form or TanStack and the controls still work. Errors surface only after blur or submit; spread `form.field(name)` onto any value control, or `form.field(name, {type:"checkbox"})` for boolean ones.
114
114
 
@@ -123,13 +123,13 @@ The system sits on **two orthogonal axes**. Don't conflate them: a *domain* is n
123
123
  | **L0 Tokens** | colour / type / space / radius / shadow / motion variables | — | `tokens/*.css` |
124
124
  | **L1 Primitives** (atoms) | no business meaning, usable anywhere | tokens | `Button`, `Input`, `Badge`, `Icon`, `BrandMark`, `RotatingTagline` |
125
125
  | **L2 Composites** (molecules) | a few primitives combined; still cross-product | L1 | `Composer`, `SecretField`, `StatusPill` |
126
- | **L3 Patterns** (organisms) | self-contained interaction + state, configurable | L1–L2 | `AuthDialog`, `IntegrationSettings`, `MarkupLayer`, `ConversationThread` |
126
+ | **L3 Patterns** (organisms) | self-contained interaction + state, configurable | L1–L2 | `AuthDialog`, `MarkupLayer`, `ConversationThread`, `DeepSeekCard` / `FeishuCard` (display-only — caller owns state) |
127
127
  | **L4 Page shells / frames** | full-page layout with slots | L1–L3 | `AppShell`, `DesignerShell`, `DocsLayout`, `SettingsPage`, `SignInPage` |
128
128
  | **L5 Product code** | real content + business logic — **never lives in the DS** | L4 | each app's flow / preview renderer |
129
129
 
130
130
  ### ② 横向 — domains (categorization *inside* a layer, not a level)
131
131
 
132
- `buttons · inputs · display · feedback · overlay · layout · chat · ai · code · voice · workflow · utilities · settings · auth · review`. A product-domain component (e.g. `IntegrationSettings`) lives at its **abstraction layer** (L3) and is merely *filed* under its **domain folder** (`settings/`). Domains are folders, not tiers.
132
+ `buttons · inputs · display · feedback · overlay · layout · chat · ai · code · voice · workflow · utilities · settings · auth · review`. A product-domain component (e.g. `FeishuCard`) lives at its **abstraction layer** and is merely *filed* under its **domain folder** (`settings/`). Domains are folders, not tiers.
133
133
 
134
134
  **Where does a component go?** Ask: (1) what does it depend on? — composites + own state → higher. (2) reused by ≥2 surfaces? — if not, keep it in the app, not the DS. (3) how much business meaning? — more → higher layer, more generic → lower.
135
135
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # agentaily design system
2
2
 
3
- Agentaily(AI chatbot)设计系统:113 个 React 组件 + Storybook,单色亮色优先(暗色可切)。品牌一句话:**极客风格,简约,大气,科技感**。
3
+ Agentaily(AI chatbot)设计系统:115 个 React 组件 + Storybook,单色亮色优先(暗色可切)。品牌一句话:**极客风格,简约,大气,科技感**。
4
4
 
5
5
  📖 **在线 Storybook:** https://agentaily.github.io/design-system/
6
6
 
@@ -28,7 +28,7 @@ npm run build:lib # 产出 dist/:每组件一个 .js + index.d.ts + styles.css
28
28
 
29
29
  | 路径 | 内容 |
30
30
  | ----------------------------------------------- | ----------------------------------------- |
31
- | `dist/index.js` | ESM 入口,re-export 全部 113 个组件符号 |
31
+ | `dist/index.js` | ESM 入口,re-export 全部 115 个组件符号 |
32
32
  | `dist/components/**/*.js` | 每个组件独立模块(含运行时 CSS 注入) |
33
33
  | `dist/index.d.ts` + `dist/components/**/*.d.ts` | TypeScript 类型契约 |
34
34
  | `dist/styles.css` | 内联好的 tokens + 字体,消费方 import 一次 |
@@ -39,7 +39,7 @@ export interface SignInPageProps {
39
39
  defaultMode?: "signin" | "signup";
40
40
  /** Fires when the footer link flips mode — wire to your router (/signin ↔ /signup). */
41
41
  onModeChange?: (mode: "signin" | "signup") => void;
42
- /** Brand-panel lockup. @default <BrandMark wordmark /> (blinking cursor) */
42
+ /** Brand-panel lockup. @default <BrandMark wordmark /> (no cursor) */
43
43
  brand?: React.ReactNode;
44
44
  /**
45
45
  * All user-facing strings, deep-merged over the English defaults. Per-mode
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Renders a model's markdown STRING into typeset, theme-aware React nodes.
3
+ *
4
+ * Composable primitive for any surface that shows model output. `<Message>`
5
+ * uses it internally to render assistant prose, but it stands alone too.
6
+ *
7
+ * Coverage: paragraphs + soft line breaks, **bold**, *italic*, ~~strikethrough~~,
8
+ * `inline code`, fenced ```code blocks``` (rendered via <CodeBlock>), unordered +
9
+ * ordered + nested (mixed) lists, GitHub task lists (- [ ] / - [x]), blockquotes
10
+ * (nested), GFM tables with per-column alignment (overflow scrolls), horizontal
11
+ * rules (--- / *** / ___), #/##/### headings, [links](url), and bare-URL autolinks.
12
+ * Images ![alt](url) render as an inert placeholder chip — never fetched.
13
+ *
14
+ * Safety: the string is parsed to a node tree and emitted as React elements
15
+ * only — never dangerouslySetInnerHTML — so all literal text is auto-escaped
16
+ * and there is no HTML-injection surface. Link hrefs are scheme-sanitized
17
+ * (javascript:/data:/vbscript: are dropped); images are not loaded.
18
+ *
19
+ * Streaming: unterminated inline delimiters (** ` _ ~~ [..]( ) degrade to literal
20
+ * text; a half table, a half blockquote, and an unclosed ``` fence render their
21
+ * partial content, so a half-streamed token never throws or vanishes mid-stream.
22
+ */
23
+ export interface MarkdownProps {
24
+ /** The markdown source string. Takes precedence over a string `children`. */
25
+ content?: string;
26
+ /** Alternative to `content`: a markdown string passed as children. */
27
+ children?: string;
28
+ className?: string;
29
+ }
30
+ export declare function Markdown(props: MarkdownProps): JSX.Element;
@@ -0,0 +1,502 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { CodeBlock } from "./CodeBlock.js";
4
+ const AX_MD_CSS = `
5
+ .ax-md { font-size: var(--text-md); line-height: var(--leading-body); color: var(--text-body); min-width: 0; }
6
+ .ax-md > :first-child { margin-top: 0; }
7
+ .ax-md > :last-child { margin-bottom: 0; }
8
+
9
+ .ax-md__p { margin: 0 0 0.7em; text-wrap: pretty; }
10
+
11
+ .ax-md__ul, .ax-md__ol { margin: 0 0 0.7em; padding-left: 1.5em; }
12
+ .ax-md__li { margin: 0.2em 0; }
13
+ .ax-md__li > .ax-md__ul, .ax-md__li > .ax-md__ol { margin: 0.25em 0 0; padding-left: 1.3em; }
14
+
15
+ .ax-md__ul { list-style: none; padding-left: 1.35em; }
16
+ .ax-md__ul > .ax-md__li { position: relative; }
17
+ .ax-md__ul > .ax-md__li::before {
18
+ content: ""; position: absolute; left: -1.05em; top: 0.62em;
19
+ width: 4px; height: 4px; background: var(--text-faint);
20
+ }
21
+
22
+ .ax-md__ol { list-style: decimal; padding-left: 1.7em; }
23
+ .ax-md__ol > .ax-md__li::marker {
24
+ font-family: var(--font-mono); font-size: 0.9em; color: var(--text-faint);
25
+ }
26
+
27
+ .ax-md__li--task { list-style: none; display: flex; align-items: flex-start; gap: 8px; }
28
+ .ax-md__ul > .ax-md__li--task::before { display: none; }
29
+ .ax-md__check {
30
+ appearance: none; -webkit-appearance: none; margin: 3px 0 0; flex: none;
31
+ width: 15px; height: 15px; border: 1px solid var(--border-strong);
32
+ border-radius: var(--radius-1); background: var(--bg-0); position: relative; cursor: default;
33
+ }
34
+ .ax-md__check:checked { background: var(--accent); border-color: var(--accent); }
35
+ .ax-md__check:checked::after {
36
+ content: ""; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px;
37
+ border: solid var(--accent-fg); border-width: 0 1.6px 1.6px 0; transform: rotate(45deg);
38
+ }
39
+ .ax-md__li--task > .ax-md__taskbody { flex: 1; min-width: 0; }
40
+
41
+ .ax-md__strong { font-weight: var(--weight-bold); color: var(--text-body); }
42
+ .ax-md__em { font-style: italic; }
43
+ .ax-md__del { text-decoration: line-through; text-decoration-thickness: 1px; color: var(--text-muted); }
44
+
45
+ .ax-md__code {
46
+ font-family: var(--font-mono); font-size: 0.86em;
47
+ background: var(--bg-3); color: var(--text-body);
48
+ border: 1px solid var(--border-default);
49
+ border-radius: var(--radius-1); padding: 0.12em 0.36em;
50
+ white-space: break-spaces; word-break: break-word;
51
+ }
52
+ [data-theme="dark"] .ax-md__code { background: var(--bg-2); }
53
+
54
+ .ax-md > .ax-code, .ax-md__li > .ax-code, .ax-md__quote > .ax-code { margin: 0 0 0.7em; }
55
+
56
+ .ax-md__link {
57
+ color: var(--text-body); text-decoration: underline;
58
+ text-underline-offset: 2px; text-decoration-color: var(--border-strong);
59
+ transition: text-decoration-color var(--dur-1) var(--ease-out);
60
+ word-break: break-word;
61
+ }
62
+ .ax-md__link:hover { text-decoration-color: var(--text-body); }
63
+
64
+ .ax-md__img {
65
+ display: inline-flex; align-items: center; gap: 6px; vertical-align: baseline;
66
+ padding: 1px 8px; border: 1px dashed var(--border-strong); border-radius: var(--radius-1);
67
+ font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-faint);
68
+ }
69
+ .ax-md__img b { font-weight: var(--weight-medium); letter-spacing: var(--tracking-label); }
70
+
71
+ .ax-md__quote {
72
+ margin: 0 0 0.7em; padding: 2px 0 2px 14px;
73
+ border-left: 2px solid var(--border-strong); color: var(--text-muted);
74
+ }
75
+ .ax-md__quote > :last-child { margin-bottom: 0; }
76
+ .ax-md__quote .ax-md__quote { margin-top: 0.5em; }
77
+
78
+ .ax-md__hr { border: none; border-top: 1px solid var(--border-default); margin: 1.2em 0; }
79
+
80
+ .ax-md__tablewrap {
81
+ margin: 0 0 0.7em; overflow-x: auto;
82
+ border: 1px solid var(--border-default); border-radius: var(--radius-2);
83
+ }
84
+ .ax-md__table { border-collapse: collapse; width: 100%; font-size: var(--text-sm); }
85
+ .ax-md__table th, .ax-md__table td {
86
+ padding: 7px 12px; text-align: left; vertical-align: top;
87
+ border-bottom: 1px solid var(--border-default); border-right: 1px solid var(--border-default);
88
+ }
89
+ .ax-md__table th:last-child, .ax-md__table td:last-child { border-right: none; }
90
+ .ax-md__table tbody tr:last-child td { border-bottom: none; }
91
+ .ax-md__table thead th {
92
+ background: var(--surface-card); color: var(--text-body);
93
+ font-weight: var(--weight-medium); white-space: nowrap;
94
+ }
95
+
96
+ .ax-md__h { font-family: var(--font-display); font-weight: var(--weight-medium);
97
+ line-height: var(--leading-snug); letter-spacing: var(--tracking-tight);
98
+ margin: 1.1em 0 0.5em; color: var(--text-body); }
99
+ .ax-md__h--1 { font-size: var(--text-xl); }
100
+ .ax-md__h--2 { font-size: var(--text-lg); }
101
+ .ax-md__h--3 { font-size: var(--text-md); }
102
+ `;
103
+ if (typeof document !== "undefined" && !document.getElementById("ax-md-css")) {
104
+ const s = document.createElement("style");
105
+ s.id = "ax-md-css";
106
+ s.textContent = AX_MD_CSS;
107
+ document.head.appendChild(s);
108
+ }
109
+ function sanitizeUrl(raw) {
110
+ const url = String(raw || "").replace(/[\u0000-\u001F\u007F]/g, "").trim();
111
+ if (!url) return null;
112
+ if (/^[a-z][a-z0-9+.-]*:/i.test(url)) {
113
+ if (/^(https?|mailto|tel):/i.test(url)) return url;
114
+ return null;
115
+ }
116
+ return url;
117
+ }
118
+ function parseInline(text, keyBase) {
119
+ const out = [];
120
+ let buf = "";
121
+ let i = 0;
122
+ let k = 0;
123
+ const len = text.length;
124
+ const flush = () => {
125
+ if (buf) {
126
+ out.push(buf);
127
+ buf = "";
128
+ }
129
+ };
130
+ while (i < len) {
131
+ const ch = text[i];
132
+ const rest = text.slice(i);
133
+ if (ch === "\n") {
134
+ flush();
135
+ out.push(/* @__PURE__ */ jsx("br", {}, keyBase + "-br" + k++));
136
+ i++;
137
+ continue;
138
+ }
139
+ if (ch === "\\" && i + 1 < len && /[\\`*_{}\[\]()#+\-.!~|>]/.test(text[i + 1])) {
140
+ buf += text[i + 1];
141
+ i += 2;
142
+ continue;
143
+ }
144
+ let m;
145
+ if (ch === "`" && (m = /^`([^`\n]+?)`/.exec(rest))) {
146
+ flush();
147
+ out.push(
148
+ /* @__PURE__ */ jsx("code", { className: "ax-md__code", children: m[1] }, keyBase + "-c" + k++)
149
+ );
150
+ i += m[0].length;
151
+ continue;
152
+ }
153
+ if (ch === "!" && text[i + 1] === "[" && (m = /^!\[([^\]]*)\]\(([^)\s]*)\)/.exec(rest))) {
154
+ flush();
155
+ out.push(
156
+ /* @__PURE__ */ jsxs("span", { className: "ax-md__img", title: m[2], children: [
157
+ /* @__PURE__ */ jsx("b", { children: "IMG" }),
158
+ m[1] ? " · " + m[1] : ""
159
+ ] }, keyBase + "-img" + k++)
160
+ );
161
+ i += m[0].length;
162
+ continue;
163
+ }
164
+ if (ch === "[" && (m = /^\[([^\]]*)\]\(([^)\s]*)\)/.exec(rest))) {
165
+ flush();
166
+ const href = sanitizeUrl(m[2]);
167
+ const inner = parseInline(m[1], keyBase + "-lt" + k);
168
+ out.push(
169
+ href ? /* @__PURE__ */ jsx(
170
+ "a",
171
+ {
172
+ className: "ax-md__link",
173
+ href,
174
+ target: "_blank",
175
+ rel: "noopener noreferrer nofollow",
176
+ children: inner
177
+ },
178
+ keyBase + "-l" + k++
179
+ ) : /* @__PURE__ */ jsx("span", { children: inner }, keyBase + "-l" + k++)
180
+ );
181
+ i += m[0].length;
182
+ continue;
183
+ }
184
+ if ((ch === "h" || ch === "w") && (i === 0 || /[\s(]/.test(text[i - 1])) && (m = /^((?:https?:\/\/|www\.)[^\s<>]+)/i.exec(rest))) {
185
+ let urlText = m[1];
186
+ const trail = /[.,;:!?'")\]]+$/.exec(urlText);
187
+ if (trail) urlText = urlText.slice(0, urlText.length - trail[0].length);
188
+ const href = sanitizeUrl(/^www\./i.test(urlText) ? "http://" + urlText : urlText);
189
+ if (href) {
190
+ flush();
191
+ out.push(
192
+ /* @__PURE__ */ jsx(
193
+ "a",
194
+ {
195
+ className: "ax-md__link",
196
+ href,
197
+ target: "_blank",
198
+ rel: "noopener noreferrer nofollow",
199
+ children: urlText
200
+ },
201
+ keyBase + "-a" + k++
202
+ )
203
+ );
204
+ i += urlText.length;
205
+ continue;
206
+ }
207
+ }
208
+ if (ch === "*" && (m = /^\*\*([\s\S]+?)\*\*/.exec(rest))) {
209
+ flush();
210
+ out.push(
211
+ /* @__PURE__ */ jsx("strong", { className: "ax-md__strong", children: parseInline(m[1], keyBase + "-bt" + k) }, keyBase + "-b" + k++)
212
+ );
213
+ i += m[0].length;
214
+ continue;
215
+ }
216
+ if (ch === "_" && (m = /^__([\s\S]+?)__/.exec(rest))) {
217
+ flush();
218
+ out.push(
219
+ /* @__PURE__ */ jsx("strong", { className: "ax-md__strong", children: parseInline(m[1], keyBase + "-bt" + k) }, keyBase + "-b" + k++)
220
+ );
221
+ i += m[0].length;
222
+ continue;
223
+ }
224
+ if (ch === "~" && (m = /^~~([\s\S]+?)~~/.exec(rest))) {
225
+ flush();
226
+ out.push(
227
+ /* @__PURE__ */ jsx("del", { className: "ax-md__del", children: parseInline(m[1], keyBase + "-st" + k) }, keyBase + "-s" + k++)
228
+ );
229
+ i += m[0].length;
230
+ continue;
231
+ }
232
+ if (ch === "*" && (m = new RegExp("^\\*(?!\\s)([^*]+?)(?<!\\s)\\*").exec(rest))) {
233
+ flush();
234
+ out.push(
235
+ /* @__PURE__ */ jsx("em", { className: "ax-md__em", children: parseInline(m[1], keyBase + "-it" + k) }, keyBase + "-i" + k++)
236
+ );
237
+ i += m[0].length;
238
+ continue;
239
+ }
240
+ if (ch === "_" && (m = new RegExp("^_(?!\\s)([^_]+?)(?<!\\s)_").exec(rest))) {
241
+ flush();
242
+ out.push(
243
+ /* @__PURE__ */ jsx("em", { className: "ax-md__em", children: parseInline(m[1], keyBase + "-it" + k) }, keyBase + "-i" + k++)
244
+ );
245
+ i += m[0].length;
246
+ continue;
247
+ }
248
+ buf += ch;
249
+ i++;
250
+ }
251
+ flush();
252
+ return out;
253
+ }
254
+ const RE_FENCE = /^(\s{0,3})(`{3,}|~{3,})\s*([\w+#.-]*)\s*$/;
255
+ const RE_HEADING = /^(#{1,6})\s+(.*)$/;
256
+ const RE_HR = /^\s{0,3}([-*_])(?:\s*\1){2,}\s*$/;
257
+ const RE_BLANK = /^\s*$/;
258
+ const RE_QUOTE = /^\s*>/;
259
+ const RE_LIST_ITEM = /^([ \t]*)([-*+]|\d{1,9}[.)])\s+(.*)$/;
260
+ function leadingSpaces(s) {
261
+ const m = /^[ \t]*/.exec(s);
262
+ return m[0].length;
263
+ }
264
+ function listMarkerInfo(line) {
265
+ const m = RE_LIST_ITEM.exec(line);
266
+ if (!m) return null;
267
+ const ordered = /\d/.test(m[2]);
268
+ return {
269
+ indent: m[1].length,
270
+ bullet: ordered ? "ol" : "ul",
271
+ start: ordered ? parseInt(m[2], 10) : null,
272
+ text: m[3],
273
+ raw: m[0]
274
+ };
275
+ }
276
+ function splitTableRow(row) {
277
+ let s = row.trim();
278
+ if (s.startsWith("|")) s = s.slice(1);
279
+ if (s.endsWith("|")) s = s.slice(0, -1);
280
+ return s.split(new RegExp("(?<!\\\\)\\|")).map((c) => c.trim().replace(/\\\|/g, "|"));
281
+ }
282
+ function isTableSep(line) {
283
+ if (!line.includes("|")) return false;
284
+ const cells = splitTableRow(line);
285
+ return cells.length > 0 && cells.every((c) => /^:?-{1,}:?$/.test(c.trim()));
286
+ }
287
+ function alignOf(cell) {
288
+ const c = cell.trim();
289
+ const l = c.startsWith(":"), r = c.endsWith(":");
290
+ if (l && r) return "center";
291
+ if (r) return "right";
292
+ if (l) return "left";
293
+ return null;
294
+ }
295
+ function startsBlock(lines, i) {
296
+ const line = lines[i];
297
+ if (RE_FENCE.test(line)) return true;
298
+ if (RE_HR.test(line)) return true;
299
+ if (RE_HEADING.test(line)) return true;
300
+ if (RE_QUOTE.test(line)) return true;
301
+ if (listMarkerInfo(line)) return true;
302
+ if (line.includes("|") && i + 1 < lines.length && isTableSep(lines[i + 1])) return true;
303
+ return false;
304
+ }
305
+ function parseList(lines, i) {
306
+ const base = leadingSpaces(lines[i]);
307
+ const baseInfo = listMarkerInfo(lines[i]);
308
+ const type = baseInfo.bullet;
309
+ const start = baseInfo.start;
310
+ const items = [];
311
+ while (i < lines.length) {
312
+ if (RE_BLANK.test(lines[i])) {
313
+ let j = i;
314
+ while (j < lines.length && RE_BLANK.test(lines[j])) j++;
315
+ const info2 = j < lines.length ? listMarkerInfo(lines[j]) : null;
316
+ if (j < lines.length && (info2 && leadingSpaces(lines[j]) === base || leadingSpaces(lines[j]) > base)) {
317
+ i = j;
318
+ continue;
319
+ }
320
+ break;
321
+ }
322
+ const ind = leadingSpaces(lines[i]);
323
+ const info = listMarkerInfo(lines[i]);
324
+ if (info && ind === base && info.bullet === type) {
325
+ const markerWidth = info.raw.length - info.text.length;
326
+ const itemLines = [info.text];
327
+ i++;
328
+ while (i < lines.length) {
329
+ if (RE_BLANK.test(lines[i])) {
330
+ let j = i;
331
+ while (j < lines.length && RE_BLANK.test(lines[j])) j++;
332
+ if (j < lines.length && leadingSpaces(lines[j]) > base) {
333
+ itemLines.push("");
334
+ i++;
335
+ continue;
336
+ }
337
+ break;
338
+ }
339
+ if (leadingSpaces(lines[i]) > base) {
340
+ itemLines.push(lines[i].slice(Math.min(markerWidth, leadingSpaces(lines[i]))));
341
+ i++;
342
+ } else break;
343
+ }
344
+ while (itemLines.length && itemLines[itemLines.length - 1] === "") itemLines.pop();
345
+ let checked = null;
346
+ const tm = /^\[([ xX])\]\s+([\s\S]*)$/.exec(itemLines[0] || "");
347
+ if (tm) {
348
+ checked = tm[1].toLowerCase() === "x";
349
+ itemLines[0] = tm[2];
350
+ }
351
+ items.push({ checked, blocks: parseBlocks(itemLines.join("\n")) });
352
+ } else {
353
+ break;
354
+ }
355
+ }
356
+ return { type, start, items, next: i };
357
+ }
358
+ function parseBlocks(src) {
359
+ const lines = String(src || "").replace(/\r\n?/g, "\n").split("\n");
360
+ const blocks = [];
361
+ let i = 0;
362
+ while (i < lines.length) {
363
+ const line = lines[i];
364
+ const fence = RE_FENCE.exec(line);
365
+ if (fence) {
366
+ const mark = fence[2][0];
367
+ const len = fence[2].length;
368
+ const close = new RegExp("^\\s{0,3}" + mark + "{" + len + ",}\\s*$");
369
+ i++;
370
+ const code = [];
371
+ while (i < lines.length && !close.test(lines[i])) {
372
+ code.push(lines[i]);
373
+ i++;
374
+ }
375
+ if (i < lines.length) i++;
376
+ blocks.push({ type: "code", lang: fence[3] || "", code: code.join("\n") });
377
+ continue;
378
+ }
379
+ if (RE_BLANK.test(line)) {
380
+ i++;
381
+ continue;
382
+ }
383
+ if (RE_HR.test(line)) {
384
+ blocks.push({ type: "hr" });
385
+ i++;
386
+ continue;
387
+ }
388
+ const h = RE_HEADING.exec(line);
389
+ if (h) {
390
+ blocks.push({ type: "heading", level: h[1].length, text: h[2] });
391
+ i++;
392
+ continue;
393
+ }
394
+ if (RE_QUOTE.test(line)) {
395
+ const inner = [];
396
+ while (i < lines.length && RE_QUOTE.test(lines[i])) {
397
+ inner.push(lines[i].replace(/^\s*>\s?/, ""));
398
+ i++;
399
+ }
400
+ blocks.push({ type: "quote", blocks: parseBlocks(inner.join("\n")) });
401
+ continue;
402
+ }
403
+ if (line.includes("|") && i + 1 < lines.length && isTableSep(lines[i + 1])) {
404
+ const header = splitTableRow(line);
405
+ const aligns = splitTableRow(lines[i + 1]).map(alignOf);
406
+ i += 2;
407
+ const rows = [];
408
+ while (i < lines.length && !RE_BLANK.test(lines[i]) && lines[i].includes("|") && !RE_FENCE.test(lines[i]) && !RE_QUOTE.test(lines[i])) {
409
+ rows.push(splitTableRow(lines[i]));
410
+ i++;
411
+ }
412
+ blocks.push({ type: "table", header, aligns, rows });
413
+ continue;
414
+ }
415
+ if (listMarkerInfo(line)) {
416
+ const res = parseList(lines, i);
417
+ blocks.push({ type: "list", listType: res.type, start: res.start, items: res.items });
418
+ i = res.next;
419
+ continue;
420
+ }
421
+ const para = [line];
422
+ i++;
423
+ while (i < lines.length && !RE_BLANK.test(lines[i]) && !startsBlock(lines, i)) {
424
+ para.push(lines[i]);
425
+ i++;
426
+ }
427
+ blocks.push({ type: "p", text: para.join("\n") });
428
+ }
429
+ return blocks;
430
+ }
431
+ function renderItemContent(blocks, key) {
432
+ if (blocks.length === 1 && blocks[0].type === "p") return parseInline(blocks[0].text, key);
433
+ return blocks.map(
434
+ (b, j) => b.type === "p" ? /* @__PURE__ */ jsx(React.Fragment, { children: parseInline(b.text, key + "-" + j) }, j) : renderBlock(b, key + "-" + j)
435
+ );
436
+ }
437
+ function renderList(b, key) {
438
+ const Tag = b.listType === "ol" ? "ol" : "ul";
439
+ const cls = b.listType === "ol" ? "ax-md__ol" : "ax-md__ul";
440
+ const startAttr = b.listType === "ol" && b.start && b.start !== 1 ? b.start : void 0;
441
+ return /* @__PURE__ */ jsx(Tag, { className: cls, start: startAttr, children: b.items.map((it, j) => {
442
+ const content = renderItemContent(it.blocks, key + "-" + j);
443
+ if (it.checked !== null) {
444
+ return /* @__PURE__ */ jsxs("li", { className: "ax-md__li ax-md__li--task", children: [
445
+ /* @__PURE__ */ jsx(
446
+ "input",
447
+ {
448
+ type: "checkbox",
449
+ className: "ax-md__check",
450
+ checked: it.checked,
451
+ disabled: true,
452
+ readOnly: true
453
+ }
454
+ ),
455
+ /* @__PURE__ */ jsx("span", { className: "ax-md__taskbody", children: content })
456
+ ] }, j);
457
+ }
458
+ return /* @__PURE__ */ jsx("li", { className: "ax-md__li", children: content }, j);
459
+ }) }, key);
460
+ }
461
+ function renderTable(b, key) {
462
+ const cols = b.header.length;
463
+ return /* @__PURE__ */ jsx("div", { className: "ax-md__tablewrap", children: /* @__PURE__ */ jsxs("table", { className: "ax-md__table", children: [
464
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: b.header.map((c, ci) => /* @__PURE__ */ jsx("th", { style: { textAlign: b.aligns[ci] || "left" }, children: parseInline(c, key + "-h" + ci) }, ci)) }) }),
465
+ /* @__PURE__ */ jsx("tbody", { children: b.rows.map((r, ri) => /* @__PURE__ */ jsx("tr", { children: Array.from({ length: cols }).map((_, ci) => /* @__PURE__ */ jsx("td", { style: { textAlign: b.aligns[ci] || "left" }, children: parseInline(r[ci] || "", key + "-r" + ri + "c" + ci) }, ci)) }, ri)) })
466
+ ] }) }, key);
467
+ }
468
+ function renderBlock(b, key) {
469
+ switch (b.type) {
470
+ case "code":
471
+ return /* @__PURE__ */ jsx(CodeBlock, { code: b.code, lang: b.lang || "text" }, key);
472
+ case "hr":
473
+ return /* @__PURE__ */ jsx("hr", { className: "ax-md__hr" }, key);
474
+ case "quote":
475
+ return /* @__PURE__ */ jsx("blockquote", { className: "ax-md__quote", children: renderBlocks(b.blocks, key) }, key);
476
+ case "table":
477
+ return renderTable(b, key);
478
+ case "list":
479
+ return renderList(b, key);
480
+ case "heading": {
481
+ const lvl = Math.min(b.level, 3);
482
+ const Tag = "h" + Math.min(b.level + 1, 6);
483
+ return /* @__PURE__ */ jsx(Tag, { className: "ax-md__h ax-md__h--" + lvl, children: parseInline(b.text, key) }, key);
484
+ }
485
+ case "p":
486
+ default:
487
+ return /* @__PURE__ */ jsx("p", { className: "ax-md__p", children: parseInline(b.text, key) }, key);
488
+ }
489
+ }
490
+ function renderBlocks(blocks, keyBase) {
491
+ return blocks.map((b, idx) => renderBlock(b, keyBase + "-blk" + idx));
492
+ }
493
+ function Markdown({ content, children, className = "", ...rest }) {
494
+ const src = typeof content === "string" ? content : typeof children === "string" ? children : "";
495
+ const blocks = React.useMemo(() => parseBlocks(src), [src]);
496
+ const cls = ["ax-md", className].filter(Boolean).join(" ");
497
+ return /* @__PURE__ */ jsx("div", { className: cls, ...rest, children: renderBlocks(blocks, "md") });
498
+ }
499
+ export {
500
+ Markdown
501
+ };
502
+ //# sourceMappingURL=Markdown.js.map