@devalok/shilp-sutra 0.55.1 → 0.56.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/BREAKING.json +13 -0
- package/MIGRATION.md +56 -0
- package/README.md +16 -1
- package/dist/_chunks/badge-group.js +45 -45
- package/dist/_chunks/emoji-suggestion.js +32 -30
- package/dist/_chunks/emoji-suggestion.js.map +1 -1
- package/dist/_chunks/mention-suggestion.js +35 -34
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/primitives-internal.js +437 -537
- package/dist/_chunks/primitives-internal.js.map +1 -1
- package/dist/composed/content-card.js +18 -18
- package/dist/composed/extensions/emoji-node.js +8 -7
- package/dist/composed/extensions/emoji-node.js.map +1 -1
- package/dist/composed/rich-chat-input.js +535 -526
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +201 -193
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/ui/alert.js +29 -29
- package/dist/ui/avatar.js +42 -42
- package/dist/ui/banner.js +25 -25
- package/dist/ui/button.js +31 -31
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.js +39 -39
- package/dist/ui/combobox.js +135 -135
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/dot.js +13 -13
- package/dist/ui/input.js +25 -25
- package/dist/ui/lib/utils.js +2 -1
- package/dist/ui/lib/utils.js.map +1 -1
- package/dist/ui/number-input.js +36 -36
- package/dist/ui/progress.js +55 -55
- package/dist/ui/select.js +58 -58
- package/dist/ui/sheet.js +46 -46
- package/dist/ui/sidebar.js +128 -128
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/skeleton.js +39 -39
- package/dist/ui/slider.js +18 -18
- package/dist/ui/surface.js +9 -9
- package/dist/ui/tabs.js +47 -47
- package/dist/ui/text.js +8 -8
- package/dist/ui/textarea.js +12 -12
- package/dist/ui/toggle.js +12 -12
- package/docs/recipes/install-astro.md +2 -2
- package/docs/recipes/install-next-app-router.md +2 -2
- package/docs/recipes/install-remix.md +2 -2
- package/docs/recipes/install-tanstack-start.md +2 -2
- package/docs/recipes/install-vite.md +2 -2
- package/docs/recipes/troubleshoot.md +26 -5
- package/llms.txt +1 -1
- package/mcp-manifest.json +24 -3
- package/package.json +38 -11
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +1 -1
- package/skill/references/setup-astro.md +2 -2
- package/skill/references/setup-next-app-router.md +2 -2
- package/skill/references/setup-remix.md +2 -2
- package/skill/references/setup-tanstack-start.md +2 -2
- package/skill/references/setup-vite.md +2 -2
- package/skill/references/troubleshoot.md +26 -5
- package/dist/_chunks/tiptap.js +0 -18809
- package/dist/_chunks/tiptap.js.map +0 -1
- package/dist/_chunks/vendor-utils.js +0 -1766
- package/dist/_chunks/vendor-utils.js.map +0 -1
- package/scripts/welcome.mjs +0 -312
package/BREAKING.json
CHANGED
|
@@ -350,6 +350,19 @@
|
|
|
350
350
|
"Fastest migration: `npx shadcn@latest add @devalok/sidebar-app`, then replace <AppSidebar navGroups={…} user={…} currentPath={…} /> with the pasted <SidebarApp/>, wiring your router Link + active path. Composing @devalok/shilp-sutra/ui/sidebar directly is equally valid and needs no registry.",
|
|
351
351
|
"Deprecation cycle: no PUBLISHED version carried an @deprecated AppSidebar — 0.53.0 shipped it undeprecated, 0.54.0 removes it. The deprecation marker existed only within the unreleased 0.54.0 line. This is a deliberate call for a 0.x beta with a single coordinated consumer (breaking changes ship in 0.x minors); a post-1.0 removal would get a real deprecate→remove window."
|
|
352
352
|
]
|
|
353
|
+
},
|
|
354
|
+
"0.56.0": {
|
|
355
|
+
"summary": "TipTap is no longer bundled — @tiptap/* and prosemirror-* are externalized, so RichTextEditor / RichChatInput now REQUIRE their peers to be installed. No symbol, prop, or export changed; this is an install-graph break only.",
|
|
356
|
+
"migrationDoc": "MIGRATION.md#v0560--tiptap-externalized--no-install-scripts",
|
|
357
|
+
"notes": [
|
|
358
|
+
"BREAKING: @tiptap/* and prosemirror-* were declared as optional peerDependencies AND bundled into a 641 KB _chunks/tiptap.js. RichTextEditor / RichChatInput therefore worked whether or not you installed the peers. They are now externalized and the peers are mandatory for those two components. Install command per framework: §2a of docs/recipes/install-*.md, or run the MCP's preflight tool.",
|
|
359
|
+
"WHY: a consumer who DID follow our peer instructions ran two ProseMirror copies. Plugin keys are module-scoped, so the copies could not see each other's plugins and the editors misbehaved un-attributably. Same failure class as the framer-motion/sonner externalization in 0.37.0. It also removes 641 KB from the package for every consumer who never touches rich text.",
|
|
360
|
+
"Twelve @tiptap/* packages are now declared as optional peers (previously four: core, pm, react, suggestion) — the full set we import must be resolvable by the consumer. Two internal `prosemirror-state` imports were rerouted to `@tiptap/pm/state` so they ride the existing @tiptap/pm peer instead of requiring a separate prosemirror-state install.",
|
|
361
|
+
"NOT breaking: every component outside RichTextEditor / RichChatInput is untouched. No exported symbol, prop type, or subpath export changed in this release — no widening and no narrowing.",
|
|
362
|
+
"use-sync-external-store is no longer a dependency. React 18+ has useSyncExternalStore built in and our own code always called it directly (primitives/_internal/react-use-is-hydrated.ts); the dep existed only to feed the bundled TipTap chunk. Runtime dependencies are now class-variance-authority, clsx, tailwind-merge, tw-animate-css.",
|
|
363
|
+
"clsx / class-variance-authority / tailwind-merge are now externalized rather than bundled. All three leak into our published .d.ts (25 files reference VariantProps, cva's return type embeds class-variance-authority/types#ClassProp, utils.d.ts imports ClassValue), so consumers already had to resolve them for tsc; bundling a second copy shipped the same code twice and blocked dedupe with the consumer's own copies. tailwind-merge moves devDependency -> dependency (it was already shipping, hidden inside our bundle). All auto-installed with us — no consumer action.",
|
|
364
|
+
"The postinstall script is REMOVED — this package now runs no lifecycle scripts at all on install. It previously printed a welcome banner and wrote a project-scoped .mcp.json into the consumer's repo pointing at our hosted docs MCP. Nothing is required when upgrading. To clean up after the old behaviour: remove the `shilp-sutra` entry from .mcp.json and delete the node_modules/.shilp-sutra-welcomed and .shilp-sutra-mcp-written sentinels. Add the MCP deliberately with `claude mcp add --transport http shilp-sutra https://shilp-sutra.devalok.in/mcp`."
|
|
365
|
+
]
|
|
353
366
|
}
|
|
354
367
|
}
|
|
355
368
|
}
|
package/MIGRATION.md
CHANGED
|
@@ -4,6 +4,62 @@ This page indexes all breaking changes across `@devalok/shilp-sutra` versions. F
|
|
|
4
4
|
|
|
5
5
|
> **Upgrading from < 0.36?** Start here, then read each intermediate version section. Breaking changes stack — skipping versions means stacking migrations.
|
|
6
6
|
|
|
7
|
+
## v0.56.0 — TipTap externalized; no install scripts
|
|
8
|
+
|
|
9
|
+
One breaking change, and it only affects `RichTextEditor` / `RichChatInput`. No exported symbol, prop type, or subpath export changed — nothing widened and nothing narrowed.
|
|
10
|
+
|
|
11
|
+
### If you import `RichTextEditor` or `RichChatInput`, install the TipTap peers
|
|
12
|
+
|
|
13
|
+
0.55.x declared `@tiptap/*` as optional peers **and** bundled TipTap into a 641 KB chunk, so these components worked whether or not you installed anything. TipTap is now externalized: the peers are required.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# RichTextEditor
|
|
17
|
+
pnpm add @tiptap/core @tiptap/extension-highlight @tiptap/extension-image \
|
|
18
|
+
@tiptap/extension-list @tiptap/extension-mention @tiptap/extension-text-align \
|
|
19
|
+
@tiptap/extensions @tiptap/markdown @tiptap/pm @tiptap/react \
|
|
20
|
+
@tiptap/starter-kit @tiptap/suggestion
|
|
21
|
+
|
|
22
|
+
# RichChatInput — the list above, plus:
|
|
23
|
+
pnpm add date-fns
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Note these are plain `pnpm add`, not `-D`. In 0.55.0 they were devDependencies for types only; now they are the runtime.
|
|
27
|
+
|
|
28
|
+
§2a of your framework's install recipe carries the same list, and the docs MCP's `preflight` derives it from your actual imports.
|
|
29
|
+
|
|
30
|
+
**Why the churn:** the old arrangement meant a consumer who *did* follow our peer instructions ran two ProseMirror copies. Plugin keys are module-scoped, so the copies could not recognise each other's plugins and the editors misbehaved in ways nobody could attribute to us. This is the same failure class as the framer-motion / sonner externalization in 0.37.0. It also removes 641 KB from the package for every consumer who never touches rich text.
|
|
31
|
+
|
|
32
|
+
### If you don't use the editors — nothing to do
|
|
33
|
+
|
|
34
|
+
Every other component is untouched, and the package gets smaller.
|
|
35
|
+
|
|
36
|
+
### `use-sync-external-store` is gone — nothing to do
|
|
37
|
+
|
|
38
|
+
It was never ours. React 18+ has `useSyncExternalStore` built in and our code always called it directly; the dependency existed only to feed the bundled TipTap chunk. Runtime dependencies are now `class-variance-authority`, `clsx`, `tailwind-merge`, `tw-animate-css`.
|
|
39
|
+
|
|
40
|
+
### `clsx` / `class-variance-authority` / `tailwind-merge` externalized — nothing to do
|
|
41
|
+
|
|
42
|
+
All three leak into our published `.d.ts`, so you already had to resolve them for `tsc`. We were also bundling copies, which shipped the same code twice and stopped your own copies from deduping with ours. `tailwind-merge` moves from our devDependencies to our dependencies — it was already shipping, just hidden inside the bundle. All three install with us automatically.
|
|
43
|
+
|
|
44
|
+
### No more `postinstall` — nothing to do
|
|
45
|
+
|
|
46
|
+
This package now runs **zero lifecycle scripts** on install. The old `postinstall` printed a welcome banner and wrote a project-scoped `.mcp.json` into your repo pointing at our hosted docs MCP.
|
|
47
|
+
|
|
48
|
+
To clean up after the old behaviour if you want to:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# 1. drop the entry we added (or the whole file, if we created it and you keep nothing else there)
|
|
52
|
+
# .mcp.json → mcpServers → "shilp-sutra"
|
|
53
|
+
# 2. remove the sentinels
|
|
54
|
+
rm -f node_modules/.shilp-sutra-welcomed node_modules/.shilp-sutra-mcp-written
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
To add the MCP deliberately:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
claude mcp add --transport http shilp-sutra https://shilp-sutra.devalok.in/mcp
|
|
61
|
+
```
|
|
62
|
+
|
|
7
63
|
## v0.55.0 — additive; one optional step if you use the editors
|
|
8
64
|
|
|
9
65
|
Nothing breaks. No existing import, prop value, or install stops working.
|
package/README.md
CHANGED
|
@@ -53,8 +53,22 @@ claude mcp add --transport http shilp-sutra https://shilp-sutra.devalok.in/mcp
|
|
|
53
53
|
|
|
54
54
|
Six read-only tools: `find_component`, `get_component`, `get_tokens`, `get_setup`, `upgrade`, `search_docs`. Every tool takes a `version` param — pass your installed version (from `node_modules/@devalok/shilp-sutra/package.json`) so answers match your prop surface exactly.
|
|
55
55
|
|
|
56
|
+
Prefer a local skill over a network call? Copy the one we ship:
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
cp -r node_modules/@devalok/shilp-sutra/skill ~/.claude/skills/shilp-sutra
|
|
60
|
+
```
|
|
61
|
+
|
|
56
62
|
Without MCP: `llms.txt` (router) → `docs/components/<tier>/<name>.md` (per-component) → `mcp-manifest.json` (all props/tokens/composition as JSON). Full contract in `AGENTS.md`.
|
|
57
63
|
|
|
64
|
+
### No install scripts
|
|
65
|
+
|
|
66
|
+
This package has **no `postinstall` and no lifecycle scripts of any kind**. Installing it runs zero code on your machine and writes nothing outside its own directory.
|
|
67
|
+
|
|
68
|
+
Up to 0.55.x we shipped a `postinstall` that printed a welcome banner and wrote a project-scoped `.mcp.json` pointing at the docs MCP above. Both are gone as of 0.56.0. The banner was noise; writing a config file into someone's repo — unasked, to wire their AI agent to our server — is exactly the behaviour npm's install-script blocking exists to stop, and it is not a thing a design system should do to earn a place in your dependency tree. Add the MCP yourself with the command above if you want it.
|
|
69
|
+
|
|
70
|
+
> **Upgrading from ≤0.55.x?** Nothing to do. If you want the old auto-written config gone, delete the `shilp-sutra` entry from your `.mcp.json` (or the file, if we created it and you keep nothing else there) and remove the `node_modules/.shilp-sutra-welcomed` / `.shilp-sutra-mcp-written` sentinels.
|
|
71
|
+
|
|
58
72
|
## Peer Dependencies
|
|
59
73
|
|
|
60
74
|
### Required
|
|
@@ -74,7 +88,8 @@ Install only what you use:
|
|
|
74
88
|
|---------|----------|
|
|
75
89
|
| Toasts (`./ui/toaster`, `./ui/toast`) | `sonner` |
|
|
76
90
|
| Charts (`./ui/charts`) | `d3-array`, `d3-axis`, `d3-format`, `d3-interpolate`, `d3-scale`, `d3-selection`, `d3-shape`, `d3-time-format`, `d3-transition` |
|
|
77
|
-
| Rich Text Editor (`./composed/rich-text-editor`) | `@tiptap/react`, `@tiptap/starter-kit` |
|
|
91
|
+
| Rich Text Editor (`./composed/rich-text-editor`) | `@tiptap/core`, `@tiptap/extension-highlight`, `@tiptap/extension-image`, `@tiptap/extension-list`, `@tiptap/extension-mention`, `@tiptap/extension-text-align`, `@tiptap/extensions`, `@tiptap/markdown`, `@tiptap/pm`, `@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/suggestion` |
|
|
92
|
+
| Rich Chat Input (`./composed/rich-chat-input`) | the Rich Text Editor list, plus `date-fns` |
|
|
78
93
|
| DataTable (`./ui/data-table`) | `@tanstack/react-table`, `@tanstack/react-virtual` |
|
|
79
94
|
| Icons | `@tabler/icons-react` |
|
|
80
95
|
| Date components (`./composed/date-picker`) | `date-fns` |
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Slot as e } from "./primitives-internal.js";
|
|
3
3
|
import { durations as t, springs as n } from "../ui/lib/motion.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
4
|
+
import { cn as r } from "../ui/lib/utils.js";
|
|
5
|
+
import { Icon as i } from "../ui/icon.js";
|
|
6
|
+
import { Dot as a } from "../ui/dot.js";
|
|
7
|
+
import { normalizeIcon as o } from "./normalize-icon.js";
|
|
8
|
+
import { BadgeIndicator as s } from "../ui/badge-indicator.js";
|
|
9
|
+
import * as c from "react";
|
|
10
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
11
|
+
import { IconCheck as d, IconX as f } from "@tabler/icons-react";
|
|
12
|
+
import { AnimatePresence as p, motion as m } from "framer-motion";
|
|
13
|
+
import { cva as h } from "class-variance-authority";
|
|
14
14
|
//#region src/ui/badge.tsx
|
|
15
15
|
var g = {
|
|
16
16
|
default: {
|
|
@@ -116,13 +116,13 @@ function _(e, t) {
|
|
|
116
116
|
if (t === "custom") return "";
|
|
117
117
|
let n = g[t];
|
|
118
118
|
switch (e) {
|
|
119
|
-
case "subtle": return
|
|
120
|
-
case "solid": return
|
|
121
|
-
case "outline": return
|
|
122
|
-
case "soft": return
|
|
119
|
+
case "subtle": return r(n.bg, n.fg, n.border);
|
|
120
|
+
case "solid": return r(n.solid, n.solidFg, "border-transparent");
|
|
121
|
+
case "outline": return r("bg-transparent", n.fg, n.border);
|
|
122
|
+
case "soft": return r(n.bg, n.fg, "border-transparent");
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
-
var v =
|
|
125
|
+
var v = h("relative inline-flex items-center rounded-pill font-sans font-medium overflow-hidden isolate transition-[color,background-color,border-color,padding] duration-fast-02 ease-productive-standard select-none [&>span:not([data-grain])]:relative [&>span:not([data-grain])]:z-[2]", {
|
|
126
126
|
variants: {
|
|
127
127
|
variant: {
|
|
128
128
|
subtle: "border",
|
|
@@ -156,8 +156,8 @@ var v = r("relative inline-flex items-center rounded-pill font-sans font-medium
|
|
|
156
156
|
sm: "pr-ds-02",
|
|
157
157
|
md: "pr-ds-02",
|
|
158
158
|
lg: "pr-ds-02b"
|
|
159
|
-
}, S =
|
|
160
|
-
let R = c ?? "subtle", z =
|
|
159
|
+
}, S = c.forwardRef(({ className: s, variant: c, color: h, size: g, asChild: S, startIcon: C, endIcon: w, dot: T, dotPulse: E, onDismiss: D, onClick: O, selected: k, disabled: A, maxWidth: j, truncate: M, circle: N, children: P, style: F, ...I }, L) => {
|
|
160
|
+
let R = c ?? "subtle", z = h ?? "default", B = g ?? "md", V = S ? e : O && D ? "div" : O ? "button" : "span", H = z === "custom" ? {
|
|
161
161
|
...R === "subtle" && {
|
|
162
162
|
backgroundColor: "color-mix(in oklch, var(--badge-color) 15%, transparent)",
|
|
163
163
|
color: "var(--badge-color)",
|
|
@@ -181,12 +181,12 @@ var v = r("relative inline-flex items-center rounded-pill font-sans font-medium
|
|
|
181
181
|
} : void 0, U = O && D ? (e) => {
|
|
182
182
|
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), A || O(e)), I.onKeyDown?.(e);
|
|
183
183
|
} : I.onKeyDown, W = !!(T || C || O && k && !C && !T), G = !!(D || w);
|
|
184
|
-
return /* @__PURE__ */
|
|
184
|
+
return /* @__PURE__ */ u(V, {
|
|
185
185
|
ref: L,
|
|
186
|
-
className:
|
|
186
|
+
className: r(v({
|
|
187
187
|
variant: R,
|
|
188
188
|
size: B
|
|
189
|
-
}), _(R, z), W && b[B], G && x[B], O && "cursor-pointer hover:brightness-[0.97] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-1 transition-[color,background-color,border-color,transform,filter] duration-moderate-01 ease-productive-exit hover:duration-fast-02 hover:ease-productive-entrance active:scale-[0.95] active:brightness-[0.92] active:duration-[0ms]", k && "ring-1 ring-current/20 transition-shadow duration-fast-02", A && "opacity-action-disabled pointer-events-none saturate-[0.3]", N && "justify-center px-0 aspect-square",
|
|
189
|
+
}), _(R, z), W && b[B], G && x[B], O && "cursor-pointer hover:brightness-[0.97] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-1 transition-[color,background-color,border-color,transform,filter] duration-moderate-01 ease-productive-exit hover:duration-fast-02 hover:ease-productive-entrance active:scale-[0.95] active:brightness-[0.92] active:duration-[0ms]", k && "ring-1 ring-current/20 transition-shadow duration-fast-02", A && "opacity-action-disabled pointer-events-none saturate-[0.3]", N && "justify-center px-0 aspect-square", s),
|
|
190
190
|
style: {
|
|
191
191
|
...F,
|
|
192
192
|
...H,
|
|
@@ -202,19 +202,19 @@ var v = r("relative inline-flex items-center rounded-pill font-sans font-medium
|
|
|
202
202
|
} : {},
|
|
203
203
|
...I,
|
|
204
204
|
children: [
|
|
205
|
-
/* @__PURE__ */
|
|
205
|
+
/* @__PURE__ */ l(p, { children: T && /* @__PURE__ */ l(m.span, {
|
|
206
206
|
initial: { scale: 0 },
|
|
207
207
|
animate: { scale: 1 },
|
|
208
208
|
exit: { scale: 0 },
|
|
209
209
|
transition: n.snappy,
|
|
210
210
|
className: "inline-flex shrink-0",
|
|
211
|
-
children: /* @__PURE__ */
|
|
211
|
+
children: /* @__PURE__ */ l(a, {
|
|
212
212
|
color: "current",
|
|
213
213
|
size: "sm",
|
|
214
214
|
pulse: E
|
|
215
215
|
})
|
|
216
216
|
}, "dot") }),
|
|
217
|
-
O && !C && !T && /* @__PURE__ */
|
|
217
|
+
O && !C && !T && /* @__PURE__ */ l(m.span, {
|
|
218
218
|
initial: !1,
|
|
219
219
|
animate: k ? {
|
|
220
220
|
opacity: 1,
|
|
@@ -239,33 +239,33 @@ var v = r("relative inline-flex items-center rounded-pill font-sans font-medium
|
|
|
239
239
|
},
|
|
240
240
|
className: "inline-flex shrink-0 overflow-hidden",
|
|
241
241
|
"aria-hidden": !k,
|
|
242
|
-
children: /* @__PURE__ */
|
|
243
|
-
icon:
|
|
242
|
+
children: /* @__PURE__ */ l(i, {
|
|
243
|
+
icon: d,
|
|
244
244
|
size: "xs"
|
|
245
245
|
})
|
|
246
246
|
}),
|
|
247
|
-
C && /* @__PURE__ */
|
|
248
|
-
className:
|
|
249
|
-
children:
|
|
247
|
+
C && /* @__PURE__ */ l("span", {
|
|
248
|
+
className: r("shrink-0", y[B]),
|
|
249
|
+
children: o(C)
|
|
250
250
|
}),
|
|
251
|
-
M || j ? /* @__PURE__ */
|
|
251
|
+
M || j ? /* @__PURE__ */ l("span", {
|
|
252
252
|
className: "truncate",
|
|
253
253
|
title: typeof P == "string" ? P : void 0,
|
|
254
254
|
children: P
|
|
255
255
|
}) : P,
|
|
256
|
-
w && /* @__PURE__ */
|
|
257
|
-
className:
|
|
258
|
-
children:
|
|
256
|
+
w && /* @__PURE__ */ l("span", {
|
|
257
|
+
className: r("shrink-0", y[B]),
|
|
258
|
+
children: o(w)
|
|
259
259
|
}),
|
|
260
|
-
D && /* @__PURE__ */
|
|
260
|
+
D && /* @__PURE__ */ l("button", {
|
|
261
261
|
type: "button",
|
|
262
262
|
onClick: (e) => {
|
|
263
263
|
e.stopPropagation(), D();
|
|
264
264
|
},
|
|
265
|
-
className:
|
|
265
|
+
className: r("shrink-0 rounded-pill text-current/60 hover:text-current hover:bg-current/10 transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-accent-9", B === "xs" ? "p-0 -mr-0.5 min-w-ds-05 min-h-ds-05" : "p-px"),
|
|
266
266
|
"aria-label": `Remove ${typeof P == "string" ? P : ""}`.trim() || "Remove",
|
|
267
|
-
children: /* @__PURE__ */
|
|
268
|
-
icon:
|
|
267
|
+
children: /* @__PURE__ */ l(i, {
|
|
268
|
+
icon: f,
|
|
269
269
|
size: "xs"
|
|
270
270
|
})
|
|
271
271
|
})
|
|
@@ -274,24 +274,24 @@ var v = r("relative inline-flex items-center rounded-pill font-sans font-medium
|
|
|
274
274
|
});
|
|
275
275
|
S.displayName = "Badge";
|
|
276
276
|
var C = Object.assign(S, {
|
|
277
|
-
Indicator:
|
|
277
|
+
Indicator: s,
|
|
278
278
|
Group: T
|
|
279
279
|
}), w = {
|
|
280
280
|
tight: "gap-1",
|
|
281
281
|
default: "gap-1.5",
|
|
282
282
|
loose: "gap-2"
|
|
283
|
-
}, T =
|
|
284
|
-
let
|
|
285
|
-
return /* @__PURE__ */
|
|
286
|
-
ref:
|
|
287
|
-
className:
|
|
283
|
+
}, T = c.forwardRef(function({ max: e, gap: t = "default", size: n, onOverflowClick: i, className: a, children: o, ...s }, l) {
|
|
284
|
+
let d = c.Children.toArray(o), f = d.length, p = e !== void 0 && f > e, m = p ? d.slice(0, e) : d, h = p ? f - e : 0;
|
|
285
|
+
return /* @__PURE__ */ u("div", {
|
|
286
|
+
ref: l,
|
|
287
|
+
className: r("flex flex-wrap items-center", w[t], a),
|
|
288
288
|
...s,
|
|
289
|
-
children: [m, p && /* @__PURE__ */
|
|
289
|
+
children: [m, p && /* @__PURE__ */ u(C, {
|
|
290
290
|
variant: "outline",
|
|
291
291
|
color: "neutral",
|
|
292
292
|
size: n ?? "sm",
|
|
293
|
-
onClick:
|
|
294
|
-
"aria-label":
|
|
293
|
+
onClick: i,
|
|
294
|
+
"aria-label": i ? `Show ${h} more` : void 0,
|
|
295
295
|
children: ["+", h]
|
|
296
296
|
})]
|
|
297
297
|
});
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../ui/lib/utils.js";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import * as t from "react";
|
|
4
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
5
|
+
import { Extension as i } from "@tiptap/core";
|
|
6
|
+
import a from "@tiptap/suggestion";
|
|
7
|
+
import { PluginKey as o } from "@tiptap/pm/state";
|
|
6
8
|
import { createRoot as s } from "react-dom/client";
|
|
7
9
|
//#region src/composed/extensions/emoji-data.ts
|
|
8
10
|
var c = null;
|
|
@@ -31,27 +33,27 @@ function d(e, t, n = 8) {
|
|
|
31
33
|
//#endregion
|
|
32
34
|
//#region src/composed/extensions/emoji-suggestion.tsx
|
|
33
35
|
function f({ emoji: e, size: t = "1.2em" }) {
|
|
34
|
-
return /* @__PURE__ */
|
|
36
|
+
return /* @__PURE__ */ n("span", {
|
|
35
37
|
style: { fontSize: t },
|
|
36
38
|
children: e.native
|
|
37
39
|
});
|
|
38
40
|
}
|
|
39
|
-
var p =
|
|
40
|
-
let [s, c] =
|
|
41
|
-
return
|
|
41
|
+
var p = t.forwardRef(({ items: i, command: a }, o) => {
|
|
42
|
+
let [s, c] = t.useState(0);
|
|
43
|
+
return t.useEffect(() => c(0), [i]), t.useImperativeHandle(o, () => ({ onKeyDown: ({ event: e }) => e.key === "ArrowUp" ? (c((e) => (e + i.length - 1) % i.length), !0) : e.key === "ArrowDown" ? (c((e) => (e + 1) % i.length), !0) : e.key === "Enter" ? (i[s] && a(i[s]), !0) : !1 })), i.length ? /* @__PURE__ */ n("div", {
|
|
42
44
|
role: "listbox",
|
|
43
45
|
"aria-label": "Emoji suggestions",
|
|
44
46
|
className: "z-popover max-h-[200px] overflow-x-hidden overflow-y-auto rounded-control bg-surface-overlay shadow-raised-hover",
|
|
45
|
-
children:
|
|
47
|
+
children: i.map((t, i) => /* @__PURE__ */ r("button", {
|
|
46
48
|
type: "button",
|
|
47
49
|
role: "option",
|
|
48
|
-
"aria-selected":
|
|
49
|
-
onClick: () =>
|
|
50
|
-
className: e("flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-body-sm",
|
|
51
|
-
children: [/* @__PURE__ */
|
|
50
|
+
"aria-selected": i === s,
|
|
51
|
+
onClick: () => a(t),
|
|
52
|
+
className: e("flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-body-sm", i === s ? "bg-surface-raised text-surface-fg" : "text-surface-fg-muted hover:bg-surface-raised"),
|
|
53
|
+
children: [/* @__PURE__ */ n(f, {
|
|
52
54
|
emoji: t,
|
|
53
55
|
size: "1.25em"
|
|
54
|
-
}), /* @__PURE__ */
|
|
56
|
+
}), /* @__PURE__ */ r("span", {
|
|
55
57
|
className: "truncate",
|
|
56
58
|
children: [
|
|
57
59
|
":",
|
|
@@ -65,31 +67,31 @@ var p = i.forwardRef(({ items: t, command: n }, r) => {
|
|
|
65
67
|
p.displayName = "EmojiList";
|
|
66
68
|
function m() {
|
|
67
69
|
return () => {
|
|
68
|
-
let e = null, t = null,
|
|
70
|
+
let e = null, t = null, r = null;
|
|
69
71
|
return {
|
|
70
|
-
onStart: (
|
|
72
|
+
onStart: (i) => {
|
|
71
73
|
t = document.createElement("div"), t.style.position = "absolute", t.style.zIndex = "1400";
|
|
72
|
-
let
|
|
73
|
-
|
|
74
|
+
let a = i.clientRect?.();
|
|
75
|
+
a && (t.style.left = `${a.left}px`, t.style.top = `${a.bottom + 4}px`), document.body.appendChild(t), e = s(t), e.render(/* @__PURE__ */ n(p, {
|
|
74
76
|
ref: (e) => {
|
|
75
|
-
|
|
77
|
+
r = e;
|
|
76
78
|
},
|
|
77
|
-
items:
|
|
78
|
-
command: (e) =>
|
|
79
|
+
items: i.items,
|
|
80
|
+
command: (e) => i.command(e)
|
|
79
81
|
}));
|
|
80
82
|
},
|
|
81
|
-
onUpdate: (
|
|
83
|
+
onUpdate: (i) => {
|
|
82
84
|
if (!e || !t) return;
|
|
83
|
-
let
|
|
84
|
-
|
|
85
|
+
let a = i.clientRect?.();
|
|
86
|
+
a && (t.style.left = `${a.left}px`, t.style.top = `${a.bottom + 4}px`), e.render(/* @__PURE__ */ n(p, {
|
|
85
87
|
ref: (e) => {
|
|
86
|
-
|
|
88
|
+
r = e;
|
|
87
89
|
},
|
|
88
|
-
items:
|
|
89
|
-
command: (e) =>
|
|
90
|
+
items: i.items,
|
|
91
|
+
command: (e) => i.command(e)
|
|
90
92
|
}));
|
|
91
93
|
},
|
|
92
|
-
onKeyDown: (
|
|
94
|
+
onKeyDown: (n) => n.event.key === "Escape" ? (t && (e?.unmount(), t.remove(), t = null, e = null), !0) : r?.onKeyDown(n) ?? !1,
|
|
93
95
|
onExit: () => {
|
|
94
96
|
t && (e?.unmount(), t.remove(), t = null, e = null);
|
|
95
97
|
}
|
|
@@ -97,11 +99,11 @@ function m() {
|
|
|
97
99
|
};
|
|
98
100
|
}
|
|
99
101
|
function h() {
|
|
100
|
-
return
|
|
102
|
+
return i.create({
|
|
101
103
|
name: "emojiSuggestion",
|
|
102
104
|
addProseMirrorPlugins() {
|
|
103
|
-
return [
|
|
104
|
-
pluginKey: new
|
|
105
|
+
return [a({
|
|
106
|
+
pluginKey: new o("emojiSuggestion"),
|
|
105
107
|
editor: this.editor,
|
|
106
108
|
char: ":",
|
|
107
109
|
items: async ({ query: e }) => d(await l(), e, 8),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emoji-suggestion.js","names":[],"sources":["../../src/composed/extensions/emoji-data.ts","../../src/composed/extensions/emoji-suggestion.tsx"],"sourcesContent":["// Emoji dataset for the editors' `:shortcode:` autocomplete. Sources\n// `@emoji-mart/data` — a pure-JSON package with NO react peer, so it is\n// unaffected by the React-19 peer issue that drove the picker off\n// `@emoji-mart/react` (→ frimousse). Native-only since that migration: no\n// spritesheet coordinates, no per-art-style loaders.\n\ninterface EmojiSkin {\n native: string\n}\n\ninterface EmojiEntry {\n id: string\n name: string\n keywords?: string[]\n skins: EmojiSkin[]\n}\n\nexport interface EmojiDataset {\n emojis: Record<string, EmojiEntry>\n}\n\nexport interface ResolvedEmoji {\n id: string\n name: string\n native: string\n}\n\nlet cachedData: EmojiDataset | null = null\n\nexport async function loadEmojiData(): Promise<EmojiDataset> {\n if (cachedData) return cachedData\n const mod = await import('@emoji-mart/data')\n cachedData = ((mod as { default?: EmojiDataset }).default ?? mod) as EmojiDataset\n return cachedData\n}\n\nfunction resolve(entry: EmojiEntry): ResolvedEmoji {\n return { id: entry.id, name: entry.name, native: entry.skins[0]?.native ?? '' }\n}\n\nexport function searchEmoji(data: EmojiDataset, query: string, limit = 8): ResolvedEmoji[] {\n const entries = Object.values(data.emojis)\n if (!query) return entries.slice(0, limit).map(resolve)\n const q = query.toLowerCase()\n const results: ResolvedEmoji[] = []\n for (const e of entries) {\n if (results.length >= limit) break\n if (\n e.id.includes(q) ||\n e.name.toLowerCase().includes(q) ||\n e.keywords?.some((k) => k.includes(q))\n ) {\n results.push(resolve(e))\n }\n }\n return results\n}\n","import { Extension } from '@tiptap/core'\nimport Suggestion, { type SuggestionKeyDownProps,type SuggestionProps } from '@tiptap/suggestion'\nimport { PluginKey } from 'prosemirror-state'\nimport * as React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\n\nimport { cn } from '../../ui/lib/utils'\nimport { loadEmojiData, type ResolvedEmoji, searchEmoji } from './emoji-data'\n\n// Re-export for external consumers\nexport type { ResolvedEmoji as EmojiSuggestionItem }\n\n// Native-only since the frimousse migration.\nfunction EmojiImage({ emoji, size = '1.2em' }: { emoji: ResolvedEmoji; size?: string }) {\n return <span style={{ fontSize: size }}>{emoji.native}</span>\n}\n\ninterface EmojiListRef {\n onKeyDown: (props: SuggestionKeyDownProps) => boolean\n}\n\ninterface EmojiListProps {\n items: ResolvedEmoji[]\n command: (item: ResolvedEmoji) => void\n}\n\nconst EmojiList = React.forwardRef<EmojiListRef, EmojiListProps>(\n ({ items, command }, ref) => {\n const [selectedIndex, setSelectedIndex] = React.useState(0)\n\n React.useEffect(() => setSelectedIndex(0), [items])\n\n React.useImperativeHandle(ref, () => ({\n onKeyDown: ({ event }: SuggestionKeyDownProps) => {\n if (event.key === 'ArrowUp') {\n setSelectedIndex((i) => (i + items.length - 1) % items.length)\n return true\n }\n if (event.key === 'ArrowDown') {\n setSelectedIndex((i) => (i + 1) % items.length)\n return true\n }\n if (event.key === 'Enter') {\n if (items[selectedIndex]) command(items[selectedIndex])\n return true\n }\n return false\n },\n }))\n\n if (!items.length) return null\n\n return (\n <div role=\"listbox\" aria-label=\"Emoji suggestions\" className=\"z-popover max-h-[200px] overflow-x-hidden overflow-y-auto rounded-control bg-surface-overlay shadow-raised-hover\">\n {items.map((item, index) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"option\"\n aria-selected={index === selectedIndex}\n onClick={() => command(item)}\n className={cn(\n 'flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-body-sm',\n index === selectedIndex ? 'bg-surface-raised text-surface-fg' : 'text-surface-fg-muted hover:bg-surface-raised',\n )}\n >\n <EmojiImage emoji={item} size=\"1.25em\" />\n <span className=\"truncate\">:{item.id}:</span>\n </button>\n ))}\n </div>\n )\n },\n)\nEmojiList.displayName = 'EmojiList'\n\nfunction createEmojiSuggestionRenderer() {\n return () => {\n let root: Root | null = null\n let container: HTMLDivElement | null = null\n let componentRef: EmojiListRef | null = null\n\n return {\n onStart: (props: SuggestionProps<ResolvedEmoji>) => {\n container = document.createElement('div')\n container.style.position = 'absolute'\n container.style.zIndex = '1400'\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n document.body.appendChild(container)\n root = createRoot(container)\n root.render(\n <EmojiList\n ref={(r) => { componentRef = r }}\n items={props.items as ResolvedEmoji[]}\n command={(item) => props.command(item)}\n />,\n )\n },\n\n onUpdate: (props: SuggestionProps<ResolvedEmoji>) => {\n if (!root || !container) return\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n root.render(\n <EmojiList\n ref={(r) => { componentRef = r }}\n items={props.items as ResolvedEmoji[]}\n command={(item) => props.command(item)}\n />,\n )\n },\n\n onKeyDown: (props: SuggestionKeyDownProps) => {\n if (props.event.key === 'Escape') {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n return true\n }\n return componentRef?.onKeyDown(props) ?? false\n },\n\n onExit: () => {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n },\n }\n }\n}\n\n/** Factory: returns the configured `:shortcode:` emoji suggestion extension. */\nexport function createEmojiSuggestion() {\n return Extension.create({\n name: 'emojiSuggestion',\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n pluginKey: new PluginKey('emojiSuggestion'),\n editor: this.editor,\n char: ':',\n items: async ({ query }) => {\n const data = await loadEmojiData()\n return searchEmoji(data, query, 8)\n },\n command: ({ editor, range, props: item }) => {\n const emoji = item as ResolvedEmoji\n editor\n .chain()\n .focus()\n .deleteRange(range)\n .insertContent({\n type: 'emojiNode',\n attrs: { id: emoji.id, native: emoji.native },\n })\n .run()\n },\n render: createEmojiSuggestionRenderer(),\n }),\n ]\n },\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"emoji-suggestion.js","names":[],"sources":["../../src/composed/extensions/emoji-data.ts","../../src/composed/extensions/emoji-suggestion.tsx"],"sourcesContent":["// Emoji dataset for the editors' `:shortcode:` autocomplete. Sources\n// `@emoji-mart/data` — a pure-JSON package with NO react peer, so it is\n// unaffected by the React-19 peer issue that drove the picker off\n// `@emoji-mart/react` (→ frimousse). Native-only since that migration: no\n// spritesheet coordinates, no per-art-style loaders.\n\ninterface EmojiSkin {\n native: string\n}\n\ninterface EmojiEntry {\n id: string\n name: string\n keywords?: string[]\n skins: EmojiSkin[]\n}\n\nexport interface EmojiDataset {\n emojis: Record<string, EmojiEntry>\n}\n\nexport interface ResolvedEmoji {\n id: string\n name: string\n native: string\n}\n\nlet cachedData: EmojiDataset | null = null\n\nexport async function loadEmojiData(): Promise<EmojiDataset> {\n if (cachedData) return cachedData\n const mod = await import('@emoji-mart/data')\n cachedData = ((mod as { default?: EmojiDataset }).default ?? mod) as EmojiDataset\n return cachedData\n}\n\nfunction resolve(entry: EmojiEntry): ResolvedEmoji {\n return { id: entry.id, name: entry.name, native: entry.skins[0]?.native ?? '' }\n}\n\nexport function searchEmoji(data: EmojiDataset, query: string, limit = 8): ResolvedEmoji[] {\n const entries = Object.values(data.emojis)\n if (!query) return entries.slice(0, limit).map(resolve)\n const q = query.toLowerCase()\n const results: ResolvedEmoji[] = []\n for (const e of entries) {\n if (results.length >= limit) break\n if (\n e.id.includes(q) ||\n e.name.toLowerCase().includes(q) ||\n e.keywords?.some((k) => k.includes(q))\n ) {\n results.push(resolve(e))\n }\n }\n return results\n}\n","import { Extension } from '@tiptap/core'\nimport Suggestion, { type SuggestionKeyDownProps,type SuggestionProps } from '@tiptap/suggestion'\nimport { PluginKey } from '@tiptap/pm/state'\nimport * as React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\n\nimport { cn } from '../../ui/lib/utils'\nimport { loadEmojiData, type ResolvedEmoji, searchEmoji } from './emoji-data'\n\n// Re-export for external consumers\nexport type { ResolvedEmoji as EmojiSuggestionItem }\n\n// Native-only since the frimousse migration.\nfunction EmojiImage({ emoji, size = '1.2em' }: { emoji: ResolvedEmoji; size?: string }) {\n return <span style={{ fontSize: size }}>{emoji.native}</span>\n}\n\ninterface EmojiListRef {\n onKeyDown: (props: SuggestionKeyDownProps) => boolean\n}\n\ninterface EmojiListProps {\n items: ResolvedEmoji[]\n command: (item: ResolvedEmoji) => void\n}\n\nconst EmojiList = React.forwardRef<EmojiListRef, EmojiListProps>(\n ({ items, command }, ref) => {\n const [selectedIndex, setSelectedIndex] = React.useState(0)\n\n React.useEffect(() => setSelectedIndex(0), [items])\n\n React.useImperativeHandle(ref, () => ({\n onKeyDown: ({ event }: SuggestionKeyDownProps) => {\n if (event.key === 'ArrowUp') {\n setSelectedIndex((i) => (i + items.length - 1) % items.length)\n return true\n }\n if (event.key === 'ArrowDown') {\n setSelectedIndex((i) => (i + 1) % items.length)\n return true\n }\n if (event.key === 'Enter') {\n if (items[selectedIndex]) command(items[selectedIndex])\n return true\n }\n return false\n },\n }))\n\n if (!items.length) return null\n\n return (\n <div role=\"listbox\" aria-label=\"Emoji suggestions\" className=\"z-popover max-h-[200px] overflow-x-hidden overflow-y-auto rounded-control bg-surface-overlay shadow-raised-hover\">\n {items.map((item, index) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"option\"\n aria-selected={index === selectedIndex}\n onClick={() => command(item)}\n className={cn(\n 'flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-body-sm',\n index === selectedIndex ? 'bg-surface-raised text-surface-fg' : 'text-surface-fg-muted hover:bg-surface-raised',\n )}\n >\n <EmojiImage emoji={item} size=\"1.25em\" />\n <span className=\"truncate\">:{item.id}:</span>\n </button>\n ))}\n </div>\n )\n },\n)\nEmojiList.displayName = 'EmojiList'\n\nfunction createEmojiSuggestionRenderer() {\n return () => {\n let root: Root | null = null\n let container: HTMLDivElement | null = null\n let componentRef: EmojiListRef | null = null\n\n return {\n onStart: (props: SuggestionProps<ResolvedEmoji>) => {\n container = document.createElement('div')\n container.style.position = 'absolute'\n container.style.zIndex = '1400'\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n document.body.appendChild(container)\n root = createRoot(container)\n root.render(\n <EmojiList\n ref={(r) => { componentRef = r }}\n items={props.items as ResolvedEmoji[]}\n command={(item) => props.command(item)}\n />,\n )\n },\n\n onUpdate: (props: SuggestionProps<ResolvedEmoji>) => {\n if (!root || !container) return\n const rect = props.clientRect?.()\n if (rect) {\n container.style.left = `${rect.left}px`\n container.style.top = `${rect.bottom + 4}px`\n }\n root.render(\n <EmojiList\n ref={(r) => { componentRef = r }}\n items={props.items as ResolvedEmoji[]}\n command={(item) => props.command(item)}\n />,\n )\n },\n\n onKeyDown: (props: SuggestionKeyDownProps) => {\n if (props.event.key === 'Escape') {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n return true\n }\n return componentRef?.onKeyDown(props) ?? false\n },\n\n onExit: () => {\n if (container) {\n root?.unmount()\n container.remove()\n container = null\n root = null\n }\n },\n }\n }\n}\n\n/** Factory: returns the configured `:shortcode:` emoji suggestion extension. */\nexport function createEmojiSuggestion() {\n return Extension.create({\n name: 'emojiSuggestion',\n\n addProseMirrorPlugins() {\n return [\n Suggestion({\n pluginKey: new PluginKey('emojiSuggestion'),\n editor: this.editor,\n char: ':',\n items: async ({ query }) => {\n const data = await loadEmojiData()\n return searchEmoji(data, query, 8)\n },\n command: ({ editor, range, props: item }) => {\n const emoji = item as ResolvedEmoji\n editor\n .chain()\n .focus()\n .deleteRange(range)\n .insertContent({\n type: 'emojiNode',\n attrs: { id: emoji.id, native: emoji.native },\n })\n .run()\n },\n render: createEmojiSuggestionRenderer(),\n }),\n ]\n },\n })\n}\n"],"mappings":"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"}
|
|
@@ -2,36 +2,37 @@
|
|
|
2
2
|
import { cn as e } from "../ui/lib/utils.js";
|
|
3
3
|
import { Icon as t } from "../ui/icon.js";
|
|
4
4
|
import { TruncatedText as n } from "../ui/truncated-text.js";
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
5
|
+
import * as r from "react";
|
|
6
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
7
|
+
import { IconDownload as o, IconFile as s } from "@tabler/icons-react";
|
|
8
|
+
import { NodeViewWrapper as c, ReactNodeViewRenderer as l } from "@tiptap/react";
|
|
9
|
+
import { Node as u, mergeAttributes as d } from "@tiptap/core";
|
|
9
10
|
import { createRoot as f } from "react-dom/client";
|
|
10
11
|
//#region src/composed/extensions/file-attachment.tsx
|
|
11
12
|
function p(e) {
|
|
12
13
|
return e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${(e / 1024).toFixed(1)} KB` : `${(e / (1024 * 1024)).toFixed(1)} MB`;
|
|
13
14
|
}
|
|
14
15
|
function m({ node: e }) {
|
|
15
|
-
return /* @__PURE__ */ c
|
|
16
|
+
return /* @__PURE__ */ i(c, {
|
|
16
17
|
className: "my-ds-02",
|
|
17
|
-
children: /* @__PURE__ */
|
|
18
|
+
children: /* @__PURE__ */ a("a", {
|
|
18
19
|
href: /^https?:\/\//.test(e.attrs.url) ? e.attrs.url : "#",
|
|
19
20
|
target: "_blank",
|
|
20
21
|
rel: "noopener noreferrer",
|
|
21
22
|
className: "inline-flex items-center gap-ds-03 rounded-control border border-surface-border-strong bg-surface-raised px-ds-04 py-ds-03 text-body-sm text-surface-fg transition-colors hover:border-surface-border-strong hover:bg-surface-raised-hover",
|
|
22
23
|
contentEditable: !1,
|
|
23
24
|
children: [
|
|
24
|
-
/* @__PURE__ */
|
|
25
|
-
icon:
|
|
25
|
+
/* @__PURE__ */ i(t, {
|
|
26
|
+
icon: s,
|
|
26
27
|
size: "sm",
|
|
27
28
|
className: "shrink-0 text-surface-fg-subtle"
|
|
28
29
|
}),
|
|
29
|
-
/* @__PURE__ */
|
|
30
|
+
/* @__PURE__ */ i(n, {
|
|
30
31
|
mode: "middle",
|
|
31
32
|
className: "min-w-0",
|
|
32
33
|
children: e.attrs.name
|
|
33
34
|
}),
|
|
34
|
-
/* @__PURE__ */
|
|
35
|
+
/* @__PURE__ */ a("span", {
|
|
35
36
|
className: "shrink-0 text-surface-fg-subtle",
|
|
36
37
|
children: [
|
|
37
38
|
"(",
|
|
@@ -39,8 +40,8 @@ function m({ node: e }) {
|
|
|
39
40
|
")"
|
|
40
41
|
]
|
|
41
42
|
}),
|
|
42
|
-
/* @__PURE__ */
|
|
43
|
-
icon:
|
|
43
|
+
/* @__PURE__ */ i(t, {
|
|
44
|
+
icon: o,
|
|
44
45
|
size: "sm",
|
|
45
46
|
className: "shrink-0 text-surface-fg-subtle"
|
|
46
47
|
})
|
|
@@ -48,7 +49,7 @@ function m({ node: e }) {
|
|
|
48
49
|
})
|
|
49
50
|
});
|
|
50
51
|
}
|
|
51
|
-
var h =
|
|
52
|
+
var h = u.create({
|
|
52
53
|
name: "fileAttachment",
|
|
53
54
|
group: "block",
|
|
54
55
|
atom: !0,
|
|
@@ -63,31 +64,31 @@ var h = r.create({
|
|
|
63
64
|
return [{ tag: "div[data-file-attachment]" }];
|
|
64
65
|
},
|
|
65
66
|
renderHTML({ HTMLAttributes: e }) {
|
|
66
|
-
return ["div",
|
|
67
|
+
return ["div", d({ "data-file-attachment": "" }, e)];
|
|
67
68
|
},
|
|
68
69
|
addNodeView() {
|
|
69
|
-
return
|
|
70
|
+
return l(m);
|
|
70
71
|
}
|
|
71
|
-
}), g =
|
|
72
|
-
let [
|
|
73
|
-
return
|
|
72
|
+
}), g = r.forwardRef(({ items: t, command: n }, o) => {
|
|
73
|
+
let [s, c] = r.useState(0);
|
|
74
|
+
return r.useEffect(() => c(0), [t]), r.useImperativeHandle(o, () => ({ onKeyDown: ({ event: e }) => e.key === "ArrowUp" ? (c((e) => (e + t.length - 1) % t.length), !0) : e.key === "ArrowDown" ? (c((e) => (e + 1) % t.length), !0) : e.key === "Enter" ? (t[s] && n(t[s]), !0) : !1 })), t.length ? /* @__PURE__ */ i("div", {
|
|
74
75
|
role: "listbox",
|
|
75
76
|
"aria-label": "Mention suggestions",
|
|
76
77
|
className: "z-popover overflow-hidden rounded-control bg-surface-overlay shadow-raised-hover",
|
|
77
|
-
children: t.map((t, r) => /* @__PURE__ */
|
|
78
|
+
children: t.map((t, r) => /* @__PURE__ */ a("button", {
|
|
78
79
|
type: "button",
|
|
79
80
|
role: "option",
|
|
80
|
-
"aria-selected": r ===
|
|
81
|
+
"aria-selected": r === s,
|
|
81
82
|
onClick: () => n(t),
|
|
82
|
-
className: e("flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-body-sm", r ===
|
|
83
|
-
children: [t.avatar ? /* @__PURE__ */
|
|
83
|
+
className: e("flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-body-sm", r === s ? "bg-surface-raised text-surface-fg" : "text-surface-fg-muted hover:bg-surface-raised"),
|
|
84
|
+
children: [t.avatar ? /* @__PURE__ */ i("img", {
|
|
84
85
|
src: t.avatar,
|
|
85
86
|
alt: "",
|
|
86
87
|
className: "h-ico-md w-ico-md rounded-pill object-cover"
|
|
87
|
-
}) : /* @__PURE__ */
|
|
88
|
+
}) : /* @__PURE__ */ i("span", {
|
|
88
89
|
className: "flex h-ico-md w-ico-md items-center justify-center rounded-pill bg-accent-2 text-[10px] font-semibold text-accent-11",
|
|
89
90
|
children: t.label.charAt(0).toUpperCase()
|
|
90
|
-
}), /* @__PURE__ */
|
|
91
|
+
}), /* @__PURE__ */ i("span", { children: t.label })]
|
|
91
92
|
}, t.id))
|
|
92
93
|
}) : null;
|
|
93
94
|
});
|
|
@@ -96,32 +97,32 @@ function _(e) {
|
|
|
96
97
|
return () => {
|
|
97
98
|
let t = null, n = null, r = null;
|
|
98
99
|
return {
|
|
99
|
-
onStart: (
|
|
100
|
+
onStart: (a) => {
|
|
100
101
|
n = document.createElement("div"), n.style.position = "absolute", n.style.zIndex = "1400";
|
|
101
|
-
let
|
|
102
|
-
|
|
102
|
+
let o = a.clientRect?.();
|
|
103
|
+
o && (n.style.left = `${o.left}px`, n.style.top = `${o.bottom + 4}px`), document.body.appendChild(n), t = f(n), t.render(/* @__PURE__ */ i(g, {
|
|
103
104
|
ref: (e) => {
|
|
104
105
|
r = e;
|
|
105
106
|
},
|
|
106
|
-
items:
|
|
107
|
+
items: a.items,
|
|
107
108
|
command: (t) => {
|
|
108
|
-
|
|
109
|
+
a.command({
|
|
109
110
|
id: t.id,
|
|
110
111
|
label: t.label
|
|
111
112
|
}), e?.(t);
|
|
112
113
|
}
|
|
113
114
|
}));
|
|
114
115
|
},
|
|
115
|
-
onUpdate: (
|
|
116
|
+
onUpdate: (a) => {
|
|
116
117
|
if (!t || !n) return;
|
|
117
|
-
let
|
|
118
|
-
|
|
118
|
+
let o = a.clientRect?.();
|
|
119
|
+
o && (n.style.left = `${o.left}px`, n.style.top = `${o.bottom + 4}px`), t.render(/* @__PURE__ */ i(g, {
|
|
119
120
|
ref: (e) => {
|
|
120
121
|
r = e;
|
|
121
122
|
},
|
|
122
|
-
items:
|
|
123
|
+
items: a.items,
|
|
123
124
|
command: (t) => {
|
|
124
|
-
|
|
125
|
+
a.command({
|
|
125
126
|
id: t.id,
|
|
126
127
|
label: t.label
|
|
127
128
|
}), e?.(t);
|