@nice2dev/ui-graphics 1.1.10 → 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 +173 -0
- package/README.md +60 -63
- package/dist/cjs/animation/AnimationEditor.js +0 -3
- package/dist/cjs/animation/Audience.js +3 -1
- package/dist/cjs/animation/BodyRenderer.js +1 -4
- package/dist/cjs/animation/rig/RigPlayer.js +1 -1
- package/dist/cjs/animation/rig/presets.js +67 -55
- package/dist/cjs/animation/shapes/heads.js +0 -3
- package/dist/cjs/animation/shapes/headwear.js +4 -1
- package/dist/cjs/core/NiceBrushEngine.js +6 -6
- package/dist/cjs/core/editorAsk.js +48 -0
- package/dist/cjs/core/i18n.js +7 -3
- package/dist/cjs/core/plugins.js +1 -1
- package/dist/cjs/core/rtl.js +1 -1
- package/dist/cjs/core/theme.js +1 -1
- package/dist/cjs/font/NiceFontEditor.js +16 -14
- package/dist/cjs/game/GameAsset2dEditor.js +28 -19
- package/dist/cjs/index.js +0 -11
- package/dist/cjs/nice2dev-ui-graphics.css +1 -1
- package/dist/cjs/photo/FilterThumb.js +3 -3
- package/dist/cjs/photo/NiceAITools.js +7 -5
- package/dist/cjs/photo/PhotoEditor.js +3 -1
- package/dist/cjs/photo/PhotoEditorCanvas.js +8 -6
- package/dist/cjs/photo/PhotoEditorLeftPanel.js +19 -19
- package/dist/cjs/photo/PhotoEditorToolbar.js +5 -5
- package/dist/cjs/photo/photoFilters.js +1 -0
- package/dist/cjs/pixel/PixelEditor.js +6 -6
- package/dist/cjs/pixel/PixelEditor.module.css.js +1 -1
- package/dist/cjs/pixel/PixelEditorCanvas.js +10 -6
- package/dist/cjs/pixel/PixelEditorMenuBar.js +3 -3
- package/dist/cjs/pixel/PixelEditorRightPanel.js +28 -24
- package/dist/cjs/pixel/PixelEditorStatusBar.js +8 -4
- package/dist/cjs/pixel/PixelEditorTimeline.js +11 -2
- package/dist/cjs/pixel/PixelEditorToolbar.js +10 -6
- package/dist/cjs/pixel/SpriteGeneratorPanel.js +12 -8
- package/dist/cjs/pixel/animalGeneratorPresets.js +31 -31
- package/dist/cjs/pixel/buildingGeneratorPresets.js +24 -24
- package/dist/cjs/pixel/characterGeneratorPresets.js +25 -25
- package/dist/cjs/pixel/usePixelEditor.js +13 -10
- package/dist/cjs/texture/Nice3DTexturePainter.js +12 -10
- package/dist/cjs/ui/NiceUIDesigner.js +18 -14
- package/dist/cjs/vector/NiceSvgToCode.js +6 -4
- package/dist/cjs/vector/VectorEditor.js +3 -5
- package/dist/cjs/vector/VectorEditorShapeRenderer.js +3 -1
- package/dist/cjs/vector/useVectorEditor.js +38 -29
- package/dist/cjs/vector/vectorEditorImport.js +1 -0
- package/dist/cjs/vector/vectorIconImport.js +1 -0
- package/dist/esm/animation/AnimationEditor.js +1 -3
- package/dist/esm/animation/Audience.js +3 -1
- package/dist/esm/animation/BodyRenderer.js +3 -5
- package/dist/esm/animation/rig/RigPlayer.js +1 -1
- package/dist/esm/animation/rig/presets.js +68 -56
- package/dist/esm/animation/shapes/heads.js +1 -3
- package/dist/esm/animation/shapes/headwear.js +4 -1
- package/dist/esm/animation/spineExport.js +1 -1
- package/dist/esm/core/NiceBrushEngine.js +6 -6
- package/dist/esm/core/editorAsk.js +45 -0
- package/dist/esm/core/i18n.js +8 -4
- package/dist/esm/core/plugins.js +1 -1
- package/dist/esm/core/rtl.js +1 -1
- package/dist/esm/core/theme.js +1 -1
- package/dist/esm/font/NiceFontEditor.js +16 -14
- package/dist/esm/game/GameAsset2dEditor.js +29 -19
- package/dist/esm/index.js +10 -10
- package/dist/esm/nice2dev-ui-graphics.css +1 -1
- package/dist/esm/photo/FilterThumb.js +3 -3
- package/dist/esm/photo/NiceAITools.js +7 -5
- package/dist/esm/photo/PhotoEditor.js +3 -1
- package/dist/esm/photo/PhotoEditorCanvas.js +8 -6
- package/dist/esm/photo/PhotoEditorLeftPanel.js +19 -19
- package/dist/esm/photo/PhotoEditorToolbar.js +5 -5
- package/dist/esm/photo/photoFilters.js +1 -0
- package/dist/esm/pixel/PixelEditor.js +7 -6
- package/dist/esm/pixel/PixelEditor.module.css.js +1 -1
- package/dist/esm/pixel/PixelEditorCanvas.js +10 -6
- package/dist/esm/pixel/PixelEditorMenuBar.js +3 -3
- package/dist/esm/pixel/PixelEditorRightPanel.js +28 -24
- package/dist/esm/pixel/PixelEditorStatusBar.js +8 -4
- package/dist/esm/pixel/PixelEditorTimeline.js +11 -2
- package/dist/esm/pixel/PixelEditorToolbar.js +10 -6
- package/dist/esm/pixel/SpriteGeneratorPanel.js +12 -8
- package/dist/esm/pixel/animalGeneratorPresets.js +32 -32
- package/dist/esm/pixel/buildingGeneratorPresets.js +25 -25
- package/dist/esm/pixel/characterGeneratorPresets.js +26 -26
- package/dist/esm/pixel/usePixelEditor.js +13 -10
- package/dist/esm/texture/Nice3DTexturePainter.js +12 -10
- package/dist/esm/ui/NiceUIDesigner.js +18 -14
- package/dist/esm/vector/NiceSvgToCode.js +6 -4
- package/dist/esm/vector/VectorEditor.js +4 -5
- package/dist/esm/vector/VectorEditorShapeRenderer.js +3 -1
- package/dist/esm/vector/useVectorEditor.js +38 -29
- package/dist/esm/vector/vectorEditorImport.js +1 -0
- package/dist/esm/vector/vectorIconImport.js +1 -0
- package/dist/types/animation/AnimatedPerson.d.ts +0 -4
- package/dist/types/animation/AnimationEditor.d.ts +1 -5
- package/dist/types/animation/Audience.d.ts +0 -4
- package/dist/types/animation/BodyRenderer.d.ts +0 -4
- package/dist/types/animation/rig/RigPlayer.d.ts +0 -7
- package/dist/types/animation/rig/RiggedBody.d.ts +0 -4
- package/dist/types/animation/shapes/heads.d.ts +0 -4
- package/dist/types/core/LocalUI.d.ts +1 -2
- package/dist/types/core/editorAsk.d.ts +26 -0
- package/dist/types/core/i18n.d.ts +1 -17
- package/dist/types/game/GameAsset2dEditor.d.ts +0 -4
- package/dist/types/game/index.d.ts +1 -1
- package/dist/types/index.d.ts +9 -19
- package/dist/types/photo/index.d.ts +0 -2
- package/dist/types/pixel/PixelEditor.d.ts +0 -4
- package/dist/types/pixel/SpriteGeneratorPanel.d.ts +0 -4
- package/dist/types/pixel/usePixelEditor.d.ts +3 -0
- package/dist/types/vector/VectorEditor.d.ts +0 -4
- package/dist/types/vector/useVectorEditor.d.ts +2 -0
- package/package.json +5 -5
|
@@ -10,13 +10,16 @@ const HeadwearCap = ({ colors, scale = 1, transform }) => {
|
|
|
10
10
|
};
|
|
11
11
|
const HeadwearCrown = ({ colors, scale = 1, transform }) => {
|
|
12
12
|
const base = characterTypes.pick(colors, 0, 'var(--nice-warning, #FFD700)');
|
|
13
|
-
return (jsxRuntime.jsx("g", { transform: `${transform !== null && transform !== void 0 ? transform : ''} scale(${scale})`, children: jsxRuntime.jsx("path", { d: "M-22 -30 l6 -16 l8 10 l8 -14 l8 14 l8 -10 l6 16 z", fill: base,
|
|
13
|
+
return (jsxRuntime.jsx("g", { transform: `${transform !== null && transform !== void 0 ? transform : ''} scale(${scale})`, children: jsxRuntime.jsx("path", { d: "M-22 -30 l6 -16 l8 10 l8 -14 l8 14 l8 -10 l6 16 z", fill: base,
|
|
14
|
+
// audit-allow: literal-color — a character-generator shape: its own drawing colour
|
|
15
|
+
stroke: "#B8860B", strokeWidth: 1.2 }) }));
|
|
14
16
|
};
|
|
15
17
|
const HeadwearHeadphones = ({ colors, scale = 1, transform }) => {
|
|
16
18
|
const base = characterTypes.pick(colors, 0, 'var(--nice-text, #333)');
|
|
17
19
|
return (jsxRuntime.jsxs("g", { transform: `${transform !== null && transform !== void 0 ? transform : ''} scale(${scale})`, stroke: base, strokeWidth: 2.5, fill: "none", children: [jsxRuntime.jsx("path", { d: "M-30 0 q0 -40 30 -42 q30 2 30 42" }), jsxRuntime.jsx("rect", { x: -36, y: -6, width: 10, height: 16, rx: 3, fill: base }), jsxRuntime.jsx("rect", { x: 26, y: -6, width: 10, height: 16, rx: 3, fill: base })] }));
|
|
18
20
|
};
|
|
19
21
|
const HeadwearBeanie = ({ colors, scale = 1, transform }) => {
|
|
22
|
+
// audit-allow: literal-color — the hat's default colour when the character sets none
|
|
20
23
|
const base = characterTypes.pick(colors, 0, '#E53E3E');
|
|
21
24
|
return (jsxRuntime.jsxs("g", { transform: `${transform !== null && transform !== void 0 ? transform : ''} scale(${scale})`, children: [jsxRuntime.jsx("path", { d: "M-28 -14 q0 -22 28 -26 q28 4 28 26 z", fill: base }), jsxRuntime.jsx("circle", { cx: 0, cy: -42, r: 6, fill: base })] }));
|
|
22
25
|
};
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var uiCore = require('@nice2dev/ui-core');
|
|
5
5
|
var React = require('react');
|
|
6
|
+
var i18n = require('./i18n.js');
|
|
6
7
|
|
|
7
8
|
/* ── Brush Presets ── */
|
|
8
9
|
const DEFAULT_DYNAMICS = {
|
|
@@ -543,6 +544,7 @@ color = '#000000') {
|
|
|
543
544
|
}
|
|
544
545
|
/* ── Component ── */
|
|
545
546
|
const NiceBrushEngine = ({ canvas, color = '#000000', onStrokeEnd, className = '', }) => {
|
|
547
|
+
const { t } = i18n.useNiceTranslation();
|
|
546
548
|
const engine = useBrushEngine(canvas, color);
|
|
547
549
|
// Override endStroke to fire callback
|
|
548
550
|
React.useEffect(() => {
|
|
@@ -559,7 +561,7 @@ const NiceBrushEngine = ({ canvas, color = '#000000', onStrokeEnd, className = '
|
|
|
559
561
|
return () => canvas.removeEventListener('pointerup', onUp);
|
|
560
562
|
}, [canvas, engine.endStroke, onStrokeEnd]);
|
|
561
563
|
const s = engine.settings;
|
|
562
|
-
return (jsxRuntime.jsxs("div", { className: `nice-brush-engine ${className}`, style: { display: 'grid', gap: 6, fontSize: 13 }, children: [jsxRuntime.jsxs("strong", { children: [jsxRuntime.jsx(uiCore.NiceIcon, { name: "brush", size: 14 }), " Brush Engine v2
|
|
564
|
+
return (jsxRuntime.jsxs("div", { className: `nice-brush-engine ${className}`, style: { display: 'grid', gap: 6, fontSize: 13 }, children: [jsxRuntime.jsxs("strong", { children: [jsxRuntime.jsx(uiCore.NiceIcon, { name: "brush", size: 14 }), " ", t('brushEngine.brushEngineV2', 'Brush Engine v2')] }), jsxRuntime.jsx("div", { style: { display: 'flex', gap: 2, flexWrap: 'wrap' }, children: engine.presetNames.map((name) => {
|
|
563
565
|
var _a, _b;
|
|
564
566
|
return (jsxRuntime.jsx("button", { type: "button", onClick: () => engine.applyPreset(name), style: {
|
|
565
567
|
padding: '2px 6px',
|
|
@@ -570,17 +572,15 @@ const NiceBrushEngine = ({ canvas, color = '#000000', onStrokeEnd, className = '
|
|
|
570
572
|
background: s.name === ((_a = BRUSH_PRESETS[name]) === null || _a === void 0 ? void 0 : _a.name)
|
|
571
573
|
? 'var(--nice-color-accent, #6366f1)'
|
|
572
574
|
: 'transparent',
|
|
573
|
-
color: s.name === ((_b = BRUSH_PRESETS[name]) === null || _b === void 0 ? void 0 : _b.name)
|
|
574
|
-
? 'var(--nice-text-on-primary, #fff)'
|
|
575
|
-
: 'inherit',
|
|
575
|
+
color: s.name === ((_b = BRUSH_PRESETS[name]) === null || _b === void 0 ? void 0 : _b.name) ? 'var(--nice-color-white, #fff)' : 'inherit',
|
|
576
576
|
}, children: BRUSH_PRESETS[name].name }, name));
|
|
577
|
-
}) }), jsxRuntime.jsxs("label", { children: ["Size: ", s.size, "px", jsxRuntime.jsx("input", { type: "range", min: 1, max: 200, value: s.size, onChange: (e) => engine.setSettings({ ...s, size: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Opacity: ", Math.round(s.opacity * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: s.opacity, onChange: (e) => engine.setSettings({ ...s, opacity: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Flow: ", Math.round(s.flow * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: s.flow, onChange: (e) => engine.setSettings({ ...s, flow: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Hardness: ", Math.round(s.hardness * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: s.hardness, onChange: (e) => engine.setSettings({ ...s, hardness: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Smoothing: ", Math.round(s.smoothing * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: s.smoothing, onChange: (e) => engine.setSettings({ ...s, smoothing: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Tip:", jsxRuntime.jsxs("select", { value: s.tipShape, onChange: (e) => engine.setSettings({ ...s, tipShape: e.target.value }), style: { width: '100%' }, children: [jsxRuntime.jsx("option", { value: "circle", children:
|
|
577
|
+
}) }), jsxRuntime.jsxs("label", { children: ["Size: ", s.size, "px", jsxRuntime.jsx("input", { type: "range", min: 1, max: 200, value: s.size, onChange: (e) => engine.setSettings({ ...s, size: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Opacity: ", Math.round(s.opacity * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: s.opacity, onChange: (e) => engine.setSettings({ ...s, opacity: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Flow: ", Math.round(s.flow * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: s.flow, onChange: (e) => engine.setSettings({ ...s, flow: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Hardness: ", Math.round(s.hardness * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: s.hardness, onChange: (e) => engine.setSettings({ ...s, hardness: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Smoothing: ", Math.round(s.smoothing * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: s.smoothing, onChange: (e) => engine.setSettings({ ...s, smoothing: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Tip:", jsxRuntime.jsxs("select", { value: s.tipShape, onChange: (e) => engine.setSettings({ ...s, tipShape: e.target.value }), style: { width: '100%' }, children: [jsxRuntime.jsx("option", { value: "circle", children: t('brushEngine.circle', 'Circle') }), jsxRuntime.jsx("option", { value: "square", children: t('brushEngine.square', 'Square') }), jsxRuntime.jsx("option", { value: "diamond", children: t('brushEngine.diamond', 'Diamond') }), jsxRuntime.jsx("option", { value: "texture", children: t('brushEngine.texture', 'Texture') })] })] }), jsxRuntime.jsxs("label", { children: ["Roundness: ", Math.round(s.roundness * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0.05, max: 1, step: 0.05, value: s.roundness, onChange: (e) => engine.setSettings({ ...s, roundness: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("details", { children: [jsxRuntime.jsxs("summary", { style: { cursor: 'pointer', fontSize: 12 }, children: [jsxRuntime.jsx(uiCore.NiceIcon, { name: "bar-chart", size: 12 }), " ", t('brushEngine.sizeDynamics', 'Size Dynamics')] }), jsxRuntime.jsxs("label", { children: ["Source:", jsxRuntime.jsxs("select", { value: s.sizeDynamics.source, onChange: (e) => engine.setSettings({
|
|
578
578
|
...s,
|
|
579
579
|
sizeDynamics: {
|
|
580
580
|
...s.sizeDynamics,
|
|
581
581
|
source: e.target.value,
|
|
582
582
|
},
|
|
583
|
-
}), style: { width: '100%' }, children: [jsxRuntime.jsx("option", { value: "none", children: "Off" }), jsxRuntime.jsx("option", { value: "pressure", children:
|
|
583
|
+
}), style: { width: '100%' }, children: [jsxRuntime.jsx("option", { value: "none", children: "Off" }), jsxRuntime.jsx("option", { value: "pressure", children: t('brushEngine.pressure', 'Pressure') }), jsxRuntime.jsx("option", { value: "tilt", children: t('brushEngine.tilt', 'Tilt') }), jsxRuntime.jsx("option", { value: "speed", children: t('brushEngine.speed', 'Speed') }), jsxRuntime.jsx("option", { value: "random", children: t('brushEngine.random', 'Random') })] })] })] }), jsxRuntime.jsxs("label", { children: ["Scatter: ", Math.round(s.scatter * 100), "%", jsxRuntime.jsx("input", { type: "range", min: 0, max: 1, step: 0.01, value: s.scatter, onChange: (e) => engine.setSettings({ ...s, scatter: +e.target.value }), style: { width: '100%' } })] }), jsxRuntime.jsxs("label", { children: ["Blend:", jsxRuntime.jsx("select", { value: s.blendMode, onChange: (e) => engine.setSettings({ ...s, blendMode: e.target.value }), style: { width: '100%' }, children: ['normal', 'multiply', 'screen', 'overlay', 'darken', 'lighten'].map((m) => (jsxRuntime.jsx("option", { value: m, children: m }, m))) })] }), jsxRuntime.jsxs("label", { style: { display: 'flex', gap: 4, alignItems: 'center' }, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: s.wetEdges, onChange: (e) => engine.setSettings({ ...s, wetEdges: e.target.checked }) }), t('brushEngine.wetEdges', 'Wet Edges')] })] }));
|
|
584
584
|
};
|
|
585
585
|
|
|
586
586
|
exports.BRUSH_PRESETS = BRUSH_PRESETS;
|
|
@@ -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 uiCore = require('@nice2dev/ui-core');
|
|
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 graphics 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 } = uiCore.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
|
|
package/dist/cjs/core/plugins.js
CHANGED
|
@@ -112,7 +112,7 @@ function usePlugins(editor) {
|
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
114
|
// ── Plugin Context (React) ──────────────────────────────────────
|
|
115
|
-
const PluginContext = React.createContext(PluginRegistry);
|
|
115
|
+
const PluginContext = /* @__PURE__ */ React.createContext(PluginRegistry);
|
|
116
116
|
const NicePluginProvider = ({ plugins, children }) => {
|
|
117
117
|
React.useEffect(() => {
|
|
118
118
|
if (plugins) {
|
package/dist/cjs/core/rtl.js
CHANGED
|
@@ -14,7 +14,7 @@ const defaultRTLConfig = {
|
|
|
14
14
|
mirrorToolbar: false,
|
|
15
15
|
mirrorPanels: false,
|
|
16
16
|
};
|
|
17
|
-
const RTLContext = React.createContext(defaultRTLConfig);
|
|
17
|
+
const RTLContext = /* @__PURE__ */ React.createContext(defaultRTLConfig);
|
|
18
18
|
/** Provider for RTL configuration. Wraps editors to enable RTL support. */
|
|
19
19
|
const NiceRTLProvider = ({ direction = 'ltr', mirrorToolbar = true, mirrorPanels = true, children }) => {
|
|
20
20
|
const config = React.useMemo(() => ({
|
package/dist/cjs/core/theme.js
CHANGED
|
@@ -4,6 +4,7 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
4
4
|
var ui = require('@nice2dev/ui');
|
|
5
5
|
var uiCore = require('@nice2dev/ui-core');
|
|
6
6
|
var React = require('react');
|
|
7
|
+
var i18n = require('../core/i18n.js');
|
|
7
8
|
|
|
8
9
|
/** Built-in guided tour (EN inline + i18n keys → PL and other locales). */
|
|
9
10
|
const FONT_EDITOR_TOUR = [
|
|
@@ -134,6 +135,7 @@ function useFontEditor(initialName) {
|
|
|
134
135
|
/** Font glyph editor with metrics, visual path editing, and preview. */
|
|
135
136
|
const NiceFontEditor = ({ fontName = 'MyFont', onSave, className = '', tutorial, }) => {
|
|
136
137
|
var _a;
|
|
138
|
+
const { t } = i18n.useNiceTranslation();
|
|
137
139
|
const editor = useFontEditor(fontName);
|
|
138
140
|
const [drawMode, setDrawMode] = React.useState('select');
|
|
139
141
|
const [pathPoints, setPathPoints] = React.useState([]);
|
|
@@ -191,7 +193,7 @@ const NiceFontEditor = ({ fontName = 'MyFont', onSave, className = '', tutorial,
|
|
|
191
193
|
border: 'none',
|
|
192
194
|
cursor: 'pointer',
|
|
193
195
|
background: active ? 'var(--nice-info, #339af0)' : 'var(--nice-bg-secondary, #2c2e33)',
|
|
194
|
-
color: active ? 'var(--nice-
|
|
196
|
+
color: active ? 'var(--nice-color-white, #fff)' : 'var(--nice-text, #c1c2c5)',
|
|
195
197
|
fontSize: 11,
|
|
196
198
|
});
|
|
197
199
|
const fieldStyle = {
|
|
@@ -221,7 +223,7 @@ const NiceFontEditor = ({ fontName = 'MyFont', onSave, className = '', tutorial,
|
|
|
221
223
|
color: 'var(--nice-text, #c1c2c5)',
|
|
222
224
|
padding: 12,
|
|
223
225
|
borderRadius: 8,
|
|
224
|
-
}, children: [jsxRuntime.jsx("span", { style: { position: 'absolute', top: 6, right: 6, zIndex: 20 }, children: jsxRuntime.jsx(ui.NiceTutorialButton, { steps: ui.resolveTutorial(tutorial, FONT_EDITOR_TOUR) }) }), jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, fontSize: 12 }, children: [jsxRuntime.jsx("strong", { style: { fontSize: 14 }, children:
|
|
226
|
+
}, children: [jsxRuntime.jsx("span", { style: { position: 'absolute', top: 6, right: 6, zIndex: 20 }, children: jsxRuntime.jsx(ui.NiceTutorialButton, { steps: ui.resolveTutorial(tutorial, FONT_EDITOR_TOUR) }) }), jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, fontSize: 12 }, children: [jsxRuntime.jsx("strong", { style: { fontSize: 14 }, children: t('fontEditor.fontEditor', 'Font Editor') }), jsxRuntime.jsx("input", { value: editor.fontName, onChange: (e) => editor.setFontName(e.target.value), placeholder: t('fontEditor.fontName', 'Font name'), style: { flex: 1, maxWidth: 200, ...fieldStyle, fontSize: 12 } }), jsxRuntime.jsx("button", { onClick: handleSave, style: {
|
|
225
227
|
padding: '4px 12px',
|
|
226
228
|
background: 'var(--nice-success, #2f9e44)',
|
|
227
229
|
color: 'var(--nice-text-on-primary, #fff)',
|
|
@@ -229,15 +231,15 @@ const NiceFontEditor = ({ fontName = 'MyFont', onSave, className = '', tutorial,
|
|
|
229
231
|
borderRadius: 3,
|
|
230
232
|
cursor: 'pointer',
|
|
231
233
|
fontSize: 11,
|
|
232
|
-
}, children:
|
|
234
|
+
}, children: t('fontEditor.save', 'Save') }), jsxRuntime.jsx("button", { onClick: handleExportSvg, style: {
|
|
233
235
|
padding: '4px 12px',
|
|
234
236
|
background: '#228be6',
|
|
235
|
-
color: 'var(--nice-
|
|
237
|
+
color: 'var(--nice-color-white, #fff)',
|
|
236
238
|
border: 'none',
|
|
237
239
|
borderRadius: 3,
|
|
238
240
|
cursor: 'pointer',
|
|
239
241
|
fontSize: 11,
|
|
240
|
-
}, children:
|
|
242
|
+
}, children: t('fontEditor.exportSvgFont', 'Export SVG Font') })] }), jsxRuntime.jsxs("div", { style: { display: 'flex', gap: 4, borderBottom: '1px solid var(--nice-border, #373a40)' }, children: [jsxRuntime.jsx("button", { onClick: () => setTab('glyph'), style: tabBtnStyle(tab === 'glyph'), children: t('fontEditor.glyphs', 'Glyphs') }), jsxRuntime.jsx("button", { onClick: () => setTab('metrics'), style: tabBtnStyle(tab === 'metrics'), children: t('fontEditor.metrics', 'Metrics') }), jsxRuntime.jsx("button", { onClick: () => setTab('kerning'), style: tabBtnStyle(tab === 'kerning'), children: t('fontEditor.kerning', 'Kerning') })] }), tab === 'glyph' && (jsxRuntime.jsxs("div", { style: { display: 'flex', gap: 8 }, children: [jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [jsxRuntime.jsxs("div", { style: {
|
|
241
243
|
fontSize: 11,
|
|
242
244
|
marginBottom: 4,
|
|
243
245
|
color: 'var(--nice-text-secondary, #868e96)',
|
|
@@ -265,14 +267,14 @@ const NiceFontEditor = ({ fontName = 'MyFont', onSave, className = '', tutorial,
|
|
|
265
267
|
? 'var(--nice-bg-secondary, #2c2e33)'
|
|
266
268
|
: '#25262b',
|
|
267
269
|
color: editor.selectedGlyph === g.unicode
|
|
268
|
-
? 'var(--nice-
|
|
270
|
+
? 'var(--nice-color-white, #fff)'
|
|
269
271
|
: g.path
|
|
270
272
|
? 'var(--nice-text, #c1c2c5)'
|
|
271
273
|
: '#5c5f66',
|
|
272
274
|
border: g.path
|
|
273
275
|
? '1px solid var(--nice-border, #373a40)'
|
|
274
276
|
: '1px solid transparent',
|
|
275
|
-
}, children: g.char }, g.unicode))) })] }), jsxRuntime.jsx("div", { style: { width: 320, fontSize: 11 }, children: selectedG ? (jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [jsxRuntime.jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, children: [jsxRuntime.jsxs("strong", { children: ["\"", selectedG.char, "\" (U+", selectedG.unicode.toString(16).toUpperCase().padStart(4, '0'), ")"] }), jsxRuntime.jsxs("div", { style: { display: 'flex', gap: 2 }, children: [jsxRuntime.jsx("button", { onClick: () => setDrawMode('select'), style: btnStyle(drawMode === 'select'), children:
|
|
277
|
+
}, children: g.char }, g.unicode))) })] }), jsxRuntime.jsx("div", { style: { width: 320, fontSize: 11 }, children: selectedG ? (jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [jsxRuntime.jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, children: [jsxRuntime.jsxs("strong", { children: ["\"", selectedG.char, "\" (U+", selectedG.unicode.toString(16).toUpperCase().padStart(4, '0'), ")"] }), jsxRuntime.jsxs("div", { style: { display: 'flex', gap: 2 }, children: [jsxRuntime.jsx("button", { onClick: () => setDrawMode('select'), style: btnStyle(drawMode === 'select'), children: t('fontEditor.select', 'Select') }), jsxRuntime.jsx("button", { onClick: () => setDrawMode('pen'), style: btnStyle(drawMode === 'pen'), children: "Pen" }), jsxRuntime.jsx("button", { onClick: clearPath, style: btnStyle(false), children: t('fontEditor.clear', 'Clear') }), jsxRuntime.jsx("button", { onClick: () => setShowGrid((g) => !g), style: btnStyle(showGrid), children: t('fontEditor.grid', 'Grid') })] })] }), jsxRuntime.jsxs("svg", { width: 280, height: 280, viewBox: `0 0 ${em} ${em}`, style: {
|
|
276
278
|
background: 'var(--nice-bg, #141517)',
|
|
277
279
|
borderRadius: 4,
|
|
278
280
|
cursor: drawMode === 'pen' ? 'crosshair' : 'default',
|
|
@@ -280,32 +282,32 @@ const NiceFontEditor = ({ fontName = 'MyFont', onSave, className = '', tutorial,
|
|
|
280
282
|
Array.from({ length: 11 }, (_, i) => {
|
|
281
283
|
const pos = (i / 10) * em;
|
|
282
284
|
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx("line", { x1: pos, y1: 0, x2: pos, y2: em, stroke: "var(--nice-overlay-light-5, rgba(255, 255, 255, 0.05))", strokeWidth: em * 0.002 }), jsxRuntime.jsx("line", { x1: 0, y1: pos, x2: em, y2: pos, stroke: "var(--nice-overlay-light-5, rgba(255, 255, 255, 0.05))", strokeWidth: em * 0.002 })] }, i));
|
|
283
|
-
}), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.ascent, x2: em, y2: em - editor.metrics.ascent, stroke: "rgba(51,154,240,0.3)", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.01}` }), jsxRuntime.jsx("line", { x1: 0, y1: em, x2: em, y2: em, stroke: "rgba(47,158,68,0.3)", strokeWidth: em * 0.003 }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.xHeight, x2: em, y2: em - editor.metrics.xHeight, stroke: "rgba(249,226,175,0.3)", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.01}` }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.capHeight, x2: em, y2: em - editor.metrics.capHeight, stroke: "rgba(243,139,168,0.3)", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.01}` }), jsxRuntime.jsx("line", { x1: selectedG.leftBearing, y1: 0, x2: selectedG.leftBearing, y2: em, stroke: "rgba(166,227,161,0.2)", strokeWidth: em * 0.002 }), jsxRuntime.jsx("line", { x1: selectedG.advanceWidth, y1: 0, x2: selectedG.advanceWidth, y2: em, stroke: "rgba(243,139,168,0.2)", strokeWidth: em * 0.002 }), selectedG.path && (jsxRuntime.jsx("path", { d: selectedG.path, fill: "rgba(205,214,244,0.8)", stroke: "#89b4fa", strokeWidth: em * 0.005 })), pathPoints.map((p, i) => (jsxRuntime.jsx("circle", { cx: p.x, cy: p.y, r: em * 0.015, fill: i === 0 ? 'var(--nice-success, #2f9e44)' : 'var(--nice-info, #339af0)', stroke: "var(--nice-bg, #fff)", strokeWidth: em * 0.003 }, i))), jsxRuntime.jsx("text", { x: em * 0.02, y: em - editor.metrics.ascent - em * 0.01, fill: "rgba(51,154,240,0.5)", fontSize: em * 0.03, children: "ascent" }), jsxRuntime.jsx("text", { x: em * 0.02, y: em - editor.metrics.xHeight - em * 0.01, fill: "rgba(249,226,175,0.5)", fontSize: em * 0.03, children: "x-height" }), jsxRuntime.jsx("text", { x: em * 0.02, y: em - editor.metrics.capHeight - em * 0.01, fill: "rgba(243,139,168,0.5)", fontSize: em * 0.03, children: "cap" })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children:
|
|
285
|
+
}), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.ascent, x2: em, y2: em - editor.metrics.ascent, stroke: "rgba(51,154,240,0.3)", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.01}` }), jsxRuntime.jsx("line", { x1: 0, y1: em, x2: em, y2: em, stroke: "rgba(47,158,68,0.3)", strokeWidth: em * 0.003 }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.xHeight, x2: em, y2: em - editor.metrics.xHeight, stroke: "rgba(249,226,175,0.3)", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.01}` }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.capHeight, x2: em, y2: em - editor.metrics.capHeight, stroke: "rgba(243,139,168,0.3)", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.01}` }), jsxRuntime.jsx("line", { x1: selectedG.leftBearing, y1: 0, x2: selectedG.leftBearing, y2: em, stroke: "rgba(166,227,161,0.2)", strokeWidth: em * 0.002 }), jsxRuntime.jsx("line", { x1: selectedG.advanceWidth, y1: 0, x2: selectedG.advanceWidth, y2: em, stroke: "rgba(243,139,168,0.2)", strokeWidth: em * 0.002 }), selectedG.path && (jsxRuntime.jsx("path", { d: selectedG.path, fill: "rgba(205,214,244,0.8)", stroke: "#89b4fa", strokeWidth: em * 0.005 })), pathPoints.map((p, i) => (jsxRuntime.jsx("circle", { cx: p.x, cy: p.y, r: em * 0.015, fill: i === 0 ? 'var(--nice-success, #2f9e44)' : 'var(--nice-info, #339af0)', stroke: "var(--nice-bg, #fff)", strokeWidth: em * 0.003 }, i))), jsxRuntime.jsx("text", { x: em * 0.02, y: em - editor.metrics.ascent - em * 0.01, fill: "rgba(51,154,240,0.5)", fontSize: em * 0.03, children: "ascent" }), jsxRuntime.jsx("text", { x: em * 0.02, y: em - editor.metrics.xHeight - em * 0.01, fill: "rgba(249,226,175,0.5)", fontSize: em * 0.03, children: "x-height" }), jsxRuntime.jsx("text", { x: em * 0.02, y: em - editor.metrics.capHeight - em * 0.01, fill: "rgba(243,139,168,0.5)", fontSize: em * 0.03, children: "cap" })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: t('fontEditor.svgPath', 'SVG Path') }), jsxRuntime.jsx("textarea", { value: selectedG.path, onChange: (e) => editor.updateGlyph(selectedG.unicode, { path: e.target.value }), rows: 3, style: { ...fieldStyle, fontFamily: 'monospace', resize: 'vertical' } })] }), jsxRuntime.jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 4 }, children: [jsxRuntime.jsx("label", { children: t('fontEditor.advanceWidth', 'Advance Width') }), jsxRuntime.jsx("input", { type: "number", value: selectedG.advanceWidth, onChange: (e) => editor.updateGlyph(selectedG.unicode, {
|
|
284
286
|
advanceWidth: Number(e.target.value),
|
|
285
|
-
}), style: fieldStyle }), jsxRuntime.jsx("label", { children:
|
|
287
|
+
}), style: fieldStyle }), jsxRuntime.jsx("label", { children: t('fontEditor.leftBearing', 'Left Bearing') }), jsxRuntime.jsx("input", { type: "number", value: selectedG.leftBearing, onChange: (e) => editor.updateGlyph(selectedG.unicode, { leftBearing: Number(e.target.value) }), style: fieldStyle })] })] })) : (jsxRuntime.jsx("div", { style: {
|
|
286
288
|
color: 'var(--nice-text-secondary, #868e96)',
|
|
287
289
|
padding: 20,
|
|
288
290
|
textAlign: 'center',
|
|
289
|
-
}, children:
|
|
291
|
+
}, children: t('fontEditor.selectAGlyphToEdit', 'Select a glyph to edit') })) })] })), tab === 'metrics' && (jsxRuntime.jsxs("div", { style: { maxWidth: 400 }, children: [jsxRuntime.jsx("strong", { style: { fontSize: 12, display: 'block', marginBottom: 8 }, children: t('fontEditor.fontMetrics', 'Font Metrics') }), [
|
|
290
292
|
['unitsPerEm', 'Units per Em'],
|
|
291
293
|
['ascent', 'Ascent'],
|
|
292
294
|
['descent', 'Descent'],
|
|
293
295
|
['lineGap', 'Line Gap'],
|
|
294
296
|
['xHeight', 'x-Height'],
|
|
295
297
|
['capHeight', 'Cap Height'],
|
|
296
|
-
].map(([key, label]) => (jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }, children: [jsxRuntime.jsx("span", { style: { minWidth: 100, fontSize: 11 }, children: label }), jsxRuntime.jsx("input", { type: "number", value: editor.metrics[key], onChange: (e) => editor.setMetrics({ ...editor.metrics, [key]: Number(e.target.value) }), style: fieldStyle })] }, key))), jsxRuntime.jsxs("svg", { width: 300, height: 200, viewBox: `0 0 ${em} ${em}`, style: { background: 'var(--nice-bg, #141517)', borderRadius: 4, marginTop: 12 }, children: [jsxRuntime.jsx("rect", { x: 0, y: em - editor.metrics.ascent, width: em, height: editor.metrics.ascent - editor.metrics.descent, fill: "rgba(51,154,240,0.05)", stroke: "rgba(51,154,240,0.2)", strokeWidth: em * 0.003 }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.ascent, x2: em, y2: em - editor.metrics.ascent, stroke: "var(--nice-info, #339af0)", strokeWidth: em * 0.004 }), jsxRuntime.jsx("line", { x1: 0, y1: em, x2: em, y2: em, stroke: "var(--nice-success, #2f9e44)", strokeWidth: em * 0.004 }), jsxRuntime.jsx("line", { x1: 0, y1: em + Math.abs(editor.metrics.descent), x2: em, y2: em + Math.abs(editor.metrics.descent), stroke: "#e03131", strokeWidth: em * 0.004 }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.xHeight, x2: em, y2: em - editor.metrics.xHeight, stroke: "#f9e2af", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.015}` }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.capHeight, x2: em, y2: em - editor.metrics.capHeight, stroke: "#f38ba8", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.015}` }), jsxRuntime.jsxs("text", { x: em * 0.02, y: em - editor.metrics.ascent + em * 0.05, fill: "var(--nice-info, #339af0)", fontSize: em * 0.04, children: ["Ascent (", editor.metrics.ascent, ")"] }), jsxRuntime.jsx("text", { x: em * 0.02, y: em + em * 0.05, fill: "var(--nice-success, #2f9e44)", fontSize: em * 0.04, children:
|
|
298
|
+
].map(([key, label]) => (jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }, children: [jsxRuntime.jsx("span", { style: { minWidth: 100, fontSize: 11 }, children: label }), jsxRuntime.jsx("input", { type: "number", value: editor.metrics[key], onChange: (e) => editor.setMetrics({ ...editor.metrics, [key]: Number(e.target.value) }), style: fieldStyle })] }, key))), jsxRuntime.jsxs("svg", { width: 300, height: 200, viewBox: `0 0 ${em} ${em}`, style: { background: 'var(--nice-bg, #141517)', borderRadius: 4, marginTop: 12 }, children: [jsxRuntime.jsx("rect", { x: 0, y: em - editor.metrics.ascent, width: em, height: editor.metrics.ascent - editor.metrics.descent, fill: "rgba(51,154,240,0.05)", stroke: "rgba(51,154,240,0.2)", strokeWidth: em * 0.003 }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.ascent, x2: em, y2: em - editor.metrics.ascent, stroke: "var(--nice-info, #339af0)", strokeWidth: em * 0.004 }), jsxRuntime.jsx("line", { x1: 0, y1: em, x2: em, y2: em, stroke: "var(--nice-success, #2f9e44)", strokeWidth: em * 0.004 }), jsxRuntime.jsx("line", { x1: 0, y1: em + Math.abs(editor.metrics.descent), x2: em, y2: em + Math.abs(editor.metrics.descent), stroke: "#e03131", strokeWidth: em * 0.004 }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.xHeight, x2: em, y2: em - editor.metrics.xHeight, stroke: "#f9e2af", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.015}` }), jsxRuntime.jsx("line", { x1: 0, y1: em - editor.metrics.capHeight, x2: em, y2: em - editor.metrics.capHeight, stroke: "#f38ba8", strokeWidth: em * 0.003, strokeDasharray: `${em * 0.015}` }), jsxRuntime.jsxs("text", { x: em * 0.02, y: em - editor.metrics.ascent + em * 0.05, fill: "var(--nice-info, #339af0)", fontSize: em * 0.04, children: ["Ascent (", editor.metrics.ascent, ")"] }), jsxRuntime.jsx("text", { x: em * 0.02, y: em + em * 0.05, fill: "var(--nice-success, #2f9e44)", fontSize: em * 0.04, children: t('fontEditor.baseline', 'Baseline') }), jsxRuntime.jsxs("text", { x: em * 0.02, y: em - editor.metrics.xHeight + em * 0.05, fill: "#f9e2af", fontSize: em * 0.04, children: ["x-Height (", editor.metrics.xHeight, ")"] }), jsxRuntime.jsxs("text", { x: em * 0.02, y: em - editor.metrics.capHeight + em * 0.05, fill: "#f38ba8", fontSize: em * 0.04, children: ["Cap (", editor.metrics.capHeight, ")"] })] })] })), tab === 'kerning' && (jsxRuntime.jsxs("div", { style: { maxWidth: 500 }, children: [jsxRuntime.jsx("strong", { style: { fontSize: 12, display: 'block', marginBottom: 8 }, children: t('fontEditor.kerningPairs', 'Kerning Pairs') }), jsxRuntime.jsxs("div", { style: { display: 'flex', gap: 4, marginBottom: 8, alignItems: 'center', fontSize: 11 }, children: [jsxRuntime.jsx("input", { value: newKernLeft, onChange: (e) => setNewKernLeft(e.target.value), maxLength: 1, style: { ...fieldStyle, width: 30, textAlign: 'center' } }), jsxRuntime.jsx("input", { value: newKernRight, onChange: (e) => setNewKernRight(e.target.value), maxLength: 1, style: { ...fieldStyle, width: 30, textAlign: 'center' } }), jsxRuntime.jsx("button", { onClick: () => {
|
|
297
299
|
if (newKernLeft && newKernRight) {
|
|
298
300
|
setKerningPairs((prev) => [
|
|
299
301
|
...prev,
|
|
300
302
|
{ left: newKernLeft, right: newKernRight, value: -50 },
|
|
301
303
|
]);
|
|
302
304
|
}
|
|
303
|
-
}, style: btnStyle(false), children:
|
|
305
|
+
}, style: btnStyle(false), children: t('fontEditor.addPair', 'Add Pair') })] }), jsxRuntime.jsx("div", { style: { maxHeight: 200, overflowY: 'auto' }, children: kerningPairs.length === 0 ? (jsxRuntime.jsx("div", { style: {
|
|
304
306
|
color: 'var(--nice-text-secondary, #868e96)',
|
|
305
307
|
fontSize: 11,
|
|
306
308
|
padding: 8,
|
|
307
309
|
textAlign: 'center',
|
|
308
|
-
}, children:
|
|
310
|
+
}, children: t('fontEditor.noKerningPairsDefined', 'No kerning pairs defined') })) : (kerningPairs.map((kp, i) => (jsxRuntime.jsxs("div", { style: {
|
|
309
311
|
display: 'flex',
|
|
310
312
|
gap: 8,
|
|
311
313
|
alignItems: 'center',
|
|
@@ -316,7 +318,7 @@ const NiceFontEditor = ({ fontName = 'MyFont', onSave, className = '', tutorial,
|
|
|
316
318
|
border: 'none',
|
|
317
319
|
color: 'var(--nice-danger, #ff6b6b)',
|
|
318
320
|
cursor: 'pointer',
|
|
319
|
-
}, "aria-label":
|
|
321
|
+
}, "aria-label": t('fontEditor.removeKerningPair', 'Remove kerning pair'), title: t('fontEditor.removeKerningPair', 'Remove kerning pair'), children: jsxRuntime.jsx(uiCore.NiceIcon, { name: "close", size: 14 }) })] }, i)))) })] })), jsxRuntime.jsxs("div", { style: { marginTop: 8, borderTop: '1px solid var(--nice-border, #373a40)', paddingTop: 8 }, children: [jsxRuntime.jsx("div", { style: { fontSize: 11, color: 'var(--nice-text-secondary, #868e96)', marginBottom: 4 }, children: t('fontEditor.preview', 'Preview') }), jsxRuntime.jsx("input", { value: editor.previewText, onChange: (e) => editor.setPreviewText(e.target.value), style: { width: '100%', padding: '6px 8px', ...fieldStyle, fontSize: 12 } }), jsxRuntime.jsx("div", { style: {
|
|
320
322
|
marginTop: 8,
|
|
321
323
|
padding: 16,
|
|
322
324
|
background: 'var(--nice-bg, #fff)',
|