Skip to content

packages/core/src/lib/components/regular-polygon.ts

Read as Markdown

This is the source snapshot used to build these API details. View this revision on GitHub.

Back to reference

1 import { definePrimitive } from '../define-primitive.js';
2 import type {
3   PibblEventFocusOptions,
4   PibblEventHandlers,
5   PibblEventParticipationOptions,
6 } from '../events/types.js';
7 import {
8   resolveRegularPolygonGeometry,
9   type RegularPolygonPathOptions,
10 } from '../geometry/regular-polygon.js';
11 import {
12   integerAtLeast,
13   type GeometryErrorFactory,
14 } from '../geometry/validation.js';
15 import {
16   resolveLocalOffset,
17   stripLayoutParticipation,
18 } from '../style/resolve-built-in.js';
19 import { registerOpaqueStyleProperties } from '../style/resolve-dispatch.js';
20 import type {
21   BoxStyle,
22   CursorStyle,
23   LayoutItemStyle,
24   Length,
25   PaintStyle,
26   RoundedCornerStyle,
27 } from '../style/types.js';
28 import type { RenderingContext2D, SystemStyle } from '../types.js';
29 import type { PibblPhysics2DPropExtension } from '../types.js';
30 import { renderPath } from './path.js';
31 import { resolveRoundedCornerStyle } from './rounded-corner-style.js';
32 import {
33   circularPercentageBasis,
34   resolveFiniteShapeNumber,
35   resolveNonnegativeShapeLength,
36   shapeGeometryErrorFactory,
37 } from './shape-style.js';
38 
39 /**
40  * Authored inputs for RegularPolygon, including the declared data and presentation options.
41  *
42  * @see {@link PibblEventHandlers}
43  * @see {@link PibblEventParticipationOptions}
44  * @see {@link PibblPhysics2DPropExtension}
45  * @see {@link RegularPolygon}
46  */
47 export interface RegularPolygonProps
48   extends PibblEventHandlers, PibblEventFocusOptions, PibblEventParticipationOptions, PibblPhysics2DPropExtension {}
49 
50 /**
51  * Center, side count, rotation, and paint shared by regular-polygon size variants.
52  *
53  * @see {@link RegularPolygonStyle}
54  */
55 interface RegularPolygonCommonStyle extends RoundedCornerStyle {
56   /** Number of sides of the regular polygon. See {@link RegularPolygonCommonStyle}. */
57   sides: number;
58   /** Horizontal coordinate of the center. See {@link Length}. */
59   cx?: Exclude<Length, 'auto'>;
60   /** Vertical coordinate of the center. See {@link Length}. */
61   cy?: Exclude<Length, 'auto'>;
62   /** Rotation applied to the containing geometry. See {@link RegularPolygonCommonStyle}. */
63   rotation?: number;
64   /**
65    * Width used for line hit testing independently of the visible stroke width. See
66    * {@link RegularPolygonCommonStyle}.
67    */
68   lineInteractionWidth?: number;
69 }
70 
71 /**
72  * Exactly one declared size measure for a regular polygon.
73  *
74  * @see {@link RegularPolygonStyle}
75  */
76 type RegularPolygonSizeStyle =
77   | {
78       /** Distance from the polygon center to a vertex. See {@link Length}. */
79       circumradius: Exclude<Length, 'auto'>;
80       /**
81        * Not accepted in this variant; use the alternative fields instead. See
82        * {@link RegularPolygonSizeStyle}.
83        */
84       inradius?: never;
85       /**
86        * Not accepted in this variant; use the alternative fields instead. See
87        * {@link RegularPolygonSizeStyle}.
88        */
89       sideLength?: never;
90     }
91   | {
92       /**
93        * Not accepted in this variant; use the alternative fields instead. See
94        * {@link RegularPolygonSizeStyle}.
95        */
96       circumradius?: never;
97       /** Distance from the polygon center to an edge. See {@link Length}. */
98       inradius: Exclude<Length, 'auto'>;
99       /**
100        * Not accepted in this variant; use the alternative fields instead. See
101        * {@link RegularPolygonSizeStyle}.
102        */
103       sideLength?: never;
104     }
105   | {
106       /**
107        * Not accepted in this variant; use the alternative fields instead. See
108        * {@link RegularPolygonSizeStyle}.
109        */
110       circumradius?: never;
111       /**
112        * Not accepted in this variant; use the alternative fields instead. See
113        * {@link RegularPolygonSizeStyle}.
114        */
115       inradius?: never;
116       /** Length of one polygon edge. See {@link Length}. */
117       sideLength: Exclude<Length, 'auto'>;
118     };
119 
120 /**
121  * Supported geometry and presentation properties for RegularPolygon.
122  *
123  * @see {@link SystemStyle}
124  * @see {@link PaintStyle}
125  * @see {@link CursorStyle}
126  * @see {@link BoxStyle}
127  * @see {@link LayoutItemStyle}
128  * @see {@link RegularPolygon}
129  */
130 export type RegularPolygonStyle = RegularPolygonCommonStyle &
131   RegularPolygonSizeStyle &
132   SystemStyle &
133   PaintStyle &
134   CursorStyle &
135   BoxStyle &
136   LayoutItemStyle;
137 
138 interface ResolvedRegularPolygonStyle
139   extends SystemStyle, PaintStyle, CursorStyle {
140   sides: number;
141   cx: number;
142   cy: number;
143   rotation: number;
144   circumradius?: number;
145   inradius?: number;
146   sideLength?: number;
147   cornerRadius?: number;
148   cornerRadii?: readonly (number | null | undefined)[];
149   lineInteractionWidth?: number;
150   geometryErrorFactory: GeometryErrorFactory;
151 }
152 
153 function renderRegularPolygon(
154   props: RegularPolygonProps,
155   style: Readonly<ResolvedRegularPolygonStyle>,
156   ctx: RenderingContext2D,
157 ) {
158   const {
159     sides,
160     cx,
161     cy,
162     rotation,
163     circumradius,
164     inradius,
165     sideLength,
166     cornerRadius,
167     cornerRadii,
168     geometryErrorFactory,
169     ...pathStyle
170   } = style;
171   const geometry = resolveRegularPolygonGeometry({
172     sides,
173     cx,
174     cy,
175     rotation,
176     ...(circumradius === undefined ? {} : { circumradius }),
177     ...(inradius === undefined ? {} : { inradius }),
178     ...(sideLength === undefined ? {} : { sideLength }),
179     cornerRadius,
180     cornerRadii,
181   } as RegularPolygonPathOptions, geometryErrorFactory);
182 
183   return renderPath({
184     ...props,
185     keyboardNavigationBounds: props.keyboardNavigationBounds ?? geometry.bounds,
186   }, {
187     ...pathStyle,
188     d: geometry.path,
189   }, ctx);
190 }
191 
192 /**
193  * Describes a regular-polygon primitive for JSX or createElement authoring.
194  *
195  * @param props - Authored component inputs, supplied through JSX or createElement. See the linked
196  * props and style types.
197  * @throws When called directly; Pibbl mounts this component through JSX or createElement.
198  *
199  * @see {@link RegularPolygonProps}
200  * @see {@link RegularPolygonStyle}
201  */
202 export const RegularPolygon = definePrimitive<
203   RegularPolygonProps,
204   RegularPolygonStyle,
205   RegularPolygonStyle,
206   ResolvedRegularPolygonStyle
207 >(renderRegularPolygon, {
208   resolveStyle: (style, context) => {
209     const errorFactory = shapeGeometryErrorFactory(context);
210     const sides = integerAtLeast(style.sides, 3, 'sides', errorFactory);
211     const basis = circularPercentageBasis(context);
212     return {
213       ...stripLayoutParticipation(style),
214       sides,
215       cx: resolveLocalOffset(
216         style.cx,
217         context.percentageBasis.width,
218         'cx',
219         context,
220       ),
221       cy: resolveLocalOffset(
222         style.cy,
223         context.percentageBasis.height,
224         'cy',
225         context,
226       ),
227       rotation: resolveFiniteShapeNumber(
228         style.rotation ?? -Math.PI / 2,
229         'rotation',
230         context,
231       ),
232       ...(style.circumradius === undefined ? {} : {
233         circumradius: resolveNonnegativeShapeLength(
234           style.circumradius,
235           basis,
236           'circumradius',
237           context,
238         ),
239       }),
240       ...(style.inradius === undefined ? {} : {
241         inradius: resolveNonnegativeShapeLength(
242           style.inradius,
243           basis,
244           'inradius',
245           context,
246         ),
247       }),
248       ...(style.sideLength === undefined ? {} : {
249         sideLength: resolveNonnegativeShapeLength(
250           style.sideLength,
251           basis,
252           'sideLength',
253           context,
254         ),
255       }),
256       ...resolveRoundedCornerStyle(sides, style, context),
257       geometryErrorFactory: errorFactory,
258     } as ResolvedRegularPolygonStyle;
259   },
260 });
261 registerOpaqueStyleProperties(RegularPolygon, ['fill', 'stroke', 'cursor']);
262 

Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.