@aicut/react 0.2.0 → 0.3.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/dist/lighting.cjs +7 -26
- package/dist/lighting.cjs.map +1 -1
- package/dist/lighting.d.cts +8 -33
- package/dist/lighting.d.ts +8 -33
- package/dist/lighting.js +7 -26
- package/dist/lighting.js.map +1 -1
- package/package.json +2 -2
package/dist/lighting.cjs
CHANGED
|
@@ -32,13 +32,12 @@ module.exports = __toCommonJS(lighting_exports);
|
|
|
32
32
|
|
|
33
33
|
// src/LightingEditor.tsx
|
|
34
34
|
var import_react = require("react");
|
|
35
|
-
var import_react_dom = require("react-dom");
|
|
36
35
|
var import_lighting = require("@aicut/core/lighting");
|
|
37
36
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
38
37
|
function LightingEditor(props) {
|
|
39
38
|
const hostRef = (0, import_react.useRef)(null);
|
|
40
39
|
const editorRef = (0, import_react.useRef)(null);
|
|
41
|
-
const [
|
|
40
|
+
const [ready, setReady] = (0, import_react.useState)(false);
|
|
42
41
|
const cbRef = (0, import_react.useRef)(props);
|
|
43
42
|
cbRef.current = props;
|
|
44
43
|
(0, import_react.useEffect)(() => {
|
|
@@ -49,20 +48,16 @@ function LightingEditor(props) {
|
|
|
49
48
|
subjectImageUrl: cbRef.current.subjectImageUrl,
|
|
50
49
|
config: cbRef.current.defaultConfig,
|
|
51
50
|
view: cbRef.current.defaultView,
|
|
52
|
-
smartEnabled: cbRef.current.smartEnabled,
|
|
53
|
-
smartOpen: cbRef.current.smartOpen,
|
|
54
51
|
theme: cbRef.current.theme,
|
|
55
52
|
locale: cbRef.current.locale,
|
|
56
|
-
onChange: (cfg) => cbRef.current.onChange?.(cfg)
|
|
57
|
-
onGenerate: (cfg) => cbRef.current.onGenerate?.(cfg),
|
|
58
|
-
onSmartOpenChange: (open) => cbRef.current.onSmartOpenChange?.(open)
|
|
53
|
+
onChange: (cfg) => cbRef.current.onChange?.(cfg)
|
|
59
54
|
});
|
|
60
55
|
editorRef.current = editor;
|
|
61
|
-
|
|
56
|
+
setReady(true);
|
|
62
57
|
return () => {
|
|
63
58
|
editor.destroy();
|
|
64
59
|
editorRef.current = null;
|
|
65
|
-
|
|
60
|
+
setReady(false);
|
|
66
61
|
};
|
|
67
62
|
}, []);
|
|
68
63
|
(0, import_react.useEffect)(() => {
|
|
@@ -75,14 +70,6 @@ function LightingEditor(props) {
|
|
|
75
70
|
if (props.subjectImageUrl)
|
|
76
71
|
editorRef.current?.setSubjectImage(props.subjectImageUrl);
|
|
77
72
|
}, [props.subjectImageUrl]);
|
|
78
|
-
(0, import_react.useEffect)(() => {
|
|
79
|
-
if (props.smartEnabled !== void 0)
|
|
80
|
-
editorRef.current?.setSmartEnabled(props.smartEnabled);
|
|
81
|
-
}, [props.smartEnabled]);
|
|
82
|
-
(0, import_react.useEffect)(() => {
|
|
83
|
-
if (props.smartOpen !== void 0)
|
|
84
|
-
editorRef.current?.setSmartOpen(props.smartOpen);
|
|
85
|
-
}, [props.smartOpen]);
|
|
86
73
|
(0, import_react.useImperativeHandle)(
|
|
87
74
|
props.apiRef,
|
|
88
75
|
() => {
|
|
@@ -93,15 +80,10 @@ function LightingEditor(props) {
|
|
|
93
80
|
getConfig: () => ed.getConfig(),
|
|
94
81
|
setSubjectImage: (url) => ed.setSubjectImage(url),
|
|
95
82
|
setView: (v) => ed.setView(v),
|
|
96
|
-
getView: () => ed.getView()
|
|
97
|
-
setSmartEnabled: (en) => ed.setSmartEnabled(en),
|
|
98
|
-
isSmartEnabled: () => ed.isSmartEnabled(),
|
|
99
|
-
setSmartOpen: (open) => ed.setSmartOpen(open),
|
|
100
|
-
isSmartOpen: () => ed.isSmartOpen(),
|
|
101
|
-
requestGenerate: () => ed.requestGenerate()
|
|
83
|
+
getView: () => ed.getView()
|
|
102
84
|
};
|
|
103
85
|
},
|
|
104
|
-
[
|
|
86
|
+
[ready]
|
|
105
87
|
);
|
|
106
88
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
107
89
|
"div",
|
|
@@ -109,8 +91,7 @@ function LightingEditor(props) {
|
|
|
109
91
|
ref: hostRef,
|
|
110
92
|
className: props.className,
|
|
111
93
|
style: props.style,
|
|
112
|
-
"data-aicut-lighting-host": ""
|
|
113
|
-
children: slot && props.smartPanel != null ? (0, import_react_dom.createPortal)(props.smartPanel, slot) : null
|
|
94
|
+
"data-aicut-lighting-host": ""
|
|
114
95
|
}
|
|
115
96
|
);
|
|
116
97
|
}
|
package/dist/lighting.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lighting.ts","../src/LightingEditor.tsx"],"sourcesContent":["/**\n * @aicut/react/lighting — separate entry that pulls three.js. Users\n * who never import this path don't pay the three.js bundle cost.\n */\nexport { LightingEditor } from \"./LightingEditor.js\";\nexport type {\n LightingEditorProps,\n LightingEditorApi,\n} from \"./LightingEditor.js\";\n\n// Re-export the data + locale exports from the core sub-entry so\n// hosts only need a single import line for everything lighting-related.\nexport {\n DEFAULT_LIGHTING_CONFIG,\n PRESET_DIRECTIONS,\n lightingLocaleEn,\n lightingLocaleZh,\n mergeLightingLocale,\n snapToPreset,\n} from \"@aicut/core/lighting\";\nexport type {\n KeyPreset,\n LightingConfig,\n LightingEditorOptions,\n LightingLocale,\n LightingView,\n} from \"@aicut/core/lighting\";\n","import {\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type
|
|
1
|
+
{"version":3,"sources":["../src/lighting.ts","../src/LightingEditor.tsx"],"sourcesContent":["/**\n * @aicut/react/lighting — separate entry that pulls three.js. Users\n * who never import this path don't pay the three.js bundle cost.\n */\nexport { LightingEditor } from \"./LightingEditor.js\";\nexport type {\n LightingEditorProps,\n LightingEditorApi,\n} from \"./LightingEditor.js\";\n\n// Re-export the data + locale exports from the core sub-entry so\n// hosts only need a single import line for everything lighting-related.\nexport {\n DEFAULT_LIGHTING_CONFIG,\n PRESET_DIRECTIONS,\n lightingLocaleEn,\n lightingLocaleZh,\n mergeLightingLocale,\n snapToPreset,\n} from \"@aicut/core/lighting\";\nexport type {\n KeyPreset,\n LightingConfig,\n LightingEditorOptions,\n LightingLocale,\n LightingView,\n} from \"@aicut/core/lighting\";\n","import {\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type Ref,\n} from \"react\";\nimport {\n LightingEditor as CoreLightingEditor,\n type LightingConfig,\n type LightingEditorOptions,\n type LightingView,\n} from \"@aicut/core/lighting\";\nimport type { Theme } from \"@aicut/core\";\n\nexport interface LightingEditorApi {\n setConfig(partial: Partial<LightingConfig>): void;\n getConfig(): LightingConfig;\n setSubjectImage(url: string): void;\n setView(v: LightingView): void;\n getView(): LightingView;\n}\n\nexport interface LightingEditorProps {\n /** Initial subject image (URL or data URI). Reactive. */\n subjectImageUrl?: string;\n /** Initial config. */\n defaultConfig?: Partial<LightingConfig>;\n /** Initial view. Default `\"perspective\"`. */\n defaultView?: LightingView;\n /** Theme — reactive (calls editor.setTheme). */\n theme?: Theme;\n /** Locale partial — reactive (calls editor.setLocale). */\n locale?: LightingEditorOptions[\"locale\"];\n\n className?: string;\n style?: CSSProperties;\n apiRef?: Ref<LightingEditorApi | null>;\n\n onChange?: (cfg: LightingConfig) => void;\n}\n\n/**\n * React shell for the 3D lighting picker. Renders scene + controls;\n * nothing else. Host code lays out their own surrounding UI (smart\n * mode panel, generate button, etc.) alongside this component in\n * whatever flex/grid the host prefers.\n */\nexport function LightingEditor(props: LightingEditorProps) {\n const hostRef = useRef<HTMLDivElement | null>(null);\n const editorRef = useRef<CoreLightingEditor | null>(null);\n // Triggers a re-render the moment the editor is created, so the\n // useImperativeHandle factory below can return the real instance\n // instead of locking at null forever (same trick as VideoEditor).\n const [ready, setReady] = useState(false);\n\n const cbRef = useRef(props);\n cbRef.current = props;\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n const editor = CoreLightingEditor.create({\n container: host,\n subjectImageUrl: cbRef.current.subjectImageUrl,\n config: cbRef.current.defaultConfig,\n view: cbRef.current.defaultView,\n theme: cbRef.current.theme,\n locale: cbRef.current.locale,\n onChange: (cfg) => cbRef.current.onChange?.(cfg),\n });\n editorRef.current = editor;\n setReady(true);\n return () => {\n editor.destroy();\n editorRef.current = null;\n setReady(false);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (props.theme) editorRef.current?.setTheme(props.theme);\n }, [props.theme]);\n useEffect(() => {\n // Always push — `undefined` is the \"reset to English defaults\"\n // signal. Without this, toggling ZH→EN in the host kept ZH labels.\n editorRef.current?.setLocale(props.locale ?? {});\n }, [props.locale]);\n useEffect(() => {\n if (props.subjectImageUrl)\n editorRef.current?.setSubjectImage(props.subjectImageUrl);\n }, [props.subjectImageUrl]);\n\n useImperativeHandle<LightingEditorApi | null, LightingEditorApi | null>(\n props.apiRef,\n () => {\n const ed = editorRef.current;\n if (!ed) return null;\n return {\n setConfig: (p) => ed.setConfig(p),\n getConfig: () => ed.getConfig(),\n setSubjectImage: (url) => ed.setSubjectImage(url),\n setView: (v) => ed.setView(v),\n getView: () => ed.getView(),\n };\n },\n [ready],\n );\n\n return (\n <div\n ref={hostRef}\n className={props.className}\n style={props.style}\n data-aicut-lighting-host=\"\"\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAOO;AACP,sBAKO;AAmGH;AA/DG,SAAS,eAAe,OAA4B;AACzD,QAAM,cAAU,qBAA8B,IAAI;AAClD,QAAM,gBAAY,qBAAkC,IAAI;AAIxD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,KAAK;AAExC,QAAM,YAAQ,qBAAO,KAAK;AAC1B,QAAM,UAAU;AAEhB,8BAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AACX,UAAM,SAAS,gBAAAA,eAAmB,OAAO;AAAA,MACvC,WAAW;AAAA,MACX,iBAAiB,MAAM,QAAQ;AAAA,MAC/B,QAAQ,MAAM,QAAQ;AAAA,MACtB,MAAM,MAAM,QAAQ;AAAA,MACpB,OAAO,MAAM,QAAQ;AAAA,MACrB,QAAQ,MAAM,QAAQ;AAAA,MACtB,UAAU,CAAC,QAAQ,MAAM,QAAQ,WAAW,GAAG;AAAA,IACjD,CAAC;AACD,cAAU,UAAU;AACpB,aAAS,IAAI;AACb,WAAO,MAAM;AACX,aAAO,QAAQ;AACf,gBAAU,UAAU;AACpB,eAAS,KAAK;AAAA,IAChB;AAAA,EAEF,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,QAAI,MAAM,MAAO,WAAU,SAAS,SAAS,MAAM,KAAK;AAAA,EAC1D,GAAG,CAAC,MAAM,KAAK,CAAC;AAChB,8BAAU,MAAM;AAGd,cAAU,SAAS,UAAU,MAAM,UAAU,CAAC,CAAC;AAAA,EACjD,GAAG,CAAC,MAAM,MAAM,CAAC;AACjB,8BAAU,MAAM;AACd,QAAI,MAAM;AACR,gBAAU,SAAS,gBAAgB,MAAM,eAAe;AAAA,EAC5D,GAAG,CAAC,MAAM,eAAe,CAAC;AAE1B;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AACJ,YAAM,KAAK,UAAU;AACrB,UAAI,CAAC,GAAI,QAAO;AAChB,aAAO;AAAA,QACL,WAAW,CAAC,MAAM,GAAG,UAAU,CAAC;AAAA,QAChC,WAAW,MAAM,GAAG,UAAU;AAAA,QAC9B,iBAAiB,CAAC,QAAQ,GAAG,gBAAgB,GAAG;AAAA,QAChD,SAAS,CAAC,MAAM,GAAG,QAAQ,CAAC;AAAA,QAC5B,SAAS,MAAM,GAAG,QAAQ;AAAA,MAC5B;AAAA,IACF;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,MAAM;AAAA,MACjB,OAAO,MAAM;AAAA,MACb,4BAAyB;AAAA;AAAA,EAC3B;AAEJ;;;AD3GA,IAAAC,mBAOO;","names":["CoreLightingEditor","import_lighting"]}
|
package/dist/lighting.d.cts
CHANGED
|
@@ -1,28 +1,18 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { CSSProperties, Ref } from 'react';
|
|
3
3
|
import { LightingConfig, LightingView, LightingEditorOptions } from '@aicut/core/lighting';
|
|
4
4
|
export { DEFAULT_LIGHTING_CONFIG, KeyPreset, LightingConfig, LightingEditorOptions, LightingLocale, LightingView, PRESET_DIRECTIONS, lightingLocaleEn, lightingLocaleZh, mergeLightingLocale, snapToPreset } from '@aicut/core/lighting';
|
|
5
5
|
import { Theme } from '@aicut/core';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Imperative handle. Mirrors the core class's mutating surface, plus
|
|
9
|
-
* a `requestGenerate()` shortcut so host buttons inside the smart slot
|
|
10
|
-
* don't need to thread the api ref to fire onGenerate.
|
|
11
|
-
*/
|
|
12
7
|
interface LightingEditorApi {
|
|
13
8
|
setConfig(partial: Partial<LightingConfig>): void;
|
|
14
9
|
getConfig(): LightingConfig;
|
|
15
10
|
setSubjectImage(url: string): void;
|
|
16
11
|
setView(v: LightingView): void;
|
|
17
12
|
getView(): LightingView;
|
|
18
|
-
setSmartEnabled(enabled: boolean): void;
|
|
19
|
-
isSmartEnabled(): boolean;
|
|
20
|
-
setSmartOpen(open: boolean): void;
|
|
21
|
-
isSmartOpen(): boolean;
|
|
22
|
-
requestGenerate(): void;
|
|
23
13
|
}
|
|
24
14
|
interface LightingEditorProps {
|
|
25
|
-
/** Initial subject image (URL or data URI). */
|
|
15
|
+
/** Initial subject image (URL or data URI). Reactive. */
|
|
26
16
|
subjectImageUrl?: string;
|
|
27
17
|
/** Initial config. */
|
|
28
18
|
defaultConfig?: Partial<LightingConfig>;
|
|
@@ -32,32 +22,17 @@ interface LightingEditorProps {
|
|
|
32
22
|
theme?: Theme;
|
|
33
23
|
/** Locale partial — reactive (calls editor.setLocale). */
|
|
34
24
|
locale?: LightingEditorOptions["locale"];
|
|
35
|
-
/**
|
|
36
|
-
* Any React node — portaled into the editor's smart slot. Host uses
|
|
37
|
-
* this for prompt textarea, preset grid, generate button, anything.
|
|
38
|
-
* The library renders nothing into the slot until you populate it.
|
|
39
|
-
*/
|
|
40
|
-
smartPanel?: ReactNode;
|
|
41
|
-
/**
|
|
42
|
-
* Whether the Smart mode feature is wired in at all. When false,
|
|
43
|
-
* the column AND the controls-header toggle disappear — leaving a
|
|
44
|
-
* clean 2-col scene + controls layout. Default `true`. Reactive.
|
|
45
|
-
*/
|
|
46
|
-
smartEnabled?: boolean;
|
|
47
|
-
/**
|
|
48
|
-
* When `smartEnabled`, whether the slot drawer starts open. Reactive
|
|
49
|
-
* — flips re-fire the editor's `setSmartOpen` so the panel slides
|
|
50
|
-
* in/out. Default `true`.
|
|
51
|
-
*/
|
|
52
|
-
smartOpen?: boolean;
|
|
53
25
|
className?: string;
|
|
54
26
|
style?: CSSProperties;
|
|
55
27
|
apiRef?: Ref<LightingEditorApi | null>;
|
|
56
28
|
onChange?: (cfg: LightingConfig) => void;
|
|
57
|
-
onGenerate?: (cfg: LightingConfig) => void;
|
|
58
|
-
/** Fires when the user clicks × or the Smart mode header toggle. */
|
|
59
|
-
onSmartOpenChange?: (open: boolean) => void;
|
|
60
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* React shell for the 3D lighting picker. Renders scene + controls;
|
|
32
|
+
* nothing else. Host code lays out their own surrounding UI (smart
|
|
33
|
+
* mode panel, generate button, etc.) alongside this component in
|
|
34
|
+
* whatever flex/grid the host prefers.
|
|
35
|
+
*/
|
|
61
36
|
declare function LightingEditor(props: LightingEditorProps): react.JSX.Element;
|
|
62
37
|
|
|
63
38
|
export { LightingEditor, type LightingEditorApi, type LightingEditorProps };
|
package/dist/lighting.d.ts
CHANGED
|
@@ -1,28 +1,18 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { CSSProperties, Ref } from 'react';
|
|
3
3
|
import { LightingConfig, LightingView, LightingEditorOptions } from '@aicut/core/lighting';
|
|
4
4
|
export { DEFAULT_LIGHTING_CONFIG, KeyPreset, LightingConfig, LightingEditorOptions, LightingLocale, LightingView, PRESET_DIRECTIONS, lightingLocaleEn, lightingLocaleZh, mergeLightingLocale, snapToPreset } from '@aicut/core/lighting';
|
|
5
5
|
import { Theme } from '@aicut/core';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Imperative handle. Mirrors the core class's mutating surface, plus
|
|
9
|
-
* a `requestGenerate()` shortcut so host buttons inside the smart slot
|
|
10
|
-
* don't need to thread the api ref to fire onGenerate.
|
|
11
|
-
*/
|
|
12
7
|
interface LightingEditorApi {
|
|
13
8
|
setConfig(partial: Partial<LightingConfig>): void;
|
|
14
9
|
getConfig(): LightingConfig;
|
|
15
10
|
setSubjectImage(url: string): void;
|
|
16
11
|
setView(v: LightingView): void;
|
|
17
12
|
getView(): LightingView;
|
|
18
|
-
setSmartEnabled(enabled: boolean): void;
|
|
19
|
-
isSmartEnabled(): boolean;
|
|
20
|
-
setSmartOpen(open: boolean): void;
|
|
21
|
-
isSmartOpen(): boolean;
|
|
22
|
-
requestGenerate(): void;
|
|
23
13
|
}
|
|
24
14
|
interface LightingEditorProps {
|
|
25
|
-
/** Initial subject image (URL or data URI). */
|
|
15
|
+
/** Initial subject image (URL or data URI). Reactive. */
|
|
26
16
|
subjectImageUrl?: string;
|
|
27
17
|
/** Initial config. */
|
|
28
18
|
defaultConfig?: Partial<LightingConfig>;
|
|
@@ -32,32 +22,17 @@ interface LightingEditorProps {
|
|
|
32
22
|
theme?: Theme;
|
|
33
23
|
/** Locale partial — reactive (calls editor.setLocale). */
|
|
34
24
|
locale?: LightingEditorOptions["locale"];
|
|
35
|
-
/**
|
|
36
|
-
* Any React node — portaled into the editor's smart slot. Host uses
|
|
37
|
-
* this for prompt textarea, preset grid, generate button, anything.
|
|
38
|
-
* The library renders nothing into the slot until you populate it.
|
|
39
|
-
*/
|
|
40
|
-
smartPanel?: ReactNode;
|
|
41
|
-
/**
|
|
42
|
-
* Whether the Smart mode feature is wired in at all. When false,
|
|
43
|
-
* the column AND the controls-header toggle disappear — leaving a
|
|
44
|
-
* clean 2-col scene + controls layout. Default `true`. Reactive.
|
|
45
|
-
*/
|
|
46
|
-
smartEnabled?: boolean;
|
|
47
|
-
/**
|
|
48
|
-
* When `smartEnabled`, whether the slot drawer starts open. Reactive
|
|
49
|
-
* — flips re-fire the editor's `setSmartOpen` so the panel slides
|
|
50
|
-
* in/out. Default `true`.
|
|
51
|
-
*/
|
|
52
|
-
smartOpen?: boolean;
|
|
53
25
|
className?: string;
|
|
54
26
|
style?: CSSProperties;
|
|
55
27
|
apiRef?: Ref<LightingEditorApi | null>;
|
|
56
28
|
onChange?: (cfg: LightingConfig) => void;
|
|
57
|
-
onGenerate?: (cfg: LightingConfig) => void;
|
|
58
|
-
/** Fires when the user clicks × or the Smart mode header toggle. */
|
|
59
|
-
onSmartOpenChange?: (open: boolean) => void;
|
|
60
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* React shell for the 3D lighting picker. Renders scene + controls;
|
|
32
|
+
* nothing else. Host code lays out their own surrounding UI (smart
|
|
33
|
+
* mode panel, generate button, etc.) alongside this component in
|
|
34
|
+
* whatever flex/grid the host prefers.
|
|
35
|
+
*/
|
|
61
36
|
declare function LightingEditor(props: LightingEditorProps): react.JSX.Element;
|
|
62
37
|
|
|
63
38
|
export { LightingEditor, type LightingEditorApi, type LightingEditorProps };
|
package/dist/lighting.js
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
useRef,
|
|
6
6
|
useState
|
|
7
7
|
} from "react";
|
|
8
|
-
import { createPortal } from "react-dom";
|
|
9
8
|
import {
|
|
10
9
|
LightingEditor as CoreLightingEditor
|
|
11
10
|
} from "@aicut/core/lighting";
|
|
@@ -13,7 +12,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
13
12
|
function LightingEditor(props) {
|
|
14
13
|
const hostRef = useRef(null);
|
|
15
14
|
const editorRef = useRef(null);
|
|
16
|
-
const [
|
|
15
|
+
const [ready, setReady] = useState(false);
|
|
17
16
|
const cbRef = useRef(props);
|
|
18
17
|
cbRef.current = props;
|
|
19
18
|
useEffect(() => {
|
|
@@ -24,20 +23,16 @@ function LightingEditor(props) {
|
|
|
24
23
|
subjectImageUrl: cbRef.current.subjectImageUrl,
|
|
25
24
|
config: cbRef.current.defaultConfig,
|
|
26
25
|
view: cbRef.current.defaultView,
|
|
27
|
-
smartEnabled: cbRef.current.smartEnabled,
|
|
28
|
-
smartOpen: cbRef.current.smartOpen,
|
|
29
26
|
theme: cbRef.current.theme,
|
|
30
27
|
locale: cbRef.current.locale,
|
|
31
|
-
onChange: (cfg) => cbRef.current.onChange?.(cfg)
|
|
32
|
-
onGenerate: (cfg) => cbRef.current.onGenerate?.(cfg),
|
|
33
|
-
onSmartOpenChange: (open) => cbRef.current.onSmartOpenChange?.(open)
|
|
28
|
+
onChange: (cfg) => cbRef.current.onChange?.(cfg)
|
|
34
29
|
});
|
|
35
30
|
editorRef.current = editor;
|
|
36
|
-
|
|
31
|
+
setReady(true);
|
|
37
32
|
return () => {
|
|
38
33
|
editor.destroy();
|
|
39
34
|
editorRef.current = null;
|
|
40
|
-
|
|
35
|
+
setReady(false);
|
|
41
36
|
};
|
|
42
37
|
}, []);
|
|
43
38
|
useEffect(() => {
|
|
@@ -50,14 +45,6 @@ function LightingEditor(props) {
|
|
|
50
45
|
if (props.subjectImageUrl)
|
|
51
46
|
editorRef.current?.setSubjectImage(props.subjectImageUrl);
|
|
52
47
|
}, [props.subjectImageUrl]);
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
if (props.smartEnabled !== void 0)
|
|
55
|
-
editorRef.current?.setSmartEnabled(props.smartEnabled);
|
|
56
|
-
}, [props.smartEnabled]);
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
if (props.smartOpen !== void 0)
|
|
59
|
-
editorRef.current?.setSmartOpen(props.smartOpen);
|
|
60
|
-
}, [props.smartOpen]);
|
|
61
48
|
useImperativeHandle(
|
|
62
49
|
props.apiRef,
|
|
63
50
|
() => {
|
|
@@ -68,15 +55,10 @@ function LightingEditor(props) {
|
|
|
68
55
|
getConfig: () => ed.getConfig(),
|
|
69
56
|
setSubjectImage: (url) => ed.setSubjectImage(url),
|
|
70
57
|
setView: (v) => ed.setView(v),
|
|
71
|
-
getView: () => ed.getView()
|
|
72
|
-
setSmartEnabled: (en) => ed.setSmartEnabled(en),
|
|
73
|
-
isSmartEnabled: () => ed.isSmartEnabled(),
|
|
74
|
-
setSmartOpen: (open) => ed.setSmartOpen(open),
|
|
75
|
-
isSmartOpen: () => ed.isSmartOpen(),
|
|
76
|
-
requestGenerate: () => ed.requestGenerate()
|
|
58
|
+
getView: () => ed.getView()
|
|
77
59
|
};
|
|
78
60
|
},
|
|
79
|
-
[
|
|
61
|
+
[ready]
|
|
80
62
|
);
|
|
81
63
|
return /* @__PURE__ */ jsx(
|
|
82
64
|
"div",
|
|
@@ -84,8 +66,7 @@ function LightingEditor(props) {
|
|
|
84
66
|
ref: hostRef,
|
|
85
67
|
className: props.className,
|
|
86
68
|
style: props.style,
|
|
87
|
-
"data-aicut-lighting-host": ""
|
|
88
|
-
children: slot && props.smartPanel != null ? createPortal(props.smartPanel, slot) : null
|
|
69
|
+
"data-aicut-lighting-host": ""
|
|
89
70
|
}
|
|
90
71
|
);
|
|
91
72
|
}
|
package/dist/lighting.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/LightingEditor.tsx","../src/lighting.ts"],"sourcesContent":["import {\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type
|
|
1
|
+
{"version":3,"sources":["../src/LightingEditor.tsx","../src/lighting.ts"],"sourcesContent":["import {\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type Ref,\n} from \"react\";\nimport {\n LightingEditor as CoreLightingEditor,\n type LightingConfig,\n type LightingEditorOptions,\n type LightingView,\n} from \"@aicut/core/lighting\";\nimport type { Theme } from \"@aicut/core\";\n\nexport interface LightingEditorApi {\n setConfig(partial: Partial<LightingConfig>): void;\n getConfig(): LightingConfig;\n setSubjectImage(url: string): void;\n setView(v: LightingView): void;\n getView(): LightingView;\n}\n\nexport interface LightingEditorProps {\n /** Initial subject image (URL or data URI). Reactive. */\n subjectImageUrl?: string;\n /** Initial config. */\n defaultConfig?: Partial<LightingConfig>;\n /** Initial view. Default `\"perspective\"`. */\n defaultView?: LightingView;\n /** Theme — reactive (calls editor.setTheme). */\n theme?: Theme;\n /** Locale partial — reactive (calls editor.setLocale). */\n locale?: LightingEditorOptions[\"locale\"];\n\n className?: string;\n style?: CSSProperties;\n apiRef?: Ref<LightingEditorApi | null>;\n\n onChange?: (cfg: LightingConfig) => void;\n}\n\n/**\n * React shell for the 3D lighting picker. Renders scene + controls;\n * nothing else. Host code lays out their own surrounding UI (smart\n * mode panel, generate button, etc.) alongside this component in\n * whatever flex/grid the host prefers.\n */\nexport function LightingEditor(props: LightingEditorProps) {\n const hostRef = useRef<HTMLDivElement | null>(null);\n const editorRef = useRef<CoreLightingEditor | null>(null);\n // Triggers a re-render the moment the editor is created, so the\n // useImperativeHandle factory below can return the real instance\n // instead of locking at null forever (same trick as VideoEditor).\n const [ready, setReady] = useState(false);\n\n const cbRef = useRef(props);\n cbRef.current = props;\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n const editor = CoreLightingEditor.create({\n container: host,\n subjectImageUrl: cbRef.current.subjectImageUrl,\n config: cbRef.current.defaultConfig,\n view: cbRef.current.defaultView,\n theme: cbRef.current.theme,\n locale: cbRef.current.locale,\n onChange: (cfg) => cbRef.current.onChange?.(cfg),\n });\n editorRef.current = editor;\n setReady(true);\n return () => {\n editor.destroy();\n editorRef.current = null;\n setReady(false);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (props.theme) editorRef.current?.setTheme(props.theme);\n }, [props.theme]);\n useEffect(() => {\n // Always push — `undefined` is the \"reset to English defaults\"\n // signal. Without this, toggling ZH→EN in the host kept ZH labels.\n editorRef.current?.setLocale(props.locale ?? {});\n }, [props.locale]);\n useEffect(() => {\n if (props.subjectImageUrl)\n editorRef.current?.setSubjectImage(props.subjectImageUrl);\n }, [props.subjectImageUrl]);\n\n useImperativeHandle<LightingEditorApi | null, LightingEditorApi | null>(\n props.apiRef,\n () => {\n const ed = editorRef.current;\n if (!ed) return null;\n return {\n setConfig: (p) => ed.setConfig(p),\n getConfig: () => ed.getConfig(),\n setSubjectImage: (url) => ed.setSubjectImage(url),\n setView: (v) => ed.setView(v),\n getView: () => ed.getView(),\n };\n },\n [ready],\n );\n\n return (\n <div\n ref={hostRef}\n className={props.className}\n style={props.style}\n data-aicut-lighting-host=\"\"\n />\n );\n}\n","/**\n * @aicut/react/lighting — separate entry that pulls three.js. Users\n * who never import this path don't pay the three.js bundle cost.\n */\nexport { LightingEditor } from \"./LightingEditor.js\";\nexport type {\n LightingEditorProps,\n LightingEditorApi,\n} from \"./LightingEditor.js\";\n\n// Re-export the data + locale exports from the core sub-entry so\n// hosts only need a single import line for everything lighting-related.\nexport {\n DEFAULT_LIGHTING_CONFIG,\n PRESET_DIRECTIONS,\n lightingLocaleEn,\n lightingLocaleZh,\n mergeLightingLocale,\n snapToPreset,\n} from \"@aicut/core/lighting\";\nexport type {\n KeyPreset,\n LightingConfig,\n LightingEditorOptions,\n LightingLocale,\n LightingView,\n} from \"@aicut/core/lighting\";\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE,kBAAkB;AAAA,OAIb;AAmGH;AA/DG,SAAS,eAAe,OAA4B;AACzD,QAAM,UAAU,OAA8B,IAAI;AAClD,QAAM,YAAY,OAAkC,IAAI;AAIxD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,KAAK;AAExC,QAAM,QAAQ,OAAO,KAAK;AAC1B,QAAM,UAAU;AAEhB,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AACX,UAAM,SAAS,mBAAmB,OAAO;AAAA,MACvC,WAAW;AAAA,MACX,iBAAiB,MAAM,QAAQ;AAAA,MAC/B,QAAQ,MAAM,QAAQ;AAAA,MACtB,MAAM,MAAM,QAAQ;AAAA,MACpB,OAAO,MAAM,QAAQ;AAAA,MACrB,QAAQ,MAAM,QAAQ;AAAA,MACtB,UAAU,CAAC,QAAQ,MAAM,QAAQ,WAAW,GAAG;AAAA,IACjD,CAAC;AACD,cAAU,UAAU;AACpB,aAAS,IAAI;AACb,WAAO,MAAM;AACX,aAAO,QAAQ;AACf,gBAAU,UAAU;AACpB,eAAS,KAAK;AAAA,IAChB;AAAA,EAEF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,MAAM,MAAO,WAAU,SAAS,SAAS,MAAM,KAAK;AAAA,EAC1D,GAAG,CAAC,MAAM,KAAK,CAAC;AAChB,YAAU,MAAM;AAGd,cAAU,SAAS,UAAU,MAAM,UAAU,CAAC,CAAC;AAAA,EACjD,GAAG,CAAC,MAAM,MAAM,CAAC;AACjB,YAAU,MAAM;AACd,QAAI,MAAM;AACR,gBAAU,SAAS,gBAAgB,MAAM,eAAe;AAAA,EAC5D,GAAG,CAAC,MAAM,eAAe,CAAC;AAE1B;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AACJ,YAAM,KAAK,UAAU;AACrB,UAAI,CAAC,GAAI,QAAO;AAChB,aAAO;AAAA,QACL,WAAW,CAAC,MAAM,GAAG,UAAU,CAAC;AAAA,QAChC,WAAW,MAAM,GAAG,UAAU;AAAA,QAC9B,iBAAiB,CAAC,QAAQ,GAAG,gBAAgB,GAAG;AAAA,QAChD,SAAS,CAAC,MAAM,GAAG,QAAQ,CAAC;AAAA,QAC5B,SAAS,MAAM,GAAG,QAAQ;AAAA,MAC5B;AAAA,IACF;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,MAAM;AAAA,MACjB,OAAO,MAAM;AAAA,MACb,4BAAyB;AAAA;AAAA,EAC3B;AAEJ;;;AC3GA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aicut/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "React wrapper for the AiCut video editor + lighting picker — thin declarative shells over @aicut/core.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ziqiang <ziqiangytu@gmail.com>",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"README.md"
|
|
60
60
|
],
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@aicut/core": "0.
|
|
62
|
+
"@aicut/core": "0.3.0"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"react": "^18.0.0 || ^19.0.0",
|