@dbcdk/react-components 0.0.10 → 0.0.13

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.
Files changed (106) hide show
  1. package/dist/components/accordion/Accordion.d.ts +2 -2
  2. package/dist/components/accordion/Accordion.js +34 -41
  3. package/dist/components/accordion/Accordion.module.css +13 -72
  4. package/dist/components/accordion/components/AccordionRow.d.ts +10 -0
  5. package/dist/components/accordion/components/AccordionRow.js +51 -0
  6. package/dist/components/accordion/components/AccordionRow.module.css +82 -0
  7. package/dist/components/breadcrumbs/Breadcrumbs.module.css +0 -1
  8. package/dist/components/button/Button.module.css +7 -7
  9. package/dist/components/card/Card.d.ts +15 -6
  10. package/dist/components/card/Card.js +39 -13
  11. package/dist/components/card/Card.module.css +22 -28
  12. package/dist/components/card/components/CardMeta.d.ts +15 -0
  13. package/dist/components/card/components/CardMeta.js +20 -0
  14. package/dist/components/card/components/CardMeta.module.css +51 -0
  15. package/dist/components/card-container/CardContainer.js +1 -1
  16. package/dist/components/card-container/CardContainer.module.css +3 -1
  17. package/dist/components/chip/Chip.module.css +7 -2
  18. package/dist/components/circle/Circle.d.ts +2 -1
  19. package/dist/components/circle/Circle.js +2 -2
  20. package/dist/components/circle/Circle.module.css +6 -2
  21. package/dist/components/code-block/CodeBlock.js +1 -1
  22. package/dist/components/code-block/CodeBlock.module.css +30 -17
  23. package/dist/components/copy-button/CopyButton.d.ts +1 -0
  24. package/dist/components/copy-button/CopyButton.js +10 -2
  25. package/dist/components/datetime-picker/DateTimePicker.d.ts +33 -8
  26. package/dist/components/datetime-picker/DateTimePicker.js +119 -78
  27. package/dist/components/datetime-picker/DateTimePicker.module.css +2 -0
  28. package/dist/components/datetime-picker/dateTimeHelpers.d.ts +15 -3
  29. package/dist/components/datetime-picker/dateTimeHelpers.js +137 -23
  30. package/dist/components/filter-field/FilterField.js +16 -11
  31. package/dist/components/filter-field/FilterField.module.css +137 -16
  32. package/dist/components/forms/checkbox/Checkbox.d.ts +2 -2
  33. package/dist/components/forms/checkbox-group/CheckboxGroup.js +1 -1
  34. package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +1 -1
  35. package/dist/components/forms/form-select/FormSelect.d.ts +35 -0
  36. package/dist/components/forms/form-select/FormSelect.js +86 -0
  37. package/dist/components/forms/form-select/FormSelect.module.css +236 -0
  38. package/dist/components/forms/input/Input.d.ts +0 -3
  39. package/dist/components/forms/input/Input.js +1 -4
  40. package/dist/components/forms/input/Input.module.css +8 -7
  41. package/dist/components/forms/input-container/InputContainer.module.css +1 -1
  42. package/dist/components/forms/radio-buttons/RadioButtons.module.css +1 -0
  43. package/dist/components/forms/select/Select.js +55 -16
  44. package/dist/components/hyperlink/Hyperlink.d.ts +19 -7
  45. package/dist/components/hyperlink/Hyperlink.js +35 -11
  46. package/dist/components/hyperlink/Hyperlink.module.css +50 -2
  47. package/dist/components/interval-select/IntervalSelect.d.ts +9 -2
  48. package/dist/components/interval-select/IntervalSelect.js +21 -6
  49. package/dist/components/menu/Menu.d.ts +29 -0
  50. package/dist/components/menu/Menu.js +61 -16
  51. package/dist/components/menu/Menu.module.css +73 -5
  52. package/dist/components/overlay/modal/Modal.module.css +4 -3
  53. package/dist/components/overlay/modal/provider/ModalProvider.js +1 -3
  54. package/dist/components/overlay/side-panel/SidePanel.js +18 -1
  55. package/dist/components/overlay/side-panel/SidePanel.module.css +1 -3
  56. package/dist/components/overlay/tooltip/useTooltipTrigger.js +4 -2
  57. package/dist/components/page-layout/PageLayout.d.ts +16 -4
  58. package/dist/components/page-layout/PageLayout.js +57 -28
  59. package/dist/components/page-layout/PageLayout.module.css +153 -33
  60. package/dist/components/popover/Popover.d.ts +17 -4
  61. package/dist/components/popover/Popover.js +147 -65
  62. package/dist/components/popover/Popover.module.css +5 -0
  63. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +22 -18
  64. package/dist/components/sidebar/providers/SidebarProvider.d.ts +4 -1
  65. package/dist/components/sidebar/providers/SidebarProvider.js +66 -18
  66. package/dist/components/split-button/SplitButton.d.ts +1 -1
  67. package/dist/components/split-button/SplitButton.js +3 -1
  68. package/dist/components/split-button/SplitButton.module.css +4 -4
  69. package/dist/components/split-pane/SplitPane.d.ts +10 -24
  70. package/dist/components/split-pane/SplitPane.js +83 -54
  71. package/dist/components/split-pane/SplitPane.module.css +11 -6
  72. package/dist/components/split-pane/provider/SplitPaneContext.js +5 -11
  73. package/dist/components/state-page/StatePage.module.css +1 -1
  74. package/dist/components/sticky-footer-layout/StickyFooterLayout.d.ts +3 -8
  75. package/dist/components/sticky-footer-layout/StickyFooterLayout.js +57 -20
  76. package/dist/components/table/Table.d.ts +8 -8
  77. package/dist/components/table/Table.js +37 -79
  78. package/dist/components/table/Table.module.css +62 -46
  79. package/dist/components/table/{tanstack.d.ts → TanstackTable.d.ts} +7 -3
  80. package/dist/components/table/TanstackTable.js +84 -0
  81. package/dist/components/table/components/column-resizer/ColumnResizer.js +1 -1
  82. package/dist/components/table/components/column-resizer/ColumnResizer.module.css +17 -7
  83. package/dist/components/table/components/table-settings/TableSettings.d.ts +13 -3
  84. package/dist/components/table/components/table-settings/TableSettings.js +55 -4
  85. package/dist/components/table/table.utils.d.ts +17 -0
  86. package/dist/components/table/table.utils.js +61 -0
  87. package/dist/components/table/tanstackTable.utils.d.ts +22 -0
  88. package/dist/components/table/tanstackTable.utils.js +104 -0
  89. package/dist/components/tabs/Tabs.d.ts +35 -12
  90. package/dist/components/tabs/Tabs.js +114 -26
  91. package/dist/components/tabs/Tabs.module.css +158 -71
  92. package/dist/hooks/useTableSettings.d.ts +23 -4
  93. package/dist/hooks/useTableSettings.js +64 -17
  94. package/dist/index.d.ts +1 -1
  95. package/dist/index.js +1 -1
  96. package/dist/src/styles/styles.css +38 -23
  97. package/dist/styles/animation.d.ts +5 -0
  98. package/dist/styles/animation.js +5 -0
  99. package/dist/styles/styles.css +38 -23
  100. package/dist/styles/themes/dbc/base.css +136 -0
  101. package/dist/styles/themes/dbc/dark.css +39 -202
  102. package/dist/styles/themes/dbc/light.css +17 -174
  103. package/dist/utils/localStorage.utils.d.ts +19 -0
  104. package/dist/utils/localStorage.utils.js +78 -0
  105. package/package.json +4 -4
  106. package/dist/components/table/tanstack.js +0 -162
@@ -1,3 +1,4 @@
1
+ /* Menu.module.css */
1
2
  .container {
2
3
  list-style: none;
3
4
  margin: 0;
@@ -17,6 +18,7 @@
17
18
  display: contents;
18
19
  }
19
20
 
21
+ /* Applied to actual interactive elements (button/a/custom that forwards className) */
20
22
  .interactive {
21
23
  display: flex;
22
24
  align-items: center;
@@ -27,7 +29,7 @@
27
29
  text-decoration: none;
28
30
 
29
31
  /* choose your density */
30
- padding-block: calc(var(--spacing-xs) + var(--density-comfortable));
32
+ padding-block: var(--spacing-xs);
31
33
  padding-inline: var(--spacing-md);
32
34
 
33
35
  background: transparent;
@@ -45,29 +47,95 @@
45
47
  color var(--transition-fast) var(--ease-standard);
46
48
  }
47
49
 
48
- .interactive:hover {
50
+ /*
51
+ Applied to the immediate child of <li> even if it's NOT an interactive element (e.g. a <div>)
52
+ so that menu row styling still works for components that render a wrapper.
53
+ */
54
+ .interactiveChild {
55
+ display: block;
56
+ inline-size: 100%;
57
+ border-radius: var(--border-radius-sm);
58
+ }
59
+
60
+ /* NEW: make wrapper-children (Checkbox/Radio) look/space like menu rows */
61
+ .row > .interactiveChild {
62
+ display: flex;
63
+ align-items: center;
64
+ inline-size: 100%;
65
+ padding-block: var(--spacing-xxs);
66
+ padding-inline: var(--spacing-md);
67
+ border-radius: var(--border-radius-sm);
68
+ }
69
+
70
+ /* NEW: let Checkbox/Radio consume full width so the hover area feels right */
71
+ .row > .interactiveChild > * {
72
+ inline-size: 100%;
73
+ }
74
+
75
+ /* NEW: add consistent gap between control and label inside Checkbox/Radio
76
+ Both components use a root element with className={styles.container}.
77
+ Because they're CSS modules, we must target it with :global(.container). */
78
+ .row :global(.container) {
79
+ display: flex;
80
+ align-items: center;
81
+ gap: var(--spacing-sm);
82
+ }
83
+
84
+ /* Hover: support both cases (interactive element, or wrapper child) */
85
+ .interactive:hover,
86
+ .row:hover > .interactiveChild {
49
87
  background-color: var(--color-bg-hover-subtle);
50
88
  }
51
89
 
90
+ /* Focus ring: support both cases */
52
91
  .interactive:focus-visible {
53
92
  outline: none;
54
93
  box-shadow: var(--focus-ring);
55
94
  }
56
95
 
96
+ /* If wrapper contains a focusable element, show ring when any child is focused */
97
+ .row:focus-within > .interactiveChild {
98
+ outline: none;
99
+ box-shadow: var(--focus-ring);
100
+ }
101
+
102
+ /* Selected/active (legacy + item variant) */
57
103
  .active,
58
- .interactive[aria-selected='true'] {
104
+ .interactive[aria-selected='true'],
105
+ .row > .interactiveChild.active,
106
+ .row > .interactiveChild[aria-selected='true'] {
59
107
  background-color: var(--color-bg-selected);
60
108
  color: var(--color-fg-default);
61
109
  }
62
110
 
111
+ /* Checked (legacy support; kept in case any interactive element still uses aria-checked) */
112
+ .interactive[aria-checked='true'],
113
+ .row > .interactiveChild[aria-checked='true'] {
114
+ background-color: var(--color-bg-selected);
115
+ color: var(--color-fg-default);
116
+ }
117
+
118
+ /* Disabled: support both cases */
63
119
  .interactive[aria-disabled='true'],
64
- .interactive:disabled {
120
+ .interactive:disabled,
121
+ .row > .interactiveChild[aria-disabled='true'] {
65
122
  color: var(--color-disabled-fg);
66
123
  cursor: not-allowed;
67
124
  pointer-events: none;
68
125
  }
69
126
 
70
- .interactive svg {
127
+ /* Icons inside either interactive element or wrapper */
128
+ .interactive svg,
129
+ .interactiveChild svg {
71
130
  inline-size: var(--icon-size-md);
72
131
  block-size: var(--icon-size-md);
73
132
  }
133
+
134
+ /* Visual separator row (used by <Menu.Separator />) */
135
+ .separator {
136
+ block-size: 1px;
137
+ margin-block: var(--spacing-2xs);
138
+ background: var(--color-border-subtle);
139
+ opacity: 0.8;
140
+ border-radius: 999px;
141
+ }
@@ -7,7 +7,7 @@
7
7
  justify-content: center;
8
8
  padding-top: clamp(var(--spacing-md), 12vh, 24vh);
9
9
  padding-bottom: var(--spacing-md);
10
- z-index: var(--z-modal);
10
+ z-index: var(--z-backdrop-modal);
11
11
  overflow-y: auto;
12
12
  }
13
13
 
@@ -15,13 +15,14 @@
15
15
  background: var(--color-bg-surface);
16
16
  border-radius: var(--border-radius-lg);
17
17
  min-width: 320px;
18
- max-width: 540px;
18
+ max-width: 700px;
19
19
  max-height: calc(100vh - (2 * var(--spacing-md)));
20
20
  display: flex;
21
21
  flex-direction: column;
22
22
  box-shadow: var(--shadow-lg);
23
23
  font-family: var(--font-family);
24
- min-width: 400px;
24
+ min-width: 500px;
25
+ z-index: var(--z-modal);
25
26
  color: var(--color-fg-default);
26
27
  }
27
28
 
@@ -43,20 +43,18 @@ export function ModalProvider({ children }) {
43
43
  label: confirmLabel,
44
44
  onClick: () => {
45
45
  resolvePending(true);
46
- closeModal();
47
46
  },
48
47
  },
49
48
  secondaryAction: {
50
49
  label: cancelLabel,
51
50
  onClick: () => {
52
51
  resolvePending(false);
53
- closeModal();
54
52
  },
55
53
  },
56
54
  });
57
55
  setIsOpen(true);
58
56
  });
59
- }, [closeModal, resolvePending]);
57
+ }, [resolvePending]);
60
58
  const modalNode = (_jsxs(ModalContext.Provider, { value: { openModal, closeModal, confirm }, children: [children, mounted &&
61
59
  createPortal(_jsx(Modal, { ...(config !== null && config !== void 0 ? config : {}), isOpen: isOpen, onRequestClose: handleRequestClose, children: config === null || config === void 0 ? void 0 : config.children }), document.body)] }));
62
60
  return modalNode;
@@ -4,6 +4,7 @@ import { useEffect, useRef, useState, } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
5
  import { Button } from '../../../components/button/Button';
6
6
  import { Headline } from '../../../components/headline/Headline';
7
+ import { MOTION_MS } from '../../../styles/animation';
7
8
  import styles from './SidePanel.module.css';
8
9
  export function SidePanel({ isOpen, onClose, children, header, headerAddition, actions, showBackdrop = true, severity, showHeaderMarker = true, width = '400px', details, detailsHeader = 'Output', detailsWidth = '420px', onCloseDetails, detailsHeaderAddition, ...props }) {
9
10
  const [mounted, setMounted] = useState(false);
@@ -16,6 +17,21 @@ export function SidePanel({ isOpen, onClose, children, header, headerAddition, a
16
17
  if (isOpen)
17
18
  setShouldRender(true);
18
19
  }, [isOpen]);
20
+ // Close on ESC key
21
+ useEffect(() => {
22
+ if (!isOpen)
23
+ return;
24
+ const handleKeyDown = (e) => {
25
+ if (e.key === 'Escape') {
26
+ e.stopPropagation();
27
+ onClose();
28
+ }
29
+ };
30
+ document.addEventListener('keydown', handleKeyDown);
31
+ return () => {
32
+ document.removeEventListener('keydown', handleKeyDown);
33
+ };
34
+ }, [isOpen, onClose]);
19
35
  // Two-phase OPEN/CLOSE class toggle (lets CSS transitions kick in reliably)
20
36
  useEffect(() => {
21
37
  if (!shouldRender)
@@ -56,11 +72,12 @@ export function SidePanel({ isOpen, onClose, children, header, headerAddition, a
56
72
  } })), _jsxs("div", { ref: panelRef, ...props, className: `${styles.sidePanel} ${isActive ? styles.open : ''} ${hasDetails ? styles.withDetails : styles.noDetails}`, style: {
57
73
  '--side-panel-width': width,
58
74
  '--details-width': detailsWidth,
75
+ '--panel-dur': MOTION_MS.panelSlide + 'ms',
59
76
  }, "data-cy": "details-panel", role: "dialog", "aria-modal": "true", children: [hasDetails ? (_jsxs("aside", { className: styles.detailsCol, "data-cy": "details-panel-details", children: [_jsxs("div", { className: styles.detailsHeader, children: [_jsx("div", { className: styles.detailsTitle, children: detailsHeader }), _jsxs("div", { className: styles.detailsHeaderActions, children: [detailsHeaderAddition, onCloseDetails ? (_jsx(Button, { type: "button", size: "sm", variant: "outlined", onClick: e => {
60
77
  e.stopPropagation();
61
78
  onCloseDetails();
62
79
  }, children: "Luk" })) : null] })] }), _jsx("div", { className: styles.detailsContent, children: details })] })) : null, _jsxs("section", { className: styles.mainCol, "data-cy": "details-panel-main", children: [_jsx("div", { className: styles.header, children: _jsxs("div", { className: "dbc-flex dbc-justify-between", children: [_jsx(Headline, { size: 3, disableMargin: true, severity: severity, marker: showHeaderMarker, children: header }), _jsxs("span", { className: "dbc-flex dbc-items-center dbc-gap-xs", children: [headerAddition, _jsx(Button, { type: "button", size: "sm", variant: "inline", onClick: e => {
63
80
  e.stopPropagation();
64
81
  onClose(e);
65
- }, "aria-label": "Close panel", children: _jsx(X, {}) })] })] }) }), _jsx("div", { className: styles.content, "data-cy": "details-panel-content", children: children }), actions && _jsx("div", { className: styles.actions, children: actions })] })] })] }), document.body);
82
+ }, "aria-label": "Luk panel", "data-cy": "side-panel-close-button", children: _jsx(X, {}) })] })] }) }), _jsx("div", { className: styles.content, "data-cy": "details-panel-content", children: children }), actions && _jsx("div", { className: styles.actions, children: actions })] })] })] }), document.body);
66
83
  }
@@ -1,8 +1,6 @@
1
1
  .sidePanel {
2
2
  --col-pad: var(--spacing-md);
3
3
 
4
- /* Dial these for “feel” */
5
- --panel-dur: 220ms;
6
4
  --panel-ease: cubic-bezier(0.22, 1, 0.36, 1); /* smooth spring-ish without overshoot */
7
5
 
8
6
  /* Shadow + edge */
@@ -159,7 +157,7 @@
159
157
  position: fixed;
160
158
  inset: 0;
161
159
  background-color: rgba(0, 0, 0, 0.45);
162
- z-index: var(--z-backdrop);
160
+ z-index: var(--z-backdrop-drawer);
163
161
 
164
162
  opacity: 0;
165
163
  transition: opacity var(--panel-dur) var(--panel-ease);
@@ -1,4 +1,5 @@
1
1
  import { useCallback, useContext, useEffect, useId, useRef, useState } from 'react';
2
+ import { MOTION_MS } from '../../../styles/animation';
2
3
  import { TooltipContext } from './TooltipProvider';
3
4
  export function useTooltipTrigger(options) {
4
5
  const ctx = useContext(TooltipContext);
@@ -45,7 +46,6 @@ export function useTooltipTrigger(options) {
45
46
  }
46
47
  show();
47
48
  }, [isOpen, show, hide]);
48
- // ✅ Only call update if THIS tooltip is the active one AND something changed
49
49
  useEffect(() => {
50
50
  var _a;
51
51
  if (!isOpen)
@@ -84,7 +84,9 @@ export function useTooltipTrigger(options) {
84
84
  const onFocus = () => {
85
85
  clearTimers();
86
86
  if (!isControlled)
87
- setOpen(true);
87
+ setTimeout(() => {
88
+ setOpen(true);
89
+ }, MOTION_MS.tooltipOpen);
88
90
  };
89
91
  const onBlur = () => {
90
92
  clearTimers();
@@ -1,11 +1,14 @@
1
- import type { PropsWithChildren, ReactNode, FC } from 'react';
2
- import { PageLayoutHeroProps } from './components/page-layout-hero/PageLayoutHero';
1
+ import type { FC, PropsWithChildren, ReactNode } from 'react';
2
+ import { type PageLayoutHeroProps } from './components/page-layout-hero/PageLayoutHero';
3
3
  type Orientation = 'vertical' | 'horizontal';
4
4
  export interface PageLayoutProps extends PropsWithChildren {
5
+ /**
6
+ * If true, PageLayout becomes a self-contained app shell (100vh) and
7
+ * scroll is contained inside the intended regions (sidebar/content).
8
+ * If false, the document scrolls normally (body scroll).
9
+ */
5
10
  containScrolling?: boolean;
6
11
  orientation?: Orientation;
7
- sidebar?: ReactNode;
8
- header?: ReactNode;
9
12
  }
10
13
  export interface PageLayoutHeaderProps {
11
14
  maxWidth?: boolean;
@@ -18,7 +21,16 @@ export interface PageLayoutContentProps {
18
21
  export interface PageLayoutFooterProps {
19
22
  children: ReactNode;
20
23
  }
24
+ export interface PageLayoutSidebarProps {
25
+ children: ReactNode;
26
+ /**
27
+ * Optional: if your sidebar contains navigation, you might wrap your nav in <nav>.
28
+ * This component will render an <aside>.
29
+ */
30
+ ariaLabel?: string;
31
+ }
21
32
  export declare const PageLayout: FC<PageLayoutProps> & {
33
+ Sidebar: FC<PageLayoutSidebarProps>;
22
34
  Header: FC<PageLayoutHeaderProps>;
23
35
  Hero: FC<PageLayoutHeroProps>;
24
36
  Content: FC<PageLayoutContentProps>;
@@ -1,38 +1,67 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { PageLayoutHero } from './components/page-layout-hero/PageLayoutHero';
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Children, isValidElement } from 'react';
3
+ import { PageLayoutHero, } from './components/page-layout-hero/PageLayoutHero';
4
4
  import styles from './PageLayout.module.css';
5
- const PageLayoutBase = ({ children, sidebar, header, containScrolling = false, orientation = 'vertical', }) => {
6
- if (orientation === 'vertical') {
7
- return (_jsx("div", { className: `${styles.container} ${styles.vertical} ${containScrolling ? styles.containScrolling : ''}`, children: _jsxs("div", { style: { flex: 1, display: 'flex', height: '100%', maxWidth: '100%' }, children: [sidebar, _jsxs("div", { style: {
8
- flex: 1,
9
- display: 'flex',
10
- flexDirection: 'column',
11
- height: '100%',
12
- maxHeight: '100vh',
13
- overflow: 'auto',
14
- }, children: [header && _jsx("div", { className: styles.header, children: header }), _jsx("div", { style: {
15
- flex: 1,
16
- display: 'flex',
17
- flexDirection: 'column',
18
- padding: 'var(--spacing-md)',
19
- backgroundColor: 'var(--color-bg-surface)',
20
- overflow: 'auto',
21
- }, children: children })] })] }) }));
22
- }
23
- return (_jsx("div", { className: `${styles.container} ${containScrolling ? styles.containScrolling : ''}`, children: children }));
5
+ function getSlotName(el) {
6
+ var _a;
7
+ const t = el.type;
8
+ return (_a = t === null || t === void 0 ? void 0 : t.__PAGE_LAYOUT_SLOT__) !== null && _a !== void 0 ? _a : null;
9
+ }
10
+ function splitSlots(children) {
11
+ const slots = {};
12
+ const rest = [];
13
+ Children.forEach(children, child => {
14
+ if (!isValidElement(child)) {
15
+ if (child != null)
16
+ rest.push(child);
17
+ return;
18
+ }
19
+ const slot = getSlotName(child);
20
+ if (!slot) {
21
+ rest.push(child);
22
+ return;
23
+ }
24
+ // If multiple of same slot are provided, last wins (simple + predictable).
25
+ slots[slot] = child;
26
+ });
27
+ return { slots, rest };
28
+ }
29
+ /** Slot components */
30
+ const PageLayoutSidebar = ({ children, }) => {
31
+ // This returns children; layout wrapper decides how to render.
32
+ // We keep this as a slot marker component.
33
+ return _jsx(_Fragment, { children: children });
24
34
  };
25
- /** Subcomponents */
26
- const PageLayoutHeader = ({ maxWidth = true, children, }) => {
35
+ PageLayoutSidebar.__PAGE_LAYOUT_SLOT__ = 'Sidebar';
36
+ const PageLayoutHeader = ({ maxWidth = false, children, }) => {
27
37
  return (_jsx("div", { className: styles.headerContainer, children: _jsx("div", { className: `${styles.headerContent} ${maxWidth ? styles.maxWidth : ''}`, children: children }) }));
28
38
  };
29
- const PageLayoutContent = ({ maxWidth = true, children, }) => {
30
- return _jsx("main", { className: `${styles.content} ${maxWidth ? styles.maxWidth : ''}`, children: children });
39
+ PageLayoutHeader.__PAGE_LAYOUT_SLOT__ = 'Header';
40
+ const PageLayoutContent = ({ maxWidth = false, children, }) => {
41
+ return (_jsx("div", { className: `${styles.contentInner} ${maxWidth ? styles.maxWidth : ''}`, children: children }));
31
42
  };
32
- const PageLayoutFooter = ({ children }) => {
33
- return _jsx("footer", { className: styles.footer, children: children });
43
+ PageLayoutContent.__PAGE_LAYOUT_SLOT__ = 'Content';
44
+ const PageLayoutFooter = ({ children, }) => {
45
+ return _jsx(_Fragment, { children: children });
46
+ };
47
+ PageLayoutFooter.__PAGE_LAYOUT_SLOT__ = 'Footer';
48
+ PageLayoutHero.__PAGE_LAYOUT_SLOT__ = 'Hero';
49
+ const PageLayoutBase = ({ children, containScrolling = false, orientation = 'vertical', }) => {
50
+ var _a, _b;
51
+ const { slots, rest } = splitSlots(children);
52
+ // If no explicit <PageLayout.Content>, we’ll treat remaining children as content.
53
+ const content = (_a = slots.Content) !== null && _a !== void 0 ? _a : (rest.length ? _jsx(PageLayoutContent, { maxWidth: true, children: rest }) : undefined);
54
+ const rootClass = [
55
+ styles.root,
56
+ orientation === 'vertical' ? styles.vertical : styles.horizontal,
57
+ containScrolling ? styles.containScrolling : styles.documentScrolling,
58
+ ]
59
+ .filter(Boolean)
60
+ .join(' ');
61
+ return (_jsxs("div", { className: rootClass, children: [slots.Sidebar ? (_jsx("aside", { className: styles.sidebar, "aria-label": (_b = slots.Sidebar.props) === null || _b === void 0 ? void 0 : _b.ariaLabel, children: slots.Sidebar })) : null, _jsxs("div", { className: styles.mainColumn, children: [slots.Header ? _jsx("header", { className: styles.header, children: slots.Header }) : null, slots.Hero ? _jsx("div", { className: styles.hero, children: slots.Hero }) : null, content || slots.Footer ? (_jsxs("div", { className: styles.mainScroll, children: [content ? _jsx("main", { className: styles.content, children: content }) : null, slots.Footer ? _jsx("footer", { className: styles.footer, children: slots.Footer }) : null] })) : null] })] }));
34
62
  };
35
63
  export const PageLayout = Object.assign(PageLayoutBase, {
64
+ Sidebar: PageLayoutSidebar,
36
65
  Header: PageLayoutHeader,
37
66
  Hero: PageLayoutHero,
38
67
  Content: PageLayoutContent,
@@ -1,66 +1,186 @@
1
- .container {
2
- display: flex;
3
- flex-direction: column;
4
- gap: 20px;
5
- max-width: 100vw;
1
+ /* Root shell */
2
+ .root {
3
+ width: 100%;
4
+ max-width: 100%;
5
+ display: grid;
6
+ gap: 0;
7
+ }
8
+
9
+ /* Viewport handling:
10
+ - containScrolling => app-shell: lock to viewport and manage scroll in regions
11
+ - documentScrolling => let page scroll normally
12
+ */
13
+ .containScrolling {
14
+ height: 100vh;
15
+ height: 100dvh;
16
+ overflow: hidden;
17
+ }
18
+
19
+ .documentScrolling {
20
+ min-height: 100%;
21
+ overflow: visible;
6
22
  }
7
23
 
24
+ /* Orientation layouts */
8
25
  .vertical {
9
- flex-direction: row;
10
- align-items: flex-start;
26
+ grid-template-columns: auto minmax(0, 1fr);
11
27
  }
12
28
 
13
- .container.containScrolling {
14
- height: 100vh;
29
+ .horizontal {
30
+ grid-template-columns: minmax(0, 1fr);
31
+ }
32
+
33
+ /* Sidebar */
34
+ .sidebar {
35
+ min-width: 0;
36
+ overflow: hidden;
37
+ border-right: var(--border-width-thin) solid var(--color-border-subtle);
38
+ background: var(--color-bg-surface);
39
+ }
40
+
41
+ .containScrolling .sidebar {
15
42
  overflow: auto;
16
- position: relative;
43
+ -webkit-overflow-scrolling: touch;
17
44
  }
18
45
 
19
- @media screen and (max-height: 400px) {
20
- .container {
21
- height: unset;
22
- }
46
+ /* In horizontal orientation, sidebar becomes a top block if used */
47
+ .horizontal .sidebar {
48
+ grid-column: 1 / -1;
49
+ border-right: none;
50
+ border-bottom: var(--border-width-thin) solid var(--color-border-subtle);
23
51
  }
24
52
 
25
- .headerContainer {
53
+ /* Main column:
54
+ Use flex so the "rest of space" logic works reliably.
55
+ */
56
+ .mainColumn {
57
+ min-width: 0;
26
58
  display: flex;
27
- justify-content: center;
59
+ flex-direction: column;
60
+ background: var(--color-bg-surface);
61
+ }
62
+
63
+ /* In containScrolling mode, mainColumn must fill the viewport height
64
+ so the flex "remaining space" can be computed.
65
+ */
66
+ .containScrolling .mainColumn {
67
+ height: 100%;
68
+ min-height: 0; /* important: allows children to shrink */
28
69
  }
29
70
 
30
- .container:not(.containScrolling) .headerContainer {
71
+ /* Regions */
72
+ .header {
73
+ min-width: 0;
74
+ background: var(--color-bg-surface);
75
+ border-bottom: var(--border-width-thin) solid var(--color-border-subtle);
76
+ flex: 0 0 auto;
77
+ }
78
+
79
+ /* Sticky header only when the document is scrolling (body scroll) */
80
+ .documentScrolling .header {
31
81
  position: sticky;
32
- z-index: 1000;
33
82
  top: 0;
83
+ z-index: var(--z-sticky);
34
84
  }
35
85
 
36
- .headerContent {
86
+ .hero {
87
+ min-width: 0;
88
+ background: var(--color-bg-surface);
89
+ border-bottom: var(--border-width-thin) solid var(--color-border-subtle);
90
+ flex: 0 0 auto;
91
+ }
92
+
93
+ /* Scroll wrapper: contains content + footer */
94
+ .mainScroll {
95
+ min-width: 0;
96
+ min-height: 0; /* CRITICAL for nested flex/scroll */
97
+ display: flex;
98
+ flex-direction: column;
99
+
100
+ /* This is the "take all remaining space" bit */
101
+ flex: 1 1 auto;
102
+
103
+ /* default: documentScrolling uses normal page flow */
104
+ overflow: visible;
105
+ }
106
+
107
+ /* Contained scrolling: mainScroll scrolls (includes footer) */
108
+ .containScrolling .mainScroll {
109
+ overflow: auto;
110
+ -webkit-overflow-scrolling: touch;
111
+ }
112
+
113
+ /* Content area (not a scroll container anymore) */
114
+ .content {
115
+ min-width: 0;
116
+ min-height: 0;
117
+ flex: 1 1 auto; /* take remaining space inside mainScroll */
118
+ display: flex; /* lets contentInner stretch */
119
+ flex-direction: column;
120
+
121
+ background: var(--color-bg-surface);
122
+ padding: var(--spacing-md);
123
+ overflow: visible;
124
+ }
125
+
126
+ .footer {
127
+ min-width: 0;
128
+ background: var(--color-bg-surface);
129
+ border-top: var(--border-width-thin) solid var(--color-border-subtle);
130
+
131
+ /* When there is extra space (content is short), this pushes footer to the bottom.
132
+ When content is long, footer follows content normally and is reached by scrolling.
133
+ */
134
+ margin-top: auto;
37
135
  flex: 0 0 auto;
136
+ }
137
+
138
+ /* Header slot wrappers */
139
+ .headerContainer {
140
+ display: flex;
141
+ justify-content: center;
142
+ width: 100%;
143
+ }
144
+
145
+ .headerContent {
38
146
  width: 100%;
39
147
  box-sizing: border-box;
40
148
  }
41
149
 
42
150
  .maxWidth {
43
151
  max-width: 1600px;
44
- margin: auto;
152
+ margin-inline: auto;
45
153
  width: 100%;
46
154
  box-sizing: border-box;
47
155
  }
48
156
 
49
- .content {
50
- flex: 1 1 auto;
51
- width: 100%;
52
- margin: 0 auto;
53
- box-sizing: border-box;
54
- gap: var(--spacing-xl);
55
- padding: var(--spacing-md) var(--spacing-xl);
56
- padding-top: 0;
57
- min-height: 0;
157
+ /* Content slot inner wrapper (so maxWidth works without interfering with scroll) */
158
+ .contentInner {
58
159
  display: flex;
59
160
  flex-direction: column;
60
- overflow: auto;
61
- -webkit-overflow-scrolling: touch;
161
+ gap: var(--spacing-xl);
162
+
163
+ box-sizing: border-box;
164
+ min-width: 0;
165
+
166
+ /* This is what makes your "main content" actually expand to fill */
167
+ flex: 1 1 auto;
168
+ min-height: 0;
62
169
  }
63
170
 
64
- .footer {
65
- flex: 0 0 auto;
171
+ /* Optional: for small viewport heights, avoid forced viewport locking */
172
+ @media (max-height: 400px) {
173
+ .containScrolling {
174
+ height: auto;
175
+ overflow: visible;
176
+ }
177
+
178
+ /* In this mode, avoid forcing a nested scroll region */
179
+ .containScrolling .mainScroll {
180
+ overflow: visible;
181
+ }
182
+
183
+ .containScrolling .mainColumn {
184
+ height: auto;
185
+ }
66
186
  }
@@ -1,12 +1,26 @@
1
1
  import * as React from 'react';
2
- interface PopoverProps {
3
- trigger: (event: (e: React.MouseEvent<HTMLElement> | React.FocusEvent<HTMLElement>) => void, icon: React.ReactNode) => React.ReactNode;
4
- children: ((close?: () => void) => React.ReactNode) | React.ReactNode;
2
+ export interface PopoverProps {
3
+ trigger: (toggle: (e: React.MouseEvent<HTMLElement> | React.FocusEvent<HTMLElement>) => void, icon: React.ReactNode, open?: boolean) => React.ReactNode;
4
+ children: ((close: () => void) => React.ReactNode) | React.ReactNode;
5
+ open?: boolean;
6
+ defaultOpen?: boolean;
7
+ onOpenChange?: (open: boolean) => void;
8
+ contentId?: string;
9
+ /**
10
+ * CSS length, recommended "NNpx" for predictability.
11
+ * Used as a minimum, not as a forced width unless matchTriggerWidth=true.
12
+ */
5
13
  minWidth?: string;
14
+ /**
15
+ * If true, force the overlay width to at least the trigger width.
16
+ * If false, overlay width is content-driven (calendar-friendly).
17
+ */
6
18
  matchTriggerWidth?: boolean;
7
19
  viewportPadding?: number;
8
20
  edgeBuffer?: number;
9
21
  dataCy?: string;
22
+ autoFocusContent?: boolean;
23
+ returnFocus?: boolean;
10
24
  }
11
25
  export interface PopoverHandle {
12
26
  close: () => void;
@@ -14,4 +28,3 @@ export interface PopoverHandle {
14
28
  isOpen: () => boolean;
15
29
  }
16
30
  export declare const Popover: React.ForwardRefExoticComponent<PopoverProps & React.RefAttributes<PopoverHandle>>;
17
- export {};