@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 +5 -5
- package/README.md +2 -2
- package/dist/components/auth/SignInPage.d.ts +1 -1
- package/dist/components/chat/Markdown.d.ts +30 -0
- package/dist/components/chat/Markdown.js +502 -0
- package/dist/components/chat/Markdown.js.map +1 -0
- package/dist/components/chat/Message.d.ts +6 -0
- package/dist/components/chat/Message.js +11 -1
- package/dist/components/chat/Message.js.map +1 -1
- package/dist/components/layout/DesignerShell.d.ts +1 -1
- package/dist/components/layout/DesignerShell.js.map +1 -1
- package/dist/components/settings/DeepSeekCard.d.ts +65 -0
- package/dist/components/settings/DeepSeekCard.js +197 -0
- package/dist/components/settings/DeepSeekCard.js.map +1 -0
- package/dist/components/settings/FeishuCard.d.ts +65 -0
- package/dist/components/settings/FeishuCard.js +271 -0
- package/dist/components/settings/FeishuCard.js.map +1 -0
- package/dist/components/utilities/BrandMark.d.ts +1 -1
- package/dist/components/utilities/BrandMark.js +1 -1
- package/dist/components/utilities/BrandMark.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/components/settings/IntegrationSettings.d.ts +0 -84
- package/dist/components/settings/IntegrationSettings.js +0 -688
- package/dist/components/settings/IntegrationSettings.js.map +0 -1
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,
|
|
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) — **
|
|
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`, `
|
|
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. `
|
|
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)设计系统:
|
|
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 全部
|
|
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 /> (
|
|
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  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
|