@nivaro/react 0.3.23 → 0.3.25
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/dist/hooks/useSessionRecorder.js +1 -1
- package/dist/index.d.ts +50 -26
- package/dist/shared/components/FilePreviewLightbox.js +56 -35
- package/dist/shared/components/ItemEditForm.js +4309 -4263
- package/dist/shared/components/PageRenderer.js +63 -62
- package/dist/shared/components/ProfileView.js +555 -520
- package/dist/shared/components/RecordReadView.js +229 -229
- package/dist/shared/components/ReportView.js +123 -120
- package/dist/shared/components/ai/AiMarkdown.js +168 -148
- package/dist/shared/components/chat/RoomParts.js +120 -119
- package/dist/shared/components/chat/chat-core.js +228 -224
- package/dist/shared/components/item-edit/FieldRenderer.js +333 -333
- package/dist/shared/components/item-edit/FieldRow.js +413 -394
- package/dist/shared/components/item-edit/GroupSection.js +637 -635
- package/dist/shared/components/item-edit/InlineGridField.js +89 -90
- package/dist/shared/components/item-edit/QuickPicker.js +9 -9
- package/dist/shared/components/item-edit/RawEditSheet.js +80 -79
- package/dist/shared/components/item-edit/RowMatchPanel.js +1 -1
- package/dist/shared/components/item-edit/m2m-invalidate.js +19 -0
- package/dist/shared/components/item-edit/record-lookups.js +15 -0
- package/dist/shared/components/item-edit/render-stability.js +147 -0
- package/dist/shared/components/layout-editor/FormMapButton.js +5 -4
- package/dist/shared/components/notifications/DeliveryChips.js +27 -17
- package/dist/shared/components/profile/TeamsConnect.js +71 -0
- package/dist/shared/components/profile/primitives.js +4 -4
- package/dist/shared/lib/safe-href.js +10 -0
- package/dist/shared/lib/socket-realtime.js +107 -78
- package/package.json +6 -6
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { jsxs as t, Fragment as m, jsx as e } from "react/jsx-runtime";
|
|
2
|
+
import { useQueryClient as l, useMutation as c } from "@tanstack/react-query";
|
|
3
|
+
import { useState as u } from "react";
|
|
4
|
+
import { useNivaroClient as f } from "../../context.js";
|
|
5
|
+
import { del as x } from "../../lib/commands.js";
|
|
6
|
+
import { Popover as p, PopoverTrigger as g, PopoverContent as h } from "../ui/popover.js";
|
|
7
|
+
import { ConfirmButton as k } from "./primitives.js";
|
|
8
|
+
function P({ linked: a, linkedAt: r }) {
|
|
9
|
+
const i = f(), d = l(), [s, n] = u(!1), o = c({
|
|
10
|
+
mutationFn: () => (n(!1), i.request(x("/teams/link"))),
|
|
11
|
+
onError: () => n(!0),
|
|
12
|
+
onSettled: () => {
|
|
13
|
+
d.invalidateQueries({ queryKey: ["nvr-profile-teams"] });
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
return a ? /* @__PURE__ */ t(m, { children: [
|
|
17
|
+
/* @__PURE__ */ t(
|
|
18
|
+
"span",
|
|
19
|
+
{
|
|
20
|
+
className: "inline-flex flex-wrap items-center justify-center gap-1 text-[10.5px] font-normal normal-case tracking-normal text-emerald-700 dark:text-emerald-400",
|
|
21
|
+
"data-teams-connected": "",
|
|
22
|
+
title: r ? `Connected ${new Date(r).toLocaleString()}` : void 0,
|
|
23
|
+
children: [
|
|
24
|
+
"Connected ·",
|
|
25
|
+
" ",
|
|
26
|
+
/* @__PURE__ */ e(
|
|
27
|
+
k,
|
|
28
|
+
{
|
|
29
|
+
onConfirm: () => o.mutate(),
|
|
30
|
+
confirmLabel: "Disconnect Teams?",
|
|
31
|
+
disabled: o.isPending,
|
|
32
|
+
className: "font-medium text-slate-500 underline decoration-dotted underline-offset-2 hover:text-slate-800 dark:text-muted-foreground dark:hover:text-foreground",
|
|
33
|
+
armedClassName: "font-medium text-red-600 dark:text-red-400",
|
|
34
|
+
children: "Disconnect"
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
),
|
|
40
|
+
s && /* @__PURE__ */ e(
|
|
41
|
+
"p",
|
|
42
|
+
{
|
|
43
|
+
role: "alert",
|
|
44
|
+
"data-teams-disconnect-error": "",
|
|
45
|
+
className: "mt-0.5 text-[10.5px] font-normal normal-case tracking-normal text-red-600 dark:text-red-400",
|
|
46
|
+
children: "Could not disconnect Teams. Try again; if it keeps failing, ask an admin."
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
] }) : /* @__PURE__ */ t(p, { children: [
|
|
50
|
+
/* @__PURE__ */ e(g, { asChild: !0, children: /* @__PURE__ */ e(
|
|
51
|
+
"button",
|
|
52
|
+
{
|
|
53
|
+
type: "button",
|
|
54
|
+
"data-teams-connect": "",
|
|
55
|
+
className: "rounded border border-slate-200 px-1.5 py-0.5 text-[10.5px] font-medium normal-case tracking-normal text-slate-600 hover:border-slate-400 hover:text-slate-800 dark:border-border dark:text-muted-foreground dark:hover:text-foreground",
|
|
56
|
+
children: "Connect Teams"
|
|
57
|
+
}
|
|
58
|
+
) }),
|
|
59
|
+
/* @__PURE__ */ e(
|
|
60
|
+
h,
|
|
61
|
+
{
|
|
62
|
+
align: "end",
|
|
63
|
+
className: "w-64 text-[12px] font-normal normal-case tracking-normal text-slate-600 dark:text-muted-foreground",
|
|
64
|
+
children: "Open Nivaro in Teams and say hi, or sign in with Microsoft once, then turn categories on."
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
] });
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
P as TeamsConnect
|
|
71
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs as c, jsx as a, Fragment as x } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useState as f, useEffect as p, Children as g } from "react";
|
|
3
3
|
import { useNavigation as b } from "../../context.js";
|
|
4
4
|
import { cn as o } from "../../lib/utils.js";
|
|
5
5
|
import { UserAvatar as k } from "../UserAvatar.js";
|
|
@@ -121,8 +121,8 @@ function P({
|
|
|
121
121
|
title: l,
|
|
122
122
|
disabled: s
|
|
123
123
|
}) {
|
|
124
|
-
const [i, m] =
|
|
125
|
-
return
|
|
124
|
+
const [i, m] = f(!1);
|
|
125
|
+
return p(() => {
|
|
126
126
|
if (!i) return;
|
|
127
127
|
const u = window.setTimeout(() => m(!1), 3e3);
|
|
128
128
|
return () => window.clearTimeout(u);
|
|
@@ -148,7 +148,7 @@ function T({ label: e, children: t }) {
|
|
|
148
148
|
] });
|
|
149
149
|
}
|
|
150
150
|
function B({ children: e, cols: t = 3 }) {
|
|
151
|
-
const r =
|
|
151
|
+
const r = g.toArray(e).filter(Boolean).length, n = t === 3 ? 6 : t, d = (n - r % n) % n;
|
|
152
152
|
return /* @__PURE__ */ c(
|
|
153
153
|
"div",
|
|
154
154
|
{
|
|
@@ -1,11 +1,32 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { bindClientChaosSocket as
|
|
5
|
-
import { deliveryAckFor as
|
|
6
|
-
import { forgetSettledReads as
|
|
7
|
-
import { createRoomGapTracker as
|
|
8
|
-
const
|
|
1
|
+
var y = Object.defineProperty;
|
|
2
|
+
var I = (i, n, r) => n in i ? y(i, n, { enumerable: !0, configurable: !0, writable: !0, value: r }) : i[n] = r;
|
|
3
|
+
var N = (i, n, r) => I(i, typeof n != "symbol" ? n + "" : n, r);
|
|
4
|
+
import { bindClientChaosSocket as J } from "./client-chaos.js";
|
|
5
|
+
import { deliveryAckFor as O } from "./delivery-ack.js";
|
|
6
|
+
import { forgetSettledReads as L } from "./request-gate.js";
|
|
7
|
+
import { createRoomGapTracker as W, refetchEventsFor as $ } from "./room-gaps.js";
|
|
8
|
+
const U = 3e3;
|
|
9
|
+
function x(i = U) {
|
|
10
|
+
const n = /* @__PURE__ */ new Map();
|
|
11
|
+
return (r, d) => {
|
|
12
|
+
var g;
|
|
13
|
+
if (!(i > 0)) {
|
|
14
|
+
d();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const a = n.has(r);
|
|
18
|
+
if (n.set(r, d), a) return;
|
|
19
|
+
const l = setTimeout(
|
|
20
|
+
() => {
|
|
21
|
+
const f = n.get(r);
|
|
22
|
+
n.delete(r), f == null || f();
|
|
23
|
+
},
|
|
24
|
+
Math.floor(Math.random() * i)
|
|
25
|
+
);
|
|
26
|
+
(g = l.unref) == null || g.call(l);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const j = {
|
|
9
30
|
catchupFull: "nvr:catchup-full",
|
|
10
31
|
accessChanged: "nvr:access-changed",
|
|
11
32
|
configUpdate: "nvr:config-update",
|
|
@@ -13,7 +34,7 @@ const p = {
|
|
|
13
34
|
};
|
|
14
35
|
class C {
|
|
15
36
|
constructor(n, r) {
|
|
16
|
-
|
|
37
|
+
N(this, "refs", /* @__PURE__ */ new Map());
|
|
17
38
|
this.join = n, this.leave = r;
|
|
18
39
|
}
|
|
19
40
|
add(n) {
|
|
@@ -31,154 +52,162 @@ class C {
|
|
|
31
52
|
return [...this.refs.keys()];
|
|
32
53
|
}
|
|
33
54
|
}
|
|
34
|
-
function
|
|
35
|
-
let n = null, r = 0,
|
|
36
|
-
const
|
|
55
|
+
function z(i) {
|
|
56
|
+
let n = null, r = 0, d = !1, a = null, l = { state: "live", transport: null, refreshed: null, resumed: null };
|
|
57
|
+
const g = /* @__PURE__ */ new Set(), f = (e) => {
|
|
37
58
|
var o;
|
|
38
59
|
return ((o = i.windowEvents) == null ? void 0 : o[e]) !== !1;
|
|
39
|
-
},
|
|
40
|
-
const o = { ...
|
|
41
|
-
if (!(o.state ===
|
|
42
|
-
|
|
43
|
-
for (const t of
|
|
60
|
+
}, b = x(i.reactionJitterMs ?? U), A = /* @__PURE__ */ new Set(), p = (e) => {
|
|
61
|
+
const o = { ...l, ...e };
|
|
62
|
+
if (!(o.state === l.state && o.transport === l.transport && o.refreshed === l.refreshed && o.resumed === l.resumed)) {
|
|
63
|
+
l = o;
|
|
64
|
+
for (const t of g) t(l);
|
|
44
65
|
}
|
|
45
|
-
},
|
|
66
|
+
}, _ = () => {
|
|
46
67
|
var e, o, t;
|
|
47
68
|
return ((t = (o = (e = n == null ? void 0 : n.io) == null ? void 0 : e.engine) == null ? void 0 : o.transport) == null ? void 0 : t.name) ?? null;
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
}, u = (e, o) => {
|
|
51
|
-
typeof window > "u" || window.dispatchEvent(new CustomEvent(e, { detail: o }));
|
|
69
|
+
}, E = (e, o) => {
|
|
70
|
+
a && clearTimeout(a), a = null, p({ state: "live", transport: _(), refreshed: e, resumed: o });
|
|
52
71
|
}, h = (e, o) => {
|
|
72
|
+
typeof window > "u" || window.dispatchEvent(new CustomEvent(e, { detail: o }));
|
|
73
|
+
}, m = (e, o) => {
|
|
53
74
|
n != null && n.connected && n.emit(e, o);
|
|
54
|
-
},
|
|
75
|
+
}, F = (e, o) => {
|
|
55
76
|
var t;
|
|
56
77
|
for (const s of ((t = n == null ? void 0 : n.listeners) == null ? void 0 : t.call(n, e)) ?? []) s(o);
|
|
57
|
-
},
|
|
58
|
-
for (const o of
|
|
59
|
-
|
|
60
|
-
},
|
|
61
|
-
request: (e) =>
|
|
62
|
-
dispatch:
|
|
63
|
-
refetch:
|
|
64
|
-
}),
|
|
78
|
+
}, M = (e) => {
|
|
79
|
+
for (const o of $(e)) F(o.event, o.payload);
|
|
80
|
+
h("nvr:realtime-stale", { rooms: e });
|
|
81
|
+
}, w = W({
|
|
82
|
+
request: (e) => m("catchup:room", e),
|
|
83
|
+
dispatch: F,
|
|
84
|
+
refetch: M
|
|
85
|
+
}), R = new C(
|
|
65
86
|
(e) => {
|
|
66
|
-
|
|
87
|
+
w.reset([`collection:${e}`]), m("collection:join", { collection: e });
|
|
67
88
|
},
|
|
68
89
|
(e) => {
|
|
69
|
-
|
|
90
|
+
w.reset([`collection:${e}`]), m("collection:leave", { collection: e });
|
|
70
91
|
}
|
|
71
|
-
),
|
|
92
|
+
), S = new C(
|
|
72
93
|
// The Traffic Map page reads batched frames (api traffic-map-batch.ts); twin: admin
|
|
73
94
|
// lib/socket.ts watchJoinPayload.
|
|
74
|
-
(e) =>
|
|
75
|
-
(e) =>
|
|
76
|
-
),
|
|
77
|
-
(e) =>
|
|
78
|
-
(e) =>
|
|
79
|
-
),
|
|
95
|
+
(e) => m("admin:join", e === "traffic-map" ? { room: e, frames: "batch" } : { room: e }),
|
|
96
|
+
(e) => m("admin:leave", { room: e })
|
|
97
|
+
), q = new C(
|
|
98
|
+
(e) => m("ops:join", { topic: e }),
|
|
99
|
+
(e) => m("ops:leave", { topic: e })
|
|
100
|
+
), T = () => {
|
|
80
101
|
var o;
|
|
81
102
|
if (n) return n;
|
|
82
103
|
const e = typeof i.socket == "function" ? i.socket() : i.socket;
|
|
83
|
-
return n = e,
|
|
84
|
-
if (
|
|
104
|
+
return n = e, J(e), d = e.connected, e.on("auth:ok", () => {
|
|
105
|
+
if (w.reset(), R.rejoinAll(), S.rejoinAll(), q.rejoinAll(), d && r > 0) {
|
|
85
106
|
const t = r;
|
|
86
|
-
|
|
107
|
+
p({ transport: _() }), a && clearTimeout(a), a = setTimeout(() => E(null, "unverified"), i.catchupTimeoutMs ?? 8e3), e.emit("catchup", { cursor: t });
|
|
87
108
|
} else
|
|
88
|
-
|
|
109
|
+
p({
|
|
89
110
|
state: "live",
|
|
90
|
-
transport:
|
|
111
|
+
transport: _(),
|
|
91
112
|
refreshed: null,
|
|
92
|
-
resumed:
|
|
113
|
+
resumed: d && l.state === "reconnecting" ? "unverified" : null
|
|
93
114
|
});
|
|
94
|
-
|
|
115
|
+
d = !0;
|
|
95
116
|
}), e.on("catchup:cursor", (t) => {
|
|
96
117
|
r === 0 && typeof (t == null ? void 0 : t.seq) == "number" && t.seq > 0 && (r = t.seq);
|
|
97
118
|
}), e.on("disconnect", () => {
|
|
98
|
-
|
|
99
|
-
}), e.on("connect_error", () =>
|
|
119
|
+
a && clearTimeout(a), a = null, p({ state: "reconnecting", refreshed: null });
|
|
120
|
+
}), e.on("connect_error", () => p({ state: "reconnecting", refreshed: null })), (o = e.onAny) == null || o.call(e, (t, s) => {
|
|
100
121
|
const c = s == null ? void 0 : s._seq;
|
|
101
|
-
typeof c == "number" && c > r && (r = c),
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
}), e.on("catchup:room:events", (t) =>
|
|
122
|
+
typeof c == "number" && c > r && (r = c), w.observe(s);
|
|
123
|
+
const v = O(s);
|
|
124
|
+
v && e.emit("rt:ack", v);
|
|
125
|
+
}), e.on("catchup:room:events", (t) => w.replayed(t)), e.on("realtime:stale", (t) => {
|
|
105
126
|
const s = Array.isArray(t == null ? void 0 : t.rooms) ? t.rooms.filter((c) => typeof c == "string") : [];
|
|
106
|
-
|
|
127
|
+
w.reset(s), t != null && t.all ? (f("catchupFull") && h(j.catchupFull, {}), h("nvr:realtime-stale", { rooms: s, all: !0 })) : s.length && M(s);
|
|
107
128
|
}), e.on(
|
|
108
129
|
"catchup:events",
|
|
109
130
|
(t) => {
|
|
110
131
|
var s;
|
|
111
132
|
for (const c of (t == null ? void 0 : t.events) ?? []) {
|
|
112
133
|
c.seq > r && (r = c.seq);
|
|
113
|
-
for (const
|
|
134
|
+
for (const v of ((s = e.listeners) == null ? void 0 : s.call(e, c.event)) ?? []) v({ ...c.payload, _seq: c.seq });
|
|
114
135
|
}
|
|
115
|
-
|
|
136
|
+
E(null, "replayed");
|
|
116
137
|
}
|
|
117
138
|
), e.on("catchup:full", (t) => {
|
|
118
|
-
|
|
139
|
+
f("catchupFull") && b("full", () => h(j.catchupFull, {})), E(
|
|
119
140
|
(t == null ? void 0 : t.reason) === "slow-consumer" ? "Live updates resumed. This tab fell too far behind to send each change, so the lists and records on this page were reloaded." : "Live updates resumed. The connection was gone too long to replay each change, so the lists and records on this page were reloaded.",
|
|
120
141
|
"reloaded"
|
|
121
142
|
);
|
|
122
143
|
}), e.on("access:changed", (t) => {
|
|
123
144
|
var s;
|
|
124
|
-
|
|
145
|
+
if (L(), (s = t == null ? void 0 : t.rooms_left) != null && s.length && f("accessChanged")) {
|
|
146
|
+
for (const c of t.rooms_left) A.add(c);
|
|
147
|
+
b("access", () => {
|
|
148
|
+
const c = [...A];
|
|
149
|
+
A.clear(), h(j.accessChanged, { rooms_left: c });
|
|
150
|
+
});
|
|
151
|
+
}
|
|
125
152
|
}), e.on("config:update", (t) => {
|
|
126
|
-
|
|
153
|
+
L(), f("configUpdate") && h(j.configUpdate, t ?? {});
|
|
127
154
|
}), e.on("client:force-refresh", (t) => {
|
|
128
|
-
|
|
155
|
+
f("forceRefresh") && h(j.forceRefresh, t ?? {});
|
|
129
156
|
}), e;
|
|
130
157
|
};
|
|
131
158
|
return {
|
|
132
159
|
subscribeCollections(e, o) {
|
|
133
|
-
const t =
|
|
134
|
-
for (const
|
|
135
|
-
const c = (
|
|
136
|
-
|
|
160
|
+
const t = T(), s = [...new Set(e.filter(Boolean))];
|
|
161
|
+
for (const u of s) R.add(u);
|
|
162
|
+
const c = (u) => {
|
|
163
|
+
u != null && u.collection && s.includes(u.collection) && o(u);
|
|
137
164
|
};
|
|
138
165
|
t.on("collection:update", c);
|
|
139
|
-
let
|
|
166
|
+
let v = !1;
|
|
140
167
|
return () => {
|
|
141
|
-
if (!
|
|
142
|
-
|
|
143
|
-
for (const
|
|
168
|
+
if (!v) {
|
|
169
|
+
v = !0, t.off("collection:update", c);
|
|
170
|
+
for (const u of s) R.remove(u);
|
|
144
171
|
}
|
|
145
172
|
};
|
|
146
173
|
},
|
|
147
174
|
on(e, o) {
|
|
148
|
-
const t =
|
|
175
|
+
const t = T();
|
|
149
176
|
return t.on(e, o), () => {
|
|
150
177
|
t.off(e, o);
|
|
151
178
|
};
|
|
152
179
|
},
|
|
153
180
|
emit(e, o) {
|
|
154
|
-
if (
|
|
181
|
+
if (T(), e === "ops:join" || e === "ops:leave") {
|
|
155
182
|
const t = String((o == null ? void 0 : o.topic) ?? "");
|
|
156
183
|
if (!t) return;
|
|
157
|
-
e === "ops:join" ?
|
|
184
|
+
e === "ops:join" ? q.add(t) : q.remove(t);
|
|
158
185
|
return;
|
|
159
186
|
}
|
|
160
187
|
n == null || n.emit(e, o);
|
|
161
188
|
},
|
|
162
189
|
status() {
|
|
163
|
-
return
|
|
190
|
+
return l;
|
|
164
191
|
},
|
|
165
192
|
onStatus(e) {
|
|
166
|
-
return
|
|
167
|
-
|
|
193
|
+
return T(), g.add(e), () => {
|
|
194
|
+
g.delete(e);
|
|
168
195
|
};
|
|
169
196
|
},
|
|
170
197
|
joinWatch(e) {
|
|
171
|
-
|
|
198
|
+
T(), S.add(e);
|
|
172
199
|
let o = !1;
|
|
173
200
|
return () => {
|
|
174
|
-
o || (o = !0,
|
|
201
|
+
o || (o = !0, S.remove(e));
|
|
175
202
|
};
|
|
176
203
|
},
|
|
177
204
|
held() {
|
|
178
|
-
return { collections:
|
|
205
|
+
return { collections: R.keys(), watch: S.keys(), ops: q.keys() };
|
|
179
206
|
}
|
|
180
207
|
};
|
|
181
208
|
}
|
|
182
209
|
export {
|
|
183
|
-
|
|
210
|
+
U as REACTION_JITTER_MS,
|
|
211
|
+
x as createJitteredReaction,
|
|
212
|
+
z as createSocketRealtime
|
|
184
213
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nivaro/react",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.25",
|
|
4
4
|
"description": "React hooks and components for Nivaro CMS forms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -77,11 +77,11 @@
|
|
|
77
77
|
"@radix-ui/react-switch": "^1.2.6",
|
|
78
78
|
"@radix-ui/react-tabs": "^1.1.14",
|
|
79
79
|
"@radix-ui/react-tooltip": "^1.2.7",
|
|
80
|
-
"@tiptap/extension-link": "^3.
|
|
81
|
-
"@tiptap/extension-placeholder": "^3.
|
|
82
|
-
"@tiptap/extension-underline": "^3.
|
|
83
|
-
"@tiptap/react": "^3.
|
|
84
|
-
"@tiptap/starter-kit": "^3.
|
|
80
|
+
"@tiptap/extension-link": "^3.32.0",
|
|
81
|
+
"@tiptap/extension-placeholder": "^3.32.0",
|
|
82
|
+
"@tiptap/extension-underline": "^3.32.0",
|
|
83
|
+
"@tiptap/react": "^3.32.0",
|
|
84
|
+
"@tiptap/starter-kit": "^3.32.0",
|
|
85
85
|
"class-variance-authority": "^0.7.0",
|
|
86
86
|
"clsx": "^2.0.0",
|
|
87
87
|
"cmdk": "^1.0.0",
|