@nice2dev/ui-3d 1.2.0 → 1.2.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/CHANGELOG.md +103 -0
- package/dist/cjs/core/editorAsk.js +48 -0
- package/dist/cjs/core/i18n.js +7 -3
- package/dist/cjs/dance/DanceScoreEngine.js +7 -0
- package/dist/cjs/dance/PoseDetector.js +4 -2
- package/dist/cjs/material/NiceMaterialEditor.js +7 -3
- package/dist/cjs/material/materialEditorTypes.js +1 -1
- package/dist/cjs/material/materialNodeDefinitions.js +14 -11
- package/dist/cjs/model/ModelEditor.js +3 -2
- package/dist/cjs/model/ModelEditorLeftPanel.js +10 -4
- package/dist/cjs/model/ModelEditorMenuBar.js +7 -5
- package/dist/cjs/model/ModelEditorRightPanel.js +18 -16
- package/dist/cjs/model/ModelEditorSubComponents.js +8 -6
- package/dist/cjs/model/ModelEditorTimeline.js +6 -4
- package/dist/cjs/model/ModelEditorToolbar.js +6 -4
- package/dist/cjs/model/ModelEditorViewport.js +16 -6
- package/dist/cjs/model/ModelViewer.js +6 -4
- package/dist/cjs/model/NiceArmatureEditor.js +6 -4
- package/dist/cjs/model/NiceMorphTargetEditor.js +5 -3
- package/dist/cjs/model/NiceOctree.js +3 -1
- package/dist/cjs/model/NicePhysicsSimulation.js +6 -4
- package/dist/cjs/model/NiceProceduralGeometry.js +5 -3
- package/dist/cjs/model/NiceTerrainEditor.js +8 -6
- package/dist/cjs/model/NiceWeightPainter.js +4 -2
- package/dist/cjs/model/NiceXRPreview.js +4 -2
- package/dist/cjs/model/useModelEditor.js +22 -15
- package/dist/cjs/nice2dev-ui-3d.css +1 -1
- package/dist/cjs/particle/NiceParticleEditor.js +14 -9
- package/dist/cjs/rendering/NiceCascadedShadows.js +3 -1
- package/dist/cjs/rendering/NiceRenderExport.js +9 -3
- package/dist/cjs/rendering/NiceSSAO.js +3 -1
- package/dist/cjs/rendering/NiceSSR.js +3 -1
- package/dist/cjs/rendering/NiceWebGPURenderer.js +4 -2
- package/dist/cjs/uv/NiceUVEditor.js +16 -12
- package/dist/cjs/uv/uvEditorTypes.js +1 -0
- package/dist/esm/core/editorAsk.js +45 -0
- package/dist/esm/core/i18n.js +8 -4
- package/dist/esm/dance/DanceScoreEngine.js +7 -0
- package/dist/esm/dance/PoseDetector.js +4 -2
- package/dist/esm/material/NiceMaterialEditor.js +7 -3
- package/dist/esm/material/materialEditorTypes.js +1 -1
- package/dist/esm/material/materialNodeDefinitions.js +14 -11
- package/dist/esm/model/ModelEditor.js +3 -2
- package/dist/esm/model/ModelEditorLeftPanel.js +10 -4
- package/dist/esm/model/ModelEditorMenuBar.js +7 -5
- package/dist/esm/model/ModelEditorRightPanel.js +18 -16
- package/dist/esm/model/ModelEditorSubComponents.js +8 -6
- package/dist/esm/model/ModelEditorTimeline.js +6 -4
- package/dist/esm/model/ModelEditorToolbar.js +6 -4
- package/dist/esm/model/ModelEditorViewport.js +16 -6
- package/dist/esm/model/ModelViewer.js +6 -4
- package/dist/esm/model/NiceArmatureEditor.js +6 -4
- package/dist/esm/model/NiceMorphTargetEditor.js +5 -3
- package/dist/esm/model/NiceOctree.js +3 -1
- package/dist/esm/model/NicePhysicsSimulation.js +6 -4
- package/dist/esm/model/NiceProceduralGeometry.js +5 -3
- package/dist/esm/model/NiceTerrainEditor.js +8 -6
- package/dist/esm/model/NiceWeightPainter.js +4 -2
- package/dist/esm/model/NiceXRPreview.js +4 -2
- package/dist/esm/model/useModelEditor.js +22 -15
- package/dist/esm/nice2dev-ui-3d.css +1 -1
- package/dist/esm/particle/NiceParticleEditor.js +14 -9
- package/dist/esm/rendering/NiceCascadedShadows.js +3 -1
- package/dist/esm/rendering/NiceRenderExport.js +9 -3
- package/dist/esm/rendering/NiceSSAO.js +3 -1
- package/dist/esm/rendering/NiceSSR.js +3 -1
- package/dist/esm/rendering/NiceWebGPURenderer.js +4 -2
- package/dist/esm/uv/NiceUVEditor.js +16 -12
- package/dist/esm/uv/uvEditorTypes.js +1 -0
- package/dist/types/core/editorAsk.d.ts +26 -0
- package/dist/types/core/i18n.d.ts +1 -17
- package/dist/types/dance/DanceScoreEngine.d.ts +0 -6
- package/dist/types/model/useModelEditor.d.ts +3 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,108 @@
|
|
|
1
1
|
# @nice2dev/ui-3d — Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8c82c30: 1.2.1 — the decisions that waited since 1.2.0, and the debts the CI gates were holding. One API
|
|
8
|
+
change, agreed: `NiceIconSuggestorAI` suggests Nice icons only. Two stylesheets to import if you use
|
|
9
|
+
the packages: `@nice2dev/social/style.css`, `@nice2dev/ui-science/style.css`. Upgrade notes:
|
|
10
|
+
`documentation/omniverk/OMNIVERK_UPGRADE_1.2.1.md`.
|
|
11
|
+
|
|
12
|
+
**Tree-shaking.** An import from a package no longer brings the whole package. Module-level
|
|
13
|
+
statements that may have a side effect — a `displayName` assigned after each component (now
|
|
14
|
+
`Object.assign` inside `/* @__PURE__ */`, or under a development check for plain functions),
|
|
15
|
+
unannotated `forwardRef` / `memo` / `createContext` / icon-factory calls, spreads, registries filled
|
|
16
|
+
at import, `<style>` tags injected at import, a direct `eval` in ui-math — are gone. One import from
|
|
17
|
+
each of 53 packages: 5066.5 kB → 1171.6 kB (`@nice2dev/ui` 1928.2 kB → 12.9 kB, icon packs 48–275 kB
|
|
18
|
+
→ 1.6–2.6 kB). `defaultViewRegistry` has the Nice\* input controls from the start, each loading its
|
|
19
|
+
module on first render; sixteen controls add their styles to `<head>` on first render.
|
|
20
|
+
|
|
21
|
+
**Dead code.** 405 source files no entry point imported (never on npm) are deleted;
|
|
22
|
+
`NiceClipboardStack` (`@nice2dev/ui`) and `NiceSampleBrowser` (`@nice2dev/ui-audio`), finished and
|
|
23
|
+
documented, are exported.
|
|
24
|
+
|
|
25
|
+
**ui-mobile draws Nice icons.** New peer `@nice2dev/icons ^1.2.0`; `TabIcons`, `DrawerIcons`,
|
|
26
|
+
`HeaderIcons`, the `NiceSwipeActions` presets and the `NiceInfiniteScroll` states are `Ntd*` icons
|
|
27
|
+
instead of pasted `<svg>`, simple glyphs are CSS marks. `@nice2dev/icons` adds `NtdReply` and
|
|
28
|
+
`NtdInbox`; an icon no longer throws without `window.matchMedia`.
|
|
29
|
+
|
|
30
|
+
**`NiceIconSuggestorAI` (breaking, agreed).** `AIIconLibrary` is `'nice'`; `svgPath` and `unicode`
|
|
31
|
+
left `AISuggestedIcon`; the preview is a `<NiceIcon>`, "Copy SVG" is "Copy JSX".
|
|
32
|
+
|
|
33
|
+
**Peer ranges.** Every internal `@nice2dev/*` peer is `^1.2.0` (was as wide as `^1.0.20`), except
|
|
34
|
+
`@nice2dev/icons ^1.2.1` where a package draws an icon new in 1.2.1: ui-mobile (`NtdReply`,
|
|
35
|
+
`NtdInbox`), ui-audio (`NtdMicrophoneOff`) and ui-security (`NtdBackspace`). ui-security, licensing
|
|
36
|
+
(`^1.2.0`) and templates (`^1.2.0`) gain the `@nice2dev/icons` peer: their glyph icons (`⌫`, `←`,
|
|
37
|
+
`→`, `↑`, `↓`) are Nice icons now. `@nice2dev/icons` adds `NtdBackspace`.
|
|
38
|
+
|
|
39
|
+
**Class names inside components.** 834 class names in library stylesheets had no `nice-` prefix
|
|
40
|
+
(`.tab-button`, `.status-badge`, `.selected`, …) and styled every element of that name on the page.
|
|
41
|
+
They follow `nice-{block}__{element}--{modifier}` now — no change on screen. The class theme hooks
|
|
42
|
+
next to `[data-theme]` on seven controls (`dark` on the AI chart / data grid / code and HTML
|
|
43
|
+
editors / form builder, `light-theme` on `NiceMAM` and `NiceVideoAnnotator`) are `nice-dark` /
|
|
44
|
+
`nice-light`; `NiceLowPowerMode` marks `<html>` with `nice-lpm-no-animations` /
|
|
45
|
+
`nice-lpm-reduced-quality`; the `NiceVideoEditor` of `@nice2dev/ui-video` styles its elements under
|
|
46
|
+
`nice-video-studio`, so they no longer collide with the `NiceVideoEditor` of `@nice2dev/ui`.
|
|
47
|
+
Rules for classes nothing rendered are gone, among them the stylesheet of `NiceGanttChart`, which
|
|
48
|
+
left ui-erp in 1.0.10.
|
|
49
|
+
|
|
50
|
+
**Translations.** About 3,400 UI texts in 32 packages were hard-coded; they go through `t()` now,
|
|
51
|
+
with the English text unchanged and pl / de / fr / es / uk in `@nice2dev/i18n` (ui-diagrams,
|
|
52
|
+
ui-presentations and ui-math in their own dictionaries). In `@nice2dev/events` and
|
|
53
|
+
`@nice2dev/admin` that includes column headers, option labels and the statuses and roles they used
|
|
54
|
+
to print raw (`checked-in`, `no-show`) — English labels for those come from the dictionary. ui-3d and ui-graphics read the app's
|
|
55
|
+
global translator, as ui-audio does since 1.2.0 — their own provider overrides it. ui-audio's
|
|
56
|
+
controls used 631 keys the dictionary did not have (English in every language), and the radio
|
|
57
|
+
player showed raw keys (`search_stations`). Texts that were hard-coded **in Polish** — in
|
|
58
|
+
`NiceSidebarNav`, `NiceNetworkDiscoveryPanel`, the backup and smart-home controls,
|
|
59
|
+
`NiceSavedQueryPanel`, `NiceNotificationPreferences`, the ui-buildings panels, the ui-printing
|
|
60
|
+
template editor and the photo editor — default to English now; Polish is in the dictionary. English
|
|
61
|
+
plurals glued on (`result{s}`) are two keys. `presentationsTranslator(lang)` (ui-presentations)
|
|
62
|
+
translates outside its provider.
|
|
63
|
+
|
|
64
|
+
**List props are optional.** 170 list props (`items`, `columns`, `data`, …) in 15 packages that
|
|
65
|
+
were required without a default are optional, with a stable empty default; every one of those
|
|
66
|
+
controls mounts without data (tested). `NiceStockChart` without data no longer computes NaN
|
|
67
|
+
coordinates.
|
|
68
|
+
|
|
69
|
+
**Unstyled components get stylesheets.** 98 components rendered class names no stylesheet had —
|
|
70
|
+
admin panels, auth forms, events rounds and pickers, the ERP invoice / purchase order / VAT table /
|
|
71
|
+
HR dashboard, the radio player, `NiceInbox`, PWA prompts, `NiceViewRenderer`, shells, smart-home,
|
|
72
|
+
… The fixed layout that sat in inline style objects is in classes now, so an app can override it;
|
|
73
|
+
values that depend on data stay inline. **`@nice2dev/social` and `@nice2dev/ui-science` ship a
|
|
74
|
+
stylesheet — import `@nice2dev/social/style.css` / `@nice2dev/ui-science/style.css`.** ui-science's
|
|
75
|
+
`sideEffects` is `["*.css"]`. Colours, spacing and radii in every stylesheet come from theme tokens
|
|
76
|
+
(visible in dark themes: `NiceRecipe` difficulty badges, transcoder states, warehouse heat map).
|
|
77
|
+
|
|
78
|
+
**Icons only from Nice.** About 130 glyphs (`×`, `→`, `↑`) and 100 pasted `<svg>` used as icons
|
|
79
|
+
are Nice icons; 11 `<svg>` stay as the control's own graphic (logos, spinners, checkbox mark). `NiceIcon`
|
|
80
|
+
gains `pin`, `mic-off`, `log-out`, `chevrons-left`, `chevrons-right`, `zoom-in`, `zoom-out`,
|
|
81
|
+
`navigation`, `refresh-ccw`, `minimize` and `smartphone`; `@nice2dev/icons` gains
|
|
82
|
+
`NtdMicrophoneOff`. The `icon` fields of the module, menu, tab, mode, quick-action, scene and admin
|
|
83
|
+
widget DTOs, notification channels and view toolbar items are rendered through `NiceIcon` — they
|
|
84
|
+
used to be printed as text. `NiceRatings` `thumbs` draws shapes instead of emoji.
|
|
85
|
+
|
|
86
|
+
**Dialogs instead of `window.prompt` / `confirm` / `alert`.** New `useNiceDialogs()` — `prompt`,
|
|
87
|
+
`confirm` and `alert` as promises on `NicePromptDialog` / `NiceConfirmDialog` — and
|
|
88
|
+
`NiceConfirmDialog.showReject`. Seventeen controls asked through the browser's blocking dialogs and
|
|
89
|
+
use the library's now (`NiceFileManager`, `NiceHtmlEditor`, `NiceViewRenderer` action `confirm`, the 3D,
|
|
90
|
+
vector and pixel editors, …). Keys pressed in `NicePromptDialog` / `NiceConfirmDialog` no longer
|
|
91
|
+
reach the page's shortcuts (Escape still closes them), and `NicePromptDialog`'s backdrop covers the
|
|
92
|
+
whole viewport.
|
|
93
|
+
|
|
94
|
+
**Smaller fixes.** `NiceFileManager.items` is optional. `NiceMLStudio` status badges: `draft`,
|
|
95
|
+
`registered`, `archived`, `cancelled` get a neutral colour, deploying / stopped deployments theirs.
|
|
96
|
+
Component docs (`doc.json`) list only props the components have. `NiceMobileTabs`: tabs beyond
|
|
97
|
+
`maxTabs` open from "More" (it only logged). `NiceInventoryManager`: new `onCreatePurchaseOrder`;
|
|
98
|
+
without it the "Create PO" button is gone (it only logged). Keyboard: `NiceNavShell` tabs follow the
|
|
99
|
+
WAI-ARIA tabs pattern, clickable `NiceDeviceTile` / `NiceCardGroup` cards and animated icons with
|
|
100
|
+
`trigger="click"` are focusable. ui-math: `CalculatorService.evaluate` parses instead of running
|
|
101
|
+
`new Function` (`asin`, `sinh`, `ceil`, exponents and `angleUnit` were wrong); `ExpressionParser`
|
|
102
|
+
takes `functions`, `constants`, `ignoreCase` and `strict`, multiplies implicitly (`2x`) and reads `^`
|
|
103
|
+
right to left. `InvoiceLine.vatRate` and `VatRate.rate` are documented as fractions (0.23).
|
|
104
|
+
`AmqpServerBinding` is `Record<string, never>`.
|
|
105
|
+
|
|
3
106
|
## 1.2.0
|
|
4
107
|
|
|
5
108
|
### Minor Changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var ui = require('@nice2dev/ui');
|
|
5
|
+
var React = require('react');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The library's dialogs in place of `window.prompt` / `window.confirm` for the editor hooks,
|
|
9
|
+
* which hold state but render nothing: `ask` resolves with the answer (`null` when cancelled)
|
|
10
|
+
* and `pendingAsk` is the open question, for the editor component to pass to
|
|
11
|
+
* {@link EditorAskDialog}. One question at a time: a new one settles the open one as cancelled.
|
|
12
|
+
*/
|
|
13
|
+
function useEditorAsk() {
|
|
14
|
+
const [pendingAsk, setPendingAsk] = React.useState(null);
|
|
15
|
+
const pendingRef = React.useRef(null);
|
|
16
|
+
const ask = React.useCallback((kind, text, defaultValue) => new Promise((resolve) => {
|
|
17
|
+
var _a;
|
|
18
|
+
(_a = pendingRef.current) === null || _a === void 0 ? void 0 : _a.answer(null);
|
|
19
|
+
const next = {
|
|
20
|
+
kind,
|
|
21
|
+
text,
|
|
22
|
+
defaultValue,
|
|
23
|
+
answer: (value) => {
|
|
24
|
+
if (pendingRef.current === next) {
|
|
25
|
+
pendingRef.current = null;
|
|
26
|
+
setPendingAsk(null);
|
|
27
|
+
}
|
|
28
|
+
resolve(value);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
pendingRef.current = next;
|
|
32
|
+
setPendingAsk(next);
|
|
33
|
+
}), []);
|
|
34
|
+
return { pendingAsk, ask };
|
|
35
|
+
}
|
|
36
|
+
/** Shows the question {@link useEditorAsk} is waiting on, if any. */
|
|
37
|
+
const EditorAskDialog = ({ ask }) => {
|
|
38
|
+
if (!ask) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
if (ask.kind === 'confirm') {
|
|
42
|
+
return (jsxRuntime.jsx(ui.NiceConfirmDialog, { visible: true, message: ask.text, onAccept: () => ask.answer(''), onReject: () => ask.answer(null) }));
|
|
43
|
+
}
|
|
44
|
+
return (jsxRuntime.jsx(ui.NicePromptDialog, { open: true, title: ask.text, defaultValue: ask.defaultValue, onSubmit: (value) => ask.answer(value), onCancel: () => ask.answer(null) }));
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
exports.EditorAskDialog = EditorAskDialog;
|
|
48
|
+
exports.useEditorAsk = useEditorAsk;
|
package/dist/cjs/core/i18n.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var ui = require('@nice2dev/ui');
|
|
4
5
|
var React = require('react');
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
const NiceI18nContext = React.createContext(
|
|
7
|
+
/** `null` outside this package's provider: the global translator applies. */
|
|
8
|
+
const NiceI18nContext = /* @__PURE__ */ React.createContext(null);
|
|
9
|
+
/** Overrides the app's global translator for the 3D controls below it. */
|
|
8
10
|
const NiceI18nProvider = ({ t, children }) => (jsxRuntime.jsx(NiceI18nContext.Provider, { value: t, children: children }));
|
|
9
11
|
function useNiceTranslation() {
|
|
10
|
-
const
|
|
12
|
+
const own = React.useContext(NiceI18nContext);
|
|
13
|
+
const { t: global } = ui.useNiceTranslation();
|
|
14
|
+
const t = React.useMemo(() => own !== null && own !== void 0 ? own : ((key, defaultValue) => global(key, defaultValue)), [own, global]);
|
|
11
15
|
return { t };
|
|
12
16
|
}
|
|
13
17
|
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* DanceScoreEngine — Compares detected poses against reference choreography
|
|
7
|
+
*
|
|
8
|
+
* Calculates real-time dance accuracy by comparing camera-detected Pose3DFrames
|
|
9
|
+
* against a reference sequence (from choreography DSL or recorded poses).
|
|
10
|
+
*/
|
|
5
11
|
// ── Default config ──────────────────────────────────────────────
|
|
6
12
|
const DEFAULT_CONFIG = {
|
|
7
13
|
keypointWeights: {},
|
|
@@ -192,6 +198,7 @@ class DanceScoreEngine {
|
|
|
192
198
|
return 'F';
|
|
193
199
|
}
|
|
194
200
|
}
|
|
201
|
+
// ── React hook ──────────────────────────────────────────────────
|
|
195
202
|
function useDanceScore(config) {
|
|
196
203
|
const engineRef = React.useRef(new DanceScoreEngine(config));
|
|
197
204
|
const [lastScore, setLastScore] = React.useState(null);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var ui = require('@nice2dev/ui');
|
|
5
5
|
var React = require('react');
|
|
6
|
+
var i18n = require('../core/i18n.js');
|
|
6
7
|
|
|
7
8
|
// ── Standard keypoint definitions (COCO 17-keypoint model) ──────
|
|
8
9
|
const COCO_KEYPOINTS = [
|
|
@@ -149,7 +150,8 @@ function usePoseDetection(config = {}) {
|
|
|
149
150
|
return { start, stop, isDetecting, getLatestFrame: () => latestFrameRef.current };
|
|
150
151
|
}
|
|
151
152
|
// ── Component: PoseDetector ─────────────────────────────────────
|
|
152
|
-
const NicePoseDetector = React.forwardRef(function NicePoseDetector(props, ref) {
|
|
153
|
+
const NicePoseDetector = /* @__PURE__ */ React.forwardRef(function NicePoseDetector(props, ref) {
|
|
154
|
+
const { t } = i18n.useNiceTranslation();
|
|
153
155
|
const { onFrame, onStart, onStop, onError, className, style, width = 640, height = 480, mirror = true, showSkeleton = true, showConfidence = false, ...config } = props;
|
|
154
156
|
const videoRef = React.useRef(null);
|
|
155
157
|
const canvasRef = React.useRef(null);
|
|
@@ -285,7 +287,7 @@ const NicePoseDetector = React.forwardRef(function NicePoseDetector(props, ref)
|
|
|
285
287
|
cursor: 'pointer',
|
|
286
288
|
fontSize: 14,
|
|
287
289
|
fontWeight: 600,
|
|
288
|
-
}, children:
|
|
290
|
+
}, children: t('poseDetector.startCamera', 'Start Camera') }))] }));
|
|
289
291
|
});
|
|
290
292
|
|
|
291
293
|
exports.NicePoseDetector = NicePoseDetector;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var ui = require('@nice2dev/ui');
|
|
5
5
|
var React = require('react');
|
|
6
|
+
var i18n = require('../core/i18n.js');
|
|
6
7
|
var MaterialEditor_module = require('./MaterialEditor.module.css.js');
|
|
7
8
|
var materialEditorTypes = require('./materialEditorTypes.js');
|
|
8
9
|
var materialEditorUtils = require('./materialEditorUtils.js');
|
|
@@ -367,6 +368,7 @@ function useMaterialEditor(initialGraph) {
|
|
|
367
368
|
return { state, dispatch };
|
|
368
369
|
}
|
|
369
370
|
function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCategory, onAddNode, onDragStart, }) {
|
|
371
|
+
const { t } = i18n.useNiceTranslation();
|
|
370
372
|
const filteredNodes = searchQuery ? materialNodeDefinitions.searchNodes(searchQuery) : materialNodeDefinitions.MATERIAL_NODE_DEFINITIONS;
|
|
371
373
|
const categories = React.useMemo(() => {
|
|
372
374
|
const cats = new Map();
|
|
@@ -378,7 +380,7 @@ function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCatego
|
|
|
378
380
|
}
|
|
379
381
|
return cats;
|
|
380
382
|
}, [filteredNodes]);
|
|
381
|
-
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.palette, children: [jsxRuntime.jsx("div", { className: MaterialEditor_module.paletteSearch, children: jsxRuntime.jsx("input", { type: "text", placeholder:
|
|
383
|
+
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.palette, children: [jsxRuntime.jsx("div", { className: MaterialEditor_module.paletteSearch, children: jsxRuntime.jsx("input", { type: "text", placeholder: t('materialEditor.searchNodes', 'Search nodes...'), value: searchQuery, onChange: (e) => onSearch(e.target.value), className: MaterialEditor_module.searchInput }) }), jsxRuntime.jsx("div", { className: MaterialEditor_module.paletteCategories, children: Array.from(categories.entries()).map(([category, nodes]) => (jsxRuntime.jsxs("div", { className: MaterialEditor_module.paletteCategory, children: [jsxRuntime.jsxs("button", { className: MaterialEditor_module.categoryHeader, onClick: () => onToggleCategory(category), style: { borderLeftColor: materialEditorTypes.NODE_CATEGORY_COLORS[category] }, children: [jsxRuntime.jsx("span", { className: MaterialEditor_module.categoryIcon, children: jsxRuntime.jsx(ui.NiceIcon, { name: expandedCategories.includes(category) ? 'chevron-down' : 'chevron-right', size: 14 }) }), jsxRuntime.jsx("span", { children: materialEditorTypes.NODE_CATEGORY_NAMES[category] }), jsxRuntime.jsx("span", { className: MaterialEditor_module.categoryCount, children: nodes.length })] }), expandedCategories.includes(category) && (jsxRuntime.jsx("div", { className: MaterialEditor_module.categoryNodes, children: nodes.map((nodeDef) => (jsxRuntime.jsxs("div", { className: MaterialEditor_module.paletteNode, draggable: true, onDragStart: (e) => onDragStart(nodeDef.type, e), onDoubleClick: () => onAddNode(nodeDef.type), title: nodeDef.description, children: [jsxRuntime.jsx("span", { className: MaterialEditor_module.nodeColor, style: {
|
|
382
384
|
backgroundColor: nodeDef.color || materialEditorTypes.NODE_CATEGORY_COLORS[nodeDef.category],
|
|
383
385
|
} }), jsxRuntime.jsx("span", { className: MaterialEditor_module.nodeName, children: nodeDef.name })] }, nodeDef.type))) }))] }, category))) })] }));
|
|
384
386
|
}
|
|
@@ -454,9 +456,11 @@ function GraphNode({ node, definition, selected, viewTransform, connections, onS
|
|
|
454
456
|
}) })] })), node.comment && jsxRuntime.jsx("div", { className: MaterialEditor_module.nodeComment, children: node.comment })] }));
|
|
455
457
|
}
|
|
456
458
|
function Toolbar({ canUndo, canRedo, canPaste, hasSelection, autoCompile, compiling, showGrid, snapToGrid, onUndo, onRedo, onCopy, onCut, onPaste, onDuplicate, onDelete, onSelectAll, onZoomToFit, onToggleGrid, onToggleSnap, onToggleAutoCompile, onCompile, onNew, onExport, onImport, }) {
|
|
457
|
-
|
|
459
|
+
const { t } = i18n.useNiceTranslation();
|
|
460
|
+
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbar, children: [jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onNew, title: t('materialEditor.newMaterialCtrlN', 'New Material (Ctrl+N)'), "aria-label": t('materialEditor.newMaterial', 'New Material'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "file", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onImport, title: t('materialEditor.importCtrlO', 'Import (Ctrl+O)'), "aria-label": t('materialEditor.import', 'Import'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "folder", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onExport, title: t('materialEditor.exportCtrlS', 'Export (Ctrl+S)'), "aria-label": t('materialEditor.export', 'Export'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "save", size: 16 }) })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onUndo, disabled: !canUndo, title: t('materialEditor.undoCtrlZ', 'Undo (Ctrl+Z)'), "aria-label": t('materialEditor.undo', 'Undo'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "arrow-left", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onRedo, disabled: !canRedo, title: t('materialEditor.redoCtrlY', 'Redo (Ctrl+Y)'), "aria-label": t('materialEditor.redo', 'Redo'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "arrow-right", size: 16 }) })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onCut, disabled: !hasSelection, title: t('materialEditor.cutCtrlX', 'Cut (Ctrl+X)'), "aria-label": t('materialEditor.cut', 'Cut'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "scissors", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onCopy, disabled: !hasSelection, title: t('materialEditor.copyCtrlC', 'Copy (Ctrl+C)'), "aria-label": t('materialEditor.copy', 'Copy'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "clipboard", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onPaste, disabled: !canPaste, title: t('materialEditor.pasteCtrlV', 'Paste (Ctrl+V)'), "aria-label": t('materialEditor.paste', 'Paste'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "download", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onDuplicate, disabled: !hasSelection, title: t('materialEditor.duplicateCtrlD', 'Duplicate (Ctrl+D)'), "aria-label": t('materialEditor.duplicate', 'Duplicate'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "refresh", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onDelete, disabled: !hasSelection, title: t('materialEditor.deleteDel', 'Delete (Del)'), "aria-label": t('materialEditor.delete', 'Delete'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "trash", size: 16 }) })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onSelectAll, title: t('materialEditor.selectAllCtrlA', 'Select All (Ctrl+A)'), "aria-label": t('materialEditor.selectAll', 'Select All'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "square", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onZoomToFit, title: t('materialEditor.zoomToFitF', 'Zoom to Fit (F)'), "aria-label": t('materialEditor.zoomToFit', 'Zoom to Fit'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "search", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onToggleGrid, className: showGrid ? MaterialEditor_module.active : '', title: t('materialEditor.toggleGridG', 'Toggle Grid (G)'), "aria-label": t('materialEditor.toggleGrid', 'Toggle Grid'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "hash", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onToggleSnap, className: snapToGrid ? MaterialEditor_module.active : '', title: t('materialEditor.toggleSnapS', 'Toggle Snap (S)'), "aria-label": t('materialEditor.toggleSnap', 'Toggle Snap'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "target", size: 16 }) })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onToggleAutoCompile, className: autoCompile ? MaterialEditor_module.active : '', title: t('materialEditor.autoCompile', 'Auto Compile'), "aria-label": t('materialEditor.autoCompile', 'Auto Compile'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "zap", size: 16 }) }), jsxRuntime.jsx("button", { onClick: onCompile, disabled: compiling, title: t('materialEditor.compileF5', 'Compile (F5)'), "aria-label": t('materialEditor.compile', 'Compile'), children: jsxRuntime.jsx(ui.NiceIcon, { name: compiling ? 'clock' : 'play', size: 16 }) })] })] }));
|
|
458
461
|
}
|
|
459
462
|
function PreviewPanel({ shader, mode, compiling, onModeChange }) {
|
|
463
|
+
const { t } = i18n.useNiceTranslation();
|
|
460
464
|
const canvasRef = React.useRef(null);
|
|
461
465
|
const previewModes = ['sphere', 'cube', 'plane', 'cylinder', 'torus'];
|
|
462
466
|
// Simple preview rendering (in real implementation would use Three.js)
|
|
@@ -486,7 +490,7 @@ function PreviewPanel({ shader, mode, compiling, onModeChange }) {
|
|
|
486
490
|
ctx.arc(100, 100, 80, 0, Math.PI * 2);
|
|
487
491
|
ctx.fill();
|
|
488
492
|
}, [shader, mode]);
|
|
489
|
-
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewPanel, children: [jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewHeader, children: [jsxRuntime.jsx("span", { children:
|
|
493
|
+
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewPanel, children: [jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewHeader, children: [jsxRuntime.jsx("span", { children: t('materialEditor.preview', 'Preview') }), jsxRuntime.jsx("select", { value: mode, onChange: (e) => onModeChange(e.target.value), className: MaterialEditor_module.previewModeSelect, children: previewModes.map((m) => (jsxRuntime.jsx("option", { value: m, children: m.charAt(0).toUpperCase() + m.slice(1) }, m))) })] }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewCanvas, children: [compiling && (jsxRuntime.jsx("div", { className: MaterialEditor_module.previewCompiling, children: t('materialEditor.compiling', 'Compiling...') })), jsxRuntime.jsx("canvas", { ref: canvasRef, width: 200, height: 200 })] }), (shader === null || shader === void 0 ? void 0 : shader.errors.length) ? (jsxRuntime.jsx("div", { className: MaterialEditor_module.previewErrors, children: shader.errors.slice(0, 3).map((err, i) => (jsxRuntime.jsx("div", { className: MaterialEditor_module.previewError, children: err.message }, i))) })) : null] }));
|
|
490
494
|
}
|
|
491
495
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
492
496
|
Main Component
|
|
@@ -44,7 +44,7 @@ const PORT_TYPE_COLORS = {
|
|
|
44
44
|
vec4: 'var(--nice-warning, #ffc107)',
|
|
45
45
|
color: 'var(--nice-danger, #ff5722)',
|
|
46
46
|
texture2d: 'var(--nice-info, #00bcd4)',
|
|
47
|
-
textureCube: '#03A9F4',
|
|
47
|
+
textureCube: 'var(--nice-color-primary, #03A9F4)',
|
|
48
48
|
sampler: 'var(--nice-accent, #3f51b5)',
|
|
49
49
|
matrix3: 'var(--nice-accent, #673ab7)',
|
|
50
50
|
matrix4: 'var(--nice-accent, #9c27b0)',
|
|
@@ -1452,17 +1452,20 @@ const logicNodes = [
|
|
|
1452
1452
|
EXPORTS
|
|
1453
1453
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
1454
1454
|
/** All built-in node definitions */
|
|
1455
|
-
const MATERIAL_NODE_DEFINITIONS =
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1455
|
+
const MATERIAL_NODE_DEFINITIONS =
|
|
1456
|
+
/* @__PURE__ */ (function () {
|
|
1457
|
+
return [
|
|
1458
|
+
...inputNodes,
|
|
1459
|
+
...outputNodes,
|
|
1460
|
+
...mathNodes,
|
|
1461
|
+
...vectorNodes,
|
|
1462
|
+
...colorNodes,
|
|
1463
|
+
...textureNodes,
|
|
1464
|
+
...proceduralNodes,
|
|
1465
|
+
...utilityNodes,
|
|
1466
|
+
...logicNodes,
|
|
1467
|
+
];
|
|
1468
|
+
})();
|
|
1466
1469
|
/** Node definitions map by type */
|
|
1467
1470
|
const MATERIAL_NODE_MAP = new Map(MATERIAL_NODE_DEFINITIONS.map((def) => [def.type, def]));
|
|
1468
1471
|
/** Get nodes by category */
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var ui = require('@nice2dev/ui');
|
|
5
|
+
var editorAsk = require('../core/editorAsk.js');
|
|
5
6
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
6
7
|
var ModelEditorLeftPanel = require('./ModelEditorLeftPanel.js');
|
|
7
8
|
var ModelEditorMenuBar = require('./ModelEditorMenuBar.js');
|
|
@@ -12,7 +13,7 @@ var modelEditorTypes = require('./modelEditorTypes.js');
|
|
|
12
13
|
var ModelEditorViewport = require('./ModelEditorViewport.js');
|
|
13
14
|
var useModelEditor = require('./useModelEditor.js');
|
|
14
15
|
|
|
15
|
-
const ACCEPT = modelEditorTypes.SUPPORTED_EXTENSIONS.map((e) => `.${e}`).join(',');
|
|
16
|
+
const ACCEPT = /* @__PURE__ */ modelEditorTypes.SUPPORTED_EXTENSIONS.map((e) => `.${e}`).join(',');
|
|
16
17
|
const NiceModelEditor = ({ className, onSaveToLibrary, onAIPoseVideo, }) => {
|
|
17
18
|
const api = useModelEditor.useModelEditor({ onSaveToLibrary, onAIPoseVideo });
|
|
18
19
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { ref: api.fileInputRef, type: "file", accept: ACCEPT, style: { display: 'none' }, onChange: (e) => {
|
|
@@ -29,7 +30,7 @@ const NiceModelEditor = ({ className, onSaveToLibrary, onAIPoseVideo, }) => {
|
|
|
29
30
|
api.mergeAnimationFBX(f);
|
|
30
31
|
}
|
|
31
32
|
e.target.value = '';
|
|
32
|
-
} }), jsxRuntime.jsx("input", { ref: api.videoInputRef, type: "file", accept: "video/*", style: { display: 'none' }, onChange: api.handleAIVideo }), jsxRuntime.jsx(ui.NiceAppShell, { className: `${ModelEditor_module.root} ${className !== null && className !== void 0 ? className : ''}`, flush: true, menubar: jsxRuntime.jsx(ModelEditorMenuBar, { api: api, hasOnSaveToLibrary: !!onSaveToLibrary }), sidebar: jsxRuntime.jsxs("div", { style: { display: 'flex', minHeight: 0 }, children: [jsxRuntime.jsx(ModelEditorLeftPanel, { api: api }), jsxRuntime.jsx(ModelEditorToolbar, { api: api })] }), rightSidebar: jsxRuntime.jsx(ModelEditorRightPanel, { api: api }), bottomPanel: jsxRuntime.jsx(ModelEditorTimeline, { api: api }), statusBar: jsxRuntime.jsxs("div", { className: ModelEditor_module.statusBar, children: [jsxRuntime.jsx("span", { children: api.statusText }), jsxRuntime.jsxs("span", { style: { marginLeft: 'auto' }, children: [api.polyCount.toLocaleString(), " triangles \u00B7 ", api.meshCount, " meshes \u00B7 ", api.boneCount, ' ', "bones \u00B7 ", api.animations.length, " anim(s)"] })] }), children: jsxRuntime.jsx(ModelEditorViewport, { api: api }) })] }));
|
|
33
|
+
} }), jsxRuntime.jsx("input", { ref: api.videoInputRef, type: "file", accept: "video/*", style: { display: 'none' }, onChange: api.handleAIVideo }), jsxRuntime.jsx(editorAsk.EditorAskDialog, { ask: api.pendingAsk }), jsxRuntime.jsx(ui.NiceAppShell, { className: `${ModelEditor_module.root} ${className !== null && className !== void 0 ? className : ''}`, flush: true, menubar: jsxRuntime.jsx(ModelEditorMenuBar, { api: api, hasOnSaveToLibrary: !!onSaveToLibrary }), sidebar: jsxRuntime.jsxs("div", { style: { display: 'flex', minHeight: 0 }, children: [jsxRuntime.jsx(ModelEditorLeftPanel, { api: api }), jsxRuntime.jsx(ModelEditorToolbar, { api: api })] }), rightSidebar: jsxRuntime.jsx(ModelEditorRightPanel, { api: api }), bottomPanel: jsxRuntime.jsx(ModelEditorTimeline, { api: api }), statusBar: jsxRuntime.jsxs("div", { className: ModelEditor_module.statusBar, children: [jsxRuntime.jsx("span", { children: api.statusText }), jsxRuntime.jsxs("span", { style: { marginLeft: 'auto' }, children: [api.polyCount.toLocaleString(), " triangles \u00B7 ", api.meshCount, " meshes \u00B7 ", api.boneCount, ' ', "bones \u00B7 ", api.animations.length, " anim(s)"] })] }), children: jsxRuntime.jsx(ModelEditorViewport, { api: api }) })] }));
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
exports.NiceModelEditor = NiceModelEditor;
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var ui = require('@nice2dev/ui');
|
|
5
5
|
var React = require('react');
|
|
6
|
+
var i18n = require('../core/i18n.js');
|
|
6
7
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
7
8
|
|
|
8
|
-
const ModelEditorLeftPanel =
|
|
9
|
+
const ModelEditorLeftPanel = /* @__PURE__ */ Object.assign(
|
|
10
|
+
/* @__PURE__ */ React.memo(({ api }) => {
|
|
11
|
+
const { t } = i18n.useNiceTranslation();
|
|
9
12
|
const { sceneTree, selectedId, outlinerSearch, setOutlinerSearch, selectObject, rebuildTree, toggleNodeExpanded, toggleNodeVisibility, } = api;
|
|
10
13
|
const renderTreeNode = (node, depth) => {
|
|
11
14
|
// Outliner search filter
|
|
@@ -39,8 +42,11 @@ const ModelEditorLeftPanel = React.memo(({ api }) => {
|
|
|
39
42
|
toggleNodeVisibility(node);
|
|
40
43
|
}, children: jsxRuntime.jsx(ui.NiceIcon, { name: node.visible ? 'eye' : 'eye-off', size: 14 }) })] }), node.expanded && node.children.map((c) => renderTreeNode(c, depth + 1))] }, node.id));
|
|
41
44
|
};
|
|
42
|
-
return (jsxRuntime.jsx("div", { className: ModelEditor_module.leftPanel, children: jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.panelTitle, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "clipboard", size: 14 }), "
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
return (jsxRuntime.jsx("div", { className: ModelEditor_module.leftPanel, children: jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.panelTitle, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "clipboard", size: 14 }), " ", t('modelEditorLeftPanel.outliner', 'Outliner'), jsxRuntime.jsx(ui.NiceButton, { variant: "ghost", size: "sm", onClick: rebuildTree, title: t('modelEditorLeftPanel.refresh', 'Refresh'), "aria-label": t('modelEditorLeftPanel.refreshOutliner', 'Refresh outliner'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "refresh", size: 14 }) })] }), jsxRuntime.jsx("div", { className: ModelEditor_module.outlinerSearch, children: jsxRuntime.jsx(ui.NiceTextInput, { className: ModelEditor_module.propInput, placeholder: t('modelEditorLeftPanel.filter', 'Filter...'), value: outlinerSearch, onChange: (val) => setOutlinerSearch(val), style: { width: '100%', marginBottom: 4 } }) }), jsxRuntime.jsxs("div", { className: ModelEditor_module.panelContent, style: { overflowY: 'auto', flex: 1 }, children: [sceneTree.length === 0 && (jsxRuntime.jsx("div", { style: {
|
|
46
|
+
color: 'var(--nice-text-secondary, #666)',
|
|
47
|
+
fontSize: 10,
|
|
48
|
+
padding: '8px 0',
|
|
49
|
+
}, children: t('modelEditorLeftPanel.dropA3dFileTo', 'Drop a 3D file to begin') })), sceneTree.map((n) => renderTreeNode(n, 0))] })] }) }));
|
|
50
|
+
}), { displayName: 'ModelEditorLeftPanel' });
|
|
45
51
|
|
|
46
52
|
module.exports = ModelEditorLeftPanel;
|
|
@@ -3,15 +3,18 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var ui = require('@nice2dev/ui');
|
|
5
5
|
var React = require('react');
|
|
6
|
+
var i18n = require('../core/i18n.js');
|
|
6
7
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
7
8
|
|
|
8
|
-
const ModelEditorMenuBar =
|
|
9
|
+
const ModelEditorMenuBar = /* @__PURE__ */ Object.assign(
|
|
10
|
+
/* @__PURE__ */ React.memo(({ api, hasOnSaveToLibrary }) => {
|
|
11
|
+
const { t } = i18n.useNiceTranslation();
|
|
9
12
|
const { editorMode, setEditorMode, fileInputRef, mergeInputRef, addMenuOpen, setAddMenuOpen, addPrimitive, addSceneLight, addCameraObject, addEmpty, selectedNode, duplicateSelected, deleteSelected, exportGLTF, exportOBJ, exportSTL, exportPLY, exportUSDZ, saveToLibrary, clearScene, showGrid, setShowGrid, showAxes, setShowAxes, wireframe, setWireframe, showSkeleton, setShowSkeleton, showLightHelpers, setShowLightHelpers, bgColor, setBgColor, } = api;
|
|
10
13
|
return (jsxRuntime.jsxs("div", { className: ModelEditor_module.menuBar, children: [jsxRuntime.jsx(ui.NiceSelect, { className: ModelEditor_module.modeSelect, value: editorMode, onChange: (val) => setEditorMode(val), options: [
|
|
11
14
|
{ value: 'object', label: 'Object Mode' },
|
|
12
15
|
{ value: 'edit', label: 'Edit Mode' },
|
|
13
16
|
{ value: 'pose', label: 'Pose Mode' },
|
|
14
|
-
] }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "folder", size: 14 }), " Open
|
|
17
|
+
] }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "folder", size: 14 }), " ", t('modelEditorMenuBar.open', 'Open')] }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => { var _a; return (_a = mergeInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, title: t('modelEditorMenuBar.mergeAnimationsFromFbxGltf', 'Merge animations from FBX/GLTF onto current model'), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "plus", size: 14 }), " ", t('modelEditorMenuBar.mergeAnim', 'Merge Anim')] }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsxs("div", { className: ModelEditor_module.menuDropdownWrap, children: [jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => setAddMenuOpen(addMenuOpen ? null : 'mesh'), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "plus", size: 14 }), " Add ", jsxRuntime.jsx(ui.NiceIcon, { name: "chevron-down", size: 14 })] }), addMenuOpen && (jsxRuntime.jsxs("div", { className: ModelEditor_module.dropdownMenu, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownTitle, children: t('modelEditorMenuBar.mesh', 'Mesh') }), [
|
|
15
18
|
'cube',
|
|
16
19
|
'sphere',
|
|
17
20
|
'cylinder',
|
|
@@ -25,8 +28,7 @@ const ModelEditorMenuBar = React.memo(({ api, hasOnSaveToLibrary }) => {
|
|
|
25
28
|
'octahedron',
|
|
26
29
|
'tetrahedron',
|
|
27
30
|
'torusKnot',
|
|
28
|
-
].map((t) => (jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownItem, onClick: () => addPrimitive(t), children: t.charAt(0).toUpperCase() + t.slice(1) }, t))), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownSep }), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownTitle, children:
|
|
29
|
-
});
|
|
30
|
-
ModelEditorMenuBar.displayName = 'ModelEditorMenuBar';
|
|
31
|
+
].map((t) => (jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownItem, onClick: () => addPrimitive(t), children: t.charAt(0).toUpperCase() + t.slice(1) }, t))), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownSep }), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownTitle, children: t('modelEditorMenuBar.light', 'Light') }), ['point', 'spot', 'directional', 'hemisphere'].map((t) => (jsxRuntime.jsxs("div", { className: ModelEditor_module.dropdownItem, onClick: () => addSceneLight(t), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "lightbulb", size: 14 }), " ", t.charAt(0).toUpperCase() + t.slice(1)] }, t))), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownSep }), jsxRuntime.jsx("div", { className: ModelEditor_module.dropdownTitle, children: t('modelEditorMenuBar.other', 'Other') }), jsxRuntime.jsxs("div", { className: ModelEditor_module.dropdownItem, onClick: addCameraObject, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "camera", size: 14 }), " ", t('modelEditorMenuBar.camera', 'Camera')] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.dropdownItem, onClick: () => addEmpty('arrows'), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "move", size: 14 }), " Empty (Arrows)"] })] }))] }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: duplicateSelected, disabled: !selectedNode, title: t('modelEditorMenuBar.duplicateSelectedShiftD', 'Duplicate selected (Shift+D)'), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "clipboard", size: 14 }), " ", t('modelEditorMenuBar.duplicate', 'Duplicate')] }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: deleteSelected, disabled: !selectedNode, title: t('modelEditorMenuBar.deleteSelectedDelete', 'Delete selected (Delete)'), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "close", size: 14 }), " ", t('modelEditorMenuBar.delete', 'Delete')] }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => exportGLTF(true), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "save", size: 14 }), " ", t('modelEditorMenuBar.exportGlb', 'Export GLB')] }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => exportGLTF(false), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "file", size: 14 }), " ", t('modelEditorMenuBar.exportGltf', 'Export GLTF')] }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: exportOBJ, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "file", size: 14 }), " ", t('modelEditorMenuBar.exportObj', 'Export OBJ')] }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => exportSTL(true), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "file", size: 14 }), " ", t('modelEditorMenuBar.exportStl', 'Export STL')] }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: () => exportPLY(true), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "file", size: 14 }), " ", t('modelEditorMenuBar.exportPly', 'Export PLY')] }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: exportUSDZ, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "file", size: 14 }), " ", t('modelEditorMenuBar.exportUsdz', 'Export USDZ')] }), hasOnSaveToLibrary && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: saveToLibrary, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "box", size: 14 }), ' ', t('modelEditorMenuBar.saveToLibrary', 'Save to Library')] })] })), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsxs(ui.NiceButton, { className: ModelEditor_module.menuBtn, variant: "ghost", size: "sm", onClick: clearScene, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "trash", size: 14 }), " ", t('modelEditorMenuBar.clear', 'Clear')] }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsx(ui.NiceCheckbox, { checked: showGrid, onChange: () => setShowGrid((v) => !v), label: t('modelEditorMenuBar.grid', 'Grid') }), jsxRuntime.jsx(ui.NiceCheckbox, { checked: showAxes, onChange: () => setShowAxes((v) => !v), label: t('modelEditorMenuBar.axes', 'Axes') }), jsxRuntime.jsx(ui.NiceCheckbox, { checked: wireframe, onChange: () => setWireframe((v) => !v), label: t('modelEditorMenuBar.wire', 'Wire') }), jsxRuntime.jsx(ui.NiceCheckbox, { checked: showSkeleton, onChange: () => setShowSkeleton((v) => !v), label: t('modelEditorMenuBar.skel', 'Skel') }), jsxRuntime.jsx(ui.NiceCheckbox, { checked: showLightHelpers, onChange: () => setShowLightHelpers((v) => !v), label: t('modelEditorMenuBar.helpers', 'Helpers') }), jsxRuntime.jsxs("div", { className: ModelEditor_module.menuRight, children: [jsxRuntime.jsx("label", { className: ModelEditor_module.menuLabel, children: "BG" }), jsxRuntime.jsx(ui.NiceColorPicker, { value: bgColor, onChange: (c) => setBgColor(c) })] })] }));
|
|
32
|
+
}), { displayName: 'ModelEditorMenuBar' });
|
|
31
33
|
|
|
32
34
|
module.exports = ModelEditorMenuBar;
|