@shineuix/react 0.0.0-stage → 1.0.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.
- package/LICENSE +21 -0
- package/README.md +39 -2
- package/dist/components/components.d.ts +845 -0
- package/dist/components/components.js +1637 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/runtime.d.ts +19 -0
- package/dist/runtime.js +98 -0
- package/package.json +64 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components/components.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components/components.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Vendored from @stencil/react-output-target 1.6.2, src/runtime/create-component.ts.
|
|
3
|
+
* The MIT License (MIT). Copyright (c) 2019-present Drifty Co.
|
|
4
|
+
* Changed here: the wrapper renders nothing on the server and during hydration (useClientRender),
|
|
5
|
+
* and `slot` is written when React creates the element (beforeInsert).
|
|
6
|
+
*/
|
|
7
|
+
import type { EventName, Options } from '@lit/react';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
export type { EventName, Options } from '@lit/react';
|
|
10
|
+
type EventNames = Record<string, EventName | string>;
|
|
11
|
+
type StencilProps<I extends HTMLElement, E extends EventNames, C, R extends keyof C = never> = Omit<React.HTMLAttributes<I>, keyof E> & Partial<{
|
|
12
|
+
[K in keyof E]: E[K] extends EventName<infer T> ? (event: T) => void : (event: any) => void;
|
|
13
|
+
}> & Required<Pick<C, R>> & Partial<Omit<C, R>> & React.RefAttributes<I>;
|
|
14
|
+
export type StencilReactComponent<I extends HTMLElement, E extends EventNames = {}, C = Omit<I, keyof HTMLElement>, R extends keyof C = never> = React.FunctionComponent<StencilProps<I, E, C, R>>;
|
|
15
|
+
export declare const mergeClassNames: (currentClasses: Iterable<string>, newClassName: string | undefined, oldClassName: string | undefined) => string;
|
|
16
|
+
export declare const createComponent: <I extends HTMLElement, E extends EventNames = {}, C = Omit<I, keyof HTMLElement>, R extends keyof C = never>({ defineCustomElement, tagName, transformTag, ...options }: Options<I, E> & {
|
|
17
|
+
defineCustomElement: () => void;
|
|
18
|
+
transformTag?: (tagName: string) => string;
|
|
19
|
+
}) => StencilReactComponent<I, E, C, R>;
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Vendored from @stencil/react-output-target 1.6.2, src/runtime/create-component.ts.
|
|
3
|
+
* The MIT License (MIT). Copyright (c) 2019-present Drifty Co.
|
|
4
|
+
* Changed here: the wrapper renders nothing on the server and during hydration (useClientRender),
|
|
5
|
+
* and `slot` is written when React creates the element (beforeInsert).
|
|
6
|
+
*/
|
|
7
|
+
import { createComponent as createComponentWrapper } from '@lit/react';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
const splitClassName = (className) => className ? className.split(/\s+/).filter(Boolean) : [];
|
|
10
|
+
export const mergeClassNames = (currentClasses, newClassName, oldClassName) => {
|
|
11
|
+
const incoming = new Set(splitClassName(newClassName));
|
|
12
|
+
const previous = new Set(splitClassName(oldClassName));
|
|
13
|
+
const finalClassNames = [];
|
|
14
|
+
for (const className of currentClasses) {
|
|
15
|
+
if (incoming.has(className)) {
|
|
16
|
+
finalClassNames.push(className);
|
|
17
|
+
incoming.delete(className);
|
|
18
|
+
}
|
|
19
|
+
else if (!previous.has(className)) {
|
|
20
|
+
finalClassNames.push(className);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
for (const className of incoming) {
|
|
24
|
+
finalClassNames.push(className);
|
|
25
|
+
}
|
|
26
|
+
return finalClassNames.join(' ');
|
|
27
|
+
};
|
|
28
|
+
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
|
|
29
|
+
const subscribeNever = () => () => { };
|
|
30
|
+
/**
|
|
31
|
+
* False on the server and while the page hydrates, true in every other render.
|
|
32
|
+
*
|
|
33
|
+
* ShineUI's elements render into their own light DOM. In a server-rendered React app (Next.js,
|
|
34
|
+
* Remix) that collides with hydration: the element modules define the tags on import, the host
|
|
35
|
+
* tags the server sent upgrade and draw their inner markup, and React then finds children it did
|
|
36
|
+
* not render, reports a hydration mismatch (#418) and throws the server's markup away for the
|
|
37
|
+
* whole tree. So a wrapper renders nothing until this is true. useSyncExternalStore is React's
|
|
38
|
+
* own switch for it: the server snapshot is used on the server and during hydration, the client
|
|
39
|
+
* snapshot in every other render, so an app that only renders on the client sees the element in
|
|
40
|
+
* its first render.
|
|
41
|
+
*/
|
|
42
|
+
const useClientRender = () => React.useSyncExternalStore(subscribeNever, () => true, () => false);
|
|
43
|
+
/**
|
|
44
|
+
* Props React has to write when it creates the element, before it inserts it anywhere.
|
|
45
|
+
*
|
|
46
|
+
* @lit/react sets every prop the element's prototype knows as a property in a layout effect, after
|
|
47
|
+
* React has inserted the element. That is too late for `slot`. A ShineUI element draws in its own
|
|
48
|
+
* light DOM, and it files a child under a slot when the child is inserted, as a shadow host would
|
|
49
|
+
* on assignment. A `SuiButton slot="actions"` that React adds to a rendered page header arrived
|
|
50
|
+
* with no slot, went to the default slot (the title) and stayed there when its slot came a moment
|
|
51
|
+
* later. On the first render it happened to work, because the header draws after the effect.
|
|
52
|
+
* Hiding these names from the prototype check makes @lit/react hand them to React, which writes
|
|
53
|
+
* them while it creates the element.
|
|
54
|
+
*/
|
|
55
|
+
const beforeInsert = new Set(['slot']);
|
|
56
|
+
function withAttributesFirst(elementClass) {
|
|
57
|
+
// A server import may hand over no class at all; @lit/react reads it only in a client render.
|
|
58
|
+
if (!elementClass || typeof elementClass.prototype !== 'object' || typeof Proxy === 'undefined')
|
|
59
|
+
return elementClass;
|
|
60
|
+
const prototype = new Proxy(elementClass.prototype, { has: (target, key) => !beforeInsert.has(key) && Reflect.has(target, key) });
|
|
61
|
+
return { name: elementClass.name, prototype };
|
|
62
|
+
}
|
|
63
|
+
export const createComponent = ({ defineCustomElement, tagName, transformTag, ...options }) => {
|
|
64
|
+
if (typeof defineCustomElement !== 'undefined') {
|
|
65
|
+
defineCustomElement();
|
|
66
|
+
}
|
|
67
|
+
const finalTagName = transformTag ? transformTag(tagName) : tagName;
|
|
68
|
+
const ReactComponent = createComponentWrapper({ ...options, elementClass: withAttributesFirst(options.elementClass), tagName: finalTagName });
|
|
69
|
+
const WrappedComponent = React.forwardRef((props, ref) => {
|
|
70
|
+
const { className, class: classProp, ...restProps } = props;
|
|
71
|
+
const incomingClassName = className ?? classProp ?? '';
|
|
72
|
+
const client = useClientRender();
|
|
73
|
+
const elementRef = React.useRef(null);
|
|
74
|
+
const previousClassName = React.useRef('');
|
|
75
|
+
useIsomorphicLayoutEffect(() => {
|
|
76
|
+
const element = elementRef.current;
|
|
77
|
+
if (element === null || incomingClassName === previousClassName.current) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
element.className = mergeClassNames(Array.from(element.classList), incomingClassName, previousClassName.current);
|
|
81
|
+
previousClassName.current = incomingClassName;
|
|
82
|
+
});
|
|
83
|
+
const setRef = React.useCallback((node) => {
|
|
84
|
+
elementRef.current = node;
|
|
85
|
+
if (typeof ref === 'function') {
|
|
86
|
+
ref(node);
|
|
87
|
+
}
|
|
88
|
+
else if (ref !== null && ref !== undefined) {
|
|
89
|
+
ref.current = node;
|
|
90
|
+
}
|
|
91
|
+
}, [ref]);
|
|
92
|
+
if (!client)
|
|
93
|
+
return null;
|
|
94
|
+
return React.createElement(ReactComponent, { ...restProps, ref: setRef });
|
|
95
|
+
});
|
|
96
|
+
WrappedComponent.displayName = options.displayName ?? finalTagName;
|
|
97
|
+
return WrappedComponent;
|
|
98
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,67 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shineuix/react",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "React bindings for ShineUI web components.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"react",
|
|
8
|
+
"web-components",
|
|
9
|
+
"design-system",
|
|
10
|
+
"ui",
|
|
11
|
+
"components",
|
|
12
|
+
"shineui"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=22"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "dist/index.js",
|
|
19
|
+
"module": "dist/index.js",
|
|
20
|
+
"types": "dist/index.d.ts",
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"LICENSE",
|
|
32
|
+
"dist/",
|
|
33
|
+
"!dist/components/components.server.*"
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@lit/react": "^1.0.8",
|
|
37
|
+
"@shineuix/core": "1.0.1"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"react": "^18 || ^19",
|
|
41
|
+
"react-dom": "^18 || ^19"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@stencil/react-output-target": "^1.6.2",
|
|
45
|
+
"@types/react": "^19.1.0",
|
|
46
|
+
"@types/react-dom": "^19.1.0",
|
|
47
|
+
"react": "^19.1.0",
|
|
48
|
+
"react-dom": "^19.1.0",
|
|
49
|
+
"typescript": "~5.9.0"
|
|
50
|
+
},
|
|
51
|
+
"author": "ShineUI contributors",
|
|
52
|
+
"homepage": "https://shineui.dev",
|
|
53
|
+
"bugs": {
|
|
54
|
+
"email": "info@shineui.dev"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git+https://github.com/smallandsimple/shineui.git",
|
|
62
|
+
"directory": "packages/react"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"build": "tsc -p tsconfig.json && node scripts/vendor-runtime.mjs"
|
|
66
|
+
}
|
|
6
67
|
}
|