@nimblebrain/synapse 0.12.0 → 0.12.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/README.md +13 -7
- package/dist/ui/index.cjs +88 -29
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +4 -4
- package/dist/ui/index.d.ts +4 -4
- package/dist/ui/index.js +88 -29
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes,
|
|
2
|
+
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, InputHTMLAttributes, RefObject, CSSProperties, ElementType } from 'react';
|
|
3
3
|
|
|
4
4
|
interface AvatarProps extends Omit<HTMLAttributes<HTMLSpanElement>, "children"> {
|
|
5
5
|
/** Name used for initials and the image alt text. */
|
|
@@ -44,9 +44,9 @@ interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
44
44
|
declare function Card({ padding, interactive, style, className, children, ...rest }: CardProps): react_jsx_runtime.JSX.Element;
|
|
45
45
|
|
|
46
46
|
type Side$1 = "left" | "right" | "bottom";
|
|
47
|
-
interface DrawerProps extends Omit<
|
|
47
|
+
interface DrawerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onClick"> {
|
|
48
48
|
open: boolean;
|
|
49
|
-
/** Called by the
|
|
49
|
+
/** Called by the scrim and the Header close button. */
|
|
50
50
|
onClose: () => void;
|
|
51
51
|
/** Called on Escape. Defaults to `onClose` — override to do something else
|
|
52
52
|
* (e.g. pop one level of a panel stack before closing). */
|
|
@@ -56,7 +56,7 @@ interface DrawerProps extends Omit<DialogHTMLAttributes<HTMLDialogElement>, "tit
|
|
|
56
56
|
width?: number | string;
|
|
57
57
|
children?: ReactNode;
|
|
58
58
|
}
|
|
59
|
-
declare function DrawerRoot({ open, onClose, onEscape, side, width, style, children, ...rest }: DrawerProps): react_jsx_runtime.JSX.Element;
|
|
59
|
+
declare function DrawerRoot({ open, onClose, onEscape, side, width, style, children, ...rest }: DrawerProps): react_jsx_runtime.JSX.Element | null;
|
|
60
60
|
interface HeaderProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
|
|
61
61
|
/**
|
|
62
62
|
* Heading text — rendered as an `<h2>` and wired as the drawer's accessible
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes,
|
|
2
|
+
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, InputHTMLAttributes, RefObject, CSSProperties, ElementType } from 'react';
|
|
3
3
|
|
|
4
4
|
interface AvatarProps extends Omit<HTMLAttributes<HTMLSpanElement>, "children"> {
|
|
5
5
|
/** Name used for initials and the image alt text. */
|
|
@@ -44,9 +44,9 @@ interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
44
44
|
declare function Card({ padding, interactive, style, className, children, ...rest }: CardProps): react_jsx_runtime.JSX.Element;
|
|
45
45
|
|
|
46
46
|
type Side$1 = "left" | "right" | "bottom";
|
|
47
|
-
interface DrawerProps extends Omit<
|
|
47
|
+
interface DrawerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onClick"> {
|
|
48
48
|
open: boolean;
|
|
49
|
-
/** Called by the
|
|
49
|
+
/** Called by the scrim and the Header close button. */
|
|
50
50
|
onClose: () => void;
|
|
51
51
|
/** Called on Escape. Defaults to `onClose` — override to do something else
|
|
52
52
|
* (e.g. pop one level of a panel stack before closing). */
|
|
@@ -56,7 +56,7 @@ interface DrawerProps extends Omit<DialogHTMLAttributes<HTMLDialogElement>, "tit
|
|
|
56
56
|
width?: number | string;
|
|
57
57
|
children?: ReactNode;
|
|
58
58
|
}
|
|
59
|
-
declare function DrawerRoot({ open, onClose, onEscape, side, width, style, children, ...rest }: DrawerProps): react_jsx_runtime.JSX.Element;
|
|
59
|
+
declare function DrawerRoot({ open, onClose, onEscape, side, width, style, children, ...rest }: DrawerProps): react_jsx_runtime.JSX.Element | null;
|
|
60
60
|
interface HeaderProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
|
|
61
61
|
/**
|
|
62
62
|
* Heading text — rendered as an `<h2>` and wired as the drawer's accessible
|
package/dist/ui/index.js
CHANGED
|
@@ -305,21 +305,23 @@ function Card({
|
|
|
305
305
|
}
|
|
306
306
|
var STYLE_ID3 = "nb-synapse-drawer";
|
|
307
307
|
var RULES3 = `
|
|
308
|
+
.nb-drawer-scrim {
|
|
309
|
+
position: fixed; inset: 0; z-index: 1000;
|
|
310
|
+
display: flex; background: rgba(0, 0, 0, 0.32);
|
|
311
|
+
animation: nb-drawer-fade 200ms ease;
|
|
312
|
+
}
|
|
313
|
+
.nb-drawer-scrim--right { justify-content: flex-end; }
|
|
314
|
+
.nb-drawer-scrim--left { justify-content: flex-start; }
|
|
315
|
+
.nb-drawer-scrim--bottom { align-items: flex-end; }
|
|
308
316
|
.nb-drawer {
|
|
309
317
|
margin: 0; padding: 0; border: none; max-width: 92%;
|
|
310
318
|
height: 100%; max-height: 100%; display: flex; flex-direction: column;
|
|
319
|
+
outline: none;
|
|
311
320
|
}
|
|
312
|
-
.nb-drawer--
|
|
313
|
-
.nb-drawer--
|
|
314
|
-
.nb-drawer--
|
|
315
|
-
|
|
316
|
-
height: auto; max-height: 92%;
|
|
317
|
-
}
|
|
318
|
-
.nb-drawer--right[open] { animation: nb-drawer-in-right 240ms cubic-bezier(0.2, 0, 0, 1); }
|
|
319
|
-
.nb-drawer--left[open] { animation: nb-drawer-in-left 240ms cubic-bezier(0.2, 0, 0, 1); }
|
|
320
|
-
.nb-drawer--bottom[open] { animation: nb-drawer-in-bottom 240ms cubic-bezier(0.2, 0, 0, 1); }
|
|
321
|
-
.nb-drawer::backdrop { background: rgba(0, 0, 0, 0.32); }
|
|
322
|
-
.nb-drawer[open]::backdrop { animation: nb-drawer-fade 200ms ease; }
|
|
321
|
+
.nb-drawer--bottom { width: 100%; max-width: 100%; height: auto; max-height: 92%; }
|
|
322
|
+
.nb-drawer--right { animation: nb-drawer-in-right 240ms cubic-bezier(0.2, 0, 0, 1); }
|
|
323
|
+
.nb-drawer--left { animation: nb-drawer-in-left 240ms cubic-bezier(0.2, 0, 0, 1); }
|
|
324
|
+
.nb-drawer--bottom { animation: nb-drawer-in-bottom 240ms cubic-bezier(0.2, 0, 0, 1); }
|
|
323
325
|
@keyframes nb-drawer-in-right { from { transform: translateX(100%); } }
|
|
324
326
|
@keyframes nb-drawer-in-left { from { transform: translateX(-100%); } }
|
|
325
327
|
@keyframes nb-drawer-in-bottom { from { transform: translateY(100%); } }
|
|
@@ -329,6 +331,18 @@ var RULES3 = `
|
|
|
329
331
|
.nb-drawer-iconbtn { min-width: 44px; min-height: 44px; }
|
|
330
332
|
}
|
|
331
333
|
`;
|
|
334
|
+
function inClosedDetails(el) {
|
|
335
|
+
const details = el.closest("details:not([open])");
|
|
336
|
+
if (!details) return false;
|
|
337
|
+
const summary = details.querySelector("summary");
|
|
338
|
+
return !summary || !summary.contains(el);
|
|
339
|
+
}
|
|
340
|
+
var CANDIDATES = "a[href], button, input, select, textarea, summary, [tabindex]";
|
|
341
|
+
function tabbables(panel) {
|
|
342
|
+
return Array.from(panel.querySelectorAll(CANDIDATES)).filter(
|
|
343
|
+
(el) => el.tabIndex >= 0 && !el.matches(":disabled") && !el.closest("[hidden]") && !inClosedDetails(el) && el.type !== "hidden"
|
|
344
|
+
);
|
|
345
|
+
}
|
|
332
346
|
var DrawerContext = createContext(null);
|
|
333
347
|
function DrawerRoot({
|
|
334
348
|
open,
|
|
@@ -341,41 +355,86 @@ function DrawerRoot({
|
|
|
341
355
|
...rest
|
|
342
356
|
}) {
|
|
343
357
|
ensureStyle(STYLE_ID3, RULES3);
|
|
344
|
-
const
|
|
358
|
+
const panelRef = useRef(null);
|
|
345
359
|
const labelId = useId();
|
|
346
360
|
const [hasTitle, setHasTitle] = useState(false);
|
|
347
361
|
useEffect(() => {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
362
|
+
if (!open) return;
|
|
363
|
+
const onKey = (e) => {
|
|
364
|
+
if (e.key === "Escape") {
|
|
365
|
+
e.preventDefault();
|
|
366
|
+
(onEscape ?? onClose)();
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
window.addEventListener("keydown", onKey);
|
|
370
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
371
|
+
}, [open, onEscape, onClose]);
|
|
372
|
+
useEffect(() => {
|
|
373
|
+
if (!open) return;
|
|
374
|
+
const panel = panelRef.current;
|
|
375
|
+
const previouslyFocused = document.activeElement;
|
|
376
|
+
panel?.focus();
|
|
377
|
+
const { body } = document;
|
|
378
|
+
const prevOverflow = body.style.overflow;
|
|
379
|
+
body.style.overflow = "hidden";
|
|
380
|
+
const onKeyDown = (e) => {
|
|
381
|
+
if (e.key !== "Tab" || !panel) return;
|
|
382
|
+
const focusables = tabbables(panel);
|
|
383
|
+
if (focusables.length === 0) {
|
|
384
|
+
e.preventDefault();
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const first = focusables[0];
|
|
388
|
+
const last = focusables[focusables.length - 1];
|
|
389
|
+
const active = document.activeElement;
|
|
390
|
+
if (e.shiftKey && (active === first || active === panel)) {
|
|
391
|
+
e.preventDefault();
|
|
392
|
+
last.focus();
|
|
393
|
+
} else if (!e.shiftKey && active === last) {
|
|
394
|
+
e.preventDefault();
|
|
395
|
+
first.focus();
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
panel?.addEventListener("keydown", onKeyDown);
|
|
399
|
+
return () => {
|
|
400
|
+
panel?.removeEventListener("keydown", onKeyDown);
|
|
401
|
+
body.style.overflow = prevOverflow;
|
|
402
|
+
previouslyFocused?.focus?.();
|
|
403
|
+
};
|
|
352
404
|
}, [open]);
|
|
405
|
+
const ctxValue = useMemo(() => ({ labelId, setHasTitle }), [labelId]);
|
|
406
|
+
if (!open) return null;
|
|
353
407
|
const isBottom = side === "bottom";
|
|
354
408
|
const panelStyle = {
|
|
355
409
|
...isBottom ? { width: "100%", maxWidth: "100%" } : { width },
|
|
356
410
|
background: tokens.bg,
|
|
357
411
|
color: tokens.fg,
|
|
358
412
|
boxShadow: tokens.shadowLg,
|
|
413
|
+
outline: "none",
|
|
359
414
|
...side === "right" ? { borderLeft: `${tokens.borderWidth} solid ${tokens.border}` } : side === "left" ? { borderRight: `${tokens.borderWidth} solid ${tokens.border}` } : { borderTop: `${tokens.borderWidth} solid ${tokens.border}` },
|
|
360
415
|
...style
|
|
361
416
|
};
|
|
362
|
-
const ctxValue = useMemo(() => ({ labelId, setHasTitle }), [labelId]);
|
|
363
417
|
return /* @__PURE__ */ jsx(DrawerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx(
|
|
364
|
-
"
|
|
418
|
+
"div",
|
|
365
419
|
{
|
|
366
|
-
|
|
367
|
-
className: `nb-drawer nb-drawer--${side}`,
|
|
368
|
-
style: panelStyle,
|
|
369
|
-
"aria-labelledby": hasTitle ? labelId : void 0,
|
|
370
|
-
onCancel: (e) => {
|
|
371
|
-
e.preventDefault();
|
|
372
|
-
(onEscape ?? onClose)();
|
|
373
|
-
},
|
|
420
|
+
className: `nb-drawer-scrim nb-drawer-scrim--${side}`,
|
|
374
421
|
onClick: (e) => {
|
|
375
|
-
if (e.target ===
|
|
422
|
+
if (e.target === e.currentTarget) onClose();
|
|
376
423
|
},
|
|
377
|
-
|
|
378
|
-
|
|
424
|
+
children: /* @__PURE__ */ jsx(
|
|
425
|
+
"div",
|
|
426
|
+
{
|
|
427
|
+
ref: panelRef,
|
|
428
|
+
role: "dialog",
|
|
429
|
+
"aria-modal": "true",
|
|
430
|
+
"aria-labelledby": hasTitle ? labelId : void 0,
|
|
431
|
+
tabIndex: -1,
|
|
432
|
+
className: `nb-drawer nb-drawer--${side}`,
|
|
433
|
+
style: panelStyle,
|
|
434
|
+
...rest,
|
|
435
|
+
children
|
|
436
|
+
}
|
|
437
|
+
)
|
|
379
438
|
}
|
|
380
439
|
) });
|
|
381
440
|
}
|