packages/core/src/lib/components/line.ts
This is the source snapshot used to build these API details. View this revision on GitHub.
1 import type { HorizontalLineStyle } from './horizontal-line.js';
2 import type { VerticalLineStyle } from './vertical-line.js';
3 import { definePrimitive } from '../define-primitive.js';
4 import type {
5 PibblEventFocusOptions,
6 PibblEventHandlers,
7 PibblEventParticipationOptions,
8 } from '../events/types.js';
9 import {
10 RenderingContext2D,
11 SystemStyle,
12 } from '../types.js';
13 import type { PibblPhysics2DPropExtension } from '../types.js';
14 import { stripLayoutParticipation } from '../style/resolve-built-in.js';
15 import { registerOpaqueStyleProperties } from '../style/resolve-dispatch.js';
16 import type {
17 BoxStyle,
18 CursorStyle,
19 LayoutItemStyle,
20 PaintStyle,
21 ResolvedDrawingStyle,
22 } from '../style/types.js';
23 import { layoutDiagnostic } from '../style/diagnostics.js';
24 import { createLinePath } from '../geometry/line.js';
25 import { validateCoordinates } from '../geometry/validation.js';
26 import type { StyleResolutionContext } from '../types.js';
27 import { renderPath } from './path.js';
28
29 /**
30 * Authored inputs for Line, including the declared data and presentation options.
31 *
32 * @see {@link PibblEventHandlers}
33 * @see {@link PibblEventParticipationOptions}
34 * @see {@link PibblPhysics2DPropExtension}
35 * @see {@link Line}
36 */
37 export interface LineProps extends PibblEventHandlers, PibblEventFocusOptions, PibblEventParticipationOptions, PibblPhysics2DPropExtension {}
38
39 /**
40 * Supported geometry and presentation properties for Line.
41 *
42 * @see {@link SystemStyle}
43 * @see {@link BoxStyle}
44 * @see {@link LayoutItemStyle}
45 * @see {@link PaintStyle}
46 * @see {@link CursorStyle}
47 * @see {@link Line}
48 * @see {@link HorizontalLineStyle}
49 * @see {@link VerticalLineStyle}
50 */
51 export interface LineStyle
52 extends SystemStyle, BoxStyle, LayoutItemStyle, Omit<PaintStyle, 'fill'>, CursorStyle {
53 /** Ordered coordinate pairs describing the path vertices. See {@link LineStyle}. */
54 coords: [number, number][];
55 /**
56 * Width used for line hit testing independently of the visible stroke width. See
57 * {@link LineStyle}.
58 */
59 lineInteractionWidth?: number;
60 }
61
62 type ResolvedLineStyle = ResolvedDrawingStyle<LineStyle>;
63
64 export function renderLine(
65 props: LineProps,
66 style: Readonly<ResolvedLineStyle>,
67 ctx: RenderingContext2D,
68 ) {
69 const {
70 coords,
71 stroke,
72 strokeWidth,
73 opacity,
74 cursor,
75 lineInteractionWidth,
76 } = style;
77 const linePath = createLinePath({ coords });
78 const interactionWidth = lineInteractionWidth ?? strokeWidth ?? 0;
79
80 return renderPath(
81 {
82 ...props,
83 keyboardNavigationBounds: props.keyboardNavigationBounds ??
84 lineBounds(coords, interactionWidth),
85 },
86 {
87 d: linePath,
88 stroke,
89 strokeWidth,
90 opacity,
91 cursor,
92 lineInteractionWidth: interactionWidth,
93 },
94 ctx,
95 );
96 }
97
98 /**
99 * Describes a polyline primitive for JSX or createElement authoring.
100 *
101 * @param props - Authored component inputs, supplied through JSX or createElement. See the linked
102 * props and style types.
103 * @throws When called directly; Pibbl mounts this component through JSX or createElement.
104 *
105 * @see {@link LineProps}
106 * @see {@link LineStyle}
107 */
108 export const Line = definePrimitive<
109 LineProps,
110 LineStyle,
111 LineStyle,
112 ResolvedLineStyle
113 >(renderLine, {
114 resolveStyle: (style, context) => ({
115 ...stripLayoutParticipation(style),
116 coords: validateCoordinates(
117 style.coords,
118 'coords',
119 layoutGeometryErrorFactory(context),
120 ),
121 }) as ResolvedLineStyle,
122 });
123 registerOpaqueStyleProperties(Line, ['stroke', 'cursor']);
124
125 function lineBounds(
126 coords: readonly [number, number][],
127 interactionWidth: number,
128 ) {
129 if (coords.length === 0) return undefined;
130 const halfWidth = interactionWidth / 2;
131 const xs = coords.map(([x]) => x);
132 const ys = coords.map(([, y]) => y);
133 const left = Math.min(...xs) - halfWidth;
134 const right = Math.max(...xs) + halfWidth;
135 const top = Math.min(...ys) - halfWidth;
136 const bottom = Math.max(...ys) + halfWidth;
137 return {
138 x: left,
139 y: top,
140 width: right - left,
141 height: bottom - top,
142 };
143 }
144
145 function layoutGeometryErrorFactory(context: Readonly<StyleResolutionContext>) {
146 return (property: string, value: unknown, reason: string) => layoutDiagnostic({
147 component: context.component,
148 property,
149 value,
150 algorithm: context.algorithm,
151 constraints: context.constraints,
152 reason,
153 });
154 }
155
Documentation version
Section titled “Documentation version”Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.