draply-dev 1.5.3 → 1.5.4

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/overlay.js +72 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "draply-dev",
3
- "version": "1.5.3",
3
+ "version": "1.5.4",
4
4
  "description": "Visual overlay for any frontend project — move, resize, restyle live in the browser, save to CSS",
5
5
  "author": "Arman",
6
6
  "type": "commonjs",
package/src/overlay.js CHANGED
@@ -1640,6 +1640,7 @@ document.addEventListener('mouseup', () => {
1640
1640
  // ══════════════════════════════════════════
1641
1641
  // Full history — every individual action
1642
1642
  const history = [];
1643
+ const redoHistory = [];
1643
1644
 
1644
1645
  function rec(el, props, prevPropsOverride, isCreate = false) {
1645
1646
  const selector = el.dataset.pixelshiftId ? null : gsel(el);
@@ -1695,7 +1696,14 @@ function rec(el, props, prevPropsOverride, isCreate = false) {
1695
1696
 
1696
1697
  // Push to history
1697
1698
  const hid = Date.now() + Math.random();
1698
- history.push({ hid, el, props, prevProps, selector: key, isCreate });
1699
+ history.push({
1700
+ hid, el, props, prevProps, selector: key, isCreate,
1701
+ parent: isCreate ? el.parentElement : null,
1702
+ nextSibling: isCreate ? el.nextElementSibling : null
1703
+ });
1704
+
1705
+ // Clear redo stack on new action
1706
+ redoHistory.length = 0;
1699
1707
 
1700
1708
  updateUnsUI();
1701
1709
  }
@@ -1736,9 +1744,12 @@ function revertChange(h) {
1736
1744
  if (h.prevProps.innerHTML !== undefined) h.el.innerHTML = h.prevProps.innerHTML;
1737
1745
  if (h.prevProps.innerText !== undefined) h.el.innerText = h.prevProps.innerText;
1738
1746
  }
1739
- // Remove from history
1747
+ // Remove from history and add to redo stack
1740
1748
  const idx = history.findIndex(x => x.hid === h.hid);
1741
- if (idx >= 0) history.splice(idx, 1);
1749
+ if (idx >= 0) {
1750
+ redoHistory.push(history[idx]);
1751
+ history.splice(idx, 1);
1752
+ }
1742
1753
  // Rebuild state.changes — preserve all original fields (#1, #2)
1743
1754
  state.changes = [];
1744
1755
  history.forEach(x => {
@@ -1761,6 +1772,58 @@ function revertChange(h) {
1761
1772
  toast('↩ Reverted');
1762
1773
  }
1763
1774
 
1775
+ function redoChange() {
1776
+ if (redoHistory.length === 0) {
1777
+ toast('Nothing to redo');
1778
+ return;
1779
+ }
1780
+ const h = redoHistory.pop();
1781
+
1782
+ if (h.isCreate) {
1783
+ if (h.parent) {
1784
+ if (h.nextSibling) {
1785
+ h.parent.insertBefore(h.el, h.nextSibling);
1786
+ } else {
1787
+ h.parent.appendChild(h.el);
1788
+ }
1789
+ } else {
1790
+ document.body.appendChild(h.el);
1791
+ }
1792
+ } else {
1793
+ // Re-apply properties
1794
+ Object.entries(h.props).forEach(([prop, val]) => {
1795
+ const camel = prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
1796
+ h.el.style[camel] = val;
1797
+ });
1798
+ if (h.props.innerHTML !== undefined) h.el.innerHTML = h.props.innerHTML;
1799
+ if (h.props.innerText !== undefined) h.el.innerText = h.props.innerText;
1800
+ }
1801
+
1802
+ history.push(h);
1803
+
1804
+ // Rebuild state.changes
1805
+ state.changes = [];
1806
+ history.forEach(x => {
1807
+ const key = x.selector;
1808
+ const i = state.changes.findIndex(c => (c.pixelshiftId || c.selector) === key);
1809
+ if (i >= 0) {
1810
+ Object.assign(state.changes[i].props, x.props);
1811
+ } else {
1812
+ state.changes.push({
1813
+ type: x.isCreate ? 'create' : 'css',
1814
+ isCreate: x.isCreate || false,
1815
+ selector: key,
1816
+ props: { ...x.props },
1817
+ outerHTML: x.isCreate && x.el ? x.el.outerHTML : undefined,
1818
+ tagName: x.el ? x.el.tagName?.toLowerCase() : undefined
1819
+ });
1820
+ }
1821
+ });
1822
+
1823
+ updateUnsUI();
1824
+ toast('↷ Redone');
1825
+ }
1826
+
1764
1827
  sv.addEventListener('click', async () => {
1765
1828
  // Check key config status
1766
1829
  let hasKey = false;
@@ -1819,13 +1882,13 @@ sv.addEventListener('click', async () => {
1819
1882
  toast('⚠ Server unreachable');
1820
1883
  }
1821
1884
 
1822
- state.changes = []; history.length = 0;
1885
+ state.changes = []; history.length = 0; redoHistory.length = 0;
1823
1886
  sv.innerHTML = 'Save'; sv.textContent = 'Save';
1824
1887
  updateUnsUI();
1825
1888
  });
1826
1889
 
1827
1890
  document.getElementById('__uns_clear__').onclick = () => {
1828
- state.changes = []; history.length = 0; updateUnsUI();
1891
+ state.changes = []; history.length = 0; redoHistory.length = 0; updateUnsUI();
1829
1892
  toast('🗑 History cleared');
1830
1893
  };
1831
1894
 
@@ -1840,7 +1903,7 @@ document.addEventListener('keydown', e => {
1840
1903
  if (tag === 'input' || tag === 'textarea' || e.target.isContentEditable) return;
1841
1904
 
1842
1905
  // Ctrl+Z — Undo last change (#4)
1843
- if ((e.ctrlKey || e.metaKey) && !e.shiftKey && e.key === 'z') {
1906
+ if ((e.ctrlKey || e.metaKey) && !e.shiftKey && e.key.toLowerCase() === 'z') {
1844
1907
  e.preventDefault();
1845
1908
  if (history.length > 0) {
1846
1909
  revertChange(history[history.length - 1]);
@@ -1850,10 +1913,10 @@ document.addEventListener('keydown', e => {
1850
1913
  return;
1851
1914
  }
1852
1915
 
1853
- // Ctrl+Shift+Z — Redo (not implemented yet, just prevent default)
1854
- if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'z') {
1916
+ // Ctrl+Shift+Z — Redo (implemented)
1917
+ if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key.toLowerCase() === 'z') {
1855
1918
  e.preventDefault();
1856
- toast('Redo not available yet');
1919
+ redoChange();
1857
1920
  return;
1858
1921
  }
1859
1922