@dogsbay/editor 0.0.0-stage → 0.2.0-beta.173
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -2
- package/dist/block-view.d.ts +25 -0
- package/dist/block-view.js +28 -0
- package/dist/block.d.ts +69 -0
- package/dist/block.js +114 -0
- package/dist/bridge.d.ts +37 -0
- package/dist/bridge.js +626 -0
- package/dist/diff.d.ts +38 -0
- package/dist/diff.js +136 -0
- package/dist/directive-context.d.ts +16 -0
- package/dist/directive-context.js +87 -0
- package/dist/directive-fields.d.ts +8 -0
- package/dist/directive-fields.js +60 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +18 -0
- package/dist/schema.d.ts +54 -0
- package/dist/schema.js +395 -0
- package/package.json +68 -3
package/dist/schema.js
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TipTap schema for the TreeNode vocabulary: StarterKit (paragraph,
|
|
3
|
+
* heading, lists, blockquote, codeBlock, horizontalRule, hardBreak,
|
|
4
|
+
* bold/italic/strike/code/link marks) plus the custom pieces:
|
|
5
|
+
* - callout — a block container
|
|
6
|
+
* - variable — an inline atom (the directive-chip mechanism)
|
|
7
|
+
* - dogsbayBlock — a block atom carrying verbatim TreeNode JSON (lossless
|
|
8
|
+
* passthrough for tables and anything unmodeled)
|
|
9
|
+
* - dogsbayInline — the inline equivalent
|
|
10
|
+
* - DogsbayProps — a hidden global attribute on every modeled block that
|
|
11
|
+
* carries the original TreeNode props/meta verbatim, so
|
|
12
|
+
* fields the editor doesn't model (code title/highlights,
|
|
13
|
+
* heading {#id .class}, ordered-list start, …) survive
|
|
14
|
+
* the round trip. ProseMirror drops undeclared attrs, so
|
|
15
|
+
* this MUST be a declared attribute.
|
|
16
|
+
*
|
|
17
|
+
* Underline is disabled: InlineText has no underline flag (markdown cannot
|
|
18
|
+
* express it), so anything underlined in the editor would be silently
|
|
19
|
+
* stripped on serialize — better not to offer it.
|
|
20
|
+
*/
|
|
21
|
+
import { Extension, Node, mergeAttributes, callOrReturn, getExtensionField } from "@tiptap/core";
|
|
22
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
23
|
+
import { tableEditing, goToNextCell, isInTable, addRowAfter } from "@tiptap/pm/tables";
|
|
24
|
+
export const DogsbayProps = Extension.create({
|
|
25
|
+
name: "dogsbayProps",
|
|
26
|
+
addGlobalAttributes() {
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
types: [
|
|
30
|
+
"paragraph",
|
|
31
|
+
"heading",
|
|
32
|
+
"blockquote",
|
|
33
|
+
"bulletList",
|
|
34
|
+
"orderedList",
|
|
35
|
+
"listItem",
|
|
36
|
+
"codeBlock",
|
|
37
|
+
"horizontalRule",
|
|
38
|
+
"callout",
|
|
39
|
+
"conditional",
|
|
40
|
+
"include",
|
|
41
|
+
"varDef",
|
|
42
|
+
"directiveRaw",
|
|
43
|
+
"table",
|
|
44
|
+
"tableRow",
|
|
45
|
+
"tableHeader",
|
|
46
|
+
"tableCell",
|
|
47
|
+
],
|
|
48
|
+
attributes: {
|
|
49
|
+
dogsbayProps: { default: null, rendered: false, keepOnSplit: false },
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Tables are NATIVE nodes on prosemirror-tables (via `@tiptap/pm/tables` —
|
|
57
|
+
* no extra dependency), not the `dogsbayBlock` passthrough: a writer edits
|
|
58
|
+
* cells in place, and row/column commands come from prosemirror-tables.
|
|
59
|
+
*
|
|
60
|
+
* Cells hold `block+` because a Dogsbay table cell may hold blocks (the
|
|
61
|
+
* serializer emits an HTML table for those); the common case is one
|
|
62
|
+
* paragraph, which the bridge maps back to the cell's `inline`.
|
|
63
|
+
*
|
|
64
|
+
* `align` is a first-class cell attribute — it is GFM column alignment
|
|
65
|
+
* (`:--`), which the toolbar edits and the serializer re-emits. Everything
|
|
66
|
+
* else the table carries (`caption`, `#id`, `.class`) rides `dogsbayProps`.
|
|
67
|
+
*
|
|
68
|
+
* The nodes deliberately do NOT render `colwidth`/resize handles: Dogsbay
|
|
69
|
+
* MD has no column-width concept, so a width set here could not survive a
|
|
70
|
+
* save.
|
|
71
|
+
*/
|
|
72
|
+
const cellAttributes = () => ({
|
|
73
|
+
colspan: { default: 1 },
|
|
74
|
+
rowspan: { default: 1 },
|
|
75
|
+
align: { default: null },
|
|
76
|
+
});
|
|
77
|
+
export const Table = Node.create({
|
|
78
|
+
name: "table",
|
|
79
|
+
group: "block",
|
|
80
|
+
content: "tableRow+",
|
|
81
|
+
tableRole: "table",
|
|
82
|
+
isolating: true,
|
|
83
|
+
parseHTML() {
|
|
84
|
+
return [{ tag: "table" }];
|
|
85
|
+
},
|
|
86
|
+
renderHTML({ HTMLAttributes }) {
|
|
87
|
+
return ["table", mergeAttributes(HTMLAttributes), ["tbody", 0]];
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
export const TableRow = Node.create({
|
|
91
|
+
name: "tableRow",
|
|
92
|
+
content: "(tableCell | tableHeader)*",
|
|
93
|
+
tableRole: "row",
|
|
94
|
+
parseHTML() {
|
|
95
|
+
return [{ tag: "tr" }];
|
|
96
|
+
},
|
|
97
|
+
renderHTML({ HTMLAttributes }) {
|
|
98
|
+
return ["tr", mergeAttributes(HTMLAttributes), 0];
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
export const TableHeader = Node.create({
|
|
102
|
+
name: "tableHeader",
|
|
103
|
+
content: "block+",
|
|
104
|
+
tableRole: "header_cell",
|
|
105
|
+
isolating: true,
|
|
106
|
+
addAttributes: cellAttributes,
|
|
107
|
+
parseHTML() {
|
|
108
|
+
return [{ tag: "th" }];
|
|
109
|
+
},
|
|
110
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
111
|
+
return ["th", mergeAttributes(HTMLAttributes, alignAttrs(node.attrs.align)), 0];
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
export const TableCell = Node.create({
|
|
115
|
+
name: "tableCell",
|
|
116
|
+
content: "block+",
|
|
117
|
+
tableRole: "cell",
|
|
118
|
+
isolating: true,
|
|
119
|
+
addAttributes: cellAttributes,
|
|
120
|
+
parseHTML() {
|
|
121
|
+
return [{ tag: "td" }];
|
|
122
|
+
},
|
|
123
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
124
|
+
return ["td", mergeAttributes(HTMLAttributes, alignAttrs(node.attrs.align)), 0];
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
const alignAttrs = (align) => (align ? { style: `text-align: ${align}` } : {});
|
|
128
|
+
/** prosemirror-tables' editing plugin + cell navigation (Tab / Shift-Tab). */
|
|
129
|
+
export const TableEditing = Extension.create({
|
|
130
|
+
name: "tableEditing",
|
|
131
|
+
extendNodeSchema(extension) {
|
|
132
|
+
const context = { name: extension.name, options: extension.options, storage: extension.storage };
|
|
133
|
+
return { tableRole: callOrReturn(getExtensionField(extension, "tableRole", context)) };
|
|
134
|
+
},
|
|
135
|
+
addProseMirrorPlugins() {
|
|
136
|
+
return [tableEditing({ allowTableNodeSelection: false })];
|
|
137
|
+
},
|
|
138
|
+
addKeyboardShortcuts() {
|
|
139
|
+
return {
|
|
140
|
+
// a list inside a cell is the INNER context: Tab indents it, as it does anywhere else
|
|
141
|
+
Tab: () => (sinkList(this.editor) ? true : goToCell(this.editor, 1)),
|
|
142
|
+
"Shift-Tab": () => (liftList(this.editor) ? true : goToCell(this.editor, -1)),
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
/**
|
|
147
|
+
* Tab moves to the next cell, and only inside a table (outside one it falls
|
|
148
|
+
* through, so Tab still means what it means everywhere else). Tab in the
|
|
149
|
+
* last cell appends a row — the standard way to grow a table by typing.
|
|
150
|
+
*/
|
|
151
|
+
function goToCell(editor, dir) {
|
|
152
|
+
const { state, view } = editor;
|
|
153
|
+
if (!isInTable(state))
|
|
154
|
+
return false;
|
|
155
|
+
if (goToNextCell(dir)(state, view.dispatch))
|
|
156
|
+
return true;
|
|
157
|
+
if (dir === -1)
|
|
158
|
+
return false;
|
|
159
|
+
if (!addRowAfter(state, view.dispatch))
|
|
160
|
+
return false;
|
|
161
|
+
// the row was added in a new state: re-read it before moving
|
|
162
|
+
return goToNextCell(1)(view.state, view.dispatch);
|
|
163
|
+
}
|
|
164
|
+
const sinkList = (editor) => editor.can().sinkListItem("listItem") && editor.commands.sinkListItem("listItem");
|
|
165
|
+
const liftList = (editor) => editor.can().liftListItem("listItem") && editor.commands.liftListItem("listItem");
|
|
166
|
+
export const Callout = Node.create({
|
|
167
|
+
name: "callout",
|
|
168
|
+
group: "block",
|
|
169
|
+
content: "block+",
|
|
170
|
+
defining: true,
|
|
171
|
+
addAttributes() {
|
|
172
|
+
return { tone: { default: "note" } };
|
|
173
|
+
},
|
|
174
|
+
parseHTML() {
|
|
175
|
+
return [{ tag: "aside[data-callout]" }];
|
|
176
|
+
},
|
|
177
|
+
renderHTML({ HTMLAttributes }) {
|
|
178
|
+
return ["aside", mergeAttributes(HTMLAttributes, { "data-callout": "" }), 0];
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
export const Variable = Node.create({
|
|
182
|
+
name: "variable",
|
|
183
|
+
group: "inline",
|
|
184
|
+
inline: true,
|
|
185
|
+
atom: true,
|
|
186
|
+
selectable: true,
|
|
187
|
+
// Atoms default to NO marks; directive chips inherit their containing
|
|
188
|
+
// span's formatting (InlineVariable.bold/italic/strikethrough), which
|
|
189
|
+
// the bridge maps to marks — so marks must be allowed here.
|
|
190
|
+
marks: "bold italic strike",
|
|
191
|
+
addAttributes() {
|
|
192
|
+
return { expr: { default: "" } };
|
|
193
|
+
},
|
|
194
|
+
parseHTML() {
|
|
195
|
+
return [{ tag: "span[data-variable]" }];
|
|
196
|
+
},
|
|
197
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
198
|
+
return [
|
|
199
|
+
"span",
|
|
200
|
+
mergeAttributes(HTMLAttributes, { "data-variable": "", class: "variable" }),
|
|
201
|
+
`{{ ${node.attrs.expr} }}`,
|
|
202
|
+
];
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
/* ── Directive nodes (directive-model Phase 5a) ─────────────────────────
|
|
206
|
+
* First-class editor nodes for the preserve-mode TreeNode vocabulary:
|
|
207
|
+
* conditional / include / var-def / directive-raw (block) and
|
|
208
|
+
* conditional-span / directive-raw-inline (inline). Chip UX (node views,
|
|
209
|
+
* attribute editing, minja preview) is Phase 5b; renderHTML below is the
|
|
210
|
+
* minimal semantic rendering the WYSIWYG shows meanwhile.
|
|
211
|
+
*/
|
|
212
|
+
export const Conditional = Node.create({
|
|
213
|
+
name: "conditional",
|
|
214
|
+
group: "block",
|
|
215
|
+
// block* not block+: an empty `{% if %}{% endif %}` region is valid source
|
|
216
|
+
content: "block*",
|
|
217
|
+
defining: true,
|
|
218
|
+
addAttributes() {
|
|
219
|
+
return { test: { default: "" } };
|
|
220
|
+
},
|
|
221
|
+
parseHTML() {
|
|
222
|
+
return [{ tag: "section[data-conditional]" }];
|
|
223
|
+
},
|
|
224
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
225
|
+
return [
|
|
226
|
+
"section",
|
|
227
|
+
mergeAttributes(HTMLAttributes, {
|
|
228
|
+
"data-conditional": "",
|
|
229
|
+
"data-test": String(node.attrs.test ?? ""),
|
|
230
|
+
class: "directive-conditional",
|
|
231
|
+
}),
|
|
232
|
+
0,
|
|
233
|
+
];
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
export const Include = Node.create({
|
|
237
|
+
name: "include",
|
|
238
|
+
group: "block",
|
|
239
|
+
atom: true,
|
|
240
|
+
addAttributes() {
|
|
241
|
+
return { src: { default: "" } };
|
|
242
|
+
},
|
|
243
|
+
parseHTML() {
|
|
244
|
+
return [{ tag: "div[data-include]" }];
|
|
245
|
+
},
|
|
246
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
247
|
+
return [
|
|
248
|
+
"div",
|
|
249
|
+
mergeAttributes(HTMLAttributes, { "data-include": "", class: "directive-include" }),
|
|
250
|
+
`include: ${node.attrs.src}`,
|
|
251
|
+
];
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
export const VarDef = Node.create({
|
|
255
|
+
name: "varDef",
|
|
256
|
+
group: "block",
|
|
257
|
+
atom: true,
|
|
258
|
+
addAttributes() {
|
|
259
|
+
return { name: { default: "" }, value: { default: "" } };
|
|
260
|
+
},
|
|
261
|
+
parseHTML() {
|
|
262
|
+
return [{ tag: "div[data-var-def]" }];
|
|
263
|
+
},
|
|
264
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
265
|
+
return [
|
|
266
|
+
"div",
|
|
267
|
+
mergeAttributes(HTMLAttributes, { "data-var-def": "", class: "directive-var-def" }),
|
|
268
|
+
`set ${node.attrs.name} = ${node.attrs.value}`,
|
|
269
|
+
];
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
export const DirectiveRaw = Node.create({
|
|
273
|
+
name: "directiveRaw",
|
|
274
|
+
group: "block",
|
|
275
|
+
atom: true,
|
|
276
|
+
addAttributes() {
|
|
277
|
+
return { source: { default: "" }, kind: { default: null } };
|
|
278
|
+
},
|
|
279
|
+
parseHTML() {
|
|
280
|
+
return [{ tag: "div[data-directive-raw]" }];
|
|
281
|
+
},
|
|
282
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
283
|
+
return [
|
|
284
|
+
"div",
|
|
285
|
+
mergeAttributes(HTMLAttributes, { "data-directive-raw": "", class: "directive-raw" }),
|
|
286
|
+
String(node.attrs.source ?? ""),
|
|
287
|
+
];
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
export const ConditionalSpan = Node.create({
|
|
291
|
+
name: "conditionalSpan",
|
|
292
|
+
group: "inline",
|
|
293
|
+
inline: true,
|
|
294
|
+
content: "inline*",
|
|
295
|
+
marks: "bold italic strike",
|
|
296
|
+
addAttributes() {
|
|
297
|
+
return { test: { default: "" } };
|
|
298
|
+
},
|
|
299
|
+
parseHTML() {
|
|
300
|
+
return [{ tag: "span[data-conditional-span]" }];
|
|
301
|
+
},
|
|
302
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
303
|
+
return [
|
|
304
|
+
"span",
|
|
305
|
+
mergeAttributes(HTMLAttributes, {
|
|
306
|
+
"data-conditional-span": "",
|
|
307
|
+
"data-test": String(node.attrs.test ?? ""),
|
|
308
|
+
class: "directive-conditional-span",
|
|
309
|
+
}),
|
|
310
|
+
0,
|
|
311
|
+
];
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
export const DirectiveRawInline = Node.create({
|
|
315
|
+
name: "directiveRawInline",
|
|
316
|
+
group: "inline",
|
|
317
|
+
inline: true,
|
|
318
|
+
atom: true,
|
|
319
|
+
marks: "bold italic strike",
|
|
320
|
+
addAttributes() {
|
|
321
|
+
return { source: { default: "" } };
|
|
322
|
+
},
|
|
323
|
+
parseHTML() {
|
|
324
|
+
return [{ tag: "span[data-directive-raw-inline]" }];
|
|
325
|
+
},
|
|
326
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
327
|
+
return [
|
|
328
|
+
"span",
|
|
329
|
+
mergeAttributes(HTMLAttributes, {
|
|
330
|
+
"data-directive-raw-inline": "",
|
|
331
|
+
class: "directive-raw-inline",
|
|
332
|
+
}),
|
|
333
|
+
String(node.attrs.source ?? ""),
|
|
334
|
+
];
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
export const DogsbayBlock = Node.create({
|
|
338
|
+
name: "dogsbayBlock",
|
|
339
|
+
group: "block",
|
|
340
|
+
atom: true,
|
|
341
|
+
addAttributes() {
|
|
342
|
+
return { json: { default: "" } };
|
|
343
|
+
},
|
|
344
|
+
parseHTML() {
|
|
345
|
+
return [{ tag: "div[data-dogsbay-block]" }];
|
|
346
|
+
},
|
|
347
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
348
|
+
let label = "block";
|
|
349
|
+
try {
|
|
350
|
+
label = JSON.parse(String(node.attrs.json ?? "{}")).type ?? "block";
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
/* keep default */
|
|
354
|
+
}
|
|
355
|
+
return [
|
|
356
|
+
"div",
|
|
357
|
+
mergeAttributes(HTMLAttributes, { "data-dogsbay-block": "", class: "dogsbay-block" }),
|
|
358
|
+
`⟨${label}⟩`,
|
|
359
|
+
];
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
export const DogsbayInline = Node.create({
|
|
363
|
+
name: "dogsbayInline",
|
|
364
|
+
group: "inline",
|
|
365
|
+
inline: true,
|
|
366
|
+
atom: true,
|
|
367
|
+
addAttributes() {
|
|
368
|
+
return { json: { default: "" } };
|
|
369
|
+
},
|
|
370
|
+
parseHTML() {
|
|
371
|
+
return [{ tag: "span[data-dogsbay-inline]" }];
|
|
372
|
+
},
|
|
373
|
+
renderHTML({ HTMLAttributes }) {
|
|
374
|
+
return ["span", mergeAttributes(HTMLAttributes, { "data-dogsbay-inline": "" }), "⟨inline⟩"];
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
export const extensions = [
|
|
378
|
+
StarterKit.configure({ underline: false }),
|
|
379
|
+
DogsbayProps,
|
|
380
|
+
Table,
|
|
381
|
+
TableRow,
|
|
382
|
+
TableHeader,
|
|
383
|
+
TableCell,
|
|
384
|
+
TableEditing,
|
|
385
|
+
Callout,
|
|
386
|
+
Variable,
|
|
387
|
+
Conditional,
|
|
388
|
+
Include,
|
|
389
|
+
VarDef,
|
|
390
|
+
DirectiveRaw,
|
|
391
|
+
ConditionalSpan,
|
|
392
|
+
DirectiveRawInline,
|
|
393
|
+
DogsbayBlock,
|
|
394
|
+
DogsbayInline,
|
|
395
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,71 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/editor",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0-beta.173",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "TipTap/ProseMirror editor for Dogsbay Markdown: schema, a lossless TreeNode ⇄ ProseMirror bridge, and the editor on one block of a page (./block)",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./block": {
|
|
15
|
+
"types": "./dist/block.d.ts",
|
|
16
|
+
"import": "./dist/block.js"
|
|
17
|
+
},
|
|
18
|
+
"./block-view": {
|
|
19
|
+
"types": "./dist/block-view.d.ts",
|
|
20
|
+
"import": "./dist/block-view.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@dogsbay/minja": "0.2.0-beta.173",
|
|
29
|
+
"@dogsbay/tree-diff": "0.2.0-beta.173",
|
|
30
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.173",
|
|
31
|
+
"@dogsbay/types": "0.2.0-beta.173"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@tiptap/core": "^3.27.3",
|
|
35
|
+
"@tiptap/pm": "^3.27.3",
|
|
36
|
+
"@tiptap/starter-kit": "^3.27.3"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@playwright/test": "^1.61.1",
|
|
40
|
+
"@tiptap/core": "^3.27.3",
|
|
41
|
+
"@tiptap/pm": "^3.27.3",
|
|
42
|
+
"@tiptap/react": "^3.27.3",
|
|
43
|
+
"@tiptap/starter-kit": "^3.27.3",
|
|
44
|
+
"@types/node": "^22.20.1",
|
|
45
|
+
"@types/react": "^19.2.17",
|
|
46
|
+
"@types/react-dom": "^19.2.3",
|
|
47
|
+
"@vitejs/plugin-react": "^6.0.3",
|
|
48
|
+
"esbuild": "0.28.1",
|
|
49
|
+
"jsdom": "^26.1.0",
|
|
50
|
+
"react": "^19.2.7",
|
|
51
|
+
"react-dom": "^19.2.7",
|
|
52
|
+
"typescript": "^5.9.3",
|
|
53
|
+
"vite": "^8.1.4",
|
|
54
|
+
"vitest": "^4.1.10"
|
|
55
|
+
},
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "https://github.com/dogsbay/dogsbay.git",
|
|
59
|
+
"directory": "packages/editor"
|
|
60
|
+
},
|
|
61
|
+
"homepage": "https://github.com/dogsbay/dogsbay/tree/main/packages/editor",
|
|
62
|
+
"bugs": {
|
|
63
|
+
"url": "https://github.com/dogsbay/dogsbay/issues"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"dev": "vite",
|
|
67
|
+
"build": "tsc -p tsconfig.build.json",
|
|
68
|
+
"test": "vitest run",
|
|
69
|
+
"test:e2e": "playwright test"
|
|
70
|
+
}
|
|
6
71
|
}
|