@nice2dev/ui-graphics 1.3.15 → 1.3.17

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.
Files changed (294) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/animation/AnimatedPerson.js +470 -143
  3. package/dist/cjs/animation/AnimationEditor.js +289 -101
  4. package/dist/cjs/animation/Audience.js +83 -61
  5. package/dist/cjs/animation/BodyRenderer.js +69 -28
  6. package/dist/cjs/animation/animationHelper.js +281 -288
  7. package/dist/cjs/animation/characterTypes.js +200 -203
  8. package/dist/cjs/animation/choreoDSL.js +205 -219
  9. package/dist/cjs/animation/choreography.js +4 -32
  10. package/dist/cjs/animation/karaokeIntegration.js +68 -77
  11. package/dist/cjs/animation/lottieExport.js +108 -114
  12. package/dist/cjs/animation/motionPath.js +225 -248
  13. package/dist/cjs/animation/physics.js +227 -254
  14. package/dist/cjs/animation/rig/RigPlayer.js +53 -56
  15. package/dist/cjs/animation/rig/RiggedBody.js +71 -26
  16. package/dist/cjs/animation/rig/choreoRigBridge.js +72 -77
  17. package/dist/cjs/animation/rig/ik.js +13 -18
  18. package/dist/cjs/animation/rig/poseOps.js +34 -41
  19. package/dist/cjs/animation/rig/presets.js +64 -72
  20. package/dist/cjs/animation/rig/rigMath.js +25 -32
  21. package/dist/cjs/animation/rig/rigTypes.js +59 -63
  22. package/dist/cjs/animation/shapes/arms.js +31 -13
  23. package/dist/cjs/animation/shapes/eyes.js +129 -47
  24. package/dist/cjs/animation/shapes/hair.js +72 -45
  25. package/dist/cjs/animation/shapes/heads.js +131 -57
  26. package/dist/cjs/animation/shapes/headwear.js +47 -38
  27. package/dist/cjs/animation/shapes/legs.js +31 -13
  28. package/dist/cjs/animation/shapes/mouths.js +120 -44
  29. package/dist/cjs/animation/shapes/noses.js +80 -25
  30. package/dist/cjs/animation/shapes/outfits.js +101 -39
  31. package/dist/cjs/animation/shapes/torsos.js +15 -11
  32. package/dist/cjs/animation/spineExport.js +103 -121
  33. package/dist/cjs/core/LocalUI.js +108 -43
  34. package/dist/cjs/core/NiceBrushEngine.js +758 -552
  35. package/dist/cjs/core/collaboration.js +249 -251
  36. package/dist/cjs/core/colorBlindness.js +100 -115
  37. package/dist/cjs/core/dragDrop.js +155 -158
  38. package/dist/cjs/core/editorAsk.js +51 -41
  39. package/dist/cjs/core/fixes.js +140 -171
  40. package/dist/cjs/core/gridGuides.js +166 -201
  41. package/dist/cjs/core/historyVisual.js +156 -135
  42. package/dist/cjs/core/i18n.js +13 -14
  43. package/dist/cjs/core/integrations.js +238 -249
  44. package/dist/cjs/core/minimap.js +149 -151
  45. package/dist/cjs/core/plugins.js +98 -113
  46. package/dist/cjs/core/rtl.js +71 -83
  47. package/dist/cjs/core/shortcuts.js +196 -225
  48. package/dist/cjs/core/theme.js +142 -149
  49. package/dist/cjs/core/yjsCollaboration.js +232 -293
  50. package/dist/cjs/design/design-tools.js +12 -22
  51. package/dist/cjs/font/NiceFontEditor.js +877 -316
  52. package/dist/cjs/font/fontFormatUtils.js +388 -448
  53. package/dist/cjs/game/GameAsset2dEditor.js +1201 -392
  54. package/dist/cjs/game/GameAsset2dEditor.module.css.js +146 -5
  55. package/dist/cjs/game/gameAssetTypes.js +7 -16
  56. package/dist/cjs/game/gameAssetUtils.js +390 -413
  57. package/dist/cjs/game/useGameAssetEditor.js +820 -763
  58. package/dist/cjs/index.js +81 -84
  59. package/dist/cjs/nice2dev-ui-graphics.css +1 -1
  60. package/dist/cjs/node_modules/lib0/array.js +8 -70
  61. package/dist/cjs/node_modules/lib0/binary.js +3 -20
  62. package/dist/cjs/node_modules/lib0/broadcastchannel.js +24 -86
  63. package/dist/cjs/node_modules/lib0/buffer.js +15 -82
  64. package/dist/cjs/node_modules/lib0/conditions.js +3 -16
  65. package/dist/cjs/node_modules/lib0/decoding.js +108 -287
  66. package/dist/cjs/node_modules/lib0/dom.js +14 -44
  67. package/dist/cjs/node_modules/lib0/encoding.js +68 -418
  68. package/dist/cjs/node_modules/lib0/environment.js +26 -92
  69. package/dist/cjs/node_modules/lib0/error.js +5 -29
  70. package/dist/cjs/node_modules/lib0/function.js +27 -66
  71. package/dist/cjs/node_modules/lib0/iterator.js +8 -33
  72. package/dist/cjs/node_modules/lib0/logging.common.js +12 -22
  73. package/dist/cjs/node_modules/lib0/logging.js +32 -71
  74. package/dist/cjs/node_modules/lib0/map.js +16 -86
  75. package/dist/cjs/node_modules/lib0/math.js +3 -32
  76. package/dist/cjs/node_modules/lib0/number.js +4 -15
  77. package/dist/cjs/node_modules/lib0/object.js +14 -88
  78. package/dist/cjs/node_modules/lib0/observable.js +38 -78
  79. package/dist/cjs/node_modules/lib0/pair.js +3 -20
  80. package/dist/cjs/node_modules/lib0/prng.js +8 -77
  81. package/dist/cjs/node_modules/lib0/promise.js +6 -30
  82. package/dist/cjs/node_modules/lib0/random.js +8 -23
  83. package/dist/cjs/node_modules/lib0/schema.js +313 -687
  84. package/dist/cjs/node_modules/lib0/set.js +3 -10
  85. package/dist/cjs/node_modules/lib0/storage.js +20 -55
  86. package/dist/cjs/node_modules/lib0/string.js +17 -72
  87. package/dist/cjs/node_modules/lib0/symbol.js +2 -12
  88. package/dist/cjs/node_modules/lib0/time.js +2 -15
  89. package/dist/cjs/node_modules/lib0/trait/equality.js +3 -28
  90. package/dist/cjs/node_modules/lib0/url.js +4 -18
  91. package/dist/cjs/node_modules/lib0/webcrypto.js +2 -5
  92. package/dist/cjs/node_modules/y-protocols/auth.js +5 -19
  93. package/dist/cjs/node_modules/y-protocols/awareness.js +53 -116
  94. package/dist/cjs/node_modules/y-protocols/sync.js +16 -103
  95. package/dist/cjs/node_modules/y-websocket/src/y-websocket.js +77 -219
  96. package/dist/cjs/node_modules/yjs/dist/yjs.js +2128 -4868
  97. package/dist/cjs/photo/FilterThumb.js +37 -25
  98. package/dist/cjs/photo/NiceAITools.js +679 -467
  99. package/dist/cjs/photo/PhotoEditor.js +34 -20
  100. package/dist/cjs/photo/PhotoEditor.module.css.js +296 -5
  101. package/dist/cjs/photo/PhotoEditorCanvas.js +250 -91
  102. package/dist/cjs/photo/PhotoEditorLeftPanel.js +1086 -224
  103. package/dist/cjs/photo/PhotoEditorToolbar.js +135 -19
  104. package/dist/cjs/photo/photoEditorActions.js +89 -72
  105. package/dist/cjs/photo/photoEditorTypes.js +29 -32
  106. package/dist/cjs/photo/photoFilters.js +959 -985
  107. package/dist/cjs/photo/photoOverlays.js +899 -945
  108. package/dist/cjs/photo/photoSelection.js +427 -499
  109. package/dist/cjs/photo/usePhotoEditor.js +739 -741
  110. package/dist/cjs/pixel/HSVPicker.js +191 -175
  111. package/dist/cjs/pixel/PixelEditor.js +159 -48
  112. package/dist/cjs/pixel/PixelEditor.module.css.js +209 -5
  113. package/dist/cjs/pixel/PixelEditorCanvas.js +29 -16
  114. package/dist/cjs/pixel/PixelEditorMenuBar.js +160 -162
  115. package/dist/cjs/pixel/PixelEditorRightPanel.js +377 -45
  116. package/dist/cjs/pixel/PixelEditorStatusBar.js +47 -20
  117. package/dist/cjs/pixel/PixelEditorTimeline.js +106 -23
  118. package/dist/cjs/pixel/PixelEditorToolbar.js +99 -21
  119. package/dist/cjs/pixel/SpriteGeneratorPanel.js +483 -303
  120. package/dist/cjs/pixel/animalGeneratorPresets.js +776 -601
  121. package/dist/cjs/pixel/asepriteFormat.js +511 -560
  122. package/dist/cjs/pixel/buildingGeneratorPresets.js +693 -520
  123. package/dist/cjs/pixel/characterGeneratorPresets.js +644 -544
  124. package/dist/cjs/pixel/pixel-pro.js +52 -63
  125. package/dist/cjs/pixel/pixelEditorExports.js +388 -428
  126. package/dist/cjs/pixel/pixelEditorTypes.js +91 -108
  127. package/dist/cjs/pixel/pixelEditorUtils.js +519 -561
  128. package/dist/cjs/pixel/spriteGeneratorCore.js +206 -257
  129. package/dist/cjs/pixel/usePixelEditor.js +1321 -1343
  130. package/dist/cjs/texture/Nice3DTexturePainter.js +707 -440
  131. package/dist/cjs/ui/NiceUIDesigner.js +954 -527
  132. package/dist/cjs/vector/NiceSvgToCode.js +586 -446
  133. package/dist/cjs/vector/VectorEditor.js +290 -117
  134. package/dist/cjs/vector/VectorEditor.module.css.js +86 -5
  135. package/dist/cjs/vector/VectorEditorMenuBar.js +333 -275
  136. package/dist/cjs/vector/VectorEditorRightPanel.js +1094 -371
  137. package/dist/cjs/vector/VectorEditorShapeRenderer.js +198 -60
  138. package/dist/cjs/vector/VectorEditorStatusBar.js +39 -13
  139. package/dist/cjs/vector/useVectorEditor.js +848 -889
  140. package/dist/cjs/vector/vectorAnimation.js +110 -137
  141. package/dist/cjs/vector/vectorBooleanOps.js +398 -485
  142. package/dist/cjs/vector/vectorEditorExport.js +201 -203
  143. package/dist/cjs/vector/vectorEditorImport.js +173 -189
  144. package/dist/cjs/vector/vectorEditorTypes.js +42 -49
  145. package/dist/cjs/vector/vectorGradients.js +151 -174
  146. package/dist/cjs/vector/vectorIconExport.js +52 -59
  147. package/dist/cjs/vector/vectorIconImport.js +169 -219
  148. package/dist/esm/animation/AnimatedPerson.js +470 -141
  149. package/dist/esm/animation/AnimationEditor.js +290 -100
  150. package/dist/esm/animation/Audience.js +83 -59
  151. package/dist/esm/animation/BodyRenderer.js +71 -25
  152. package/dist/esm/animation/animationHelper.js +284 -287
  153. package/dist/esm/animation/characterTypes.js +204 -202
  154. package/dist/esm/animation/choreoDSL.js +212 -218
  155. package/dist/esm/animation/choreography.js +8 -31
  156. package/dist/esm/animation/karaokeIntegration.js +74 -76
  157. package/dist/esm/animation/lottieExport.js +112 -113
  158. package/dist/esm/animation/motionPath.js +235 -247
  159. package/dist/esm/animation/physics.js +235 -253
  160. package/dist/esm/animation/rig/RigPlayer.js +53 -54
  161. package/dist/esm/animation/rig/RiggedBody.js +71 -24
  162. package/dist/esm/animation/rig/choreoRigBridge.js +74 -76
  163. package/dist/esm/animation/rig/ik.js +14 -17
  164. package/dist/esm/animation/rig/poseOps.js +37 -40
  165. package/dist/esm/animation/rig/presets.js +70 -71
  166. package/dist/esm/animation/rig/rigMath.js +28 -31
  167. package/dist/esm/animation/rig/rigTypes.js +62 -62
  168. package/dist/esm/animation/shapes/arms.js +32 -12
  169. package/dist/esm/animation/shapes/eyes.js +135 -46
  170. package/dist/esm/animation/shapes/hair.js +80 -44
  171. package/dist/esm/animation/shapes/heads.js +140 -56
  172. package/dist/esm/animation/shapes/headwear.js +54 -37
  173. package/dist/esm/animation/shapes/legs.js +32 -12
  174. package/dist/esm/animation/shapes/mouths.js +127 -43
  175. package/dist/esm/animation/shapes/noses.js +87 -24
  176. package/dist/esm/animation/shapes/outfits.js +106 -38
  177. package/dist/esm/animation/shapes/torsos.js +16 -10
  178. package/dist/esm/animation/spineExport.js +106 -120
  179. package/dist/esm/core/LocalUI.js +111 -42
  180. package/dist/esm/core/NiceBrushEngine.js +761 -551
  181. package/dist/esm/core/collaboration.js +255 -250
  182. package/dist/esm/core/colorBlindness.js +106 -114
  183. package/dist/esm/core/dragDrop.js +157 -157
  184. package/dist/esm/core/editorAsk.js +53 -40
  185. package/dist/esm/core/fixes.js +145 -170
  186. package/dist/esm/core/gridGuides.js +178 -200
  187. package/dist/esm/core/historyVisual.js +158 -134
  188. package/dist/esm/core/i18n.js +15 -13
  189. package/dist/esm/core/integrations.js +244 -248
  190. package/dist/esm/core/minimap.js +151 -150
  191. package/dist/esm/core/plugins.js +102 -112
  192. package/dist/esm/core/rtl.js +77 -82
  193. package/dist/esm/core/shortcuts.js +200 -224
  194. package/dist/esm/core/theme.js +150 -148
  195. package/dist/esm/core/yjsCollaboration.js +240 -292
  196. package/dist/esm/design/design-tools.js +13 -21
  197. package/dist/esm/font/NiceFontEditor.js +880 -315
  198. package/dist/esm/font/fontFormatUtils.js +394 -447
  199. package/dist/esm/game/GameAsset2dEditor.js +1202 -391
  200. package/dist/esm/game/GameAsset2dEditor.module.css.js +146 -3
  201. package/dist/esm/game/gameAssetTypes.js +8 -15
  202. package/dist/esm/game/gameAssetUtils.js +408 -412
  203. package/dist/esm/game/useGameAssetEditor.js +821 -762
  204. package/dist/esm/index.js +332 -69
  205. package/dist/esm/nice2dev-ui-graphics.css +1 -1
  206. package/dist/esm/node_modules/lib0/array.js +15 -69
  207. package/dist/esm/node_modules/lib0/binary.js +14 -19
  208. package/dist/esm/node_modules/lib0/broadcastchannel.js +27 -85
  209. package/dist/esm/node_modules/lib0/buffer.js +20 -80
  210. package/dist/esm/node_modules/lib0/conditions.js +4 -15
  211. package/dist/esm/node_modules/lib0/decoding.js +128 -286
  212. package/dist/esm/node_modules/lib0/dom.js +20 -43
  213. package/dist/esm/node_modules/lib0/encoding.js +90 -415
  214. package/dist/esm/node_modules/lib0/environment.js +33 -91
  215. package/dist/esm/node_modules/lib0/error.js +8 -28
  216. package/dist/esm/node_modules/lib0/function.js +31 -65
  217. package/dist/esm/node_modules/lib0/iterator.js +11 -32
  218. package/dist/esm/node_modules/lib0/logging.common.js +22 -21
  219. package/dist/esm/node_modules/lib0/logging.js +44 -70
  220. package/dist/esm/node_modules/lib0/map.js +21 -85
  221. package/dist/esm/node_modules/lib0/math.js +9 -31
  222. package/dist/esm/node_modules/lib0/number.js +7 -14
  223. package/dist/esm/node_modules/lib0/object.js +26 -87
  224. package/dist/esm/node_modules/lib0/observable.js +40 -77
  225. package/dist/esm/node_modules/lib0/pair.js +5 -19
  226. package/dist/esm/node_modules/lib0/prng.js +15 -76
  227. package/dist/esm/node_modules/lib0/promise.js +7 -29
  228. package/dist/esm/node_modules/lib0/random.js +10 -22
  229. package/dist/esm/node_modules/lib0/schema.js +367 -686
  230. package/dist/esm/node_modules/lib0/set.js +4 -9
  231. package/dist/esm/node_modules/lib0/storage.js +23 -54
  232. package/dist/esm/node_modules/lib0/string.js +26 -71
  233. package/dist/esm/node_modules/lib0/symbol.js +3 -11
  234. package/dist/esm/node_modules/lib0/time.js +3 -14
  235. package/dist/esm/node_modules/lib0/trait/equality.js +5 -27
  236. package/dist/esm/node_modules/lib0/url.js +5 -17
  237. package/dist/esm/node_modules/lib0/webcrypto.js +3 -4
  238. package/dist/esm/node_modules/y-protocols/auth.js +7 -18
  239. package/dist/esm/node_modules/y-protocols/awareness.js +58 -115
  240. package/dist/esm/node_modules/y-protocols/sync.js +26 -102
  241. package/dist/esm/node_modules/y-websocket/src/y-websocket.js +82 -218
  242. package/dist/esm/node_modules/yjs/dist/yjs.js +2263 -4899
  243. package/dist/esm/photo/FilterThumb.js +37 -23
  244. package/dist/esm/photo/NiceAITools.js +685 -466
  245. package/dist/esm/photo/PhotoEditor.js +34 -18
  246. package/dist/esm/photo/PhotoEditor.module.css.js +296 -3
  247. package/dist/esm/photo/PhotoEditorCanvas.js +250 -89
  248. package/dist/esm/photo/PhotoEditorLeftPanel.js +1086 -222
  249. package/dist/esm/photo/PhotoEditorToolbar.js +135 -17
  250. package/dist/esm/photo/photoEditorActions.js +93 -71
  251. package/dist/esm/photo/photoEditorTypes.js +32 -31
  252. package/dist/esm/photo/photoFilters.js +967 -984
  253. package/dist/esm/photo/photoOverlays.js +913 -944
  254. package/dist/esm/photo/photoSelection.js +438 -498
  255. package/dist/esm/photo/usePhotoEditor.js +740 -740
  256. package/dist/esm/pixel/HSVPicker.js +192 -174
  257. package/dist/esm/pixel/PixelEditor.js +160 -47
  258. package/dist/esm/pixel/PixelEditor.module.css.js +209 -3
  259. package/dist/esm/pixel/PixelEditorCanvas.js +29 -14
  260. package/dist/esm/pixel/PixelEditorMenuBar.js +160 -160
  261. package/dist/esm/pixel/PixelEditorRightPanel.js +377 -43
  262. package/dist/esm/pixel/PixelEditorStatusBar.js +47 -18
  263. package/dist/esm/pixel/PixelEditorTimeline.js +106 -21
  264. package/dist/esm/pixel/PixelEditorToolbar.js +99 -19
  265. package/dist/esm/pixel/SpriteGeneratorPanel.js +483 -301
  266. package/dist/esm/pixel/animalGeneratorPresets.js +782 -600
  267. package/dist/esm/pixel/asepriteFormat.js +517 -559
  268. package/dist/esm/pixel/buildingGeneratorPresets.js +699 -519
  269. package/dist/esm/pixel/characterGeneratorPresets.js +650 -543
  270. package/dist/esm/pixel/pixel-pro.js +53 -62
  271. package/dist/esm/pixel/pixelEditorExports.js +397 -427
  272. package/dist/esm/pixel/pixelEditorTypes.js +103 -107
  273. package/dist/esm/pixel/pixelEditorUtils.js +551 -560
  274. package/dist/esm/pixel/spriteGeneratorCore.js +223 -256
  275. package/dist/esm/pixel/usePixelEditor.js +1322 -1342
  276. package/dist/esm/texture/Nice3DTexturePainter.js +709 -439
  277. package/dist/esm/ui/NiceUIDesigner.js +957 -526
  278. package/dist/esm/vector/NiceSvgToCode.js +589 -445
  279. package/dist/esm/vector/VectorEditor.js +291 -116
  280. package/dist/esm/vector/VectorEditor.module.css.js +86 -3
  281. package/dist/esm/vector/VectorEditorMenuBar.js +333 -273
  282. package/dist/esm/vector/VectorEditorRightPanel.js +1094 -369
  283. package/dist/esm/vector/VectorEditorShapeRenderer.js +199 -59
  284. package/dist/esm/vector/VectorEditorStatusBar.js +39 -11
  285. package/dist/esm/vector/useVectorEditor.js +849 -888
  286. package/dist/esm/vector/vectorAnimation.js +115 -136
  287. package/dist/esm/vector/vectorBooleanOps.js +401 -484
  288. package/dist/esm/vector/vectorEditorExport.js +207 -202
  289. package/dist/esm/vector/vectorEditorImport.js +174 -188
  290. package/dist/esm/vector/vectorEditorTypes.js +50 -48
  291. package/dist/esm/vector/vectorGradients.js +158 -173
  292. package/dist/esm/vector/vectorIconExport.js +53 -58
  293. package/dist/esm/vector/vectorIconImport.js +171 -218
  294. package/package.json +9 -15
@@ -1,380 +1,1103 @@
1
- 'use strict';
2
-
3
- var jsxRuntime = require('react/jsx-runtime');
4
- var ui = require('@nice2dev/ui');
5
- var uiCore = require('@nice2dev/ui-core');
6
- var React = require('react');
7
- var i18n = require('../core/i18n.js');
8
- var vectorAnimation = require('./vectorAnimation.js');
9
- var VectorEditor_module = require('./VectorEditor.module.css.js');
10
- var vectorEditorTypes = require('./vectorEditorTypes.js');
11
- var vectorGradients = require('./vectorGradients.js');
12
- var vectorIconImport = require('./vectorIconImport.js');
13
-
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const ui = require("@nice2dev/ui");
5
+ const uiCore = require("@nice2dev/ui-core");
6
+ const React = require("react");
7
+ const i18n = require("../core/i18n.js");
8
+ const vectorAnimation = require("./vectorAnimation.js");
9
+ const VectorEditor_module = require("./VectorEditor.module.css.js");
10
+ const vectorEditorTypes = require("./vectorEditorTypes.js");
11
+ const vectorGradients = require("./vectorGradients.js");
12
+ const vectorIconImport = require("./vectorIconImport.js");
14
13
  const VectorEditorRightPanel = ({ api, library, artW = 512, artH = 512 }) => {
15
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
16
- const { t } = i18n.useNiceTranslation();
17
- const { tool, selId, selShape, shapes, fillCol, strokeCol, strokeW, shapeOpacity, cornerRadius, polygonSides, starPoints2, starInnerRatio, fontSize, fontFamily, snapGrid, gridSize, setFillCol, setStrokeCol, setStrokeW, setShapeOpacity, setCornerRadius, setPolygonSides, setStarPoints2, setStarInnerRatio, setFontSize, setFontFamily, setGridSize, updateSel, setSelId, setTool, setShapes, snap, animations, isPlaying, setShapeAnimation, setIsPlaying, setPreviewTime, } = api;
18
- // Gradient editing state
19
- const [fillMode, setFillMode] = React.useState('solid');
20
- const [selectedGradient, setSelectedGradient] = React.useState(null);
21
- const [showGradientEditor, setShowGradientEditor] = React.useState(false);
22
- // Library: insert the next picked icon as a small top-right corner badge
23
- // (ports the badge/overlay feature from the retired NiceIconEditor).
24
- const [asBadge, setAsBadge] = React.useState(false);
25
- const applyGradient = (gradient) => {
26
- const newGrad = { ...vectorGradients.cloneGradient(gradient), id: vectorGradients.gradientId() };
27
- setSelectedGradient(newGrad);
28
- // Store gradient in shape as serialized reference
29
- updateSel({
30
- fill: `url(#${newGrad.id})`,
31
- // Store gradient data as custom property (will be used in SVG export)
32
- });
33
- };
34
- const propertiesContent = (jsxRuntime.jsxs("div", { className: VectorEditor_module.rightPanelTabBody, children: [jsxRuntime.jsxs("div", { className: VectorEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: VectorEditor_module.panelTitle, children: jsxRuntime.jsx("span", { children: t('vectorEditor.properties.appearance', 'Appearance') }) }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.fill', 'Fill') }), jsxRuntime.jsxs("div", { style: { display: 'flex', gap: 4 }, children: [jsxRuntime.jsx(ui.NiceButton, { className: `${VectorEditor_module.menuBtn} ${fillMode === 'solid' ? VectorEditor_module.menuBtnActive : ''}`, style: { padding: '2px 6px', fontSize: 10 }, variant: fillMode === 'solid' ? 'primary' : 'ghost', size: "sm", onClick: () => setFillMode('solid'), children: t('vectorEditor.properties.solid', 'Solid') }), jsxRuntime.jsx(ui.NiceButton, { className: `${VectorEditor_module.menuBtn} ${fillMode === 'gradient' ? VectorEditor_module.menuBtnActive : ''}`, style: { padding: '2px 6px', fontSize: 10 }, variant: fillMode === 'gradient' ? 'primary' : 'ghost', size: "sm", onClick: () => setFillMode('gradient'), children: t('vectorEditor.properties.gradient', 'Gradient') })] })] }), fillMode === 'solid' ? (jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel }), jsxRuntime.jsx("div", { className: VectorEditor_module.propColorSwatch, style: { background: fillCol }, children: jsxRuntime.jsx(ui.NiceColorPicker, { value: fillCol, showInput: false, showRandom: false, onChange: (c) => {
35
- setFillCol(c);
36
- updateSel({ fill: c });
37
- } }) }), jsxRuntime.jsx(ui.NiceTextInput, { className: VectorEditor_module.propInput, value: (selShape === null || selShape === void 0 ? void 0 : selShape.fill) || fillCol, onChange: (val) => {
38
- setFillCol(val);
39
- updateSel({ fill: val });
40
- } })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: VectorEditor_module.propRow, style: { flexWrap: 'wrap', gap: 4 }, children: vectorGradients.PRESET_GRADIENTS.map((grad, i) => (jsxRuntime.jsx("div", { role: "button", tabIndex: 0, onKeyDown: uiCore.clickOnActivationKey, style: {
41
- width: 24,
42
- height: 24,
43
- borderRadius: 4,
44
- background: vectorGradients.gradientToCSS(grad),
45
- cursor: 'pointer',
46
- border: (selectedGradient === null || selectedGradient === void 0 ? void 0 : selectedGradient.id) === grad.id
47
- ? '2px solid var(--nice-bg, #FFF)'
48
- : '1px solid var(--nice-border-color, #444)',
49
- }, onClick: () => applyGradient(grad), title: t('vectorEditor.gradient', '{type} gradient').replace('{type}', String(grad.type)) }, i))) }), jsxRuntime.jsx("div", { className: VectorEditor_module.propRow, children: jsxRuntime.jsxs(ui.NiceButton, { className: VectorEditor_module.menuBtn, variant: "ghost", size: "sm", style: { width: '100%', fontSize: 10 }, onClick: () => setShowGradientEditor(!showGradientEditor), children: [jsxRuntime.jsx(uiCore.NiceIcon, { name: showGradientEditor ? 'chevron-down' : 'chevron-right', size: 14 }), ' ', showGradientEditor
50
- ? t('vectorEditor.properties.hideEditor', 'Hide Editor')
51
- : t('vectorEditor.properties.editGradient', 'Edit Gradient')] }) }), showGradientEditor && selectedGradient && (jsxRuntime.jsxs("div", { style: {
52
- padding: 4,
53
- background: 'var(--nice-bg-secondary, #252525)',
54
- borderRadius: 4,
55
- margin: '4px 0',
56
- }, children: [jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.type', 'Type') }), jsxRuntime.jsx(ui.NiceSelect, { className: VectorEditor_module.propInput, value: selectedGradient.type, onChange: (val) => {
57
- const type = val;
58
- let newGrad;
59
- if (type === 'linear') {
60
- newGrad = {
61
- type: 'linear',
62
- id: vectorGradients.gradientId(),
63
- angle: 0,
64
- stops: selectedGradient.stops,
65
- };
66
- }
67
- else {
68
- newGrad = {
69
- type: 'radial',
70
- id: vectorGradients.gradientId(),
71
- cx: 0.5,
72
- cy: 0.5,
73
- r: 0.7,
74
- stops: selectedGradient.stops,
75
- };
76
- }
77
- setSelectedGradient(newGrad);
78
- updateSel({ fill: `url(#${newGrad.id})` });
79
- }, options: [
80
- { value: 'linear', label: t('vectorEditor.properties.linear', 'Linear') },
81
- { value: 'radial', label: t('vectorEditor.properties.radial', 'Radial') },
82
- ] })] }), selectedGradient.type === 'linear' && (jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.angle', 'Angle') }), jsxRuntime.jsx(ui.NiceSlider, { className: VectorEditor_module.propInput, min: 0, max: 360, value: selectedGradient.angle, onChange: (val) => {
83
- const newGrad = {
84
- ...selectedGradient,
85
- id: vectorGradients.gradientId(),
86
- angle: val,
87
- };
88
- setSelectedGradient(newGrad);
89
- updateSel({ fill: `url(#${newGrad.id})` });
90
- } }), jsxRuntime.jsxs("span", { style: { fontSize: 10, minWidth: 28 }, children: [selectedGradient.angle, "\u00B0"] })] })), selectedGradient.type === 'radial' && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.cx', 'CX') }), jsxRuntime.jsx(ui.NiceSlider, { className: VectorEditor_module.propInput, min: 0, max: 100, value: selectedGradient.cx * 100, onChange: (val) => {
91
- const newGrad = {
92
- ...selectedGradient,
93
- id: vectorGradients.gradientId(),
94
- cx: val / 100,
95
- };
96
- setSelectedGradient(newGrad);
97
- updateSel({ fill: `url(#${newGrad.id})` });
98
- } })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.cy', 'CY') }), jsxRuntime.jsx(ui.NiceSlider, { className: VectorEditor_module.propInput, min: 0, max: 100, value: selectedGradient.cy * 100, onChange: (val) => {
99
- const newGrad = {
100
- ...selectedGradient,
101
- id: vectorGradients.gradientId(),
102
- cy: val / 100,
103
- };
104
- setSelectedGradient(newGrad);
105
- updateSel({ fill: `url(#${newGrad.id})` });
106
- } })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.r', 'R') }), jsxRuntime.jsx(ui.NiceSlider, { className: VectorEditor_module.propInput, min: 10, max: 100, value: selectedGradient.r * 100, onChange: (val) => {
107
- const newGrad = {
108
- ...selectedGradient,
109
- id: vectorGradients.gradientId(),
110
- r: val / 100,
111
- };
112
- setSelectedGradient(newGrad);
113
- updateSel({ fill: `url(#${newGrad.id})` });
114
- } })] })] })), jsxRuntime.jsx("div", { style: { fontSize: 10, color: 'var(--nice-text-secondary, #888)', marginTop: 4 }, children: t('vectorEditor.properties.colorStops', 'Color Stops:') }), selectedGradient.stops.map((stop, i) => (jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx(ui.NiceColorPicker, { value: stop.color, showInput: false, showRandom: false, style: { width: 24, height: 20 }, onChange: (color) => {
115
- const newStops = [...selectedGradient.stops];
116
- newStops[i] = { ...newStops[i], color };
117
- const newGrad = { ...selectedGradient, id: vectorGradients.gradientId(), stops: newStops };
118
- setSelectedGradient(newGrad);
119
- updateSel({ fill: `url(#${newGrad.id})` });
120
- } }), jsxRuntime.jsx(ui.NiceSlider, { min: 0, max: 100, value: stop.offset * 100, style: { flex: 1 }, onChange: (val) => {
121
- const newStops = [...selectedGradient.stops];
122
- newStops[i] = { ...newStops[i], offset: val / 100 };
123
- newStops.sort((a, b) => a.offset - b.offset);
124
- const newGrad = { ...selectedGradient, id: vectorGradients.gradientId(), stops: newStops };
125
- setSelectedGradient(newGrad);
126
- updateSel({ fill: `url(#${newGrad.id})` });
127
- } }), jsxRuntime.jsxs("span", { style: { fontSize: 9, minWidth: 24 }, children: [Math.round(stop.offset * 100), "%"] })] }, i))), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, style: { gap: 4 }, children: [jsxRuntime.jsx(ui.NiceButton, { className: VectorEditor_module.menuBtn, variant: "ghost", size: "sm", style: { fontSize: 10, flex: 1 }, onClick: () => {
128
- const newStops = [
129
- ...selectedGradient.stops,
130
- { offset: 0.5, color: 'var(--nice-text-secondary, #888888)' },
131
- ];
132
- newStops.sort((a, b) => a.offset - b.offset);
133
- const newGrad = { ...selectedGradient, id: vectorGradients.gradientId(), stops: newStops };
134
- setSelectedGradient(newGrad);
135
- updateSel({ fill: `url(#${newGrad.id})` });
136
- }, children: t('vectorEditor.properties.addStop', '+ Add Stop') }), jsxRuntime.jsx(ui.NiceButton, { className: VectorEditor_module.menuBtn, variant: "ghost", size: "sm", style: { fontSize: 10, flex: 1 }, disabled: selectedGradient.stops.length <= 2, onClick: () => {
137
- if (selectedGradient.stops.length <= 2) {
138
- return;
139
- }
140
- const newStops = selectedGradient.stops.slice(0, -1);
141
- const newGrad = { ...selectedGradient, id: vectorGradients.gradientId(), stops: newStops };
142
- setSelectedGradient(newGrad);
143
- updateSel({ fill: `url(#${newGrad.id})` });
144
- }, children: t('vectorEditor.properties.removeStop', '- Remove') })] })] }))] })), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.stroke', 'Stroke') }), jsxRuntime.jsx("div", { className: VectorEditor_module.propColorSwatch, style: { background: strokeCol }, children: jsxRuntime.jsx(ui.NiceColorPicker, { value: strokeCol, showInput: false, showRandom: false, onChange: (c) => {
145
- setStrokeCol(c);
146
- updateSel({ stroke: c });
147
- } }) }), jsxRuntime.jsx(ui.NiceTextInput, { className: VectorEditor_module.propInput, value: (selShape === null || selShape === void 0 ? void 0 : selShape.stroke) || strokeCol, onChange: (val) => {
148
- setStrokeCol(val);
149
- updateSel({ stroke: val });
150
- } })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.width', 'Width') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, min: 0, max: 100, value: (_a = selShape === null || selShape === void 0 ? void 0 : selShape.strokeWidth) !== null && _a !== void 0 ? _a : strokeW, onChange: (val) => {
151
- const v = val !== null && val !== void 0 ? val : 0;
152
- setStrokeW(v);
153
- updateSel({ strokeWidth: v });
154
- } })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.opacity', 'Opacity') }), jsxRuntime.jsx(ui.NiceSlider, { className: VectorEditor_module.propInput, min: 0, max: 1, step: 0.01, value: (_b = selShape === null || selShape === void 0 ? void 0 : selShape.opacity) !== null && _b !== void 0 ? _b : shapeOpacity, onChange: (val) => {
155
- setShapeOpacity(val);
156
- updateSel({ opacity: val });
157
- } }), jsxRuntime.jsxs("span", { style: { fontSize: 10, minWidth: 28 }, children: [Math.round(((_c = selShape === null || selShape === void 0 ? void 0 : selShape.opacity) !== null && _c !== void 0 ? _c : shapeOpacity) * 100), "%"] })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.rotation', 'Rotation') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, min: -360, max: 360, value: (_d = selShape === null || selShape === void 0 ? void 0 : selShape.rotation) !== null && _d !== void 0 ? _d : 0, onChange: (val) => updateSel({ rotation: val !== null && val !== void 0 ? val : 0 }) }), jsxRuntime.jsx("span", { style: { fontSize: 10 }, children: "\u00B0" })] })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: VectorEditor_module.panelTitle, children: jsxRuntime.jsx("span", { children: t('vectorEditor.properties.toolOptions', 'Tool Options') }) }), (tool === 'roundrect' || (selShape === null || selShape === void 0 ? void 0 : selShape.type) === 'roundrect') && (jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.radius', 'Radius') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, min: 0, max: 200, value: (_e = selShape === null || selShape === void 0 ? void 0 : selShape.rx) !== null && _e !== void 0 ? _e : cornerRadius, onChange: (val) => {
158
- const v = val !== null && val !== void 0 ? val : 0;
159
- setCornerRadius(v);
160
- updateSel({ rx: v });
161
- } })] })), (tool === 'polygon' || (selShape === null || selShape === void 0 ? void 0 : selShape.type) === 'polygon') && (jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.sides', 'Sides') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, min: 3, max: 32, value: (_f = selShape === null || selShape === void 0 ? void 0 : selShape.sides) !== null && _f !== void 0 ? _f : polygonSides, onChange: (val) => {
162
- const v = val !== null && val !== void 0 ? val : 3;
163
- setPolygonSides(v);
164
- updateSel({ sides: v });
165
- } })] })), (tool === 'star' || (selShape === null || selShape === void 0 ? void 0 : selShape.type) === 'star') && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.points', 'Points') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, min: 3, max: 32, value: (_g = selShape === null || selShape === void 0 ? void 0 : selShape.sides) !== null && _g !== void 0 ? _g : starPoints2, onChange: (val) => {
166
- const v = val !== null && val !== void 0 ? val : 3;
167
- setStarPoints2(v);
168
- updateSel({ sides: v });
169
- } })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.innerR', 'Inner R') }), jsxRuntime.jsx(ui.NiceSlider, { className: VectorEditor_module.propInput, min: 0.1, max: 0.9, step: 0.05, value: (_h = selShape === null || selShape === void 0 ? void 0 : selShape.innerRadius) !== null && _h !== void 0 ? _h : starInnerRatio, onChange: (val) => {
170
- setStarInnerRatio(val);
171
- updateSel({ innerRadius: val });
172
- } }), jsxRuntime.jsxs("span", { style: { fontSize: 10 }, children: [Math.round(((_j = selShape === null || selShape === void 0 ? void 0 : selShape.innerRadius) !== null && _j !== void 0 ? _j : starInnerRatio) * 100), "%"] })] })] })), (tool === 'text' || (selShape === null || selShape === void 0 ? void 0 : selShape.type) === 'text') && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.size', 'Size') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, min: 8, max: 200, value: (_k = selShape === null || selShape === void 0 ? void 0 : selShape.fontSize) !== null && _k !== void 0 ? _k : fontSize, onChange: (val) => {
173
- const v = val !== null && val !== void 0 ? val : 12;
174
- setFontSize(v);
175
- updateSel({ fontSize: v });
176
- } })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.font', 'Font') }), jsxRuntime.jsx(ui.NiceSelect, { className: VectorEditor_module.propInput, value: (_l = selShape === null || selShape === void 0 ? void 0 : selShape.fontFamily) !== null && _l !== void 0 ? _l : fontFamily, onChange: (val) => {
177
- setFontFamily(val);
178
- updateSel({ fontFamily: val });
179
- }, options: vectorEditorTypes.FONTS.map((f) => ({ value: f, label: f })) })] })] })), snapGrid && (jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.grid', 'Grid') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, min: 4, max: 128, value: gridSize, onChange: (val) => setGridSize(val !== null && val !== void 0 ? val : 8) })] }))] }), selShape && (jsxRuntime.jsxs("div", { className: VectorEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: VectorEditor_module.panelTitle, children: jsxRuntime.jsx("span", { children: t('vectorEditor.properties.transform', 'Transform') }) }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.x', 'X') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, value: Math.round(selShape.x), onChange: (val) => updateSel({ x: val !== null && val !== void 0 ? val : 0 }) })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.y', 'Y') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, value: Math.round(selShape.y), onChange: (val) => updateSel({ y: val !== null && val !== void 0 ? val : 0 }) })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.w', 'W') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, value: Math.round(selShape.w), onChange: (val) => updateSel({ w: val !== null && val !== void 0 ? val : 0 }) })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.properties.h', 'H') }), jsxRuntime.jsx(ui.NiceNumberInput, { className: VectorEditor_module.propInput, value: Math.round(selShape.h), onChange: (val) => updateSel({ h: val !== null && val !== void 0 ? val : 0 }) })] })] }))] }));
180
- // Insert an icon as editable shapes. `badge` scales it down and pins it to the
181
- // top-right corner (the former NiceIconEditor "badge/overlay" feature).
182
- const insertIcon = (Icon, badge) => {
183
- var _a, _b;
184
- if (badge) {
185
- const box = Math.round(Math.min(artW, artH) * 0.42);
186
- const made = vectorIconImport.iconComponentToShapes(Icon, { artW: box, artH: box, margin: 4 });
187
- if (made.length === 0) {
188
- return;
14
+ const { t } = i18n.useNiceTranslation();
15
+ const {
16
+ tool,
17
+ selId,
18
+ selShape,
19
+ shapes,
20
+ fillCol,
21
+ strokeCol,
22
+ strokeW,
23
+ shapeOpacity,
24
+ cornerRadius,
25
+ polygonSides,
26
+ starPoints2,
27
+ starInnerRatio,
28
+ fontSize,
29
+ fontFamily,
30
+ snapGrid,
31
+ gridSize,
32
+ setFillCol,
33
+ setStrokeCol,
34
+ setStrokeW,
35
+ setShapeOpacity,
36
+ setCornerRadius,
37
+ setPolygonSides,
38
+ setStarPoints2,
39
+ setStarInnerRatio,
40
+ setFontSize,
41
+ setFontFamily,
42
+ setGridSize,
43
+ updateSel,
44
+ setSelId,
45
+ setTool,
46
+ setShapes,
47
+ snap,
48
+ animations,
49
+ isPlaying,
50
+ setShapeAnimation,
51
+ setIsPlaying,
52
+ setPreviewTime
53
+ } = api;
54
+ const [fillMode, setFillMode] = React.useState("solid");
55
+ const [selectedGradient, setSelectedGradient] = React.useState(null);
56
+ const [showGradientEditor, setShowGradientEditor] = React.useState(false);
57
+ const [asBadge, setAsBadge] = React.useState(false);
58
+ const applyGradient = (gradient) => {
59
+ const newGrad = { ...vectorGradients.cloneGradient(gradient), id: vectorGradients.gradientId() };
60
+ setSelectedGradient(newGrad);
61
+ updateSel({
62
+ fill: `url(#${newGrad.id})`
63
+ // Store gradient data as custom property (will be used in SVG export)
64
+ });
65
+ };
66
+ const propertiesContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.rightPanelTabBody, children: [
67
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.panelSection, children: [
68
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.panelTitle, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("vectorEditor.properties.appearance", "Appearance") }) }),
69
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
70
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.fill", "Fill") }),
71
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 4 }, children: [
72
+ /* @__PURE__ */ jsxRuntime.jsx(
73
+ ui.NiceButton,
74
+ {
75
+ className: `${VectorEditor_module.default.menuBtn} ${fillMode === "solid" ? VectorEditor_module.default.menuBtnActive : ""}`,
76
+ style: { padding: "2px 6px", fontSize: 10 },
77
+ variant: fillMode === "solid" ? "primary" : "ghost",
78
+ size: "sm",
79
+ onClick: () => setFillMode("solid"),
80
+ children: t("vectorEditor.properties.solid", "Solid")
189
81
  }
190
- const dx = artW - box;
191
- const offset = made.map((s) => ({
192
- ...s,
193
- x: s.x + dx,
194
- ...(s.x2 != null ? { x2: s.x2 + dx } : {}),
195
- ...(s.points ? { points: s.points.map((p) => ({ ...p, x: p.x + dx })) } : {}),
196
- }));
197
- const next = [...shapes, ...offset];
198
- setShapes(next);
199
- snap(next);
200
- if ((_a = offset[0]) === null || _a === void 0 ? void 0 : _a.id) {
201
- setSelId(offset[0].id);
82
+ ),
83
+ /* @__PURE__ */ jsxRuntime.jsx(
84
+ ui.NiceButton,
85
+ {
86
+ className: `${VectorEditor_module.default.menuBtn} ${fillMode === "gradient" ? VectorEditor_module.default.menuBtnActive : ""}`,
87
+ style: { padding: "2px 6px", fontSize: 10 },
88
+ variant: fillMode === "gradient" ? "primary" : "ghost",
89
+ size: "sm",
90
+ onClick: () => setFillMode("gradient"),
91
+ children: t("vectorEditor.properties.gradient", "Gradient")
202
92
  }
203
- setTool('pointer');
204
- return;
205
- }
206
- const inserted = vectorIconImport.iconComponentToShapes(Icon, { artW, artH });
207
- if (inserted.length === 0) {
208
- return;
209
- }
210
- const next = [...shapes, ...inserted];
211
- setShapes(next);
212
- snap(next);
213
- if ((_b = inserted[0]) === null || _b === void 0 ? void 0 : _b.id) {
214
- setSelId(inserted[0].id);
215
- }
216
- setTool('pointer');
217
- };
218
- const reorderShape = (id, dir) => {
219
- const idx = shapes.findIndex((s) => s.id === id);
220
- if (idx < 0) {
221
- return;
222
- }
223
- const next = shapes.slice();
224
- const target = idx + dir;
225
- if (target < 0 || target >= next.length) {
226
- return;
227
- }
228
- [next[idx], next[target]] = [next[target], next[idx]];
229
- setShapes(next);
230
- snap(next);
231
- };
232
- const layersContent = (jsxRuntime.jsx("div", { className: VectorEditor_module.rightPanelTabBody, children: jsxRuntime.jsxs("div", { className: VectorEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: VectorEditor_module.panelTitle, children: jsxRuntime.jsxs("span", { children: [t('vectorEditor.layers.title', 'Layers'), " (", shapes.length, ")"] }) }), [...shapes].reverse().map((s, revIdx) => {
233
- var _a;
234
- const realIdx = shapes.length - 1 - revIdx;
235
- const active = s.id === selId;
236
- return (jsxRuntime.jsxs("div", { role: "button", tabIndex: 0, onKeyDown: uiCore.clickOnActivationKey, className: `${VectorEditor_module.layerRow} ${active ? VectorEditor_module.layerRowActive : ''} ${s.locked ? VectorEditor_module.layerRowLocked : ''}`, onClick: () => {
237
- setSelId(s.id);
238
- setTool('pointer');
239
- }, children: [jsxRuntime.jsx("button", { type: "button", className: VectorEditor_module.layerIconBtn, title: s.hidden
240
- ? t('vectorEditor.layers.show', 'Show')
241
- : t('vectorEditor.layers.hide', 'Hide'), onClick: (e) => {
242
- e.stopPropagation();
243
- const next = shapes.map((x) => (x.id === s.id ? { ...x, hidden: !x.hidden } : x));
244
- setShapes(next);
245
- snap(next);
246
- }, children: jsxRuntime.jsx(uiCore.NiceIcon, { name: s.hidden ? 'eye-off' : 'eye', size: 14 }) }), jsxRuntime.jsx("button", { type: "button", className: VectorEditor_module.layerIconBtn, title: s.locked
247
- ? t('vectorEditor.layers.unlock', 'Unlock')
248
- : t('vectorEditor.layers.lock', 'Lock'), onClick: (e) => {
249
- e.stopPropagation();
250
- const next = shapes.map((x) => (x.id === s.id ? { ...x, locked: !x.locked } : x));
251
- setShapes(next);
252
- snap(next);
253
- }, children: jsxRuntime.jsx(uiCore.NiceIcon, { name: "lock", size: 14, style: { opacity: s.locked ? 1 : 0.4 } }) }), jsxRuntime.jsx("span", { className: VectorEditor_module.shapeIcon, children: jsxRuntime.jsx(uiCore.NiceIcon, { name: s.type === 'rect' || s.type === 'roundrect'
254
- ? 'square'
255
- : s.type === 'ellipse'
256
- ? 'circle'
257
- : s.type === 'line'
258
- ? 'line'
259
- : s.type === 'arrow'
260
- ? 'arrow-right'
261
- : s.type === 'polygon'
262
- ? 'hexagon'
263
- : s.type === 'star'
264
- ? 'star'
265
- : s.type === 'polyline'
266
- ? 'pen'
267
- : s.type === 'path'
268
- ? 'wand'
269
- : 'type', size: 14 }) }), jsxRuntime.jsx("input", { className: VectorEditor_module.layerNameInput, value: (_a = s.name) !== null && _a !== void 0 ? _a : s.type, disabled: s.locked, onClick: (e) => e.stopPropagation(), onChange: (e) => {
270
- const v = e.target.value;
271
- const next = shapes.map((x) => (x.id === s.id ? { ...x, name: v } : x));
272
- setShapes(next);
273
- }, onBlur: () => snap(shapes) }), jsxRuntime.jsx("button", { type: "button", className: VectorEditor_module.layerIconBtn, title: t('vectorEditor.layers.moveUp', 'Move up'), onClick: (e) => {
274
- e.stopPropagation();
275
- reorderShape(s.id, 1);
276
- }, disabled: realIdx === shapes.length - 1, children: jsxRuntime.jsx(uiCore.NiceIcon, { name: "arrow-up", size: 14 }) }), jsxRuntime.jsx("button", { type: "button", className: VectorEditor_module.layerIconBtn, title: t('vectorEditor.layers.moveDown', 'Move down'), onClick: (e) => {
277
- e.stopPropagation();
278
- reorderShape(s.id, -1);
279
- }, disabled: realIdx === 0, children: jsxRuntime.jsx(uiCore.NiceIcon, { name: "arrow-down", size: 14 }) })] }, s.id));
280
- }), shapes.length === 0 && (jsxRuntime.jsx("div", { style: { color: 'var(--nice-text-secondary)', fontSize: 11, padding: 4 }, children: t('vectorEditor.layers.empty', 'No layers yet. Use the tools to draw, or insert from the Library tab.') }))] }) }));
281
- const libraryContent = (jsxRuntime.jsx("div", { className: VectorEditor_module.rightPanelTabBody, children: library && library.length > 0 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: VectorEditor_module.propRow, style: { padding: '4px 0' }, children: jsxRuntime.jsxs(ui.NiceButton, { className: `${VectorEditor_module.menuBtn} ${asBadge ? VectorEditor_module.menuBtnActive : ''}`, variant: asBadge ? 'primary' : 'ghost', size: "sm", style: { width: '100%', fontSize: 11 }, onClick: () => setAsBadge((v) => !v), "aria-pressed": asBadge, children: [asBadge && jsxRuntime.jsx(uiCore.NiceIcon, { name: "plus", size: 14 }), ' ', asBadge
282
- ? t('vectorEditor.library.insertAsBadgeOn', 'Inserting as corner badge')
283
- : t('vectorEditor.library.insertAsBadge', 'Insert as corner badge')] }) }), jsxRuntime.jsx("div", { className: VectorEditor_module.libraryGrid, children: library.map((entry) => {
284
- const Icon = entry.Component;
285
- return (jsxRuntime.jsxs("button", { type: "button", className: VectorEditor_module.libraryCell, title: entry.name, onClick: () => insertIcon(Icon, asBadge), children: [jsxRuntime.jsx("div", { style: {
286
- width: 28,
287
- height: 28,
288
- display: 'flex',
289
- alignItems: 'center',
290
- justifyContent: 'center',
291
- }, children: jsxRuntime.jsx(Icon, { size: "md" }) }), jsxRuntime.jsx("span", { children: entry.name })] }, entry.name));
292
- }) })] })) : (jsxRuntime.jsx("div", { style: { color: 'var(--nice-text-secondary)', fontSize: 11, padding: 12 }, children: t('vectorEditor.library.passProp', 'Pass a library prop to NiceVectorEditor to populate this tab with insertable icons.') })) }));
293
- const selAnim = selId ? animations[selId] : undefined;
294
- const animationCount = Object.keys(animations).length;
295
- const timelineContent = (jsxRuntime.jsxs("div", { className: VectorEditor_module.rightPanelTabBody, children: [jsxRuntime.jsxs("div", { className: VectorEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: VectorEditor_module.panelTitle, children: jsxRuntime.jsx("span", { children: t('vectorEditor.timeline.animationTitle', 'Animation') }) }), !selId ? (jsxRuntime.jsx("div", { style: { color: 'var(--nice-text-secondary)', fontSize: 11, padding: 4 }, children: t('vectorEditor.timeline.attachHint', 'Select a shape to attach an animation.') })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.timeline.preset', 'Preset') }), jsxRuntime.jsx("div", { style: { display: 'flex', flexWrap: 'wrap', gap: 4 }, children: Object.keys(vectorAnimation.ANIMATION_PRESETS).map((key) => (jsxRuntime.jsx(ui.NiceButton, { variant: "ghost", size: "sm", onClick: () => setShapeAnimation(selId, vectorAnimation.ANIMATION_PRESETS[key]), children: key }, key))) })] }), selAnim && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.timeline.duration', 'Duration (ms)') }), jsxRuntime.jsx(ui.NiceNumberInput, { value: selAnim.duration, min: 100, max: 10000, step: 100, onChange: (v) => setShapeAnimation(selId, {
296
- ...selAnim,
297
- duration: Number(v) || selAnim.duration,
298
- }) })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.timeline.repeat', 'Repeat') }), jsxRuntime.jsx(ui.NiceSelect, { value: selAnim.repeat === 'infinite' ? 'infinite' : String(selAnim.repeat), onChange: (v) => setShapeAnimation(selId, {
299
- ...selAnim,
300
- repeat: v === 'infinite' ? 'infinite' : Number(v),
301
- }), options: [
302
- { value: 'infinite', label: 'infinite' },
303
- { value: '1', label: '1x' },
304
- { value: '2', label: '2x' },
305
- { value: '3', label: '3x' },
306
- { value: '5', label: '5x' },
307
- ] })] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, children: t('vectorEditor.timeline.direction', 'Direction') }), jsxRuntime.jsx(ui.NiceSelect, { value: selAnim.direction, onChange: (v) => setShapeAnimation(selId, {
308
- ...selAnim,
309
- direction: v,
310
- }), options: [
311
- { value: 'normal', label: 'normal' },
312
- { value: 'alternate', label: 'alternate' },
313
- ] })] }), jsxRuntime.jsx("div", { className: VectorEditor_module.propRow, children: jsxRuntime.jsx(ui.NiceButton, { variant: "ghost", size: "sm", onClick: () => setShapeAnimation(selId, null), children: t('vectorEditor.timeline.remove', 'Remove animation') }) }), jsxRuntime.jsx("div", { className: VectorEditor_module.panelTitle, style: { marginTop: 8 }, children: jsxRuntime.jsx("span", { children: t('vectorEditor.timeline.keyframes', 'Keyframes') }) }), selAnim.keyframes.map((k, i) => (jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, style: { flexDirection: 'column', alignItems: 'stretch', gap: 2 }, children: [jsxRuntime.jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 4 }, children: [jsxRuntime.jsx("span", { className: VectorEditor_module.propLabel, style: { minWidth: 24 }, children: t('vectorEditor.timeline.tLabel', 't') }), jsxRuntime.jsx(ui.NiceSlider, { value: k.t, min: 0, max: 1, step: 0.01, onChange: (v) => {
314
- const nextKfs = selAnim.keyframes.map((kf, j) => j === i ? { ...kf, t: Number(v) } : kf);
315
- nextKfs.sort((a, b) => a.t - b.t);
316
- setShapeAnimation(selId, { ...selAnim, keyframes: nextKfs });
317
- } }), jsxRuntime.jsx(ui.NiceButton, { variant: "ghost", size: "sm", disabled: selAnim.keyframes.length <= 2, onClick: () => {
318
- const nextKfs = selAnim.keyframes.filter((_, j) => j !== i);
319
- setShapeAnimation(selId, { ...selAnim, keyframes: nextKfs });
320
- }, "aria-label": t('vectorEditor.timeline.removeKeyframe', 'Remove keyframe'), children: jsxRuntime.jsx(uiCore.NiceIcon, { name: "trash", size: 14 }) })] }), jsxRuntime.jsx("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 2 }, children: ['rotate', 'scale', 'translateX', 'translateY', 'opacity'].map((field) => {
321
- var _a;
322
- return (jsxRuntime.jsx(ui.NiceNumberInput, { value: (_a = k[field]) !== null && _a !== void 0 ? _a : 0, step: field === 'scale' || field === 'opacity' ? 0.1 : 1, placeholder: field[0].toUpperCase(), onChange: (v) => {
323
- const num = v == null ? undefined : Number(v);
324
- const nextKfs = selAnim.keyframes.map((kf, j) => j === i ? { ...kf, [field]: num } : kf);
325
- setShapeAnimation(selId, { ...selAnim, keyframes: nextKfs });
326
- } }, field));
327
- }) })] }, i))), jsxRuntime.jsx("div", { className: VectorEditor_module.propRow, children: jsxRuntime.jsx(ui.NiceButton, { variant: "ghost", size: "sm", onClick: () => {
328
- const last = selAnim.keyframes[selAnim.keyframes.length - 1];
329
- const prev = selAnim.keyframes[selAnim.keyframes.length - 2];
330
- const newT = prev ? (prev.t + last.t) / 2 : Math.min(1, last.t + 0.1);
331
- const nextKfs = [...selAnim.keyframes, { ...last, t: newT }].sort((a, b) => a.t - b.t);
332
- setShapeAnimation(selId, { ...selAnim, keyframes: nextKfs });
333
- }, children: t('vectorEditor.timeline.addKeyframe', '+ Add keyframe') }) })] }))] }))] }), jsxRuntime.jsxs("div", { className: VectorEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: VectorEditor_module.panelTitle, children: jsxRuntime.jsx("span", { children: t('vectorEditor.timeline.playbackTitle', 'Playback') }) }), jsxRuntime.jsxs("div", { className: VectorEditor_module.propRow, children: [jsxRuntime.jsxs(ui.NiceButton, { variant: isPlaying ? 'primary' : 'ghost', size: "sm", onClick: () => {
334
- if (isPlaying) {
335
- setIsPlaying(false);
336
- }
337
- else {
338
- setPreviewTime(0);
339
- setIsPlaying(true);
340
- }
341
- }, disabled: animationCount === 0, children: [jsxRuntime.jsx(uiCore.NiceIcon, { name: isPlaying ? 'pause' : 'play', size: 14 }), ' ', isPlaying
342
- ? t('vectorEditor.timeline.pauseLabel', 'Pause')
343
- : t('vectorEditor.timeline.playLabel', 'Play')] }), jsxRuntime.jsxs(ui.NiceButton, { variant: "ghost", size: "sm", onClick: () => {
344
- setIsPlaying(false);
345
- setPreviewTime(0);
346
- }, children: [jsxRuntime.jsx(uiCore.NiceIcon, { name: "stop", size: 14 }), " ", t('vectorEditor.timeline.stopLabel', 'Stop')] })] }), animationCount > 0 && (jsxRuntime.jsx("div", { className: VectorEditor_module.propRow, children: jsxRuntime.jsxs(ui.NiceButton, { variant: "ghost", size: "sm", onClick: () => {
347
- const lines = [];
348
- for (const [shapeId, a] of Object.entries(animations)) {
349
- const name = `anim-${shapeId}`;
350
- lines.push(vectorAnimation.animationToCSSKeyframes(name, a));
351
- lines.push(vectorAnimation.animationToCSSRule(`[data-shape="${shapeId}"]`, name, a));
352
- }
353
- const css = lines.join('\n\n');
354
- if (typeof navigator !== 'undefined' && navigator.clipboard) {
355
- navigator.clipboard.writeText(css).catch(() => { });
356
- }
357
- }, children: [jsxRuntime.jsx(uiCore.NiceIcon, { name: "clipboard", size: 14 }), ' ', t('vectorEditor.timeline.copyCssKeyframes', 'Copy CSS keyframes')] }) }))] })] }));
358
- const tabs = [
93
+ )
94
+ ] })
95
+ ] }),
96
+ fillMode === "solid" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
97
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel }),
98
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.propColorSwatch, style: { background: fillCol }, children: /* @__PURE__ */ jsxRuntime.jsx(
99
+ ui.NiceColorPicker,
100
+ {
101
+ value: fillCol,
102
+ showInput: false,
103
+ showRandom: false,
104
+ onChange: (c) => {
105
+ setFillCol(c);
106
+ updateSel({ fill: c });
107
+ }
108
+ }
109
+ ) }),
110
+ /* @__PURE__ */ jsxRuntime.jsx(
111
+ ui.NiceTextInput,
112
+ {
113
+ className: VectorEditor_module.default.propInput,
114
+ value: selShape?.fill || fillCol,
115
+ onChange: (val) => {
116
+ setFillCol(val);
117
+ updateSel({ fill: val });
118
+ }
119
+ }
120
+ )
121
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
122
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.propRow, style: { flexWrap: "wrap", gap: 4 }, children: vectorGradients.PRESET_GRADIENTS.map((grad, i) => /* @__PURE__ */ jsxRuntime.jsx(
123
+ "div",
124
+ {
125
+ role: "button",
126
+ tabIndex: 0,
127
+ onKeyDown: uiCore.clickOnActivationKey,
128
+ style: {
129
+ width: 24,
130
+ height: 24,
131
+ borderRadius: 4,
132
+ background: vectorGradients.gradientToCSS(grad),
133
+ cursor: "pointer",
134
+ border: selectedGradient?.id === grad.id ? "2px solid var(--nice-bg, #FFF)" : "1px solid var(--nice-border-color, #444)"
135
+ },
136
+ onClick: () => applyGradient(grad),
137
+ title: t("vectorEditor.gradient", "{type} gradient").replace(
138
+ "{type}",
139
+ String(grad.type)
140
+ )
141
+ },
142
+ i
143
+ )) }),
144
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.propRow, children: /* @__PURE__ */ jsxRuntime.jsxs(
145
+ ui.NiceButton,
146
+ {
147
+ className: VectorEditor_module.default.menuBtn,
148
+ variant: "ghost",
149
+ size: "sm",
150
+ style: { width: "100%", fontSize: 10 },
151
+ onClick: () => setShowGradientEditor(!showGradientEditor),
152
+ children: [
153
+ /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: showGradientEditor ? "chevron-down" : "chevron-right", size: 14 }),
154
+ " ",
155
+ showGradientEditor ? t("vectorEditor.properties.hideEditor", "Hide Editor") : t("vectorEditor.properties.editGradient", "Edit Gradient")
156
+ ]
157
+ }
158
+ ) }),
159
+ showGradientEditor && selectedGradient && /* @__PURE__ */ jsxRuntime.jsxs(
160
+ "div",
161
+ {
162
+ style: {
163
+ padding: 4,
164
+ background: "var(--nice-bg-secondary, #252525)",
165
+ borderRadius: 4,
166
+ margin: "4px 0"
167
+ },
168
+ children: [
169
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
170
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.type", "Type") }),
171
+ /* @__PURE__ */ jsxRuntime.jsx(
172
+ ui.NiceSelect,
173
+ {
174
+ className: VectorEditor_module.default.propInput,
175
+ value: selectedGradient.type,
176
+ onChange: (val) => {
177
+ const type = val;
178
+ let newGrad;
179
+ if (type === "linear") {
180
+ newGrad = {
181
+ type: "linear",
182
+ id: vectorGradients.gradientId(),
183
+ angle: 0,
184
+ stops: selectedGradient.stops
185
+ };
186
+ } else {
187
+ newGrad = {
188
+ type: "radial",
189
+ id: vectorGradients.gradientId(),
190
+ cx: 0.5,
191
+ cy: 0.5,
192
+ r: 0.7,
193
+ stops: selectedGradient.stops
194
+ };
195
+ }
196
+ setSelectedGradient(newGrad);
197
+ updateSel({ fill: `url(#${newGrad.id})` });
198
+ },
199
+ options: [
200
+ { value: "linear", label: t("vectorEditor.properties.linear", "Linear") },
201
+ { value: "radial", label: t("vectorEditor.properties.radial", "Radial") }
202
+ ]
203
+ }
204
+ )
205
+ ] }),
206
+ selectedGradient.type === "linear" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
207
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.angle", "Angle") }),
208
+ /* @__PURE__ */ jsxRuntime.jsx(
209
+ ui.NiceSlider,
210
+ {
211
+ className: VectorEditor_module.default.propInput,
212
+ min: 0,
213
+ max: 360,
214
+ value: selectedGradient.angle,
215
+ onChange: (val) => {
216
+ const newGrad = {
217
+ ...selectedGradient,
218
+ id: vectorGradients.gradientId(),
219
+ angle: val
220
+ };
221
+ setSelectedGradient(newGrad);
222
+ updateSel({ fill: `url(#${newGrad.id})` });
223
+ }
224
+ }
225
+ ),
226
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 10, minWidth: 28 }, children: [
227
+ selectedGradient.angle,
228
+ "°"
229
+ ] })
230
+ ] }),
231
+ selectedGradient.type === "radial" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
232
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
233
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.cx", "CX") }),
234
+ /* @__PURE__ */ jsxRuntime.jsx(
235
+ ui.NiceSlider,
236
+ {
237
+ className: VectorEditor_module.default.propInput,
238
+ min: 0,
239
+ max: 100,
240
+ value: selectedGradient.cx * 100,
241
+ onChange: (val) => {
242
+ const newGrad = {
243
+ ...selectedGradient,
244
+ id: vectorGradients.gradientId(),
245
+ cx: val / 100
246
+ };
247
+ setSelectedGradient(newGrad);
248
+ updateSel({ fill: `url(#${newGrad.id})` });
249
+ }
250
+ }
251
+ )
252
+ ] }),
253
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
254
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.cy", "CY") }),
255
+ /* @__PURE__ */ jsxRuntime.jsx(
256
+ ui.NiceSlider,
257
+ {
258
+ className: VectorEditor_module.default.propInput,
259
+ min: 0,
260
+ max: 100,
261
+ value: selectedGradient.cy * 100,
262
+ onChange: (val) => {
263
+ const newGrad = {
264
+ ...selectedGradient,
265
+ id: vectorGradients.gradientId(),
266
+ cy: val / 100
267
+ };
268
+ setSelectedGradient(newGrad);
269
+ updateSel({ fill: `url(#${newGrad.id})` });
270
+ }
271
+ }
272
+ )
273
+ ] }),
274
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
275
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.r", "R") }),
276
+ /* @__PURE__ */ jsxRuntime.jsx(
277
+ ui.NiceSlider,
278
+ {
279
+ className: VectorEditor_module.default.propInput,
280
+ min: 10,
281
+ max: 100,
282
+ value: selectedGradient.r * 100,
283
+ onChange: (val) => {
284
+ const newGrad = {
285
+ ...selectedGradient,
286
+ id: vectorGradients.gradientId(),
287
+ r: val / 100
288
+ };
289
+ setSelectedGradient(newGrad);
290
+ updateSel({ fill: `url(#${newGrad.id})` });
291
+ }
292
+ }
293
+ )
294
+ ] })
295
+ ] }),
296
+ /* @__PURE__ */ jsxRuntime.jsx(
297
+ "div",
298
+ {
299
+ style: { fontSize: 10, color: "var(--nice-text-secondary, #888)", marginTop: 4 },
300
+ children: t("vectorEditor.properties.colorStops", "Color Stops:")
301
+ }
302
+ ),
303
+ selectedGradient.stops.map((stop, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
304
+ /* @__PURE__ */ jsxRuntime.jsx(
305
+ ui.NiceColorPicker,
306
+ {
307
+ value: stop.color,
308
+ showInput: false,
309
+ showRandom: false,
310
+ style: { width: 24, height: 20 },
311
+ onChange: (color) => {
312
+ const newStops = [...selectedGradient.stops];
313
+ newStops[i] = { ...newStops[i], color };
314
+ const newGrad = { ...selectedGradient, id: vectorGradients.gradientId(), stops: newStops };
315
+ setSelectedGradient(newGrad);
316
+ updateSel({ fill: `url(#${newGrad.id})` });
317
+ }
318
+ }
319
+ ),
320
+ /* @__PURE__ */ jsxRuntime.jsx(
321
+ ui.NiceSlider,
322
+ {
323
+ min: 0,
324
+ max: 100,
325
+ value: stop.offset * 100,
326
+ style: { flex: 1 },
327
+ onChange: (val) => {
328
+ const newStops = [...selectedGradient.stops];
329
+ newStops[i] = { ...newStops[i], offset: val / 100 };
330
+ newStops.sort((a, b) => a.offset - b.offset);
331
+ const newGrad = { ...selectedGradient, id: vectorGradients.gradientId(), stops: newStops };
332
+ setSelectedGradient(newGrad);
333
+ updateSel({ fill: `url(#${newGrad.id})` });
334
+ }
335
+ }
336
+ ),
337
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 9, minWidth: 24 }, children: [
338
+ Math.round(stop.offset * 100),
339
+ "%"
340
+ ] })
341
+ ] }, i)),
342
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, style: { gap: 4 }, children: [
343
+ /* @__PURE__ */ jsxRuntime.jsx(
344
+ ui.NiceButton,
345
+ {
346
+ className: VectorEditor_module.default.menuBtn,
347
+ variant: "ghost",
348
+ size: "sm",
349
+ style: { fontSize: 10, flex: 1 },
350
+ onClick: () => {
351
+ const newStops = [
352
+ ...selectedGradient.stops,
353
+ { offset: 0.5, color: "var(--nice-text-secondary, #888888)" }
354
+ ];
355
+ newStops.sort((a, b) => a.offset - b.offset);
356
+ const newGrad = { ...selectedGradient, id: vectorGradients.gradientId(), stops: newStops };
357
+ setSelectedGradient(newGrad);
358
+ updateSel({ fill: `url(#${newGrad.id})` });
359
+ },
360
+ children: t("vectorEditor.properties.addStop", "+ Add Stop")
361
+ }
362
+ ),
363
+ /* @__PURE__ */ jsxRuntime.jsx(
364
+ ui.NiceButton,
365
+ {
366
+ className: VectorEditor_module.default.menuBtn,
367
+ variant: "ghost",
368
+ size: "sm",
369
+ style: { fontSize: 10, flex: 1 },
370
+ disabled: selectedGradient.stops.length <= 2,
371
+ onClick: () => {
372
+ if (selectedGradient.stops.length <= 2) {
373
+ return;
374
+ }
375
+ const newStops = selectedGradient.stops.slice(0, -1);
376
+ const newGrad = { ...selectedGradient, id: vectorGradients.gradientId(), stops: newStops };
377
+ setSelectedGradient(newGrad);
378
+ updateSel({ fill: `url(#${newGrad.id})` });
379
+ },
380
+ children: t("vectorEditor.properties.removeStop", "- Remove")
381
+ }
382
+ )
383
+ ] })
384
+ ]
385
+ }
386
+ )
387
+ ] }),
388
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
389
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.stroke", "Stroke") }),
390
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.propColorSwatch, style: { background: strokeCol }, children: /* @__PURE__ */ jsxRuntime.jsx(
391
+ ui.NiceColorPicker,
392
+ {
393
+ value: strokeCol,
394
+ showInput: false,
395
+ showRandom: false,
396
+ onChange: (c) => {
397
+ setStrokeCol(c);
398
+ updateSel({ stroke: c });
399
+ }
400
+ }
401
+ ) }),
402
+ /* @__PURE__ */ jsxRuntime.jsx(
403
+ ui.NiceTextInput,
404
+ {
405
+ className: VectorEditor_module.default.propInput,
406
+ value: selShape?.stroke || strokeCol,
407
+ onChange: (val) => {
408
+ setStrokeCol(val);
409
+ updateSel({ stroke: val });
410
+ }
411
+ }
412
+ )
413
+ ] }),
414
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
415
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.width", "Width") }),
416
+ /* @__PURE__ */ jsxRuntime.jsx(
417
+ ui.NiceNumberInput,
418
+ {
419
+ className: VectorEditor_module.default.propInput,
420
+ min: 0,
421
+ max: 100,
422
+ value: selShape?.strokeWidth ?? strokeW,
423
+ onChange: (val) => {
424
+ const v = val ?? 0;
425
+ setStrokeW(v);
426
+ updateSel({ strokeWidth: v });
427
+ }
428
+ }
429
+ )
430
+ ] }),
431
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
432
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.opacity", "Opacity") }),
433
+ /* @__PURE__ */ jsxRuntime.jsx(
434
+ ui.NiceSlider,
435
+ {
436
+ className: VectorEditor_module.default.propInput,
437
+ min: 0,
438
+ max: 1,
439
+ step: 0.01,
440
+ value: selShape?.opacity ?? shapeOpacity,
441
+ onChange: (val) => {
442
+ setShapeOpacity(val);
443
+ updateSel({ opacity: val });
444
+ }
445
+ }
446
+ ),
447
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 10, minWidth: 28 }, children: [
448
+ Math.round((selShape?.opacity ?? shapeOpacity) * 100),
449
+ "%"
450
+ ] })
451
+ ] }),
452
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
453
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.rotation", "Rotation") }),
454
+ /* @__PURE__ */ jsxRuntime.jsx(
455
+ ui.NiceNumberInput,
456
+ {
457
+ className: VectorEditor_module.default.propInput,
458
+ min: -360,
459
+ max: 360,
460
+ value: selShape?.rotation ?? 0,
461
+ onChange: (val) => updateSel({ rotation: val ?? 0 })
462
+ }
463
+ ),
464
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 10 }, children: "°" })
465
+ ] })
466
+ ] }),
467
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.panelSection, children: [
468
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.panelTitle, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("vectorEditor.properties.toolOptions", "Tool Options") }) }),
469
+ (tool === "roundrect" || selShape?.type === "roundrect") && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
470
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.radius", "Radius") }),
471
+ /* @__PURE__ */ jsxRuntime.jsx(
472
+ ui.NiceNumberInput,
473
+ {
474
+ className: VectorEditor_module.default.propInput,
475
+ min: 0,
476
+ max: 200,
477
+ value: selShape?.rx ?? cornerRadius,
478
+ onChange: (val) => {
479
+ const v = val ?? 0;
480
+ setCornerRadius(v);
481
+ updateSel({ rx: v });
482
+ }
483
+ }
484
+ )
485
+ ] }),
486
+ (tool === "polygon" || selShape?.type === "polygon") && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
487
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.sides", "Sides") }),
488
+ /* @__PURE__ */ jsxRuntime.jsx(
489
+ ui.NiceNumberInput,
490
+ {
491
+ className: VectorEditor_module.default.propInput,
492
+ min: 3,
493
+ max: 32,
494
+ value: selShape?.sides ?? polygonSides,
495
+ onChange: (val) => {
496
+ const v = val ?? 3;
497
+ setPolygonSides(v);
498
+ updateSel({ sides: v });
499
+ }
500
+ }
501
+ )
502
+ ] }),
503
+ (tool === "star" || selShape?.type === "star") && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
504
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
505
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.points", "Points") }),
506
+ /* @__PURE__ */ jsxRuntime.jsx(
507
+ ui.NiceNumberInput,
508
+ {
509
+ className: VectorEditor_module.default.propInput,
510
+ min: 3,
511
+ max: 32,
512
+ value: selShape?.sides ?? starPoints2,
513
+ onChange: (val) => {
514
+ const v = val ?? 3;
515
+ setStarPoints2(v);
516
+ updateSel({ sides: v });
517
+ }
518
+ }
519
+ )
520
+ ] }),
521
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
522
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.innerR", "Inner R") }),
523
+ /* @__PURE__ */ jsxRuntime.jsx(
524
+ ui.NiceSlider,
525
+ {
526
+ className: VectorEditor_module.default.propInput,
527
+ min: 0.1,
528
+ max: 0.9,
529
+ step: 0.05,
530
+ value: selShape?.innerRadius ?? starInnerRatio,
531
+ onChange: (val) => {
532
+ setStarInnerRatio(val);
533
+ updateSel({ innerRadius: val });
534
+ }
535
+ }
536
+ ),
537
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 10 }, children: [
538
+ Math.round((selShape?.innerRadius ?? starInnerRatio) * 100),
539
+ "%"
540
+ ] })
541
+ ] })
542
+ ] }),
543
+ (tool === "text" || selShape?.type === "text") && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
544
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
545
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.size", "Size") }),
546
+ /* @__PURE__ */ jsxRuntime.jsx(
547
+ ui.NiceNumberInput,
548
+ {
549
+ className: VectorEditor_module.default.propInput,
550
+ min: 8,
551
+ max: 200,
552
+ value: selShape?.fontSize ?? fontSize,
553
+ onChange: (val) => {
554
+ const v = val ?? 12;
555
+ setFontSize(v);
556
+ updateSel({ fontSize: v });
557
+ }
558
+ }
559
+ )
560
+ ] }),
561
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
562
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.font", "Font") }),
563
+ /* @__PURE__ */ jsxRuntime.jsx(
564
+ ui.NiceSelect,
565
+ {
566
+ className: VectorEditor_module.default.propInput,
567
+ value: selShape?.fontFamily ?? fontFamily,
568
+ onChange: (val) => {
569
+ setFontFamily(val);
570
+ updateSel({ fontFamily: val });
571
+ },
572
+ options: vectorEditorTypes.FONTS.map((f) => ({ value: f, label: f }))
573
+ }
574
+ )
575
+ ] })
576
+ ] }),
577
+ snapGrid && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
578
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.grid", "Grid") }),
579
+ /* @__PURE__ */ jsxRuntime.jsx(
580
+ ui.NiceNumberInput,
581
+ {
582
+ className: VectorEditor_module.default.propInput,
583
+ min: 4,
584
+ max: 128,
585
+ value: gridSize,
586
+ onChange: (val) => setGridSize(val ?? 8)
587
+ }
588
+ )
589
+ ] })
590
+ ] }),
591
+ selShape && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.panelSection, children: [
592
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.panelTitle, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("vectorEditor.properties.transform", "Transform") }) }),
593
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
594
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.x", "X") }),
595
+ /* @__PURE__ */ jsxRuntime.jsx(
596
+ ui.NiceNumberInput,
597
+ {
598
+ className: VectorEditor_module.default.propInput,
599
+ value: Math.round(selShape.x),
600
+ onChange: (val) => updateSel({ x: val ?? 0 })
601
+ }
602
+ )
603
+ ] }),
604
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
605
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.y", "Y") }),
606
+ /* @__PURE__ */ jsxRuntime.jsx(
607
+ ui.NiceNumberInput,
608
+ {
609
+ className: VectorEditor_module.default.propInput,
610
+ value: Math.round(selShape.y),
611
+ onChange: (val) => updateSel({ y: val ?? 0 })
612
+ }
613
+ )
614
+ ] }),
615
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
616
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.w", "W") }),
617
+ /* @__PURE__ */ jsxRuntime.jsx(
618
+ ui.NiceNumberInput,
619
+ {
620
+ className: VectorEditor_module.default.propInput,
621
+ value: Math.round(selShape.w),
622
+ onChange: (val) => updateSel({ w: val ?? 0 })
623
+ }
624
+ )
625
+ ] }),
626
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
627
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.properties.h", "H") }),
628
+ /* @__PURE__ */ jsxRuntime.jsx(
629
+ ui.NiceNumberInput,
630
+ {
631
+ className: VectorEditor_module.default.propInput,
632
+ value: Math.round(selShape.h),
633
+ onChange: (val) => updateSel({ h: val ?? 0 })
634
+ }
635
+ )
636
+ ] })
637
+ ] })
638
+ ] });
639
+ const insertIcon = (Icon, badge) => {
640
+ if (badge) {
641
+ const box = Math.round(Math.min(artW, artH) * 0.42);
642
+ const made = vectorIconImport.iconComponentToShapes(Icon, { artW: box, artH: box, margin: 4 });
643
+ if (made.length === 0) {
644
+ return;
645
+ }
646
+ const dx = artW - box;
647
+ const offset = made.map((s) => ({
648
+ ...s,
649
+ x: s.x + dx,
650
+ ...s.x2 != null ? { x2: s.x2 + dx } : {},
651
+ ...s.points ? { points: s.points.map((p) => ({ ...p, x: p.x + dx })) } : {}
652
+ }));
653
+ const next2 = [...shapes, ...offset];
654
+ setShapes(next2);
655
+ snap(next2);
656
+ if (offset[0]?.id) {
657
+ setSelId(offset[0].id);
658
+ }
659
+ setTool("pointer");
660
+ return;
661
+ }
662
+ const inserted = vectorIconImport.iconComponentToShapes(Icon, { artW, artH });
663
+ if (inserted.length === 0) {
664
+ return;
665
+ }
666
+ const next = [...shapes, ...inserted];
667
+ setShapes(next);
668
+ snap(next);
669
+ if (inserted[0]?.id) {
670
+ setSelId(inserted[0].id);
671
+ }
672
+ setTool("pointer");
673
+ };
674
+ const reorderShape = (id, dir) => {
675
+ const idx = shapes.findIndex((s) => s.id === id);
676
+ if (idx < 0) {
677
+ return;
678
+ }
679
+ const next = shapes.slice();
680
+ const target = idx + dir;
681
+ if (target < 0 || target >= next.length) {
682
+ return;
683
+ }
684
+ [next[idx], next[target]] = [next[target], next[idx]];
685
+ setShapes(next);
686
+ snap(next);
687
+ };
688
+ const layersContent = /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.rightPanelTabBody, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.panelSection, children: [
689
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.panelTitle, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
690
+ t("vectorEditor.layers.title", "Layers"),
691
+ " (",
692
+ shapes.length,
693
+ ")"
694
+ ] }) }),
695
+ [...shapes].reverse().map((s, revIdx) => {
696
+ const realIdx = shapes.length - 1 - revIdx;
697
+ const active = s.id === selId;
698
+ return /* @__PURE__ */ jsxRuntime.jsxs(
699
+ "div",
359
700
  {
360
- id: 'properties',
361
- label: t('vectorEditor.tabs.properties', 'Properties'),
362
- content: propertiesContent,
701
+ role: "button",
702
+ tabIndex: 0,
703
+ onKeyDown: uiCore.clickOnActivationKey,
704
+ className: `${VectorEditor_module.default.layerRow} ${active ? VectorEditor_module.default.layerRowActive : ""} ${s.locked ? VectorEditor_module.default.layerRowLocked : ""}`,
705
+ onClick: () => {
706
+ setSelId(s.id);
707
+ setTool("pointer");
708
+ },
709
+ children: [
710
+ /* @__PURE__ */ jsxRuntime.jsx(
711
+ "button",
712
+ {
713
+ type: "button",
714
+ className: VectorEditor_module.default.layerIconBtn,
715
+ title: s.hidden ? t("vectorEditor.layers.show", "Show") : t("vectorEditor.layers.hide", "Hide"),
716
+ onClick: (e) => {
717
+ e.stopPropagation();
718
+ const next = shapes.map((x) => x.id === s.id ? { ...x, hidden: !x.hidden } : x);
719
+ setShapes(next);
720
+ snap(next);
721
+ },
722
+ children: /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: s.hidden ? "eye-off" : "eye", size: 14 })
723
+ }
724
+ ),
725
+ /* @__PURE__ */ jsxRuntime.jsx(
726
+ "button",
727
+ {
728
+ type: "button",
729
+ className: VectorEditor_module.default.layerIconBtn,
730
+ title: s.locked ? t("vectorEditor.layers.unlock", "Unlock") : t("vectorEditor.layers.lock", "Lock"),
731
+ onClick: (e) => {
732
+ e.stopPropagation();
733
+ const next = shapes.map((x) => x.id === s.id ? { ...x, locked: !x.locked } : x);
734
+ setShapes(next);
735
+ snap(next);
736
+ },
737
+ children: /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: "lock", size: 14, style: { opacity: s.locked ? 1 : 0.4 } })
738
+ }
739
+ ),
740
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.shapeIcon, children: /* @__PURE__ */ jsxRuntime.jsx(
741
+ uiCore.NiceIcon,
742
+ {
743
+ name: s.type === "rect" || s.type === "roundrect" ? "square" : s.type === "ellipse" ? "circle" : s.type === "line" ? "line" : s.type === "arrow" ? "arrow-right" : s.type === "polygon" ? "hexagon" : s.type === "star" ? "star" : s.type === "polyline" ? "pen" : s.type === "path" ? "wand" : "type",
744
+ size: 14
745
+ }
746
+ ) }),
747
+ /* @__PURE__ */ jsxRuntime.jsx(
748
+ "input",
749
+ {
750
+ className: VectorEditor_module.default.layerNameInput,
751
+ value: s.name ?? s.type,
752
+ disabled: s.locked,
753
+ onClick: (e) => e.stopPropagation(),
754
+ onChange: (e) => {
755
+ const v = e.target.value;
756
+ const next = shapes.map((x) => x.id === s.id ? { ...x, name: v } : x);
757
+ setShapes(next);
758
+ },
759
+ onBlur: () => snap(shapes)
760
+ }
761
+ ),
762
+ /* @__PURE__ */ jsxRuntime.jsx(
763
+ "button",
764
+ {
765
+ type: "button",
766
+ className: VectorEditor_module.default.layerIconBtn,
767
+ title: t("vectorEditor.layers.moveUp", "Move up"),
768
+ onClick: (e) => {
769
+ e.stopPropagation();
770
+ reorderShape(s.id, 1);
771
+ },
772
+ disabled: realIdx === shapes.length - 1,
773
+ children: /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: "arrow-up", size: 14 })
774
+ }
775
+ ),
776
+ /* @__PURE__ */ jsxRuntime.jsx(
777
+ "button",
778
+ {
779
+ type: "button",
780
+ className: VectorEditor_module.default.layerIconBtn,
781
+ title: t("vectorEditor.layers.moveDown", "Move down"),
782
+ onClick: (e) => {
783
+ e.stopPropagation();
784
+ reorderShape(s.id, -1);
785
+ },
786
+ disabled: realIdx === 0,
787
+ children: /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: "arrow-down", size: 14 })
788
+ }
789
+ )
790
+ ]
363
791
  },
792
+ s.id
793
+ );
794
+ }),
795
+ shapes.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "var(--nice-text-secondary)", fontSize: 11, padding: 4 }, children: t(
796
+ "vectorEditor.layers.empty",
797
+ "No layers yet. Use the tools to draw, or insert from the Library tab."
798
+ ) })
799
+ ] }) });
800
+ const libraryContent = /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.rightPanelTabBody, children: library && library.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
801
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.propRow, style: { padding: "4px 0" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
802
+ ui.NiceButton,
803
+ {
804
+ className: `${VectorEditor_module.default.menuBtn} ${asBadge ? VectorEditor_module.default.menuBtnActive : ""}`,
805
+ variant: asBadge ? "primary" : "ghost",
806
+ size: "sm",
807
+ style: { width: "100%", fontSize: 11 },
808
+ onClick: () => setAsBadge((v) => !v),
809
+ "aria-pressed": asBadge,
810
+ children: [
811
+ asBadge && /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: "plus", size: 14 }),
812
+ " ",
813
+ asBadge ? t("vectorEditor.library.insertAsBadgeOn", "Inserting as corner badge") : t("vectorEditor.library.insertAsBadge", "Insert as corner badge")
814
+ ]
815
+ }
816
+ ) }),
817
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.libraryGrid, children: library.map((entry) => {
818
+ const Icon = entry.Component;
819
+ return /* @__PURE__ */ jsxRuntime.jsxs(
820
+ "button",
364
821
  {
365
- id: 'layers',
366
- label: `${t('vectorEditor.tabs.layers', 'Layers')} (${shapes.length})`,
367
- content: layersContent,
822
+ type: "button",
823
+ className: VectorEditor_module.default.libraryCell,
824
+ title: entry.name,
825
+ onClick: () => insertIcon(Icon, asBadge),
826
+ children: [
827
+ /* @__PURE__ */ jsxRuntime.jsx(
828
+ "div",
829
+ {
830
+ style: {
831
+ width: 28,
832
+ height: 28,
833
+ display: "flex",
834
+ alignItems: "center",
835
+ justifyContent: "center"
836
+ },
837
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "md" })
838
+ }
839
+ ),
840
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: entry.name })
841
+ ]
368
842
  },
369
- { id: 'library', label: t('vectorEditor.tabs.library', 'Library'), content: libraryContent },
843
+ entry.name
844
+ );
845
+ }) })
846
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "var(--nice-text-secondary)", fontSize: 11, padding: 12 }, children: t(
847
+ "vectorEditor.library.passProp",
848
+ "Pass a library prop to NiceVectorEditor to populate this tab with insertable icons."
849
+ ) }) });
850
+ const selAnim = selId ? animations[selId] : void 0;
851
+ const animationCount = Object.keys(animations).length;
852
+ const timelineContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.rightPanelTabBody, children: [
853
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.panelSection, children: [
854
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.panelTitle, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("vectorEditor.timeline.animationTitle", "Animation") }) }),
855
+ !selId ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "var(--nice-text-secondary)", fontSize: 11, padding: 4 }, children: t("vectorEditor.timeline.attachHint", "Select a shape to attach an animation.") }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
856
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
857
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.timeline.preset", "Preset") }),
858
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: Object.keys(vectorAnimation.ANIMATION_PRESETS).map((key) => /* @__PURE__ */ jsxRuntime.jsx(
859
+ ui.NiceButton,
860
+ {
861
+ variant: "ghost",
862
+ size: "sm",
863
+ onClick: () => setShapeAnimation(selId, vectorAnimation.ANIMATION_PRESETS[key]),
864
+ children: key
865
+ },
866
+ key
867
+ )) })
868
+ ] }),
869
+ selAnim && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
870
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
871
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.timeline.duration", "Duration (ms)") }),
872
+ /* @__PURE__ */ jsxRuntime.jsx(
873
+ ui.NiceNumberInput,
874
+ {
875
+ value: selAnim.duration,
876
+ min: 100,
877
+ max: 1e4,
878
+ step: 100,
879
+ onChange: (v) => setShapeAnimation(selId, {
880
+ ...selAnim,
881
+ duration: Number(v) || selAnim.duration
882
+ })
883
+ }
884
+ )
885
+ ] }),
886
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
887
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.timeline.repeat", "Repeat") }),
888
+ /* @__PURE__ */ jsxRuntime.jsx(
889
+ ui.NiceSelect,
890
+ {
891
+ value: selAnim.repeat === "infinite" ? "infinite" : String(selAnim.repeat),
892
+ onChange: (v) => setShapeAnimation(selId, {
893
+ ...selAnim,
894
+ repeat: v === "infinite" ? "infinite" : Number(v)
895
+ }),
896
+ options: [
897
+ { value: "infinite", label: "infinite" },
898
+ { value: "1", label: "1x" },
899
+ { value: "2", label: "2x" },
900
+ { value: "3", label: "3x" },
901
+ { value: "5", label: "5x" }
902
+ ]
903
+ }
904
+ )
905
+ ] }),
906
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
907
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, children: t("vectorEditor.timeline.direction", "Direction") }),
908
+ /* @__PURE__ */ jsxRuntime.jsx(
909
+ ui.NiceSelect,
910
+ {
911
+ value: selAnim.direction,
912
+ onChange: (v) => setShapeAnimation(selId, {
913
+ ...selAnim,
914
+ direction: v
915
+ }),
916
+ options: [
917
+ { value: "normal", label: "normal" },
918
+ { value: "alternate", label: "alternate" }
919
+ ]
920
+ }
921
+ )
922
+ ] }),
923
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.propRow, children: /* @__PURE__ */ jsxRuntime.jsx(
924
+ ui.NiceButton,
925
+ {
926
+ variant: "ghost",
927
+ size: "sm",
928
+ onClick: () => setShapeAnimation(selId, null),
929
+ children: t("vectorEditor.timeline.remove", "Remove animation")
930
+ }
931
+ ) }),
932
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.panelTitle, style: { marginTop: 8 }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("vectorEditor.timeline.keyframes", "Keyframes") }) }),
933
+ selAnim.keyframes.map((k, i) => /* @__PURE__ */ jsxRuntime.jsxs(
934
+ "div",
935
+ {
936
+ className: VectorEditor_module.default.propRow,
937
+ style: { flexDirection: "column", alignItems: "stretch", gap: 2 },
938
+ children: [
939
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
940
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: VectorEditor_module.default.propLabel, style: { minWidth: 24 }, children: t("vectorEditor.timeline.tLabel", "t") }),
941
+ /* @__PURE__ */ jsxRuntime.jsx(
942
+ ui.NiceSlider,
943
+ {
944
+ value: k.t,
945
+ min: 0,
946
+ max: 1,
947
+ step: 0.01,
948
+ onChange: (v) => {
949
+ const nextKfs = selAnim.keyframes.map(
950
+ (kf, j) => j === i ? { ...kf, t: Number(v) } : kf
951
+ );
952
+ nextKfs.sort((a, b) => a.t - b.t);
953
+ setShapeAnimation(selId, { ...selAnim, keyframes: nextKfs });
954
+ }
955
+ }
956
+ ),
957
+ /* @__PURE__ */ jsxRuntime.jsx(
958
+ ui.NiceButton,
959
+ {
960
+ variant: "ghost",
961
+ size: "sm",
962
+ disabled: selAnim.keyframes.length <= 2,
963
+ onClick: () => {
964
+ const nextKfs = selAnim.keyframes.filter((_, j) => j !== i);
965
+ setShapeAnimation(selId, { ...selAnim, keyframes: nextKfs });
966
+ },
967
+ "aria-label": t("vectorEditor.timeline.removeKeyframe", "Remove keyframe"),
968
+ children: /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: "trash", size: 14 })
969
+ }
970
+ )
971
+ ] }),
972
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 2 }, children: ["rotate", "scale", "translateX", "translateY", "opacity"].map(
973
+ (field) => /* @__PURE__ */ jsxRuntime.jsx(
974
+ ui.NiceNumberInput,
975
+ {
976
+ value: k[field] ?? 0,
977
+ step: field === "scale" || field === "opacity" ? 0.1 : 1,
978
+ placeholder: field[0].toUpperCase(),
979
+ onChange: (v) => {
980
+ const num = v == null ? void 0 : Number(v);
981
+ const nextKfs = selAnim.keyframes.map(
982
+ (kf, j) => j === i ? { ...kf, [field]: num } : kf
983
+ );
984
+ setShapeAnimation(selId, { ...selAnim, keyframes: nextKfs });
985
+ }
986
+ },
987
+ field
988
+ )
989
+ ) })
990
+ ]
991
+ },
992
+ i
993
+ )),
994
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.propRow, children: /* @__PURE__ */ jsxRuntime.jsx(
995
+ ui.NiceButton,
996
+ {
997
+ variant: "ghost",
998
+ size: "sm",
999
+ onClick: () => {
1000
+ const last = selAnim.keyframes[selAnim.keyframes.length - 1];
1001
+ const prev = selAnim.keyframes[selAnim.keyframes.length - 2];
1002
+ const newT = prev ? (prev.t + last.t) / 2 : Math.min(1, last.t + 0.1);
1003
+ const nextKfs = [...selAnim.keyframes, { ...last, t: newT }].sort(
1004
+ (a, b) => a.t - b.t
1005
+ );
1006
+ setShapeAnimation(selId, { ...selAnim, keyframes: nextKfs });
1007
+ },
1008
+ children: t("vectorEditor.timeline.addKeyframe", "+ Add keyframe")
1009
+ }
1010
+ ) })
1011
+ ] })
1012
+ ] })
1013
+ ] }),
1014
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.panelSection, children: [
1015
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.panelTitle, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("vectorEditor.timeline.playbackTitle", "Playback") }) }),
1016
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: VectorEditor_module.default.propRow, children: [
1017
+ /* @__PURE__ */ jsxRuntime.jsxs(
1018
+ ui.NiceButton,
1019
+ {
1020
+ variant: isPlaying ? "primary" : "ghost",
1021
+ size: "sm",
1022
+ onClick: () => {
1023
+ if (isPlaying) {
1024
+ setIsPlaying(false);
1025
+ } else {
1026
+ setPreviewTime(0);
1027
+ setIsPlaying(true);
1028
+ }
1029
+ },
1030
+ disabled: animationCount === 0,
1031
+ children: [
1032
+ /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: isPlaying ? "pause" : "play", size: 14 }),
1033
+ " ",
1034
+ isPlaying ? t("vectorEditor.timeline.pauseLabel", "Pause") : t("vectorEditor.timeline.playLabel", "Play")
1035
+ ]
1036
+ }
1037
+ ),
1038
+ /* @__PURE__ */ jsxRuntime.jsxs(
1039
+ ui.NiceButton,
1040
+ {
1041
+ variant: "ghost",
1042
+ size: "sm",
1043
+ onClick: () => {
1044
+ setIsPlaying(false);
1045
+ setPreviewTime(0);
1046
+ },
1047
+ children: [
1048
+ /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: "stop", size: 14 }),
1049
+ " ",
1050
+ t("vectorEditor.timeline.stopLabel", "Stop")
1051
+ ]
1052
+ }
1053
+ )
1054
+ ] }),
1055
+ animationCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.propRow, children: /* @__PURE__ */ jsxRuntime.jsxs(
1056
+ ui.NiceButton,
370
1057
  {
371
- id: 'timeline',
372
- label: `${t('vectorEditor.tabs.timeline', 'Timeline')}${animationCount ? ` (${animationCount})` : ''}`,
373
- content: timelineContent,
374
- },
375
- ];
376
- return (jsxRuntime.jsx("div", { className: VectorEditor_module.rightPanel, children: jsxRuntime.jsx(ui.NiceTabs, { tabs: tabs, size: "sm" }) }));
1058
+ variant: "ghost",
1059
+ size: "sm",
1060
+ onClick: () => {
1061
+ const lines = [];
1062
+ for (const [shapeId, a] of Object.entries(animations)) {
1063
+ const name = `anim-${shapeId}`;
1064
+ lines.push(vectorAnimation.animationToCSSKeyframes(name, a));
1065
+ lines.push(vectorAnimation.animationToCSSRule(`[data-shape="${shapeId}"]`, name, a));
1066
+ }
1067
+ const css = lines.join("\n\n");
1068
+ if (typeof navigator !== "undefined" && navigator.clipboard) {
1069
+ navigator.clipboard.writeText(css).catch(() => {
1070
+ });
1071
+ }
1072
+ },
1073
+ children: [
1074
+ /* @__PURE__ */ jsxRuntime.jsx(uiCore.NiceIcon, { name: "clipboard", size: 14 }),
1075
+ " ",
1076
+ t("vectorEditor.timeline.copyCssKeyframes", "Copy CSS keyframes")
1077
+ ]
1078
+ }
1079
+ ) })
1080
+ ] })
1081
+ ] });
1082
+ const tabs = [
1083
+ {
1084
+ id: "properties",
1085
+ label: t("vectorEditor.tabs.properties", "Properties"),
1086
+ content: propertiesContent
1087
+ },
1088
+ {
1089
+ id: "layers",
1090
+ label: `${t("vectorEditor.tabs.layers", "Layers")} (${shapes.length})`,
1091
+ content: layersContent
1092
+ },
1093
+ { id: "library", label: t("vectorEditor.tabs.library", "Library"), content: libraryContent },
1094
+ {
1095
+ id: "timeline",
1096
+ label: `${t("vectorEditor.tabs.timeline", "Timeline")}${animationCount ? ` (${animationCount})` : ""}`,
1097
+ content: timelineContent
1098
+ }
1099
+ ];
1100
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: VectorEditor_module.default.rightPanel, children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceTabs, { tabs, size: "sm" }) });
377
1101
  };
378
- var VectorEditorRightPanel$1 = React.memo(VectorEditorRightPanel);
379
-
380
- module.exports = VectorEditorRightPanel$1;
1102
+ const VectorEditorRightPanel$1 = React.memo(VectorEditorRightPanel);
1103
+ exports.default = VectorEditorRightPanel$1;