@nimblebrain/synapse 0.9.0 → 0.10.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/ui/index.cjs +93 -39
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +13 -4
- package/dist/ui/index.d.ts +13 -4
- package/dist/ui/index.js +94 -40
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/index.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
43
43
|
}
|
|
44
44
|
declare function Card({ padding, interactive, style, className, children, ...rest }: CardProps): react_jsx_runtime.JSX.Element;
|
|
45
45
|
|
|
46
|
-
type Side$1 = "left" | "right";
|
|
46
|
+
type Side$1 = "left" | "right" | "bottom";
|
|
47
47
|
interface DrawerProps extends Omit<DialogHTMLAttributes<HTMLDialogElement>, "title" | "onCancel" | "onClick"> {
|
|
48
48
|
open: boolean;
|
|
49
49
|
/** Called by the backdrop and the Header close button. */
|
|
@@ -52,17 +52,26 @@ interface DrawerProps extends Omit<DialogHTMLAttributes<HTMLDialogElement>, "tit
|
|
|
52
52
|
* (e.g. pop one level of a panel stack before closing). */
|
|
53
53
|
onEscape?: () => void;
|
|
54
54
|
side?: Side$1;
|
|
55
|
-
/** Panel width. Default 480. */
|
|
55
|
+
/** Panel width (ignored for `side="bottom"`, which is full width). Default 480. */
|
|
56
56
|
width?: number | string;
|
|
57
57
|
children?: ReactNode;
|
|
58
58
|
}
|
|
59
59
|
declare function DrawerRoot({ open, onClose, onEscape, side, width, style, children, ...rest }: DrawerProps): react_jsx_runtime.JSX.Element;
|
|
60
|
-
interface HeaderProps extends HTMLAttributes<HTMLElement> {
|
|
60
|
+
interface HeaderProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
|
|
61
|
+
/**
|
|
62
|
+
* Heading text — rendered as an `<h2>` and wired as the drawer's accessible
|
|
63
|
+
* name. Renders **instead of** `children` (pass one or the other, not both).
|
|
64
|
+
*/
|
|
65
|
+
title?: ReactNode;
|
|
66
|
+
/** Show a leading back button (e.g. pop one level of a panel stack). */
|
|
67
|
+
onBack?: () => void;
|
|
68
|
+
/** Trailing controls placed before the close button. */
|
|
69
|
+
actions?: ReactNode;
|
|
61
70
|
/** Show a close button that calls this. */
|
|
62
71
|
onClose?: () => void;
|
|
63
72
|
children?: ReactNode;
|
|
64
73
|
}
|
|
65
|
-
declare function Header$1({ onClose, style, children, ...rest }: HeaderProps): react_jsx_runtime.JSX.Element;
|
|
74
|
+
declare function Header$1({ title, onBack, actions, onClose, style, children, ...rest }: HeaderProps): react_jsx_runtime.JSX.Element;
|
|
66
75
|
declare function Body$1({ style, children, ...rest }: HTMLAttributes<HTMLDivElement>): react_jsx_runtime.JSX.Element;
|
|
67
76
|
declare function Footer$1({ style, children, ...rest }: HTMLAttributes<HTMLElement>): react_jsx_runtime.JSX.Element;
|
|
68
77
|
/** `Drawer` with `.Header`, `.Body`, `.Footer` slots. */
|
package/dist/ui/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useRef, useEffect,
|
|
1
|
+
import { createContext, useRef, useId, useState, useEffect, useMemo, useContext, useLayoutEffect } from 'react';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/ui/components/Avatar.tsx
|
|
@@ -322,14 +322,25 @@ var RULES3 = `
|
|
|
322
322
|
}
|
|
323
323
|
.nb-drawer--right { margin-left: auto; }
|
|
324
324
|
.nb-drawer--left { margin-right: auto; }
|
|
325
|
+
.nb-drawer--bottom {
|
|
326
|
+
margin-top: auto; width: 100%; max-width: 100%;
|
|
327
|
+
height: auto; max-height: 92%;
|
|
328
|
+
}
|
|
325
329
|
.nb-drawer--right[open] { animation: nb-drawer-in-right 240ms cubic-bezier(0.2, 0, 0, 1); }
|
|
326
330
|
.nb-drawer--left[open] { animation: nb-drawer-in-left 240ms cubic-bezier(0.2, 0, 0, 1); }
|
|
331
|
+
.nb-drawer--bottom[open] { animation: nb-drawer-in-bottom 240ms cubic-bezier(0.2, 0, 0, 1); }
|
|
327
332
|
.nb-drawer::backdrop { background: rgba(0, 0, 0, 0.32); }
|
|
328
333
|
.nb-drawer[open]::backdrop { animation: nb-drawer-fade 200ms ease; }
|
|
329
334
|
@keyframes nb-drawer-in-right { from { transform: translateX(100%); } }
|
|
330
335
|
@keyframes nb-drawer-in-left { from { transform: translateX(-100%); } }
|
|
336
|
+
@keyframes nb-drawer-in-bottom { from { transform: translateY(100%); } }
|
|
331
337
|
@keyframes nb-drawer-fade { from { opacity: 0; } }
|
|
338
|
+
.nb-drawer-iconbtn { width: 28px; height: 28px; }
|
|
339
|
+
@media (pointer: coarse) {
|
|
340
|
+
.nb-drawer-iconbtn { min-width: 44px; min-height: 44px; }
|
|
341
|
+
}
|
|
332
342
|
`;
|
|
343
|
+
var DrawerContext = createContext(null);
|
|
333
344
|
function DrawerRoot({
|
|
334
345
|
open,
|
|
335
346
|
onClose,
|
|
@@ -342,42 +353,51 @@ function DrawerRoot({
|
|
|
342
353
|
}) {
|
|
343
354
|
ensureStyle(STYLE_ID3, RULES3);
|
|
344
355
|
const dialogRef = useRef(null);
|
|
356
|
+
const labelId = useId();
|
|
357
|
+
const [hasTitle, setHasTitle] = useState(false);
|
|
345
358
|
useEffect(() => {
|
|
346
359
|
const dialog = dialogRef.current;
|
|
347
360
|
if (!dialog || typeof dialog.showModal !== "function") return;
|
|
348
361
|
if (open && !dialog.open) dialog.showModal();
|
|
349
362
|
else if (!open && dialog.open) dialog.close();
|
|
350
363
|
}, [open]);
|
|
364
|
+
const isBottom = side === "bottom";
|
|
351
365
|
const panelStyle = {
|
|
352
|
-
width,
|
|
366
|
+
...isBottom ? { width: "100%", maxWidth: "100%" } : { width },
|
|
353
367
|
background: tokens.bg,
|
|
354
368
|
color: tokens.fg,
|
|
355
369
|
boxShadow: tokens.shadowLg,
|
|
356
|
-
...side === "right" ? { borderLeft: `${tokens.borderWidth} solid ${tokens.border}` } : { borderRight: `${tokens.borderWidth} solid ${tokens.border}` },
|
|
370
|
+
...side === "right" ? { borderLeft: `${tokens.borderWidth} solid ${tokens.border}` } : side === "left" ? { borderRight: `${tokens.borderWidth} solid ${tokens.border}` } : { borderTop: `${tokens.borderWidth} solid ${tokens.border}` },
|
|
357
371
|
...style
|
|
358
372
|
};
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
);
|
|
373
|
+
const ctxValue = useMemo(() => ({ labelId, setHasTitle }), [labelId]);
|
|
374
|
+
return /* @__PURE__ */ jsx(DrawerContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx(
|
|
375
|
+
"dialog",
|
|
376
|
+
{
|
|
377
|
+
ref: dialogRef,
|
|
378
|
+
className: `nb-drawer nb-drawer--${side}`,
|
|
379
|
+
style: panelStyle,
|
|
380
|
+
"aria-labelledby": hasTitle ? labelId : void 0,
|
|
381
|
+
onCancel: (e) => {
|
|
382
|
+
e.preventDefault();
|
|
383
|
+
(onEscape ?? onClose)();
|
|
384
|
+
},
|
|
385
|
+
onClick: (e) => {
|
|
386
|
+
if (e.target === dialogRef.current) onClose();
|
|
387
|
+
},
|
|
388
|
+
...rest,
|
|
389
|
+
children
|
|
390
|
+
}
|
|
391
|
+
) });
|
|
379
392
|
}
|
|
380
|
-
function Header({ onClose, style, children, ...rest }) {
|
|
393
|
+
function Header({ title, onBack, actions, onClose, style, children, ...rest }) {
|
|
394
|
+
const ctx = useContext(DrawerContext);
|
|
395
|
+
const hasTitle = title != null;
|
|
396
|
+
useEffect(() => {
|
|
397
|
+
if (!ctx || !hasTitle) return;
|
|
398
|
+
ctx.setHasTitle(true);
|
|
399
|
+
return () => ctx.setHasTitle(false);
|
|
400
|
+
}, [ctx, hasTitle]);
|
|
381
401
|
return /* @__PURE__ */ jsxs(
|
|
382
402
|
"header",
|
|
383
403
|
{
|
|
@@ -395,41 +415,75 @@ function Header({ onClose, style, children, ...rest }) {
|
|
|
395
415
|
},
|
|
396
416
|
...rest,
|
|
397
417
|
children: [
|
|
398
|
-
/* @__PURE__ */ jsx(
|
|
399
|
-
|
|
418
|
+
onBack ? /* @__PURE__ */ jsx(IconButton, { label: "Back", onClick: onBack, children: /* @__PURE__ */ jsx(
|
|
419
|
+
"path",
|
|
420
|
+
{
|
|
421
|
+
d: "M10 3L5 8l5 5",
|
|
422
|
+
stroke: "currentColor",
|
|
423
|
+
strokeWidth: "1.5",
|
|
424
|
+
fill: "none",
|
|
425
|
+
strokeLinecap: "round",
|
|
426
|
+
strokeLinejoin: "round"
|
|
427
|
+
}
|
|
428
|
+
) }) : null,
|
|
429
|
+
hasTitle ? /* @__PURE__ */ jsx(
|
|
430
|
+
"h2",
|
|
431
|
+
{
|
|
432
|
+
id: ctx?.labelId,
|
|
433
|
+
style: {
|
|
434
|
+
flex: 1,
|
|
435
|
+
minWidth: 0,
|
|
436
|
+
margin: 0,
|
|
437
|
+
fontFamily: tokens.fontSans,
|
|
438
|
+
fontSize: tokens.textBaseSize,
|
|
439
|
+
lineHeight: tokens.textBaseLine,
|
|
440
|
+
fontWeight: tokens.weightSemibold,
|
|
441
|
+
color: tokens.fg,
|
|
442
|
+
whiteSpace: "nowrap",
|
|
443
|
+
overflow: "hidden",
|
|
444
|
+
textOverflow: "ellipsis"
|
|
445
|
+
},
|
|
446
|
+
children: title
|
|
447
|
+
}
|
|
448
|
+
) : /* @__PURE__ */ jsx("div", { style: { flex: 1, minWidth: 0 }, children }),
|
|
449
|
+
actions ? /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", gap: "0.4rem", flexShrink: 0 }, children: actions }) : null,
|
|
450
|
+
onClose ? /* @__PURE__ */ jsx(IconButton, { label: "Close", onClick: onClose, children: /* @__PURE__ */ jsx(
|
|
451
|
+
"path",
|
|
452
|
+
{
|
|
453
|
+
d: "M4 4l8 8M12 4l-8 8",
|
|
454
|
+
stroke: "currentColor",
|
|
455
|
+
strokeWidth: "1.5",
|
|
456
|
+
strokeLinecap: "round"
|
|
457
|
+
}
|
|
458
|
+
) }) : null
|
|
400
459
|
]
|
|
401
460
|
}
|
|
402
461
|
);
|
|
403
462
|
}
|
|
404
|
-
function
|
|
463
|
+
function IconButton({
|
|
464
|
+
label,
|
|
465
|
+
onClick,
|
|
466
|
+
children
|
|
467
|
+
}) {
|
|
405
468
|
return /* @__PURE__ */ jsx(
|
|
406
469
|
"button",
|
|
407
470
|
{
|
|
408
471
|
type: "button",
|
|
409
|
-
"aria-label":
|
|
410
|
-
onClick
|
|
472
|
+
"aria-label": label,
|
|
473
|
+
onClick,
|
|
474
|
+
className: "nb-drawer-iconbtn",
|
|
411
475
|
style: {
|
|
412
476
|
flexShrink: 0,
|
|
413
477
|
display: "inline-flex",
|
|
414
478
|
alignItems: "center",
|
|
415
479
|
justifyContent: "center",
|
|
416
|
-
width: 28,
|
|
417
|
-
height: 28,
|
|
418
480
|
border: "none",
|
|
419
481
|
background: "transparent",
|
|
420
482
|
color: tokens.fgMuted,
|
|
421
483
|
cursor: "pointer",
|
|
422
484
|
borderRadius: tokens.radiusSm
|
|
423
485
|
},
|
|
424
|
-
children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", children
|
|
425
|
-
"path",
|
|
426
|
-
{
|
|
427
|
-
d: "M4 4l8 8M12 4l-8 8",
|
|
428
|
-
stroke: "currentColor",
|
|
429
|
-
strokeWidth: "1.5",
|
|
430
|
-
strokeLinecap: "round"
|
|
431
|
-
}
|
|
432
|
-
) })
|
|
486
|
+
children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", children })
|
|
433
487
|
}
|
|
434
488
|
);
|
|
435
489
|
}
|