@nimblebrain/synapse 0.12.0 → 0.12.1

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.
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, DialogHTMLAttributes, InputHTMLAttributes, RefObject, CSSProperties, ElementType } from 'react';
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<DialogHTMLAttributes<HTMLDialogElement>, "title" | "onCancel" | "onClick"> {
47
+ interface DrawerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onClick"> {
48
48
  open: boolean;
49
- /** Called by the backdrop and the Header close button. */
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
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, DialogHTMLAttributes, InputHTMLAttributes, RefObject, CSSProperties, ElementType } from 'react';
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<DialogHTMLAttributes<HTMLDialogElement>, "title" | "onCancel" | "onClick"> {
47
+ interface DrawerProps extends Omit<HTMLAttributes<HTMLDivElement>, "onClick"> {
48
48
  open: boolean;
49
- /** Called by the backdrop and the Header close button. */
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--right { margin-left: auto; }
313
- .nb-drawer--left { margin-right: auto; }
314
- .nb-drawer--bottom {
315
- margin-top: auto; width: 100%; max-width: 100%;
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%); } }
@@ -341,41 +343,65 @@ function DrawerRoot({
341
343
  ...rest
342
344
  }) {
343
345
  ensureStyle(STYLE_ID3, RULES3);
344
- const dialogRef = useRef(null);
346
+ const panelRef = useRef(null);
345
347
  const labelId = useId();
346
348
  const [hasTitle, setHasTitle] = useState(false);
347
349
  useEffect(() => {
348
- const dialog = dialogRef.current;
349
- if (!dialog || typeof dialog.showModal !== "function") return;
350
- if (open && !dialog.open) dialog.showModal();
351
- else if (!open && dialog.open) dialog.close();
350
+ if (!open) return;
351
+ const onKey = (e) => {
352
+ if (e.key === "Escape") {
353
+ e.preventDefault();
354
+ (onEscape ?? onClose)();
355
+ }
356
+ };
357
+ window.addEventListener("keydown", onKey);
358
+ return () => window.removeEventListener("keydown", onKey);
359
+ }, [open, onEscape, onClose]);
360
+ useEffect(() => {
361
+ if (!open) return;
362
+ const previouslyFocused = document.activeElement;
363
+ panelRef.current?.focus();
364
+ const { body } = document;
365
+ const prevOverflow = body.style.overflow;
366
+ body.style.overflow = "hidden";
367
+ return () => {
368
+ body.style.overflow = prevOverflow;
369
+ previouslyFocused?.focus?.();
370
+ };
352
371
  }, [open]);
372
+ const ctxValue = useMemo(() => ({ labelId, setHasTitle }), [labelId]);
373
+ if (!open) return null;
353
374
  const isBottom = side === "bottom";
354
375
  const panelStyle = {
355
376
  ...isBottom ? { width: "100%", maxWidth: "100%" } : { width },
356
377
  background: tokens.bg,
357
378
  color: tokens.fg,
358
379
  boxShadow: tokens.shadowLg,
380
+ outline: "none",
359
381
  ...side === "right" ? { borderLeft: `${tokens.borderWidth} solid ${tokens.border}` } : side === "left" ? { borderRight: `${tokens.borderWidth} solid ${tokens.border}` } : { borderTop: `${tokens.borderWidth} solid ${tokens.border}` },
360
382
  ...style
361
383
  };
362
- const ctxValue = useMemo(() => ({ labelId, setHasTitle }), [labelId]);
363
384
  return /* @__PURE__ */ jsx(DrawerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx(
364
- "dialog",
385
+ "div",
365
386
  {
366
- ref: dialogRef,
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
- },
387
+ className: `nb-drawer-scrim nb-drawer-scrim--${side}`,
374
388
  onClick: (e) => {
375
- if (e.target === dialogRef.current) onClose();
389
+ if (e.target === e.currentTarget) onClose();
376
390
  },
377
- ...rest,
378
- children
391
+ children: /* @__PURE__ */ jsx(
392
+ "div",
393
+ {
394
+ ref: panelRef,
395
+ role: "dialog",
396
+ "aria-modal": "true",
397
+ "aria-labelledby": hasTitle ? labelId : void 0,
398
+ tabIndex: -1,
399
+ className: `nb-drawer nb-drawer--${side}`,
400
+ style: panelStyle,
401
+ ...rest,
402
+ children
403
+ }
404
+ )
379
405
  }
380
406
  ) });
381
407
  }