@fairfox/polly 0.73.0 → 0.74.0
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/dist/src/mesh.js +18 -12
- package/dist/src/mesh.js.map +5 -4
- package/dist/src/polly-ui/ActionSelect.d.ts +7 -3
- package/dist/src/polly-ui/Dropdown.d.ts +15 -0
- package/dist/src/polly-ui/Select.d.ts +2 -0
- package/dist/src/polly-ui/index.css +31 -14
- package/dist/src/polly-ui/index.js +124 -25
- package/dist/src/polly-ui/index.js.map +5 -5
- package/dist/src/polly-ui/styles.css +31 -14
- package/dist/src/shared/lib/derive-document-id.d.ts +21 -0
- package/dist/src/shared/lib/mesh-state.d.ts +6 -6
- package/dist/tools/verify/src/cli.js +25 -2
- package/dist/tools/verify/src/cli.js.map +3 -3
- package/dist/tools/visualize/src/cli.js +473 -23
- package/dist/tools/visualize/src/cli.js.map +9 -7
- package/package.json +1 -1
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
* <ActionInput> and <ActionForm>, with no synthetic signal or bridging
|
|
10
10
|
* `effect` required.
|
|
11
11
|
*
|
|
12
|
-
* Composes <Dropdown> for the menu. The trigger is
|
|
13
|
-
*
|
|
14
|
-
* interactive element
|
|
12
|
+
* Composes <Dropdown> for the menu. The trigger styling is applied
|
|
13
|
+
* directly to Dropdown's own <button> via `triggerClassName`, so the
|
|
14
|
+
* visible box and the interactive element are one and the same node —
|
|
15
|
+
* no styled <span> nested inside an unstyled <button>. A disabled
|
|
16
|
+
* ActionSelect renders as static text without a caret.
|
|
15
17
|
*/
|
|
16
18
|
import type { JSX } from "preact";
|
|
17
19
|
import { type PassthroughAttrs } from "./internal/passthrough.ts";
|
|
@@ -30,6 +32,8 @@ export type ActionSelectProps = PassthroughAttrs & {
|
|
|
30
32
|
/** Trigger text shown when `value` matches no option. Default: "Select…". */
|
|
31
33
|
placeholder?: string;
|
|
32
34
|
disabled?: boolean;
|
|
35
|
+
/** Apply a comfortable minimum width to the trigger. Default: sizes to content. */
|
|
36
|
+
wide?: boolean;
|
|
33
37
|
className?: string;
|
|
34
38
|
id?: string;
|
|
35
39
|
};
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dropdown — trigger button + popover menu using the native Popover API.
|
|
3
3
|
*
|
|
4
|
+
* A shown popover is promoted to the browser's top layer, where CSS
|
|
5
|
+
* positioning resolves against the viewport rather than the `.dropdown`
|
|
6
|
+
* wrapper — so the menu cannot be placed with `position: absolute`
|
|
7
|
+
* alone. Instead it is pinned with `position: fixed` and coordinates
|
|
8
|
+
* measured from the trigger; see `positionMenu` below (issue #128).
|
|
9
|
+
*
|
|
4
10
|
* The menu element gets `popover="auto"` and a unique `data-overlay-id`.
|
|
5
11
|
* `closeTopOverlay()` from @fairfox/polly/actions finds the topmost
|
|
6
12
|
* `[data-overlay-id]` element and dispatches `overlay:close` — the
|
|
@@ -18,6 +24,15 @@ export type DropdownProps = {
|
|
|
18
24
|
align?: "left" | "right";
|
|
19
25
|
multiSelect?: boolean;
|
|
20
26
|
className?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Class applied to the trigger <button> in place of Dropdown's own
|
|
29
|
+
* default. Lets a composing component (Select, ActionSelect) style
|
|
30
|
+
* the single interactive element directly, with no styled node
|
|
31
|
+
* nested inside the button.
|
|
32
|
+
*/
|
|
33
|
+
triggerClassName?: string;
|
|
34
|
+
/** Disables the trigger <button>. */
|
|
35
|
+
triggerDisabled?: boolean;
|
|
21
36
|
id?: string;
|
|
22
37
|
};
|
|
23
38
|
export declare function Dropdown(props: DropdownProps): JSX.Element;
|
|
@@ -20,6 +20,8 @@ export type SelectProps<T = string> = {
|
|
|
20
20
|
placeholder?: string;
|
|
21
21
|
multiSelect?: boolean;
|
|
22
22
|
disabled?: boolean;
|
|
23
|
+
/** Apply a comfortable minimum width to the trigger. Default: sizes to content. */
|
|
24
|
+
wide?: boolean;
|
|
23
25
|
className?: string;
|
|
24
26
|
id?: string;
|
|
25
27
|
};
|
|
@@ -67,10 +67,9 @@
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
.menu_HX48zA {
|
|
70
|
-
position:
|
|
70
|
+
position: fixed;
|
|
71
71
|
inset: unset;
|
|
72
72
|
z-index: var(--polly-z-raised);
|
|
73
|
-
margin: var(--polly-space-xs) 0 0;
|
|
74
73
|
padding: var(--polly-space-xs) 0;
|
|
75
74
|
border: var(--polly-border-width-default) solid var(--polly-border);
|
|
76
75
|
border-radius: var(--polly-radius-md);
|
|
@@ -80,13 +79,7 @@
|
|
|
80
79
|
overflow-y: auto;
|
|
81
80
|
min-width: 160px;
|
|
82
81
|
max-height: 280px;
|
|
83
|
-
|
|
84
|
-
left: 0;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
.alignRight_HX48zA {
|
|
88
|
-
left: auto;
|
|
89
|
-
right: 0;
|
|
82
|
+
margin: 0;
|
|
90
83
|
}
|
|
91
84
|
}
|
|
92
85
|
|
|
@@ -163,7 +156,9 @@
|
|
|
163
156
|
}
|
|
164
157
|
|
|
165
158
|
.trigger_daofbw {
|
|
166
|
-
display: inline-
|
|
159
|
+
display: inline-flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
gap: var(--polly-space-sm);
|
|
167
162
|
padding: var(--polly-space-sm) var(--polly-space-md);
|
|
168
163
|
border: var(--polly-border-width-default) solid var(--polly-border);
|
|
169
164
|
border-radius: var(--polly-radius-sm);
|
|
@@ -173,15 +168,37 @@
|
|
|
173
168
|
color: var(--polly-text);
|
|
174
169
|
text-align: left;
|
|
175
170
|
cursor: pointer;
|
|
171
|
+
max-width: 100%;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.trigger_daofbw:disabled, .trigger_daofbw[aria-disabled="true"] {
|
|
175
|
+
opacity: var(--polly-opacity-disabled);
|
|
176
|
+
cursor: not-allowed;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.triggerWide_daofbw {
|
|
180
|
+
min-width: 140px;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.triggerLabel_daofbw {
|
|
176
184
|
white-space: nowrap;
|
|
177
185
|
overflow: hidden;
|
|
178
186
|
text-overflow: ellipsis;
|
|
179
|
-
|
|
187
|
+
flex: auto;
|
|
188
|
+
min-width: 0;
|
|
180
189
|
}
|
|
181
190
|
|
|
182
|
-
.
|
|
183
|
-
|
|
184
|
-
|
|
191
|
+
.caret_daofbw {
|
|
192
|
+
color: var(--polly-text-muted);
|
|
193
|
+
pointer-events: none;
|
|
194
|
+
flex: none;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.caret_daofbw:before {
|
|
198
|
+
content: "▾";
|
|
199
|
+
display: block;
|
|
200
|
+
font-size: var(--polly-text-xs);
|
|
201
|
+
line-height: 1;
|
|
185
202
|
}
|
|
186
203
|
|
|
187
204
|
.placeholder_daofbw {
|
|
@@ -275,8 +275,7 @@ import { useEffect as useEffect2, useRef as useRef2 } from "preact/hooks";
|
|
|
275
275
|
var Dropdown_module_default = {
|
|
276
276
|
dropdown: "dropdown_HX48zA",
|
|
277
277
|
trigger: "trigger_HX48zA",
|
|
278
|
-
menu: "menu_HX48zA"
|
|
279
|
-
alignRight: "alignRight_HX48zA"
|
|
278
|
+
menu: "menu_HX48zA"
|
|
280
279
|
};
|
|
281
280
|
|
|
282
281
|
// src/polly-ui/Layout.tsx
|
|
@@ -392,8 +391,20 @@ function Layout(props) {
|
|
|
392
391
|
// src/polly-ui/Dropdown.tsx
|
|
393
392
|
import { jsxDEV as jsxDEV3 } from "preact/jsx-dev-runtime";
|
|
394
393
|
var dropdownCounter = 0;
|
|
394
|
+
var MENU_GAP = 4;
|
|
395
|
+
var VIEWPORT_PADDING = 8;
|
|
395
396
|
function Dropdown(props) {
|
|
396
|
-
const {
|
|
397
|
+
const {
|
|
398
|
+
isOpen,
|
|
399
|
+
trigger,
|
|
400
|
+
children,
|
|
401
|
+
align = "left",
|
|
402
|
+
multiSelect = false,
|
|
403
|
+
className,
|
|
404
|
+
triggerClassName,
|
|
405
|
+
triggerDisabled = false,
|
|
406
|
+
id
|
|
407
|
+
} = props;
|
|
397
408
|
const menuRef = useRef2(null);
|
|
398
409
|
const triggerRef = useRef2(null);
|
|
399
410
|
const idRef = useRef2(`polly-dropdown-${++dropdownCounter}`);
|
|
@@ -415,6 +426,60 @@ function Dropdown(props) {
|
|
|
415
426
|
menu.removeEventListener("overlay:close", onOverlayClose);
|
|
416
427
|
};
|
|
417
428
|
}, [popoverId, isOpen]);
|
|
429
|
+
useEffect2(() => {
|
|
430
|
+
const menu = menuRef.current;
|
|
431
|
+
const trigger2 = triggerRef.current;
|
|
432
|
+
if (!menu || !trigger2)
|
|
433
|
+
return;
|
|
434
|
+
const positionMenu = () => {
|
|
435
|
+
const t = trigger2.getBoundingClientRect();
|
|
436
|
+
const prevDisplay = menu.style.display;
|
|
437
|
+
menu.style.maxHeight = "";
|
|
438
|
+
menu.style.display = "block";
|
|
439
|
+
const menuWidth = menu.offsetWidth;
|
|
440
|
+
const menuHeight = menu.offsetHeight;
|
|
441
|
+
menu.style.display = prevDisplay;
|
|
442
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
443
|
+
const viewportHeight = document.documentElement.clientHeight;
|
|
444
|
+
let left = align === "right" ? t.right - menuWidth : t.left;
|
|
445
|
+
const maxLeft = Math.max(VIEWPORT_PADDING, viewportWidth - menuWidth - VIEWPORT_PADDING);
|
|
446
|
+
left = Math.min(Math.max(left, VIEWPORT_PADDING), maxLeft);
|
|
447
|
+
const spaceBelow = viewportHeight - t.bottom - MENU_GAP - VIEWPORT_PADDING;
|
|
448
|
+
const spaceAbove = t.top - MENU_GAP - VIEWPORT_PADDING;
|
|
449
|
+
let top;
|
|
450
|
+
if (menuHeight <= spaceBelow || spaceBelow >= spaceAbove) {
|
|
451
|
+
top = t.bottom + MENU_GAP;
|
|
452
|
+
if (menuHeight > spaceBelow) {
|
|
453
|
+
menu.style.maxHeight = `${Math.max(spaceBelow, 0)}px`;
|
|
454
|
+
}
|
|
455
|
+
} else {
|
|
456
|
+
const available = Math.max(spaceAbove, 0);
|
|
457
|
+
menu.style.maxHeight = `${available}px`;
|
|
458
|
+
top = t.top - MENU_GAP - Math.min(menuHeight, available);
|
|
459
|
+
}
|
|
460
|
+
menu.style.position = "fixed";
|
|
461
|
+
menu.style.margin = "0";
|
|
462
|
+
menu.style.left = `${left}px`;
|
|
463
|
+
menu.style.top = `${top}px`;
|
|
464
|
+
};
|
|
465
|
+
const onBeforeToggle = (e) => {
|
|
466
|
+
if (e.newState === "open") {
|
|
467
|
+
positionMenu();
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
const onReposition = () => {
|
|
471
|
+
if (menu.matches(":popover-open"))
|
|
472
|
+
positionMenu();
|
|
473
|
+
};
|
|
474
|
+
menu.addEventListener("beforetoggle", onBeforeToggle);
|
|
475
|
+
window.addEventListener("scroll", onReposition, true);
|
|
476
|
+
window.addEventListener("resize", onReposition);
|
|
477
|
+
return () => {
|
|
478
|
+
menu.removeEventListener("beforetoggle", onBeforeToggle);
|
|
479
|
+
window.removeEventListener("scroll", onReposition, true);
|
|
480
|
+
window.removeEventListener("resize", onReposition);
|
|
481
|
+
};
|
|
482
|
+
}, [align]);
|
|
418
483
|
useSignalEffect(() => {
|
|
419
484
|
const menu = menuRef.current;
|
|
420
485
|
if (!menu)
|
|
@@ -443,9 +508,6 @@ function Dropdown(props) {
|
|
|
443
508
|
const parts = [Dropdown_module_default["dropdown"] ?? ""];
|
|
444
509
|
if (className)
|
|
445
510
|
parts.push(className);
|
|
446
|
-
const menuParts = [Dropdown_module_default["menu"] ?? ""];
|
|
447
|
-
if (align === "right")
|
|
448
|
-
menuParts.push(Dropdown_module_default["alignRight"] ?? "");
|
|
449
511
|
return /* @__PURE__ */ jsxDEV3("div", {
|
|
450
512
|
id,
|
|
451
513
|
class: parts.filter(Boolean).join(" "),
|
|
@@ -455,14 +517,16 @@ function Dropdown(props) {
|
|
|
455
517
|
/* @__PURE__ */ jsxDEV3("button", {
|
|
456
518
|
ref: triggerRef,
|
|
457
519
|
type: "button",
|
|
458
|
-
class: Dropdown_module_default["trigger"],
|
|
520
|
+
class: triggerClassName ?? Dropdown_module_default["trigger"] ?? "",
|
|
521
|
+
disabled: triggerDisabled,
|
|
459
522
|
children: trigger
|
|
460
523
|
}, undefined, false, undefined, this),
|
|
461
524
|
/* @__PURE__ */ jsxDEV3("div", {
|
|
462
525
|
ref: menuRef,
|
|
463
526
|
id: popoverId,
|
|
464
527
|
role: "listbox",
|
|
465
|
-
class:
|
|
528
|
+
class: Dropdown_module_default["menu"] ?? "",
|
|
529
|
+
"data-align": align,
|
|
466
530
|
popover: "auto",
|
|
467
531
|
"data-overlay-id": popoverId,
|
|
468
532
|
onToggle: handleToggle,
|
|
@@ -483,6 +547,9 @@ var Select_module_default = {
|
|
|
483
547
|
select: "select_daofbw",
|
|
484
548
|
label: "label_daofbw",
|
|
485
549
|
trigger: "trigger_daofbw",
|
|
550
|
+
triggerWide: "triggerWide_daofbw",
|
|
551
|
+
triggerLabel: "triggerLabel_daofbw",
|
|
552
|
+
caret: "caret_daofbw",
|
|
486
553
|
placeholder: "placeholder_daofbw",
|
|
487
554
|
actions: "actions_daofbw",
|
|
488
555
|
actionBtn: "actionBtn_daofbw",
|
|
@@ -492,7 +559,7 @@ var Select_module_default = {
|
|
|
492
559
|
};
|
|
493
560
|
|
|
494
561
|
// src/polly-ui/ActionSelect.tsx
|
|
495
|
-
import { jsxDEV as jsxDEV4 } from "preact/jsx-dev-runtime";
|
|
562
|
+
import { jsxDEV as jsxDEV4, Fragment } from "preact/jsx-dev-runtime";
|
|
496
563
|
function labelFor(options, value) {
|
|
497
564
|
for (const opt of options) {
|
|
498
565
|
if (opt.value === value)
|
|
@@ -509,6 +576,7 @@ function ActionSelect(props) {
|
|
|
509
576
|
label,
|
|
510
577
|
placeholder = "Select…",
|
|
511
578
|
disabled = false,
|
|
579
|
+
wide = false,
|
|
512
580
|
className,
|
|
513
581
|
id
|
|
514
582
|
} = props;
|
|
@@ -522,7 +590,12 @@ function ActionSelect(props) {
|
|
|
522
590
|
return;
|
|
523
591
|
dispatchAction(action, { ...actionData ?? {}, value: next });
|
|
524
592
|
};
|
|
525
|
-
const
|
|
593
|
+
const triggerParts = [Select_module_default["trigger"] ?? ""];
|
|
594
|
+
if (isEmpty)
|
|
595
|
+
triggerParts.push(Select_module_default["placeholder"] ?? "");
|
|
596
|
+
if (wide)
|
|
597
|
+
triggerParts.push(Select_module_default["triggerWide"] ?? "");
|
|
598
|
+
const triggerClass = triggerParts.filter(Boolean).join(" ");
|
|
526
599
|
const parts = [Select_module_default["select"] ?? ""];
|
|
527
600
|
if (className)
|
|
528
601
|
parts.push(className);
|
|
@@ -541,13 +614,25 @@ function ActionSelect(props) {
|
|
|
541
614
|
disabled ? /* @__PURE__ */ jsxDEV4("span", {
|
|
542
615
|
class: triggerClass,
|
|
543
616
|
"aria-disabled": "true",
|
|
544
|
-
children:
|
|
617
|
+
children: /* @__PURE__ */ jsxDEV4("span", {
|
|
618
|
+
class: Select_module_default["triggerLabel"],
|
|
619
|
+
children: displayText
|
|
620
|
+
}, undefined, false, undefined, this)
|
|
545
621
|
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV4(Dropdown, {
|
|
546
622
|
isOpen,
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
children:
|
|
550
|
-
|
|
623
|
+
triggerClassName: triggerClass,
|
|
624
|
+
trigger: /* @__PURE__ */ jsxDEV4(Fragment, {
|
|
625
|
+
children: [
|
|
626
|
+
/* @__PURE__ */ jsxDEV4("span", {
|
|
627
|
+
class: Select_module_default["triggerLabel"],
|
|
628
|
+
children: displayText
|
|
629
|
+
}, undefined, false, undefined, this),
|
|
630
|
+
/* @__PURE__ */ jsxDEV4("span", {
|
|
631
|
+
class: Select_module_default["caret"],
|
|
632
|
+
"aria-hidden": "true"
|
|
633
|
+
}, undefined, false, undefined, this)
|
|
634
|
+
]
|
|
635
|
+
}, undefined, true, undefined, this),
|
|
551
636
|
children: options.map((opt) => {
|
|
552
637
|
const isSelected = opt.value === value;
|
|
553
638
|
const optClass = isSelected ? `${Select_module_default["option"]} ${Select_module_default["optionSelected"]}` : Select_module_default["option"];
|
|
@@ -1571,7 +1656,7 @@ function Host() {
|
|
|
1571
1656
|
var ConfirmDialog = { Host, confirm };
|
|
1572
1657
|
// src/polly-ui/Select.tsx
|
|
1573
1658
|
import { useComputed, useSignal as useSignal2 } from "@preact/signals";
|
|
1574
|
-
import { jsxDEV as jsxDEV14 } from "preact/jsx-dev-runtime";
|
|
1659
|
+
import { jsxDEV as jsxDEV14, Fragment as Fragment2 } from "preact/jsx-dev-runtime";
|
|
1575
1660
|
function formatSelected(options, selected) {
|
|
1576
1661
|
if (selected.size === 0)
|
|
1577
1662
|
return "";
|
|
@@ -1590,6 +1675,7 @@ function Select(props) {
|
|
|
1590
1675
|
placeholder = "Select…",
|
|
1591
1676
|
multiSelect = false,
|
|
1592
1677
|
disabled = false,
|
|
1678
|
+
wide = false,
|
|
1593
1679
|
className,
|
|
1594
1680
|
id
|
|
1595
1681
|
} = props;
|
|
@@ -1618,13 +1704,24 @@ function Select(props) {
|
|
|
1618
1704
|
const handleClear = () => {
|
|
1619
1705
|
selected.value = new Set;
|
|
1620
1706
|
};
|
|
1621
|
-
const
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1707
|
+
const triggerParts = [Select_module_default["trigger"] ?? ""];
|
|
1708
|
+
if (isEmpty.value)
|
|
1709
|
+
triggerParts.push(Select_module_default["placeholder"] ?? "");
|
|
1710
|
+
if (wide)
|
|
1711
|
+
triggerParts.push(Select_module_default["triggerWide"] ?? "");
|
|
1712
|
+
const triggerClass = triggerParts.filter(Boolean).join(" ");
|
|
1713
|
+
const triggerContent = /* @__PURE__ */ jsxDEV14(Fragment2, {
|
|
1714
|
+
children: [
|
|
1715
|
+
/* @__PURE__ */ jsxDEV14("span", {
|
|
1716
|
+
class: Select_module_default["triggerLabel"],
|
|
1717
|
+
children: displayText.value
|
|
1718
|
+
}, undefined, false, undefined, this),
|
|
1719
|
+
/* @__PURE__ */ jsxDEV14("span", {
|
|
1720
|
+
class: Select_module_default["caret"],
|
|
1721
|
+
"aria-hidden": "true"
|
|
1722
|
+
}, undefined, false, undefined, this)
|
|
1723
|
+
]
|
|
1724
|
+
}, undefined, true, undefined, this);
|
|
1628
1725
|
const parts = [Select_module_default["select"] ?? ""];
|
|
1629
1726
|
if (className)
|
|
1630
1727
|
parts.push(className);
|
|
@@ -1640,7 +1737,9 @@ function Select(props) {
|
|
|
1640
1737
|
}, undefined, false, undefined, this),
|
|
1641
1738
|
/* @__PURE__ */ jsxDEV14(Dropdown, {
|
|
1642
1739
|
isOpen: isOpen2,
|
|
1643
|
-
trigger:
|
|
1740
|
+
trigger: triggerContent,
|
|
1741
|
+
triggerClassName: triggerClass,
|
|
1742
|
+
triggerDisabled: disabled,
|
|
1644
1743
|
multiSelect,
|
|
1645
1744
|
children: [
|
|
1646
1745
|
multiSelect && /* @__PURE__ */ jsxDEV14("div", {
|
|
@@ -2100,4 +2199,4 @@ export {
|
|
|
2100
2199
|
ActionForm
|
|
2101
2200
|
};
|
|
2102
2201
|
|
|
2103
|
-
//# debugId=
|
|
2202
|
+
//# debugId=D646BF0B09E9BEC064756E2164756E21
|