@lazlon-platform/html-editor 0.3.0 → 0.3.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.
@@ -218,3 +218,30 @@ export function regularPolygonPoints(props: {
218
218
  }
219
219
  })
220
220
  }
221
+
222
+ export function starPoints(props: {
223
+ width: number
224
+ height: number
225
+ corners: number
226
+ depth: number
227
+ }): Point[] {
228
+ const { width, height, corners, depth } = props
229
+ const cx = width / 2
230
+ const cy = height / 2
231
+ const outerRx = width / 2
232
+ const outerRy = height / 2
233
+ const innerRx = outerRx * depth
234
+ const innerRy = outerRy * depth
235
+
236
+ return Array.from({ length: corners * 2 }, (_, i) => {
237
+ const angle = (i * Math.PI) / corners - Math.PI / 2
238
+ const isOuter = i % 2 === 0
239
+ const rx = isOuter ? outerRx : innerRx
240
+ const ry = isOuter ? outerRy : innerRy
241
+
242
+ return {
243
+ x: cx + rx * Math.cos(angle),
244
+ y: cy + ry * Math.sin(angle),
245
+ }
246
+ })
247
+ }
@@ -9,6 +9,7 @@ export { ArrowNode, type ArrowNodeProps } from "./node/shape/arrow"
9
9
  export { EllipseNode, type EllipseNodeProps } from "./node/shape/ellipse"
10
10
  export { PolygonNode, type PolygonNodeProps } from "./node/shape/polygon"
11
11
  export { ShapeNode, type ShapeNodeProps } from "./node/shape/shape"
12
+ export { StarNode, type StarNodeProps } from "./node/shape/star"
12
13
  export { TextNode, type TextNodeProps } from "./node/text"
13
14
  export { Page, type PageProps, type SerializedPage } from "./page"
14
15
  export { flattenNodes } from "./traversal"
@@ -0,0 +1,63 @@
1
+ import { computed, state } from "react-bolt"
2
+ import { clamp, roundedPathData, starPoints } from "../../geometry"
3
+ import type { Editor } from "../../editor"
4
+ import type { SerializedNode } from "../../node"
5
+ import type { Page } from "../../page"
6
+ import { ShapeNode, type ShapeNodeProps } from "./shape"
7
+
8
+ export type StarNodeProps = ShapeNodeProps &
9
+ Partial<Pick<StarNode, "corners" | "roundness" | "depth">>
10
+
11
+ export class StarNode extends ShapeNode {
12
+ get name() {
13
+ return "star"
14
+ }
15
+
16
+ @state accessor corners: number
17
+ @state accessor roundness: number
18
+ @state private accessor _depth: number
19
+
20
+ @computed get depth() {
21
+ return this._depth
22
+ }
23
+
24
+ set depth(value: number) {
25
+ this._depth = clamp(value, 0, 1)
26
+ }
27
+
28
+ constructor(
29
+ editor: Editor,
30
+ page: Page,
31
+ { corners = 5, roundness = 0, depth = 0.4, ...props }: StarNodeProps,
32
+ ) {
33
+ super(editor, page, props)
34
+ this.corners = corners
35
+ this.roundness = roundness
36
+ this._depth = clamp(depth, 0, 1)
37
+ }
38
+
39
+ props(): StarNodeProps {
40
+ return {
41
+ ...super.props(),
42
+ corners: this.corners,
43
+ roundness: this.roundness,
44
+ depth: this.depth,
45
+ }
46
+ }
47
+
48
+ serialize(): SerializedNode<this["name"], StarNodeProps> {
49
+ return super.serialize()
50
+ }
51
+
52
+ @computed get svgPathData() {
53
+ return roundedPathData(
54
+ starPoints({
55
+ width: this.width,
56
+ height: this.height,
57
+ corners: this.corners,
58
+ depth: this.depth,
59
+ }),
60
+ this.roundness,
61
+ )
62
+ }
63
+ }
package/lib/ui/index.ts CHANGED
@@ -7,4 +7,5 @@ export { GroupContent } from "./node/GroupContent"
7
7
  export { ImageContent } from "./node/ImageContent"
8
8
  export { NodeView } from "./node/NodeView"
9
9
  export { PolygonContent } from "./node/PolygonContent"
10
+ export { StarContent } from "./node/StarContent"
10
11
  export { TextContent } from "./node/TextContent"
@@ -0,0 +1,60 @@
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazlon-platform/html-editor",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "lib"