@jobber/components 6.112.1 → 6.112.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.
@@ -1,74 +1,74 @@
1
- import type { ReactNode } from "react";
1
+ import type { ReactElement } from "react";
2
2
  import React from "react";
3
- import type { XOR } from "ts-xor";
3
+ import type { ButtonActionProps, PageActionButtonProps, PageActionsProps, PageBodyProps, PageComposableProps, PageHeaderContentProps, PageHeaderProps, PageIntroProps, PageLegacyProps, PageMenuProps, PageSlotProps, PageSubtitleProps, PageTitleBarProps, PageTitleProps } from "./types";
4
4
  import { type ButtonProps } from "../Button";
5
- import { type SectionProps } from "../Menu";
6
- export type ButtonActionProps = ButtonProps & {
7
- ref?: React.RefObject<HTMLDivElement | null>;
8
- };
9
- interface PageFoundationProps {
10
- readonly children: ReactNode | ReactNode[];
11
- /**
12
- * Title of the page.
13
- *
14
- * Supports any React node. If a string is provided, it will be rendered as an H1 heading.
15
- * Otherwise it will be rendered as is.
16
- *
17
- * **Important**: If you're passing a custom element, it must include an H1-level heading within it.
18
- * Ideally <Heading level={1}> should be used here.
19
- */
20
- readonly title: ReactNode;
21
- /**
22
- * TitleMetaData component to be displayed
23
- * next to the title. Only compatible with string titles.
24
- */
25
- readonly titleMetaData?: ReactNode;
26
- /**
27
- * Subtitle of the page.
28
- */
29
- readonly subtitle?: string;
30
- /**
31
- * Determines the width of the page.
32
- *
33
- * Fill makes the width grow to 100%.
34
- *
35
- * Standard caps out at 1280px.
36
- *
37
- * Narrow caps out at 1024px.
38
- *
39
- * @default standard
40
- */
41
- readonly width?: "fill" | "standard" | "narrow";
42
- /**
43
- * Page title primary action button settings.
44
- */
45
- readonly primaryAction?: ButtonActionProps;
46
- /**
47
- * Page title secondary action button settings.
48
- */
49
- readonly secondaryAction?: ButtonActionProps;
50
- /**
51
- * Page title Action menu.
52
- */
53
- readonly moreActionsMenu?: SectionProps[];
5
+ export declare function Page(props: PageLegacyProps): ReactElement;
6
+ export declare function Page(props: PageComposableProps): ReactElement;
7
+ export declare namespace Page {
8
+ var Header: typeof PageHeader;
9
+ var HeaderContent: typeof PageHeaderContent;
10
+ var TitleBar: typeof PageTitleBar;
11
+ var Title: typeof PageTitle;
12
+ var Subtitle: typeof PageSubtitle;
13
+ var Intro: typeof PageIntro;
14
+ var Actions: typeof PageActions;
15
+ var ActionPrimary: typeof PageActionPrimary;
16
+ var ActionSecondary: typeof PageActionSecondary;
17
+ var ActionMenu: typeof PageActionMenu;
18
+ var PrimaryButton: typeof PagePrimaryButton;
19
+ var SecondaryButton: typeof PageSecondaryButton;
20
+ var Menu: typeof PageMenu;
21
+ var Body: typeof PageBody;
54
22
  }
55
- interface PageWithIntroProps extends PageFoundationProps {
56
- /**
57
- * Content of the page. This supports basic markdown node types
58
- * such as `_italic_`, `**bold**`, and `[link name](url)`.
59
- */
60
- readonly intro: string;
61
- /**
62
- * Causes any markdown links in the `intro` prop to open in a new
63
- * tab, i.e. with `target="_blank"`.
64
- *
65
- * Can only be used if `intro` prop is also specified.
66
- *
67
- * Defaults to `false`.
68
- */
69
- readonly externalIntroLinks?: boolean;
70
- }
71
- export type PageProps = XOR<PageFoundationProps, PageWithIntroProps>;
72
- export declare function Page({ title, titleMetaData, intro, externalIntroLinks, subtitle, children, width, primaryAction, secondaryAction, moreActionsMenu, }: PageProps): React.JSX.Element;
73
- export declare const getActionProps: (actionProps: ButtonActionProps) => ButtonProps;
23
+ /**
24
+ * Groups the title area and actions into the page header layout.
25
+ * Place non-action content (title, subtitle) inside `Page.HeaderContent`
26
+ * and actions inside `Page.Actions`.
27
+ */
28
+ declare function PageHeader({ children, ...rest }: PageHeaderProps): React.JSX.Element;
29
+ /** Wraps the title area (title, subtitle) inside `Page.Header`. Use when the header contains more than one content element to keep them stacked vertically. */
30
+ declare function PageHeaderContent({ children, ...rest }: PageHeaderContentProps): React.JSX.Element;
31
+ /**
32
+ * Flex container for the page title and optional sibling elements such as
33
+ * status badges. Use when you need to display metadata alongside the heading.
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * <Page.TitleBar>
38
+ * <Page.Title>Clients</Page.Title>
39
+ * <StatusLabel label="Active" status="success" />
40
+ * </Page.TitleBar>
41
+ * ```
42
+ */
43
+ declare function PageTitleBar({ children, ...rest }: PageTitleBarProps): React.JSX.Element;
44
+ /**
45
+ * Renders the page heading as an H1. When metadata is present alongside the
46
+ * title, wrap both in `Page.TitleBar`.
47
+ */
48
+ declare function PageTitle({ children, ...rest }: PageTitleProps): React.JSX.Element;
49
+ /** Secondary text below the title. Always applies default Text/Emphasis styling. */
50
+ declare function PageSubtitle({ children, ...rest }: PageSubtitleProps): React.JSX.Element;
51
+ /** Introduction text between the header and body. Always applies default Text styling. */
52
+ declare function PageIntro({ children }: PageIntroProps): React.JSX.Element;
53
+ /** Container for action buttons and menu. Applies responsive actionGroup layout. */
54
+ declare function PageActions({ children, ...rest }: PageActionsProps): React.JSX.Element;
55
+ /** Positional container for the primary action. Should contain a Button element, e.g. <Page.PrimaryButton>. */
56
+ declare function PageActionPrimary({ children, ref }: PageSlotProps): React.JSX.Element;
57
+ /** Positional container for the secondary action. Should contain a Button element, e.g. <Page.SecondaryButton>. */
58
+ declare function PageActionSecondary({ children, ref }: PageSlotProps): React.JSX.Element;
59
+ /** Positional container for the menu action. Should contain Page.Menu or a custom Menu. */
60
+ declare function PageActionMenu({ children, ref }: PageSlotProps): React.JSX.Element;
61
+ /** Default primary Button with opinionated styling. Use inside Page.ActionPrimary. */
62
+ declare function PagePrimaryButton({ ref, label, onClick, icon, disabled, loading, ariaLabel, ...rest }: PageActionButtonProps): React.JSX.Element;
63
+ /** Default secondary Button with opinionated styling. Use inside Page.ActionSecondary. */
64
+ declare function PageSecondaryButton({ ref, label, onClick, icon, disabled, loading, ariaLabel, ...rest }: PageActionButtonProps): React.JSX.Element;
65
+ /**
66
+ * "More Actions" menu with a default trigger button.
67
+ * Consumers supply Menu.Item children (in case custom routing is needed,
68
+ * e.g. wrapping Menu.Item with createLink() from TanStack Router).
69
+ */
70
+ declare function PageMenu({ children, triggerLabel, ...rest }: PageMenuProps): React.JSX.Element;
71
+ /** Main content area of the page. */
72
+ declare function PageBody({ children }: PageBodyProps): React.JSX.Element;
73
+ export declare const getActionProps: (actionProps?: ButtonActionProps) => ButtonProps;
74
74
  export {};
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var Page = require('../Page-cjs.js');
4
+ require('../tslib.es6-cjs.js');
4
5
  require('react');
5
6
  require('classnames');
6
7
  require('@jobber/hooks');
@@ -14,7 +15,6 @@ require('react/jsx-runtime');
14
15
  require('../_commonjsHelpers-cjs.js');
15
16
  require('../Button-cjs.js');
16
17
  require('react-router-dom');
17
- require('../tslib.es6-cjs.js');
18
18
  require('../Icon-cjs.js');
19
19
  require('@jobber/design');
20
20
  require('../Menu-cjs.js');
@@ -25,6 +25,7 @@ require('../Tree-cjs.js');
25
25
  require('../clsx-cjs.js');
26
26
  require('../useFormFieldFocus-cjs.js');
27
27
  require('../maxHeight-cjs.js');
28
+ require('../filterDataAttributes-cjs.js');
28
29
 
29
30
 
30
31
 
@@ -1 +1,2 @@
1
- export { Page, type PageProps } from "./Page";
1
+ export { Page } from "./Page";
2
+ export type { ButtonActionProps, PageActionButtonProps, PageComposableProps, PageLegacyProps, PageMenuProps, PageProps, PageSlotProps, } from "./types";
@@ -1,4 +1,5 @@
1
1
  export { P as Page } from '../Page-es.js';
2
+ import '../tslib.es6-es.js';
2
3
  import 'react';
3
4
  import 'classnames';
4
5
  import '@jobber/hooks';
@@ -12,7 +13,6 @@ import 'react/jsx-runtime';
12
13
  import '../_commonjsHelpers-es.js';
13
14
  import '../Button-es.js';
14
15
  import 'react-router-dom';
15
- import '../tslib.es6-es.js';
16
16
  import '../Icon-es.js';
17
17
  import '@jobber/design';
18
18
  import '../Menu-es.js';
@@ -23,3 +23,4 @@ import '../Tree-es.js';
23
23
  import '../clsx-es.js';
24
24
  import '../useFormFieldFocus-es.js';
25
25
  import '../maxHeight-es.js';
26
+ import '../filterDataAttributes-es.js';
@@ -0,0 +1,120 @@
1
+ import type { ReactNode, RefObject } from "react";
2
+ import { type ButtonProps } from "../Button";
3
+ import { type SectionProps } from "../Menu";
4
+ export type ButtonActionProps = ButtonProps & {
5
+ ref?: React.RefObject<HTMLDivElement | null>;
6
+ };
7
+ interface PageBaseProps {
8
+ readonly children: ReactNode | ReactNode[];
9
+ /**
10
+ * Title of the page.
11
+ *
12
+ * Supports any React node. If a string is provided, it will be rendered as an H1 heading.
13
+ * Otherwise it will be rendered as is.
14
+ *
15
+ * **Important**: If you're passing a custom element, it must include an H1-level heading within it.
16
+ * Ideally <Heading level={1}> should be used here.
17
+ */
18
+ readonly title: ReactNode;
19
+ /**
20
+ * TitleMetaData component to be displayed
21
+ * next to the title. Only compatible with string titles.
22
+ */
23
+ readonly titleMetaData?: ReactNode;
24
+ /**
25
+ * Subtitle of the page.
26
+ */
27
+ readonly subtitle?: string;
28
+ /**
29
+ * Determines the width of the page.
30
+ *
31
+ * Fill makes the width grow to 100%.
32
+ *
33
+ * Standard caps out at 1280px.
34
+ *
35
+ * Narrow caps out at 1024px.
36
+ *
37
+ * @default standard
38
+ */
39
+ readonly width?: "fill" | "standard" | "narrow";
40
+ /**
41
+ * Page title primary action button settings.
42
+ */
43
+ readonly primaryAction?: ButtonActionProps;
44
+ /**
45
+ * Page title secondary action button settings.
46
+ */
47
+ readonly secondaryAction?: ButtonActionProps;
48
+ /**
49
+ * Page title Action menu.
50
+ */
51
+ readonly moreActionsMenu?: SectionProps[];
52
+ }
53
+ interface PageWithIntroProps extends PageBaseProps {
54
+ /**
55
+ * Content of the page. This supports basic markdown node types
56
+ * such as `_italic_`, `**bold**`, and `[link name](url)`.
57
+ */
58
+ readonly intro: string;
59
+ /**
60
+ * Causes any markdown links in the `intro` prop to open in a new
61
+ * tab, i.e. with `target="_blank"`.
62
+ *
63
+ * Can only be used if `intro` prop is also specified.
64
+ *
65
+ * Defaults to `false`.
66
+ */
67
+ readonly externalIntroLinks?: boolean;
68
+ }
69
+ interface PageWithoutIntroProps extends PageBaseProps {
70
+ readonly intro?: never;
71
+ readonly externalIntroLinks?: never;
72
+ }
73
+ export type PageLegacyProps = PageWithIntroProps | PageWithoutIntroProps;
74
+ export interface PageComposableProps {
75
+ readonly children: ReactNode;
76
+ readonly width?: "fill" | "standard" | "narrow";
77
+ }
78
+ export type PageProps = PageLegacyProps | PageComposableProps;
79
+ export interface PageHeaderProps {
80
+ readonly children: ReactNode;
81
+ }
82
+ export interface PageHeaderContentProps {
83
+ readonly children: ReactNode;
84
+ }
85
+ export interface PageTitleBarProps {
86
+ readonly children: ReactNode;
87
+ }
88
+ export interface PageTitleProps {
89
+ readonly children: ReactNode;
90
+ }
91
+ export interface PageSubtitleProps {
92
+ readonly children: ReactNode;
93
+ }
94
+ export interface PageIntroProps {
95
+ readonly children: ReactNode;
96
+ }
97
+ export interface PageActionsProps {
98
+ readonly children: ReactNode;
99
+ }
100
+ export interface PageSlotProps {
101
+ readonly children: ReactNode;
102
+ readonly ref?: RefObject<HTMLDivElement | null>;
103
+ }
104
+ export interface PageActionButtonProps {
105
+ readonly ref?: RefObject<HTMLDivElement | null>;
106
+ readonly label: string;
107
+ readonly onClick?: () => void;
108
+ readonly icon?: ButtonProps["icon"];
109
+ readonly disabled?: boolean;
110
+ readonly loading?: boolean;
111
+ readonly ariaLabel?: string;
112
+ }
113
+ export interface PageMenuProps {
114
+ readonly children: ReactNode;
115
+ readonly triggerLabel?: string;
116
+ }
117
+ export interface PageBodyProps {
118
+ readonly children: ReactNode;
119
+ }
120
+ export {};
package/dist/Page-cjs.js CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var tslib_es6 = require('./tslib.es6-cjs.js');
3
4
  var React = require('react');
4
5
  var classnames = require('classnames');
5
6
  var jobberHooks = require('@jobber/hooks');
@@ -10,11 +11,27 @@ var Markdown = require('./Markdown-cjs.js');
10
11
  var Button = require('./Button-cjs.js');
11
12
  var Menu = require('./Menu-cjs.js');
12
13
  var Emphasis = require('./Emphasis-cjs.js');
14
+ var filterDataAttributes = require('./filterDataAttributes-cjs.js');
13
15
 
14
16
  var styles = {"page":"BLYnKItuM3c-","fill":"n5WRRhMkoLs-","standard":"WziKEWW9nA8-","narrow":"qgGzgDyS2NY-","titleBar":"lbmoDvdtQO4-","titleRow":"k9y5NuqTcks-","actionGroup":"_7t53-bnzh98-","large":"SH0aNOLVhE8-","medium":"Lc7Z0FsBa6w-","small":"iF5IA1SYKoA-","primaryAction":"g-H7CKkX-LA-","actionButton":"RSP7jHjP-mw-","subtitle":"EqsNMrZVL-8-","spinning":"MJZVhEmx6h4-"};
15
17
 
16
- function Page({ title, titleMetaData, intro, externalIntroLinks, subtitle, children, width = "standard", primaryAction, secondaryAction, moreActionsMenu = [], }) {
17
- const pageStyles = classnames(styles.page, styles[width]);
18
+ /** Discriminates between the props-based API and the composable children API. */
19
+ function isLegacy(props) {
20
+ return "title" in props;
21
+ }
22
+ function Page(props) {
23
+ var _a;
24
+ const pageStyles = classnames(styles.page, styles[(_a = props.width) !== null && _a !== void 0 ? _a : "standard"]);
25
+ if (isLegacy(props)) {
26
+ return React.createElement(PageLegacy, Object.assign({}, props, { pageStyles: pageStyles }));
27
+ }
28
+ return (React.createElement("div", { className: pageStyles },
29
+ React.createElement(Content.Content, null, props.children)));
30
+ }
31
+ /** Props-based renderer. Preserves the original Page behavior for existing consumers. */
32
+ function PageLegacy(_a) {
33
+ var { title, titleMetaData, intro, externalIntroLinks, subtitle, children, primaryAction, secondaryAction, moreActionsMenu = [], pageStyles } = _a, rest = tslib_es6.__rest(_a, ["title", "titleMetaData", "intro", "externalIntroLinks", "subtitle", "children", "primaryAction", "secondaryAction", "moreActionsMenu", "pageStyles"]);
34
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
18
35
  const [titleBarRef, { width: titleBarWidth = jobberHooks.Breakpoints.large }] = jobberHooks.useResizeObserver();
19
36
  const titleBarClasses = classnames(styles.titleBar, {
20
37
  [styles.small]: titleBarWidth > jobberHooks.Breakpoints.smaller,
@@ -23,16 +40,7 @@ function Page({ title, titleMetaData, intro, externalIntroLinks, subtitle, child
23
40
  });
24
41
  const showMenu = moreActionsMenu.length > 0;
25
42
  const showActionGroup = showMenu || primaryAction || secondaryAction;
26
- if (primaryAction != undefined) {
27
- primaryAction = Object.assign({ fullWidth: true }, primaryAction);
28
- }
29
- if (secondaryAction != undefined) {
30
- secondaryAction = Object.assign({ type: "secondary", fullWidth: true }, secondaryAction);
31
- }
32
- if (secondaryAction != undefined) {
33
- secondaryAction = Object.assign({ type: "secondary", fullWidth: true }, secondaryAction);
34
- }
35
- return (React.createElement("div", { className: pageStyles },
43
+ return (React.createElement("div", Object.assign({ className: pageStyles }, dataAttrs),
36
44
  React.createElement(Content.Content, null,
37
45
  React.createElement(Content.Content, null,
38
46
  React.createElement("div", { className: titleBarClasses, ref: titleBarRef },
@@ -46,20 +54,144 @@ function Page({ title, titleMetaData, intro, externalIntroLinks, subtitle, child
46
54
  React.createElement(Markdown.Markdown, { content: subtitle, basicUsage: true })))))),
47
55
  showActionGroup && (React.createElement("div", { className: styles.actionGroup },
48
56
  primaryAction && (React.createElement("div", { className: styles.primaryAction, ref: primaryAction.ref },
49
- React.createElement(Button.Button, Object.assign({}, getActionProps(primaryAction))))),
57
+ React.createElement(Button.Button, Object.assign({}, getActionProps(primaryAction), { fullWidth: true })))),
50
58
  secondaryAction && (React.createElement("div", { className: styles.actionButton, ref: secondaryAction.ref },
51
- React.createElement(Button.Button, Object.assign({}, getActionProps(secondaryAction))))),
59
+ React.createElement(Button.Button, Object.assign({}, getActionProps(secondaryAction), { fullWidth: true, type: "secondary" })))),
52
60
  showMenu && (React.createElement("div", { className: styles.actionButton },
53
61
  React.createElement(Menu.Menu, { items: moreActionsMenu })))))),
54
62
  intro && (React.createElement(Text.Text, { size: "large" },
55
63
  React.createElement(Markdown.Markdown, { content: intro, basicUsage: true, externalLink: externalIntroLinks })))),
56
64
  React.createElement(Content.Content, null, children))));
57
65
  }
66
+ /**
67
+ * Groups the title area and actions into the page header layout.
68
+ * Place non-action content (title, subtitle) inside `Page.HeaderContent`
69
+ * and actions inside `Page.Actions`.
70
+ */
71
+ function PageHeader(_a) {
72
+ var { children } = _a, rest = tslib_es6.__rest(_a, ["children"]);
73
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
74
+ const [titleBarRef, { width: titleBarWidth = jobberHooks.Breakpoints.large }] = jobberHooks.useResizeObserver();
75
+ const titleBarClasses = classnames(styles.titleBar, {
76
+ [styles.small]: titleBarWidth > jobberHooks.Breakpoints.smaller,
77
+ [styles.medium]: titleBarWidth > jobberHooks.Breakpoints.small,
78
+ [styles.large]: titleBarWidth > jobberHooks.Breakpoints.base,
79
+ });
80
+ return (React.createElement("div", Object.assign({ className: titleBarClasses, ref: titleBarRef }, dataAttrs), children));
81
+ }
82
+ /** Wraps the title area (title, subtitle) inside `Page.Header`. Use when the header contains more than one content element to keep them stacked vertically. */
83
+ function PageHeaderContent(_a) {
84
+ var { children } = _a, rest = tslib_es6.__rest(_a, ["children"]);
85
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
86
+ return React.createElement("div", Object.assign({}, dataAttrs), children);
87
+ }
88
+ /**
89
+ * Flex container for the page title and optional sibling elements such as
90
+ * status badges. Use when you need to display metadata alongside the heading.
91
+ *
92
+ * @example
93
+ * ```tsx
94
+ * <Page.TitleBar>
95
+ * <Page.Title>Clients</Page.Title>
96
+ * <StatusLabel label="Active" status="success" />
97
+ * </Page.TitleBar>
98
+ * ```
99
+ */
100
+ function PageTitleBar(_a) {
101
+ var { children } = _a, rest = tslib_es6.__rest(_a, ["children"]);
102
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
103
+ return (React.createElement("div", Object.assign({ className: styles.titleRow }, dataAttrs), children));
104
+ }
105
+ /**
106
+ * Renders the page heading as an H1. When metadata is present alongside the
107
+ * title, wrap both in `Page.TitleBar`.
108
+ */
109
+ function PageTitle(_a) {
110
+ var { children } = _a, rest = tslib_es6.__rest(_a, ["children"]);
111
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
112
+ return (React.createElement(Heading.Heading, Object.assign({ level: 1 }, dataAttrs), children));
113
+ }
114
+ /** Secondary text below the title. Always applies default Text/Emphasis styling. */
115
+ function PageSubtitle(_a) {
116
+ var { children } = _a, rest = tslib_es6.__rest(_a, ["children"]);
117
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
118
+ return (React.createElement("div", Object.assign({ className: styles.subtitle }, dataAttrs),
119
+ React.createElement(Text.Text, { size: "large", variation: "subdued" },
120
+ React.createElement(Emphasis.Emphasis, { variation: "bold" }, children))));
121
+ }
122
+ /** Introduction text between the header and body. Always applies default Text styling. */
123
+ function PageIntro({ children }) {
124
+ return React.createElement(Text.Text, { size: "large" }, children);
125
+ }
126
+ /** Container for action buttons and menu. Applies responsive actionGroup layout. */
127
+ function PageActions(_a) {
128
+ var { children } = _a, rest = tslib_es6.__rest(_a, ["children"]);
129
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
130
+ return (React.createElement("div", Object.assign({ className: styles.actionGroup }, dataAttrs), children));
131
+ }
132
+ /** Positional container for the primary action. Should contain a Button element, e.g. <Page.PrimaryButton>. */
133
+ function PageActionPrimary({ children, ref }) {
134
+ return (React.createElement("div", { className: styles.primaryAction, ref: ref }, children));
135
+ }
136
+ /** Positional container for the secondary action. Should contain a Button element, e.g. <Page.SecondaryButton>. */
137
+ function PageActionSecondary({ children, ref }) {
138
+ return (React.createElement("div", { className: styles.actionButton, ref: ref }, children));
139
+ }
140
+ /** Positional container for the menu action. Should contain Page.Menu or a custom Menu. */
141
+ function PageActionMenu({ children, ref }) {
142
+ return (React.createElement("div", { className: styles.actionButton, ref: ref }, children));
143
+ }
144
+ /** Default primary Button with opinionated styling. Use inside Page.ActionPrimary. */
145
+ function PagePrimaryButton(_a) {
146
+ var { ref, label, onClick, icon, disabled, loading, ariaLabel } = _a, rest = tslib_es6.__rest(_a, ["ref", "label", "onClick", "icon", "disabled", "loading", "ariaLabel"]);
147
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
148
+ return (React.createElement("div", Object.assign({ ref: ref }, dataAttrs),
149
+ React.createElement(Button.Button, { label: label, onClick: onClick, icon: icon, disabled: disabled, loading: loading, ariaLabel: ariaLabel, fullWidth: true })));
150
+ }
151
+ /** Default secondary Button with opinionated styling. Use inside Page.ActionSecondary. */
152
+ function PageSecondaryButton(_a) {
153
+ var { ref, label, onClick, icon, disabled, loading, ariaLabel } = _a, rest = tslib_es6.__rest(_a, ["ref", "label", "onClick", "icon", "disabled", "loading", "ariaLabel"]);
154
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
155
+ return (React.createElement("div", Object.assign({ ref: ref }, dataAttrs),
156
+ React.createElement(Button.Button, { label: label, onClick: onClick, icon: icon, disabled: disabled, loading: loading, ariaLabel: ariaLabel, fullWidth: true, type: "secondary" })));
157
+ }
158
+ /**
159
+ * "More Actions" menu with a default trigger button.
160
+ * Consumers supply Menu.Item children (in case custom routing is needed,
161
+ * e.g. wrapping Menu.Item with createLink() from TanStack Router).
162
+ */
163
+ function PageMenu(_a) {
164
+ var { children, triggerLabel = "More Actions" } = _a, rest = tslib_es6.__rest(_a, ["children", "triggerLabel"]);
165
+ const dataAttrs = filterDataAttributes.filterDataAttributes(rest);
166
+ return (React.createElement("div", Object.assign({}, dataAttrs),
167
+ React.createElement(Menu.Menu, null,
168
+ React.createElement(Menu.Menu.Trigger, { UNSAFE_style: { display: "block" } },
169
+ React.createElement(Button.Button, { icon: "more", label: triggerLabel, type: "secondary", fullWidth: true })),
170
+ React.createElement(Menu.Menu.Content, null, children))));
171
+ }
172
+ /** Main content area of the page. */
173
+ function PageBody({ children }) {
174
+ return React.createElement(Content.Content, null, children);
175
+ }
58
176
  const getActionProps = (actionProps) => {
59
- const buttonProps = Object.assign({}, actionProps);
60
- if (actionProps.ref)
177
+ const buttonProps = (actionProps !== null && actionProps !== void 0 ? actionProps : {});
178
+ if (actionProps === null || actionProps === void 0 ? void 0 : actionProps.ref)
61
179
  delete buttonProps.ref;
62
180
  return buttonProps;
63
181
  };
182
+ Page.Header = PageHeader;
183
+ Page.HeaderContent = PageHeaderContent;
184
+ Page.TitleBar = PageTitleBar;
185
+ Page.Title = PageTitle;
186
+ Page.Subtitle = PageSubtitle;
187
+ Page.Intro = PageIntro;
188
+ Page.Actions = PageActions;
189
+ Page.ActionPrimary = PageActionPrimary;
190
+ Page.ActionSecondary = PageActionSecondary;
191
+ Page.ActionMenu = PageActionMenu;
192
+ Page.PrimaryButton = PagePrimaryButton;
193
+ Page.SecondaryButton = PageSecondaryButton;
194
+ Page.Menu = PageMenu;
195
+ Page.Body = PageBody;
64
196
 
65
197
  exports.Page = Page;
package/dist/Page-es.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { _ as __rest } from './tslib.es6-es.js';
1
2
  import React__default from 'react';
2
3
  import classnames from 'classnames';
3
4
  import { useResizeObserver, Breakpoints } from '@jobber/hooks';
@@ -8,11 +9,27 @@ import { M as Markdown } from './Markdown-es.js';
8
9
  import { B as Button } from './Button-es.js';
9
10
  import { M as Menu } from './Menu-es.js';
10
11
  import { E as Emphasis } from './Emphasis-es.js';
12
+ import { f as filterDataAttributes } from './filterDataAttributes-es.js';
11
13
 
12
14
  var styles = {"page":"BLYnKItuM3c-","fill":"n5WRRhMkoLs-","standard":"WziKEWW9nA8-","narrow":"qgGzgDyS2NY-","titleBar":"lbmoDvdtQO4-","titleRow":"k9y5NuqTcks-","actionGroup":"_7t53-bnzh98-","large":"SH0aNOLVhE8-","medium":"Lc7Z0FsBa6w-","small":"iF5IA1SYKoA-","primaryAction":"g-H7CKkX-LA-","actionButton":"RSP7jHjP-mw-","subtitle":"EqsNMrZVL-8-","spinning":"MJZVhEmx6h4-"};
13
15
 
14
- function Page({ title, titleMetaData, intro, externalIntroLinks, subtitle, children, width = "standard", primaryAction, secondaryAction, moreActionsMenu = [], }) {
15
- const pageStyles = classnames(styles.page, styles[width]);
16
+ /** Discriminates between the props-based API and the composable children API. */
17
+ function isLegacy(props) {
18
+ return "title" in props;
19
+ }
20
+ function Page(props) {
21
+ var _a;
22
+ const pageStyles = classnames(styles.page, styles[(_a = props.width) !== null && _a !== void 0 ? _a : "standard"]);
23
+ if (isLegacy(props)) {
24
+ return React__default.createElement(PageLegacy, Object.assign({}, props, { pageStyles: pageStyles }));
25
+ }
26
+ return (React__default.createElement("div", { className: pageStyles },
27
+ React__default.createElement(Content, null, props.children)));
28
+ }
29
+ /** Props-based renderer. Preserves the original Page behavior for existing consumers. */
30
+ function PageLegacy(_a) {
31
+ var { title, titleMetaData, intro, externalIntroLinks, subtitle, children, primaryAction, secondaryAction, moreActionsMenu = [], pageStyles } = _a, rest = __rest(_a, ["title", "titleMetaData", "intro", "externalIntroLinks", "subtitle", "children", "primaryAction", "secondaryAction", "moreActionsMenu", "pageStyles"]);
32
+ const dataAttrs = filterDataAttributes(rest);
16
33
  const [titleBarRef, { width: titleBarWidth = Breakpoints.large }] = useResizeObserver();
17
34
  const titleBarClasses = classnames(styles.titleBar, {
18
35
  [styles.small]: titleBarWidth > Breakpoints.smaller,
@@ -21,16 +38,7 @@ function Page({ title, titleMetaData, intro, externalIntroLinks, subtitle, child
21
38
  });
22
39
  const showMenu = moreActionsMenu.length > 0;
23
40
  const showActionGroup = showMenu || primaryAction || secondaryAction;
24
- if (primaryAction != undefined) {
25
- primaryAction = Object.assign({ fullWidth: true }, primaryAction);
26
- }
27
- if (secondaryAction != undefined) {
28
- secondaryAction = Object.assign({ type: "secondary", fullWidth: true }, secondaryAction);
29
- }
30
- if (secondaryAction != undefined) {
31
- secondaryAction = Object.assign({ type: "secondary", fullWidth: true }, secondaryAction);
32
- }
33
- return (React__default.createElement("div", { className: pageStyles },
41
+ return (React__default.createElement("div", Object.assign({ className: pageStyles }, dataAttrs),
34
42
  React__default.createElement(Content, null,
35
43
  React__default.createElement(Content, null,
36
44
  React__default.createElement("div", { className: titleBarClasses, ref: titleBarRef },
@@ -44,20 +52,144 @@ function Page({ title, titleMetaData, intro, externalIntroLinks, subtitle, child
44
52
  React__default.createElement(Markdown, { content: subtitle, basicUsage: true })))))),
45
53
  showActionGroup && (React__default.createElement("div", { className: styles.actionGroup },
46
54
  primaryAction && (React__default.createElement("div", { className: styles.primaryAction, ref: primaryAction.ref },
47
- React__default.createElement(Button, Object.assign({}, getActionProps(primaryAction))))),
55
+ React__default.createElement(Button, Object.assign({}, getActionProps(primaryAction), { fullWidth: true })))),
48
56
  secondaryAction && (React__default.createElement("div", { className: styles.actionButton, ref: secondaryAction.ref },
49
- React__default.createElement(Button, Object.assign({}, getActionProps(secondaryAction))))),
57
+ React__default.createElement(Button, Object.assign({}, getActionProps(secondaryAction), { fullWidth: true, type: "secondary" })))),
50
58
  showMenu && (React__default.createElement("div", { className: styles.actionButton },
51
59
  React__default.createElement(Menu, { items: moreActionsMenu })))))),
52
60
  intro && (React__default.createElement(Text, { size: "large" },
53
61
  React__default.createElement(Markdown, { content: intro, basicUsage: true, externalLink: externalIntroLinks })))),
54
62
  React__default.createElement(Content, null, children))));
55
63
  }
64
+ /**
65
+ * Groups the title area and actions into the page header layout.
66
+ * Place non-action content (title, subtitle) inside `Page.HeaderContent`
67
+ * and actions inside `Page.Actions`.
68
+ */
69
+ function PageHeader(_a) {
70
+ var { children } = _a, rest = __rest(_a, ["children"]);
71
+ const dataAttrs = filterDataAttributes(rest);
72
+ const [titleBarRef, { width: titleBarWidth = Breakpoints.large }] = useResizeObserver();
73
+ const titleBarClasses = classnames(styles.titleBar, {
74
+ [styles.small]: titleBarWidth > Breakpoints.smaller,
75
+ [styles.medium]: titleBarWidth > Breakpoints.small,
76
+ [styles.large]: titleBarWidth > Breakpoints.base,
77
+ });
78
+ return (React__default.createElement("div", Object.assign({ className: titleBarClasses, ref: titleBarRef }, dataAttrs), children));
79
+ }
80
+ /** Wraps the title area (title, subtitle) inside `Page.Header`. Use when the header contains more than one content element to keep them stacked vertically. */
81
+ function PageHeaderContent(_a) {
82
+ var { children } = _a, rest = __rest(_a, ["children"]);
83
+ const dataAttrs = filterDataAttributes(rest);
84
+ return React__default.createElement("div", Object.assign({}, dataAttrs), children);
85
+ }
86
+ /**
87
+ * Flex container for the page title and optional sibling elements such as
88
+ * status badges. Use when you need to display metadata alongside the heading.
89
+ *
90
+ * @example
91
+ * ```tsx
92
+ * <Page.TitleBar>
93
+ * <Page.Title>Clients</Page.Title>
94
+ * <StatusLabel label="Active" status="success" />
95
+ * </Page.TitleBar>
96
+ * ```
97
+ */
98
+ function PageTitleBar(_a) {
99
+ var { children } = _a, rest = __rest(_a, ["children"]);
100
+ const dataAttrs = filterDataAttributes(rest);
101
+ return (React__default.createElement("div", Object.assign({ className: styles.titleRow }, dataAttrs), children));
102
+ }
103
+ /**
104
+ * Renders the page heading as an H1. When metadata is present alongside the
105
+ * title, wrap both in `Page.TitleBar`.
106
+ */
107
+ function PageTitle(_a) {
108
+ var { children } = _a, rest = __rest(_a, ["children"]);
109
+ const dataAttrs = filterDataAttributes(rest);
110
+ return (React__default.createElement(Heading, Object.assign({ level: 1 }, dataAttrs), children));
111
+ }
112
+ /** Secondary text below the title. Always applies default Text/Emphasis styling. */
113
+ function PageSubtitle(_a) {
114
+ var { children } = _a, rest = __rest(_a, ["children"]);
115
+ const dataAttrs = filterDataAttributes(rest);
116
+ return (React__default.createElement("div", Object.assign({ className: styles.subtitle }, dataAttrs),
117
+ React__default.createElement(Text, { size: "large", variation: "subdued" },
118
+ React__default.createElement(Emphasis, { variation: "bold" }, children))));
119
+ }
120
+ /** Introduction text between the header and body. Always applies default Text styling. */
121
+ function PageIntro({ children }) {
122
+ return React__default.createElement(Text, { size: "large" }, children);
123
+ }
124
+ /** Container for action buttons and menu. Applies responsive actionGroup layout. */
125
+ function PageActions(_a) {
126
+ var { children } = _a, rest = __rest(_a, ["children"]);
127
+ const dataAttrs = filterDataAttributes(rest);
128
+ return (React__default.createElement("div", Object.assign({ className: styles.actionGroup }, dataAttrs), children));
129
+ }
130
+ /** Positional container for the primary action. Should contain a Button element, e.g. <Page.PrimaryButton>. */
131
+ function PageActionPrimary({ children, ref }) {
132
+ return (React__default.createElement("div", { className: styles.primaryAction, ref: ref }, children));
133
+ }
134
+ /** Positional container for the secondary action. Should contain a Button element, e.g. <Page.SecondaryButton>. */
135
+ function PageActionSecondary({ children, ref }) {
136
+ return (React__default.createElement("div", { className: styles.actionButton, ref: ref }, children));
137
+ }
138
+ /** Positional container for the menu action. Should contain Page.Menu or a custom Menu. */
139
+ function PageActionMenu({ children, ref }) {
140
+ return (React__default.createElement("div", { className: styles.actionButton, ref: ref }, children));
141
+ }
142
+ /** Default primary Button with opinionated styling. Use inside Page.ActionPrimary. */
143
+ function PagePrimaryButton(_a) {
144
+ var { ref, label, onClick, icon, disabled, loading, ariaLabel } = _a, rest = __rest(_a, ["ref", "label", "onClick", "icon", "disabled", "loading", "ariaLabel"]);
145
+ const dataAttrs = filterDataAttributes(rest);
146
+ return (React__default.createElement("div", Object.assign({ ref: ref }, dataAttrs),
147
+ React__default.createElement(Button, { label: label, onClick: onClick, icon: icon, disabled: disabled, loading: loading, ariaLabel: ariaLabel, fullWidth: true })));
148
+ }
149
+ /** Default secondary Button with opinionated styling. Use inside Page.ActionSecondary. */
150
+ function PageSecondaryButton(_a) {
151
+ var { ref, label, onClick, icon, disabled, loading, ariaLabel } = _a, rest = __rest(_a, ["ref", "label", "onClick", "icon", "disabled", "loading", "ariaLabel"]);
152
+ const dataAttrs = filterDataAttributes(rest);
153
+ return (React__default.createElement("div", Object.assign({ ref: ref }, dataAttrs),
154
+ React__default.createElement(Button, { label: label, onClick: onClick, icon: icon, disabled: disabled, loading: loading, ariaLabel: ariaLabel, fullWidth: true, type: "secondary" })));
155
+ }
156
+ /**
157
+ * "More Actions" menu with a default trigger button.
158
+ * Consumers supply Menu.Item children (in case custom routing is needed,
159
+ * e.g. wrapping Menu.Item with createLink() from TanStack Router).
160
+ */
161
+ function PageMenu(_a) {
162
+ var { children, triggerLabel = "More Actions" } = _a, rest = __rest(_a, ["children", "triggerLabel"]);
163
+ const dataAttrs = filterDataAttributes(rest);
164
+ return (React__default.createElement("div", Object.assign({}, dataAttrs),
165
+ React__default.createElement(Menu, null,
166
+ React__default.createElement(Menu.Trigger, { UNSAFE_style: { display: "block" } },
167
+ React__default.createElement(Button, { icon: "more", label: triggerLabel, type: "secondary", fullWidth: true })),
168
+ React__default.createElement(Menu.Content, null, children))));
169
+ }
170
+ /** Main content area of the page. */
171
+ function PageBody({ children }) {
172
+ return React__default.createElement(Content, null, children);
173
+ }
56
174
  const getActionProps = (actionProps) => {
57
- const buttonProps = Object.assign({}, actionProps);
58
- if (actionProps.ref)
175
+ const buttonProps = (actionProps !== null && actionProps !== void 0 ? actionProps : {});
176
+ if (actionProps === null || actionProps === void 0 ? void 0 : actionProps.ref)
59
177
  delete buttonProps.ref;
60
178
  return buttonProps;
61
179
  };
180
+ Page.Header = PageHeader;
181
+ Page.HeaderContent = PageHeaderContent;
182
+ Page.TitleBar = PageTitleBar;
183
+ Page.Title = PageTitle;
184
+ Page.Subtitle = PageSubtitle;
185
+ Page.Intro = PageIntro;
186
+ Page.Actions = PageActions;
187
+ Page.ActionPrimary = PageActionPrimary;
188
+ Page.ActionSecondary = PageActionSecondary;
189
+ Page.ActionMenu = PageActionMenu;
190
+ Page.PrimaryButton = PagePrimaryButton;
191
+ Page.SecondaryButton = PageSecondaryButton;
192
+ Page.Menu = PageMenu;
193
+ Page.Body = PageBody;
62
194
 
63
195
  export { Page as P };
@@ -158,6 +158,20 @@
158
158
  "MultiSelect",
159
159
  "Option",
160
160
  "Page",
161
+ "Page.ActionMenu",
162
+ "Page.ActionPrimary",
163
+ "Page.ActionSecondary",
164
+ "Page.Actions",
165
+ "Page.Body",
166
+ "Page.Header",
167
+ "Page.HeaderContent",
168
+ "Page.Intro",
169
+ "Page.Menu",
170
+ "Page.PrimaryButton",
171
+ "Page.SecondaryButton",
172
+ "Page.Subtitle",
173
+ "Page.Title",
174
+ "Page.TitleBar",
161
175
  "Popover",
162
176
  "Popover.Arrow",
163
177
  "Popover.DismissButton",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "6.112.1",
3
+ "version": "6.112.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -538,5 +538,5 @@
538
538
  "> 1%",
539
539
  "IE 10"
540
540
  ],
541
- "gitHead": "6a70e6fdb7ebd0925285306df14b17ba21d78679"
541
+ "gitHead": "5c6d2a8ba2313768db2fd1147c74de0b4e8c3710"
542
542
  }