@arbisoft/react-design-tool 1.0.56 → 1.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,19 +12,37 @@ With this tool, you can:
12
12
 
13
13
  Perfect for integrating into applications that require user-driven visual content creation.
14
14
 
15
+ ---
16
+
17
+ ## 🔔 What’s New
18
+
19
+ - **Auto-placement for QR ID**: When enabled, the QR ID text is **automatically positioned above the Location text** (`LOCATION_ELEMENT_ID`).
20
+ If the Location element doesn’t exist, it’s **centered on the canvas**.
21
+ - **Persistent QR ID across template switches**: If the QR ID was visible before switching templates, it stays visible and **reflows** for the new template.
22
+ - **No more “ghost selection”**: Selection is cleared when the selected element no longer exists after a template/elements change.
23
+ - **New imperative API**: `reflowQrId()` lets you programmatically re-snap the QR ID above Location (or center) at any time.
24
+
25
+ > **Heads up:** `qrIdText` **no longer controls placement**. Position is computed automatically from the Location element or canvas center. See the updated “QR ID Controls” section.
26
+
27
+ ---
28
+
15
29
  ## 🎬 Studio Preview
16
30
 
17
31
  **Live Walkthrough (GIF)**
18
32
 
19
33
  ![Studio Editor Screenshot](https://i.ibb.co/M5hZtFTG/design-tool.gif)
20
34
 
35
+ ---
36
+
21
37
  ## 🖥️ Demo
22
38
 
23
39
  Check out the live demo here:
24
40
 
25
41
  [![Live Demo](https://img.shields.io/badge/Live-Demo-blue?style=for-the-badge)](https://codesandbox.io/p/sandbox/fdftlr)
26
42
 
27
- ## 📦 Installation( react >= 19 )
43
+ ---
44
+
45
+ ## 📦 Installation (React ≥ 19)
28
46
 
29
47
  ```bash
30
48
  npm install @arbisoft/react-design-tool
@@ -40,13 +58,13 @@ yarn add @arbisoft/react-design-tool
40
58
  #### ⚠️ Important: Installation Guide for React 18 and Below
41
59
 
42
60
  ```bash
43
- npm install @arbisoft/react-design-tool@1.0.55
61
+ npm install @arbisoft/react-design-tool@1.0.60
44
62
  ```
45
63
 
46
64
  OR
47
65
 
48
66
  ```bash
49
- yarn add @arbisoft/react-design-tool@1.0.55
67
+ yarn add @arbisoft/react-design-tool@1.0.60
50
68
 
51
69
  ```
52
70
 
@@ -56,38 +74,45 @@ yarn add @arbisoft/react-design-tool@1.0.55
56
74
  import React, { useRef } from 'react';
57
75
  import { Studio } from '@arbisoft/react-design-tool';
58
76
 
59
- function MyComponent() {
60
- const studioRef = useRef(null);
61
-
62
- return (
63
- <Studio
64
- ref={studioRef}
65
- defaultTemplatesList={[]}
66
- customTemplatesList={[]}
67
- defaultImages={[]}
68
- customImages={[]}
69
- uploadImageCallBack={async file => {
70
- // Upload logic here
71
- return 'url_of_uploaded_image';
72
- }}
73
- elementsList={[]}
74
- qrLink={'http://example.com'}
75
- disableWhiteLabel={true}
76
- title={'New Title'}
77
- styleProps={{
78
- primaryColor: 'red',
79
- }}
80
- defaultText={'Your Default Text'}
81
- onSave={async data => {
82
- console.log('Saved data:', data);
83
- }}
84
- saveButtonText={'Save Progress'}
85
- locale={'en'}
86
- />
87
- );
77
+ export default function MyComponent() {
78
+ const studioRef = useRef<React.ElementRef<typeof Studio>>(null);
79
+
80
+ return (
81
+ <>
82
+ {/* Optional: a button to re-snap QR ID above the Location text */}
83
+ <button onClick={() => studioRef.current?.reflowQrId?.()}>
84
+ Realign QR ID
85
+ </button>
86
+
87
+ <Studio
88
+ ref={studioRef}
89
+ defaultTemplatesList={[]}
90
+ customTemplatesList={[]}
91
+ defaultImages={[]}
92
+ customImages={[]}
93
+ uploadImageCallBack={async (file) => {
94
+ // Upload logic here
95
+ return 'https://your-cdn.com/uploaded-image.png';
96
+ }}
97
+ elementsList={[]}
98
+ qrLink="https://example.com"
99
+ showQrIdToggle
100
+ qrId="LOT-22-7B"
101
+ disableWhiteLabel
102
+ title="New Title"
103
+ styleProps={{ primaryColor: 'red' }}
104
+ defaultText="Your Default Text"
105
+ onSave={async (data) => {
106
+ console.log('Saved data:', data);
107
+ // { elements: [...], image: 'data:image/png;base64,...' }
108
+ }}
109
+ saveButtonText="Save Progress"
110
+ locale="en"
111
+ zoomLevel={100}
112
+ />
113
+ </>
114
+ );
88
115
  }
89
-
90
- export default MyComponent;
91
116
  ```
92
117
 
93
118
  ## Props Configuration
@@ -415,24 +440,19 @@ Used to set configure allowed images formats for our gallert
415
440
  <Studio allowedFormats={['png', 'jpg']} />
416
441
  ```
417
442
 
418
- ### (New) QR ID Controls
443
+ ## 🆕 (Updated) QR ID Controls
419
444
 
420
- #### 24. `showQrIdToggle` (Boolean)
445
+ ### 24. `showQrIdToggle` (boolean)
421
446
 
422
- Shows the **“Show QR ID”** toggle in the Templates sidebar.
423
- If `true`, the user can add/remove a QR ID text element on the canvas.
447
+ Shows the **“Show QR ID”** toggle in the sidebar.
424
448
 
425
- **Example:**
426
- ```jsx
449
+ ```tsx
427
450
  <Studio showQrIdToggle />
428
451
  ```
429
452
 
430
453
  #### 25. `qrId` (String | Number)
431
454
 
432
- The value to render as the **QR ID** when the “Show QR ID” toggle is enabled.
433
-
434
- - If `qrId` is falsy (`null`, `undefined`, `''`, `0`), enabling the toggle will **not** add the QR ID text.
435
- - When toggled off and back on, the QR ID text is restored with the **last used** position/style (cached).
455
+ The value rendered in the QR ID text when the toggle is ON.
436
456
 
437
457
  **Example:**
438
458
  ```jsx
@@ -441,38 +461,23 @@ The value to render as the **QR ID** when the “Show QR ID” toggle is enabled
441
461
  qrId="FA-98231"
442
462
  />
443
463
  ```
444
- #### 26. `qrIdText` (Object)
464
+ #### 26. `qrIdText` (**deprecated for placement**)
445
465
 
446
- Controls the **initial placement and appearance** of the QR ID text *only on first insert*.
447
- If the user later moves/edits it and toggles off/on, the element is restored from cache (last known position/style), so these options won’t re-apply until no cached version exists.
466
+ > **Deprecated for positioning.**
467
+ > The QR ID position is now **computed automatically**:
448
468
 
449
- > **Coordinates are in base canvas units** (unscaled page size, not affected by zoom).
469
+ - If `LOCATION_ELEMENT_ID` (Location text) exists QR ID is centered **above it**.
470
+ - Otherwise → QR ID is **centered on the canvas**.
471
+
472
+ You may still pass stylistic hints that your theme may read (e.g., `color`),
473
+ but **`x`/`y` positioning fields are ignored** for insert/reflow.
450
474
 
451
- | Field | Type | Default | Description |
452
- |-------------|----------------------------------|-------------|-----------------------------------------------------------------------------------------------|
453
- | `x` | `number` | — | **Required** for custom placement. X position (base canvas units). |
454
- | `y` | `number` | — | **Required** for custom placement. Y position (base canvas units). |
455
- | `color` | `string` | theme text | Text color (e.g., `'#111'`, `'rgba(255,255,255,0.9)'`). |
456
- | `width` | `number` | `240` | Text box width (enables neat alignment). |
457
- | `textAlign` | `'left' \| 'center' \| 'right'` | `'center'` | Horizontal alignment within the text box. |
458
- | `pill` | `boolean` | `false` | If `true`, renders a subtle rounded pill behind the text for readability. |
459
- | `pillColor` | `string` | auto | Pill fill color. If omitted (and `pill: true`), a sensible default is chosen from text color. |
460
- | `outline` | `boolean` | `false` | If `true`, adds a thin text stroke and soft shadow for contrast on busy/dark backgrounds. |
461
475
 
462
476
  **Example:**
463
- ```jsx
477
+
478
+ ```tsx
464
479
  <Studio
465
480
  showQrIdToggle
466
481
  qrId="LOT-22-7B"
467
- qrIdText={{
468
- x: 420, // base canvas coords (unscaled)
469
- y: 760,
470
- width: 180,
471
- textAlign: 'right',
472
- color: '#FFFFFF',
473
- pill: true,
474
- pillColor: 'rgba(0,0,0,0.45)',
475
- outline: true,
476
- }}
477
482
  />
478
- ```
483
+
package/dist/cjs/index.js CHANGED
@@ -146,6 +146,9 @@ function _nonIterableRest() {
146
146
  function _nonIterableSpread() {
147
147
  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
148
148
  }
149
+ function _objectDestructuringEmpty(t) {
150
+ if (null == t) throw new TypeError("Cannot destructure " + t);
151
+ }
149
152
  function ownKeys(e, r) {
150
153
  var t = Object.keys(e);
151
154
  if (Object.getOwnPropertySymbols) {
@@ -2075,7 +2078,6 @@ var TEXT_DICTIONARY = {
2075
2078
  };
2076
2079
  var LOCATION_ELEMENT_ID = 'element-location-text';
2077
2080
  var QRID_ELEMENT_ID = 'element-qrid-text';
2078
- var QRID_ELEMENT_PILL = 'element-qrid-text-pill';
2079
2081
 
2080
2082
  var SideBar = function SideBar(_ref) {
2081
2083
  var _TEXT_DICTIONARY$lang, _TEXT_DICTIONARY$lang2, _TEXT_DICTIONARY$lang3, _TEXT_DICTIONARY$lang4, _TEXT_DICTIONARY$lang5, _TEXT_DICTIONARY$lang6;
@@ -2762,7 +2764,7 @@ var StyledText = styled.p(_templateObject2$g || (_templateObject2$g = _taggedTem
2762
2764
  return "".concat(paddingLeft, "px");
2763
2765
  });
2764
2766
 
2765
- var _excluded$1 = ["image"];
2767
+ var _excluded = ["image"];
2766
2768
  var calculatePercentageValue = function calculatePercentageValue(value, percentage) {
2767
2769
  return value * percentage / 100;
2768
2770
  };
@@ -2925,7 +2927,7 @@ var removeImageProperty = function removeImageProperty() {
2925
2927
  if ('image' in elem) {
2926
2928
  // eslint-disable-next-line no-unused-vars
2927
2929
  elem.image;
2928
- var rest = _objectWithoutProperties(elem, _excluded$1);
2930
+ var rest = _objectWithoutProperties(elem, _excluded);
2929
2931
  return rest;
2930
2932
  }
2931
2933
  return elem;
@@ -6435,7 +6437,6 @@ var isPropValid = /* #__PURE__ */memoize(function (prop) {
6435
6437
  /* Z+1 */
6436
6438
  );
6437
6439
 
6438
- var _excluded = ["ref"];
6439
6440
  /**
6440
6441
  * @typedef {Object} StudioProps
6441
6442
  * @property {string} [title]
@@ -6455,7 +6456,8 @@ var _excluded = ["ref"];
6455
6456
  * @property {'en'|'ru'|'pl'|'de'|'es'|'fr'|'it'} [locale]
6456
6457
  * @property {Function} [onCreateNewTemplate] - called when user creates a new template, passes new canvas elements
6457
6458
  * @property {Function} [onTemplateSelect] - called when a template is selected, passes template id
6458
- * @property {Function} [uploadQRLogoImage] - Optional callback to upload the QR logo image. Should return a string or an object with `{ url }`
6459
+ * @property {Function} [uploadQRLogoImage]
6460
+ * - Optional callback to upload the QR logo image. Should return a string or an object with `{ url }`
6459
6461
  * @property {number} [zoomLevel] - Optional zoom level (e.g. 100 for 100%)
6460
6462
  * @property {boolean} [showBackgroundImagePicker] - Used to set background image on entire canvas
6461
6463
  * @property {boolean} [showOpacityPicker] - Related to showBackgroundImagePicker and it's opacity
@@ -6468,7 +6470,7 @@ var _excluded = ["ref"];
6468
6470
  * @type {React.ForwardRefExoticComponent<StudioProps & React.RefAttributes<HTMLDivElement>>}
6469
6471
  */
6470
6472
  var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
6471
- var _elements$elements$fi, _elements$find6, _elements$find7, _elements$find8;
6473
+ var _elements$elements$fi, _elements$find5, _elements$find6, _elements$find7;
6472
6474
  var _ref$title = _ref.title,
6473
6475
  title = _ref$title === void 0 ? '' : _ref$title,
6474
6476
  _ref$defaultQrLogo = _ref.defaultQrLogo,
@@ -6506,11 +6508,10 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
6506
6508
  _ref$showQrIdToggle = _ref.showQrIdToggle,
6507
6509
  showQrIdToggle = _ref$showQrIdToggle === void 0 ? false : _ref$showQrIdToggle,
6508
6510
  _ref$qrId = _ref.qrId,
6509
- qrId = _ref$qrId === void 0 ? null : _ref$qrId,
6510
- _ref$qrIdText = _ref.qrIdText,
6511
- qrIdText = _ref$qrIdText === void 0 ? null : _ref$qrIdText;
6511
+ qrId = _ref$qrId === void 0 ? null : _ref$qrId;
6512
6512
  var stageRef = React.useRef(null);
6513
6513
  var elementCacheRef = React.useRef({});
6514
+ var qrIdActiveRef = React.useRef(false);
6514
6515
  var _useState = React.useState(null),
6515
6516
  _useState2 = _slicedToArray(_useState, 2),
6516
6517
  copiedElement = _useState2[0],
@@ -6620,7 +6621,59 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
6620
6621
  _useState52 = _slicedToArray(_useState51, 2),
6621
6622
  defaultTextProps = _useState52[0],
6622
6623
  setDefaultTextProps = _useState52[1];
6624
+ var _useState53 = React.useState(qrId),
6625
+ _useState54 = _slicedToArray(_useState53, 2),
6626
+ currentQrId = _useState54[0],
6627
+ setCurrentQrId = _useState54[1];
6623
6628
  var overallLoading = loadingFonts || loadingImages || loadingUploadImage || loading;
6629
+ var getPageDims = React.useCallback(function () {
6630
+ var _base$find;
6631
+ var base = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : elements;
6632
+ var sizeKey = (base === null || base === void 0 || (_base$find = base.find(function (e) {
6633
+ return (e === null || e === void 0 ? void 0 : e.type) === (elementTypes === null || elementTypes === void 0 ? void 0 : elementTypes.pageSize);
6634
+ })) === null || _base$find === void 0 ? void 0 : _base$find.size) || pageSizes.A4;
6635
+ return pageSizesDimensions[sizeKey] || pageSizesDimensions[pageSizes.A4];
6636
+ }, [elements]);
6637
+ var findById = React.useCallback(function (id) {
6638
+ var base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : elements;
6639
+ return base.find(function (e) {
6640
+ return e.id === id;
6641
+ });
6642
+ }, [elements]);
6643
+
6644
+ /**
6645
+ * Compute the QR-ID frame:
6646
+ * - If LOCATION_ELEMENT_ID exists: center-align above it
6647
+ * - Otherwise: center of page
6648
+ */
6649
+ var computeQrIdFrame = React.useCallback(function () {
6650
+ var _ref2, _loc$fontSize, _loc$x, _loc$width, _loc$y, _ref3, _loc$color, _loc$fontFamily;
6651
+ var base = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : elements;
6652
+ var _getPageDims = getPageDims(base),
6653
+ Cw = _getPageDims.width,
6654
+ Ch = _getPageDims.height;
6655
+ var loc = findById(LOCATION_ELEMENT_ID, base);
6656
+ var fs = Math.max(14, Math.min(28, (_ref2 = (_loc$fontSize = loc === null || loc === void 0 ? void 0 : loc.fontSize) !== null && _loc$fontSize !== void 0 ? _loc$fontSize : defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.fontSize) !== null && _ref2 !== void 0 ? _ref2 : 16));
6657
+ var GAP = 8; // vertical gap above location text line
6658
+ var width = Number.isFinite(loc === null || loc === void 0 ? void 0 : loc.width) ? loc.width : 240;
6659
+
6660
+ // center horizontally over location text (or page)
6661
+ var x = loc ? Math.max(0, ((_loc$x = loc.x) !== null && _loc$x !== void 0 ? _loc$x : 0) + (((_loc$width = loc.width) !== null && _loc$width !== void 0 ? _loc$width : width) - width) / 2) : Math.max(0, (Cw - width) / 2);
6662
+
6663
+ // place just above location text line (or vertical center)
6664
+ var y = loc ? Math.max(0, ((_loc$y = loc.y) !== null && _loc$y !== void 0 ? _loc$y : 0) - fs - GAP) : Math.max(0, (Ch - fs) / 2);
6665
+ var color = (_ref3 = (_loc$color = loc === null || loc === void 0 ? void 0 : loc.color) !== null && _loc$color !== void 0 ? _loc$color : defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.color) !== null && _ref3 !== void 0 ? _ref3 : '#111';
6666
+ var fontFamily = (_loc$fontFamily = loc === null || loc === void 0 ? void 0 : loc.fontFamily) !== null && _loc$fontFamily !== void 0 ? _loc$fontFamily : defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.fontFamily;
6667
+ return {
6668
+ x: x,
6669
+ y: y,
6670
+ width: width,
6671
+ textAlign: 'center',
6672
+ fontSize: fs,
6673
+ color: color,
6674
+ fontFamily: fontFamily
6675
+ };
6676
+ }, [getPageDims, findById, defaultTextProps]);
6624
6677
  var undo = React.useCallback(function () {
6625
6678
  if (history.length > 0) {
6626
6679
  setSelectedElement(null);
@@ -6676,9 +6729,41 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
6676
6729
  setLoading: setLoading,
6677
6730
  undoCount: history.length,
6678
6731
  hasChanges: history.length > 0,
6679
- redoCount: redoStack.length
6732
+ redoCount: redoStack.length,
6733
+ updateQrId: function updateQrId(newId) {
6734
+ setCurrentQrId(newId);
6735
+ var idx = elements.findIndex(function (e) {
6736
+ return e.id === QRID_ELEMENT_ID;
6737
+ });
6738
+ if (idx > -1) {
6739
+ var frame = computeQrIdFrame(elements);
6740
+ var newElements = _toConsumableArray(elements);
6741
+ newElements[idx] = _objectSpread2(_objectSpread2({}, newElements[idx]), {}, {
6742
+ text: String(newId)
6743
+ }, frame);
6744
+ saveHistory(newElements);
6745
+ if ((selectedElement === null || selectedElement === void 0 ? void 0 : selectedElement.id) === QRID_ELEMENT_ID) setSelectedElement(newElements[idx]);
6746
+ }
6747
+ },
6748
+ reflowQrId: function reflowQrId() {
6749
+ var idx = elements.findIndex(function (e) {
6750
+ return e.id === QRID_ELEMENT_ID;
6751
+ });
6752
+ if (idx === -1) return;
6753
+ var frame = computeQrIdFrame(elements);
6754
+ var copy = _toConsumableArray(elements);
6755
+ copy[idx] = _objectSpread2(_objectSpread2({}, copy[idx]), frame);
6756
+ saveHistory(copy);
6757
+ }
6680
6758
  };
6681
6759
  });
6760
+ React.useEffect(function () {
6761
+ if (selectedElement && !elements.some(function (e) {
6762
+ return e.id === selectedElement.id;
6763
+ })) {
6764
+ setSelectedElement(null);
6765
+ }
6766
+ }, [elements, selectedElement]);
6682
6767
  React.useEffect(function () {
6683
6768
  if (typeof zoomLevel === 'number') {
6684
6769
  setZoomPercentage(zoomLevel);
@@ -6767,16 +6852,15 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
6767
6852
  });
6768
6853
  if (foundLoc) {
6769
6854
  // store a clean copy (no runtime refs)
6770
- var _ref2 = foundLoc || {};
6771
- _ref2.ref;
6772
- var rest = _objectWithoutProperties(_ref2, _excluded);
6855
+ var _ref4 = foundLoc || {},
6856
+ rest = _extends({}, (_objectDestructuringEmpty(_ref4), _ref4));
6773
6857
  elementCacheRef.current[LOCATION_ELEMENT_ID] = _objectSpread2({}, rest);
6774
6858
  }
6775
6859
  }, _toConsumableArray(elementsList));
6776
6860
  var LoadImages = function LoadImages(elems) {
6777
6861
  setLoadingImages(true);
6778
- preloadRelevantImages(elems).then(function (_ref4) {
6779
- var errors = _ref4.errors;
6862
+ preloadRelevantImages(elems).then(function (_ref5) {
6863
+ var errors = _ref5.errors;
6780
6864
  // console.log('✅ Loaded images:', successes);
6781
6865
  if ((errors === null || errors === void 0 ? void 0 : errors.length) > 0) {
6782
6866
  console.log('❌ Failed images:', errors);
@@ -6815,6 +6899,9 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
6815
6899
  return e.type === elementTypes.text && e.id === QRID_ELEMENT_ID;
6816
6900
  });
6817
6901
  }, [elements]);
6902
+ React.useEffect(function () {
6903
+ qrIdActiveRef.current = hasQrIdText; // keep this in sync
6904
+ }, [hasQrIdText]);
6818
6905
  var removeElementById = function removeElementById(id) {
6819
6906
  var idx = elements.findIndex(function (e) {
6820
6907
  return e.id === id;
@@ -6823,16 +6910,11 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
6823
6910
  var snapshot = _objectSpread2({}, elements[idx]);
6824
6911
  delete snapshot.ref;
6825
6912
  // cache latest props before removing
6826
- elementCacheRef.current[id] = snapshot;
6913
+ if (id !== QRID_ELEMENT_ID) {
6914
+ elementCacheRef.current[id] = snapshot; // never cache QR-ID
6915
+ }
6827
6916
  var next = elements.slice();
6828
6917
  next.splice(idx, 1);
6829
- if (id === QRID_ELEMENT_ID) {
6830
- // remove its pill if present
6831
- var pillId = "".concat(QRID_ELEMENT_ID, "-pill");
6832
- for (var i = next.length - 1; i >= 0; i--) {
6833
- if (next[i].id === pillId) next.splice(i, 1);
6834
- }
6835
- }
6836
6918
  if ((selectedElement === null || selectedElement === void 0 ? void 0 : selectedElement.id) === id) setSelectedElement(null);
6837
6919
  saveHistory(next);
6838
6920
  }
@@ -6850,88 +6932,23 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
6850
6932
  setSelectedElement(toAdd);
6851
6933
  };
6852
6934
  var addQrIdText = function addQrIdText() {
6853
- var _elements$find4, _qrIdText$width, _qrIdText$textAlign, _ref5, _qrIdText$color, _ref6, _qrIdText$fontWeight;
6854
- if (!qrId || hasQrIdText) return;
6855
-
6856
- // 1) If we’ve seen it before, restore EXACTLY as it was
6857
- var cached = elementCacheRef.current[QRID_ELEMENT_ID];
6858
- if (cached) {
6859
- var toAdd = _objectSpread2(_objectSpread2({}, cached), {}, {
6860
- id: QRID_ELEMENT_ID,
6861
- text: String(qrId)
6862
- });
6863
- saveHistory([].concat(_toConsumableArray(elements), [toAdd]));
6864
- setSelectedElement(toAdd);
6865
- return;
6866
- }
6867
-
6868
- // 2) Otherwise, build from external qrIdText + sensible defaults
6869
- var sizeKey = (elements === null || elements === void 0 || (_elements$find4 = elements.find(function (e) {
6870
- return (e === null || e === void 0 ? void 0 : e.type) === (elementTypes === null || elementTypes === void 0 ? void 0 : elementTypes.pageSize);
6871
- })) === null || _elements$find4 === void 0 ? void 0 : _elements$find4.size) || pageSizes.A4;
6872
- var _pageSizesDimensions$ = pageSizesDimensions[sizeKey],
6873
- Cw = _pageSizesDimensions$.width,
6874
- Ch = _pageSizesDimensions$.height;
6875
- var fs = (defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.fontSize) || 16;
6876
- var lineH = fs * 1.25;
6877
-
6878
- // --- external layout (REQUIRED x,y for custom placement) ---
6879
- var hasExternal = qrIdText && typeof qrIdText.x === 'number' && typeof qrIdText.y === 'number';
6880
- var x = hasExternal ? qrIdText.x : Math.max(0, (Cw - 240) / 2);
6881
- var y = hasExternal ? qrIdText.y : Math.max(0, (Ch - lineH) / 2);
6882
- var width = (_qrIdText$width = qrIdText === null || qrIdText === void 0 ? void 0 : qrIdText.width) !== null && _qrIdText$width !== void 0 ? _qrIdText$width : 240;
6883
- var textAlign = (_qrIdText$textAlign = qrIdText === null || qrIdText === void 0 ? void 0 : qrIdText.textAlign) !== null && _qrIdText$textAlign !== void 0 ? _qrIdText$textAlign : 'center';
6884
- var color = (_ref5 = (_qrIdText$color = qrIdText === null || qrIdText === void 0 ? void 0 : qrIdText.color) !== null && _qrIdText$color !== void 0 ? _qrIdText$color : defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.color) !== null && _ref5 !== void 0 ? _ref5 : '#111';
6885
-
6886
- // optional readability helpers (opt-in)
6887
- var wantPill = !!(qrIdText !== null && qrIdText !== void 0 && qrIdText.pill);
6888
- var pillColor = (qrIdText === null || qrIdText === void 0 ? void 0 : qrIdText.pillColor) || (color === '#fff' || color.toLowerCase() === 'white' ? 'rgba(0,0,0,0.35)' : 'rgba(255,255,255,0.85)');
6889
- var wantOutline = !!(qrIdText !== null && qrIdText !== void 0 && qrIdText.outline);
6890
- var pillId = "".concat(QRID_ELEMENT_ID, "-pill");
6891
- var vPad = 8,
6892
- hPad = 10;
6893
- var newElements = _toConsumableArray(elements);
6894
- if (wantPill) {
6895
- newElements.push({
6896
- id: pillId,
6897
- type: elementTypes.square,
6898
- draggable: true,
6899
- x: x - hPad,
6900
- y: y - vPad,
6901
- width: width + hPad * 2,
6902
- height: lineH + vPad * 2,
6903
- cornerRadius: 8,
6904
- fill: pillColor,
6905
- opacity: 1,
6906
- stroke: 'rgba(0,0,0,0.12)',
6907
- strokeWidth: 1
6908
- });
6909
- }
6935
+ var base = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : elements;
6936
+ if (!currentQrId || base.some(function (e) {
6937
+ return e.id === QRID_ELEMENT_ID;
6938
+ })) return;
6939
+ var frame = computeQrIdFrame(base);
6910
6940
  var textProps = _objectSpread2({
6911
6941
  id: QRID_ELEMENT_ID,
6912
6942
  type: elementTypes.text,
6913
6943
  draggable: true,
6914
- x: x,
6915
- y: y,
6916
- width: width,
6917
- textAlign: textAlign,
6918
- text: String(qrId),
6919
- opacity: defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.opacity,
6920
- fontSize: fs,
6921
- fontFamily: defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.fontFamily,
6922
- color: color,
6923
- textDecoration: defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.textDecoration,
6924
- fontStyle: defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.fontStyle,
6925
- fontWeight: (_ref6 = (_qrIdText$fontWeight = qrIdText === null || qrIdText === void 0 ? void 0 : qrIdText.fontWeight) !== null && _qrIdText$fontWeight !== void 0 ? _qrIdText$fontWeight : defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.fontWeight) !== null && _ref6 !== void 0 ? _ref6 : '400'
6926
- }, wantOutline && {
6927
- stroke: color.toLowerCase() === '#ffffff' || color.toLowerCase() === 'white' ? 'rgba(0,0,0,0.5)' : 'rgba(255,255,255,0.8)',
6928
- strokeWidth: 1,
6929
- shadowColor: 'rgba(0,0,0,0.4)',
6930
- shadowBlur: 3,
6931
- shadowOpacity: 0.8
6932
- });
6933
- newElements.push(textProps);
6934
- saveHistory(newElements);
6944
+ text: String(currentQrId),
6945
+ fontWeight: '700',
6946
+ // always bold
6947
+ textAlign: 'center',
6948
+ opacity: defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.opacity
6949
+ }, frame);
6950
+ var next = [].concat(_toConsumableArray(base), [textProps]);
6951
+ saveHistory(next);
6935
6952
  setSelectedElement(textProps);
6936
6953
  };
6937
6954
  var toggleLocationText = function toggleLocationText() {
@@ -7000,11 +7017,11 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
7000
7017
  saveHistory([].concat(_toConsumableArray(elemClone), [newElement]));
7001
7018
  };
7002
7019
  var onSetPageSize = function onSetPageSize(newSize) {
7003
- var _elements$find5;
7020
+ var _elements$find4;
7004
7021
  if (!newSize) return;
7005
- var oldSize = (elements === null || elements === void 0 || (_elements$find5 = elements.find(function (e) {
7022
+ var oldSize = (elements === null || elements === void 0 || (_elements$find4 = elements.find(function (e) {
7006
7023
  return (e === null || e === void 0 ? void 0 : e.type) === (elementTypes === null || elementTypes === void 0 ? void 0 : elementTypes.pageSize);
7007
- })) === null || _elements$find5 === void 0 ? void 0 : _elements$find5.size) || pageSizes.A4;
7024
+ })) === null || _elements$find4 === void 0 ? void 0 : _elements$find4.size) || pageSizes.A4;
7008
7025
  var oldDims = pageSizesDimensions[oldSize];
7009
7026
  var newDims = pageSizesDimensions[newSize];
7010
7027
  var scaleX = newDims.width / oldDims.width;
@@ -7261,6 +7278,7 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
7261
7278
  saveHistory(_toConsumableArray(copyElements));
7262
7279
  };
7263
7280
  var createNewTemplate = function createNewTemplate() {
7281
+ var _elementsRef$current;
7264
7282
  var elems = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [].concat(_toConsumableArray(defaultElements), [{
7265
7283
  type: elementTypes.qr,
7266
7284
  id: "element".concat(Date.now() + 1),
@@ -7277,19 +7295,25 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
7277
7295
  opacity: 1,
7278
7296
  logoVisible: false
7279
7297
  }]);
7280
- var prevElements = elementsRef.current;
7281
- var prevQrIdText = prevElements.find(function (element) {
7282
- return element.id === QRID_ELEMENT_ID;
7298
+ var prevHadQrId = (_elementsRef$current = elementsRef.current) === null || _elementsRef$current === void 0 ? void 0 : _elementsRef$current.some(function (e) {
7299
+ return e.id === QRID_ELEMENT_ID;
7283
7300
  });
7284
- var newQrIdText = elems.find(function (element) {
7285
- return element.id === QRID_ELEMENT_ID;
7286
- });
7287
- if (!(newQrIdText !== null && newQrIdText !== void 0 && newQrIdText.id) && prevQrIdText !== null && prevQrIdText !== void 0 && prevQrIdText.id) {
7288
- var qrIdPill = prevElements.find(function (element) {
7289
- return element.id === QRID_ELEMENT_PILL;
7290
- });
7291
- if (qrIdPill.id) elems.push(qrIdPill);
7292
- elems.push(prevQrIdText);
7301
+ var next = _toConsumableArray(elems);
7302
+
7303
+ // If toggle was ON before and current template doesn’t include QR-ID, re-add it above Location (or center)
7304
+ if (prevHadQrId && !next.some(function (e) {
7305
+ return e.id === QRID_ELEMENT_ID;
7306
+ }) && showQrIdToggle && currentQrId) {
7307
+ var frame = computeQrIdFrame(next);
7308
+ next.push(_objectSpread2({
7309
+ id: QRID_ELEMENT_ID,
7310
+ type: elementTypes.text,
7311
+ draggable: true,
7312
+ text: String(currentQrId),
7313
+ fontWeight: '700',
7314
+ textAlign: 'center',
7315
+ opacity: defaultTextProps === null || defaultTextProps === void 0 ? void 0 : defaultTextProps.opacity
7316
+ }, frame));
7293
7317
  }
7294
7318
  setElements(_toConsumableArray(elems));
7295
7319
  setHistory([]);
@@ -7474,7 +7498,7 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
7474
7498
  }
7475
7499
  };
7476
7500
  var addQrLogo = /*#__PURE__*/function () {
7477
- var _ref7 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
7501
+ var _ref6 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
7478
7502
  var file, result, imageUrl, reader, _t;
7479
7503
  return _regenerator().w(function (_context2) {
7480
7504
  while (1) switch (_context2.n) {
@@ -7530,7 +7554,7 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
7530
7554
  }, _callee2, null, [[3, 5, 6, 7]]);
7531
7555
  }));
7532
7556
  return function addQrLogo() {
7533
- return _ref7.apply(this, arguments);
7557
+ return _ref6.apply(this, arguments);
7534
7558
  };
7535
7559
  }();
7536
7560
  var addLogo = function addLogo(url) {
@@ -7559,7 +7583,7 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
7559
7583
  }
7560
7584
  };
7561
7585
  var onSaveProgress = /*#__PURE__*/function () {
7562
- var _ref8 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
7586
+ var _ref7 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
7563
7587
  var processedElements, dataURL;
7564
7588
  return _regenerator().w(function (_context3) {
7565
7589
  while (1) switch (_context3.n) {
@@ -7593,7 +7617,7 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
7593
7617
  }, _callee3);
7594
7618
  }));
7595
7619
  return function onSaveProgress() {
7596
- return _ref8.apply(this, arguments);
7620
+ return _ref7.apply(this, arguments);
7597
7621
  };
7598
7622
  }();
7599
7623
  return /*#__PURE__*/React.createElement(styled.StyleSheetManager, {
@@ -7642,12 +7666,12 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
7642
7666
  onToggleQrIdText: toggleQrIdText
7643
7667
  }), loadingFonts ? null : /*#__PURE__*/React.createElement(Editor, {
7644
7668
  setLoading: setLoading,
7645
- cuttingGuideStroke: (elements === null || elements === void 0 || (_elements$find6 = elements.find(function (e) {
7669
+ cuttingGuideStroke: (elements === null || elements === void 0 || (_elements$find5 = elements.find(function (e) {
7646
7670
  return (e === null || e === void 0 ? void 0 : e.type) === (elementTypes === null || elementTypes === void 0 ? void 0 : elementTypes.pageSize);
7647
- })) === null || _elements$find6 === void 0 ? void 0 : _elements$find6.cuttingGuideStroke) || 0,
7648
- cuttingGuideStrokeColor: (elements === null || elements === void 0 || (_elements$find7 = elements.find(function (e) {
7671
+ })) === null || _elements$find5 === void 0 ? void 0 : _elements$find5.cuttingGuideStroke) || 0,
7672
+ cuttingGuideStrokeColor: (elements === null || elements === void 0 || (_elements$find6 = elements.find(function (e) {
7649
7673
  return (e === null || e === void 0 ? void 0 : e.type) === (elementTypes === null || elementTypes === void 0 ? void 0 : elementTypes.pageSize);
7650
- })) === null || _elements$find7 === void 0 ? void 0 : _elements$find7.cuttingGuideStrokeColor) || (theme === null || theme === void 0 ? void 0 : theme.color.black),
7674
+ })) === null || _elements$find6 === void 0 ? void 0 : _elements$find6.cuttingGuideStrokeColor) || (theme === null || theme === void 0 ? void 0 : theme.color.black),
7651
7675
  onChangeCuttingGuideProp: function onChangeCuttingGuideProp(type, value) {
7652
7676
  _onChangeCuttingGuideProp(type, value);
7653
7677
  },
@@ -7689,9 +7713,9 @@ var Studio = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
7689
7713
  stageRef: stageRef,
7690
7714
  saveHistory: saveHistory,
7691
7715
  onChangeBackgroundImageOpacity: onChangeBackgroundImageOpacity,
7692
- backgroundImageOpacity: (elements === null || elements === void 0 || (_elements$find8 = elements.find(function (e) {
7716
+ backgroundImageOpacity: (elements === null || elements === void 0 || (_elements$find7 = elements.find(function (e) {
7693
7717
  return (e === null || e === void 0 ? void 0 : e.type) === (elementTypes === null || elementTypes === void 0 ? void 0 : elementTypes.backgroundImage);
7694
- })) === null || _elements$find8 === void 0 ? void 0 : _elements$find8.opacity) || backgroundImageOpacity,
7718
+ })) === null || _elements$find7 === void 0 ? void 0 : _elements$find7.opacity) || backgroundImageOpacity,
7695
7719
  onDeleteSelectedElement: onDeleteSelectedElement,
7696
7720
  onCopySelectedElement: onCopySelectedElement,
7697
7721
  onToggleLockElement: onToggleLockElement,