@qeetrix/react 0.0.1 → 0.0.4
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/CHANGELOG.md +288 -0
- package/README.md +240 -4
- package/dist/accordion/accordion.d.ts +42 -0
- package/dist/accordion/accordion.js +72 -0
- package/dist/accordion/index.d.ts +2 -0
- package/dist/accordion/index.js +1 -0
- package/dist/avatar/avatar.d.ts +21 -0
- package/dist/avatar/avatar.js +43 -0
- package/dist/avatar/index.d.ts +2 -0
- package/dist/avatar/index.js +1 -0
- package/dist/badge/badge.d.ts +14 -0
- package/dist/badge/badge.js +25 -0
- package/dist/badge/index.d.ts +2 -0
- package/dist/badge/index.js +1 -0
- package/dist/box/box.d.ts +27 -0
- package/dist/box/box.js +21 -0
- package/dist/box/index.d.ts +2 -0
- package/dist/box/index.js +1 -0
- package/dist/button/button.d.ts +50 -0
- package/dist/button/button.js +78 -0
- package/dist/button/index.d.ts +2 -0
- package/dist/button/index.js +1 -0
- package/dist/card/card.d.ts +30 -0
- package/dist/card/card.js +56 -0
- package/dist/card/index.d.ts +2 -0
- package/dist/card/index.js +1 -0
- package/dist/checkbox/checkbox.d.ts +33 -0
- package/dist/checkbox/checkbox.js +61 -0
- package/dist/checkbox/index.d.ts +2 -0
- package/dist/checkbox/index.js +1 -0
- package/dist/css/accordion.css +73 -0
- package/dist/css/avatar.css +50 -0
- package/dist/css/badge.css +59 -0
- package/dist/css/box.css +163 -0
- package/dist/css/button.css +243 -0
- package/dist/css/card.css +75 -0
- package/dist/css/checkbox.css +67 -0
- package/dist/css/dialog.css +128 -0
- package/dist/css/drawer.css +129 -0
- package/dist/css/experimental/alert.css +89 -0
- package/dist/css/experimental/app-shell.css +258 -0
- package/dist/css/experimental/breadcrumb.css +67 -0
- package/dist/css/experimental/copy-button.css +13 -0
- package/dist/css/experimental/empty-state.css +63 -0
- package/dist/css/experimental/otp-input.css +84 -0
- package/dist/css/experimental/page-header.css +110 -0
- package/dist/css/experimental/password-input.css +21 -0
- package/dist/css/experimental/sidebar.css +234 -0
- package/dist/css/experimental/stat.css +115 -0
- package/dist/css/experimental/top-bar.css +299 -0
- package/dist/css/field.css +121 -0
- package/dist/css/fieldset.css +37 -0
- package/dist/css/grid.css +86 -0
- package/dist/css/heading.css +93 -0
- package/dist/css/inline.css +85 -0
- package/dist/css/input.css +108 -0
- package/dist/css/link.css +45 -0
- package/dist/css/menu.css +166 -0
- package/dist/css/popover.css +72 -0
- package/dist/css/progress.css +102 -0
- package/dist/css/radio.css +54 -0
- package/dist/css/scroll-area.css +70 -0
- package/dist/css/select.css +189 -0
- package/dist/css/separator.css +35 -0
- package/dist/css/skeleton.css +39 -0
- package/dist/css/skip-link.css +33 -0
- package/dist/css/slider.css +108 -0
- package/dist/css/spinner.css +55 -0
- package/dist/css/stack.css +76 -0
- package/dist/css/switch.css +112 -0
- package/dist/css/table.css +68 -0
- package/dist/css/tabs.css +123 -0
- package/dist/css/text-field.css +4 -0
- package/dist/css/text.css +106 -0
- package/dist/css/toast.css +115 -0
- package/dist/css/toggle.css +125 -0
- package/dist/css/tooltip.css +47 -0
- package/dist/css/visually-hidden.css +15 -0
- package/dist/dialog/dialog.d.ts +54 -0
- package/dist/dialog/dialog.js +121 -0
- package/dist/dialog/index.d.ts +2 -0
- package/dist/dialog/index.js +1 -0
- package/dist/drawer/drawer.d.ts +49 -0
- package/dist/drawer/drawer.js +102 -0
- package/dist/drawer/index.d.ts +2 -0
- package/dist/drawer/index.js +1 -0
- package/dist/experimental/alert/alert.d.ts +29 -0
- package/dist/experimental/alert/alert.js +72 -0
- package/dist/experimental/alert/index.d.ts +2 -0
- package/dist/experimental/app-shell/app-shell.d.ts +60 -0
- package/dist/experimental/app-shell/app-shell.js +224 -0
- package/dist/experimental/app-shell/index.d.ts +2 -0
- package/dist/experimental/breadcrumb/breadcrumb.d.ts +27 -0
- package/dist/experimental/breadcrumb/breadcrumb.js +48 -0
- package/dist/experimental/breadcrumb/index.d.ts +2 -0
- package/dist/experimental/copy-button/copy-button.d.ts +27 -0
- package/dist/experimental/copy-button/copy-button.js +61 -0
- package/dist/experimental/copy-button/index.d.ts +2 -0
- package/dist/experimental/empty-state/data-state.d.ts +23 -0
- package/dist/experimental/empty-state/data-state.js +40 -0
- package/dist/experimental/empty-state/empty-state.d.ts +26 -0
- package/dist/experimental/empty-state/empty-state.js +46 -0
- package/dist/experimental/empty-state/index.d.ts +3 -0
- package/dist/experimental/index.d.ts +24 -0
- package/dist/experimental/index.js +13 -0
- package/dist/experimental/otp-input/index.d.ts +2 -0
- package/dist/experimental/otp-input/otp-input.d.ts +27 -0
- package/dist/experimental/otp-input/otp-input.js +39 -0
- package/dist/experimental/page-header/index.d.ts +2 -0
- package/dist/experimental/page-header/page-header.d.ts +32 -0
- package/dist/experimental/page-header/page-header.js +73 -0
- package/dist/experimental/password-input/index.d.ts +2 -0
- package/dist/experimental/password-input/password-input.d.ts +26 -0
- package/dist/experimental/password-input/password-input.js +103 -0
- package/dist/experimental/sidebar/index.d.ts +2 -0
- package/dist/experimental/sidebar/sidebar.d.ts +64 -0
- package/dist/experimental/sidebar/sidebar.js +200 -0
- package/dist/experimental/stat/index.d.ts +2 -0
- package/dist/experimental/stat/stat.d.ts +31 -0
- package/dist/experimental/stat/stat.js +90 -0
- package/dist/experimental/top-bar/index.d.ts +2 -0
- package/dist/experimental/top-bar/top-bar.d.ts +60 -0
- package/dist/experimental/top-bar/top-bar.js +162 -0
- package/dist/field/choice.d.ts +21 -0
- package/dist/field/choice.js +67 -0
- package/dist/field/field.d.ts +31 -0
- package/dist/field/field.js +78 -0
- package/dist/field/index.d.ts +3 -0
- package/dist/field/index.js +1 -0
- package/dist/fieldset/fieldset.d.ts +19 -0
- package/dist/fieldset/fieldset.js +29 -0
- package/dist/fieldset/index.d.ts +2 -0
- package/dist/fieldset/index.js +1 -0
- package/dist/format/format.d.ts +12 -0
- package/dist/format/format.js +50 -0
- package/dist/format/index.d.ts +2 -0
- package/dist/format/index.js +1 -0
- package/dist/grid/grid.d.ts +30 -0
- package/dist/grid/grid.js +36 -0
- package/dist/grid/index.d.ts +2 -0
- package/dist/grid/index.js +1 -0
- package/dist/heading/heading.d.ts +23 -0
- package/dist/heading/heading.js +30 -0
- package/dist/heading/index.d.ts +2 -0
- package/dist/heading/index.js +1 -0
- package/dist/index.d.ts +84 -1
- package/dist/index.js +40 -0
- package/dist/inline/index.d.ts +2 -0
- package/dist/inline/index.js +1 -0
- package/dist/inline/inline.d.ts +19 -0
- package/dist/inline/inline.js +16 -0
- package/dist/input/index.d.ts +2 -0
- package/dist/input/index.js +1 -0
- package/dist/input/input.d.ts +37 -0
- package/dist/input/input.js +63 -0
- package/dist/internal/control.d.ts +9 -0
- package/dist/internal/control.js +4 -0
- package/dist/internal/cx.js +7 -0
- package/dist/internal/media.js +15 -0
- package/dist/internal/messages.d.ts +75 -0
- package/dist/internal/messages.js +61 -0
- package/dist/internal/refs.js +23 -0
- package/dist/internal/render.d.ts +6 -0
- package/dist/internal/render.js +22 -0
- package/dist/internal/space.d.ts +9 -0
- package/dist/internal/text.d.ts +5 -0
- package/dist/internal/text.js +18 -0
- package/dist/link/index.d.ts +2 -0
- package/dist/link/index.js +1 -0
- package/dist/link/link.d.ts +19 -0
- package/dist/link/link.js +32 -0
- package/dist/locales/hi.d.ts +8 -0
- package/dist/locales/hi.js +60 -0
- package/dist/menu/index.d.ts +2 -0
- package/dist/menu/index.js +1 -0
- package/dist/menu/menu.d.ts +76 -0
- package/dist/menu/menu.js +172 -0
- package/dist/popover/index.d.ts +2 -0
- package/dist/popover/index.js +1 -0
- package/dist/popover/popover.d.ts +33 -0
- package/dist/popover/popover.js +48 -0
- package/dist/progress/index.d.ts +2 -0
- package/dist/progress/index.js +1 -0
- package/dist/progress/progress.d.ts +26 -0
- package/dist/progress/progress.js +62 -0
- package/dist/provider/index.d.ts +3 -0
- package/dist/provider/index.js +1 -0
- package/dist/provider/provider.d.ts +46 -0
- package/dist/provider/provider.js +90 -0
- package/dist/radio/index.d.ts +2 -0
- package/dist/radio/index.js +1 -0
- package/dist/radio/radio.d.ts +31 -0
- package/dist/radio/radio.js +47 -0
- package/dist/scroll-area/index.d.ts +2 -0
- package/dist/scroll-area/index.js +1 -0
- package/dist/scroll-area/scroll-area.d.ts +18 -0
- package/dist/scroll-area/scroll-area.js +39 -0
- package/dist/select/index.d.ts +2 -0
- package/dist/select/index.js +1 -0
- package/dist/select/select.d.ts +36 -0
- package/dist/select/select.js +82 -0
- package/dist/separator/index.d.ts +2 -0
- package/dist/separator/index.js +1 -0
- package/dist/separator/separator.d.ts +16 -0
- package/dist/separator/separator.js +16 -0
- package/dist/skeleton/index.d.ts +2 -0
- package/dist/skeleton/index.js +1 -0
- package/dist/skeleton/skeleton.d.ts +12 -0
- package/dist/skeleton/skeleton.js +18 -0
- package/dist/skip-link/index.d.ts +2 -0
- package/dist/skip-link/index.js +1 -0
- package/dist/skip-link/skip-link.d.ts +13 -0
- package/dist/skip-link/skip-link.js +18 -0
- package/dist/slider/index.d.ts +2 -0
- package/dist/slider/index.js +1 -0
- package/dist/slider/slider.d.ts +20 -0
- package/dist/slider/slider.js +58 -0
- package/dist/spinner/index.d.ts +2 -0
- package/dist/spinner/index.js +1 -0
- package/dist/spinner/spinner.d.ts +15 -0
- package/dist/spinner/spinner.js +19 -0
- package/dist/stack/index.d.ts +2 -0
- package/dist/stack/index.js +1 -0
- package/dist/stack/stack.d.ts +17 -0
- package/dist/stack/stack.js +15 -0
- package/dist/styles.css +4548 -0
- package/dist/switch/index.d.ts +2 -0
- package/dist/switch/index.js +1 -0
- package/dist/switch/switch.d.ts +18 -0
- package/dist/switch/switch.js +31 -0
- package/dist/table/index.d.ts +2 -0
- package/dist/table/index.js +1 -0
- package/dist/table/table.d.ts +36 -0
- package/dist/table/table.js +69 -0
- package/dist/tabs/index.d.ts +2 -0
- package/dist/tabs/index.js +1 -0
- package/dist/tabs/tabs.d.ts +43 -0
- package/dist/tabs/tabs.js +66 -0
- package/dist/text/index.d.ts +3 -0
- package/dist/text/index.js +1 -0
- package/dist/text/text.d.ts +24 -0
- package/dist/text/text.js +24 -0
- package/dist/text-field/index.d.ts +2 -0
- package/dist/text-field/index.js +1 -0
- package/dist/text-field/text-field.d.ts +15 -0
- package/dist/text-field/text-field.js +43 -0
- package/dist/toast/index.d.ts +2 -0
- package/dist/toast/index.js +1 -0
- package/dist/toast/toast.d.ts +57 -0
- package/dist/toast/toast.js +124 -0
- package/dist/toggle/index.d.ts +2 -0
- package/dist/toggle/index.js +1 -0
- package/dist/toggle/toggle.d.ts +48 -0
- package/dist/toggle/toggle.js +54 -0
- package/dist/tooltip/index.d.ts +2 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/tooltip/tooltip.d.ts +26 -0
- package/dist/tooltip/tooltip.js +39 -0
- package/dist/visually-hidden/index.d.ts +2 -0
- package/dist/visually-hidden/index.js +1 -0
- package/dist/visually-hidden/visually-hidden.d.ts +8 -0
- package/dist/visually-hidden/visually-hidden.js +12 -0
- package/package.json +170 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "../internal/cx.js";
|
|
3
|
+
import { IconButton } from "../button/button.js";
|
|
4
|
+
import { useMessages } from "../provider/provider.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { createContext, use } from "react";
|
|
7
|
+
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
8
|
+
import { Dialog } from "@base-ui/react/dialog";
|
|
9
|
+
import { XIcon } from "@qeetrix/icons/icons/x";
|
|
10
|
+
// src/dialog/dialog.tsx
|
|
11
|
+
/** The ways a user dismisses a dialog, as opposed to choosing one of its actions. */
|
|
12
|
+
const DISMISSALS = /* @__PURE__ */ new Set([
|
|
13
|
+
"escape-key",
|
|
14
|
+
"outside-press",
|
|
15
|
+
"focus-out"
|
|
16
|
+
]);
|
|
17
|
+
const DialogContext = createContext({
|
|
18
|
+
intent: "standard",
|
|
19
|
+
dismissible: true
|
|
20
|
+
});
|
|
21
|
+
/** Holds a dialog's open state: `open` / `defaultOpen` / `onOpenChange(open, details)`. */
|
|
22
|
+
function Dialog$1({ intent = "standard", dismissible = intent !== "danger", modal, onOpenChange, children, ...props }) {
|
|
23
|
+
const handleOpenChange = (open, details) => {
|
|
24
|
+
if (!open && !dismissible && DISMISSALS.has(details.reason)) {
|
|
25
|
+
details.cancel();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
onOpenChange?.(open, details);
|
|
29
|
+
};
|
|
30
|
+
return /* @__PURE__ */ jsx(DialogContext, {
|
|
31
|
+
value: {
|
|
32
|
+
intent,
|
|
33
|
+
dismissible
|
|
34
|
+
},
|
|
35
|
+
children: intent === "standard" ? /* @__PURE__ */ jsx(Dialog.Root, {
|
|
36
|
+
...props,
|
|
37
|
+
modal,
|
|
38
|
+
disablePointerDismissal: !dismissible,
|
|
39
|
+
onOpenChange: handleOpenChange,
|
|
40
|
+
children
|
|
41
|
+
}) : /* @__PURE__ */ jsx(AlertDialog.Root, {
|
|
42
|
+
...props,
|
|
43
|
+
onOpenChange: handleOpenChange,
|
|
44
|
+
children
|
|
45
|
+
})
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/** Opens the dialog. Render your own control: `render={<Button tone="danger">Revoke</Button>}`. */
|
|
49
|
+
function DialogTrigger(props) {
|
|
50
|
+
const { intent } = use(DialogContext);
|
|
51
|
+
return intent === "standard" ? /* @__PURE__ */ jsx(Dialog.Trigger, { ...props }) : /* @__PURE__ */ jsx(AlertDialog.Trigger, { ...props });
|
|
52
|
+
}
|
|
53
|
+
/** Closes the dialog, e.g. Cancel: `render={<Button variant="ghost">Cancel</Button>}`. */
|
|
54
|
+
function DialogClose(props) {
|
|
55
|
+
return /* @__PURE__ */ jsx(Dialog.Close, { ...props });
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The dialog (06-component-specs.md §6): over a scrim, with the intent line, the header, then your
|
|
59
|
+
* body and footer. The close button comes last in the DOM, so initial focus lands on the first field
|
|
60
|
+
* or else the footer's first (least destructive) action.
|
|
61
|
+
*/
|
|
62
|
+
function DialogContent({ title, description, size = "md", messages, className, children, ...props }) {
|
|
63
|
+
const { intent, dismissible } = use(DialogContext);
|
|
64
|
+
const strings = useMessages("overlay", messages);
|
|
65
|
+
return /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {
|
|
66
|
+
className: "qx-dialog-backdrop",
|
|
67
|
+
"data-slot": "dialog-backdrop"
|
|
68
|
+
}), /* @__PURE__ */ jsx(Dialog.Viewport, {
|
|
69
|
+
className: "qx-dialog-viewport",
|
|
70
|
+
children: /* @__PURE__ */ jsxs(Dialog.Popup, {
|
|
71
|
+
...props,
|
|
72
|
+
className: cx("qx-dialog", className),
|
|
73
|
+
"data-slot": "dialog-popup",
|
|
74
|
+
"data-intent": intent,
|
|
75
|
+
"data-size": size,
|
|
76
|
+
"data-dismissible": dismissible ? "" : void 0,
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ jsxs("div", {
|
|
79
|
+
className: "qx-dialog-header",
|
|
80
|
+
"data-slot": "dialog-header",
|
|
81
|
+
children: [/* @__PURE__ */ jsx(Dialog.Title, {
|
|
82
|
+
className: "qx-dialog-title",
|
|
83
|
+
"data-slot": "dialog-title",
|
|
84
|
+
children: title
|
|
85
|
+
}), description != null && /* @__PURE__ */ jsx(Dialog.Description, {
|
|
86
|
+
className: "qx-dialog-description",
|
|
87
|
+
"data-slot": "dialog-description",
|
|
88
|
+
children: description
|
|
89
|
+
})]
|
|
90
|
+
}),
|
|
91
|
+
children,
|
|
92
|
+
dismissible && /* @__PURE__ */ jsx("div", {
|
|
93
|
+
className: "qx-dialog-close",
|
|
94
|
+
"data-slot": "dialog-close",
|
|
95
|
+
children: /* @__PURE__ */ jsx(Dialog.Close, { render: /* @__PURE__ */ jsx(IconButton, {
|
|
96
|
+
icon: XIcon,
|
|
97
|
+
"aria-label": strings.close,
|
|
98
|
+
size: "sm"
|
|
99
|
+
}) })
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
})
|
|
103
|
+
})] });
|
|
104
|
+
}
|
|
105
|
+
/** The dialog's content; it scrolls when the dialog reaches its maximum height. */
|
|
106
|
+
function DialogBody({ className, ...props }) {
|
|
107
|
+
return /* @__PURE__ */ jsx("div", {
|
|
108
|
+
...props,
|
|
109
|
+
className: cx("qx-dialog-body", className),
|
|
110
|
+
"data-slot": "dialog-body"
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** The actions, end-aligned: tertiary first, then the primary or destructive action. */
|
|
114
|
+
function DialogFooter({ className, ...props }) {
|
|
115
|
+
return /* @__PURE__ */ jsx("div", {
|
|
116
|
+
...props,
|
|
117
|
+
className: cx("qx-dialog-footer", className),
|
|
118
|
+
"data-slot": "dialog-footer"
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
export { Dialog$1 as Dialog, DialogBody, DialogClose, DialogContent, DialogFooter, DialogTrigger };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Dialog, DialogBody, DialogBodyProps, DialogClose, DialogCloseProps, DialogContent, DialogContentProps, DialogFooter, DialogFooterProps, DialogIntent, DialogProps, DialogSize, DialogTrigger, DialogTriggerProps } from "./dialog.js";
|
|
2
|
+
export { Dialog, DialogBody, type DialogBodyProps, DialogClose, type DialogCloseProps, DialogContent, type DialogContentProps, DialogFooter, type DialogFooterProps, type DialogIntent, type DialogProps, type DialogSize, DialogTrigger, type DialogTriggerProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Dialog, DialogBody, DialogClose, DialogContent, DialogFooter, DialogTrigger } from "./dialog.js";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { QeetrixMessages } from "../internal/messages.js";
|
|
2
|
+
import { CSSProperties, ComponentProps, ReactElement, ReactNode } from "react";
|
|
3
|
+
import { Drawer } from "@base-ui/react/drawer";
|
|
4
|
+
/** The edge a drawer opens from, in the text direction: `end` is the right edge in English. */
|
|
5
|
+
export type DrawerSide = "start" | "end";
|
|
6
|
+
export type DrawerSize = "sm" | "md" | "lg";
|
|
7
|
+
export interface DrawerProps extends Omit<Drawer.Root.Props, "swipeDirection"> {
|
|
8
|
+
/** Default `end`. Right-to-left layouts need Base UI's DirectionProvider, as its keyboard does. */
|
|
9
|
+
side?: DrawerSide;
|
|
10
|
+
}
|
|
11
|
+
export type DrawerTriggerProps = Drawer.Trigger.Props;
|
|
12
|
+
export type DrawerCloseProps = Drawer.Close.Props;
|
|
13
|
+
export interface DrawerContentProps extends Omit<Drawer.Popup.Props, "className" | "style" | "title" | "children"> {
|
|
14
|
+
/** The title; it labels the drawer. */
|
|
15
|
+
title: ReactNode;
|
|
16
|
+
/** A line under the title; it describes the drawer. */
|
|
17
|
+
description?: ReactNode;
|
|
18
|
+
/** Width: `sm` 400, `md` 560 (default) or `lg` 800px. */
|
|
19
|
+
size?: DrawerSize;
|
|
20
|
+
/** The close button's label, over QeetrixProvider's and the English default. */
|
|
21
|
+
messages?: Partial<QeetrixMessages["overlay"]>;
|
|
22
|
+
/** Placement only. */
|
|
23
|
+
className?: string;
|
|
24
|
+
style?: CSSProperties;
|
|
25
|
+
/** DrawerBody and DrawerFooter. */
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
export interface DrawerBodyProps extends Omit<Drawer.Content.Props, "className"> {
|
|
29
|
+
className?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface DrawerFooterProps extends ComponentProps<"div"> {}
|
|
32
|
+
/** Holds a drawer's open state: `open` / `defaultOpen` / `onOpenChange(open, details)`. */
|
|
33
|
+
declare function Drawer$1({ side, ...props }: DrawerProps): ReactElement;
|
|
34
|
+
/** Opens the drawer. Render your own control: `render={<Button>Edit</Button>}`. */
|
|
35
|
+
export declare function DrawerTrigger(props: DrawerTriggerProps): ReactElement;
|
|
36
|
+
/** Closes the drawer, e.g. Cancel: `render={<Button variant="ghost">Cancel</Button>}`. */
|
|
37
|
+
export declare function DrawerClose(props: DrawerCloseProps): ReactElement;
|
|
38
|
+
/**
|
|
39
|
+
* A full-height side panel (06-component-specs.md, increment 4) with a ruled header, a scrolling
|
|
40
|
+
* body and a ruled footer. Escape, an outside click and a swipe toward its edge close it. On open,
|
|
41
|
+
* focus goes to the first focusable element in the body, as in a dialog; on touch it goes to the
|
|
42
|
+
* drawer itself, so a phone's keyboard doesn't open over it.
|
|
43
|
+
*/
|
|
44
|
+
export declare function DrawerContent({ title, description, size, messages, initialFocus, ref, className, children, ...props }: DrawerContentProps): ReactElement;
|
|
45
|
+
/** The drawer's content; it scrolls, and text in it can be selected without starting a swipe. */
|
|
46
|
+
export declare function DrawerBody({ className, ...props }: DrawerBodyProps): ReactElement;
|
|
47
|
+
/** The actions, end-aligned under a rule: tertiary first, then the primary action. */
|
|
48
|
+
export declare function DrawerFooter({ className, ...props }: DrawerFooterProps): ReactElement;
|
|
49
|
+
export { Drawer$1 as Drawer };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "../internal/cx.js";
|
|
3
|
+
import { IconButton } from "../button/button.js";
|
|
4
|
+
import { useMessages } from "../provider/provider.js";
|
|
5
|
+
import { mergeRefs } from "../internal/refs.js";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { createContext, use, useRef } from "react";
|
|
8
|
+
import { useDirection } from "@base-ui/react/direction-provider";
|
|
9
|
+
import { XIcon } from "@qeetrix/icons/icons/x";
|
|
10
|
+
import { Drawer } from "@base-ui/react/drawer";
|
|
11
|
+
// src/drawer/drawer.tsx
|
|
12
|
+
const SideContext = createContext("end");
|
|
13
|
+
const FOCUSABLE = "input:not([type=\"hidden\"], :disabled), textarea:not(:disabled), select:not(:disabled), button:not(:disabled), [href], [tabindex]:not([tabindex=\"-1\"])";
|
|
14
|
+
/** Holds a drawer's open state: `open` / `defaultOpen` / `onOpenChange(open, details)`. */
|
|
15
|
+
function Drawer$1({ side = "end", ...props }) {
|
|
16
|
+
const rtl = useDirection() === "rtl";
|
|
17
|
+
const swipeDirection = side === "end" === rtl ? "left" : "right";
|
|
18
|
+
return /* @__PURE__ */ jsx(SideContext, {
|
|
19
|
+
value: side,
|
|
20
|
+
children: /* @__PURE__ */ jsx(Drawer.Root, {
|
|
21
|
+
...props,
|
|
22
|
+
swipeDirection
|
|
23
|
+
})
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/** Opens the drawer. Render your own control: `render={<Button>Edit</Button>}`. */
|
|
27
|
+
function DrawerTrigger(props) {
|
|
28
|
+
return /* @__PURE__ */ jsx(Drawer.Trigger, { ...props });
|
|
29
|
+
}
|
|
30
|
+
/** Closes the drawer, e.g. Cancel: `render={<Button variant="ghost">Cancel</Button>}`. */
|
|
31
|
+
function DrawerClose(props) {
|
|
32
|
+
return /* @__PURE__ */ jsx(Drawer.Close, { ...props });
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A full-height side panel (06-component-specs.md, increment 4) with a ruled header, a scrolling
|
|
36
|
+
* body and a ruled footer. Escape, an outside click and a swipe toward its edge close it. On open,
|
|
37
|
+
* focus goes to the first focusable element in the body, as in a dialog; on touch it goes to the
|
|
38
|
+
* drawer itself, so a phone's keyboard doesn't open over it.
|
|
39
|
+
*/
|
|
40
|
+
function DrawerContent({ title, description, size = "md", messages, initialFocus, ref, className, children, ...props }) {
|
|
41
|
+
const side = use(SideContext);
|
|
42
|
+
const strings = useMessages("overlay", messages);
|
|
43
|
+
const popup = useRef(null);
|
|
44
|
+
const firstInBody = (type) => type === "touch" || (popup.current?.querySelector(`[data-slot="drawer-body"] :is(${FOCUSABLE})`) ?? true);
|
|
45
|
+
return /* @__PURE__ */ jsxs(Drawer.Portal, { children: [/* @__PURE__ */ jsx(Drawer.Backdrop, {
|
|
46
|
+
className: "qx-drawer-backdrop",
|
|
47
|
+
"data-slot": "drawer-backdrop"
|
|
48
|
+
}), /* @__PURE__ */ jsx(Drawer.Viewport, {
|
|
49
|
+
className: "qx-drawer-viewport",
|
|
50
|
+
"data-side": side,
|
|
51
|
+
children: /* @__PURE__ */ jsxs(Drawer.Popup, {
|
|
52
|
+
...props,
|
|
53
|
+
ref: mergeRefs(ref, popup),
|
|
54
|
+
initialFocus: initialFocus ?? firstInBody,
|
|
55
|
+
className: cx("qx-drawer", className),
|
|
56
|
+
"data-slot": "drawer-popup",
|
|
57
|
+
"data-size": size,
|
|
58
|
+
children: [
|
|
59
|
+
/* @__PURE__ */ jsxs("div", {
|
|
60
|
+
className: "qx-drawer-header",
|
|
61
|
+
"data-slot": "drawer-header",
|
|
62
|
+
children: [/* @__PURE__ */ jsx(Drawer.Title, {
|
|
63
|
+
className: "qx-drawer-title",
|
|
64
|
+
"data-slot": "drawer-title",
|
|
65
|
+
children: title
|
|
66
|
+
}), description != null && /* @__PURE__ */ jsx(Drawer.Description, {
|
|
67
|
+
className: "qx-drawer-description",
|
|
68
|
+
"data-slot": "drawer-description",
|
|
69
|
+
children: description
|
|
70
|
+
})]
|
|
71
|
+
}),
|
|
72
|
+
children,
|
|
73
|
+
/* @__PURE__ */ jsx("div", {
|
|
74
|
+
className: "qx-drawer-close",
|
|
75
|
+
"data-slot": "drawer-close",
|
|
76
|
+
children: /* @__PURE__ */ jsx(Drawer.Close, { render: /* @__PURE__ */ jsx(IconButton, {
|
|
77
|
+
icon: XIcon,
|
|
78
|
+
"aria-label": strings.close,
|
|
79
|
+
size: "sm"
|
|
80
|
+
}) })
|
|
81
|
+
})
|
|
82
|
+
]
|
|
83
|
+
})
|
|
84
|
+
})] });
|
|
85
|
+
}
|
|
86
|
+
/** The drawer's content; it scrolls, and text in it can be selected without starting a swipe. */
|
|
87
|
+
function DrawerBody({ className, ...props }) {
|
|
88
|
+
return /* @__PURE__ */ jsx(Drawer.Content, {
|
|
89
|
+
...props,
|
|
90
|
+
className: cx("qx-drawer-body", className),
|
|
91
|
+
"data-slot": "drawer-body"
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** The actions, end-aligned under a rule: tertiary first, then the primary action. */
|
|
95
|
+
function DrawerFooter({ className, ...props }) {
|
|
96
|
+
return /* @__PURE__ */ jsx("div", {
|
|
97
|
+
...props,
|
|
98
|
+
className: cx("qx-drawer-footer", className),
|
|
99
|
+
"data-slot": "drawer-footer"
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
export { Drawer$1 as Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerFooter, DrawerTrigger };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Drawer, DrawerBody, DrawerBodyProps, DrawerClose, DrawerCloseProps, DrawerContent, DrawerContentProps, DrawerFooter, DrawerFooterProps, DrawerProps, DrawerSide, DrawerSize, DrawerTrigger, DrawerTriggerProps } from "./drawer.js";
|
|
2
|
+
export { Drawer, DrawerBody, type DrawerBodyProps, DrawerClose, type DrawerCloseProps, DrawerContent, type DrawerContentProps, DrawerFooter, type DrawerFooterProps, type DrawerProps, type DrawerSide, type DrawerSize, DrawerTrigger, type DrawerTriggerProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerFooter, DrawerTrigger } from "./drawer.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { QeetrixMessages } from "../../internal/messages.js";
|
|
2
|
+
import { ComponentProps, ReactElement, ReactNode } from "react";
|
|
3
|
+
export type AlertTone = "info" | "success" | "warning" | "danger";
|
|
4
|
+
export interface AlertProps extends Omit<ComponentProps<"div">, "title"> {
|
|
5
|
+
/** Default `info`. The icon and a hidden word ("Warning:") carry it, never colour alone. */
|
|
6
|
+
tone?: AlertTone;
|
|
7
|
+
/** What happened, in a few words: "Directory sync failed". */
|
|
8
|
+
title: ReactNode;
|
|
9
|
+
/** One or two sentences: why, and what to do. */
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
/** Buttons or links under the text: one primary at most. */
|
|
12
|
+
actions?: ReactNode;
|
|
13
|
+
/** Adds a Dismiss button. The product decides whether the alert comes back. */
|
|
14
|
+
onDismiss?: () => void;
|
|
15
|
+
/**
|
|
16
|
+
* Only for an alert that appears after something happens: `polite` (`role="status"`) waits its
|
|
17
|
+
* turn; `urgent` (`role="alert"`) interrupts, for errors that block the task. An alert that is
|
|
18
|
+
* there when the page loads needs neither.
|
|
19
|
+
*/
|
|
20
|
+
announce?: "polite" | "urgent";
|
|
21
|
+
/** This alert's strings, over QeetrixProvider's and the English defaults. */
|
|
22
|
+
messages?: Partial<QeetrixMessages["alert"]>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A message in the page (07-components.md, C2): above a form, inside a card, or across the top of
|
|
26
|
+
* a console page in AppShell's `notifications`. A tinted surface with the 3px status edge on its
|
|
27
|
+
* start side. It never takes focus and never disappears by itself.
|
|
28
|
+
*/
|
|
29
|
+
export declare function Alert({ tone, title, children, actions, onDismiss, announce, messages, className, ...props }: AlertProps): ReactElement;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "../../internal/cx.js";
|
|
3
|
+
import { IconButton } from "../../button/button.js";
|
|
4
|
+
import { useMessages } from "../../provider/provider.js";
|
|
5
|
+
import { VisuallyHidden } from "../../visually-hidden/visually-hidden.js";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { CircleAlertIcon } from "@qeetrix/icons/icons/circle-alert";
|
|
8
|
+
import { XIcon } from "@qeetrix/icons/icons/x";
|
|
9
|
+
import { CircleCheckIcon } from "@qeetrix/icons/icons/circle-check";
|
|
10
|
+
import { InfoIcon } from "@qeetrix/icons/icons/info";
|
|
11
|
+
import { TriangleAlertIcon } from "@qeetrix/icons/icons/triangle-alert";
|
|
12
|
+
// src/experimental/alert/alert.tsx
|
|
13
|
+
const ICONS = {
|
|
14
|
+
info: InfoIcon,
|
|
15
|
+
success: CircleCheckIcon,
|
|
16
|
+
warning: TriangleAlertIcon,
|
|
17
|
+
danger: CircleAlertIcon
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A message in the page (07-components.md, C2): above a form, inside a card, or across the top of
|
|
21
|
+
* a console page in AppShell's `notifications`. A tinted surface with the 3px status edge on its
|
|
22
|
+
* start side. It never takes focus and never disappears by itself.
|
|
23
|
+
*/
|
|
24
|
+
function Alert({ tone = "info", title, children, actions, onDismiss, announce, messages, className, ...props }) {
|
|
25
|
+
const strings = useMessages("alert", messages);
|
|
26
|
+
const Icon = ICONS[tone];
|
|
27
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
28
|
+
...props,
|
|
29
|
+
role: announce === "urgent" ? "alert" : announce === "polite" ? "status" : void 0,
|
|
30
|
+
className: cx("qx-alert", className),
|
|
31
|
+
"data-slot": "alert",
|
|
32
|
+
"data-tone": tone,
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
35
|
+
shape: "sharp",
|
|
36
|
+
size: 16,
|
|
37
|
+
"aria-hidden": true,
|
|
38
|
+
className: "qx-alert-icon"
|
|
39
|
+
}),
|
|
40
|
+
/* @__PURE__ */ jsxs("div", {
|
|
41
|
+
className: "qx-alert-body",
|
|
42
|
+
children: [
|
|
43
|
+
/* @__PURE__ */ jsxs("div", {
|
|
44
|
+
className: "qx-alert-title",
|
|
45
|
+
"data-slot": "alert-title",
|
|
46
|
+
children: [/* @__PURE__ */ jsx(VisuallyHidden, { children: `${strings[tone]}: ` }), title]
|
|
47
|
+
}),
|
|
48
|
+
children != null && /* @__PURE__ */ jsx("div", {
|
|
49
|
+
className: "qx-alert-description",
|
|
50
|
+
"data-slot": "alert-description",
|
|
51
|
+
children
|
|
52
|
+
}),
|
|
53
|
+
actions != null && /* @__PURE__ */ jsx("div", {
|
|
54
|
+
className: "qx-alert-actions",
|
|
55
|
+
"data-slot": "alert-actions",
|
|
56
|
+
children: actions
|
|
57
|
+
})
|
|
58
|
+
]
|
|
59
|
+
}),
|
|
60
|
+
onDismiss && /* @__PURE__ */ jsx(IconButton, {
|
|
61
|
+
icon: XIcon,
|
|
62
|
+
"aria-label": strings.dismiss,
|
|
63
|
+
size: "sm",
|
|
64
|
+
tone: "neutral",
|
|
65
|
+
tooltip: false,
|
|
66
|
+
onClick: onDismiss,
|
|
67
|
+
className: "qx-alert-dismiss"
|
|
68
|
+
})
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export { Alert };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { QeetrixIcon } from "../../internal/control.js";
|
|
2
|
+
import { QeetrixMessages } from "../../internal/messages.js";
|
|
3
|
+
import { ComponentProps, ReactElement, ReactNode } from "react";
|
|
4
|
+
/** The frame's density; `inherit` leaves it to the page. */
|
|
5
|
+
export type AppShellDensity = "compact" | "default" | "comfortable" | "inherit";
|
|
6
|
+
/** An end-edge panel: help, the assistant, activity. */
|
|
7
|
+
export interface AppShellDrawer {
|
|
8
|
+
id: string;
|
|
9
|
+
/** The trigger's label and the panel's title. */
|
|
10
|
+
label: string;
|
|
11
|
+
/** The trigger's icon, from `@qeetrix/icons`. */
|
|
12
|
+
icon: QeetrixIcon;
|
|
13
|
+
/** The panel's content. */
|
|
14
|
+
content: ReactNode;
|
|
15
|
+
/** A dot on the trigger: something new inside. */
|
|
16
|
+
badge?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface AppShellProps extends Omit<ComponentProps<"div">, "children"> {
|
|
19
|
+
/** The global bar: a TopBar. */
|
|
20
|
+
topBar?: ReactNode;
|
|
21
|
+
/** The navigation: a Sidebar. */
|
|
22
|
+
sidebar?: ReactNode;
|
|
23
|
+
/** End-edge panels: help, the assistant, activity. Their triggers sit in the TopBar. */
|
|
24
|
+
drawers?: AppShellDrawer[];
|
|
25
|
+
/** The open panel's id, or `null`, controlled. */
|
|
26
|
+
activeDrawer?: string | null;
|
|
27
|
+
/** The open panel when uncontrolled. Default none. */
|
|
28
|
+
defaultActiveDrawer?: string | null;
|
|
29
|
+
/** Called with the panel that opens, or `null` when it closes. */
|
|
30
|
+
onActiveDrawerChange?: (id: string | null) => void;
|
|
31
|
+
/** Page messages (Alerts) above the page header. */
|
|
32
|
+
notifications?: ReactNode;
|
|
33
|
+
/** The frame's density. Default `compact`: consoles are dense (design rules §15). */
|
|
34
|
+
density?: AppShellDensity;
|
|
35
|
+
/** The page: a PageHeader and PageContent. */
|
|
36
|
+
children?: ReactNode;
|
|
37
|
+
/** Whether the sidebar is collapsed to its icon rail, controlled. */
|
|
38
|
+
sidebarCollapsed?: boolean;
|
|
39
|
+
/** The initial collapsed state when uncontrolled. Default `false`. */
|
|
40
|
+
defaultSidebarCollapsed?: boolean;
|
|
41
|
+
/** Called with the new collapsed state. Persist it in the product, e.g. the user's settings. */
|
|
42
|
+
onSidebarCollapsedChange?: (collapsed: boolean) => void;
|
|
43
|
+
/** The main region's id, which the built-in skip link targets. Default `main`. */
|
|
44
|
+
mainId?: string;
|
|
45
|
+
/** The shell's strings, over QeetrixProvider's and the English defaults. */
|
|
46
|
+
messages?: Partial<QeetrixMessages["appShell"]>;
|
|
47
|
+
}
|
|
48
|
+
export interface AppShellState {
|
|
49
|
+
/** The sidebar is showing as its icon rail. */
|
|
50
|
+
collapsed: boolean;
|
|
51
|
+
}
|
|
52
|
+
/** The AppShell's state, for content inside its sidebar or bar. */
|
|
53
|
+
export declare function useAppShell(): AppShellState;
|
|
54
|
+
/**
|
|
55
|
+
* The frame of a Qeet console (07-components.md, C1 · Ruled): the black scope bar across the full
|
|
56
|
+
* width; the ruled navigation column, which collapses to a 48px icon rail that expands while
|
|
57
|
+
* hovered or focused; the page; and a panel on the end edge that the bar's tools open. Seams are
|
|
58
|
+
* 1px rules, never shadows. Compact by default.
|
|
59
|
+
*/
|
|
60
|
+
export declare function AppShell({ topBar, sidebar, drawers, activeDrawer, defaultActiveDrawer, onActiveDrawerChange, notifications, density, children, sidebarCollapsed, defaultSidebarCollapsed, onSidebarCollapsedChange, mainId, messages, className, ...props }: AppShellProps): ReactElement;
|