@lazlon-platform/html-editor 0.5.0 → 0.7.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/lib/hooks/actions.ts +136 -87
- package/lib/hooks/batch.ts +24 -10
- package/lib/hooks/index.ts +7 -6
- package/lib/hooks/page.ts +2 -4
- package/lib/hooks/pointer/useMovePoint.ts +100 -0
- package/lib/hooks/pointer/{moveable.ts → useMoveable.ts} +47 -39
- package/lib/hooks/pointer/{pointer.ts → usePointer.ts} +4 -5
- package/lib/hooks/pointer/useResize/index.ts +31 -0
- package/lib/hooks/pointer/useResize/multi.ts +161 -0
- package/lib/hooks/pointer/useResize/multiLineNode.ts +99 -0
- package/lib/hooks/pointer/useResize/multiRegularNode.ts +109 -0
- package/lib/hooks/pointer/useResize/multiTextNode.ts +108 -0
- package/lib/hooks/pointer/useResize/singleRegularNode.ts +91 -0
- package/lib/hooks/pointer/useResize/singleTextNode.ts +115 -0
- package/lib/hooks/pointer/useRotation.ts +102 -0
- package/lib/hooks/pointer/{selector.ts → useSelector.ts} +18 -3
- package/lib/hooks/pointer/{snap.ts → useSnap.ts} +5 -4
- package/lib/hooks/{pointer/selectionFrame.ts → selectionFrame.ts} +9 -6
- package/lib/hooks/textMarks.ts +30 -21
- package/lib/lib/googleFonts.ts +1 -5
- package/lib/model/editor.ts +31 -13
- package/lib/model/geometry/math.ts +128 -1
- package/lib/model/history.ts +10 -13
- package/lib/model/index.ts +15 -10
- package/lib/model/node/{editable → editableNode}/index.ts +13 -29
- package/lib/model/node/{formattable.ts → formattableNode/index.ts} +5 -11
- package/lib/model/node/{group.ts → groupNode.ts} +9 -13
- package/lib/model/node/{image.ts → imageNode.ts} +6 -12
- package/lib/model/node/lineNode.ts +80 -0
- package/lib/model/node/{shape/shape.ts → shapeNode/index.ts} +30 -15
- package/lib/model/node/shapeNode/shape.ts +96 -0
- package/lib/model/node/{text.ts → textNode.ts} +9 -24
- package/lib/model/node.ts +27 -32
- package/lib/model/page.ts +4 -4
- package/lib/model/traversal.ts +1 -1
- package/lib/ui/extractor.ts +3 -3
- package/lib/ui/index.ts +2 -4
- package/lib/ui/node/{EditableContent.tsx → EditableContent/index.tsx} +10 -7
- package/lib/ui/node/GroupContent.tsx +1 -1
- package/lib/ui/node/ImageContent.tsx +1 -1
- package/lib/ui/node/LineContent.tsx +30 -0
- package/lib/ui/node/ShapeContent/ArrowContent.tsx +57 -0
- package/lib/ui/node/ShapeContent/EllipseContent.tsx +37 -0
- package/lib/ui/node/ShapeContent/PolygonContent.tsx +62 -0
- package/lib/ui/node/ShapeContent/RectangleContent.tsx +35 -0
- package/lib/ui/node/ShapeContent/StarContent.tsx +75 -0
- package/lib/ui/node/ShapeContent/index.tsx +43 -0
- package/lib/ui/node/TextContent.tsx +1 -1
- package/lib/ui/selection.ts +6 -5
- package/package.json +1 -1
- package/lib/hooks/pointer/resize.ts +0 -247
- package/lib/hooks/pointer/rotation.ts +0 -103
- package/lib/model/node/shape/arrow.ts +0 -50
- package/lib/model/node/shape/ellipse.ts +0 -26
- package/lib/model/node/shape/polygon.ts +0 -130
- package/lib/model/node/shape/star.ts +0 -91
- package/lib/ui/node/ArrowContent.tsx +0 -60
- package/lib/ui/node/EllipseContent.tsx +0 -49
- package/lib/ui/node/PolygonContent.tsx +0 -81
- package/lib/ui/node/StarContent.tsx +0 -60
- /package/lib/model/node/{editable → editableNode}/letterSpacing.ts +0 -0
- /package/lib/model/node/{editable → editableNode}/persistentMarks.ts +0 -0
- /package/lib/model/node/{editable → editableNode}/tiptapExtensions.ts +0 -0
- /package/lib/ui/node/{useDoubleClick.ts → EditableContent/useDoubleClick.ts} +0 -0
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { computed, state } from "react-bolt"
|
|
2
|
-
import type { Editor } from "../../editor"
|
|
3
|
-
import type { Point } from "../../geometry/math"
|
|
4
|
-
import { roundedPathData } from "../../geometry/svg"
|
|
5
|
-
import type { SerializedNode } from "../../node"
|
|
6
|
-
import type { Page } from "../../page"
|
|
7
|
-
import { ShapeNode, type ShapeNodeProps } from "./shape"
|
|
8
|
-
|
|
9
|
-
export type PolygonNodeProps = ShapeNodeProps &
|
|
10
|
-
Partial<
|
|
11
|
-
Pick<
|
|
12
|
-
PolygonNode,
|
|
13
|
-
| "roundness"
|
|
14
|
-
| "sides"
|
|
15
|
-
| "cornerTopLeft"
|
|
16
|
-
| "cornerTopRight"
|
|
17
|
-
| "cornerBottomLeft"
|
|
18
|
-
| "cornerBottomRight"
|
|
19
|
-
>
|
|
20
|
-
>
|
|
21
|
-
|
|
22
|
-
export class PolygonNode extends ShapeNode {
|
|
23
|
-
get name() {
|
|
24
|
-
return "polygon"
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@state private accessor _roundness: number
|
|
28
|
-
@state accessor sides: number
|
|
29
|
-
|
|
30
|
-
// rectangles are special cased where they support by corner rounding
|
|
31
|
-
@state accessor cornerTopLeft: number
|
|
32
|
-
@state accessor cornerTopRight: number
|
|
33
|
-
@state accessor cornerBottomLeft: number
|
|
34
|
-
@state accessor cornerBottomRight: number
|
|
35
|
-
|
|
36
|
-
set roundness(r: number) {
|
|
37
|
-
if (this.sides === 4) {
|
|
38
|
-
this.cornerTopLeft = r
|
|
39
|
-
this.cornerTopRight = r
|
|
40
|
-
this.cornerBottomLeft = r
|
|
41
|
-
this.cornerBottomRight = r
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this._roundness = r
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
@computed get roundness() {
|
|
48
|
-
if (this.sides === 4) {
|
|
49
|
-
const [first, ...radii] = [
|
|
50
|
-
this.cornerTopLeft,
|
|
51
|
-
this.cornerTopRight,
|
|
52
|
-
this.cornerBottomLeft,
|
|
53
|
-
this.cornerBottomRight,
|
|
54
|
-
]
|
|
55
|
-
|
|
56
|
-
return radii.reduce((acc, it) => (it === acc ? acc : 0), first)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return this._roundness
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
constructor(
|
|
63
|
-
editor: Editor,
|
|
64
|
-
page: Page,
|
|
65
|
-
{
|
|
66
|
-
sides,
|
|
67
|
-
cornerTopLeft,
|
|
68
|
-
cornerTopRight,
|
|
69
|
-
cornerBottomLeft,
|
|
70
|
-
cornerBottomRight,
|
|
71
|
-
roundness = 0,
|
|
72
|
-
...props
|
|
73
|
-
}: PolygonNodeProps,
|
|
74
|
-
) {
|
|
75
|
-
super(editor, page, props)
|
|
76
|
-
this._roundness = roundness
|
|
77
|
-
this.sides = sides ?? 4
|
|
78
|
-
this.cornerTopLeft = cornerTopLeft ?? roundness
|
|
79
|
-
this.cornerTopRight = cornerTopRight ?? roundness
|
|
80
|
-
this.cornerBottomLeft = cornerBottomLeft ?? roundness
|
|
81
|
-
this.cornerBottomRight = cornerBottomRight ?? roundness
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
props(): PolygonNodeProps {
|
|
85
|
-
return {
|
|
86
|
-
...super.props(),
|
|
87
|
-
sides: this.sides,
|
|
88
|
-
cornerTopLeft: this.cornerTopLeft,
|
|
89
|
-
cornerTopRight: this.cornerTopRight,
|
|
90
|
-
cornerBottomLeft: this.cornerBottomLeft,
|
|
91
|
-
cornerBottomRight: this.cornerBottomRight,
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
serialize(): SerializedNode<this["name"], PolygonNodeProps> {
|
|
96
|
-
return super.serialize()
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
@computed get svgPathData() {
|
|
100
|
-
return roundedPathData(
|
|
101
|
-
regularPolygonPoints({
|
|
102
|
-
width: this.width,
|
|
103
|
-
height: this.height,
|
|
104
|
-
sides: this.sides,
|
|
105
|
-
}),
|
|
106
|
-
this._roundness,
|
|
107
|
-
)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function regularPolygonPoints(props: {
|
|
112
|
-
width: number
|
|
113
|
-
height: number
|
|
114
|
-
sides: number
|
|
115
|
-
}): Point[] {
|
|
116
|
-
const { width, height, sides } = props
|
|
117
|
-
const rotation = sides % 2 === 0 ? Math.PI / sides : 0
|
|
118
|
-
const cx = width / 2
|
|
119
|
-
const cy = height / 2
|
|
120
|
-
const rx = width / 2
|
|
121
|
-
const ry = height / 2
|
|
122
|
-
|
|
123
|
-
return Array.from({ length: sides }, (_, i) => {
|
|
124
|
-
const angle = (i * Math.PI * 2) / sides - Math.PI / 2 + rotation
|
|
125
|
-
return {
|
|
126
|
-
x: cx + rx * Math.cos(angle),
|
|
127
|
-
y: cy + ry * Math.sin(angle),
|
|
128
|
-
}
|
|
129
|
-
})
|
|
130
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { computed, state } from "react-bolt"
|
|
2
|
-
import type { Editor } from "../../editor"
|
|
3
|
-
import type { SerializedNode } from "../../node"
|
|
4
|
-
import type { Page } from "../../page"
|
|
5
|
-
import { ShapeNode, type ShapeNodeProps } from "./shape"
|
|
6
|
-
import { clamp, type Point } from "../../geometry/math"
|
|
7
|
-
import { roundedPathData } from "../../geometry/svg"
|
|
8
|
-
|
|
9
|
-
export type StarNodeProps = ShapeNodeProps &
|
|
10
|
-
Partial<Pick<StarNode, "corners" | "roundness" | "depth">>
|
|
11
|
-
|
|
12
|
-
export class StarNode extends ShapeNode {
|
|
13
|
-
get name() {
|
|
14
|
-
return "star"
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
@state accessor corners: number
|
|
18
|
-
@state accessor roundness: number
|
|
19
|
-
@state private accessor _depth: number
|
|
20
|
-
|
|
21
|
-
@computed get depth() {
|
|
22
|
-
return this._depth
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
set depth(value: number) {
|
|
26
|
-
this._depth = clamp(value, 0, 1)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
constructor(
|
|
30
|
-
editor: Editor,
|
|
31
|
-
page: Page,
|
|
32
|
-
{ corners = 5, roundness = 0, depth = 0.4, ...props }: StarNodeProps,
|
|
33
|
-
) {
|
|
34
|
-
super(editor, page, props)
|
|
35
|
-
this.corners = corners
|
|
36
|
-
this.roundness = roundness
|
|
37
|
-
this._depth = clamp(depth, 0, 1)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
props(): StarNodeProps {
|
|
41
|
-
return {
|
|
42
|
-
...super.props(),
|
|
43
|
-
corners: this.corners,
|
|
44
|
-
roundness: this.roundness,
|
|
45
|
-
depth: this.depth,
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
serialize(): SerializedNode<this["name"], StarNodeProps> {
|
|
50
|
-
return super.serialize()
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@computed get svgPathData() {
|
|
54
|
-
return roundedPathData(
|
|
55
|
-
starPoints({
|
|
56
|
-
width: this.width,
|
|
57
|
-
height: this.height,
|
|
58
|
-
corners: this.corners,
|
|
59
|
-
depth: this.depth,
|
|
60
|
-
}),
|
|
61
|
-
this.roundness,
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function starPoints(props: {
|
|
67
|
-
width: number
|
|
68
|
-
height: number
|
|
69
|
-
corners: number
|
|
70
|
-
depth: number
|
|
71
|
-
}): Point[] {
|
|
72
|
-
const { width, height, corners, depth } = props
|
|
73
|
-
const cx = width / 2
|
|
74
|
-
const cy = height / 2
|
|
75
|
-
const outerRx = width / 2
|
|
76
|
-
const outerRy = height / 2
|
|
77
|
-
const innerRx = outerRx * depth
|
|
78
|
-
const innerRy = outerRy * depth
|
|
79
|
-
|
|
80
|
-
return Array.from({ length: corners * 2 }, (_, i) => {
|
|
81
|
-
const angle = (i * Math.PI) / corners - Math.PI / 2
|
|
82
|
-
const isOuter = i % 2 === 0
|
|
83
|
-
const rx = isOuter ? outerRx : innerRx
|
|
84
|
-
const ry = isOuter ? outerRy : innerRy
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
x: cx + rx * Math.cos(angle),
|
|
88
|
-
y: cy + ry * Math.sin(angle),
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import clsx from "clsx"
|
|
2
|
-
import { useId } from "react"
|
|
3
|
-
import { useStore } from "react-bolt"
|
|
4
|
-
import { type ArrowNode } from "../../model/node/shape/arrow"
|
|
5
|
-
import { EditableContent } from "./EditableContent"
|
|
6
|
-
|
|
7
|
-
export function ArrowContent(props: { node: ArrowNode; isStatic?: boolean }) {
|
|
8
|
-
const maskId = useId()
|
|
9
|
-
const { node, isStatic } = props
|
|
10
|
-
|
|
11
|
-
const [valign, halign, background, borderWidth, borderColor] = useStore(
|
|
12
|
-
node,
|
|
13
|
-
"valign",
|
|
14
|
-
"halign",
|
|
15
|
-
"background",
|
|
16
|
-
"borderWidth",
|
|
17
|
-
"borderColor",
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
const [w, h, d] = useStore(node, "width", "height", "svgPathData")
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<div className="relative size-full">
|
|
24
|
-
<svg width={w} height={h} className="absolute inset-0">
|
|
25
|
-
<defs>
|
|
26
|
-
<mask id={maskId} maskUnits="userSpaceOnUse">
|
|
27
|
-
<path d={d} fill="white" />
|
|
28
|
-
</mask>
|
|
29
|
-
</defs>
|
|
30
|
-
|
|
31
|
-
<path d={d} fill={background} />
|
|
32
|
-
<path
|
|
33
|
-
d={d}
|
|
34
|
-
fill="none"
|
|
35
|
-
stroke={borderColor}
|
|
36
|
-
strokeWidth={borderWidth}
|
|
37
|
-
mask={`url(#${maskId})`}
|
|
38
|
-
/>
|
|
39
|
-
</svg>
|
|
40
|
-
<div
|
|
41
|
-
className={clsx(
|
|
42
|
-
"flex size-full",
|
|
43
|
-
valign === "top" && "items-start",
|
|
44
|
-
valign === "center" && "items-center",
|
|
45
|
-
valign === "bottom" && "items-end",
|
|
46
|
-
halign === "left" && "justify-start text-left",
|
|
47
|
-
halign === "center" && "justify-center text-center",
|
|
48
|
-
halign === "right" && "justify-end text-right",
|
|
49
|
-
halign === "justify" && "w-full text-justify",
|
|
50
|
-
)}
|
|
51
|
-
>
|
|
52
|
-
<EditableContent
|
|
53
|
-
isStatic={isStatic}
|
|
54
|
-
node={node}
|
|
55
|
-
className={clsx(halign === "justify" && "w-full")}
|
|
56
|
-
/>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import clsx from "clsx"
|
|
2
|
-
import { useStore } from "react-bolt"
|
|
3
|
-
import { type EllipseNode } from "../../model/node/shape/ellipse"
|
|
4
|
-
import { EditableContent } from "./EditableContent"
|
|
5
|
-
|
|
6
|
-
export function EllipseContent(props: { node: EllipseNode; isStatic?: boolean }) {
|
|
7
|
-
const { node, isStatic } = props
|
|
8
|
-
|
|
9
|
-
const [valign, halign, background, borderWidth, borderColor] = useStore(
|
|
10
|
-
node,
|
|
11
|
-
"valign",
|
|
12
|
-
"halign",
|
|
13
|
-
"background",
|
|
14
|
-
"borderWidth",
|
|
15
|
-
"borderColor",
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div className="relative size-full">
|
|
20
|
-
<div
|
|
21
|
-
className="absolute inset-0 size-full"
|
|
22
|
-
onDragStart={(e) => e.preventDefault()}
|
|
23
|
-
style={{
|
|
24
|
-
borderRadius: "50%",
|
|
25
|
-
background,
|
|
26
|
-
border: `${borderWidth}px solid ${borderColor}`,
|
|
27
|
-
}}
|
|
28
|
-
/>
|
|
29
|
-
<div
|
|
30
|
-
className={clsx(
|
|
31
|
-
"flex size-full",
|
|
32
|
-
valign === "top" && "items-start",
|
|
33
|
-
valign === "center" && "items-center",
|
|
34
|
-
valign === "bottom" && "items-end",
|
|
35
|
-
halign === "left" && "justify-start text-left",
|
|
36
|
-
halign === "center" && "justify-center text-center",
|
|
37
|
-
halign === "right" && "justify-end text-right",
|
|
38
|
-
halign === "justify" && "w-full text-justify",
|
|
39
|
-
)}
|
|
40
|
-
>
|
|
41
|
-
<EditableContent
|
|
42
|
-
isStatic={isStatic}
|
|
43
|
-
node={node}
|
|
44
|
-
className={clsx(halign === "justify" && "w-full")}
|
|
45
|
-
/>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import clsx from "clsx"
|
|
2
|
-
import { useId } from "react"
|
|
3
|
-
import { useStore } from "react-bolt"
|
|
4
|
-
import { type PolygonNode } from "../../model/node/shape/polygon"
|
|
5
|
-
import { EditableContent } from "./EditableContent"
|
|
6
|
-
|
|
7
|
-
export function PolygonContent(props: { node: PolygonNode; isStatic?: boolean }) {
|
|
8
|
-
const maskId = useId()
|
|
9
|
-
const { node, isStatic } = props
|
|
10
|
-
|
|
11
|
-
const [valign, halign, background, borderWidth, borderColor, sides] = useStore(
|
|
12
|
-
node,
|
|
13
|
-
"valign",
|
|
14
|
-
"halign",
|
|
15
|
-
"background",
|
|
16
|
-
"borderWidth",
|
|
17
|
-
"borderColor",
|
|
18
|
-
"sides",
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
const [w, h, d] = useStore(node, "width", "height", "svgPathData")
|
|
22
|
-
|
|
23
|
-
const radii = useStore(
|
|
24
|
-
node,
|
|
25
|
-
"cornerTopLeft",
|
|
26
|
-
"cornerTopRight",
|
|
27
|
-
"cornerBottomRight",
|
|
28
|
-
"cornerBottomLeft",
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<div className="relative size-full">
|
|
33
|
-
{sides !== 4 ? (
|
|
34
|
-
<svg width={w} height={h} className="absolute inset-0">
|
|
35
|
-
<defs>
|
|
36
|
-
<mask id={maskId} maskUnits="userSpaceOnUse">
|
|
37
|
-
<path d={d} fill="white" />
|
|
38
|
-
</mask>
|
|
39
|
-
</defs>
|
|
40
|
-
|
|
41
|
-
<path d={d} fill={background} />
|
|
42
|
-
<path
|
|
43
|
-
d={d}
|
|
44
|
-
fill="none"
|
|
45
|
-
stroke={borderColor}
|
|
46
|
-
strokeWidth={borderWidth}
|
|
47
|
-
mask={`url(#${maskId})`}
|
|
48
|
-
/>
|
|
49
|
-
</svg>
|
|
50
|
-
) : (
|
|
51
|
-
<div
|
|
52
|
-
className="absolute inset-0 size-full"
|
|
53
|
-
onDragStart={(e) => e.preventDefault()}
|
|
54
|
-
style={{
|
|
55
|
-
borderRadius: radii.map((r) => `${r}px`).join(" "),
|
|
56
|
-
background: background,
|
|
57
|
-
border: `${borderWidth}px solid ${borderColor}`,
|
|
58
|
-
}}
|
|
59
|
-
/>
|
|
60
|
-
)}
|
|
61
|
-
<div
|
|
62
|
-
className={clsx(
|
|
63
|
-
"flex size-full",
|
|
64
|
-
valign === "top" && "items-start",
|
|
65
|
-
valign === "center" && "items-center",
|
|
66
|
-
valign === "bottom" && "items-end",
|
|
67
|
-
halign === "left" && "justify-start text-left",
|
|
68
|
-
halign === "center" && "justify-center text-center",
|
|
69
|
-
halign === "right" && "justify-end text-right",
|
|
70
|
-
halign === "justify" && "w-full text-justify",
|
|
71
|
-
)}
|
|
72
|
-
>
|
|
73
|
-
<EditableContent
|
|
74
|
-
isStatic={isStatic}
|
|
75
|
-
node={node}
|
|
76
|
-
className={clsx(halign === "justify" && "w-full")}
|
|
77
|
-
/>
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
)
|
|
81
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import clsx from "clsx"
|
|
2
|
-
import { useId } from "react"
|
|
3
|
-
import { useStore } from "react-bolt"
|
|
4
|
-
import { type StarNode } from "../../model/node/shape/star"
|
|
5
|
-
import { EditableContent } from "./EditableContent"
|
|
6
|
-
|
|
7
|
-
export function StarContent(props: { node: StarNode; isStatic?: boolean }) {
|
|
8
|
-
const maskId = useId()
|
|
9
|
-
const { node, isStatic } = props
|
|
10
|
-
|
|
11
|
-
const [valign, halign, background, borderWidth, borderColor] = useStore(
|
|
12
|
-
node,
|
|
13
|
-
"valign",
|
|
14
|
-
"halign",
|
|
15
|
-
"background",
|
|
16
|
-
"borderWidth",
|
|
17
|
-
"borderColor",
|
|
18
|
-
)
|
|
19
|
-
const [w, h, d] = useStore(node, "width", "height", "svgPathData")
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<div className="relative size-full">
|
|
23
|
-
<svg width={w} height={h} className="absolute inset-0">
|
|
24
|
-
<defs>
|
|
25
|
-
<mask id={maskId} maskUnits="userSpaceOnUse">
|
|
26
|
-
<path d={d} fill="white" />
|
|
27
|
-
</mask>
|
|
28
|
-
</defs>
|
|
29
|
-
|
|
30
|
-
<path d={d} fill={background} />
|
|
31
|
-
<path
|
|
32
|
-
d={d}
|
|
33
|
-
fill="none"
|
|
34
|
-
stroke={borderColor}
|
|
35
|
-
strokeWidth={borderWidth}
|
|
36
|
-
mask={`url(#${maskId})`}
|
|
37
|
-
/>
|
|
38
|
-
</svg>
|
|
39
|
-
|
|
40
|
-
<div
|
|
41
|
-
className={clsx(
|
|
42
|
-
"flex size-full",
|
|
43
|
-
valign === "top" && "items-start",
|
|
44
|
-
valign === "center" && "items-center",
|
|
45
|
-
valign === "bottom" && "items-end",
|
|
46
|
-
halign === "left" && "justify-start text-left",
|
|
47
|
-
halign === "center" && "justify-center text-center",
|
|
48
|
-
halign === "right" && "justify-end text-right",
|
|
49
|
-
halign === "justify" && "w-full text-justify",
|
|
50
|
-
)}
|
|
51
|
-
>
|
|
52
|
-
<EditableContent
|
|
53
|
-
isStatic={isStatic}
|
|
54
|
-
node={node}
|
|
55
|
-
className={clsx(halign === "justify" && "w-full")}
|
|
56
|
-
/>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|