dsh-skill-picker 0.5.24 → 0.5.25

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-skill-picker",
3
3
  "description": "DSH Web GUI skill picker: a button beside the composer opens a searchable list of installed skills; picking one inserts the official `/skill-name` gesture into the input box, so the skill loads with your message (WorkBuddy-style skill invocation for DeepSeek Harness).",
4
- "version": "0.5.24",
4
+ "version": "0.5.25",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -274,10 +274,21 @@ const buttonStyle = {
274
274
  flex: 'none',
275
275
  }
276
276
 
277
+ /**
278
+ * Panel placement.
279
+ *
280
+ * Fixed (not absolute) and anchored to the RIGHT EDGE OF THE WINDOW, with the
281
+ * vertical offset measured from the ⚡ button so it still opens just above the
282
+ * composer.
283
+ *
284
+ * Why not `absolute; right: 0` on the button's own wrapper — which is what it
285
+ * used to be: the ⚡ sits next to the model picker, well left of the composer's
286
+ * right edge, so the panel was right-aligned to *that* and threw itself across
287
+ * the middle of the conversation, covering the text. 国豪 spotted it.
288
+ */
277
289
  const popoverStyle = {
278
- position: 'absolute',
279
- bottom: 'calc(100% + 8px)',
280
- right: '0',
290
+ position: 'fixed',
291
+ right: '24px',
281
292
  width: '340px',
282
293
  maxHeight: '320px',
283
294
  display: 'flex',
@@ -466,6 +477,12 @@ function SkillPickerButton(props) {
466
477
  const itemRefs = useRef([])
467
478
  /** Pending long-press timer for the touch path (see the menu below). */
468
479
  const longPressRef = useRef(0)
480
+ /**
481
+ * Distance from the window bottom to the panel's bottom edge, measured from
482
+ * the ⚡ button each time the panel opens. See `popoverStyle`: the horizontal
483
+ * anchor is the window's right edge, only the height follows the button.
484
+ */
485
+ const [panelBottom, setPanelBottom] = useState(88)
469
486
 
470
487
  // The usage store is shared with the official `/` menu: picks made there go
471
488
  // through window.__dshSkillPickerTrack (localStorage only). Refresh this
@@ -671,6 +688,13 @@ function SkillPickerButton(props) {
671
688
 
672
689
  const toggle = () => {
673
690
  if (!open) {
691
+ // Measure before opening so the panel is already in place on its first
692
+ // paint (no visible jump).
693
+ const el = boxRef.current
694
+ if (el !== null) {
695
+ const rect = el.getBoundingClientRect()
696
+ setPanelBottom(Math.max(64, Math.round(window.innerHeight - rect.top + 8)))
697
+ }
674
698
  // Pull first: a pin or a pick made on another client (desktop ↔ web ↔
675
699
  // phone) should be visible the moment this panel opens. The pull fires
676
700
  // SHARED_STATE_EVENT, which is what refreshes `usage`/`pinned` here.
@@ -791,7 +815,7 @@ function SkillPickerButton(props) {
791
815
  <BoltIcon />
792
816
  </button>
793
817
  {open && (
794
- <div style={popoverStyle}>
818
+ <div style={{ ...popoverStyle, bottom: `${panelBottom}px` }}>
795
819
  <input
796
820
  value={query}
797
821
  onChange={(event) => setQuery(event.target.value)}