@velinstyle/react 1.1.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/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # @velinstyle/react
2
+
3
+ Official React wrappers around the VelinStyle custom elements. Every canonical
4
+ `velin-*` element has a wrapper — the list is generated from the framework's
5
+ component registry, so the adapter cannot fall behind the elements that ship.
6
+
7
+ There is no re-implementation: each wrapper renders the real custom element and
8
+ forwards refs to it, so accessibility behaviour, keyboard handling and styling
9
+ are identical to the plain HTML usage.
10
+
11
+ ```jsx
12
+ import { useRef } from 'react';
13
+ import { VelinDialog, VelinThemeToggle } from '@velinstyle/react';
14
+ import '@birdapi/velinstyle/css';
15
+ import '@birdapi/velinstyle/bundle';
16
+
17
+ export function App() {
18
+ const dialogRef = useRef(null);
19
+ return (
20
+ <>
21
+ <VelinThemeToggle target="html" />
22
+ <VelinDialog ref={dialogRef} />
23
+ <button type="button" onClick={() => dialogRef.current?.confirm('Continue?')}>
24
+ Open dialog
25
+ </button>
26
+ </>
27
+ );
28
+ }
29
+ ```
30
+
31
+ ## How props are mapped
32
+
33
+ React 18 renders unknown props as string attributes, which turns `open={false}`
34
+ into `open="false"` and stringifies objects. The wrappers avoid both:
35
+
36
+ | Prop value | Applied as |
37
+ | --- | --- |
38
+ | string, number | attribute |
39
+ | boolean | presence attribute (`open` set or removed) |
40
+ | object, array, function | element property |
41
+ | `onVelin*` function | `addEventListener` for the matching custom event |
42
+ | `null` / `undefined` | omitted |
43
+ | `onClick` and other React events | passed to React unchanged |
44
+
45
+ Custom event names are derived from the prop name: `onVelinSearchSelect` binds
46
+ `velin-search-select`.
47
+
48
+ ```jsx
49
+ <VelinSearch
50
+ entries={entries} // element property, not stringified
51
+ open={isOpen} // presence attribute
52
+ onVelinSearchSelect={handleSelect} // custom event listener
53
+ onClick={handleClick} // regular React handler
54
+ />
55
+ ```
56
+
57
+ ## Wrapping additional elements
58
+
59
+ `createVelinComponent` builds a wrapper for any tag, which is useful for custom
60
+ elements built on top of VelinStyle:
61
+
62
+ ```jsx
63
+ import { createVelinComponent } from '@velinstyle/react';
64
+
65
+ const MyWidget = createVelinComponent('my-widget');
66
+ ```
67
+
68
+ ## Build
69
+
70
+ From the repository root:
71
+
72
+ ```bash
73
+ npm run build:react
74
+ ```
75
+
76
+ That regenerates the wrappers from the component registry and bundles the
77
+ package. `react >= 18` is a peer dependency. Framework CI fails if the generated
78
+ wrappers are out of date, which keeps new components from shipping without one.
@@ -0,0 +1,86 @@
1
+ /**
2
+ * AUTO-GENERATED — run: node scripts/generate-react-wrappers.mjs
3
+ */
4
+ import type { ComponentType, CSSProperties, ReactNode, Ref } from 'react';
5
+
6
+ /**
7
+ * Props accepted by every wrapper. Scalars become attributes, booleans become
8
+ * presence attributes, objects and arrays are assigned as element properties,
9
+ * and `onVelin*` handlers are bound as custom-event listeners.
10
+ */
11
+ export interface VelinComponentProps {
12
+ children?: ReactNode;
13
+ className?: string;
14
+ style?: CSSProperties;
15
+ ref?: Ref<HTMLElement>;
16
+ [prop: string]: unknown;
17
+ }
18
+
19
+ export interface VelinComponent extends ComponentType<VelinComponentProps> {
20
+ /** Custom element tag rendered by this wrapper. */
21
+ tagName: string;
22
+ }
23
+
24
+ export declare function createVelinComponent(tag: string): VelinComponent;
25
+ export declare const VELIN_TAGS: readonly string[];
26
+
27
+ export declare function isVelinEventProp(name: string): boolean;
28
+ export declare function velinEventName(propName: string): string;
29
+ export declare function componentNameForTag(tag: string): string;
30
+ export declare function splitProps(props: Record<string, unknown>): {
31
+ children?: ReactNode;
32
+ className?: string;
33
+ style?: CSSProperties;
34
+ attributes: Record<string, string | number>;
35
+ properties: Record<string, unknown>;
36
+ booleans: Record<string, boolean>;
37
+ listeners: Record<string, EventListener>;
38
+ reactProps: Record<string, unknown>;
39
+ };
40
+ export declare function applyVelinProps(
41
+ el: Element,
42
+ parts: { properties?: Record<string, unknown>; booleans?: Record<string, boolean> },
43
+ ): void;
44
+ export declare function bindVelinListeners(
45
+ el: Element,
46
+ listeners: Record<string, EventListener>,
47
+ ): () => void;
48
+
49
+ export declare const VelinAccordion: VelinComponent;
50
+ export declare const VelinAnnouncer: VelinComponent;
51
+ export declare const VelinBottomNav: VelinComponent;
52
+ export declare const VelinCarousel: VelinComponent;
53
+ export declare const VelinCodeBlock: VelinComponent;
54
+ export declare const VelinCollapse: VelinComponent;
55
+ export declare const VelinCombobox: VelinComponent;
56
+ export declare const VelinCommand: VelinComponent;
57
+ export declare const VelinCopy: VelinComponent;
58
+ export declare const VelinCountdown: VelinComponent;
59
+ export declare const VelinCounter: VelinComponent;
60
+ export declare const VelinDataTable: VelinComponent;
61
+ export declare const VelinDialog: VelinComponent;
62
+ export declare const VelinDrawer: VelinComponent;
63
+ export declare const VelinDropdown: VelinComponent;
64
+ export declare const VelinEmail: VelinComponent;
65
+ export declare const VelinFormSummary: VelinComponent;
66
+ export declare const VelinIcon: VelinComponent;
67
+ export declare const VelinLightbox: VelinComponent;
68
+ export declare const VelinLiveDot: VelinComponent;
69
+ export declare const VelinMenubar: VelinComponent;
70
+ export declare const VelinModal: VelinComponent;
71
+ export declare const VelinPersist: VelinComponent;
72
+ export declare const VelinPopover: VelinComponent;
73
+ export declare const VelinProgressRing: VelinComponent;
74
+ export declare const VelinRating: VelinComponent;
75
+ export declare const VelinScrollTop: VelinComponent;
76
+ export declare const VelinScrollspy: VelinComponent;
77
+ export declare const VelinSearch: VelinComponent;
78
+ export declare const VelinSecureField: VelinComponent;
79
+ export declare const VelinSegmentedControl: VelinComponent;
80
+ export declare const VelinSheet: VelinComponent;
81
+ export declare const VelinSparkline: VelinComponent;
82
+ export declare const VelinStepper: VelinComponent;
83
+ export declare const VelinTabs: VelinComponent;
84
+ export declare const VelinThemeToggle: VelinComponent;
85
+ export declare const VelinToast: VelinComponent;
86
+ export declare const VelinTooltip: VelinComponent;
package/dist/index.js ADDED
@@ -0,0 +1,225 @@
1
+ // src/create-component.jsx
2
+ import * as React from "react";
3
+
4
+ // src/apply-props.js
5
+ var VELIN_EVENT_RE = /^onVelin[A-Z]/;
6
+ function isVelinEventProp(name) {
7
+ return VELIN_EVENT_RE.test(name);
8
+ }
9
+ function velinEventName(propName) {
10
+ return propName.slice(2).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
11
+ }
12
+ function splitProps(props) {
13
+ const attributes = {};
14
+ const properties = {};
15
+ const booleans = {};
16
+ const listeners = {};
17
+ const reactProps = {};
18
+ let children;
19
+ let className;
20
+ let style;
21
+ for (const [key, value] of Object.entries(props)) {
22
+ if (key === "children") {
23
+ children = value;
24
+ } else if (key === "className") {
25
+ className = /** @type {string} */
26
+ value;
27
+ } else if (key === "style") {
28
+ style = value;
29
+ } else if (isVelinEventProp(key)) {
30
+ if (typeof value === "function") listeners[velinEventName(key)] = /** @type {EventListener} */
31
+ value;
32
+ } else if (/^on[A-Z]/.test(key)) {
33
+ reactProps[key] = value;
34
+ } else if (value === null || value === void 0) {
35
+ } else if (typeof value === "boolean") {
36
+ booleans[key] = value;
37
+ } else if (typeof value === "object" || typeof value === "function") {
38
+ properties[key] = value;
39
+ } else {
40
+ attributes[key] = /** @type {string | number} */
41
+ value;
42
+ }
43
+ }
44
+ return { children, className, style, attributes, properties, booleans, listeners, reactProps };
45
+ }
46
+ function applyVelinProps(el, { properties = {}, booleans = {} } = {}) {
47
+ for (const [key, value] of Object.entries(properties)) {
48
+ el[key] = value;
49
+ }
50
+ for (const [key, value] of Object.entries(booleans)) {
51
+ if (value) el.setAttribute(key, "");
52
+ else el.removeAttribute(key);
53
+ }
54
+ }
55
+ function bindVelinListeners(el, listeners) {
56
+ const entries = Object.entries(listeners);
57
+ for (const [name, handler] of entries) el.addEventListener(name, handler);
58
+ return () => {
59
+ for (const [name, handler] of entries) el.removeEventListener(name, handler);
60
+ };
61
+ }
62
+ function componentNameForTag(tag) {
63
+ return tag.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
64
+ }
65
+
66
+ // src/create-component.jsx
67
+ function createVelinComponent(tag) {
68
+ const Component = React.forwardRef(function VelinComponent(props, forwardedRef) {
69
+ const elementRef = React.useRef(null);
70
+ const { children, className, style, attributes, properties, booleans, listeners, reactProps } = splitProps(props);
71
+ const setRef = React.useCallback(
72
+ (node) => {
73
+ elementRef.current = node;
74
+ if (typeof forwardedRef === "function") forwardedRef(node);
75
+ else if (forwardedRef) forwardedRef.current = node;
76
+ },
77
+ [forwardedRef]
78
+ );
79
+ React.useLayoutEffect(() => {
80
+ if (elementRef.current) applyVelinProps(elementRef.current, { properties, booleans });
81
+ });
82
+ React.useLayoutEffect(() => {
83
+ if (!elementRef.current) return void 0;
84
+ return bindVelinListeners(elementRef.current, listeners);
85
+ });
86
+ return React.createElement(
87
+ tag,
88
+ { ref: setRef, className, style, ...attributes, ...reactProps },
89
+ children
90
+ );
91
+ });
92
+ Component.displayName = componentNameForTag(tag);
93
+ Component.tagName = tag;
94
+ return Component;
95
+ }
96
+
97
+ // src/tags.js
98
+ var VELIN_TAGS = [
99
+ "velin-accordion",
100
+ "velin-announcer",
101
+ "velin-bottom-nav",
102
+ "velin-carousel",
103
+ "velin-code-block",
104
+ "velin-collapse",
105
+ "velin-combobox",
106
+ "velin-command",
107
+ "velin-copy",
108
+ "velin-countdown",
109
+ "velin-counter",
110
+ "velin-data-table",
111
+ "velin-dialog",
112
+ "velin-drawer",
113
+ "velin-dropdown",
114
+ "velin-email",
115
+ "velin-form-summary",
116
+ "velin-icon",
117
+ "velin-lightbox",
118
+ "velin-live-dot",
119
+ "velin-menubar",
120
+ "velin-modal",
121
+ "velin-persist",
122
+ "velin-popover",
123
+ "velin-progress-ring",
124
+ "velin-rating",
125
+ "velin-scroll-top",
126
+ "velin-scrollspy",
127
+ "velin-search",
128
+ "velin-secure-field",
129
+ "velin-segmented-control",
130
+ "velin-sheet",
131
+ "velin-sparkline",
132
+ "velin-stepper",
133
+ "velin-tabs",
134
+ "velin-theme-toggle",
135
+ "velin-toast",
136
+ "velin-tooltip"
137
+ ];
138
+
139
+ // src/index.jsx
140
+ var VelinAccordion = createVelinComponent("velin-accordion");
141
+ var VelinAnnouncer = createVelinComponent("velin-announcer");
142
+ var VelinBottomNav = createVelinComponent("velin-bottom-nav");
143
+ var VelinCarousel = createVelinComponent("velin-carousel");
144
+ var VelinCodeBlock = createVelinComponent("velin-code-block");
145
+ var VelinCollapse = createVelinComponent("velin-collapse");
146
+ var VelinCombobox = createVelinComponent("velin-combobox");
147
+ var VelinCommand = createVelinComponent("velin-command");
148
+ var VelinCopy = createVelinComponent("velin-copy");
149
+ var VelinCountdown = createVelinComponent("velin-countdown");
150
+ var VelinCounter = createVelinComponent("velin-counter");
151
+ var VelinDataTable = createVelinComponent("velin-data-table");
152
+ var VelinDialog = createVelinComponent("velin-dialog");
153
+ var VelinDrawer = createVelinComponent("velin-drawer");
154
+ var VelinDropdown = createVelinComponent("velin-dropdown");
155
+ var VelinEmail = createVelinComponent("velin-email");
156
+ var VelinFormSummary = createVelinComponent("velin-form-summary");
157
+ var VelinIcon = createVelinComponent("velin-icon");
158
+ var VelinLightbox = createVelinComponent("velin-lightbox");
159
+ var VelinLiveDot = createVelinComponent("velin-live-dot");
160
+ var VelinMenubar = createVelinComponent("velin-menubar");
161
+ var VelinModal = createVelinComponent("velin-modal");
162
+ var VelinPersist = createVelinComponent("velin-persist");
163
+ var VelinPopover = createVelinComponent("velin-popover");
164
+ var VelinProgressRing = createVelinComponent("velin-progress-ring");
165
+ var VelinRating = createVelinComponent("velin-rating");
166
+ var VelinScrollTop = createVelinComponent("velin-scroll-top");
167
+ var VelinScrollspy = createVelinComponent("velin-scrollspy");
168
+ var VelinSearch = createVelinComponent("velin-search");
169
+ var VelinSecureField = createVelinComponent("velin-secure-field");
170
+ var VelinSegmentedControl = createVelinComponent("velin-segmented-control");
171
+ var VelinSheet = createVelinComponent("velin-sheet");
172
+ var VelinSparkline = createVelinComponent("velin-sparkline");
173
+ var VelinStepper = createVelinComponent("velin-stepper");
174
+ var VelinTabs = createVelinComponent("velin-tabs");
175
+ var VelinThemeToggle = createVelinComponent("velin-theme-toggle");
176
+ var VelinToast = createVelinComponent("velin-toast");
177
+ var VelinTooltip = createVelinComponent("velin-tooltip");
178
+ export {
179
+ VELIN_TAGS,
180
+ VelinAccordion,
181
+ VelinAnnouncer,
182
+ VelinBottomNav,
183
+ VelinCarousel,
184
+ VelinCodeBlock,
185
+ VelinCollapse,
186
+ VelinCombobox,
187
+ VelinCommand,
188
+ VelinCopy,
189
+ VelinCountdown,
190
+ VelinCounter,
191
+ VelinDataTable,
192
+ VelinDialog,
193
+ VelinDrawer,
194
+ VelinDropdown,
195
+ VelinEmail,
196
+ VelinFormSummary,
197
+ VelinIcon,
198
+ VelinLightbox,
199
+ VelinLiveDot,
200
+ VelinMenubar,
201
+ VelinModal,
202
+ VelinPersist,
203
+ VelinPopover,
204
+ VelinProgressRing,
205
+ VelinRating,
206
+ VelinScrollTop,
207
+ VelinScrollspy,
208
+ VelinSearch,
209
+ VelinSecureField,
210
+ VelinSegmentedControl,
211
+ VelinSheet,
212
+ VelinSparkline,
213
+ VelinStepper,
214
+ VelinTabs,
215
+ VelinThemeToggle,
216
+ VelinToast,
217
+ VelinTooltip,
218
+ applyVelinProps,
219
+ bindVelinListeners,
220
+ componentNameForTag,
221
+ createVelinComponent,
222
+ isVelinEventProp,
223
+ splitProps,
224
+ velinEventName
225
+ };
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@velinstyle/react",
3
+ "version": "1.1.0",
4
+ "description": "Official React wrappers for VelinStyle web components",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist/",
17
+ "src/"
18
+ ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/SkyliteDesign/velinstyle.git",
22
+ "directory": "packages/react"
23
+ },
24
+ "homepage": "https://velinstyle.info/docs/guides/react-vite-starter.html",
25
+ "bugs": {
26
+ "url": "https://github.com/SkyliteDesign/velinstyle/issues"
27
+ },
28
+ "keywords": [
29
+ "react",
30
+ "web-components",
31
+ "velinstyle",
32
+ "accessibility",
33
+ "wcag"
34
+ ],
35
+ "author": "SkyliteDesign",
36
+ "license": "MIT",
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "registry": "https://registry.npmjs.org"
40
+ },
41
+ "peerDependencies": {
42
+ "react": ">=18"
43
+ },
44
+ "scripts": {
45
+ "generate": "node ../../scripts/generate-react-wrappers.mjs",
46
+ "build": "npm run generate && esbuild src/index.jsx --bundle --format=esm --packages=external --loader:.jsx=jsx --outfile=dist/index.js && node -e \"require('fs').copyFileSync('src/index.d.ts','dist/index.d.ts')\"",
47
+ "prepublishOnly": "npm run build",
48
+ "pack:check": "npm pack --dry-run"
49
+ },
50
+ "devDependencies": {
51
+ "esbuild": "^0.24.0",
52
+ "react": "^18.3.0"
53
+ }
54
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Prop mapping between React and VelinStyle custom elements.
3
+ *
4
+ * React 18 renders every unknown prop as a string attribute, which breaks two
5
+ * things for custom elements: `false` becomes the attribute `"false"` (still
6
+ * truthy to `hasAttribute`), and objects/arrays are stringified. Both are
7
+ * handled imperatively here so the wrappers behave the same on React 18 and 19.
8
+ */
9
+
10
+ /** Custom-event props use the `onVelin…` prefix; plain React events pass through. */
11
+ const VELIN_EVENT_RE = /^onVelin[A-Z]/;
12
+
13
+ /** @param {string} name */
14
+ export function isVelinEventProp(name) {
15
+ return VELIN_EVENT_RE.test(name);
16
+ }
17
+
18
+ /**
19
+ * `onVelinSearchSelect` → `velin-search-select`
20
+ * @param {string} propName
21
+ */
22
+ export function velinEventName(propName) {
23
+ return propName
24
+ .slice(2)
25
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
26
+ .toLowerCase();
27
+ }
28
+
29
+ /**
30
+ * Split React props into the buckets each target can handle.
31
+ * @param {Record<string, unknown>} props
32
+ */
33
+ export function splitProps(props) {
34
+ /** @type {Record<string, string | number>} */
35
+ const attributes = {};
36
+ /** @type {Record<string, unknown>} */
37
+ const properties = {};
38
+ /** @type {Record<string, boolean>} */
39
+ const booleans = {};
40
+ /** @type {Record<string, EventListener>} */
41
+ const listeners = {};
42
+ /** @type {Record<string, unknown>} */
43
+ const reactProps = {};
44
+
45
+ let children;
46
+ let className;
47
+ let style;
48
+
49
+ for (const [key, value] of Object.entries(props)) {
50
+ if (key === 'children') {
51
+ children = value;
52
+ } else if (key === 'className') {
53
+ className = /** @type {string} */ (value);
54
+ } else if (key === 'style') {
55
+ style = value;
56
+ } else if (isVelinEventProp(key)) {
57
+ if (typeof value === 'function') listeners[velinEventName(key)] = /** @type {EventListener} */ (value);
58
+ } else if (/^on[A-Z]/.test(key)) {
59
+ reactProps[key] = value;
60
+ } else if (value === null || value === undefined) {
61
+ // Omitted entirely so the attribute is absent rather than "null".
62
+ } else if (typeof value === 'boolean') {
63
+ booleans[key] = value;
64
+ } else if (typeof value === 'object' || typeof value === 'function') {
65
+ properties[key] = value;
66
+ } else {
67
+ attributes[key] = /** @type {string | number} */ (value);
68
+ }
69
+ }
70
+
71
+ return { children, className, style, attributes, properties, booleans, listeners, reactProps };
72
+ }
73
+
74
+ /**
75
+ * Apply the buckets React cannot express directly onto the element.
76
+ * @param {Element} el
77
+ * @param {{ properties?: Record<string, unknown>, booleans?: Record<string, boolean> }} parts
78
+ */
79
+ export function applyVelinProps(el, { properties = {}, booleans = {} } = {}) {
80
+ for (const [key, value] of Object.entries(properties)) {
81
+ el[key] = value;
82
+ }
83
+ for (const [key, value] of Object.entries(booleans)) {
84
+ if (value) el.setAttribute(key, '');
85
+ else el.removeAttribute(key);
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Attach custom-event listeners and return a cleanup function.
91
+ * @param {Element} el
92
+ * @param {Record<string, EventListener>} listeners
93
+ */
94
+ export function bindVelinListeners(el, listeners) {
95
+ const entries = Object.entries(listeners);
96
+ for (const [name, handler] of entries) el.addEventListener(name, handler);
97
+ return () => {
98
+ for (const [name, handler] of entries) el.removeEventListener(name, handler);
99
+ };
100
+ }
101
+
102
+ /**
103
+ * `velin-code-block` → `VelinCodeBlock`
104
+ * @param {string} tag
105
+ */
106
+ export function componentNameForTag(tag) {
107
+ return tag
108
+ .split('-')
109
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
110
+ .join('');
111
+ }
@@ -0,0 +1,46 @@
1
+ import * as React from 'react';
2
+ import { splitProps, applyVelinProps, bindVelinListeners, componentNameForTag } from './apply-props.js';
3
+
4
+ /**
5
+ * Build a React wrapper for a VelinStyle custom element.
6
+ *
7
+ * Scalar props become attributes, booleans become presence attributes, objects
8
+ * and arrays are assigned as element properties, and `onVelin*` props are bound
9
+ * as custom-event listeners.
10
+ *
11
+ * @param {string} tag
12
+ */
13
+ export function createVelinComponent(tag) {
14
+ const Component = React.forwardRef(function VelinComponent(props, forwardedRef) {
15
+ const elementRef = React.useRef(null);
16
+ const { children, className, style, attributes, properties, booleans, listeners, reactProps } = splitProps(props);
17
+
18
+ const setRef = React.useCallback(
19
+ (node) => {
20
+ elementRef.current = node;
21
+ if (typeof forwardedRef === 'function') forwardedRef(node);
22
+ else if (forwardedRef) forwardedRef.current = node;
23
+ },
24
+ [forwardedRef],
25
+ );
26
+
27
+ React.useLayoutEffect(() => {
28
+ if (elementRef.current) applyVelinProps(elementRef.current, { properties, booleans });
29
+ });
30
+
31
+ React.useLayoutEffect(() => {
32
+ if (!elementRef.current) return undefined;
33
+ return bindVelinListeners(elementRef.current, listeners);
34
+ });
35
+
36
+ return React.createElement(
37
+ tag,
38
+ { ref: setRef, className, style, ...attributes, ...reactProps },
39
+ children,
40
+ );
41
+ });
42
+
43
+ Component.displayName = componentNameForTag(tag);
44
+ Component.tagName = tag;
45
+ return Component;
46
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * AUTO-GENERATED — run: node scripts/generate-react-wrappers.mjs
3
+ */
4
+ import type { ComponentType, CSSProperties, ReactNode, Ref } from 'react';
5
+
6
+ /**
7
+ * Props accepted by every wrapper. Scalars become attributes, booleans become
8
+ * presence attributes, objects and arrays are assigned as element properties,
9
+ * and `onVelin*` handlers are bound as custom-event listeners.
10
+ */
11
+ export interface VelinComponentProps {
12
+ children?: ReactNode;
13
+ className?: string;
14
+ style?: CSSProperties;
15
+ ref?: Ref<HTMLElement>;
16
+ [prop: string]: unknown;
17
+ }
18
+
19
+ export interface VelinComponent extends ComponentType<VelinComponentProps> {
20
+ /** Custom element tag rendered by this wrapper. */
21
+ tagName: string;
22
+ }
23
+
24
+ export declare function createVelinComponent(tag: string): VelinComponent;
25
+ export declare const VELIN_TAGS: readonly string[];
26
+
27
+ export declare function isVelinEventProp(name: string): boolean;
28
+ export declare function velinEventName(propName: string): string;
29
+ export declare function componentNameForTag(tag: string): string;
30
+ export declare function splitProps(props: Record<string, unknown>): {
31
+ children?: ReactNode;
32
+ className?: string;
33
+ style?: CSSProperties;
34
+ attributes: Record<string, string | number>;
35
+ properties: Record<string, unknown>;
36
+ booleans: Record<string, boolean>;
37
+ listeners: Record<string, EventListener>;
38
+ reactProps: Record<string, unknown>;
39
+ };
40
+ export declare function applyVelinProps(
41
+ el: Element,
42
+ parts: { properties?: Record<string, unknown>; booleans?: Record<string, boolean> },
43
+ ): void;
44
+ export declare function bindVelinListeners(
45
+ el: Element,
46
+ listeners: Record<string, EventListener>,
47
+ ): () => void;
48
+
49
+ export declare const VelinAccordion: VelinComponent;
50
+ export declare const VelinAnnouncer: VelinComponent;
51
+ export declare const VelinBottomNav: VelinComponent;
52
+ export declare const VelinCarousel: VelinComponent;
53
+ export declare const VelinCodeBlock: VelinComponent;
54
+ export declare const VelinCollapse: VelinComponent;
55
+ export declare const VelinCombobox: VelinComponent;
56
+ export declare const VelinCommand: VelinComponent;
57
+ export declare const VelinCopy: VelinComponent;
58
+ export declare const VelinCountdown: VelinComponent;
59
+ export declare const VelinCounter: VelinComponent;
60
+ export declare const VelinDataTable: VelinComponent;
61
+ export declare const VelinDialog: VelinComponent;
62
+ export declare const VelinDrawer: VelinComponent;
63
+ export declare const VelinDropdown: VelinComponent;
64
+ export declare const VelinEmail: VelinComponent;
65
+ export declare const VelinFormSummary: VelinComponent;
66
+ export declare const VelinIcon: VelinComponent;
67
+ export declare const VelinLightbox: VelinComponent;
68
+ export declare const VelinLiveDot: VelinComponent;
69
+ export declare const VelinMenubar: VelinComponent;
70
+ export declare const VelinModal: VelinComponent;
71
+ export declare const VelinPersist: VelinComponent;
72
+ export declare const VelinPopover: VelinComponent;
73
+ export declare const VelinProgressRing: VelinComponent;
74
+ export declare const VelinRating: VelinComponent;
75
+ export declare const VelinScrollTop: VelinComponent;
76
+ export declare const VelinScrollspy: VelinComponent;
77
+ export declare const VelinSearch: VelinComponent;
78
+ export declare const VelinSecureField: VelinComponent;
79
+ export declare const VelinSegmentedControl: VelinComponent;
80
+ export declare const VelinSheet: VelinComponent;
81
+ export declare const VelinSparkline: VelinComponent;
82
+ export declare const VelinStepper: VelinComponent;
83
+ export declare const VelinTabs: VelinComponent;
84
+ export declare const VelinThemeToggle: VelinComponent;
85
+ export declare const VelinToast: VelinComponent;
86
+ export declare const VelinTooltip: VelinComponent;
package/src/index.jsx ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * AUTO-GENERATED — run: node scripts/generate-react-wrappers.mjs
3
+ */
4
+ import { createVelinComponent } from './create-component.jsx';
5
+
6
+ export { createVelinComponent } from './create-component.jsx';
7
+ export {
8
+ splitProps,
9
+ applyVelinProps,
10
+ bindVelinListeners,
11
+ isVelinEventProp,
12
+ velinEventName,
13
+ componentNameForTag,
14
+ } from './apply-props.js';
15
+ export { VELIN_TAGS } from './tags.js';
16
+
17
+ export const VelinAccordion = createVelinComponent('velin-accordion');
18
+ export const VelinAnnouncer = createVelinComponent('velin-announcer');
19
+ export const VelinBottomNav = createVelinComponent('velin-bottom-nav');
20
+ export const VelinCarousel = createVelinComponent('velin-carousel');
21
+ export const VelinCodeBlock = createVelinComponent('velin-code-block');
22
+ export const VelinCollapse = createVelinComponent('velin-collapse');
23
+ export const VelinCombobox = createVelinComponent('velin-combobox');
24
+ export const VelinCommand = createVelinComponent('velin-command');
25
+ export const VelinCopy = createVelinComponent('velin-copy');
26
+ export const VelinCountdown = createVelinComponent('velin-countdown');
27
+ export const VelinCounter = createVelinComponent('velin-counter');
28
+ export const VelinDataTable = createVelinComponent('velin-data-table');
29
+ export const VelinDialog = createVelinComponent('velin-dialog');
30
+ export const VelinDrawer = createVelinComponent('velin-drawer');
31
+ export const VelinDropdown = createVelinComponent('velin-dropdown');
32
+ export const VelinEmail = createVelinComponent('velin-email');
33
+ export const VelinFormSummary = createVelinComponent('velin-form-summary');
34
+ export const VelinIcon = createVelinComponent('velin-icon');
35
+ export const VelinLightbox = createVelinComponent('velin-lightbox');
36
+ export const VelinLiveDot = createVelinComponent('velin-live-dot');
37
+ export const VelinMenubar = createVelinComponent('velin-menubar');
38
+ export const VelinModal = createVelinComponent('velin-modal');
39
+ export const VelinPersist = createVelinComponent('velin-persist');
40
+ export const VelinPopover = createVelinComponent('velin-popover');
41
+ export const VelinProgressRing = createVelinComponent('velin-progress-ring');
42
+ export const VelinRating = createVelinComponent('velin-rating');
43
+ export const VelinScrollTop = createVelinComponent('velin-scroll-top');
44
+ export const VelinScrollspy = createVelinComponent('velin-scrollspy');
45
+ export const VelinSearch = createVelinComponent('velin-search');
46
+ export const VelinSecureField = createVelinComponent('velin-secure-field');
47
+ export const VelinSegmentedControl = createVelinComponent('velin-segmented-control');
48
+ export const VelinSheet = createVelinComponent('velin-sheet');
49
+ export const VelinSparkline = createVelinComponent('velin-sparkline');
50
+ export const VelinStepper = createVelinComponent('velin-stepper');
51
+ export const VelinTabs = createVelinComponent('velin-tabs');
52
+ export const VelinThemeToggle = createVelinComponent('velin-theme-toggle');
53
+ export const VelinToast = createVelinComponent('velin-toast');
54
+ export const VelinTooltip = createVelinComponent('velin-tooltip');
package/src/tags.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * AUTO-GENERATED — run: node scripts/generate-react-wrappers.mjs
3
+ */
4
+ export const VELIN_TAGS = [
5
+ 'velin-accordion',
6
+ 'velin-announcer',
7
+ 'velin-bottom-nav',
8
+ 'velin-carousel',
9
+ 'velin-code-block',
10
+ 'velin-collapse',
11
+ 'velin-combobox',
12
+ 'velin-command',
13
+ 'velin-copy',
14
+ 'velin-countdown',
15
+ 'velin-counter',
16
+ 'velin-data-table',
17
+ 'velin-dialog',
18
+ 'velin-drawer',
19
+ 'velin-dropdown',
20
+ 'velin-email',
21
+ 'velin-form-summary',
22
+ 'velin-icon',
23
+ 'velin-lightbox',
24
+ 'velin-live-dot',
25
+ 'velin-menubar',
26
+ 'velin-modal',
27
+ 'velin-persist',
28
+ 'velin-popover',
29
+ 'velin-progress-ring',
30
+ 'velin-rating',
31
+ 'velin-scroll-top',
32
+ 'velin-scrollspy',
33
+ 'velin-search',
34
+ 'velin-secure-field',
35
+ 'velin-segmented-control',
36
+ 'velin-sheet',
37
+ 'velin-sparkline',
38
+ 'velin-stepper',
39
+ 'velin-tabs',
40
+ 'velin-theme-toggle',
41
+ 'velin-toast',
42
+ 'velin-tooltip',
43
+ ];