@liquid-glass-forge/react 0.0.0-stage → 0.1.0-rc.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nami Poursafargholi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,7 @@
1
+ Liquid Glass Forge
2
+ Copyright (c) 2026 Nami Poursafargholi. MIT licensed.
3
+
4
+ Independent implementation inspired by Apple's Liquid Glass design.
5
+ Not affiliated with, sponsored by or endorsed by Apple Inc.
6
+ Apple and its design/assets remain subject to their respective rights.
7
+ No Apple assets or upstream Liquid Glass/Sileo implementation is included.
package/README.md CHANGED
@@ -1,3 +1,29 @@
1
- # Temporary Holding Version
1
+ # Liquid Glass Forge React
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Experimental preview. API and device/performance qualification remain open; iPad is unqualified.
4
+
5
+ Experimental preview `0.1.0-rc.1`. Pinned peers: React and React DOM **19.3.1**.
6
+ Framework peers are imported, never bundled into this package. The ESM entry
7
+ retains `use client` for Next.js client boundaries and has public JSX declarations.
8
+
9
+ Import `GlassSurface`, `GlassSceneProvider` and `useGlassSurface` from
10
+ `@liquid-glass-forge/react`. Import `@liquid-glass-forge/dom/styles.css` in the
11
+ application for the server/no-JavaScript material baseline. No stylesheet is
12
+ injected by JavaScript.
13
+
14
+ `GlassSurface` renders a stable div, decorative canvas and ordinary children.
15
+ It forwards the div ref, including callback-ref cleanup. Without a provider it
16
+ uses CSS material. A provider accepts an explicit `source`/`renderer` pair,
17
+ `paused`, `timeoutMs` and `onError`; multiple children share one scene.
18
+ Source or renderer identity changes replace the scene. Keep these objects stable
19
+ between intentional replacements. The caller owns these reusable objects;
20
+ effect cleanup releases scene resources without terminally disposing them.
21
+
22
+ `useGlassSurface({material})` returns `ref`, `targetRef` and `invalidate`. Render
23
+ the target as a dedicated direct canvas child with the decorative CSS class,
24
+ material data attribute, `aria-hidden`, presentation role and negative tab index.
25
+ React owns both DOM nodes. Do not concurrently control canvas backing dimensions
26
+ or draw into its context while mounted.
27
+
28
+ See repository `docs/PHASE-7.md` for usage, Strict Mode ownership, exact Vite/Next
29
+ consumer evidence and remaining integration limits. No registry package is published.
@@ -0,0 +1,29 @@
1
+ import type { HTMLAttributes, ReactNode, RefCallback } from 'react';
2
+ import type { GlassScene, GlassMaterial, GlassRenderer, SceneSource } from '@liquid-glass-forge/dom';
3
+ export interface GlassSceneProviderProps {
4
+ readonly children?: ReactNode;
5
+ readonly source?: SceneSource;
6
+ readonly renderer?: GlassRenderer;
7
+ readonly timeoutMs?: number;
8
+ readonly paused?: boolean;
9
+ readonly onError?: (error: unknown) => void;
10
+ }
11
+ /** Caller owns source/renderer objects. Each effect owns one engine lifetime. */
12
+ export declare function GlassSceneProvider({ children, source, renderer, timeoutMs, paused, onError }: GlassSceneProviderProps): import("react").FunctionComponentElement<import("react").ProviderProps<{
13
+ readonly scene: GlassScene | null;
14
+ } | null>>;
15
+ export interface UseGlassSurfaceOptions {
16
+ readonly material?: GlassMaterial;
17
+ }
18
+ export interface GlassSurfaceBinding {
19
+ readonly ref: RefCallback<HTMLElement>;
20
+ readonly targetRef: RefCallback<HTMLCanvasElement>;
21
+ readonly invalidate: () => void;
22
+ }
23
+ /** Supply a dedicated direct canvas child. React retains both DOM nodes. */
24
+ export declare function useGlassSurface({ material }?: UseGlassSurfaceOptions): GlassSurfaceBinding;
25
+ export interface GlassSurfaceProps extends HTMLAttributes<HTMLDivElement>, UseGlassSurfaceOptions {
26
+ readonly children?: ReactNode;
27
+ }
28
+ /** Stable server/client markup; no DOM access or engine allocation in render. */
29
+ export declare const GlassSurface: import("react").ForwardRefExoticComponent<GlassSurfaceProps & import("react").RefAttributes<HTMLDivElement>>;
package/dist/index.js ADDED
@@ -0,0 +1,90 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { createContext, createElement, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
4
+ import { createGlassScene } from '@liquid-glass-forge/dom';
5
+ const SceneContext = createContext(null);
6
+ /** Caller owns source/renderer objects. Each effect owns one engine lifetime. */
7
+ export function GlassSceneProvider({ children, source, renderer, timeoutMs, paused = false, onError }) {
8
+ const [scene, setScene] = useState(null);
9
+ const error = useRef(onError);
10
+ const pausedRef = useRef(paused);
11
+ useEffect(() => { error.current = onError; pausedRef.current = paused; }, [onError, paused]);
12
+ useEffect(() => {
13
+ const next = createGlassScene({ ...(source ? { source } : {}), ...(renderer ? { renderer } : {}),
14
+ ...(timeoutMs === undefined ? {} : { timeoutMs }), onError: cause => error.current?.(cause) });
15
+ if (pausedRef.current)
16
+ next.pause();
17
+ setScene(next);
18
+ return () => { next.dispose(); setScene(null); };
19
+ }, [source, renderer, timeoutMs]);
20
+ useEffect(() => {
21
+ if (!scene || scene.state === 'destroyed')
22
+ return;
23
+ if (paused)
24
+ scene.pause();
25
+ else if (scene.state === 'paused')
26
+ scene.resume();
27
+ }, [scene, paused]);
28
+ const value = useMemo(() => ({ scene }), [scene]);
29
+ return createElement(SceneContext.Provider, { value }, children);
30
+ }
31
+ /** Supply a dedicated direct canvas child. React retains both DOM nodes. */
32
+ export function useGlassSurface({ material = 'glass' } = {}) {
33
+ const shared = useContext(SceneContext);
34
+ const [element, setElement] = useState(null);
35
+ const [target, setTarget] = useState(null);
36
+ const attachment = useRef(null);
37
+ const materialRef = useRef(material);
38
+ useEffect(() => { materialRef.current = material; }, [material]);
39
+ const ref = useCallback((node) => { setElement(node); }, []);
40
+ const targetRef = useCallback((node) => { setTarget(node); }, []);
41
+ useEffect(() => {
42
+ if (!element || !target || (shared && !shared.scene))
43
+ return;
44
+ const owned = shared ? null : createGlassScene();
45
+ const scene = shared?.scene ?? owned;
46
+ if (scene.state === 'destroyed')
47
+ return;
48
+ let current;
49
+ try {
50
+ current = scene.attach(element, { target, material: materialRef.current });
51
+ }
52
+ catch (cause) {
53
+ owned?.dispose();
54
+ throw cause;
55
+ }
56
+ attachment.current = current;
57
+ return () => {
58
+ if (attachment.current === current)
59
+ attachment.current = null;
60
+ current.dispose();
61
+ owned?.dispose();
62
+ };
63
+ }, [element, target, shared?.scene, !!shared]);
64
+ useEffect(() => { attachment.current?.update({ material }); }, [material]);
65
+ const invalidate = useCallback(() => { attachment.current?.invalidate(); }, []);
66
+ return useMemo(() => ({ ref, targetRef, invalidate }), [ref, targetRef, invalidate]);
67
+ }
68
+ /** Stable server/client markup; no DOM access or engine allocation in render. */
69
+ export const GlassSurface = forwardRef(function GlassSurface({ children, material = 'glass', className, ...attributes }, forwardedRef) {
70
+ const binding = useGlassSurface({ material });
71
+ const ref = useCallback((node) => {
72
+ binding.ref(node);
73
+ if (typeof forwardedRef === 'function') {
74
+ // ForwardedRef retains its legacy void signature; public RefCallback supports cleanup.
75
+ const cleanup = forwardedRef(node);
76
+ if (node)
77
+ return () => { binding.ref(null); if (typeof cleanup === 'function')
78
+ cleanup();
79
+ else
80
+ forwardedRef(null); };
81
+ }
82
+ else if (forwardedRef) {
83
+ forwardedRef.current = node;
84
+ if (node)
85
+ return () => { binding.ref(null); forwardedRef.current = null; };
86
+ }
87
+ return undefined;
88
+ }, [binding.ref, forwardedRef]);
89
+ return _jsxs("div", { ...attributes, className: ['lgf-host', className].filter(Boolean).join(' '), ref: ref, children: [_jsx("canvas", { className: "lgf-surface", "data-lgf-material": material, "aria-hidden": "true", role: "presentation", tabIndex: -1, ref: binding.targetRef }), children] });
90
+ });
package/package.json CHANGED
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "name": "@liquid-glass-forge/react",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0-rc.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "license": "MIT",
8
+ "engines": {
9
+ "node": ">=20.19.0"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "LICENSE",
21
+ "NOTICE",
22
+ "README.md"
23
+ ],
24
+ "dependencies": {
25
+ "@liquid-glass-forge/dom": "0.1.0-rc.1"
26
+ },
27
+ "peerDependencies": {
28
+ "react": "19.3.1",
29
+ "react-dom": "19.3.1"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/namipsg/liquid-glass-forge.git",
34
+ "directory": "packages/react"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ }
39
+ }