@jobber/components 8.21.1 → 8.23.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/Dialog.d.ts +1 -0
- package/Dialog.js +17 -0
- package/dist/BottomSheet-cjs.js +34 -7
- package/dist/BottomSheet-es.js +34 -8
- package/dist/CSPContext-cjs.js +69 -0
- package/dist/CSPContext-es.js +46 -0
- package/dist/Card/index.cjs +3 -0
- package/dist/Card/index.mjs +3 -0
- package/dist/ComboboxChipRemove-cjs.js +54 -211
- package/dist/ComboboxChipRemove-es.js +8 -164
- package/dist/DataDump/index.cjs +3 -0
- package/dist/DataDump/index.mjs +3 -0
- package/dist/Dialog/Dialog.d.ts +3 -0
- package/dist/Dialog/Dialog.types.d.ts +205 -0
- package/dist/Dialog/DialogBottomSheet.d.ts +28 -0
- package/dist/Dialog/DialogModal.d.ts +20 -0
- package/dist/Dialog/constants.d.ts +1 -0
- package/dist/Dialog/dialogComposableShared.d.ts +53 -0
- package/dist/Dialog/dialogReturnFocus.d.ts +43 -0
- package/dist/Dialog/index.cjs +33 -0
- package/dist/Dialog/index.d.ts +4 -0
- package/dist/Dialog/index.mjs +25 -0
- package/dist/DrawerDescription-cjs.js +410 -0
- package/dist/DrawerDescription-es.js +383 -0
- package/dist/DrawerTitle-cjs.js +116 -0
- package/dist/DrawerTitle-es.js +92 -0
- package/dist/InputNumberExperimental-cjs.js +24 -23
- package/dist/InputNumberExperimental-es.js +3 -2
- package/dist/InternalBackdrop-es.js +3 -3
- package/dist/Menu/index.cjs +3 -0
- package/dist/Menu/index.mjs +3 -0
- package/dist/Menu-cjs.js +6 -4
- package/dist/Menu-es.js +6 -4
- package/dist/MenuSubmenuTrigger-cjs.js +53 -103
- package/dist/MenuSubmenuTrigger-es.js +55 -103
- package/dist/NumberFieldInput-cjs.js +9 -9
- package/dist/NumberFieldInput-es.js +3 -3
- package/dist/Page/index.cjs +3 -0
- package/dist/Page/index.mjs +3 -0
- package/dist/ScrollAreaViewport-cjs.js +921 -960
- package/dist/ScrollAreaViewport-es.js +917 -958
- package/dist/SelectGroupLabel-cjs.js +1924 -0
- package/dist/SelectGroupLabel-es.js +1888 -0
- package/dist/SelectPrimitive-cjs.js +112 -0
- package/dist/SelectPrimitive-es.js +110 -0
- package/dist/ToolbarRootContext-cjs.js +35 -0
- package/dist/ToolbarRootContext-es.js +14 -0
- package/dist/dialogReturnFocus-cjs.js +427 -0
- package/dist/dialogReturnFocus-es.js +423 -0
- package/dist/docs/SelectPrimitive/SelectPrimitive.md +326 -0
- package/dist/docs/index.md +1 -0
- package/dist/floating-ui.react-dom-cjs.js +1 -0
- package/dist/floating-ui.react-dom-es.js +2 -2
- package/dist/floating-ui.utils.dom-es.js +1 -1
- package/dist/index.cjs +15 -7
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +12 -7
- package/dist/primitives/BottomSheet/BottomSheet.d.ts +19 -1
- package/dist/primitives/BottomSheet/BottomSheet.types.d.ts +8 -0
- package/dist/primitives/BottomSheet/index.cjs +2 -0
- package/dist/primitives/BottomSheet/index.d.ts +1 -1
- package/dist/primitives/BottomSheet/index.mjs +2 -1
- package/dist/primitives/ComboboxPrimitive/index.cjs +3 -1
- package/dist/primitives/ComboboxPrimitive/index.mjs +3 -1
- package/dist/primitives/InputNumberExperimental/index.cjs +2 -1
- package/dist/primitives/InputNumberExperimental/index.mjs +2 -1
- package/dist/primitives/SelectPrimitive/SelectPrimitive.d.ts +63 -0
- package/dist/primitives/SelectPrimitive/index.cjs +29 -0
- package/dist/primitives/SelectPrimitive/index.d.ts +2 -0
- package/dist/primitives/SelectPrimitive/index.mjs +23 -0
- package/dist/primitives/SelectPrimitive/types.d.ts +16 -0
- package/dist/primitives/index.cjs +9 -1
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.mjs +8 -2
- package/dist/primitives/mergeClassName.d.ts +12 -0
- package/dist/resolveAriaLabelledBy-cjs.js +195 -0
- package/dist/resolveAriaLabelledBy-es.js +162 -0
- package/dist/styles.css +685 -0
- package/dist/unstyledPrimitives/index.cjs +434 -259
- package/dist/unstyledPrimitives/index.d.ts +2 -0
- package/dist/unstyledPrimitives/index.mjs +425 -252
- package/dist/useButton-cjs.js +2 -0
- package/dist/useButton-es.js +3 -2
- package/dist/useCompositeListItem-es.js +4 -4
- package/dist/useLabel-cjs.js +3 -329
- package/dist/useLabel-es.js +4 -299
- package/dist/useLabelableId-cjs.js +332 -0
- package/dist/useLabelableId-es.js +300 -0
- package/dist/useRenderElement-cjs.js +3 -0
- package/dist/useRenderElement-es.js +4 -1
- package/dist/utils/meta/meta.json +11 -1
- package/package.json +2 -2
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib_es6 = require('./tslib.es6-cjs.js');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var jobberHooks = require('@jobber/hooks');
|
|
6
|
+
var classnames = require('classnames');
|
|
7
|
+
var buttonRenderAdapter = require('./buttonRenderAdapter-cjs.js');
|
|
8
|
+
var Button = require('./Button-cjs.js');
|
|
9
|
+
var ScrollAreaViewport = require('./ScrollAreaViewport-cjs.js');
|
|
10
|
+
var Heading = require('./Heading-cjs.js');
|
|
11
|
+
var BottomSheet = require('./BottomSheet-cjs.js');
|
|
12
|
+
var DrawerTitle = require('./DrawerTitle-cjs.js');
|
|
13
|
+
var useRenderElement = require('./useRenderElement-cjs.js');
|
|
14
|
+
var DrawerDescription = require('./DrawerDescription-cjs.js');
|
|
15
|
+
|
|
16
|
+
// Copied from Menu's constant so the two surfaces agree on what "mobile" means.
|
|
17
|
+
// (The proposal calls for copying shared Menu values into the component first
|
|
18
|
+
// and deciding later whether to promote them to a shared location.)
|
|
19
|
+
const SMALL_SCREEN_BREAKPOINT = 490;
|
|
20
|
+
|
|
21
|
+
var styles = {"small":"uYYyCR3l6E8-","base":"X1jGz-sLWf4-","large":"_4zFf2PkFhaA-","fullScreen":"nJoCr8oWJ7w-","header":"XFKiCQ8QbQU-","close":"FDOhnO0TT08-","scrollRegion":"_8DjYA23vHXA-","scrollViewport":"Bwr9IUYpLfM-","body":"zp9kx9uue2I-","fullBleed":"EhtwBTy1ai4-","footer":"DRIJhI1knKw-","sheetSurface":"vmcZRwOcNMo-","popup":"mFX7qDCd17I-","backdrop":"NE-BIsVE-hE-","viewport":"hp70o-3Cf-w-","spinning":"Zf-Z8DJcC-Y-"};
|
|
22
|
+
|
|
23
|
+
var actionsStyles = {"actions":"hKVNddbxkmo-","leftActions":"nslrozOH-v4-","buttonGroup":"BrXAnQBttWE-","align-left":"_9Vgd-3YJxlI-","align-right":"_8HC9NqvmJdo-","align-fullWidth":"ZZ3XuxGv6ow-","spinning":"PWf7wHPhd2A-"};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Resolves the trigger element for `Dialog.Trigger`. Copied from Menu's
|
|
27
|
+
* `resolveMenuTriggerRender` so an Atlantis `<Button>` works as a trigger via
|
|
28
|
+
* `children` or `render` identically in both shells. Raw text children are
|
|
29
|
+
* wrapped in a default `Button`.
|
|
30
|
+
*/
|
|
31
|
+
function resolveComposableTriggerRender({ children, render, }) {
|
|
32
|
+
if (render) {
|
|
33
|
+
if (typeof render === "function") {
|
|
34
|
+
return (props) => {
|
|
35
|
+
const renderedElement = render(buttonRenderAdapter.normalizeBaseUiButtonProps(props));
|
|
36
|
+
return buttonRenderAdapter.isAtlantisButtonRenderTarget(renderedElement)
|
|
37
|
+
? buttonRenderAdapter.stripNativeTypeFromButtonRenderTarget(renderedElement)
|
|
38
|
+
: renderedElement;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return buttonRenderAdapter.isAtlantisButtonRenderTarget(render)
|
|
42
|
+
? buttonRenderAdapter.renderAtlantisButtonTarget(render)
|
|
43
|
+
: render;
|
|
44
|
+
}
|
|
45
|
+
if (buttonRenderAdapter.isAtlantisButtonRenderTarget(children)) {
|
|
46
|
+
return buttonRenderAdapter.renderAtlantisButtonTarget(children);
|
|
47
|
+
}
|
|
48
|
+
if (React.isValidElement(children)) {
|
|
49
|
+
return children;
|
|
50
|
+
}
|
|
51
|
+
return buttonRenderAdapter.renderAtlantisButtonTarget(React.createElement(Button.Button, { type: "primary" },
|
|
52
|
+
React.createElement(Button.Button.Label, null, children)));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolves the dismiss element for `Dialog.Close`, mirroring
|
|
56
|
+
* `resolveComposableTriggerRender` so a custom render works in both shells.
|
|
57
|
+
* Falls back to the subtle "remove" `ButtonDismiss` when neither `render` nor
|
|
58
|
+
* `children` are supplied. An Atlantis `<Button>`/`<ButtonDismiss>` passed via
|
|
59
|
+
* `render` or `children` is adapted; any other valid element is used as-is.
|
|
60
|
+
*/
|
|
61
|
+
function resolveComposableCloseRender({ children, render, }) {
|
|
62
|
+
if (render) {
|
|
63
|
+
if (typeof render === "function") {
|
|
64
|
+
return (props) => {
|
|
65
|
+
const renderedElement = render(buttonRenderAdapter.normalizeBaseUiButtonProps(props));
|
|
66
|
+
return buttonRenderAdapter.isAtlantisButtonRenderTarget(renderedElement)
|
|
67
|
+
? buttonRenderAdapter.stripNativeTypeFromButtonRenderTarget(renderedElement)
|
|
68
|
+
: renderedElement;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return buttonRenderAdapter.isAtlantisButtonRenderTarget(render)
|
|
72
|
+
? buttonRenderAdapter.renderAtlantisButtonTarget(render)
|
|
73
|
+
: render;
|
|
74
|
+
}
|
|
75
|
+
if (buttonRenderAdapter.isAtlantisButtonRenderTarget(children)) {
|
|
76
|
+
return buttonRenderAdapter.renderAtlantisButtonTarget(children);
|
|
77
|
+
}
|
|
78
|
+
if (React.isValidElement(children)) {
|
|
79
|
+
return children;
|
|
80
|
+
}
|
|
81
|
+
return buttonRenderAdapter.renderAtlantisButtonTarget(React.createElement(Button.Button, { type: "tertiary", variation: "subtle", ariaLabel: "Close dialog" },
|
|
82
|
+
React.createElement(Button.Button.Icon, { name: "remove" })));
|
|
83
|
+
}
|
|
84
|
+
const DialogContext = React.createContext({
|
|
85
|
+
type: "dialog",
|
|
86
|
+
size: "base",
|
|
87
|
+
isMobile: false,
|
|
88
|
+
finalFocus: undefined,
|
|
89
|
+
});
|
|
90
|
+
/** Supplies the static config (type/size/isMobile/finalFocus) to the parts. */
|
|
91
|
+
function DialogProvider({ children, type, size, isMobile, finalFocus, }) {
|
|
92
|
+
return (React.createElement(DialogContext.Provider, { value: { type, size, isMobile, finalFocus } }, children));
|
|
93
|
+
}
|
|
94
|
+
/** Reads the Dialog config; throws if a part is used outside `<Dialog>`. */
|
|
95
|
+
function useDialogContext() {
|
|
96
|
+
const context = React.useContext(DialogContext);
|
|
97
|
+
return context;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* True when the current parts render inside a `Dialog.ScrollArea` (or the scroll
|
|
101
|
+
* region a `Dialog.Body` wraps itself in). Header/Footer read it to know whether
|
|
102
|
+
* they are sticky (not nested inside a `Dialog.ScrollArea`) or scroll (nested inside a `Dialog.ScrollArea`); `Dialog.Body`
|
|
103
|
+
* reads it to avoid creating a nested scroller.
|
|
104
|
+
*/
|
|
105
|
+
const DialogScrollAreaContext = React.createContext(false);
|
|
106
|
+
/** Whether the current part is nested inside a `Dialog.ScrollArea`. */
|
|
107
|
+
function useInsideDialogScrollArea() {
|
|
108
|
+
return React.useContext(DialogScrollAreaContext);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The modal's scroll region — a BaseUI `ScrollArea` that scrolls its content
|
|
112
|
+
* with the browser's native scrollbar (re-enabled in Dialog.module.css). Content
|
|
113
|
+
* placed inside it scrolls and owns the scrollbar; `Dialog.Body` used on its own
|
|
114
|
+
* wraps itself in one. (The bottom sheet uses `DialogBottomSheetScrollArea`,
|
|
115
|
+
* backed by the BottomSheet primitive's scroll area, for its fade.)
|
|
116
|
+
*/
|
|
117
|
+
function DialogScrollArea$1({ children, className, style, }) {
|
|
118
|
+
return (React.createElement(ScrollAreaViewport.ScrollAreaRoot, { className: classnames(styles.scrollRegion, className), style: style },
|
|
119
|
+
React.createElement(ScrollAreaViewport.ScrollAreaViewport, { className: styles.scrollViewport,
|
|
120
|
+
// BaseUI defaults the viewport to `overflow: scroll`; `auto` so the
|
|
121
|
+
// native scrollbar only shows when the content overflows.
|
|
122
|
+
style: { overflow: "auto" } },
|
|
123
|
+
React.createElement(DialogScrollAreaContext.Provider, { value: true }, children))));
|
|
124
|
+
}
|
|
125
|
+
/** Layout-only header row; sticky unless nested inside a `Dialog.ScrollArea`. */
|
|
126
|
+
function SharedDialogHeader(_a) {
|
|
127
|
+
var { children, className, style } = _a, rest = tslib_es6.__rest(_a, ["children", "className", "style"]);
|
|
128
|
+
const sticky = !useInsideDialogScrollArea();
|
|
129
|
+
return (React.createElement("div", Object.assign({}, rest, { className: classnames(styles.header, className), style: style, "data-sticky": sticky || undefined }), children));
|
|
130
|
+
}
|
|
131
|
+
/** Generic footer region; sticky unless nested inside a `Dialog.ScrollArea`. */
|
|
132
|
+
function SharedDialogFooter(_a) {
|
|
133
|
+
var { children, className, style } = _a, rest = tslib_es6.__rest(_a, ["children", "className", "style"]);
|
|
134
|
+
const sticky = !useInsideDialogScrollArea();
|
|
135
|
+
return (React.createElement("div", Object.assign({}, rest, { className: classnames(styles.footer, className), style: style, "data-sticky": sticky || undefined, "data-testid": "ATL-Dialog-Footer" }), children));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* The action-button layout: tertiary on the left, primary/secondary grouped on
|
|
139
|
+
* the right. Drop it inside a `Dialog.Footer`.
|
|
140
|
+
*/
|
|
141
|
+
function DialogActions(_a) {
|
|
142
|
+
var { primary, secondary, tertiary, align = "right", className, style } = _a, rest = tslib_es6.__rest(_a, ["primary", "secondary", "tertiary", "align", "className", "style"]);
|
|
143
|
+
const secondaryAction = secondary && React.isValidElement(secondary) ? (secondary) : (React.createElement(Button.Button, Object.assign({ type: "primary", variation: "subtle" }, secondary)));
|
|
144
|
+
const primaryAction = primary && React.isValidElement(primary) ? (primary) : (React.createElement(Button.Button, Object.assign({ type: "primary" }, primary)));
|
|
145
|
+
const tertiaryAction = tertiary && React.isValidElement(tertiary) ? (tertiary) : (React.createElement(Button.Button, Object.assign({ type: "secondary", variation: "destructive" }, tertiary)));
|
|
146
|
+
return (React.createElement("div", Object.assign({}, rest, { className: classnames(actionsStyles.actions, [actionsStyles[`align-${align}`]], className), style: style, "data-testid": "ATL-Dialog-Actions" }),
|
|
147
|
+
tertiary && (React.createElement("div", { className: actionsStyles.leftActions }, tertiaryAction)),
|
|
148
|
+
React.createElement("div", { className: classnames(actionsStyles.buttonGroup, actionsStyles[`align-${align}`]) },
|
|
149
|
+
secondary && secondaryAction,
|
|
150
|
+
primary && primaryAction)));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function DialogBottomSheetRoot(props) {
|
|
154
|
+
return (React.createElement(BottomSheet.BottomSheet.Root, Object.assign({}, props)));
|
|
155
|
+
}
|
|
156
|
+
function DialogBottomSheetTrigger(props) {
|
|
157
|
+
return (React.createElement(BottomSheet.BottomSheet.Trigger, Object.assign({}, props)));
|
|
158
|
+
}
|
|
159
|
+
function DialogBottomSheetContent(_a) {
|
|
160
|
+
var { children, className, style } = _a, rest = tslib_es6.__rest(_a, ["children", "className", "style"]);
|
|
161
|
+
const { type, size, finalFocus } = useDialogContext();
|
|
162
|
+
return (
|
|
163
|
+
// Opt-out of the BottomSheet's built-in scroll area.
|
|
164
|
+
// Dialog will handle the scroll area itself.
|
|
165
|
+
React.createElement(BottomSheet.BottomSheetScrollAreaContext.Provider, { value: false },
|
|
166
|
+
React.createElement(BottomSheet.BottomSheet.Popup, Object.assign({}, rest, { className: classnames(styles.sheetSurface, className), style: style, role: type, finalFocus: finalFocus, "data-dialog-variant": "sheet", "data-size": size }), children)));
|
|
167
|
+
}
|
|
168
|
+
function DialogBottomSheetTitle(_a) {
|
|
169
|
+
var { children } = _a, rest = tslib_es6.__rest(_a, ["children"]);
|
|
170
|
+
return (React.createElement(DrawerTitle.DrawerTitle, Object.assign({}, rest, { render: titleProps => (React.createElement(Heading.Heading, Object.assign({ level: 2 }, titleProps), children)) })));
|
|
171
|
+
}
|
|
172
|
+
function DialogBottomSheetClose(_a) {
|
|
173
|
+
var { children, render } = _a, rest = tslib_es6.__rest(_a, ["children", "render"]);
|
|
174
|
+
const closeProps = useRenderElement.mergeProps({ className: styles.close }, Object.assign({}, rest));
|
|
175
|
+
return (React.createElement(DrawerTitle.DrawerClose, Object.assign({}, closeProps, { render: resolveComposableCloseRender({ children, render }) })));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The sheet's scroll region — backed by the BottomSheet primitive's styled
|
|
179
|
+
* scroll area (native scrollbar + bottom fade). Marks its content as inside a
|
|
180
|
+
* scroll area so a nested `Dialog.Body` renders plain and sticky regions know
|
|
181
|
+
* they scroll.
|
|
182
|
+
*/
|
|
183
|
+
function DialogBottomSheetScrollArea({ children, className, style, }) {
|
|
184
|
+
return (React.createElement(BottomSheet.BottomSheet.ScrollArea, { className: className, style: style },
|
|
185
|
+
React.createElement(DialogScrollAreaContext.Provider, { value: true }, children)));
|
|
186
|
+
}
|
|
187
|
+
function DialogBottomSheetBody(_a) {
|
|
188
|
+
var { children, fullBleed = false, className, style } = _a, rest = tslib_es6.__rest(_a, ["children", "fullBleed", "className", "style"]);
|
|
189
|
+
const insideScrollArea = useInsideDialogScrollArea();
|
|
190
|
+
// Owns padding and the accessible-description wiring. By default it is the
|
|
191
|
+
// scroll region (wraps itself in the sheet's scroll area); inside an explicit
|
|
192
|
+
// `Dialog.ScrollArea` it renders as plain content (no nested scroller).
|
|
193
|
+
const content = (React.createElement(DrawerDescription.DrawerDescription, { render: descriptionProps => (React.createElement("div", Object.assign({}, rest, descriptionProps, { className: classnames(styles.body, { [styles.fullBleed]: fullBleed }, className), style: style }), children)) }));
|
|
194
|
+
return insideScrollArea ? (content) : (React.createElement(DialogBottomSheetScrollArea, null, content));
|
|
195
|
+
}
|
|
196
|
+
/** Mobile shell: a bottom sheet built on the BottomSheet/Drawer primitives. */
|
|
197
|
+
const DialogBottomSheet = Object.assign(DialogBottomSheetRoot, {
|
|
198
|
+
Trigger: DialogBottomSheetTrigger,
|
|
199
|
+
Content: DialogBottomSheetContent,
|
|
200
|
+
Header: SharedDialogHeader,
|
|
201
|
+
Title: DialogBottomSheetTitle,
|
|
202
|
+
Close: DialogBottomSheetClose,
|
|
203
|
+
Body: DialogBottomSheetBody,
|
|
204
|
+
Footer: SharedDialogFooter,
|
|
205
|
+
ScrollArea: DialogBottomSheetScrollArea,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
function DialogModalRoot(props) {
|
|
209
|
+
return React.createElement(ScrollAreaViewport.DialogRoot, Object.assign({}, props));
|
|
210
|
+
}
|
|
211
|
+
function DialogModalTrigger(_a) {
|
|
212
|
+
var { children, render, handle, payload, className, style } = _a, rest = tslib_es6.__rest(_a, ["children", "render", "handle", "payload", "className", "style"]);
|
|
213
|
+
return (React.createElement(ScrollAreaViewport.DialogTrigger, Object.assign({}, rest, { handle: handle, payload: payload, className: className, style: style, render: resolveComposableTriggerRender({ children, render }) })));
|
|
214
|
+
}
|
|
215
|
+
function DialogModalContent(_a) {
|
|
216
|
+
var { children, className, style } = _a, rest = tslib_es6.__rest(_a, ["children", "className", "style"]);
|
|
217
|
+
const { type, size, finalFocus } = useDialogContext();
|
|
218
|
+
return (React.createElement(ScrollAreaViewport.DialogPortal, null,
|
|
219
|
+
React.createElement(DrawerDescription.DialogBackdrop, { forceRender: true, className: styles.backdrop, "data-testid": "ATL-Dialog-Backdrop" }),
|
|
220
|
+
React.createElement(DrawerDescription.DialogViewport, { className: styles.viewport },
|
|
221
|
+
React.createElement(DrawerDescription.DialogPopup, Object.assign({}, rest, { className: classnames(styles.popup, styles[size], className), style: style, role: type, finalFocus: finalFocus, "data-dialog-variant": "modal" }), children))));
|
|
222
|
+
}
|
|
223
|
+
function DialogModalTitle(_a) {
|
|
224
|
+
var { children } = _a, rest = tslib_es6.__rest(_a, ["children"]);
|
|
225
|
+
return (React.createElement(DrawerTitle.DialogTitle, Object.assign({}, rest, { render: titleProps => (React.createElement(Heading.Heading, Object.assign({ level: 2 }, titleProps), children)) })));
|
|
226
|
+
}
|
|
227
|
+
function DialogModalClose(_a) {
|
|
228
|
+
var { children, render } = _a, rest = tslib_es6.__rest(_a, ["children", "render"]);
|
|
229
|
+
const closeProps = useRenderElement.mergeProps({ className: styles.close }, Object.assign({}, rest));
|
|
230
|
+
return (React.createElement(DrawerTitle.DialogClose, Object.assign({}, closeProps, { render: resolveComposableCloseRender({ children, render }) })));
|
|
231
|
+
}
|
|
232
|
+
function DialogModalBody(_a) {
|
|
233
|
+
var { children, fullBleed = false, className, style } = _a, rest = tslib_es6.__rest(_a, ["children", "fullBleed", "className", "style"]);
|
|
234
|
+
const insideScrollArea = useInsideDialogScrollArea();
|
|
235
|
+
// Owns padding and the accessible-description wiring. On its own the body is
|
|
236
|
+
// the scroll region, so it wraps itself in a `DialogScrollArea`; inside an
|
|
237
|
+
// explicit `Dialog.ScrollArea` it renders as plain content (no nested scroller).
|
|
238
|
+
const content = (React.createElement(DrawerDescription.DialogDescription, { render: descriptionProps => (React.createElement("div", Object.assign({}, rest, descriptionProps, { className: classnames(styles.body, { [styles.fullBleed]: fullBleed }, className), style: style }), children)) }));
|
|
239
|
+
return insideScrollArea ? (content) : (React.createElement(DialogScrollArea$1, null, content));
|
|
240
|
+
}
|
|
241
|
+
const DialogModal = Object.assign(DialogModalRoot, {
|
|
242
|
+
Trigger: DialogModalTrigger,
|
|
243
|
+
Content: DialogModalContent,
|
|
244
|
+
Header: SharedDialogHeader,
|
|
245
|
+
Title: DialogModalTitle,
|
|
246
|
+
Close: DialogModalClose,
|
|
247
|
+
Body: DialogModalBody,
|
|
248
|
+
Footer: SharedDialogFooter,
|
|
249
|
+
// The modal keeps the plain native-scrollbar scroll region.
|
|
250
|
+
ScrollArea: DialogScrollArea$1,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Creates a handle that opens/closes a `Dialog` from detached triggers (e.g. an
|
|
255
|
+
* action inside a `Combobox`/`Menu`) without prop-drilling open state. Mirrors
|
|
256
|
+
* BaseUI's `Dialog.createHandle()`.
|
|
257
|
+
*/
|
|
258
|
+
function createHandle() {
|
|
259
|
+
return DrawerDescription.createDialogHandle();
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Returns the active shell — the bottom sheet on mobile, otherwise the centered
|
|
263
|
+
* modal. Each shell is a root component with
|
|
264
|
+
* its parts attached, so callers do `const Shell = useDialogShell()` then render
|
|
265
|
+
* `<Shell.Whatever />`.
|
|
266
|
+
*/
|
|
267
|
+
function useDialogShell() {
|
|
268
|
+
const { isMobile } = useDialogContext();
|
|
269
|
+
return isMobile ? DialogBottomSheet : DialogModal;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* The Dialog root is a centered modal on
|
|
273
|
+
* desktop, a bottom sheet on mobile. Compose it with `Dialog.Trigger`,
|
|
274
|
+
* `Dialog.Content`, and the layout parts.
|
|
275
|
+
*/
|
|
276
|
+
function DialogRoot(_a) {
|
|
277
|
+
var { onRequestClose, size = "base", type = "dialog", finalFocus, children, onOpenChange } = _a, rest = tslib_es6.__rest(_a, ["onRequestClose", "size", "type", "finalFocus", "children", "onOpenChange"]);
|
|
278
|
+
function handleOpenChange(nextOpen, eventDetails) {
|
|
279
|
+
if (!nextOpen) {
|
|
280
|
+
onRequestClose === null || onRequestClose === void 0 ? void 0 : onRequestClose(eventDetails);
|
|
281
|
+
}
|
|
282
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen, eventDetails);
|
|
283
|
+
}
|
|
284
|
+
const { width } = jobberHooks.useWindowDimensions();
|
|
285
|
+
const isMobile = width !== undefined && width <= SMALL_SCREEN_BREAKPOINT;
|
|
286
|
+
// The shell is the root component; its parts are reached via `useDialogShell`
|
|
287
|
+
// in each part below (the Menu pattern).
|
|
288
|
+
const RootComponent = isMobile ? DialogBottomSheet : DialogModal;
|
|
289
|
+
const rootProps = Object.assign(Object.assign({}, rest), { onOpenChange: handleOpenChange, modal: true, disablePointerDismissal: type === "alertdialog", children });
|
|
290
|
+
return (React.createElement(DialogProvider, { type: type, size: size, isMobile: isMobile, finalFocus: finalFocus },
|
|
291
|
+
React.createElement(RootComponent, Object.assign({}, rootProps))));
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Opens the dialog. Accepts an Atlantis `<Button>` (via `children` or `render`)
|
|
295
|
+
* or links a detached `Dialog` through a matching `handle`.
|
|
296
|
+
*/
|
|
297
|
+
function DialogTrigger(props) {
|
|
298
|
+
const Shell = useDialogShell();
|
|
299
|
+
return React.createElement(Shell.Trigger, Object.assign({}, props));
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* The dialog popup surface. Holds the `Header`, `Body`, and `Footer`; renders as a
|
|
303
|
+
* centered modal on desktop and a bottom sheet on mobile.
|
|
304
|
+
*/
|
|
305
|
+
function DialogContent(props) {
|
|
306
|
+
const Shell = useDialogShell();
|
|
307
|
+
return React.createElement(Shell.Content, Object.assign({}, props));
|
|
308
|
+
}
|
|
309
|
+
/** Layout-only header row — typically a `Dialog.Title` and a `Dialog.Close`. */
|
|
310
|
+
function DialogHeader(props) {
|
|
311
|
+
const Shell = useDialogShell();
|
|
312
|
+
return React.createElement(Shell.Header, Object.assign({}, props));
|
|
313
|
+
}
|
|
314
|
+
/** The dialog's accessible title; wired to `aria-labelledby`. */
|
|
315
|
+
function DialogTitle(props) {
|
|
316
|
+
const Shell = useDialogShell();
|
|
317
|
+
return React.createElement(Shell.Title, Object.assign({}, props));
|
|
318
|
+
}
|
|
319
|
+
/** A dismiss button that closes the dialog. */
|
|
320
|
+
function DialogClose(props) {
|
|
321
|
+
const Shell = useDialogShell();
|
|
322
|
+
return React.createElement(Shell.Close, Object.assign({}, props));
|
|
323
|
+
}
|
|
324
|
+
/** The dialog body; wired to `aria-describedby`. */
|
|
325
|
+
function DialogBody(props) {
|
|
326
|
+
const Shell = useDialogShell();
|
|
327
|
+
return React.createElement(Shell.Body, Object.assign({}, props));
|
|
328
|
+
}
|
|
329
|
+
/** Footer region for actions or supporting content. */
|
|
330
|
+
function DialogFooter(props) {
|
|
331
|
+
const Shell = useDialogShell();
|
|
332
|
+
return React.createElement(Shell.Footer, Object.assign({}, props));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Advanced scroll region. Delegates to the shell: the modal uses a native
|
|
336
|
+
* scrollbar; the sheet uses the BottomSheet primitive's scroll area (with fade).
|
|
337
|
+
*/
|
|
338
|
+
function DialogScrollArea(props) {
|
|
339
|
+
const Shell = useDialogShell();
|
|
340
|
+
return React.createElement(Shell.ScrollArea, Object.assign({}, props));
|
|
341
|
+
}
|
|
342
|
+
const Dialog = DialogRoot;
|
|
343
|
+
Dialog.Trigger = DialogTrigger;
|
|
344
|
+
Dialog.Content = DialogContent;
|
|
345
|
+
Dialog.Header = DialogHeader;
|
|
346
|
+
Dialog.Title = DialogTitle;
|
|
347
|
+
Dialog.Close = DialogClose;
|
|
348
|
+
Dialog.Body = DialogBody;
|
|
349
|
+
Dialog.Footer = DialogFooter;
|
|
350
|
+
Dialog.Actions = DialogActions;
|
|
351
|
+
Dialog.ScrollArea = DialogScrollArea;
|
|
352
|
+
Dialog.createHandle = createHandle;
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Selector for elements that can receive focus. Mirrors the common
|
|
356
|
+
* "focus-trap"/"tabbable" baseline without pulling in a dependency: anything
|
|
357
|
+
* natively focusable plus explicit positive/zero tabindex, minus disabled
|
|
358
|
+
* controls and `tabindex="-1"`.
|
|
359
|
+
*/
|
|
360
|
+
const FOCUSABLE_SELECTOR = [
|
|
361
|
+
"a[href]",
|
|
362
|
+
"area[href]",
|
|
363
|
+
"button:not([disabled])",
|
|
364
|
+
"input:not([disabled]):not([type='hidden'])",
|
|
365
|
+
"select:not([disabled])",
|
|
366
|
+
"textarea:not([disabled])",
|
|
367
|
+
"iframe",
|
|
368
|
+
"audio[controls]",
|
|
369
|
+
"video[controls]",
|
|
370
|
+
"[contenteditable]:not([contenteditable='false'])",
|
|
371
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
372
|
+
].join(",");
|
|
373
|
+
function isVisible(element) {
|
|
374
|
+
if (typeof element.checkVisibility === "function") {
|
|
375
|
+
return element.checkVisibility();
|
|
376
|
+
}
|
|
377
|
+
return Boolean(element.offsetWidth ||
|
|
378
|
+
element.offsetHeight ||
|
|
379
|
+
element.getClientRects().length);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* The first focusable element within `container` (the container itself counts if
|
|
383
|
+
* it is focusable). Skips hidden elements. Returns `null` when nothing inside is
|
|
384
|
+
* focusable.
|
|
385
|
+
*/
|
|
386
|
+
function getFirstFocusableWithin(container) {
|
|
387
|
+
var _a;
|
|
388
|
+
if (!container)
|
|
389
|
+
return null;
|
|
390
|
+
if (container.matches(FOCUSABLE_SELECTOR) && isVisible(container)) {
|
|
391
|
+
return container;
|
|
392
|
+
}
|
|
393
|
+
const candidates = Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
394
|
+
return (_a = candidates.find(isVisible)) !== null && _a !== void 0 ? _a : null;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Builds a `finalFocus` callback for `Dialog` that keeps keyboard focus near the
|
|
398
|
+
* trigger even when the trigger unmounts while the dialog is open (e.g. an
|
|
399
|
+
* autocomplete "Create" action whose row is replaced by a card on save).
|
|
400
|
+
*
|
|
401
|
+
* Resolution order on close:
|
|
402
|
+
* 1. the `trigger`, if it is still connected;
|
|
403
|
+
* 2. otherwise the first focusable element inside `boundary` (the "closest"
|
|
404
|
+
* landing spot);
|
|
405
|
+
* 3. otherwise `null`, which lets BaseUI fall back to its default behavior.
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* const triggerRef = useRef<HTMLInputElement>(null);
|
|
409
|
+
* const boundaryRef = useRef<HTMLDivElement>(null);
|
|
410
|
+
* <div ref={boundaryRef}>…</div>
|
|
411
|
+
* <Dialog
|
|
412
|
+
* handle={handle}
|
|
413
|
+
* finalFocus={getDialogReturnFocus({ trigger: triggerRef, boundary: boundaryRef })}
|
|
414
|
+
* >
|
|
415
|
+
*/
|
|
416
|
+
function getDialogReturnFocus({ trigger, boundary, }) {
|
|
417
|
+
return () => {
|
|
418
|
+
const target = trigger === null || trigger === void 0 ? void 0 : trigger.current;
|
|
419
|
+
if (target === null || target === void 0 ? void 0 : target.isConnected)
|
|
420
|
+
return target;
|
|
421
|
+
return getFirstFocusableWithin(boundary.current);
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
exports.Dialog = Dialog;
|
|
426
|
+
exports.getDialogReturnFocus = getDialogReturnFocus;
|
|
427
|
+
exports.getFirstFocusableWithin = getFirstFocusableWithin;
|