@devalok/shilp-sutra 0.39.0 → 0.40.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/AGENTS.md +151 -0
- package/MIGRATION.md +137 -0
- package/README.md +3 -0
- package/dist/_chunks/badge-group.js +75 -74
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/chart-container.js +50 -0
- package/dist/_chunks/chart-container.js.map +1 -0
- package/dist/_chunks/chat.js +231 -223
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/colors.js +30 -0
- package/dist/_chunks/colors.js.map +1 -0
- package/dist/_chunks/emoji-data.js +45 -0
- package/dist/_chunks/emoji-data.js.map +1 -0
- package/dist/_chunks/grid-lines.js +72 -0
- package/dist/_chunks/grid-lines.js.map +1 -0
- package/dist/_chunks/mention-suggestion.js +31 -259
- package/dist/_chunks/mention-suggestion.js.map +1 -1
- package/dist/_chunks/normalize-icon.js +18 -0
- package/dist/_chunks/normalize-icon.js.map +1 -0
- package/dist/_chunks/oauth-button.js +227 -0
- package/dist/_chunks/oauth-button.js.map +1 -0
- package/dist/_chunks/primitives.js +107 -107
- package/dist/_chunks/primitives.js.map +1 -1
- package/dist/_chunks/{text.js → success.js} +24 -61
- package/dist/_chunks/success.js.map +1 -0
- package/dist/_chunks/tiptap.js +1952 -1949
- package/dist/_chunks/tiptap.js.map +1 -1
- package/dist/_chunks/tooltip.js +58 -0
- package/dist/_chunks/tooltip.js.map +1 -0
- package/dist/_chunks/tree-view.js +101 -96
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/ai/ai-command-provider.d.ts +3 -2
- package/dist/ai/ai-command-provider.d.ts.map +1 -1
- package/dist/ai/ai-command-provider.js.map +1 -1
- package/dist/ai/block-renderer.js +11 -9
- package/dist/ai/block-renderer.js.map +1 -1
- package/dist/ai/blocks/error.js +31 -0
- package/dist/ai/blocks/error.js.map +1 -0
- package/dist/ai/blocks/index.d.ts +0 -2
- package/dist/ai/blocks/index.d.ts.map +1 -1
- package/dist/ai/blocks/index.js +2 -2
- package/dist/ai/blocks/text.js +19 -0
- package/dist/ai/blocks/text.js.map +1 -0
- package/dist/ai/command-bar.d.ts.map +1 -1
- package/dist/ai/command-bar.js +192 -187
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.d.ts +2 -1
- package/dist/ai/conversation.d.ts.map +1 -1
- package/dist/ai/conversation.js +88 -83
- package/dist/ai/conversation.js.map +1 -1
- package/dist/ai/index.d.ts +0 -4
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +45 -46
- package/dist/ai/index.js.map +1 -1
- package/dist/composed/activity-feed.d.ts +2 -1
- package/dist/composed/activity-feed.d.ts.map +1 -1
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/bulk-action-bar.d.ts +2 -2
- package/dist/composed/bulk-action-bar.d.ts.map +1 -1
- package/dist/composed/bulk-action-bar.js +11 -11
- package/dist/composed/bulk-action-bar.js.map +1 -1
- package/dist/composed/command-palette.d.ts +2 -1
- package/dist/composed/command-palette.d.ts.map +1 -1
- package/dist/composed/command-palette.js +103 -98
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/date-picker/index.js +747 -3
- package/dist/composed/date-picker/index.js.map +1 -0
- package/dist/composed/empty-state.d.ts +3 -3
- package/dist/composed/empty-state.d.ts.map +1 -1
- package/dist/composed/empty-state.js +40 -31
- package/dist/composed/empty-state.js.map +1 -1
- package/dist/composed/extensions/emoji-node.js +81 -0
- package/dist/composed/extensions/emoji-node.js.map +1 -0
- package/dist/composed/extensions/emoji-suggestion.js +117 -0
- package/dist/composed/extensions/emoji-suggestion.js.map +1 -0
- package/dist/composed/file-preview.js +498 -2
- package/dist/{_chunks → composed}/file-preview.js.map +1 -1
- package/dist/composed/index.d.ts +0 -15
- package/dist/composed/index.d.ts.map +1 -1
- package/dist/composed/index.js +16 -24
- package/dist/composed/rich-chat-input.js +2073 -2
- package/dist/{_chunks → composed}/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +64 -61
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/status-badge.d.ts +3 -2
- package/dist/composed/status-badge.d.ts.map +1 -1
- package/dist/composed/status-badge.js +58 -53
- package/dist/composed/status-badge.js.map +1 -1
- package/dist/shell/app-command-palette.d.ts +2 -1
- package/dist/shell/app-command-palette.d.ts.map +1 -1
- package/dist/shell/app-command-palette.js.map +1 -1
- package/dist/shell/bottom-navbar.d.ts +3 -1
- package/dist/shell/bottom-navbar.d.ts.map +1 -1
- package/dist/shell/bottom-navbar.js +90 -82
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/command-registry.d.ts +2 -1
- package/dist/shell/command-registry.d.ts.map +1 -1
- package/dist/shell/command-registry.js.map +1 -1
- package/dist/shell/sidebar.d.ts +7 -4
- package/dist/shell/sidebar.d.ts.map +1 -1
- package/dist/shell/sidebar.js +143 -129
- package/dist/shell/sidebar.js.map +1 -1
- package/dist/shell/top-bar.d.ts +4 -3
- package/dist/shell/top-bar.d.ts.map +1 -1
- package/dist/shell/top-bar.js +114 -106
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/ui/badge.d.ts +3 -2
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/button.d.ts +3 -2
- package/dist/ui/button.d.ts.map +1 -1
- package/dist/ui/button.js +54 -53
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/charts/area-chart.js +177 -0
- package/dist/ui/charts/area-chart.js.map +1 -0
- package/dist/ui/charts/bar-chart.js +127 -0
- package/dist/ui/charts/bar-chart.js.map +1 -0
- package/dist/ui/charts/chart-container.js +3 -0
- package/dist/ui/charts/gauge-chart.js +72 -0
- package/dist/ui/charts/gauge-chart.js.map +1 -0
- package/dist/ui/charts/index.js +10 -1035
- package/dist/ui/charts/line-chart.js +135 -0
- package/dist/ui/charts/line-chart.js.map +1 -0
- package/dist/ui/charts/pie-chart.js +111 -0
- package/dist/ui/charts/pie-chart.js.map +1 -0
- package/dist/ui/charts/radar-chart.js +170 -0
- package/dist/ui/charts/radar-chart.js.map +1 -0
- package/dist/ui/charts/sparkline.js +119 -0
- package/dist/ui/charts/sparkline.js.map +1 -0
- package/dist/ui/chat/message.d.ts +3 -3
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/chat/system-message.d.ts +2 -1
- package/dist/ui/chat/system-message.d.ts.map +1 -1
- package/dist/ui/combobox.d.ts +2 -1
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +97 -92
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/container.d.ts +6 -1
- package/dist/ui/container.d.ts.map +1 -1
- package/dist/ui/container.js +2 -1
- package/dist/ui/container.js.map +1 -1
- package/dist/ui/icon-button.d.ts +9 -2
- package/dist/ui/icon-button.d.ts.map +1 -1
- package/dist/ui/icon-button.js +14 -13
- package/dist/ui/icon-button.js.map +1 -1
- package/dist/ui/index.d.ts +1 -3
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +31 -33
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/lib/icon-input.d.ts +42 -0
- package/dist/ui/lib/icon-input.d.ts.map +1 -0
- package/dist/ui/lib/normalize-icon.d.ts +39 -0
- package/dist/ui/lib/normalize-icon.d.ts.map +1 -0
- package/dist/ui/oauth-button/index.d.ts +3 -0
- package/dist/ui/oauth-button/index.d.ts.map +1 -0
- package/dist/ui/oauth-button/index.js +3 -0
- package/dist/ui/oauth-button/oauth-button.d.ts +208 -0
- package/dist/ui/oauth-button/oauth-button.d.ts.map +1 -0
- package/dist/ui/progress.js +1 -1
- package/dist/ui/segmented-control.d.ts +3 -4
- package/dist/ui/segmented-control.d.ts.map +1 -1
- package/dist/ui/segmented-control.js +53 -45
- package/dist/ui/segmented-control.js.map +1 -1
- package/dist/ui/stack.d.ts +6 -1
- package/dist/ui/stack.d.ts.map +1 -1
- package/dist/ui/stack.js +2 -1
- package/dist/ui/stack.js.map +1 -1
- package/dist/ui/stat-card.d.ts +2 -3
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +117 -115
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stepper.d.ts +2 -1
- package/dist/ui/stepper.d.ts.map +1 -1
- package/dist/ui/stepper.js +74 -69
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/text.d.ts +7 -2
- package/dist/ui/text.d.ts.map +1 -1
- package/dist/ui/text.js +2 -1
- package/dist/ui/text.js.map +1 -1
- package/dist/ui/toaster.d.ts +11 -2
- package/dist/ui/toaster.d.ts.map +1 -1
- package/dist/ui/toaster.js.map +1 -1
- package/dist/ui/tooltip.js +12 -12
- package/dist/ui/tree-view/tree-item.d.ts +3 -2
- package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
- package/dist/ui/tree-view/use-tree.d.ts +2 -1
- package/dist/ui/tree-view/use-tree.d.ts.map +1 -1
- package/docs/components/ui/oauth-button.md +86 -0
- package/docs/recipes/customize-brand.md +15 -0
- package/docs/recipes/index.md +5 -1
- package/docs/recipes/install-astro.md +15 -0
- package/docs/recipes/install-next-app-router.md +21 -5
- package/docs/recipes/install-next-pages.md +2 -0
- package/docs/recipes/install-remix.md +15 -0
- package/docs/recipes/install-tanstack-start.md +15 -0
- package/docs/recipes/install-vite.md +15 -0
- package/docs/recipes/troubleshoot.md +22 -0
- package/llms-full.txt +87 -1
- package/llms-quick.txt +247 -0
- package/llms.txt +107 -2
- package/package.json +79 -2
- package/scripts/welcome.mjs +219 -0
- package/skill/SKILL.md +22 -3
- package/skill/references/components-full.md +87 -1
- package/skill/references/components.md +107 -2
- package/skill/references/customize-brand.md +15 -0
- package/skill/references/setup-astro.md +15 -0
- package/skill/references/setup-next-app-router.md +21 -5
- package/skill/references/setup-next-pages.md +2 -0
- package/skill/references/setup-remix.md +15 -0
- package/skill/references/setup-tanstack-start.md +15 -0
- package/skill/references/setup-vite.md +15 -0
- package/skill/references/troubleshoot.md +22 -0
- package/dist/_chunks/date-picker.js +0 -748
- package/dist/_chunks/date-picker.js.map +0 -1
- package/dist/_chunks/file-preview.js +0 -499
- package/dist/_chunks/rich-chat-input.js +0 -2071
- package/dist/_chunks/text.js.map +0 -1
- package/dist/ui/charts/index.js.map +0 -1
|
@@ -1,272 +1,44 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../ui/lib/utils.js";
|
|
3
3
|
import { Icon as t } from "../ui/icon.js";
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { createRoot as h } from "react-dom/client";
|
|
10
|
-
//#region src/composed/extensions/emoji-data.ts
|
|
11
|
-
var g = (e) => `https://cdn.jsdelivr.net/npm/emoji-datasource-${e}@15.0.1/img/${e}/sheets-256/64.png`, _ = null, v = null;
|
|
12
|
-
async function y(e) {
|
|
13
|
-
if (_ === e && v) return v;
|
|
14
|
-
let t = await (n[e] ?? n.native)();
|
|
15
|
-
return v = t.default ?? t, _ = e, v;
|
|
16
|
-
}
|
|
17
|
-
function b(e, t) {
|
|
18
|
-
let n = e.emojis[t];
|
|
19
|
-
if (!n) return null;
|
|
20
|
-
let r = n.skins[0];
|
|
21
|
-
return r ? {
|
|
22
|
-
id: n.id,
|
|
23
|
-
name: n.name,
|
|
24
|
-
native: r.native,
|
|
25
|
-
x: r.x ?? 0,
|
|
26
|
-
y: r.y ?? 0
|
|
27
|
-
} : null;
|
|
28
|
-
}
|
|
29
|
-
function x(e, t, n = 8) {
|
|
30
|
-
let r = Object.values(e.emojis);
|
|
31
|
-
if (!t) return r.slice(0, n).map((e) => ({
|
|
32
|
-
id: e.id,
|
|
33
|
-
name: e.name,
|
|
34
|
-
native: e.skins[0]?.native ?? "",
|
|
35
|
-
x: e.skins[0]?.x ?? 0,
|
|
36
|
-
y: e.skins[0]?.y ?? 0
|
|
37
|
-
}));
|
|
38
|
-
let i = t.toLowerCase(), a = [];
|
|
39
|
-
for (let e of r) {
|
|
40
|
-
if (a.length >= n) break;
|
|
41
|
-
(e.id.includes(i) || e.name.toLowerCase().includes(i) || e.keywords?.some((e) => e.includes(i))) && a.push({
|
|
42
|
-
id: e.id,
|
|
43
|
-
name: e.name,
|
|
44
|
-
native: e.skins[0]?.native ?? "",
|
|
45
|
-
x: e.skins[0]?.x ?? 0,
|
|
46
|
-
y: e.skins[0]?.y ?? 0
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
return a;
|
|
50
|
-
}
|
|
51
|
-
//#endregion
|
|
52
|
-
//#region src/composed/extensions/emoji-node.tsx
|
|
53
|
-
function S({ node: e }) {
|
|
54
|
-
let { native: t, set: n, x: r, y: a } = e.attrs;
|
|
55
|
-
if (n === "native") return /* @__PURE__ */ d(i, {
|
|
56
|
-
as: "span",
|
|
57
|
-
className: "inline",
|
|
58
|
-
children: /* @__PURE__ */ d("span", { children: t })
|
|
59
|
-
});
|
|
60
|
-
let o = `${100 / 60 * r}% ${100 / 60 * a}%`;
|
|
61
|
-
return /* @__PURE__ */ d(i, {
|
|
62
|
-
as: "span",
|
|
63
|
-
className: "inline",
|
|
64
|
-
children: /* @__PURE__ */ d("span", {
|
|
65
|
-
role: "img",
|
|
66
|
-
"aria-label": t,
|
|
67
|
-
className: "inline-block h-[1.2em] w-[1.2em] align-text-bottom",
|
|
68
|
-
style: {
|
|
69
|
-
backgroundImage: `url(${g(n)})`,
|
|
70
|
-
backgroundSize: "6100% 6100%",
|
|
71
|
-
backgroundPosition: o
|
|
72
|
-
}
|
|
73
|
-
})
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
var C = r.create({
|
|
77
|
-
name: "emojiNode",
|
|
78
|
-
group: "inline",
|
|
79
|
-
inline: !0,
|
|
80
|
-
atom: !0,
|
|
81
|
-
selectable: !1,
|
|
82
|
-
addAttributes() {
|
|
83
|
-
return {
|
|
84
|
-
id: { default: null },
|
|
85
|
-
native: { default: null },
|
|
86
|
-
set: { default: "native" },
|
|
87
|
-
x: { default: 0 },
|
|
88
|
-
y: { default: 0 }
|
|
89
|
-
};
|
|
90
|
-
},
|
|
91
|
-
renderText({ node: e }) {
|
|
92
|
-
return e.attrs.native ?? "";
|
|
93
|
-
},
|
|
94
|
-
parseHTML() {
|
|
95
|
-
return [{
|
|
96
|
-
tag: "span[data-emoji-id]",
|
|
97
|
-
getAttrs: (e) => {
|
|
98
|
-
let t = e;
|
|
99
|
-
return {
|
|
100
|
-
id: t.getAttribute("data-emoji-id"),
|
|
101
|
-
set: t.getAttribute("data-emoji-set") ?? "native",
|
|
102
|
-
x: parseInt(t.getAttribute("data-emoji-x") ?? "0", 10),
|
|
103
|
-
y: parseInt(t.getAttribute("data-emoji-y") ?? "0", 10),
|
|
104
|
-
native: t.textContent ?? ""
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}];
|
|
108
|
-
},
|
|
109
|
-
renderHTML({ node: e }) {
|
|
110
|
-
return [
|
|
111
|
-
"span",
|
|
112
|
-
{
|
|
113
|
-
"data-emoji-id": e.attrs.id,
|
|
114
|
-
"data-emoji-set": e.attrs.set,
|
|
115
|
-
"data-emoji-x": e.attrs.x,
|
|
116
|
-
"data-emoji-y": e.attrs.y,
|
|
117
|
-
role: "img",
|
|
118
|
-
"aria-label": e.attrs.native
|
|
119
|
-
},
|
|
120
|
-
e.attrs.native ?? ""
|
|
121
|
-
];
|
|
122
|
-
},
|
|
123
|
-
addNodeView() {
|
|
124
|
-
return o(S);
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
//#endregion
|
|
128
|
-
//#region src/composed/extensions/emoji-suggestion.tsx
|
|
129
|
-
function w({ emoji: e, set: t, size: n = "1.2em" }) {
|
|
130
|
-
return t === "native" ? /* @__PURE__ */ d("span", {
|
|
131
|
-
style: { fontSize: n },
|
|
132
|
-
children: e.native
|
|
133
|
-
}) : /* @__PURE__ */ d("span", {
|
|
134
|
-
role: "img",
|
|
135
|
-
"aria-label": e.native,
|
|
136
|
-
className: "inline-block",
|
|
137
|
-
style: {
|
|
138
|
-
width: n,
|
|
139
|
-
height: n,
|
|
140
|
-
backgroundImage: `url(${g(t)})`,
|
|
141
|
-
backgroundSize: "6100% 6100%",
|
|
142
|
-
backgroundPosition: `${100 / 60 * e.x}% ${100 / 60 * e.y}%`
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
var T = u.forwardRef(({ items: t, set: n, command: r }, i) => {
|
|
147
|
-
let [a, o] = u.useState(0);
|
|
148
|
-
return u.useEffect(() => o(0), [t]), u.useImperativeHandle(i, () => ({ onKeyDown: ({ event: e }) => e.key === "ArrowUp" ? (o((e) => (e + t.length - 1) % t.length), !0) : e.key === "ArrowDown" ? (o((e) => (e + 1) % t.length), !0) : e.key === "Enter" ? (t[a] && r(t[a]), !0) : !1 })), t.length ? /* @__PURE__ */ d("div", {
|
|
149
|
-
role: "listbox",
|
|
150
|
-
"aria-label": "Emoji suggestions",
|
|
151
|
-
className: "z-popover max-h-[200px] overflow-x-hidden overflow-y-auto rounded-control border border-surface-border-strong bg-surface-overlay shadow-raised-hover",
|
|
152
|
-
children: t.map((t, i) => /* @__PURE__ */ f("button", {
|
|
153
|
-
type: "button",
|
|
154
|
-
role: "option",
|
|
155
|
-
"aria-selected": i === a,
|
|
156
|
-
onClick: () => r(t),
|
|
157
|
-
className: e("flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-ds-sm", i === a ? "bg-surface-raised text-surface-fg" : "text-surface-fg-muted hover:bg-surface-raised"),
|
|
158
|
-
children: [/* @__PURE__ */ d(w, {
|
|
159
|
-
emoji: t,
|
|
160
|
-
set: n,
|
|
161
|
-
size: "1.25em"
|
|
162
|
-
}), /* @__PURE__ */ f("span", {
|
|
163
|
-
className: "truncate",
|
|
164
|
-
children: [
|
|
165
|
-
":",
|
|
166
|
-
t.id,
|
|
167
|
-
":"
|
|
168
|
-
]
|
|
169
|
-
})]
|
|
170
|
-
}, t.id))
|
|
171
|
-
}) : null;
|
|
172
|
-
});
|
|
173
|
-
T.displayName = "EmojiList";
|
|
174
|
-
function E(e) {
|
|
175
|
-
return () => {
|
|
176
|
-
let t = null, n = null, r = null;
|
|
177
|
-
return {
|
|
178
|
-
onStart: (i) => {
|
|
179
|
-
n = document.createElement("div"), n.style.position = "absolute", n.style.zIndex = "1400";
|
|
180
|
-
let a = i.clientRect?.();
|
|
181
|
-
a && (n.style.left = `${a.left}px`, n.style.top = `${a.bottom + 4}px`), document.body.appendChild(n), t = h(n), t.render(/* @__PURE__ */ d(T, {
|
|
182
|
-
ref: (e) => {
|
|
183
|
-
r = e;
|
|
184
|
-
},
|
|
185
|
-
items: i.items,
|
|
186
|
-
set: e,
|
|
187
|
-
command: (e) => i.command(e)
|
|
188
|
-
}));
|
|
189
|
-
},
|
|
190
|
-
onUpdate: (i) => {
|
|
191
|
-
if (!t || !n) return;
|
|
192
|
-
let a = i.clientRect?.();
|
|
193
|
-
a && (n.style.left = `${a.left}px`, n.style.top = `${a.bottom + 4}px`), t.render(/* @__PURE__ */ d(T, {
|
|
194
|
-
ref: (e) => {
|
|
195
|
-
r = e;
|
|
196
|
-
},
|
|
197
|
-
items: i.items,
|
|
198
|
-
set: e,
|
|
199
|
-
command: (e) => i.command(e)
|
|
200
|
-
}));
|
|
201
|
-
},
|
|
202
|
-
onKeyDown: (e) => e.event.key === "Escape" ? (n && (t?.unmount(), n.remove(), n = null, t = null), !0) : r?.onKeyDown(e) ?? !1,
|
|
203
|
-
onExit: () => {
|
|
204
|
-
n && (t?.unmount(), n.remove(), n = null, t = null);
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
function D(e = "native") {
|
|
210
|
-
return a.create({
|
|
211
|
-
name: "emojiSuggestion",
|
|
212
|
-
addProseMirrorPlugins() {
|
|
213
|
-
return [s({
|
|
214
|
-
pluginKey: new l("emojiSuggestion"),
|
|
215
|
-
editor: this.editor,
|
|
216
|
-
char: ":",
|
|
217
|
-
items: async ({ query: t }) => x(await y(e), t, 8),
|
|
218
|
-
command: ({ editor: t, range: n, props: r }) => {
|
|
219
|
-
let i = r;
|
|
220
|
-
t.chain().focus().deleteRange(n).insertContent({
|
|
221
|
-
type: "emojiNode",
|
|
222
|
-
attrs: {
|
|
223
|
-
id: i.id,
|
|
224
|
-
native: i.native,
|
|
225
|
-
set: e,
|
|
226
|
-
x: i.x,
|
|
227
|
-
y: i.y
|
|
228
|
-
}
|
|
229
|
-
}).run();
|
|
230
|
-
},
|
|
231
|
-
render: E(e)
|
|
232
|
-
})];
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
//#endregion
|
|
4
|
+
import { _ as n, o as r, s as i, v as a } from "./tiptap.js";
|
|
5
|
+
import * as o from "react";
|
|
6
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
7
|
+
import { IconDownload as l, IconFile as u } from "@tabler/icons-react";
|
|
8
|
+
import { createRoot as d } from "react-dom/client";
|
|
237
9
|
//#region src/composed/extensions/file-attachment.tsx
|
|
238
|
-
function
|
|
10
|
+
function f(e) {
|
|
239
11
|
return e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${(e / 1024).toFixed(1)} KB` : `${(e / (1024 * 1024)).toFixed(1)} MB`;
|
|
240
12
|
}
|
|
241
|
-
function
|
|
242
|
-
return /* @__PURE__ */
|
|
13
|
+
function p({ node: e }) {
|
|
14
|
+
return /* @__PURE__ */ s(r, {
|
|
243
15
|
className: "my-ds-02",
|
|
244
|
-
children: /* @__PURE__ */
|
|
16
|
+
children: /* @__PURE__ */ c("a", {
|
|
245
17
|
href: /^https?:\/\//.test(e.attrs.url) ? e.attrs.url : "#",
|
|
246
18
|
target: "_blank",
|
|
247
19
|
rel: "noopener noreferrer",
|
|
248
20
|
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-ds-sm text-surface-fg transition-colors hover:border-surface-border-strong hover:bg-surface-raised-hover",
|
|
249
21
|
contentEditable: !1,
|
|
250
22
|
children: [
|
|
251
|
-
/* @__PURE__ */
|
|
252
|
-
icon:
|
|
23
|
+
/* @__PURE__ */ s(t, {
|
|
24
|
+
icon: u,
|
|
253
25
|
size: "sm",
|
|
254
26
|
className: "shrink-0 text-surface-fg-subtle"
|
|
255
27
|
}),
|
|
256
|
-
/* @__PURE__ */
|
|
28
|
+
/* @__PURE__ */ s("span", {
|
|
257
29
|
className: "truncate",
|
|
258
30
|
children: e.attrs.name
|
|
259
31
|
}),
|
|
260
|
-
/* @__PURE__ */
|
|
32
|
+
/* @__PURE__ */ c("span", {
|
|
261
33
|
className: "shrink-0 text-surface-fg-subtle",
|
|
262
34
|
children: [
|
|
263
35
|
"(",
|
|
264
|
-
|
|
36
|
+
f(e.attrs.size),
|
|
265
37
|
")"
|
|
266
38
|
]
|
|
267
39
|
}),
|
|
268
|
-
/* @__PURE__ */
|
|
269
|
-
icon:
|
|
40
|
+
/* @__PURE__ */ s(t, {
|
|
41
|
+
icon: l,
|
|
270
42
|
size: "sm",
|
|
271
43
|
className: "shrink-0 text-surface-fg-subtle"
|
|
272
44
|
})
|
|
@@ -274,7 +46,7 @@ function k({ node: e }) {
|
|
|
274
46
|
})
|
|
275
47
|
});
|
|
276
48
|
}
|
|
277
|
-
var
|
|
49
|
+
var m = n.create({
|
|
278
50
|
name: "fileAttachment",
|
|
279
51
|
group: "block",
|
|
280
52
|
atom: !0,
|
|
@@ -289,43 +61,43 @@ var A = r.create({
|
|
|
289
61
|
return [{ tag: "div[data-file-attachment]" }];
|
|
290
62
|
},
|
|
291
63
|
renderHTML({ HTMLAttributes: e }) {
|
|
292
|
-
return ["div",
|
|
64
|
+
return ["div", a({ "data-file-attachment": "" }, e)];
|
|
293
65
|
},
|
|
294
66
|
addNodeView() {
|
|
295
|
-
return
|
|
67
|
+
return i(p);
|
|
296
68
|
}
|
|
297
|
-
}),
|
|
298
|
-
let [i, a] =
|
|
299
|
-
return
|
|
69
|
+
}), h = o.forwardRef(({ items: t, command: n }, r) => {
|
|
70
|
+
let [i, a] = o.useState(0);
|
|
71
|
+
return o.useEffect(() => a(0), [t]), o.useImperativeHandle(r, () => ({ onKeyDown: ({ event: e }) => e.key === "ArrowUp" ? (a((e) => (e + t.length - 1) % t.length), !0) : e.key === "ArrowDown" ? (a((e) => (e + 1) % t.length), !0) : e.key === "Enter" ? (t[i] && n(t[i]), !0) : !1 })), t.length ? /* @__PURE__ */ s("div", {
|
|
300
72
|
role: "listbox",
|
|
301
73
|
"aria-label": "Mention suggestions",
|
|
302
74
|
className: "z-popover overflow-hidden rounded-control border border-surface-border-strong bg-surface-overlay shadow-raised-hover",
|
|
303
|
-
children: t.map((t, r) => /* @__PURE__ */
|
|
75
|
+
children: t.map((t, r) => /* @__PURE__ */ c("button", {
|
|
304
76
|
type: "button",
|
|
305
77
|
role: "option",
|
|
306
78
|
"aria-selected": r === i,
|
|
307
79
|
onClick: () => n(t),
|
|
308
80
|
className: e("flex w-full items-center gap-ds-03 px-ds-04 py-ds-02b text-left text-ds-sm", r === i ? "bg-surface-raised text-surface-fg" : "text-surface-fg-muted hover:bg-surface-raised"),
|
|
309
|
-
children: [t.avatar ? /* @__PURE__ */
|
|
81
|
+
children: [t.avatar ? /* @__PURE__ */ s("img", {
|
|
310
82
|
src: t.avatar,
|
|
311
83
|
alt: "",
|
|
312
84
|
className: "h-ico-md w-ico-md rounded-pill object-cover"
|
|
313
|
-
}) : /* @__PURE__ */
|
|
85
|
+
}) : /* @__PURE__ */ s("span", {
|
|
314
86
|
className: "flex h-ico-md w-ico-md items-center justify-center rounded-pill bg-accent-2 text-[10px] font-semibold text-accent-11",
|
|
315
87
|
children: t.label.charAt(0).toUpperCase()
|
|
316
|
-
}), /* @__PURE__ */
|
|
88
|
+
}), /* @__PURE__ */ s("span", { children: t.label })]
|
|
317
89
|
}, t.id))
|
|
318
90
|
}) : null;
|
|
319
91
|
});
|
|
320
|
-
|
|
321
|
-
function
|
|
92
|
+
h.displayName = "MentionList";
|
|
93
|
+
function g(e) {
|
|
322
94
|
return () => {
|
|
323
95
|
let t = null, n = null, r = null;
|
|
324
96
|
return {
|
|
325
97
|
onStart: (i) => {
|
|
326
98
|
n = document.createElement("div"), n.style.position = "absolute", n.style.zIndex = "1400";
|
|
327
99
|
let a = i.clientRect?.();
|
|
328
|
-
a && (n.style.left = `${a.left}px`, n.style.top = `${a.bottom + 4}px`), document.body.appendChild(n), t =
|
|
100
|
+
a && (n.style.left = `${a.left}px`, n.style.top = `${a.bottom + 4}px`), document.body.appendChild(n), t = d(n), t.render(/* @__PURE__ */ s(h, {
|
|
329
101
|
ref: (e) => {
|
|
330
102
|
r = e;
|
|
331
103
|
},
|
|
@@ -341,7 +113,7 @@ function M(e) {
|
|
|
341
113
|
onUpdate: (i) => {
|
|
342
114
|
if (!t || !n) return;
|
|
343
115
|
let a = i.clientRect?.();
|
|
344
|
-
a && (n.style.left = `${a.left}px`, n.style.top = `${a.bottom + 4}px`), t.render(/* @__PURE__ */
|
|
116
|
+
a && (n.style.left = `${a.left}px`, n.style.top = `${a.bottom + 4}px`), t.render(/* @__PURE__ */ s(h, {
|
|
345
117
|
ref: (e) => {
|
|
346
118
|
r = e;
|
|
347
119
|
},
|
|
@@ -362,4 +134,4 @@ function M(e) {
|
|
|
362
134
|
};
|
|
363
135
|
}
|
|
364
136
|
//#endregion
|
|
365
|
-
export {
|
|
137
|
+
export { m as n, g as t };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mention-suggestion.js","names":[],"sources":["../../src/composed/extensions/emoji-data.ts","../../src/composed/extensions/emoji-node.tsx","../../src/composed/extensions/emoji-suggestion.tsx","../../src/composed/extensions/file-attachment.tsx","../../src/composed/extensions/mention-suggestion.tsx"],"sourcesContent":["import { emojiDataLoaders } from '../emoji-picker'\n\n// Spritesheet constants — must match emoji-mart's rendering (emoji-datasource v15.0.1)\nexport const SPRITESHEET_URL = (set: string) =>\n `https://cdn.jsdelivr.net/npm/emoji-datasource-${set}@15.0.1/img/${set}/sheets-256/64.png`\nexport const SHEET_COLS = 61\nexport const SHEET_ROWS = 61\n\ninterface EmojiSkin {\n unified: string\n native: string\n x?: number\n y?: number\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 sheet?: { cols: number; rows: number }\n}\n\nexport interface ResolvedEmoji {\n id: string\n name: string\n native: string\n x: number\n y: number\n}\n\nlet cachedSet: string | null = null\nlet cachedData: EmojiDataset | null = null\n\nexport async function loadEmojiData(set: string): Promise<EmojiDataset> {\n if (cachedSet === set && cachedData) return cachedData\n const loader = emojiDataLoaders[set] ?? emojiDataLoaders.native\n const mod = await loader()\n cachedData = (mod.default ?? mod) as EmojiDataset\n cachedSet = set\n return cachedData\n}\n\nexport function lookupEmoji(data: EmojiDataset, id: string): ResolvedEmoji | null {\n const entry = data.emojis[id]\n if (!entry) return null\n const skin = entry.skins[0]\n if (!skin) return null\n return {\n id: entry.id,\n name: entry.name,\n native: skin.native,\n x: skin.x ?? 0,\n y: skin.y ?? 0,\n }\n}\n\nexport function searchEmoji(data: EmojiDataset, query: string, limit = 8): ResolvedEmoji[] {\n const entries = Object.values(data.emojis)\n if (!query) {\n return entries.slice(0, limit).map((e) => ({\n id: e.id,\n name: e.name,\n native: e.skins[0]?.native ?? '',\n x: e.skins[0]?.x ?? 0,\n y: e.skins[0]?.y ?? 0,\n }))\n }\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({\n id: e.id,\n name: e.name,\n native: e.skins[0]?.native ?? '',\n x: e.skins[0]?.x ?? 0,\n y: e.skins[0]?.y ?? 0,\n })\n }\n }\n return results\n}\n","import { Node } from '@tiptap/core'\nimport { type NodeViewProps,NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react'\n\nimport { SHEET_COLS, SHEET_ROWS,SPRITESHEET_URL } from './emoji-data'\n\nexport interface EmojiNodeAttrs {\n id: string\n native: string\n set: string\n x: number\n y: number\n}\n\nfunction EmojiNodeView({ node }: NodeViewProps) {\n const { native, set, x, y } = node.attrs as EmojiNodeAttrs\n\n if (set === 'native') {\n return (\n <NodeViewWrapper as=\"span\" className=\"inline\">\n <span>{native}</span>\n </NodeViewWrapper>\n )\n }\n\n const bgSize = `${100 * SHEET_COLS}% ${100 * SHEET_ROWS}%`\n const bgPos = `${(100 / (SHEET_COLS - 1)) * x}% ${(100 / (SHEET_ROWS - 1)) * y}%`\n\n return (\n <NodeViewWrapper as=\"span\" className=\"inline\">\n <span\n role=\"img\"\n aria-label={native}\n className=\"inline-block h-[1.2em] w-[1.2em] align-text-bottom\"\n style={{\n backgroundImage: `url(${SPRITESHEET_URL(set)})`,\n backgroundSize: bgSize,\n backgroundPosition: bgPos,\n }}\n />\n </NodeViewWrapper>\n )\n}\n\nexport const EmojiNode = Node.create({\n name: 'emojiNode',\n group: 'inline',\n inline: true,\n atom: true,\n selectable: false,\n\n addAttributes() {\n return {\n id: { default: null },\n native: { default: null },\n set: { default: 'native' },\n x: { default: 0 },\n y: { default: 0 },\n }\n },\n\n renderText({ node }) {\n return node.attrs.native ?? ''\n },\n\n parseHTML() {\n return [{\n tag: 'span[data-emoji-id]',\n getAttrs: (el) => {\n const dom = el as HTMLElement\n return {\n id: dom.getAttribute('data-emoji-id'),\n set: dom.getAttribute('data-emoji-set') ?? 'native',\n x: parseInt(dom.getAttribute('data-emoji-x') ?? '0', 10),\n y: parseInt(dom.getAttribute('data-emoji-y') ?? '0', 10),\n native: dom.textContent ?? '',\n }\n },\n }]\n },\n\n renderHTML({ node }) {\n return ['span', {\n 'data-emoji-id': node.attrs.id,\n 'data-emoji-set': node.attrs.set,\n 'data-emoji-x': node.attrs.x,\n 'data-emoji-y': node.attrs.y,\n 'role': 'img',\n 'aria-label': node.attrs.native,\n }, node.attrs.native ?? '']\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(EmojiNodeView)\n },\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, SHEET_COLS, SHEET_ROWS,SPRITESHEET_URL } from './emoji-data'\n\n// Re-export for external consumers\nexport type { ResolvedEmoji as EmojiSuggestionItem }\n\nfunction EmojiImage({ emoji, set, size = '1.2em' }: { emoji: ResolvedEmoji; set: string; size?: string }) {\n if (set === 'native') {\n return <span style={{ fontSize: size }}>{emoji.native}</span>\n }\n return (\n <span\n role=\"img\"\n aria-label={emoji.native}\n className=\"inline-block\"\n style={{\n width: size,\n height: size,\n backgroundImage: `url(${SPRITESHEET_URL(set)})`,\n backgroundSize: `${100 * SHEET_COLS}% ${100 * SHEET_ROWS}%`,\n backgroundPosition: `${(100 / (SHEET_COLS - 1)) * emoji.x}% ${(100 / (SHEET_ROWS - 1)) * emoji.y}%`,\n }}\n />\n )\n}\n\ninterface EmojiListRef {\n onKeyDown: (props: SuggestionKeyDownProps) => boolean\n}\n\ninterface EmojiListProps {\n items: ResolvedEmoji[]\n set: string\n command: (item: ResolvedEmoji) => void\n}\n\nconst EmojiList = React.forwardRef<EmojiListRef, EmojiListProps>(\n ({ items, set, 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 border border-surface-border-strong 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-ds-sm',\n index === selectedIndex ? 'bg-surface-raised text-surface-fg' : 'text-surface-fg-muted hover:bg-surface-raised',\n )}\n >\n <EmojiImage emoji={item} set={set} size=\"1.25em\" />\n <span className=\"truncate\">:{item.id}:</span>\n </button>\n ))}\n </div>\n )\n },\n)\nEmojiList.displayName = 'EmojiList'\n\nfunction createEmojiSuggestionRenderer(set: string) {\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 set={set}\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 set={set}\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: call with the emoji set to get a configured extension. */\nexport function createEmojiSuggestion(set = 'native') {\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(set)\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, set, x: emoji.x, y: emoji.y },\n })\n .run()\n },\n render: createEmojiSuggestionRenderer(set),\n }),\n ]\n },\n })\n}\n","import { IconDownload,IconFile } from '@tabler/icons-react'\nimport { mergeAttributes,Node } from '@tiptap/core'\nimport { type NodeViewProps,NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react'\n\nimport { Icon } from '../../ui/icon'\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nfunction FileAttachmentView({ node }: NodeViewProps) {\n const safeUrl = /^https?:\\/\\//.test(node.attrs.url) ? node.attrs.url : '#'\n return (\n <NodeViewWrapper className=\"my-ds-02\">\n <a\n href={safeUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n 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-ds-sm text-surface-fg transition-colors hover:border-surface-border-strong hover:bg-surface-raised-hover\"\n contentEditable={false}\n >\n <Icon icon={IconFile} size=\"sm\" className=\"shrink-0 text-surface-fg-subtle\" />\n <span className=\"truncate\">{node.attrs.name}</span>\n <span className=\"shrink-0 text-surface-fg-subtle\">({formatFileSize(node.attrs.size)})</span>\n <Icon icon={IconDownload} size=\"sm\" className=\"shrink-0 text-surface-fg-subtle\" />\n </a>\n </NodeViewWrapper>\n )\n}\n\nexport const FileAttachment = Node.create({\n name: 'fileAttachment',\n group: 'block',\n atom: true,\n\n addAttributes() {\n return {\n url: { default: null },\n name: { default: 'Untitled' },\n size: { default: 0 },\n }\n },\n\n parseHTML() {\n return [{ tag: 'div[data-file-attachment]' }]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['div', mergeAttributes({ 'data-file-attachment': '' }, HTMLAttributes)]\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(FileAttachmentView)\n },\n})\n","import type { SuggestionKeyDownProps,SuggestionProps } from '@tiptap/suggestion'\nimport * as React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\n\nimport { cn } from '../../ui/lib/utils'\nimport type { MentionItem } from '../rich-text-editor'\n\ninterface MentionListRef {\n onKeyDown: (props: SuggestionKeyDownProps) => boolean\n}\n\ninterface MentionListProps {\n items: MentionItem[]\n command: (item: MentionItem) => void\n}\n\nconst MentionList = React.forwardRef<MentionListRef, MentionListProps>(\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=\"Mention suggestions\" className=\"z-popover overflow-hidden rounded-control border border-surface-border-strong 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-ds-sm',\n index === selectedIndex ? 'bg-surface-raised text-surface-fg' : 'text-surface-fg-muted hover:bg-surface-raised',\n )}\n >\n {item.avatar ? (\n <img src={item.avatar} alt=\"\" className=\"h-ico-md w-ico-md rounded-pill object-cover\" />\n ) : (\n <span className=\"flex h-ico-md w-ico-md items-center justify-center rounded-pill bg-accent-2 text-[10px] font-semibold text-accent-11\">\n {item.label.charAt(0).toUpperCase()}\n </span>\n )}\n <span>{item.label}</span>\n </button>\n ))}\n </div>\n )\n },\n)\nMentionList.displayName = 'MentionList'\n\nexport function createSuggestionRenderer(onMentionSelect?: (item: MentionItem) => void) {\n return () => {\n let root: Root | null = null\n let container: HTMLDivElement | null = null\n let componentRef: MentionListRef | null = null\n\n return {\n onStart: (props: SuggestionProps<MentionItem>) => {\n container = document.createElement('div')\n container.style.position = 'absolute'\n container.style.zIndex = '1400' // z-popover\n\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\n root = createRoot(container)\n root.render(\n <MentionList\n ref={(r) => { componentRef = r }}\n items={props.items as MentionItem[]}\n command={(item) => {\n props.command({ id: item.id, label: item.label })\n onMentionSelect?.(item)\n }}\n />,\n )\n },\n\n onUpdate: (props: SuggestionProps<MentionItem>) => {\n if (!root || !container) return\n\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\n root.render(\n <MentionList\n ref={(r) => { componentRef = r }}\n items={props.items as MentionItem[]}\n command={(item) => {\n props.command({ id: item.id, label: item.label })\n onMentionSelect?.(item)\n }}\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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mention-suggestion.js","names":[],"sources":["../../src/composed/extensions/file-attachment.tsx","../../src/composed/extensions/mention-suggestion.tsx"],"sourcesContent":["import { IconDownload,IconFile } from '@tabler/icons-react'\nimport { mergeAttributes,Node } from '@tiptap/core'\nimport { type NodeViewProps,NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react'\n\nimport { Icon } from '../../ui/icon'\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nfunction FileAttachmentView({ node }: NodeViewProps) {\n const safeUrl = /^https?:\\/\\//.test(node.attrs.url) ? node.attrs.url : '#'\n return (\n <NodeViewWrapper className=\"my-ds-02\">\n <a\n href={safeUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n 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-ds-sm text-surface-fg transition-colors hover:border-surface-border-strong hover:bg-surface-raised-hover\"\n contentEditable={false}\n >\n <Icon icon={IconFile} size=\"sm\" className=\"shrink-0 text-surface-fg-subtle\" />\n <span className=\"truncate\">{node.attrs.name}</span>\n <span className=\"shrink-0 text-surface-fg-subtle\">({formatFileSize(node.attrs.size)})</span>\n <Icon icon={IconDownload} size=\"sm\" className=\"shrink-0 text-surface-fg-subtle\" />\n </a>\n </NodeViewWrapper>\n )\n}\n\nexport const FileAttachment = Node.create({\n name: 'fileAttachment',\n group: 'block',\n atom: true,\n\n addAttributes() {\n return {\n url: { default: null },\n name: { default: 'Untitled' },\n size: { default: 0 },\n }\n },\n\n parseHTML() {\n return [{ tag: 'div[data-file-attachment]' }]\n },\n\n renderHTML({ HTMLAttributes }) {\n return ['div', mergeAttributes({ 'data-file-attachment': '' }, HTMLAttributes)]\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(FileAttachmentView)\n },\n})\n","import type { SuggestionKeyDownProps,SuggestionProps } from '@tiptap/suggestion'\nimport * as React from 'react'\nimport { createRoot, type Root } from 'react-dom/client'\n\nimport { cn } from '../../ui/lib/utils'\nimport type { MentionItem } from '../rich-text-editor'\n\ninterface MentionListRef {\n onKeyDown: (props: SuggestionKeyDownProps) => boolean\n}\n\ninterface MentionListProps {\n items: MentionItem[]\n command: (item: MentionItem) => void\n}\n\nconst MentionList = React.forwardRef<MentionListRef, MentionListProps>(\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=\"Mention suggestions\" className=\"z-popover overflow-hidden rounded-control border border-surface-border-strong 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-ds-sm',\n index === selectedIndex ? 'bg-surface-raised text-surface-fg' : 'text-surface-fg-muted hover:bg-surface-raised',\n )}\n >\n {item.avatar ? (\n <img src={item.avatar} alt=\"\" className=\"h-ico-md w-ico-md rounded-pill object-cover\" />\n ) : (\n <span className=\"flex h-ico-md w-ico-md items-center justify-center rounded-pill bg-accent-2 text-[10px] font-semibold text-accent-11\">\n {item.label.charAt(0).toUpperCase()}\n </span>\n )}\n <span>{item.label}</span>\n </button>\n ))}\n </div>\n )\n },\n)\nMentionList.displayName = 'MentionList'\n\nexport function createSuggestionRenderer(onMentionSelect?: (item: MentionItem) => void) {\n return () => {\n let root: Root | null = null\n let container: HTMLDivElement | null = null\n let componentRef: MentionListRef | null = null\n\n return {\n onStart: (props: SuggestionProps<MentionItem>) => {\n container = document.createElement('div')\n container.style.position = 'absolute'\n container.style.zIndex = '1400' // z-popover\n\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\n root = createRoot(container)\n root.render(\n <MentionList\n ref={(r) => { componentRef = r }}\n items={props.items as MentionItem[]}\n command={(item) => {\n props.command({ id: item.id, label: item.label })\n onMentionSelect?.(item)\n }}\n />,\n )\n },\n\n onUpdate: (props: SuggestionProps<MentionItem>) => {\n if (!root || !container) return\n\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\n root.render(\n <MentionList\n ref={(r) => { componentRef = r }}\n items={props.items as MentionItem[]}\n command={(item) => {\n props.command({ id: item.id, label: item.label })\n onMentionSelect?.(item)\n }}\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"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Icon as e } from "../ui/icon.js";
|
|
3
|
+
import * as t from "react";
|
|
4
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
5
|
+
//#region src/ui/lib/normalize-icon.tsx
|
|
6
|
+
function r(r, a) {
|
|
7
|
+
return r == null ? null : t.isValidElement(r) ? r : i(r) ? /* @__PURE__ */ n(e, {
|
|
8
|
+
icon: r,
|
|
9
|
+
size: a
|
|
10
|
+
}) : typeof r == "function" ? /* @__PURE__ */ n(r, {}) : null;
|
|
11
|
+
}
|
|
12
|
+
function i(e) {
|
|
13
|
+
if (typeof e != "object" || !e) return !1;
|
|
14
|
+
let t = e;
|
|
15
|
+
return typeof t.$$typeof == "symbol" && typeof t.render == "function";
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { r as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize-icon.js","names":[],"sources":["../../src/ui/lib/normalize-icon.tsx"],"sourcesContent":["// @server-safe\nimport * as React from 'react'\n\nimport { Icon } from '../icon'\nimport type { IconSize } from '../icon-context'\nimport type { IconInput } from './icon-input'\n\n/**\n * Normalize any IconInput shape into a renderable React node.\n *\n * - Component refs (`IconPlus`) → wrap in `<Icon icon={IconPlus} />` (context-aware).\n * - Already-instantiated elements (`<IconPlus />`, `<Icon …/>`, `<span>$</span>`) →\n * passed through. If inside an `<IconProvider>`, any nested `<Icon>` element\n * picks up the size + stroke from context automatically.\n * - `null` / `undefined` → returns `null`.\n *\n * Components calling this should also wrap their icon slot in\n * `<IconProvider size={defaultSize}>` so the size context propagates to\n * nested `<Icon>` elements. Example:\n *\n * ```tsx\n * import { IconProvider } from './icon-context'\n * import { normalizeIcon } from './lib/normalize-icon'\n *\n * function MyComponent({ icon, size = 'md' }: { icon?: IconInput; size?: 'sm' | 'md' | 'lg' }) {\n * return (\n * <div>\n * <IconProvider size={iconSizeMap[size]}>\n * {normalizeIcon(icon)}\n * </IconProvider>\n * </div>\n * )\n * }\n * ```\n *\n * @param input Anything matching `IconInput`.\n * @param fallbackSize Optional explicit size to apply if the input is a\n * raw component ref AND no IconProvider context is set. In practice you\n * should use IconProvider for size control; this fallback is for unusual\n * cases where the consumer can't be wrapped (e.g. portal-rendered icons).\n */\nexport function normalizeIcon(\n input: IconInput,\n fallbackSize?: IconSize,\n): React.ReactNode {\n if (input == null) return null\n\n // Already an instantiated React element — pass through. If it's our\n // `<Icon>`, the IconProvider above will populate any unset size/stroke.\n // If it's a raw Tabler element (`<IconPlus />`) or any custom node, it\n // renders as-is.\n if (React.isValidElement(input)) return input\n\n // ForwardRef component (Tabler icons + anything built with React.forwardRef).\n // Wrap in <Icon /> so it participates in IconContext (size + stroke flow\n // from any surrounding IconProvider).\n if (isForwardRefComponent(input)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return <Icon icon={input as any} size={fallbackSize} />\n }\n\n // Plain function/class component — render directly. The component is\n // responsible for its own sizing; we don't force <Icon> wrapping because\n // <Icon>'s type expects a ForwardRef shape and passing arbitrary props\n // would generate React warnings.\n if (typeof input === 'function') {\n const Component = input as React.ComponentType<{\n className?: string\n size?: number | string\n }>\n return <Component />\n }\n\n return null\n}\n\n/**\n * True only for `React.forwardRef`-shaped components (Tabler icons fit\n * this). React tags forwardRef objects with `$$typeof` (a symbol) and a\n * `render` function.\n */\nfunction isForwardRefComponent(value: unknown): boolean {\n if (value == null) return false\n if (typeof value !== 'object') return false\n const v = value as { $$typeof?: symbol; render?: unknown }\n return typeof v.$$typeof === 'symbol' && typeof v.render === 'function'\n}\n"],"mappings":";;;;AAyCA,SAAgB,EACd,GACA,GACiB;AA6BjB,QA5BI,KAAS,OAAa,OAMtB,EAAM,eAAe,EAAM,GAAS,IAKpC,EAAsB,EAAM,GAEvB,kBAAC,GAAD;EAAM,MAAM;EAAc,MAAM;EAAgB,CAAA,GAOrD,OAAO,KAAU,aAKZ,kBAJW,GAIX,EAAa,CAAA,GAGf;;AAQT,SAAS,EAAsB,GAAyB;AAEtD,KAAI,OAAO,KAAU,aADjB,EAC2B,QAAO;CACtC,IAAM,IAAI;AACV,QAAO,OAAO,EAAE,YAAa,YAAY,OAAO,EAAE,UAAW"}
|