@zccz14/ux 0.3.0 → 0.4.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/README.md +43 -7
- package/dist/icons.d.ts +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +269 -134
- package/dist/markdown.d.ts +3 -0
- package/dist/mermaid.d.ts +3 -0
- package/dist/styles.css +241 -0
- package/dist/types.d.ts +3 -0
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @zccz14/ux
|
|
2
2
|
|
|
3
|
-
`@zccz14/ux` provides the shared
|
|
3
|
+
`@zccz14/ux` provides the shared app shell and the shared Markdown renderer for the NTNL app family (Cybion, NormAI, CTX, Linkit, Midas, HIT, 1Exchange, DeepSeek-LB, OpenAI-LB). One implementation of the sidebar, the AppHeader and the Linkit account control keeps the interaction identical across apps; one implementation of `<Markdown>` keeps rendered content — replies, checkpoints, manuals, documents, articles — identical too. Both replace the per-app copies they supersede.
|
|
4
4
|
|
|
5
5
|
## What the shell owns
|
|
6
6
|
|
|
@@ -102,9 +102,45 @@ type AppNavGroup = { label: string; items: AppNavItem[] };
|
|
|
102
102
|
- **Favicon** — an `<svg>` logo is serialised to a `data:image/svg+xml` icon with its rendered colour pinned; an `<img>` logo reuses the image URL. The icon is rewritten when `.dark` flips, when `prefers-color-scheme` changes, and when the mark itself is swapped.
|
|
103
103
|
- **Layout contract** — the shell is viewport-locked (`100svh`); the main region is the page's only scroll container and applies the standard `1rem` / `1.5rem` padding. Pages own their inner layout.
|
|
104
104
|
|
|
105
|
+
## Markdown
|
|
106
|
+
|
|
107
|
+
`<Markdown content={...} />` is the single renderer for every piece of Markdown in the family.
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { Markdown } from "@zccz14/ux";
|
|
111
|
+
|
|
112
|
+
<Markdown content={reply} />;
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
One prop, on purpose. There is no `math`, `mermaid`, `components`, `remarkPlugins` or `urlTransform` switch: a surface either renders Markdown the family way, or it renders through something else. Every capability below is always on, because the point of the component is that a reply in Cybion, a checkpoint, a manual preview and a CTX article look the same.
|
|
116
|
+
|
|
117
|
+
### What it renders
|
|
118
|
+
|
|
119
|
+
- **GitHub Flavored Markdown** — tables, task lists, strikethrough, autolinks.
|
|
120
|
+
- **Math through KaTeX** — `$E=mc^2$`, `$$…$$`, `\(…\)`, `\[…\]` and `math`-tagged code fences, because models emit all of them. KaTeX's stylesheet and fonts are imported by the component itself, so a formula is never unstyled. Broken math degrades to one `.katex-error` span carrying the parser message; math that is still streaming — no closing delimiter yet — stays source instead of flickering.
|
|
121
|
+
- **Mermaid diagrams** — a `mermaid`-tagged fence becomes an SVG, loaded on demand: a surface without a diagram never downloads mermaid. The chart follows the current theme and the surrounding text size, and re-renders when `.dark` flips. An unparseable diagram falls back to its own source block.
|
|
122
|
+
- **Links** — absolute URLs open in a new tab with `rel="noopener noreferrer"` and an external marker; in-page anchors and relative paths stay in the app. Only `http(s)` and `mailto` survive: `javascript:`, `data:` and friends degrade to plain text.
|
|
123
|
+
- **Tables and code** — a wide table or a long code block scrolls inside its own box, so the transcript or article around it never grows a horizontal scrollbar.
|
|
124
|
+
- **Raw HTML** — never rendered. The pipeline has no `rehype-raw`, so HTML in the source is shown as text.
|
|
125
|
+
|
|
126
|
+
### Typography is owned here
|
|
127
|
+
|
|
128
|
+
The component wraps its content in `.ux-markdown`, and that block is the family's typographic contract: every size is expressed in `em` off the inherited font size, and no measure is imposed. The same content therefore keeps identical proportions in a 14px chat bubble and a 16px article page. The host decides two things and only two — the font size of the container the content is dropped into, and the width of that container. Do not wrap the component in `prose` classes: the stylesheet is the single source of the look, and `scripts/check-styles.mjs` enforces it.
|
|
129
|
+
|
|
130
|
+
### Why the pipeline is a runtime dependency
|
|
131
|
+
|
|
132
|
+
`react-markdown`, `remark-gfm`, `remark-math-extended`, `rehype-katex`, `katex` and `mermaid` are `dependencies`, not peers, so an app wires nothing. An app that never renders Markdown tree-shakes the whole pipeline away, with one deliberate exception: `katex/dist/katex.min.css` is a module-level side effect of the renderer (about 3.6 KB gzipped, plus fonts the browser fetches only when a formula appears). `scripts/check-package.mjs` fails the build if the manifest ever claims `sideEffects: false`, which would let a bundler drop that stylesheet and render every formula as bare LaTeX with no error to notice.
|
|
133
|
+
|
|
134
|
+
## Migrating an app from its local Markdown renderer
|
|
135
|
+
|
|
136
|
+
1. Delete the app's own renderer — the `react-markdown` wrapper, its plugin wiring, its `components` map, its `Mermaid`/`MarkdownPre` pair, and any `mermaid`/`rehype-katex`/`remark-*`/`katex` dependency entries that only served it.
|
|
137
|
+
2. Replace each call site with `<Markdown content={markdown} />` and drop the surrounding `prose …` classes: the typography lives in `.ux-markdown`, and the container only owes the content a font size and a width.
|
|
138
|
+
3. Keep app-specific node mapping out of the way — if a surface really needs different output (inline mention tokens, a clamped preview), it belongs in the library, not in a local fork of the plugin chain.
|
|
139
|
+
4. Keep the KaTeX stylesheet import out of the app: the component owns it.
|
|
140
|
+
|
|
105
141
|
## Styling
|
|
106
142
|
|
|
107
|
-
Import `@zccz14/ux/styles.css` once. It consumes the app's shadcn theme tokens and falls back to its own values, so the shell stays readable even when a token is missing: `--background`, `--foreground`, `--border`, `--accent`, `--muted`, `--ring`, `--sidebar`, `--sidebar-foreground`, `--sidebar-accent`, `--sidebar-accent-foreground`, `--sidebar-border`, `--sidebar-ring`.
|
|
143
|
+
Import `@zccz14/ux/styles.css` once. It consumes the app's shadcn theme tokens and falls back to its own values, so the shell stays readable even when a token is missing: `--background`, `--foreground`, `--border`, `--accent`, `--muted`, `--ring`, `--sidebar`, `--sidebar-foreground`, `--sidebar-accent`, `--sidebar-accent-foreground`, `--sidebar-border`, `--sidebar-ring`. The Markdown layer reads `--muted`, `--muted-foreground`, `--primary` and `--destructive` through the same `--ux-*` layer (`--ux-muted`, `--ux-muted-foreground`, `--ux-primary`, `--ux-destructive`).
|
|
108
144
|
|
|
109
145
|
Those tokens are read through a `--ux-*` layer declared twice — a light set on `:root` and a dark set on `.dark` — so every fallback has a dark counterpart. A missing `--sidebar` therefore renders dark in dark mode instead of a light sidebar. The shell also sets `color-scheme` per mode, so native scrollbars and controls follow the theme without help from a theme provider.
|
|
110
146
|
|
|
@@ -121,9 +157,9 @@ Theme state itself is not the shell's business: whatever toggles `.dark` on `<ht
|
|
|
121
157
|
## Development
|
|
122
158
|
|
|
123
159
|
```sh
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
160
|
+
pnpm install
|
|
161
|
+
pnpm run typecheck
|
|
162
|
+
pnpm test
|
|
163
|
+
pnpm run build
|
|
164
|
+
pnpm run pack:check
|
|
129
165
|
```
|
package/dist/icons.d.ts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,65 +1,70 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useEffect as
|
|
1
|
+
import { jsxs as u, jsx as n, Fragment as L } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect as v, useRef as f, useState as g, useCallback as y, useSyncExternalStore as C } from "react";
|
|
3
3
|
import { Dialog as h } from "@base-ui/react/dialog";
|
|
4
|
-
import { Tooltip as
|
|
4
|
+
import { Tooltip as p } from "@base-ui/react/tooltip";
|
|
5
5
|
import { useLinkit as E, LinkitMyInfo as O } from "linkit-react-components";
|
|
6
|
-
import { useLocation as
|
|
7
|
-
|
|
6
|
+
import { useLocation as w, NavLink as z } from "react-router-dom";
|
|
7
|
+
import T from "react-markdown";
|
|
8
|
+
import P from "rehype-katex";
|
|
9
|
+
import F from "remark-gfm";
|
|
10
|
+
import I from "remark-math-extended";
|
|
11
|
+
import "katex/dist/katex.min.css";
|
|
12
|
+
const $ = {
|
|
8
13
|
closeNavigation: "Close navigation",
|
|
9
14
|
navigation: "Navigation",
|
|
10
15
|
toggleSidebar: "Toggle sidebar"
|
|
11
|
-
},
|
|
16
|
+
}, A = {
|
|
12
17
|
closeNavigation: "关闭导航",
|
|
13
18
|
navigation: "导航",
|
|
14
19
|
toggleSidebar: "切换侧边栏"
|
|
15
20
|
};
|
|
16
|
-
function
|
|
17
|
-
return e.toLowerCase().startsWith("zh") ?
|
|
21
|
+
function W(e) {
|
|
22
|
+
return e.toLowerCase().startsWith("zh") ? A : $;
|
|
18
23
|
}
|
|
19
|
-
const
|
|
20
|
-
function
|
|
24
|
+
const R = 'link[rel~="icon"]';
|
|
25
|
+
function j(e) {
|
|
21
26
|
const t = e.cloneNode(!0);
|
|
22
27
|
return t.setAttribute("xmlns", "http://www.w3.org/2000/svg"), t.style.color = getComputedStyle(e).color, new XMLSerializer().serializeToString(t);
|
|
23
28
|
}
|
|
24
|
-
function
|
|
29
|
+
function B(e) {
|
|
25
30
|
if (e instanceof SVGSVGElement)
|
|
26
31
|
return {
|
|
27
|
-
href: `data:image/svg+xml,${encodeURIComponent(
|
|
32
|
+
href: `data:image/svg+xml,${encodeURIComponent(j(e))}`,
|
|
28
33
|
type: "image/svg+xml"
|
|
29
34
|
};
|
|
30
|
-
const { currentSrc: t, src:
|
|
31
|
-
return /\.svg([?#]|$)/i.test(
|
|
35
|
+
const { currentSrc: t, src: a } = e, r = t || a;
|
|
36
|
+
return /\.svg([?#]|$)/i.test(r) ? { href: r, type: "image/svg+xml" } : { href: r };
|
|
32
37
|
}
|
|
33
|
-
function
|
|
34
|
-
const e = document.querySelector(
|
|
38
|
+
function q() {
|
|
39
|
+
const e = document.querySelector(R);
|
|
35
40
|
if (e)
|
|
36
41
|
return e;
|
|
37
42
|
const t = document.createElement("link");
|
|
38
43
|
return t.rel = "icon", document.head.append(t), t;
|
|
39
44
|
}
|
|
40
|
-
function
|
|
41
|
-
|
|
45
|
+
function D(e, t) {
|
|
46
|
+
v(() => {
|
|
42
47
|
if (!t)
|
|
43
48
|
return;
|
|
44
|
-
const
|
|
45
|
-
var
|
|
46
|
-
const
|
|
47
|
-
if (!
|
|
49
|
+
const a = () => {
|
|
50
|
+
var m;
|
|
51
|
+
const i = (m = e.current) == null ? void 0 : m.querySelector("svg, img");
|
|
52
|
+
if (!i)
|
|
48
53
|
return;
|
|
49
|
-
const { href:
|
|
50
|
-
s ?
|
|
54
|
+
const { href: d, type: s } = B(i), l = q();
|
|
55
|
+
s ? l.type = s : l.removeAttribute("type"), l.getAttribute("href") !== d && l.setAttribute("href", d);
|
|
51
56
|
};
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
return
|
|
57
|
-
|
|
57
|
+
a();
|
|
58
|
+
const r = new MutationObserver(a);
|
|
59
|
+
r.observe(document.documentElement, { attributes: !0, attributeFilter: ["class", "style"] }), e.current && r.observe(e.current, { childList: !0, subtree: !0 });
|
|
60
|
+
const o = window.matchMedia("(prefers-color-scheme: dark)");
|
|
61
|
+
return o.addEventListener("change", a), () => {
|
|
62
|
+
r.disconnect(), o.removeEventListener("change", a);
|
|
58
63
|
};
|
|
59
64
|
}, [t, e]);
|
|
60
65
|
}
|
|
61
|
-
function
|
|
62
|
-
return /* @__PURE__ */
|
|
66
|
+
function K() {
|
|
67
|
+
return /* @__PURE__ */ u(
|
|
63
68
|
"svg",
|
|
64
69
|
{
|
|
65
70
|
"aria-hidden": "true",
|
|
@@ -76,8 +81,8 @@ function B() {
|
|
|
76
81
|
}
|
|
77
82
|
);
|
|
78
83
|
}
|
|
79
|
-
function
|
|
80
|
-
return /* @__PURE__ */
|
|
84
|
+
function V() {
|
|
85
|
+
return /* @__PURE__ */ u(
|
|
81
86
|
"svg",
|
|
82
87
|
{
|
|
83
88
|
"aria-hidden": "true",
|
|
@@ -94,81 +99,101 @@ function F() {
|
|
|
94
99
|
}
|
|
95
100
|
);
|
|
96
101
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
function G() {
|
|
103
|
+
return /* @__PURE__ */ u(
|
|
104
|
+
"svg",
|
|
105
|
+
{
|
|
106
|
+
"aria-hidden": "true",
|
|
107
|
+
className: "ux-markdown__external-link",
|
|
108
|
+
fill: "none",
|
|
109
|
+
stroke: "currentColor",
|
|
110
|
+
strokeLinecap: "round",
|
|
111
|
+
strokeLinejoin: "round",
|
|
112
|
+
strokeWidth: "2",
|
|
113
|
+
viewBox: "0 0 24 24",
|
|
114
|
+
children: [
|
|
115
|
+
/* @__PURE__ */ n("path", { d: "M15 3h6v6" }),
|
|
116
|
+
/* @__PURE__ */ n("path", { d: "M10 14 21 3" }),
|
|
117
|
+
/* @__PURE__ */ n("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" })
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const b = "sidebar_state", H = 3600 * 24 * 7, _ = "(max-width: 767px)";
|
|
123
|
+
function U() {
|
|
124
|
+
const e = document.cookie.split("; ").find((t) => t.startsWith(`${b}=`));
|
|
125
|
+
return e ? e.slice(b.length + 1) !== "false" : !0;
|
|
101
126
|
}
|
|
102
|
-
function
|
|
103
|
-
document.cookie = `${
|
|
127
|
+
function Q(e) {
|
|
128
|
+
document.cookie = `${b}=${e}; path=/; max-age=${H}`;
|
|
104
129
|
}
|
|
105
|
-
function
|
|
106
|
-
const t = window.matchMedia(
|
|
130
|
+
function X(e) {
|
|
131
|
+
const t = window.matchMedia(_);
|
|
107
132
|
return t.addEventListener("change", e), () => t.removeEventListener("change", e);
|
|
108
133
|
}
|
|
109
|
-
function
|
|
134
|
+
function J() {
|
|
110
135
|
return C(
|
|
111
|
-
|
|
112
|
-
() => window.matchMedia(
|
|
136
|
+
X,
|
|
137
|
+
() => window.matchMedia(_).matches,
|
|
113
138
|
() => !1
|
|
114
139
|
);
|
|
115
140
|
}
|
|
116
|
-
function
|
|
117
|
-
const e =
|
|
118
|
-
|
|
119
|
-
}, []),
|
|
141
|
+
function Y() {
|
|
142
|
+
const e = J(), [t, a] = g(U), [r, o] = g(!1), i = y((s) => {
|
|
143
|
+
a(s), Q(s);
|
|
144
|
+
}, []), d = y(() => {
|
|
120
145
|
if (e) {
|
|
121
|
-
|
|
146
|
+
o((s) => !s);
|
|
122
147
|
return;
|
|
123
148
|
}
|
|
124
|
-
|
|
125
|
-
}, [e, t,
|
|
126
|
-
return
|
|
127
|
-
function s(
|
|
128
|
-
(
|
|
149
|
+
i(!t);
|
|
150
|
+
}, [e, t, i]);
|
|
151
|
+
return v(() => {
|
|
152
|
+
function s(l) {
|
|
153
|
+
(l.metaKey || l.ctrlKey) && l.key === "b" && (l.preventDefault(), d());
|
|
129
154
|
}
|
|
130
155
|
return window.addEventListener("keydown", s), () => window.removeEventListener("keydown", s);
|
|
131
|
-
}, [
|
|
156
|
+
}, [d]), { isMobile: e, open: t, openMobile: r, setOpenMobile: o, toggleSidebar: d };
|
|
132
157
|
}
|
|
133
|
-
function
|
|
134
|
-
let
|
|
135
|
-
for (const
|
|
136
|
-
for (const
|
|
137
|
-
(
|
|
138
|
-
return
|
|
158
|
+
function M(e, t) {
|
|
159
|
+
let a;
|
|
160
|
+
for (const r of e)
|
|
161
|
+
for (const o of r.items)
|
|
162
|
+
(o.to === "/" ? t === "/" : t === o.to || t.startsWith(`${o.to}/`)) && (!a || o.to.length > a.to.length) && (a = o);
|
|
163
|
+
return a;
|
|
139
164
|
}
|
|
140
|
-
function
|
|
165
|
+
function Z({
|
|
141
166
|
collapsed: e,
|
|
142
167
|
end: t,
|
|
143
|
-
item:
|
|
144
|
-
onNavigate:
|
|
168
|
+
item: a,
|
|
169
|
+
onNavigate: r
|
|
145
170
|
}) {
|
|
146
|
-
return /* @__PURE__ */
|
|
147
|
-
/* @__PURE__ */
|
|
148
|
-
|
|
171
|
+
return /* @__PURE__ */ u(p.Root, { children: [
|
|
172
|
+
/* @__PURE__ */ u(
|
|
173
|
+
p.Trigger,
|
|
149
174
|
{
|
|
150
175
|
render: /* @__PURE__ */ n(
|
|
151
|
-
|
|
176
|
+
z,
|
|
152
177
|
{
|
|
153
178
|
className: "ux-nav-item",
|
|
154
179
|
end: t,
|
|
155
|
-
onClick:
|
|
156
|
-
to:
|
|
180
|
+
onClick: r,
|
|
181
|
+
to: a.to
|
|
157
182
|
}
|
|
158
183
|
),
|
|
159
184
|
children: [
|
|
160
|
-
/* @__PURE__ */ n("span", { className: "ux-nav-item__icon", children:
|
|
161
|
-
/* @__PURE__ */ n("span", { className: "ux-nav-item__text", children:
|
|
185
|
+
/* @__PURE__ */ n("span", { className: "ux-nav-item__icon", children: a.icon }),
|
|
186
|
+
/* @__PURE__ */ n("span", { className: "ux-nav-item__text", children: a.label })
|
|
162
187
|
]
|
|
163
188
|
}
|
|
164
189
|
),
|
|
165
|
-
/* @__PURE__ */ n(
|
|
166
|
-
|
|
190
|
+
/* @__PURE__ */ n(p.Portal, { children: /* @__PURE__ */ n(
|
|
191
|
+
p.Positioner,
|
|
167
192
|
{
|
|
168
193
|
className: "ux-tooltip-positioner",
|
|
169
194
|
side: "right",
|
|
170
195
|
sideOffset: 6,
|
|
171
|
-
children: /* @__PURE__ */ n(
|
|
196
|
+
children: /* @__PURE__ */ n(p.Popup, { className: "ux-tooltip", hidden: !e, children: a.label })
|
|
172
197
|
}
|
|
173
198
|
) })
|
|
174
199
|
] });
|
|
@@ -176,116 +201,116 @@ function U({
|
|
|
176
201
|
function N({
|
|
177
202
|
copy: e,
|
|
178
203
|
logo: t,
|
|
179
|
-
logoRef:
|
|
180
|
-
nav:
|
|
181
|
-
onNavigate:
|
|
182
|
-
state:
|
|
183
|
-
title:
|
|
204
|
+
logoRef: a,
|
|
205
|
+
nav: r,
|
|
206
|
+
onNavigate: o,
|
|
207
|
+
state: i,
|
|
208
|
+
title: d
|
|
184
209
|
}) {
|
|
185
|
-
const { pathname: s } =
|
|
186
|
-
return /* @__PURE__ */
|
|
187
|
-
/* @__PURE__ */
|
|
188
|
-
/* @__PURE__ */ n("span", { className: "ux-sidebar__logo", ref:
|
|
189
|
-
/* @__PURE__ */ n("span", { className: "ux-sidebar__title", children:
|
|
210
|
+
const { pathname: s } = w(), l = M(r, s);
|
|
211
|
+
return /* @__PURE__ */ u(L, { children: [
|
|
212
|
+
/* @__PURE__ */ u("div", { className: "ux-sidebar__header", children: [
|
|
213
|
+
/* @__PURE__ */ n("span", { className: "ux-sidebar__logo", ref: a, children: t }),
|
|
214
|
+
/* @__PURE__ */ n("span", { className: "ux-sidebar__title", children: d })
|
|
190
215
|
] }),
|
|
191
|
-
/* @__PURE__ */ n("nav", { "aria-label": e.navigation, className: "ux-sidebar__nav", children:
|
|
192
|
-
/* @__PURE__ */ n("div", { className: "ux-nav-group__label", children:
|
|
193
|
-
|
|
216
|
+
/* @__PURE__ */ n("nav", { "aria-label": e.navigation, className: "ux-sidebar__nav", children: r.map((m) => /* @__PURE__ */ u("div", { className: "ux-nav-group", children: [
|
|
217
|
+
/* @__PURE__ */ n("div", { className: "ux-nav-group__label", children: m.label }),
|
|
218
|
+
m.items.map((c) => (
|
|
194
219
|
// NavLink would mark a parent section current on its children's
|
|
195
220
|
// routes; follow matchActiveItem instead so only the deepest
|
|
196
221
|
// match (or the exact path) stays marked.
|
|
197
222
|
/* @__PURE__ */ n(
|
|
198
|
-
|
|
223
|
+
Z,
|
|
199
224
|
{
|
|
200
|
-
collapsed:
|
|
201
|
-
end:
|
|
202
|
-
item:
|
|
203
|
-
onNavigate:
|
|
225
|
+
collapsed: i === "collapsed",
|
|
226
|
+
end: c !== l || c.to === s,
|
|
227
|
+
item: c,
|
|
228
|
+
onNavigate: o
|
|
204
229
|
},
|
|
205
|
-
|
|
230
|
+
c.to
|
|
206
231
|
)
|
|
207
232
|
))
|
|
208
|
-
] },
|
|
233
|
+
] }, m.label)) })
|
|
209
234
|
] });
|
|
210
235
|
}
|
|
211
|
-
function
|
|
236
|
+
function _e({
|
|
212
237
|
children: e,
|
|
213
238
|
favicon: t = !0,
|
|
214
|
-
headerSlot:
|
|
215
|
-
logo:
|
|
216
|
-
nav:
|
|
217
|
-
pageTitle:
|
|
218
|
-
title:
|
|
239
|
+
headerSlot: a,
|
|
240
|
+
logo: r,
|
|
241
|
+
nav: o,
|
|
242
|
+
pageTitle: i,
|
|
243
|
+
title: d
|
|
219
244
|
}) {
|
|
220
|
-
var
|
|
221
|
-
const { pathname: s } =
|
|
222
|
-
return
|
|
245
|
+
var k;
|
|
246
|
+
const { pathname: s } = w(), { lang: l } = E(), m = W(l), c = Y(), x = f(null), S = i ?? ((k = M(o, s)) == null ? void 0 : k.label);
|
|
247
|
+
return D(x, t), /* @__PURE__ */ n(p.Provider, { delay: 0, children: /* @__PURE__ */ u(
|
|
223
248
|
"div",
|
|
224
249
|
{
|
|
225
250
|
className: "ux-app-layout",
|
|
226
|
-
"data-state":
|
|
251
|
+
"data-state": c.open ? "expanded" : "collapsed",
|
|
227
252
|
children: [
|
|
228
253
|
/* @__PURE__ */ n("aside", { className: "ux-sidebar", children: /* @__PURE__ */ n(
|
|
229
254
|
N,
|
|
230
255
|
{
|
|
231
|
-
copy:
|
|
232
|
-
logo:
|
|
233
|
-
logoRef:
|
|
234
|
-
nav:
|
|
235
|
-
state:
|
|
236
|
-
title:
|
|
256
|
+
copy: m,
|
|
257
|
+
logo: r,
|
|
258
|
+
logoRef: x,
|
|
259
|
+
nav: o,
|
|
260
|
+
state: c.open ? "expanded" : "collapsed",
|
|
261
|
+
title: d
|
|
237
262
|
}
|
|
238
263
|
) }),
|
|
239
|
-
|
|
264
|
+
c.isMobile ? /* @__PURE__ */ n(
|
|
240
265
|
h.Root,
|
|
241
266
|
{
|
|
242
|
-
open:
|
|
243
|
-
onOpenChange:
|
|
244
|
-
children: /* @__PURE__ */
|
|
267
|
+
open: c.openMobile,
|
|
268
|
+
onOpenChange: c.setOpenMobile,
|
|
269
|
+
children: /* @__PURE__ */ u(h.Portal, { children: [
|
|
245
270
|
/* @__PURE__ */ n(h.Backdrop, { className: "ux-drawer-backdrop" }),
|
|
246
|
-
/* @__PURE__ */
|
|
247
|
-
/* @__PURE__ */ n(h.Title, { className: "ux-visually-hidden", children:
|
|
271
|
+
/* @__PURE__ */ u(h.Popup, { className: "ux-drawer", children: [
|
|
272
|
+
/* @__PURE__ */ n(h.Title, { className: "ux-visually-hidden", children: m.navigation }),
|
|
248
273
|
/* @__PURE__ */ n(
|
|
249
274
|
"button",
|
|
250
275
|
{
|
|
251
|
-
"aria-label":
|
|
276
|
+
"aria-label": m.closeNavigation,
|
|
252
277
|
className: "ux-drawer__close",
|
|
253
278
|
type: "button",
|
|
254
|
-
onClick: () =>
|
|
255
|
-
children: /* @__PURE__ */ n(
|
|
279
|
+
onClick: () => c.setOpenMobile(!1),
|
|
280
|
+
children: /* @__PURE__ */ n(K, {})
|
|
256
281
|
}
|
|
257
282
|
),
|
|
258
283
|
/* @__PURE__ */ n(
|
|
259
284
|
N,
|
|
260
285
|
{
|
|
261
|
-
copy:
|
|
262
|
-
logo:
|
|
263
|
-
nav:
|
|
264
|
-
onNavigate: () =>
|
|
286
|
+
copy: m,
|
|
287
|
+
logo: r,
|
|
288
|
+
nav: o,
|
|
289
|
+
onNavigate: () => c.setOpenMobile(!1),
|
|
265
290
|
state: "expanded",
|
|
266
|
-
title:
|
|
291
|
+
title: d
|
|
267
292
|
}
|
|
268
293
|
)
|
|
269
294
|
] })
|
|
270
295
|
] })
|
|
271
296
|
}
|
|
272
297
|
) : null,
|
|
273
|
-
/* @__PURE__ */
|
|
274
|
-
/* @__PURE__ */
|
|
298
|
+
/* @__PURE__ */ u("div", { className: "ux-shell", children: [
|
|
299
|
+
/* @__PURE__ */ u("header", { className: "ux-app-header", children: [
|
|
275
300
|
/* @__PURE__ */ n(
|
|
276
301
|
"button",
|
|
277
302
|
{
|
|
278
|
-
"aria-expanded":
|
|
279
|
-
"aria-label":
|
|
303
|
+
"aria-expanded": c.isMobile ? c.openMobile : c.open,
|
|
304
|
+
"aria-label": m.toggleSidebar,
|
|
280
305
|
className: "ux-app-header__trigger",
|
|
281
306
|
type: "button",
|
|
282
|
-
onClick:
|
|
283
|
-
children: /* @__PURE__ */ n(
|
|
307
|
+
onClick: c.toggleSidebar,
|
|
308
|
+
children: /* @__PURE__ */ n(V, {})
|
|
284
309
|
}
|
|
285
310
|
),
|
|
286
311
|
/* @__PURE__ */ n("span", { "aria-hidden": "true", className: "ux-app-header__separator" }),
|
|
287
312
|
/* @__PURE__ */ n("p", { className: "ux-app-header__title", children: S }),
|
|
288
|
-
/* @__PURE__ */ n("div", { className: "ux-app-header__slot", children:
|
|
313
|
+
/* @__PURE__ */ n("div", { className: "ux-app-header__slot", children: a }),
|
|
289
314
|
/* @__PURE__ */ n(O, {})
|
|
290
315
|
] }),
|
|
291
316
|
/* @__PURE__ */ n("main", { className: "ux-main", children: e })
|
|
@@ -294,6 +319,116 @@ function te({
|
|
|
294
319
|
}
|
|
295
320
|
) });
|
|
296
321
|
}
|
|
322
|
+
let ee = 0;
|
|
323
|
+
function te() {
|
|
324
|
+
return document.documentElement.classList.contains("dark") ? "dark" : "neutral";
|
|
325
|
+
}
|
|
326
|
+
function ne() {
|
|
327
|
+
const e = getComputedStyle(document.documentElement).fontFamily.trim();
|
|
328
|
+
return e === "" ? "sans-serif" : e;
|
|
329
|
+
}
|
|
330
|
+
function re(e) {
|
|
331
|
+
const t = e ? Number.parseFloat(getComputedStyle(e).fontSize) : Number.NaN;
|
|
332
|
+
return !Number.isFinite(t) || t <= 0 ? 16 : Math.min(Math.max(t, 10), 20);
|
|
333
|
+
}
|
|
334
|
+
async function ae(e, t) {
|
|
335
|
+
try {
|
|
336
|
+
const { default: a } = await import("mermaid");
|
|
337
|
+
a.initialize({
|
|
338
|
+
startOnLoad: !1,
|
|
339
|
+
securityLevel: "strict",
|
|
340
|
+
theme: te(),
|
|
341
|
+
themeVariables: { fontFamily: ne(), fontSize: `${re(t)}px` }
|
|
342
|
+
});
|
|
343
|
+
const { svg: r } = await a.render(`ux-mermaid-${++ee}`, e);
|
|
344
|
+
return r;
|
|
345
|
+
} catch {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function oe({ source: e }) {
|
|
350
|
+
const [t, a] = g(null), r = f(null), o = f(0);
|
|
351
|
+
return v(() => {
|
|
352
|
+
const i = async () => {
|
|
353
|
+
const s = ++o.current, l = await ae(e, r.current);
|
|
354
|
+
o.current === s && a(l);
|
|
355
|
+
};
|
|
356
|
+
i();
|
|
357
|
+
const d = new MutationObserver(() => void i());
|
|
358
|
+
return d.observe(document.documentElement, { attributes: !0, attributeFilter: ["class"] }), () => {
|
|
359
|
+
o.current += 1, d.disconnect();
|
|
360
|
+
};
|
|
361
|
+
}, [e]), t === null ? /* @__PURE__ */ n(
|
|
362
|
+
"pre",
|
|
363
|
+
{
|
|
364
|
+
className: "ux-markdown__mermaid-source",
|
|
365
|
+
"data-mermaid": "source",
|
|
366
|
+
ref: (i) => {
|
|
367
|
+
r.current = i;
|
|
368
|
+
},
|
|
369
|
+
children: /* @__PURE__ */ n("code", { className: "language-mermaid", children: e })
|
|
370
|
+
}
|
|
371
|
+
) : /* @__PURE__ */ n(
|
|
372
|
+
"div",
|
|
373
|
+
{
|
|
374
|
+
"aria-label": "Mermaid diagram",
|
|
375
|
+
className: "ux-markdown__mermaid",
|
|
376
|
+
"data-mermaid": "diagram",
|
|
377
|
+
dangerouslySetInnerHTML: { __html: t },
|
|
378
|
+
ref: (i) => {
|
|
379
|
+
r.current = i;
|
|
380
|
+
},
|
|
381
|
+
role: "img"
|
|
382
|
+
}
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
function ie(e) {
|
|
386
|
+
const t = e == null ? void 0 : e.children[0];
|
|
387
|
+
if ((t == null ? void 0 : t.type) !== "element" || t.tagName !== "code")
|
|
388
|
+
return null;
|
|
389
|
+
const a = t.properties.className;
|
|
390
|
+
if (!Array.isArray(a) || !a.includes("language-mermaid"))
|
|
391
|
+
return null;
|
|
392
|
+
const r = t.children[0];
|
|
393
|
+
return (r == null ? void 0 : r.type) === "text" ? r.value : null;
|
|
394
|
+
}
|
|
395
|
+
const se = {
|
|
396
|
+
a: ({ children: e, href: t, node: a, ...r }) => t ? le(t) ? /* @__PURE__ */ u("a", { ...r, href: t, rel: "noopener noreferrer", target: "_blank", children: [
|
|
397
|
+
e,
|
|
398
|
+
/* @__PURE__ */ n(G, {})
|
|
399
|
+
] }) : /* @__PURE__ */ n("a", { ...r, href: t, children: e }) : /* @__PURE__ */ n("span", { ...r, children: e }),
|
|
400
|
+
pre: ({ children: e, node: t, ...a }) => {
|
|
401
|
+
const r = ie(t);
|
|
402
|
+
return r === null ? /* @__PURE__ */ n("pre", { ...a, children: e }) : /* @__PURE__ */ n(oe, { source: r });
|
|
403
|
+
},
|
|
404
|
+
// A wide table scrolls on its own; the transcript or article around it never grows a horizontal
|
|
405
|
+
// scrollbar, so the columns past the fold stay reachable.
|
|
406
|
+
table: ({ children: e, node: t, ...a }) => /* @__PURE__ */ n("div", { className: "ux-markdown__table", children: /* @__PURE__ */ n("table", { ...a, children: e }) })
|
|
407
|
+
}, ce = /* @__PURE__ */ new Set(["http", "https", "mailto"]);
|
|
408
|
+
function le(e) {
|
|
409
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(e) || e.startsWith("//");
|
|
410
|
+
}
|
|
411
|
+
function de(e) {
|
|
412
|
+
const t = e.trim(), a = t.indexOf(":");
|
|
413
|
+
if (a === -1)
|
|
414
|
+
return t;
|
|
415
|
+
const r = t.slice(0, a).toLowerCase();
|
|
416
|
+
return /^[a-z][a-z0-9+.-]*$/.test(r) ? ce.has(r) ? t : "" : t;
|
|
417
|
+
}
|
|
418
|
+
const ue = [F, I], me = [[P, { strict: "ignore", errorColor: "var(--ux-destructive)" }]];
|
|
419
|
+
function Me({ content: e }) {
|
|
420
|
+
return /* @__PURE__ */ n("div", { className: "ux-markdown", children: /* @__PURE__ */ n(
|
|
421
|
+
T,
|
|
422
|
+
{
|
|
423
|
+
components: se,
|
|
424
|
+
rehypePlugins: me,
|
|
425
|
+
remarkPlugins: ue,
|
|
426
|
+
urlTransform: de,
|
|
427
|
+
children: e
|
|
428
|
+
}
|
|
429
|
+
) });
|
|
430
|
+
}
|
|
297
431
|
export {
|
|
298
|
-
|
|
432
|
+
_e as AppLayout,
|
|
433
|
+
Me as Markdown
|
|
299
434
|
};
|
package/dist/styles.css
CHANGED
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
--ux-foreground: var(--foreground, #0f172a);
|
|
14
14
|
--ux-border: var(--border, #e2e8f0);
|
|
15
15
|
--ux-accent: var(--accent, var(--muted, #f1f5f9));
|
|
16
|
+
--ux-muted: var(--muted, #f1f5f9);
|
|
17
|
+
--ux-muted-foreground: var(--muted-foreground, #64748b);
|
|
18
|
+
--ux-primary: var(--primary, #2563eb);
|
|
19
|
+
--ux-destructive: var(--destructive, #dc2626);
|
|
16
20
|
--ux-ring: var(--ring, #2563eb);
|
|
17
21
|
--ux-sidebar: var(--sidebar, #fafafa);
|
|
18
22
|
--ux-sidebar-foreground: var(--sidebar-foreground, var(--foreground, #0f172a));
|
|
@@ -27,6 +31,10 @@
|
|
|
27
31
|
--ux-foreground: var(--foreground, #f2f2f2);
|
|
28
32
|
--ux-border: var(--border, #383838);
|
|
29
33
|
--ux-accent: var(--accent, var(--muted, #303030));
|
|
34
|
+
--ux-muted: var(--muted, #262626);
|
|
35
|
+
--ux-muted-foreground: var(--muted-foreground, #a3a3a3);
|
|
36
|
+
--ux-primary: var(--primary, #60a5fa);
|
|
37
|
+
--ux-destructive: var(--destructive, #f87171);
|
|
30
38
|
--ux-ring: var(--ring, #d4d4d4);
|
|
31
39
|
--ux-sidebar: var(--sidebar, #161616);
|
|
32
40
|
--ux-sidebar-foreground: var(--sidebar-foreground, var(--foreground, #f2f2f2));
|
|
@@ -462,3 +470,236 @@
|
|
|
462
470
|
transition: none;
|
|
463
471
|
}
|
|
464
472
|
}
|
|
473
|
+
|
|
474
|
+
/* --- Markdown --- */
|
|
475
|
+
|
|
476
|
+
/*
|
|
477
|
+
* One typographic scale for every Markdown surface in the family: replies, checkpoints, manuals,
|
|
478
|
+
* documents and articles all render through <Markdown>. Every size here is relative to the
|
|
479
|
+
* inherited font size and no measure is imposed, so the same content keeps identical proportions
|
|
480
|
+
* inside a 14px chat bubble and a 16px article page — the host container decides the column, this
|
|
481
|
+
* block decides the rhythm.
|
|
482
|
+
*/
|
|
483
|
+
|
|
484
|
+
.ux-markdown {
|
|
485
|
+
min-width: 0;
|
|
486
|
+
line-height: 1.7;
|
|
487
|
+
overflow-wrap: break-word;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.ux-markdown > :first-child {
|
|
491
|
+
margin-top: 0;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.ux-markdown > :last-child {
|
|
495
|
+
margin-bottom: 0;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.ux-markdown p,
|
|
499
|
+
.ux-markdown ul,
|
|
500
|
+
.ux-markdown ol,
|
|
501
|
+
.ux-markdown blockquote,
|
|
502
|
+
.ux-markdown pre,
|
|
503
|
+
.ux-markdown .ux-markdown__table,
|
|
504
|
+
.ux-markdown .ux-markdown__mermaid {
|
|
505
|
+
margin: 0.75em 0;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.ux-markdown h1,
|
|
509
|
+
.ux-markdown h2,
|
|
510
|
+
.ux-markdown h3,
|
|
511
|
+
.ux-markdown h4,
|
|
512
|
+
.ux-markdown h5,
|
|
513
|
+
.ux-markdown h6 {
|
|
514
|
+
margin: 1.5em 0 0.5em;
|
|
515
|
+
font-weight: 600;
|
|
516
|
+
line-height: 1.3;
|
|
517
|
+
letter-spacing: -0.01em;
|
|
518
|
+
text-wrap: balance;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.ux-markdown h1 {
|
|
522
|
+
font-size: 1.5em;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.ux-markdown h2 {
|
|
526
|
+
font-size: 1.25em;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.ux-markdown h3 {
|
|
530
|
+
font-size: 1.125em;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.ux-markdown h4,
|
|
534
|
+
.ux-markdown h5,
|
|
535
|
+
.ux-markdown h6 {
|
|
536
|
+
font-size: 1em;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.ux-markdown ul,
|
|
540
|
+
.ux-markdown ol {
|
|
541
|
+
padding-left: 1.5em;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.ux-markdown ul {
|
|
545
|
+
list-style: disc;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.ux-markdown ol {
|
|
549
|
+
list-style: decimal;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.ux-markdown li {
|
|
553
|
+
margin: 0.25em 0;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.ux-markdown li > ul,
|
|
557
|
+
.ux-markdown li > ol {
|
|
558
|
+
margin: 0.25em 0;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/* GFM task lists: the marker column disappears and the checkbox takes its place. */
|
|
562
|
+
.ux-markdown ul.contains-task-list {
|
|
563
|
+
padding-left: 0.25em;
|
|
564
|
+
list-style: none;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.ux-markdown li.task-list-item {
|
|
568
|
+
list-style: none;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.ux-markdown li.task-list-item > input[type="checkbox"] {
|
|
572
|
+
margin: 0 0.4em 0 0;
|
|
573
|
+
vertical-align: 0.05em;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
.ux-markdown blockquote {
|
|
577
|
+
padding-left: 1em;
|
|
578
|
+
color: var(--ux-muted-foreground);
|
|
579
|
+
border-left: 2px solid var(--ux-border);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.ux-markdown blockquote > :first-child {
|
|
583
|
+
margin-top: 0;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.ux-markdown blockquote > :last-child {
|
|
587
|
+
margin-bottom: 0;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.ux-markdown hr {
|
|
591
|
+
margin: 2em 0;
|
|
592
|
+
border: 0;
|
|
593
|
+
border-top: 1px solid var(--ux-border);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
.ux-markdown a {
|
|
597
|
+
color: var(--ux-primary);
|
|
598
|
+
text-decoration: underline;
|
|
599
|
+
text-underline-offset: 0.2em;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.ux-markdown a:hover {
|
|
603
|
+
text-decoration-thickness: 2px;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/* Sized in `em` so the marker tracks the text it follows instead of sitting at a fixed 12px. */
|
|
607
|
+
.ux-markdown .ux-markdown__external-link {
|
|
608
|
+
display: inline-block;
|
|
609
|
+
width: 0.75em;
|
|
610
|
+
height: 0.75em;
|
|
611
|
+
margin-left: 0.2em;
|
|
612
|
+
vertical-align: -0.05em;
|
|
613
|
+
color: var(--ux-muted-foreground);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
.ux-markdown code {
|
|
617
|
+
padding: 0.15em 0.35em;
|
|
618
|
+
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
|
|
619
|
+
font-size: 0.875em;
|
|
620
|
+
background: var(--ux-muted);
|
|
621
|
+
border-radius: 0.25rem;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.ux-markdown pre {
|
|
625
|
+
padding: 0.875em 1em;
|
|
626
|
+
overflow-x: auto;
|
|
627
|
+
overscroll-behavior-x: contain;
|
|
628
|
+
line-height: 1.55;
|
|
629
|
+
background: var(--ux-muted);
|
|
630
|
+
border-radius: 0.5rem;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.ux-markdown pre code {
|
|
634
|
+
padding: 0;
|
|
635
|
+
font-size: 0.8125em;
|
|
636
|
+
background: none;
|
|
637
|
+
border-radius: 0;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.ux-markdown .ux-markdown__table {
|
|
641
|
+
max-width: 100%;
|
|
642
|
+
overflow-x: auto;
|
|
643
|
+
overscroll-behavior-x: contain;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/* Wide tables scroll; short ones still fill the column rather than shrinking to their content. */
|
|
647
|
+
.ux-markdown table {
|
|
648
|
+
width: 100%;
|
|
649
|
+
min-width: max-content;
|
|
650
|
+
font-size: 0.9375em;
|
|
651
|
+
text-align: left;
|
|
652
|
+
border-collapse: collapse;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.ux-markdown th,
|
|
656
|
+
.ux-markdown td {
|
|
657
|
+
padding: 0.4em 0.75em;
|
|
658
|
+
vertical-align: top;
|
|
659
|
+
border-bottom: 1px solid var(--ux-border);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.ux-markdown th {
|
|
663
|
+
font-weight: 600;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.ux-markdown tr:last-child td {
|
|
667
|
+
border-bottom: 0;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.ux-markdown img {
|
|
671
|
+
max-width: 100%;
|
|
672
|
+
height: auto;
|
|
673
|
+
border-radius: 0.375rem;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.ux-markdown del {
|
|
677
|
+
color: var(--ux-muted-foreground);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.ux-markdown strong {
|
|
681
|
+
font-weight: 600;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/* Display math scrolls inside its own line instead of widening the surface around it. */
|
|
685
|
+
.ux-markdown .katex-display {
|
|
686
|
+
padding: 0.25em 0;
|
|
687
|
+
overflow-x: auto;
|
|
688
|
+
overflow-y: hidden;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.ux-markdown .katex-error {
|
|
692
|
+
color: var(--ux-destructive);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.ux-markdown .ux-markdown__mermaid {
|
|
696
|
+
overflow-x: auto;
|
|
697
|
+
overscroll-behavior-x: contain;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
.ux-markdown .ux-markdown__mermaid svg {
|
|
701
|
+
display: block;
|
|
702
|
+
max-width: none;
|
|
703
|
+
height: auto;
|
|
704
|
+
margin: 0 auto;
|
|
705
|
+
}
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zccz14/ux",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Unified
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Unified app shell and Markdown renderer for the NTNL app family: one animated icon sidebar, a fixed-size logo that doubles as the page favicon, the Linkit-integrated AppHeader, and the single Markdown surface every app renders through.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "vite build && tsc -p tsconfig.build.json && cp src/styles.css dist/styles.css",
|
|
36
|
-
"test": "vitest run && node scripts/check-styles.mjs",
|
|
36
|
+
"test": "vitest run && node scripts/check-styles.mjs && node scripts/check-package.mjs",
|
|
37
37
|
"typecheck": "tsc --noEmit",
|
|
38
38
|
"pack:check": "npm pack --dry-run"
|
|
39
39
|
},
|
|
@@ -44,10 +44,19 @@
|
|
|
44
44
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
45
45
|
"react-router-dom": "^7.0.0"
|
|
46
46
|
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"katex": "^0.16.47",
|
|
49
|
+
"mermaid": "^11.17.2",
|
|
50
|
+
"react-markdown": "^10.1.0",
|
|
51
|
+
"rehype-katex": "^7.0.1",
|
|
52
|
+
"remark-gfm": "^4.0.1",
|
|
53
|
+
"remark-math-extended": "^6.1.1"
|
|
54
|
+
},
|
|
47
55
|
"devDependencies": {
|
|
48
56
|
"@base-ui/react": "^1.6.0",
|
|
49
57
|
"@testing-library/jest-dom": "^6.9.1",
|
|
50
58
|
"@testing-library/react": "^16.3.0",
|
|
59
|
+
"@types/hast": "^3.0.5",
|
|
51
60
|
"@types/react": "^19.1.16",
|
|
52
61
|
"@types/react-dom": "^19.1.9",
|
|
53
62
|
"auth-mini-react-components": "^0.6.10",
|