@lotics/ui 47.5.1 → 47.5.2
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/docs/composition.md +13 -0
- package/package.json +1 -1
- package/src/popover.tsx +28 -0
package/docs/composition.md
CHANGED
|
@@ -136,6 +136,19 @@ the subject into rows.
|
|
|
136
136
|
| Register / work list / calendar | 1040 |
|
|
137
137
|
| Wide wallboard / report | 1100 |
|
|
138
138
|
|
|
139
|
+
**A row that navigates PAINTS.** A link is not a row: it paints nothing, so a row tall enough to
|
|
140
|
+
hold an identity mark becomes a large silent target — the pointer crosses it and the only thing
|
|
141
|
+
saying it is pressable is the cursor. Reach for the row surface (`PressableRow`), never a
|
|
142
|
+
hand-rolled hover on the anchor: the wash has to span the WHOLE row *including its trailing
|
|
143
|
+
controls*, and a parent's Pressability hover is released to the innermost nested pressable, which
|
|
144
|
+
stops the wash short of the `⋯` and leaves a gap exactly where the eye is going. Keep the anchor
|
|
145
|
+
INSIDE as the accessible door — a row of places to go owes middle-click, cmd-click and copy-link,
|
|
146
|
+
which only a real anchor gives.
|
|
147
|
+
|
|
148
|
+
Without that wash the trailing controls are what look wrong: nothing ties a `⋯` to its row, so the
|
|
149
|
+
right edge reads as a floating column competing with the names, and the instinct is to hide the
|
|
150
|
+
control. Paint the row first — the clutter usually WAS the missing wash.
|
|
151
|
+
|
|
139
152
|
**ONE LEFT EDGE — the whole page, and then the whole APP.** Headings, detail labels, prose, a
|
|
140
153
|
table's first column, a footer's totals, a dialog's title. Then check the screen this one OPENS: a
|
|
141
154
|
list and the record it opens are one reading column seen twice, and both must derive from ONE
|
package/package.json
CHANGED
package/src/popover.tsx
CHANGED
|
@@ -433,6 +433,34 @@ export function PopoverContent(props: PopoverContentProps) {
|
|
|
433
433
|
return () => document.removeEventListener("click", onOutsideClick, true);
|
|
434
434
|
}, [open, small, onOpenChange, triggerRef]);
|
|
435
435
|
|
|
436
|
+
// The one press the click listener above CANNOT see: one that lands inside a
|
|
437
|
+
// cross-origin iframe. Those events are dispatched in the frame's own document
|
|
438
|
+
// and never cross into this one, so a popover anchored over an embedded app —
|
|
439
|
+
// the app page's own chrome is exactly this shape — stayed open while the user
|
|
440
|
+
// clicked around underneath it, with no way to dismiss but pressing the trigger
|
|
441
|
+
// again or hitting Escape.
|
|
442
|
+
//
|
|
443
|
+
// Focus is the signal that survives the boundary: clicking into a frame moves
|
|
444
|
+
// this document's `activeElement` to the IFRAME element and blurs the window.
|
|
445
|
+
//
|
|
446
|
+
// Checking `activeElement` is what keeps this from over-firing. A window blur
|
|
447
|
+
// alone also means "switched tab" or "moved to another app", and dismissing
|
|
448
|
+
// then is a menu that quietly disappears while the user was reading something
|
|
449
|
+
// else. Only a blur that HANDED FOCUS TO A FRAME is a press we missed.
|
|
450
|
+
useEffect(() => {
|
|
451
|
+
if (!open || small) return;
|
|
452
|
+
const onWindowBlur = () => {
|
|
453
|
+
// Deferred: at blur time the browser has not always moved `activeElement`
|
|
454
|
+
// to the frame yet, so reading it synchronously can still report the
|
|
455
|
+
// trigger and miss the dismissal entirely.
|
|
456
|
+
setTimeout(() => {
|
|
457
|
+
if (document.activeElement instanceof HTMLIFrameElement) onOpenChange(false);
|
|
458
|
+
}, 0);
|
|
459
|
+
};
|
|
460
|
+
window.addEventListener("blur", onWindowBlur);
|
|
461
|
+
return () => window.removeEventListener("blur", onWindowBlur);
|
|
462
|
+
}, [open, small, onOpenChange]);
|
|
463
|
+
|
|
436
464
|
const calculatePosition = useCallback(() => {
|
|
437
465
|
if (!popoverRef.current) return;
|
|
438
466
|
if (small) return;
|