@restregular/dsh-powerup 0.2.2 → 0.2.3
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 +3 -1
- package/client.js +237 -106
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,7 +87,9 @@ unload the dialog mid-flow. Use **Add plugin** with the new package version.
|
|
|
87
87
|
`--dsw-elevation-prominent`, and the primary button uses
|
|
88
88
|
`--dsw-alias-button-primary-fill` / `-hover`, so the dialog follows both
|
|
89
89
|
themes instead of inventing its own palette. The registry picker and version
|
|
90
|
-
list are custom controls built from `--dsw-alias-*` tokens
|
|
90
|
+
list are custom controls built from `--dsw-alias-*` tokens; both open as
|
|
91
|
+
fixed-position popovers anchored to their triggers, so they never grow the
|
|
92
|
+
dialog or get clipped by its scroll area.
|
|
91
93
|
|
|
92
94
|
## Development
|
|
93
95
|
|
package/client.js
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
|
|
45
45
|
const NS = 'dsh-powerup';
|
|
46
46
|
const SETTINGS_KEY = 'dsh-powerup:settings:v1';
|
|
47
|
-
const VERSION = '0.2.
|
|
47
|
+
const VERSION = '0.2.3';
|
|
48
48
|
const MENU_GAP = 8;
|
|
49
49
|
const MENU_WIDTH = 248;
|
|
50
50
|
|
|
@@ -698,6 +698,9 @@
|
|
|
698
698
|
.dsh-powerup-update-toggle .chevron{display:inline-flex;color:var(--dsw-alias-label-tertiary);transition:transform .16s ease}
|
|
699
699
|
.dsh-powerup-update-toggle[aria-expanded=true] .chevron{transform:rotate(180deg);color:var(--dsw-alias-label-secondary)}
|
|
700
700
|
.dsh-powerup-update-list{display:flex;flex-direction:column;max-height:240px;overflow-y:auto;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-lg,10px);background:var(--dsw-alias-bg-layer-1);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2)}
|
|
701
|
+
.dsh-powerup-update-popover{position:fixed;z-index:1300;box-sizing:border-box;overflow-y:auto;pointer-events:auto;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-lg,10px);background:var(--dsw-alias-bg-layer-2);box-shadow:var(--dsw-elevation-prominent);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2)}
|
|
702
|
+
.dsh-powerup-update-popover.dsh-powerup-update-list{border-radius:var(--dsw-radius-lg,10px)}
|
|
703
|
+
.dsh-powerup-update-popover.dsh-powerup-update-select-menu{display:flex;flex-direction:column;padding:4px}
|
|
701
704
|
.dsh-powerup-update-list-head{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px 12px;border-bottom:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}
|
|
702
705
|
.dsh-powerup-update-version{display:flex;align-items:center;gap:8px;width:100%;min-height:34px;padding:0 12px;border:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12.5px;line-height:18px;text-align:left;cursor:pointer;font-variant-numeric:tabular-nums}
|
|
703
706
|
.dsh-powerup-update-version>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
@@ -1502,6 +1505,33 @@
|
|
|
1502
1505
|
for (const button of [...buttons]) if (button.isConnected !== true) buttons.delete(button);
|
|
1503
1506
|
}
|
|
1504
1507
|
|
|
1508
|
+
/**
|
|
1509
|
+
* Place a floating panel under an anchor, flipping above when the space
|
|
1510
|
+
* below is short, and clamp it to the viewport.
|
|
1511
|
+
* @param {{ getBoundingClientRect: () => DOMRect }} anchor
|
|
1512
|
+
* @param {number} minWidth
|
|
1513
|
+
* @param {number} preferredHeight
|
|
1514
|
+
* @returns {{ left: number, width: number, top?: number, bottom?: number, maxHeight: number }}
|
|
1515
|
+
*/
|
|
1516
|
+
function popoverPlacement(anchor, minWidth, preferredHeight) {
|
|
1517
|
+
const rect = anchor.getBoundingClientRect();
|
|
1518
|
+
const gap = 6;
|
|
1519
|
+
const margin = 12;
|
|
1520
|
+
const viewportWidth = typeof window === 'undefined' ? 1280 : window.innerWidth;
|
|
1521
|
+
const viewportHeight = typeof window === 'undefined' ? 900 : window.innerHeight;
|
|
1522
|
+
const width = Math.min(Math.max(rect.width, minWidth), Math.max(200, viewportWidth - margin * 2));
|
|
1523
|
+
const left = Math.min(Math.max(margin, rect.left), Math.max(margin, viewportWidth - width - margin));
|
|
1524
|
+
const spaceBelow = viewportHeight - rect.bottom - margin - gap;
|
|
1525
|
+
const spaceAbove = rect.top - margin - gap;
|
|
1526
|
+
const above = spaceBelow < Math.min(preferredHeight, 180) && spaceAbove > spaceBelow;
|
|
1527
|
+
return {
|
|
1528
|
+
left,
|
|
1529
|
+
width,
|
|
1530
|
+
...(above ? { bottom: viewportHeight - rect.top + gap } : { top: rect.bottom + gap }),
|
|
1531
|
+
maxHeight: Math.max(120, Math.min(preferredHeight, above ? spaceAbove : spaceBelow)),
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1505
1535
|
/**
|
|
1506
1536
|
* The Plugins-page update control. It injects one icon button into each
|
|
1507
1537
|
* third-party card of the built-in "Installed plugins" group, then owns
|
|
@@ -1516,7 +1546,10 @@
|
|
|
1516
1546
|
const abortRef = useRef(null);
|
|
1517
1547
|
const buttonsRef = useRef(new Set());
|
|
1518
1548
|
const inputRef = useRef(null);
|
|
1549
|
+
const versionRef = useRef(null);
|
|
1550
|
+
const versionPanelRef = useRef(null);
|
|
1519
1551
|
const registryRef = useRef(null);
|
|
1552
|
+
const registryPanelRef = useRef(null);
|
|
1520
1553
|
const versionSeq = useRef(0);
|
|
1521
1554
|
const tRef = useRef((key, params) => translateCurrent(key, params));
|
|
1522
1555
|
tRef.current = (key, params) => translateCurrent(key, params);
|
|
@@ -1548,6 +1581,17 @@
|
|
|
1548
1581
|
setView(null);
|
|
1549
1582
|
}, [view]);
|
|
1550
1583
|
|
|
1584
|
+
/** Dismiss both floating panels without touching the dialog. */
|
|
1585
|
+
const closePopovers = useCallback(() => {
|
|
1586
|
+
setView((current) => current === null ? current : {
|
|
1587
|
+
...current,
|
|
1588
|
+
listOpen: false,
|
|
1589
|
+
listPopover: null,
|
|
1590
|
+
registryOpen: false,
|
|
1591
|
+
registryPopover: null,
|
|
1592
|
+
});
|
|
1593
|
+
}, []);
|
|
1594
|
+
|
|
1551
1595
|
const loadVersions = useCallback(async (token, name, choice, choices, resetVersion) => {
|
|
1552
1596
|
const t = tRef.current;
|
|
1553
1597
|
const seq = versionSeq.current + 1;
|
|
@@ -1606,8 +1650,10 @@
|
|
|
1606
1650
|
versionsError: null,
|
|
1607
1651
|
versionsRegistry: null,
|
|
1608
1652
|
version: '',
|
|
1609
|
-
listOpen:
|
|
1653
|
+
listOpen: false,
|
|
1654
|
+
listPopover: null,
|
|
1610
1655
|
registryOpen: false,
|
|
1656
|
+
registryPopover: null,
|
|
1611
1657
|
error: null,
|
|
1612
1658
|
formError: null,
|
|
1613
1659
|
log: '',
|
|
@@ -1700,19 +1746,18 @@
|
|
|
1700
1746
|
}
|
|
1701
1747
|
}, [view === null ? null : view.phase]);
|
|
1702
1748
|
|
|
1703
|
-
// Escape closes the innermost
|
|
1704
|
-
// version list, then the dialog itself.
|
|
1749
|
+
// Escape closes the innermost floating panel first, then the dialog.
|
|
1705
1750
|
useEffect(() => {
|
|
1706
1751
|
if (view === null) return undefined;
|
|
1707
1752
|
const onKeyDown = (event) => {
|
|
1708
1753
|
if (event.key !== 'Escape') return;
|
|
1709
1754
|
event.stopPropagation();
|
|
1710
1755
|
if (view.registryOpen === true) {
|
|
1711
|
-
setView((current) => current === null ? current : { ...current, registryOpen: false });
|
|
1756
|
+
setView((current) => current === null ? current : { ...current, registryOpen: false, registryPopover: null });
|
|
1712
1757
|
return;
|
|
1713
1758
|
}
|
|
1714
1759
|
if (view.phase === 'choose' && view.listOpen === true) {
|
|
1715
|
-
setView((current) => current === null ? current : { ...current, listOpen: false });
|
|
1760
|
+
setView((current) => current === null ? current : { ...current, listOpen: false, listPopover: null });
|
|
1716
1761
|
return;
|
|
1717
1762
|
}
|
|
1718
1763
|
close();
|
|
@@ -1721,17 +1766,42 @@
|
|
|
1721
1766
|
return () => document.removeEventListener('keydown', onKeyDown, true);
|
|
1722
1767
|
}, [view, close]);
|
|
1723
1768
|
|
|
1724
|
-
//
|
|
1769
|
+
// Clicking outside the open floating panel and its trigger dismisses it.
|
|
1725
1770
|
useEffect(() => {
|
|
1726
|
-
if (view === null || view.registryOpen !== true) return undefined;
|
|
1771
|
+
if (view === null || (view.registryOpen !== true && view.listOpen !== true)) return undefined;
|
|
1727
1772
|
const onPointerDown = (event) => {
|
|
1728
|
-
const
|
|
1729
|
-
if (
|
|
1730
|
-
|
|
1773
|
+
const target = event.target;
|
|
1774
|
+
if (!(target instanceof Node)) return;
|
|
1775
|
+
const inside = [versionRef.current, versionPanelRef.current, registryRef.current, registryPanelRef.current]
|
|
1776
|
+
.some((root) => root !== null && root.contains(target));
|
|
1777
|
+
if (inside) return;
|
|
1778
|
+
closePopovers();
|
|
1731
1779
|
};
|
|
1732
1780
|
document.addEventListener('pointerdown', onPointerDown, true);
|
|
1733
1781
|
return () => document.removeEventListener('pointerdown', onPointerDown, true);
|
|
1734
|
-
}, [view === null ? null : view.registryOpen]);
|
|
1782
|
+
}, [view === null ? null : `${String(view.registryOpen)}:${String(view.listOpen)}`, closePopovers]);
|
|
1783
|
+
|
|
1784
|
+
// Scrolling the dialog or the page would leave a fixed panel behind;
|
|
1785
|
+
// dismiss it instead. Scrolling inside the panel itself is allowed.
|
|
1786
|
+
useEffect(() => {
|
|
1787
|
+
if (view === null || (view.registryOpen !== true && view.listOpen !== true)) return undefined;
|
|
1788
|
+
const onScroll = (event) => {
|
|
1789
|
+
const target = event.target;
|
|
1790
|
+
if (target instanceof Node) {
|
|
1791
|
+
const insidePanel = [versionPanelRef.current, registryPanelRef.current]
|
|
1792
|
+
.some((panel) => panel !== null && panel.contains(target));
|
|
1793
|
+
if (insidePanel) return;
|
|
1794
|
+
}
|
|
1795
|
+
closePopovers();
|
|
1796
|
+
};
|
|
1797
|
+
const onResize = () => closePopovers();
|
|
1798
|
+
document.addEventListener('scroll', onScroll, true);
|
|
1799
|
+
window.addEventListener('resize', onResize);
|
|
1800
|
+
return () => {
|
|
1801
|
+
document.removeEventListener('scroll', onScroll, true);
|
|
1802
|
+
window.removeEventListener('resize', onResize);
|
|
1803
|
+
};
|
|
1804
|
+
}, [view === null ? null : `${String(view.registryOpen)}:${String(view.listOpen)}`, closePopovers]);
|
|
1735
1805
|
|
|
1736
1806
|
// Show pnpm output while an installation runs.
|
|
1737
1807
|
useEffect(() => {
|
|
@@ -1756,7 +1826,7 @@
|
|
|
1756
1826
|
|
|
1757
1827
|
const chooseVersion = (version) => {
|
|
1758
1828
|
if (tokenRef.current === null) return;
|
|
1759
|
-
setView((current) => current === null ? current : { ...current, version, listOpen: false, formError: null });
|
|
1829
|
+
setView((current) => current === null ? current : { ...current, version, listOpen: false, listPopover: null, formError: null });
|
|
1760
1830
|
};
|
|
1761
1831
|
|
|
1762
1832
|
const chooseRegistry = (key) => {
|
|
@@ -1766,10 +1836,48 @@
|
|
|
1766
1836
|
if (current === null) return;
|
|
1767
1837
|
const choice = current.choices.find((item) => item.key === key);
|
|
1768
1838
|
if (choice === undefined) return;
|
|
1769
|
-
setView((state) => state === null ? state : { ...state, registryKey: key, registryOpen: false, formError: null });
|
|
1839
|
+
setView((state) => state === null ? state : { ...state, registryKey: key, registryOpen: false, registryPopover: null, formError: null });
|
|
1770
1840
|
loadVersions(token, current.name, choice, current.choices, true);
|
|
1771
1841
|
};
|
|
1772
1842
|
|
|
1843
|
+
/** Open or close the floating version list under the input row. */
|
|
1844
|
+
const toggleVersionList = () => {
|
|
1845
|
+
const current = view;
|
|
1846
|
+
if (current === null || current.phase !== 'choose') return;
|
|
1847
|
+
if (current.listOpen === true) {
|
|
1848
|
+
setView((state) => state === null ? state : { ...state, listOpen: false, listPopover: null });
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
const anchor = versionRef.current;
|
|
1852
|
+
const popover = anchor === null ? null : popoverPlacement(anchor, 280, 260);
|
|
1853
|
+
setView((state) => state === null ? state : {
|
|
1854
|
+
...state,
|
|
1855
|
+
listOpen: true,
|
|
1856
|
+
listPopover: popover,
|
|
1857
|
+
registryOpen: false,
|
|
1858
|
+
registryPopover: null,
|
|
1859
|
+
});
|
|
1860
|
+
};
|
|
1861
|
+
|
|
1862
|
+
/** Open or close the floating registry menu under its trigger. */
|
|
1863
|
+
const toggleRegistry = () => {
|
|
1864
|
+
const current = view;
|
|
1865
|
+
if (current === null || current.phase !== 'choose') return;
|
|
1866
|
+
if (current.registryOpen === true) {
|
|
1867
|
+
setView((state) => state === null ? state : { ...state, registryOpen: false, registryPopover: null });
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
const anchor = registryRef.current;
|
|
1871
|
+
const popover = anchor === null ? null : popoverPlacement(anchor, 280, 220);
|
|
1872
|
+
setView((state) => state === null ? state : {
|
|
1873
|
+
...state,
|
|
1874
|
+
registryOpen: true,
|
|
1875
|
+
registryPopover: popover,
|
|
1876
|
+
listOpen: false,
|
|
1877
|
+
listPopover: null,
|
|
1878
|
+
});
|
|
1879
|
+
};
|
|
1880
|
+
|
|
1773
1881
|
const startUpdate = async () => {
|
|
1774
1882
|
const token = tokenRef.current;
|
|
1775
1883
|
const current = view;
|
|
@@ -1932,6 +2040,61 @@
|
|
|
1932
2040
|
|
|
1933
2041
|
const currentChoice = view.choices.find((item) => item.key === view.registryKey) ?? view.choices[0];
|
|
1934
2042
|
|
|
2043
|
+
/** Rows of the floating version list, including its loading/error states. */
|
|
2044
|
+
const versionRows = (() => {
|
|
2045
|
+
if (view.versionsState === 'loading') {
|
|
2046
|
+
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
2047
|
+
h('div', { className: 'dsh-powerup-update-status' },
|
|
2048
|
+
h('span', { className: 'dsh-powerup-update-spinner', 'aria-hidden': 'true' }),
|
|
2049
|
+
t('update.loadingVersions'),
|
|
2050
|
+
),
|
|
2051
|
+
)];
|
|
2052
|
+
}
|
|
2053
|
+
if (view.versionsState === 'error') {
|
|
2054
|
+
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
2055
|
+
notice('error', h(WarnIcon, { size: 14 }), null, t('update.versionsFailed', { message: view.versionsError ?? '' })),
|
|
2056
|
+
h('button', {
|
|
2057
|
+
type: 'button',
|
|
2058
|
+
className: 'dsh-powerup-update-ghost',
|
|
2059
|
+
onClick: () => loadVersions(tokenRef.current, view.name, currentChoice, view.choices, false),
|
|
2060
|
+
}, t('update.retry')),
|
|
2061
|
+
)];
|
|
2062
|
+
}
|
|
2063
|
+
if ((view.versions ?? []).length === 0) {
|
|
2064
|
+
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
2065
|
+
h('p', { className: 'dsh-powerup-update-note' }, t('update.versionsEmpty')),
|
|
2066
|
+
)];
|
|
2067
|
+
}
|
|
2068
|
+
return [
|
|
2069
|
+
h('div', { key: 'head', className: 'dsh-powerup-update-list-head' },
|
|
2070
|
+
h('span', null, t('update.versionsCount', { count: view.versions.length })),
|
|
2071
|
+
view.versionsRegistry === null || view.versionsRegistry === undefined
|
|
2072
|
+
? null
|
|
2073
|
+
: h('span', { title: view.versionsRegistry.hint }, view.versionsRegistry.hint),
|
|
2074
|
+
),
|
|
2075
|
+
...view.versions.map((version) => {
|
|
2076
|
+
const tagKind = versionTagKind(version, view.currentVersion, view.latest);
|
|
2077
|
+
return h('button', {
|
|
2078
|
+
key: version,
|
|
2079
|
+
type: 'button',
|
|
2080
|
+
role: 'option',
|
|
2081
|
+
className: 'dsh-powerup-update-version',
|
|
2082
|
+
'aria-selected': version === view.version ? 'true' : 'false',
|
|
2083
|
+
'data-current': version === view.currentVersion ? '' : undefined,
|
|
2084
|
+
onClick: () => chooseVersion(version),
|
|
2085
|
+
},
|
|
2086
|
+
h('span', null, version),
|
|
2087
|
+
h('span', { className: 'dsh-powerup-update-trailing' },
|
|
2088
|
+
tagKind === null ? null : h('span', {
|
|
2089
|
+
className: `dsh-powerup-update-tag${tagKind === 'latest' ? '' : ' is-current'}`,
|
|
2090
|
+
}, t(tagKind === 'current-latest' ? 'update.currentAndLatest' : tagKind === 'current' ? 'update.currentTag' : 'update.latest')),
|
|
2091
|
+
version === view.version ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
|
|
2092
|
+
),
|
|
2093
|
+
);
|
|
2094
|
+
}),
|
|
2095
|
+
];
|
|
2096
|
+
})();
|
|
2097
|
+
|
|
1935
2098
|
const body = (() => {
|
|
1936
2099
|
if (view.phase === 'loading') {
|
|
1937
2100
|
return h('div', { className: 'dsh-powerup-update-status' },
|
|
@@ -1946,59 +2109,6 @@
|
|
|
1946
2109
|
return notice('error', h(WarnIcon, { size: 15 }), t('update.unsupportedTitle'), view.error ?? t('update.notRemovable'));
|
|
1947
2110
|
}
|
|
1948
2111
|
if (view.phase === 'choose') {
|
|
1949
|
-
const rows = (() => {
|
|
1950
|
-
if (view.versionsState === 'loading') {
|
|
1951
|
-
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
1952
|
-
h('div', { className: 'dsh-powerup-update-status' },
|
|
1953
|
-
h('span', { className: 'dsh-powerup-update-spinner', 'aria-hidden': 'true' }),
|
|
1954
|
-
t('update.loadingVersions'),
|
|
1955
|
-
),
|
|
1956
|
-
)];
|
|
1957
|
-
}
|
|
1958
|
-
if (view.versionsState === 'error') {
|
|
1959
|
-
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
1960
|
-
notice('error', h(WarnIcon, { size: 14 }), null, t('update.versionsFailed', { message: view.versionsError ?? '' })),
|
|
1961
|
-
h('button', {
|
|
1962
|
-
type: 'button',
|
|
1963
|
-
className: 'dsh-powerup-update-ghost',
|
|
1964
|
-
onClick: () => loadVersions(tokenRef.current, view.name, currentChoice, view.choices, false),
|
|
1965
|
-
}, t('update.retry')),
|
|
1966
|
-
)];
|
|
1967
|
-
}
|
|
1968
|
-
if ((view.versions ?? []).length === 0) {
|
|
1969
|
-
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
1970
|
-
h('p', { className: 'dsh-powerup-update-note' }, t('update.versionsEmpty')),
|
|
1971
|
-
)];
|
|
1972
|
-
}
|
|
1973
|
-
return [
|
|
1974
|
-
h('div', { key: 'head', className: 'dsh-powerup-update-list-head' },
|
|
1975
|
-
h('span', null, t('update.versionsCount', { count: view.versions.length })),
|
|
1976
|
-
view.versionsRegistry === null || view.versionsRegistry === undefined
|
|
1977
|
-
? null
|
|
1978
|
-
: h('span', { title: view.versionsRegistry.hint }, view.versionsRegistry.hint),
|
|
1979
|
-
),
|
|
1980
|
-
...view.versions.map((version) => {
|
|
1981
|
-
const tagKind = versionTagKind(version, view.currentVersion, view.latest);
|
|
1982
|
-
return h('button', {
|
|
1983
|
-
key: version,
|
|
1984
|
-
type: 'button',
|
|
1985
|
-
role: 'option',
|
|
1986
|
-
className: 'dsh-powerup-update-version',
|
|
1987
|
-
'aria-selected': version === view.version ? 'true' : 'false',
|
|
1988
|
-
'data-current': version === view.currentVersion ? '' : undefined,
|
|
1989
|
-
onClick: () => chooseVersion(version),
|
|
1990
|
-
},
|
|
1991
|
-
h('span', null, version),
|
|
1992
|
-
h('span', { className: 'dsh-powerup-update-trailing' },
|
|
1993
|
-
tagKind === null ? null : h('span', {
|
|
1994
|
-
className: `dsh-powerup-update-tag${tagKind === 'latest' ? '' : ' is-current'}`,
|
|
1995
|
-
}, t(tagKind === 'current-latest' ? 'update.currentAndLatest' : tagKind === 'current' ? 'update.currentTag' : 'update.latest')),
|
|
1996
|
-
version === view.version ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
|
|
1997
|
-
),
|
|
1998
|
-
);
|
|
1999
|
-
}),
|
|
2000
|
-
];
|
|
2001
|
-
})();
|
|
2002
2112
|
return [
|
|
2003
2113
|
h('div', { key: 'summary', className: 'dsh-powerup-update-summary' },
|
|
2004
2114
|
h('div', { className: 'dsh-powerup-update-now' },
|
|
@@ -2010,7 +2120,7 @@
|
|
|
2010
2120
|
),
|
|
2011
2121
|
h('div', { key: 'version', className: 'dsh-powerup-update-field' },
|
|
2012
2122
|
h('label', { className: 'dsh-powerup-update-label', htmlFor: 'dsh-powerup-update-version' }, t('update.versionLabel')),
|
|
2013
|
-
h('div', { className: 'dsh-powerup-update-row' },
|
|
2123
|
+
h('div', { className: 'dsh-powerup-update-row', ref: versionRef },
|
|
2014
2124
|
h('input', {
|
|
2015
2125
|
id: 'dsh-powerup-update-version',
|
|
2016
2126
|
ref: inputRef,
|
|
@@ -2030,7 +2140,7 @@
|
|
|
2030
2140
|
className: 'dsh-powerup-update-toggle',
|
|
2031
2141
|
'aria-expanded': showVersions ? 'true' : 'false',
|
|
2032
2142
|
'aria-controls': 'dsh-powerup-update-versions',
|
|
2033
|
-
onClick:
|
|
2143
|
+
onClick: toggleVersionList,
|
|
2034
2144
|
},
|
|
2035
2145
|
showVersions ? t('update.hideVersions') : t('update.chooseVersion'),
|
|
2036
2146
|
h('span', { className: 'chevron' }, h(ChevronDownIcon, { size: 12 })),
|
|
@@ -2040,7 +2150,6 @@
|
|
|
2040
2150
|
? null
|
|
2041
2151
|
: notice('error', h(WarnIcon, { size: 14 }), null, view.formError),
|
|
2042
2152
|
),
|
|
2043
|
-
showVersions ? h('div', { key: 'versions', id: 'dsh-powerup-update-versions', className: 'dsh-powerup-update-list', role: 'listbox', 'aria-label': t('update.versionLabel') }, rows) : null,
|
|
2044
2153
|
h('div', { key: 'registry', className: 'dsh-powerup-update-field' },
|
|
2045
2154
|
h('span', { className: 'dsh-powerup-update-label' }, t('update.registry')),
|
|
2046
2155
|
h('div', { className: 'dsh-powerup-update-select', ref: registryRef },
|
|
@@ -2049,27 +2158,12 @@
|
|
|
2049
2158
|
className: 'dsh-powerup-update-select-trigger',
|
|
2050
2159
|
'aria-haspopup': 'listbox',
|
|
2051
2160
|
'aria-expanded': view.registryOpen === true ? 'true' : 'false',
|
|
2052
|
-
onClick:
|
|
2161
|
+
onClick: toggleRegistry,
|
|
2053
2162
|
},
|
|
2054
2163
|
h('span', { className: 'dsh-powerup-update-select-value' }, currentChoice?.label ?? ''),
|
|
2055
2164
|
h('span', { className: 'dsh-powerup-update-select-host' }, currentChoice?.hint ?? ''),
|
|
2056
2165
|
h('span', { className: 'chevron' }, h(ChevronDownIcon, { size: 12 })),
|
|
2057
2166
|
),
|
|
2058
|
-
view.registryOpen === true ? h('div', { className: 'dsh-powerup-update-select-menu', role: 'listbox', 'aria-label': t('update.registry') },
|
|
2059
|
-
view.choices.map((choice) => h('button', {
|
|
2060
|
-
key: choice.key,
|
|
2061
|
-
type: 'button',
|
|
2062
|
-
role: 'option',
|
|
2063
|
-
className: 'dsh-powerup-update-option',
|
|
2064
|
-
'aria-selected': choice.key === view.registryKey ? 'true' : 'false',
|
|
2065
|
-
onClick: () => chooseRegistry(choice.key),
|
|
2066
|
-
},
|
|
2067
|
-
h('span', { className: 'dsh-powerup-update-option-copy' },
|
|
2068
|
-
h('span', { className: 'dsh-powerup-update-option-title' }, choice.label),
|
|
2069
|
-
h('span', { className: 'dsh-powerup-update-option-host' }, choice.hint),
|
|
2070
|
-
),
|
|
2071
|
-
choice.key === view.registryKey ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
|
|
2072
|
-
))) : null,
|
|
2073
2167
|
),
|
|
2074
2168
|
view.versionsRegistry === null || view.versionsRegistry === undefined
|
|
2075
2169
|
? null
|
|
@@ -2152,28 +2246,64 @@
|
|
|
2152
2246
|
return null;
|
|
2153
2247
|
})();
|
|
2154
2248
|
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2249
|
+
const fallbackPopover = { left: 24, top: 120, width: 320, maxHeight: 260 };
|
|
2250
|
+
|
|
2251
|
+
return h(React.Fragment, null,
|
|
2252
|
+
h('div', {
|
|
2253
|
+
className: 'dsh-powerup-update-mask',
|
|
2254
|
+
onMouseDown: (event) => {
|
|
2255
|
+
if (event.target === event.currentTarget) close();
|
|
2256
|
+
},
|
|
2159
2257
|
},
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2258
|
+
h('div', {
|
|
2259
|
+
className: 'dsh-powerup-update-dialog',
|
|
2260
|
+
role: 'dialog',
|
|
2261
|
+
'aria-modal': 'true',
|
|
2262
|
+
'aria-labelledby': 'dsh-powerup-update-title',
|
|
2263
|
+
},
|
|
2264
|
+
h('div', { className: 'dsh-powerup-update-head' },
|
|
2265
|
+
h('div', { className: 'dsh-powerup-update-heading' },
|
|
2266
|
+
h('h2', { id: 'dsh-powerup-update-title' }, t('update.title')),
|
|
2267
|
+
h('p', { title }, title),
|
|
2268
|
+
),
|
|
2269
|
+
canClose ? h('button', { type: 'button', className: 'dsh-powerup-update-close', 'aria-label': t('update.close'), onClick: close }, '×') : null,
|
|
2171
2270
|
),
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2271
|
+
h('div', { className: 'dsh-powerup-update-body' }, body),
|
|
2272
|
+
footer.length === 0 ? null : h('div', { className: 'dsh-powerup-update-foot' }, footer),
|
|
2273
|
+
),
|
|
2274
|
+
),
|
|
2275
|
+
view.listOpen === true
|
|
2276
|
+
? h('div', {
|
|
2277
|
+
id: 'dsh-powerup-update-versions',
|
|
2278
|
+
ref: versionPanelRef,
|
|
2279
|
+
className: 'dsh-powerup-update-popover dsh-powerup-update-list',
|
|
2280
|
+
role: 'listbox',
|
|
2281
|
+
'aria-label': t('update.versionLabel'),
|
|
2282
|
+
style: view.listPopover ?? fallbackPopover,
|
|
2283
|
+
}, versionRows)
|
|
2284
|
+
: null,
|
|
2285
|
+
view.registryOpen === true
|
|
2286
|
+
? h('div', {
|
|
2287
|
+
ref: registryPanelRef,
|
|
2288
|
+
className: 'dsh-powerup-update-popover dsh-powerup-update-select-menu',
|
|
2289
|
+
role: 'listbox',
|
|
2290
|
+
'aria-label': t('update.registry'),
|
|
2291
|
+
style: view.registryPopover ?? fallbackPopover,
|
|
2292
|
+
}, view.choices.map((choice) => h('button', {
|
|
2293
|
+
key: choice.key,
|
|
2294
|
+
type: 'button',
|
|
2295
|
+
role: 'option',
|
|
2296
|
+
className: 'dsh-powerup-update-option',
|
|
2297
|
+
'aria-selected': choice.key === view.registryKey ? 'true' : 'false',
|
|
2298
|
+
onClick: () => chooseRegistry(choice.key),
|
|
2299
|
+
},
|
|
2300
|
+
h('span', { className: 'dsh-powerup-update-option-copy' },
|
|
2301
|
+
h('span', { className: 'dsh-powerup-update-option-title' }, choice.label),
|
|
2302
|
+
h('span', { className: 'dsh-powerup-update-option-host' }, choice.hint),
|
|
2303
|
+
),
|
|
2304
|
+
choice.key === view.registryKey ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
|
|
2305
|
+
)))
|
|
2306
|
+
: null,
|
|
2177
2307
|
);
|
|
2178
2308
|
}
|
|
2179
2309
|
|
|
@@ -2548,6 +2678,7 @@
|
|
|
2548
2678
|
PluginUpdateOverlay,
|
|
2549
2679
|
ensureUpdateButtons,
|
|
2550
2680
|
updateButtonLabel,
|
|
2681
|
+
popoverPlacement,
|
|
2551
2682
|
rowKeyParts,
|
|
2552
2683
|
resolveForkSeq,
|
|
2553
2684
|
markdownQuote,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@restregular/dsh-powerup",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Power-Up — small, opt-in upgrades for DeepSeek Harness. Adds a right-click action menu to the Trajectory ledger and an update control for third-party plugins installed from the Plugins page, with version lookup, uninstall-and-reinstall through the Add plugin path, and an optional DSH restart. · 为 DeepSeek Harness 提供小型增强:在轨迹页面右键记录即可复制、引用、查看详情或从该记录 Fork;并在插件页为第三方已安装插件提供带版本查询的更新按钮,沿用「添加插件」的安装流程,并可重启 DSH 使更改生效。",
|
|
5
5
|
"icon": "./icon.svg",
|
|
6
6
|
"type": "module",
|