@lazlon-platform/html-editor 0.1.0 → 0.2.1
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/package.json +14 -11
- package/.claude/settings.local.json +0 -9
- package/.github/workflows/ci.yml +0 -34
- package/demo/App.tsx +0 -62
- package/demo/EditorView/PageView/NodeContent.tsx +0 -35
- package/demo/EditorView/PageView/SnapLines.tsx +0 -28
- package/demo/EditorView/PageView/index.tsx +0 -45
- package/demo/EditorView/SelectionFrame/Corner.tsx +0 -24
- package/demo/EditorView/SelectionFrame/Edge.tsx +0 -21
- package/demo/EditorView/SelectionFrame/index.tsx +0 -27
- package/demo/EditorView/SelectionOverlay/ActionHud.tsx +0 -32
- package/demo/EditorView/SelectionOverlay/Rotation.tsx +0 -39
- package/demo/EditorView/SelectionOverlay/Toolbar.tsx +0 -128
- package/demo/EditorView/SelectionOverlay/index.tsx +0 -21
- package/demo/EditorView/Toolbar/index.tsx +0 -68
- package/demo/EditorView/index.tsx +0 -47
- package/demo/Navbar/index.tsx +0 -33
- package/demo/Sidebar/index.tsx +0 -71
- package/demo/hotkeys.ts +0 -93
- package/demo/main.tsx +0 -10
- package/demo/style.css +0 -1
- package/eslint.config.js +0 -43
- package/index.html +0 -14
- package/tests/createTestEditor.ts +0 -19
- package/tests/hooks/actions.test.tsx +0 -736
- package/tests/hooks/batch.test.tsx +0 -332
- package/tests/hooks/editor.test.tsx +0 -56
- package/tests/hooks/page.test.tsx +0 -135
- package/tests/hooks/pointer/pointer.test.tsx +0 -244
- package/tests/hooks/textMarks.test.tsx +0 -624
- package/tests/model/editor.test.ts +0 -384
- package/tests/model/history.test.ts +0 -293
- package/tests/model/node/group.test.ts +0 -294
- package/tests/model/node/image.test.ts +0 -150
- package/tests/model/node/polygon.test.ts +0 -408
- package/tests/model/node/text.test.ts +0 -158
- package/tests/model/node.test.ts +0 -276
- package/tests/model/page.test.ts +0 -150
- package/tests/setup.ts +0 -7
- package/tsconfig.json +0 -28
- package/vite.config.ts +0 -9
- package/vitest.config.ts +0 -13
package/tests/model/node.test.ts
DELETED
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest"
|
|
2
|
-
import { Page } from "../../lib/model/page"
|
|
3
|
-
import { ImageNode } from "../../lib/model/node/image"
|
|
4
|
-
import { createTestEditor } from "../createTestEditor"
|
|
5
|
-
|
|
6
|
-
// Using ImageNode as a concrete implementation of Node for testing
|
|
7
|
-
describe("Node", () => {
|
|
8
|
-
let editor: ReturnType<typeof createTestEditor>
|
|
9
|
-
let page: Page
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
editor = createTestEditor()
|
|
13
|
-
page = new Page(editor, { id: "page-1" })
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
describe("construction", () => {
|
|
17
|
-
it("initializes with required properties", () => {
|
|
18
|
-
const node = new ImageNode(editor, page, {
|
|
19
|
-
id: "node-1",
|
|
20
|
-
x: 10,
|
|
21
|
-
y: 20,
|
|
22
|
-
width: 100,
|
|
23
|
-
height: 50,
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
expect(node.id).toBe("node-1")
|
|
27
|
-
expect(node.x).toBe(10)
|
|
28
|
-
expect(node.y).toBe(20)
|
|
29
|
-
expect(node.width).toBe(100)
|
|
30
|
-
expect(node.height).toBe(50)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it("applies default values for optional properties", () => {
|
|
34
|
-
const node = new ImageNode(editor, page, {
|
|
35
|
-
id: "node-1",
|
|
36
|
-
x: 0,
|
|
37
|
-
y: 0,
|
|
38
|
-
width: 100,
|
|
39
|
-
height: 100,
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
expect(node.rotation).toBe(0)
|
|
43
|
-
expect(node.locked).toBe(false)
|
|
44
|
-
expect(node.role).toBeNull()
|
|
45
|
-
expect(node.css).toBe("")
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it("accepts optional properties", () => {
|
|
49
|
-
const node = new ImageNode(editor, page, {
|
|
50
|
-
id: "node-1",
|
|
51
|
-
x: 0,
|
|
52
|
-
y: 0,
|
|
53
|
-
width: 100,
|
|
54
|
-
height: 100,
|
|
55
|
-
rotation: 45,
|
|
56
|
-
locked: true,
|
|
57
|
-
role: ["header"],
|
|
58
|
-
css: "filter: blur(2px);",
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
expect(node.rotation).toBe(45)
|
|
62
|
-
expect(node.locked).toBe(true)
|
|
63
|
-
expect(node.role).toBe("header")
|
|
64
|
-
expect(node.css).toBe("filter: blur(2px);")
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it("stores reference to parent page", () => {
|
|
68
|
-
const node = new ImageNode(editor, page, {
|
|
69
|
-
id: "node-1",
|
|
70
|
-
x: 0,
|
|
71
|
-
y: 0,
|
|
72
|
-
width: 100,
|
|
73
|
-
height: 100,
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
expect(node.page).toBe(page)
|
|
77
|
-
})
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
describe("width and height constraints", () => {
|
|
81
|
-
it("enforces minimum width of 1", () => {
|
|
82
|
-
const node = new ImageNode(editor, page, {
|
|
83
|
-
id: "node-1",
|
|
84
|
-
x: 0,
|
|
85
|
-
y: 0,
|
|
86
|
-
width: 100,
|
|
87
|
-
height: 100,
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
node.width = 0
|
|
91
|
-
expect(node.width).toBe(1)
|
|
92
|
-
|
|
93
|
-
node.width = -10
|
|
94
|
-
expect(node.width).toBe(1)
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it("enforces minimum height of 1", () => {
|
|
98
|
-
const node = new ImageNode(editor, page, {
|
|
99
|
-
id: "node-1",
|
|
100
|
-
x: 0,
|
|
101
|
-
y: 0,
|
|
102
|
-
width: 100,
|
|
103
|
-
height: 100,
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
node.height = 0
|
|
107
|
-
expect(node.height).toBe(1)
|
|
108
|
-
|
|
109
|
-
node.height = -10
|
|
110
|
-
expect(node.height).toBe(1)
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it("allows setting width and height to exactly 1", () => {
|
|
114
|
-
const node = new ImageNode(editor, page, {
|
|
115
|
-
id: "node-1",
|
|
116
|
-
x: 0,
|
|
117
|
-
y: 0,
|
|
118
|
-
width: 100,
|
|
119
|
-
height: 100,
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
node.width = 1
|
|
123
|
-
node.height = 1
|
|
124
|
-
|
|
125
|
-
expect(node.width).toBe(1)
|
|
126
|
-
expect(node.height).toBe(1)
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
describe("boundingBox", () => {
|
|
131
|
-
it("returns node rect when rotation is 0", () => {
|
|
132
|
-
const node = new ImageNode(editor, page, {
|
|
133
|
-
id: "node-1",
|
|
134
|
-
x: 10,
|
|
135
|
-
y: 20,
|
|
136
|
-
width: 100,
|
|
137
|
-
height: 50,
|
|
138
|
-
rotation: 0,
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
const bbox = node.boundingBox
|
|
142
|
-
expect(bbox.x).toBe(10)
|
|
143
|
-
expect(bbox.y).toBe(20)
|
|
144
|
-
expect(bbox.width).toBe(100)
|
|
145
|
-
expect(bbox.height).toBe(50)
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
it("expands bounding box for rotated node", () => {
|
|
149
|
-
const node = new ImageNode(editor, page, {
|
|
150
|
-
id: "node-1",
|
|
151
|
-
x: 0,
|
|
152
|
-
y: 0,
|
|
153
|
-
width: 100,
|
|
154
|
-
height: 100,
|
|
155
|
-
rotation: 45,
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
const bbox = node.boundingBox
|
|
159
|
-
// A 100x100 square rotated 45 degrees has diagonal ~141.4
|
|
160
|
-
expect(bbox.width).toBeGreaterThan(100)
|
|
161
|
-
expect(bbox.height).toBeGreaterThan(100)
|
|
162
|
-
})
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
describe("blockMove", () => {
|
|
166
|
-
it("returns true when node is locked", () => {
|
|
167
|
-
const node = new ImageNode(editor, page, {
|
|
168
|
-
id: "node-1",
|
|
169
|
-
x: 0,
|
|
170
|
-
y: 0,
|
|
171
|
-
width: 100,
|
|
172
|
-
height: 100,
|
|
173
|
-
locked: true,
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
const mockEvent = {} as React.PointerEvent
|
|
177
|
-
expect(node.blockMove(mockEvent)).toBe(true)
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
it("returns false when node is not locked", () => {
|
|
181
|
-
const node = new ImageNode(editor, page, {
|
|
182
|
-
id: "node-1",
|
|
183
|
-
x: 0,
|
|
184
|
-
y: 0,
|
|
185
|
-
width: 100,
|
|
186
|
-
height: 100,
|
|
187
|
-
locked: false,
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
const mockEvent = {} as React.PointerEvent
|
|
191
|
-
expect(node.blockMove(mockEvent)).toBe(false)
|
|
192
|
-
})
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
describe("serialization", () => {
|
|
196
|
-
it("serializes required properties", () => {
|
|
197
|
-
const node = new ImageNode(editor, page, {
|
|
198
|
-
id: "node-1",
|
|
199
|
-
x: 10,
|
|
200
|
-
y: 20,
|
|
201
|
-
width: 100,
|
|
202
|
-
height: 50,
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
const serialized = node.serialize()
|
|
206
|
-
|
|
207
|
-
expect(serialized.name).toBe("image")
|
|
208
|
-
expect(serialized.props.id).toBe("node-1")
|
|
209
|
-
expect(serialized.props.x).toBe(10)
|
|
210
|
-
expect(serialized.props.y).toBe(20)
|
|
211
|
-
expect(serialized.props.width).toBe(100)
|
|
212
|
-
expect(serialized.props.height).toBe(50)
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it("omits default optional properties", () => {
|
|
216
|
-
const node = new ImageNode(editor, page, {
|
|
217
|
-
id: "node-1",
|
|
218
|
-
x: 0,
|
|
219
|
-
y: 0,
|
|
220
|
-
width: 100,
|
|
221
|
-
height: 100,
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
const props = node.props()
|
|
225
|
-
|
|
226
|
-
expect(props).not.toHaveProperty("rotation")
|
|
227
|
-
expect(props).not.toHaveProperty("locked")
|
|
228
|
-
expect(props).not.toHaveProperty("css")
|
|
229
|
-
expect(props).not.toHaveProperty("role")
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
it("includes non-default optional properties", () => {
|
|
233
|
-
const node = new ImageNode(editor, page, {
|
|
234
|
-
id: "node-1",
|
|
235
|
-
x: 0,
|
|
236
|
-
y: 0,
|
|
237
|
-
width: 100,
|
|
238
|
-
height: 100,
|
|
239
|
-
rotation: 90,
|
|
240
|
-
locked: true,
|
|
241
|
-
css: "opacity: 0.5;",
|
|
242
|
-
role: ["button"],
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
const props = node.props()
|
|
246
|
-
|
|
247
|
-
expect(props.rotation).toBe(90)
|
|
248
|
-
expect(props.locked).toBe(true)
|
|
249
|
-
expect(props.css).toBe("opacity: 0.5;")
|
|
250
|
-
expect(props.role).toEqual(["button"])
|
|
251
|
-
})
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
describe("deserialization round-trip", () => {
|
|
255
|
-
it("produces identical props after serialize -> deserialize -> serialize", () => {
|
|
256
|
-
const original = new ImageNode(editor, page, {
|
|
257
|
-
id: "node-1",
|
|
258
|
-
x: 50,
|
|
259
|
-
y: 100,
|
|
260
|
-
width: 200,
|
|
261
|
-
height: 150,
|
|
262
|
-
rotation: 30,
|
|
263
|
-
locked: true,
|
|
264
|
-
css: "border: 1px solid red;",
|
|
265
|
-
role: ["logo"],
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
const firstSerialized = original.serialize()
|
|
269
|
-
|
|
270
|
-
const restored = editor.deserializeNode(page, firstSerialized)
|
|
271
|
-
const secondSerialized = restored.serialize()
|
|
272
|
-
|
|
273
|
-
expect(secondSerialized).toEqual(firstSerialized)
|
|
274
|
-
})
|
|
275
|
-
})
|
|
276
|
-
})
|
package/tests/model/page.test.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest"
|
|
2
|
-
import { Page } from "../../lib/model/page"
|
|
3
|
-
import { createTestEditor } from "../createTestEditor"
|
|
4
|
-
|
|
5
|
-
describe("Page", () => {
|
|
6
|
-
let editor: ReturnType<typeof createTestEditor>
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
editor = createTestEditor()
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
describe("construction", () => {
|
|
13
|
-
it("creates a page with required id", () => {
|
|
14
|
-
const page = new Page(editor, { id: "page-1" })
|
|
15
|
-
expect(page.id).toBe("page-1")
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it("applies default dimensions (A4 landscape)", () => {
|
|
19
|
-
const page = new Page(editor, { id: "page-1" })
|
|
20
|
-
expect(page.width).toBe(841)
|
|
21
|
-
expect(page.height).toBe(595)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it("applies default white background", () => {
|
|
25
|
-
const page = new Page(editor, { id: "page-1" })
|
|
26
|
-
expect(page.background).toBe("#ffffff")
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it("accepts custom dimensions", () => {
|
|
30
|
-
const page = new Page(editor, { id: "page-1", width: 1920, height: 1080 })
|
|
31
|
-
expect(page.width).toBe(1920)
|
|
32
|
-
expect(page.height).toBe(1080)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it("accepts custom background", () => {
|
|
36
|
-
const page = new Page(editor, { id: "page-1", background: "#ff0000" })
|
|
37
|
-
expect(page.background).toBe("#ff0000")
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it("initializes with empty nodes map", () => {
|
|
41
|
-
const page = new Page(editor, { id: "page-1" })
|
|
42
|
-
expect(page.nodes.size).toBe(0)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it("initializes with empty snapLines", () => {
|
|
46
|
-
const page = new Page(editor, { id: "page-1" })
|
|
47
|
-
expect(page.snapLines).toEqual([])
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
describe("serialization", () => {
|
|
52
|
-
it("serializes all page properties", () => {
|
|
53
|
-
const page = new Page(editor, {
|
|
54
|
-
id: "page-1",
|
|
55
|
-
width: 800,
|
|
56
|
-
height: 600,
|
|
57
|
-
background: "#cccccc",
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
const serialized = page.serialize()
|
|
61
|
-
|
|
62
|
-
expect(serialized).toEqual({
|
|
63
|
-
id: "page-1",
|
|
64
|
-
width: 800,
|
|
65
|
-
height: 600,
|
|
66
|
-
background: "#cccccc",
|
|
67
|
-
nodes: [],
|
|
68
|
-
})
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it("serializes with default values", () => {
|
|
72
|
-
const page = new Page(editor, { id: "page-1" })
|
|
73
|
-
const serialized = page.serialize()
|
|
74
|
-
|
|
75
|
-
expect(serialized).toEqual({
|
|
76
|
-
id: "page-1",
|
|
77
|
-
width: 841,
|
|
78
|
-
height: 595,
|
|
79
|
-
background: "#ffffff",
|
|
80
|
-
nodes: [],
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
it("serializes contained nodes", () => {
|
|
85
|
-
const page = new Page(editor, { id: "page-1" })
|
|
86
|
-
|
|
87
|
-
// Add a node via the editor's deserialize method
|
|
88
|
-
const node = editor.deserializeNode(page, {
|
|
89
|
-
name: "image",
|
|
90
|
-
props: { id: "img-1", x: 10, y: 20, width: 100, height: 100 },
|
|
91
|
-
})
|
|
92
|
-
page.nodes = new Map([["img-1", node]])
|
|
93
|
-
|
|
94
|
-
const serialized = page.serialize()
|
|
95
|
-
|
|
96
|
-
expect(serialized.nodes).toHaveLength(1)
|
|
97
|
-
expect(serialized.nodes[0].name).toBe("image")
|
|
98
|
-
expect(serialized.nodes[0].props.id).toBe("img-1")
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
describe("deserialization round-trip", () => {
|
|
103
|
-
it("produces identical output after serialize -> load -> serialize", () => {
|
|
104
|
-
const page = new Page(editor, {
|
|
105
|
-
id: "page-1",
|
|
106
|
-
width: 1024,
|
|
107
|
-
height: 768,
|
|
108
|
-
background: "#f0f0f0",
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
// Add nodes
|
|
112
|
-
const node = editor.deserializeNode(page, {
|
|
113
|
-
name: "image",
|
|
114
|
-
props: {
|
|
115
|
-
id: "img-1",
|
|
116
|
-
x: 50,
|
|
117
|
-
y: 100,
|
|
118
|
-
width: 200,
|
|
119
|
-
height: 150,
|
|
120
|
-
url: "https://example.com/image.png",
|
|
121
|
-
fit: "cover",
|
|
122
|
-
roundness: 10,
|
|
123
|
-
borderWidth: 2,
|
|
124
|
-
borderColor: "#333333",
|
|
125
|
-
},
|
|
126
|
-
})
|
|
127
|
-
page.nodes = new Map([["img-1", node]])
|
|
128
|
-
|
|
129
|
-
const firstSerialized = page.serialize()
|
|
130
|
-
|
|
131
|
-
// Create new page from serialized data
|
|
132
|
-
const restoredPage = new Page(editor, {
|
|
133
|
-
id: firstSerialized.id,
|
|
134
|
-
width: firstSerialized.width,
|
|
135
|
-
height: firstSerialized.height,
|
|
136
|
-
background: firstSerialized.background,
|
|
137
|
-
})
|
|
138
|
-
restoredPage.nodes = new Map(
|
|
139
|
-
firstSerialized.nodes.map((n) => [
|
|
140
|
-
n.props.id,
|
|
141
|
-
editor.deserializeNode(restoredPage, n),
|
|
142
|
-
]),
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
const secondSerialized = restoredPage.serialize()
|
|
146
|
-
|
|
147
|
-
expect(secondSerialized).toEqual(firstSerialized)
|
|
148
|
-
})
|
|
149
|
-
})
|
|
150
|
-
})
|
package/tests/setup.ts
DELETED
package/tsconfig.json
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ESNext", "DOM"],
|
|
6
|
-
"types": ["vite/client"],
|
|
7
|
-
"skipLibCheck": true,
|
|
8
|
-
|
|
9
|
-
"moduleResolution": "Bundler",
|
|
10
|
-
"verbatimModuleSyntax": true,
|
|
11
|
-
"noEmit": true,
|
|
12
|
-
"jsx": "react-jsx",
|
|
13
|
-
|
|
14
|
-
"strict": true,
|
|
15
|
-
"noUnusedLocals": true,
|
|
16
|
-
"noUnusedParameters": true,
|
|
17
|
-
"erasableSyntaxOnly": true,
|
|
18
|
-
"noFallthroughCasesInSwitch": true,
|
|
19
|
-
"noUncheckedSideEffectImports": true,
|
|
20
|
-
|
|
21
|
-
"paths": {
|
|
22
|
-
"@lazlon/html-editor/ui": ["./lib/ui/index.ts"],
|
|
23
|
-
"@lazlon/html-editor/model": ["./lib/model/index.ts"],
|
|
24
|
-
"@lazlon/html-editor/hooks": ["./lib/hooks/index.ts"]
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
"include": ["lib", "demo"]
|
|
28
|
-
}
|
package/vite.config.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vite"
|
|
2
|
-
import react from "@vitejs/plugin-react"
|
|
3
|
-
import tailwindcss from "@tailwindcss/vite"
|
|
4
|
-
import tsconfigPaths from "vite-tsconfig-paths"
|
|
5
|
-
|
|
6
|
-
// https://vite.dev/config/
|
|
7
|
-
export default defineConfig({
|
|
8
|
-
plugins: [react(), tailwindcss(), tsconfigPaths()],
|
|
9
|
-
})
|
package/vitest.config.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vitest/config"
|
|
2
|
-
import react from "@vitejs/plugin-react"
|
|
3
|
-
import tsconfigPaths from "vite-tsconfig-paths"
|
|
4
|
-
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
plugins: [react(), tsconfigPaths()],
|
|
7
|
-
test: {
|
|
8
|
-
globals: true,
|
|
9
|
-
environment: "happy-dom",
|
|
10
|
-
setupFiles: ["./tests/setup.ts"],
|
|
11
|
-
include: ["tests/**/*.test.{ts,tsx}"],
|
|
12
|
-
},
|
|
13
|
-
})
|