@dbcdk/react-components 0.0.190 → 0.0.191
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.cjs +7 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +1 -0
- package/dist/components/button-select/ButtonSelect.cjs +2 -2
- package/dist/components/button-select/ButtonSelect.d.ts +1 -0
- package/dist/components/button-select/ButtonSelect.js +2 -2
- package/dist/components/button-select/ButtonSelect.module.css +14 -0
- package/dist/components/chip/Chip.module.css +25 -2
- package/dist/components/forms/checkbox/Checkbox.cjs +6 -1
- package/dist/components/forms/checkbox/Checkbox.js +6 -1
- package/dist/components/forms/checkbox/Checkbox.module.css +26 -0
- package/dist/components/forms/input-container/InputContainer.module.css +0 -7
- package/dist/components/grid/Grid.cjs +4 -2
- package/dist/components/grid/Grid.d.ts +2 -2
- package/dist/components/grid/Grid.js +4 -2
- package/dist/components/overlay/side-panel/SidePanel.module.css +3 -1
- package/dist/components/page-layout/PageLayout.module.css +12 -3
- package/dist/hooks/useStickyLayout.cjs +99 -0
- package/dist/hooks/useStickyLayout.d.ts +22 -0
- package/dist/hooks/useStickyLayout.js +97 -0
- package/dist/index.cjs +7 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/styles/css-helper-classes/scrollbar.css +10 -0
- package/dist/styles/styles.css +1 -21
- package/dist/styles/themes/dbc/base.css +2 -2
- package/dist/styles.css +1 -21
- package/package.json +1 -1
- package/dist/styles/fonts/Roboto/OFL.txt +0 -93
- package/dist/styles/fonts/Roboto/README.txt +0 -118
- package/dist/styles/fonts/Roboto/Roboto-Black.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-BlackItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-Bold.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-BoldItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-ExtraBold.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-ExtraBoldItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-ExtraLight.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-ExtraLightItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-Italic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-Light.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-LightItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-Medium.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-Regular.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-SemiBold.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-SemiBoldItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-Thin.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto-ThinItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-Black.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-BlackItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-Bold.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-BoldItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-ExtraBold.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-ExtraBoldItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-ExtraLight.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-ExtraLightItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-Italic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-Light.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-LightItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-Medium.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-MediumItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-Regular.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-SemiBold.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-SemiBoldItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-Thin.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_Condensed-ThinItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-Black.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-BlackItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-Bold.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-BoldItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-ExtraBold.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-ExtraBoldItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-ExtraLight.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-ExtraLightItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-Italic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-Light.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-LightItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-Medium.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-MediumItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-Regular.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-SemiBold.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-SemiBoldItalic.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-Thin.ttf +0 -0
- package/dist/styles/fonts/Roboto/Roboto_SemiCondensed-ThinItalic.ttf +0 -0
- package/dist/styles/fonts/Tajawal/OFL.txt +0 -93
- package/dist/styles/fonts/Tajawal/Tajawal-Black.ttf +0 -0
- package/dist/styles/fonts/Tajawal/Tajawal-Bold.ttf +0 -0
- package/dist/styles/fonts/Tajawal/Tajawal-ExtraBold.ttf +0 -0
- package/dist/styles/fonts/Tajawal/Tajawal-ExtraLight.ttf +0 -0
- package/dist/styles/fonts/Tajawal/Tajawal-Light.ttf +0 -0
- package/dist/styles/fonts/Tajawal/Tajawal-Medium.ttf +0 -0
- package/dist/styles/fonts/Tajawal/Tajawal-Regular.ttf +0 -0
package/dist/client.cjs
CHANGED
|
@@ -48,6 +48,7 @@ var TreeView = require('./components/tree-view/TreeView');
|
|
|
48
48
|
var nestedFiltering = require('./utils/arrays/nested-filtering');
|
|
49
49
|
var MultiSelect = require('./components/forms/multi-select/MultiSelect');
|
|
50
50
|
var useViewportFill = require('./hooks/useViewportFill');
|
|
51
|
+
var useStickyLayout = require('./hooks/useStickyLayout');
|
|
51
52
|
var formatDate = require('./utils/date/formatDate');
|
|
52
53
|
var FilterField = require('./components/filter-field/FilterField');
|
|
53
54
|
var Select = require('./components/forms/select/Select');
|
|
@@ -386,6 +387,12 @@ Object.keys(useViewportFill).forEach(function (k) {
|
|
|
386
387
|
get: function () { return useViewportFill[k]; }
|
|
387
388
|
});
|
|
388
389
|
});
|
|
390
|
+
Object.keys(useStickyLayout).forEach(function (k) {
|
|
391
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
392
|
+
enumerable: true,
|
|
393
|
+
get: function () { return useStickyLayout[k]; }
|
|
394
|
+
});
|
|
395
|
+
});
|
|
389
396
|
Object.keys(formatDate).forEach(function (k) {
|
|
390
397
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
391
398
|
enumerable: true,
|
package/dist/client.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ export * from './components/tree-view/TreeView';
|
|
|
45
45
|
export * from './utils/arrays/nested-filtering';
|
|
46
46
|
export * from './components/forms/multi-select/MultiSelect';
|
|
47
47
|
export * from './hooks/useViewportFill';
|
|
48
|
+
export * from './hooks/useStickyLayout';
|
|
48
49
|
export * from './utils/date/formatDate';
|
|
49
50
|
export * from './components/filter-field/FilterField';
|
|
50
51
|
export * from './components/forms/select/Select';
|
package/dist/client.js
CHANGED
|
@@ -46,6 +46,7 @@ export * from './components/tree-view/TreeView';
|
|
|
46
46
|
export * from './utils/arrays/nested-filtering';
|
|
47
47
|
export * from './components/forms/multi-select/MultiSelect';
|
|
48
48
|
export * from './hooks/useViewportFill';
|
|
49
|
+
export * from './hooks/useStickyLayout';
|
|
49
50
|
export * from './utils/date/formatDate';
|
|
50
51
|
export * from './components/filter-field/FilterField';
|
|
51
52
|
export * from './components/forms/select/Select';
|
|
@@ -10,7 +10,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
10
10
|
var styles__default = /*#__PURE__*/_interopDefault(styles);
|
|
11
11
|
|
|
12
12
|
function ButtonSelect(props) {
|
|
13
|
-
const { options, size = "md", disabled } = props;
|
|
13
|
+
const { options, size = "md", disabled, modified = false } = props;
|
|
14
14
|
const selectedValues = Array.isArray(props.value) ? props.value : [props.value];
|
|
15
15
|
function handleSelect(optionValue) {
|
|
16
16
|
if (props.multiple) {
|
|
@@ -20,7 +20,7 @@ function ButtonSelect(props) {
|
|
|
20
20
|
}
|
|
21
21
|
props.onChange(optionValue);
|
|
22
22
|
}
|
|
23
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.group, role: "group", children: options.map((option) => {
|
|
23
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.group, role: "group", "data-modified": modified ? "true" : void 0, children: options.map((option) => {
|
|
24
24
|
const isSelected = selectedValues.includes(option.value);
|
|
25
25
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
26
26
|
Button.Button,
|
|
@@ -10,6 +10,7 @@ interface ButtonSelectBaseProps<T extends string = string> {
|
|
|
10
10
|
options: ButtonSelectOption<T>[];
|
|
11
11
|
size?: ButtonSize;
|
|
12
12
|
disabled?: boolean;
|
|
13
|
+
modified?: boolean;
|
|
13
14
|
}
|
|
14
15
|
export interface ButtonSelectSingleProps<T extends string = string> extends ButtonSelectBaseProps<T> {
|
|
15
16
|
value: T;
|
|
@@ -4,7 +4,7 @@ import { Button } from '../../components/button/Button';
|
|
|
4
4
|
import styles from './ButtonSelect.module.css';
|
|
5
5
|
|
|
6
6
|
function ButtonSelect(props) {
|
|
7
|
-
const { options, size = "md", disabled } = props;
|
|
7
|
+
const { options, size = "md", disabled, modified = false } = props;
|
|
8
8
|
const selectedValues = Array.isArray(props.value) ? props.value : [props.value];
|
|
9
9
|
function handleSelect(optionValue) {
|
|
10
10
|
if (props.multiple) {
|
|
@@ -14,7 +14,7 @@ function ButtonSelect(props) {
|
|
|
14
14
|
}
|
|
15
15
|
props.onChange(optionValue);
|
|
16
16
|
}
|
|
17
|
-
return /* @__PURE__ */ jsx("div", { className: styles.group, role: "group", children: options.map((option) => {
|
|
17
|
+
return /* @__PURE__ */ jsx("div", { className: styles.group, role: "group", "data-modified": modified ? "true" : void 0, children: options.map((option) => {
|
|
18
18
|
const isSelected = selectedValues.includes(option.value);
|
|
19
19
|
return /* @__PURE__ */ jsx(
|
|
20
20
|
Button,
|
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
flex-wrap: nowrap;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
.group[data-modified='true'] {
|
|
7
|
+
background-color: color-mix(in srgb, var(--color-status-warning-bg) 35%, transparent);
|
|
8
|
+
border-radius: var(--border-radius-default);
|
|
9
|
+
padding: 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.group[data-modified='true'] .btn {
|
|
13
|
+
border-color: color-mix(
|
|
14
|
+
in srgb,
|
|
15
|
+
var(--color-status-warning-border) 60%,
|
|
16
|
+
var(--color-border-default)
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
6
20
|
/* Collapse the doubled border between adjacent buttons */
|
|
7
21
|
.group .btn:not(:first-child) {
|
|
8
22
|
margin-left: -1px;
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
/* Types */
|
|
44
44
|
|
|
45
45
|
.outlined {
|
|
46
|
-
--chip-bg:
|
|
46
|
+
--chip-bg: transparent;
|
|
47
47
|
--chip-border: var(--chip-outlined-border, var(--color-border-subtle));
|
|
48
48
|
--chip-fg: var(--chip-outlined-fg, var(--color-fg-muted));
|
|
49
49
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
.outlined:hover {
|
|
53
|
-
background-color:
|
|
53
|
+
background-color: transparent;
|
|
54
54
|
border-color: var(--chip-outlined-border-hover, var(--color-border-default));
|
|
55
55
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
56
56
|
color: var(--chip-outlined-fg-hover, var(--color-fg-default));
|
|
@@ -124,6 +124,16 @@
|
|
|
124
124
|
box-shadow: none;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
.outlined.neutral {
|
|
128
|
+
--chip-bg: transparent;
|
|
129
|
+
--chip-border: var(--chip-outlined-border, var(--color-border-subtle));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.outlined.neutral:hover,
|
|
133
|
+
.outlined.neutral:focus-visible {
|
|
134
|
+
--chip-bg: transparent;
|
|
135
|
+
}
|
|
136
|
+
|
|
127
137
|
.neutral .close {
|
|
128
138
|
color: var(--color-fg-subtle);
|
|
129
139
|
}
|
|
@@ -208,6 +218,19 @@
|
|
|
208
218
|
box-shadow: inset 0 0 0 1px var(--color-border-selected);
|
|
209
219
|
}
|
|
210
220
|
|
|
221
|
+
.outlined.selected,
|
|
222
|
+
.outlined.selected:hover,
|
|
223
|
+
.outlined.selected:focus-visible {
|
|
224
|
+
background: color-mix(in srgb, var(--color-bg-selected) 65%, var(--color-bg-surface));
|
|
225
|
+
border-color: var(--color-border-selected);
|
|
226
|
+
box-shadow: inset 0 0 0 1px var(--color-border-selected);
|
|
227
|
+
color: var(--color-brand);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.outlined.selected:hover {
|
|
231
|
+
background: color-mix(in srgb, var(--color-bg-selected-hover) 65%, var(--color-bg-surface));
|
|
232
|
+
}
|
|
233
|
+
|
|
211
234
|
.selected:hover {
|
|
212
235
|
background-color: var(--color-bg-selected);
|
|
213
236
|
border-color: var(--color-border-selected);
|
|
@@ -49,7 +49,11 @@ function Checkbox({
|
|
|
49
49
|
const content = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
50
50
|
"span",
|
|
51
51
|
{
|
|
52
|
-
className: [
|
|
52
|
+
className: [
|
|
53
|
+
styles__default.default.container,
|
|
54
|
+
size === "sm" ? styles__default.default.containerSm : "",
|
|
55
|
+
modified ? styles__default.default.modified : ""
|
|
56
|
+
].filter(Boolean).join(" "),
|
|
53
57
|
"data-cy": dataCy,
|
|
54
58
|
children: [
|
|
55
59
|
/* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: tooltip, placement: tooltipPlacement, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -65,6 +69,7 @@ function Checkbox({
|
|
|
65
69
|
onClick: toggle,
|
|
66
70
|
className: [
|
|
67
71
|
styles__default.default.checkbox,
|
|
72
|
+
disabled ? "disabled" : "",
|
|
68
73
|
isChecked ? styles__default.default.checked : "",
|
|
69
74
|
styles__default.default[variant],
|
|
70
75
|
styles__default.default[size]
|
|
@@ -43,7 +43,11 @@ function Checkbox({
|
|
|
43
43
|
const content = /* @__PURE__ */ jsxs(
|
|
44
44
|
"span",
|
|
45
45
|
{
|
|
46
|
-
className: [
|
|
46
|
+
className: [
|
|
47
|
+
styles.container,
|
|
48
|
+
size === "sm" ? styles.containerSm : "",
|
|
49
|
+
modified ? styles.modified : ""
|
|
50
|
+
].filter(Boolean).join(" "),
|
|
47
51
|
"data-cy": dataCy,
|
|
48
52
|
children: [
|
|
49
53
|
/* @__PURE__ */ jsx(Tooltip, { content: tooltip, placement: tooltipPlacement, children: /* @__PURE__ */ jsx(
|
|
@@ -59,6 +63,7 @@ function Checkbox({
|
|
|
59
63
|
onClick: toggle,
|
|
60
64
|
className: [
|
|
61
65
|
styles.checkbox,
|
|
66
|
+
disabled ? "disabled" : "",
|
|
62
67
|
isChecked ? styles.checked : "",
|
|
63
68
|
styles[variant],
|
|
64
69
|
styles[size]
|
|
@@ -7,6 +7,13 @@
|
|
|
7
7
|
color: var(--color-fg-default);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
.container.modified {
|
|
11
|
+
background-color: color-mix(in srgb, var(--color-status-warning-bg) 75%, transparent);
|
|
12
|
+
border-radius: var(--border-radius-default);
|
|
13
|
+
padding: 0;
|
|
14
|
+
display: inline-flex;
|
|
15
|
+
}
|
|
16
|
+
|
|
10
17
|
.containerSm {
|
|
11
18
|
gap: var(--spacing-xs);
|
|
12
19
|
}
|
|
@@ -28,6 +35,12 @@
|
|
|
28
35
|
box-shadow var(--transition-fast) var(--ease-standard);
|
|
29
36
|
}
|
|
30
37
|
|
|
38
|
+
.checkbox:disabled {
|
|
39
|
+
cursor: not-allowed;
|
|
40
|
+
opacity: 0.5;
|
|
41
|
+
filter: grayscale(0.2);
|
|
42
|
+
}
|
|
43
|
+
|
|
31
44
|
.checkbox.sm {
|
|
32
45
|
width: var(--component-size-xs);
|
|
33
46
|
height: var(--component-size-xs);
|
|
@@ -54,11 +67,24 @@
|
|
|
54
67
|
border-color: var(--color-fg-default);
|
|
55
68
|
}
|
|
56
69
|
|
|
70
|
+
.checkbox:disabled:hover {
|
|
71
|
+
border-color: var(--color-border-default);
|
|
72
|
+
}
|
|
73
|
+
|
|
57
74
|
.checked {
|
|
58
75
|
background-color: var(--color-brand);
|
|
59
76
|
border-color: var(--color-brand);
|
|
60
77
|
}
|
|
61
78
|
|
|
79
|
+
.checkbox:disabled.checked {
|
|
80
|
+
background-color: var(--color-bg-subtle);
|
|
81
|
+
border-color: var(--color-border-muted);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.checkbox:disabled.checked .icon {
|
|
85
|
+
color: var(--color-fg-muted);
|
|
86
|
+
}
|
|
87
|
+
|
|
62
88
|
.icon {
|
|
63
89
|
width: var(--icon-size-md);
|
|
64
90
|
height: var(--icon-size-md);
|
|
@@ -50,10 +50,3 @@
|
|
|
50
50
|
.messageRow {
|
|
51
51
|
min-height: 1lh;
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
/* Optional: keep this only for controls whose own label lives inside children,
|
|
55
|
-
such as checkbox/radio wrappers. It will not affect Input's top label. */
|
|
56
|
-
.inputContainer[data-modified] label:not(.label) {
|
|
57
|
-
background-color: color-mix(in srgb, var(--color-status-warning-bg) 35%, transparent);
|
|
58
|
-
border-radius: var(--border-radius-default);
|
|
59
|
-
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var react = require('react');
|
|
4
5
|
var styles = require('./Grid.module.css');
|
|
5
6
|
|
|
6
7
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -38,11 +39,12 @@ function Grid({
|
|
|
38
39
|
}
|
|
39
40
|
);
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
+
const GridItem = react.forwardRef(function GridItem2({ children, base = 12, md, lg, className, style }, ref) {
|
|
42
43
|
const toTrackSpan = (span) => span * 2;
|
|
43
44
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44
45
|
"div",
|
|
45
46
|
{
|
|
47
|
+
ref,
|
|
46
48
|
className: [styles__default.default.item, className].filter(Boolean).join(" "),
|
|
47
49
|
style: {
|
|
48
50
|
"--span-base": toTrackSpan(base),
|
|
@@ -53,7 +55,7 @@ function GridItem({ children, base = 12, md, lg, className, style }) {
|
|
|
53
55
|
children
|
|
54
56
|
}
|
|
55
57
|
);
|
|
56
|
-
}
|
|
58
|
+
});
|
|
57
59
|
|
|
58
60
|
exports.Grid = Grid;
|
|
59
61
|
exports.GridItem = GridItem;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CSSProperties, type ReactNode } from 'react';
|
|
2
2
|
export type GridGap = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
3
3
|
export interface GridMaxWidth {
|
|
4
4
|
base?: string;
|
|
@@ -26,4 +26,4 @@ export interface GridItemProps {
|
|
|
26
26
|
className?: string;
|
|
27
27
|
style?: CSSProperties;
|
|
28
28
|
}
|
|
29
|
-
export declare
|
|
29
|
+
export declare const GridItem: import("react").ForwardRefExoticComponent<GridItemProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
2
3
|
import styles from './Grid.module.css';
|
|
3
4
|
|
|
4
5
|
const GAP_TOKEN = {
|
|
@@ -32,11 +33,12 @@ function Grid({
|
|
|
32
33
|
}
|
|
33
34
|
);
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
const GridItem = forwardRef(function GridItem2({ children, base = 12, md, lg, className, style }, ref) {
|
|
36
37
|
const toTrackSpan = (span) => span * 2;
|
|
37
38
|
return /* @__PURE__ */ jsx(
|
|
38
39
|
"div",
|
|
39
40
|
{
|
|
41
|
+
ref,
|
|
40
42
|
className: [styles.item, className].filter(Boolean).join(" "),
|
|
41
43
|
style: {
|
|
42
44
|
"--span-base": toTrackSpan(base),
|
|
@@ -47,6 +49,6 @@ function GridItem({ children, base = 12, md, lg, className, style }) {
|
|
|
47
49
|
children
|
|
48
50
|
}
|
|
49
51
|
);
|
|
50
|
-
}
|
|
52
|
+
});
|
|
51
53
|
|
|
52
54
|
export { Grid, GridItem };
|
|
@@ -96,7 +96,9 @@
|
|
|
96
96
|
|
|
97
97
|
display: flex;
|
|
98
98
|
flex-direction: column;
|
|
99
|
-
|
|
99
|
+
/* Header/content spacing is defined by their own padding, so avoid adding another
|
|
100
|
+
gap that creates double spacing between the panel title and the content area. */
|
|
101
|
+
gap: 0;
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
.header {
|
|
@@ -17,8 +17,9 @@
|
|
|
17
17
|
var(--spacing-2xs) * 2 + var(--font-size-md) * var(--line-height-normal)
|
|
18
18
|
);
|
|
19
19
|
|
|
20
|
-
/* Structural bottom breathing room for all page content
|
|
21
|
-
|
|
20
|
+
/* Structural bottom breathing room for all page content, so it doesn't sit
|
|
21
|
+
flush against the viewport edge. */
|
|
22
|
+
--page-layout-content-padding-bottom: var(--spacing-xl);
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
/* Viewport handling:
|
|
@@ -211,7 +212,15 @@
|
|
|
211
212
|
/* Content area (not a scroll container anymore) */
|
|
212
213
|
.content {
|
|
213
214
|
min-width: 0;
|
|
214
|
-
min-height:
|
|
215
|
+
/* Deliberately no min-height:0 here (unlike `.mainScroll` above, which does
|
|
216
|
+
need it): this lets `.content` size to its own natural content height —
|
|
217
|
+
including its own padding-block-end — instead of being flex-shrunk
|
|
218
|
+
shorter than that content. `.mainScroll` (overflow:auto) already has its
|
|
219
|
+
own min-height:0, which is what lets it stay bounded to the available
|
|
220
|
+
space and scroll; if `.content` could *also* shrink below its content,
|
|
221
|
+
that shrunk-but-visible-overflow content would spill straight past
|
|
222
|
+
wherever its own bottom padding was supposed to land, so it would never
|
|
223
|
+
actually render (this happened in practice before this comment existed). */
|
|
215
224
|
flex: 1 1 auto; /* take remaining space inside mainScroll */
|
|
216
225
|
display: flex; /* lets contentInner stretch */
|
|
217
226
|
flex-direction: column;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var react = require('react');
|
|
5
|
+
|
|
6
|
+
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
|
|
7
|
+
const getScrollport = (element) => {
|
|
8
|
+
for (let parent = element.parentElement; parent; parent = parent.parentElement) {
|
|
9
|
+
if (parent === document.body || parent === document.documentElement) return null;
|
|
10
|
+
const { overflowY } = window.getComputedStyle(parent);
|
|
11
|
+
if (/^(auto|scroll|hidden|overlay)$/.test(overflowY)) return parent;
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
};
|
|
15
|
+
function useStickyLayout(ref, {
|
|
16
|
+
mediaQuery,
|
|
17
|
+
offset = 0,
|
|
18
|
+
min = 0,
|
|
19
|
+
includeMarginTop = false,
|
|
20
|
+
boundaryRef,
|
|
21
|
+
watchRef,
|
|
22
|
+
bottomOffset = 0
|
|
23
|
+
} = {}) {
|
|
24
|
+
const [layout, setLayout] = react.useState(
|
|
25
|
+
() => ({
|
|
26
|
+
active: !mediaQuery,
|
|
27
|
+
top: Math.max(0, min, offset)
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
const raf = react.useRef(null);
|
|
31
|
+
const measure = react.useCallback(() => {
|
|
32
|
+
const element = ref.current;
|
|
33
|
+
if (typeof window === "undefined" || !element) return;
|
|
34
|
+
if (mediaQuery && !window.matchMedia(mediaQuery).matches) {
|
|
35
|
+
setLayout((prev) => prev.active ? { top: 0, active: false } : prev);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const scrollport = getScrollport(element);
|
|
39
|
+
const scrollportTop = scrollport ? scrollport.getBoundingClientRect().top + scrollport.clientTop : 0;
|
|
40
|
+
const scrollportBottom = scrollport ? Math.min(window.innerHeight, scrollportTop + scrollport.clientHeight) : window.innerHeight;
|
|
41
|
+
const boundary = boundaryRef == null ? void 0 : boundaryRef.current;
|
|
42
|
+
const boundaryBottom = boundary && boundary !== element ? boundary.getBoundingClientRect().bottom : scrollportTop;
|
|
43
|
+
const marginTop = includeMarginTop ? parseFloat(window.getComputedStyle(element).marginTop) || 0 : 0;
|
|
44
|
+
const top = Math.max(0, min, boundaryBottom - scrollportTop + offset - marginTop);
|
|
45
|
+
const visibleTop = Math.max(element.getBoundingClientRect().top, scrollportTop + top);
|
|
46
|
+
const maxHeight = Math.max(0, Math.floor(scrollportBottom - visibleTop - bottomOffset));
|
|
47
|
+
setLayout(
|
|
48
|
+
(prev) => prev.active && prev.top === top && prev.maxHeight === maxHeight ? prev : { top, maxHeight, active: true }
|
|
49
|
+
);
|
|
50
|
+
}, [ref, boundaryRef, offset, min, includeMarginTop, bottomOffset, mediaQuery]);
|
|
51
|
+
const scheduleMeasure = react.useCallback(() => {
|
|
52
|
+
if (raf.current !== null) return;
|
|
53
|
+
raf.current = window.requestAnimationFrame(() => {
|
|
54
|
+
raf.current = null;
|
|
55
|
+
measure();
|
|
56
|
+
});
|
|
57
|
+
}, [measure]);
|
|
58
|
+
useIsomorphicLayoutEffect(() => {
|
|
59
|
+
measure();
|
|
60
|
+
}, [measure]);
|
|
61
|
+
react.useEffect(() => {
|
|
62
|
+
if (!ref.current) return;
|
|
63
|
+
const element = ref.current;
|
|
64
|
+
const media = mediaQuery ? window.matchMedia(mediaQuery) : null;
|
|
65
|
+
media == null ? void 0 : media.addEventListener("change", scheduleMeasure);
|
|
66
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(scheduleMeasure);
|
|
67
|
+
const targets = /* @__PURE__ */ new Set([element]);
|
|
68
|
+
for (let parent = element.parentElement; parent; parent = parent.parentElement)
|
|
69
|
+
targets.add(parent);
|
|
70
|
+
if (boundaryRef == null ? void 0 : boundaryRef.current) targets.add(boundaryRef.current);
|
|
71
|
+
if (watchRef == null ? void 0 : watchRef.current) targets.add(watchRef.current);
|
|
72
|
+
targets.forEach((target) => observer == null ? void 0 : observer.observe(target));
|
|
73
|
+
window.addEventListener("resize", scheduleMeasure);
|
|
74
|
+
document.addEventListener("scroll", scheduleMeasure, true);
|
|
75
|
+
document.addEventListener("transitionend", scheduleMeasure, true);
|
|
76
|
+
document.addEventListener("animationend", scheduleMeasure, true);
|
|
77
|
+
return () => {
|
|
78
|
+
observer == null ? void 0 : observer.disconnect();
|
|
79
|
+
media == null ? void 0 : media.removeEventListener("change", scheduleMeasure);
|
|
80
|
+
window.removeEventListener("resize", scheduleMeasure);
|
|
81
|
+
document.removeEventListener("scroll", scheduleMeasure, true);
|
|
82
|
+
document.removeEventListener("transitionend", scheduleMeasure, true);
|
|
83
|
+
document.removeEventListener("animationend", scheduleMeasure, true);
|
|
84
|
+
if (raf.current !== null) cancelAnimationFrame(raf.current);
|
|
85
|
+
raf.current = null;
|
|
86
|
+
};
|
|
87
|
+
}, [ref, boundaryRef, watchRef, scheduleMeasure, mediaQuery]);
|
|
88
|
+
const style = react.useMemo(
|
|
89
|
+
() => layout.active ? { position: "sticky", top: `${layout.top}px` } : {},
|
|
90
|
+
[layout.top, layout.active]
|
|
91
|
+
);
|
|
92
|
+
const viewportStyle = react.useMemo(
|
|
93
|
+
() => layout.active ? { maxHeight: layout.maxHeight, overflowY: "auto", overscrollBehavior: "contain" } : {},
|
|
94
|
+
[layout.maxHeight, layout.active]
|
|
95
|
+
);
|
|
96
|
+
return { top: layout.top, style, viewportStyle, recompute: measure };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
exports.useStickyLayout = useStickyLayout;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CSSProperties, type RefObject } from 'react';
|
|
2
|
+
type Options = {
|
|
3
|
+
/** Enable sticky behavior only while this media query matches. */
|
|
4
|
+
mediaQuery?: string;
|
|
5
|
+
/** Extra inset below the scrollport edge or boundary, in pixels. */
|
|
6
|
+
offset?: number;
|
|
7
|
+
min?: number;
|
|
8
|
+
includeMarginTop?: boolean;
|
|
9
|
+
/** Header whose bottom edge the sticky element must stay below. */
|
|
10
|
+
boundaryRef?: RefObject<HTMLElement | null>;
|
|
11
|
+
/** Optional additional element whose resizing affects the layout. */
|
|
12
|
+
watchRef?: RefObject<HTMLElement | null>;
|
|
13
|
+
/** Breathing room below the inner scrollable content, in pixels. */
|
|
14
|
+
bottomOffset?: number;
|
|
15
|
+
};
|
|
16
|
+
export declare function useStickyLayout<T extends HTMLElement>(ref: RefObject<T | null>, { mediaQuery, offset, min, includeMarginTop, boundaryRef, watchRef, bottomOffset, }?: Options): {
|
|
17
|
+
top: number;
|
|
18
|
+
style: CSSProperties;
|
|
19
|
+
viewportStyle: CSSProperties;
|
|
20
|
+
recompute: () => void;
|
|
21
|
+
};
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useState, useRef, useCallback, useEffect, useMemo, useLayoutEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
5
|
+
const getScrollport = (element) => {
|
|
6
|
+
for (let parent = element.parentElement; parent; parent = parent.parentElement) {
|
|
7
|
+
if (parent === document.body || parent === document.documentElement) return null;
|
|
8
|
+
const { overflowY } = window.getComputedStyle(parent);
|
|
9
|
+
if (/^(auto|scroll|hidden|overlay)$/.test(overflowY)) return parent;
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
};
|
|
13
|
+
function useStickyLayout(ref, {
|
|
14
|
+
mediaQuery,
|
|
15
|
+
offset = 0,
|
|
16
|
+
min = 0,
|
|
17
|
+
includeMarginTop = false,
|
|
18
|
+
boundaryRef,
|
|
19
|
+
watchRef,
|
|
20
|
+
bottomOffset = 0
|
|
21
|
+
} = {}) {
|
|
22
|
+
const [layout, setLayout] = useState(
|
|
23
|
+
() => ({
|
|
24
|
+
active: !mediaQuery,
|
|
25
|
+
top: Math.max(0, min, offset)
|
|
26
|
+
})
|
|
27
|
+
);
|
|
28
|
+
const raf = useRef(null);
|
|
29
|
+
const measure = useCallback(() => {
|
|
30
|
+
const element = ref.current;
|
|
31
|
+
if (typeof window === "undefined" || !element) return;
|
|
32
|
+
if (mediaQuery && !window.matchMedia(mediaQuery).matches) {
|
|
33
|
+
setLayout((prev) => prev.active ? { top: 0, active: false } : prev);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const scrollport = getScrollport(element);
|
|
37
|
+
const scrollportTop = scrollport ? scrollport.getBoundingClientRect().top + scrollport.clientTop : 0;
|
|
38
|
+
const scrollportBottom = scrollport ? Math.min(window.innerHeight, scrollportTop + scrollport.clientHeight) : window.innerHeight;
|
|
39
|
+
const boundary = boundaryRef == null ? void 0 : boundaryRef.current;
|
|
40
|
+
const boundaryBottom = boundary && boundary !== element ? boundary.getBoundingClientRect().bottom : scrollportTop;
|
|
41
|
+
const marginTop = includeMarginTop ? parseFloat(window.getComputedStyle(element).marginTop) || 0 : 0;
|
|
42
|
+
const top = Math.max(0, min, boundaryBottom - scrollportTop + offset - marginTop);
|
|
43
|
+
const visibleTop = Math.max(element.getBoundingClientRect().top, scrollportTop + top);
|
|
44
|
+
const maxHeight = Math.max(0, Math.floor(scrollportBottom - visibleTop - bottomOffset));
|
|
45
|
+
setLayout(
|
|
46
|
+
(prev) => prev.active && prev.top === top && prev.maxHeight === maxHeight ? prev : { top, maxHeight, active: true }
|
|
47
|
+
);
|
|
48
|
+
}, [ref, boundaryRef, offset, min, includeMarginTop, bottomOffset, mediaQuery]);
|
|
49
|
+
const scheduleMeasure = useCallback(() => {
|
|
50
|
+
if (raf.current !== null) return;
|
|
51
|
+
raf.current = window.requestAnimationFrame(() => {
|
|
52
|
+
raf.current = null;
|
|
53
|
+
measure();
|
|
54
|
+
});
|
|
55
|
+
}, [measure]);
|
|
56
|
+
useIsomorphicLayoutEffect(() => {
|
|
57
|
+
measure();
|
|
58
|
+
}, [measure]);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (!ref.current) return;
|
|
61
|
+
const element = ref.current;
|
|
62
|
+
const media = mediaQuery ? window.matchMedia(mediaQuery) : null;
|
|
63
|
+
media == null ? void 0 : media.addEventListener("change", scheduleMeasure);
|
|
64
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(scheduleMeasure);
|
|
65
|
+
const targets = /* @__PURE__ */ new Set([element]);
|
|
66
|
+
for (let parent = element.parentElement; parent; parent = parent.parentElement)
|
|
67
|
+
targets.add(parent);
|
|
68
|
+
if (boundaryRef == null ? void 0 : boundaryRef.current) targets.add(boundaryRef.current);
|
|
69
|
+
if (watchRef == null ? void 0 : watchRef.current) targets.add(watchRef.current);
|
|
70
|
+
targets.forEach((target) => observer == null ? void 0 : observer.observe(target));
|
|
71
|
+
window.addEventListener("resize", scheduleMeasure);
|
|
72
|
+
document.addEventListener("scroll", scheduleMeasure, true);
|
|
73
|
+
document.addEventListener("transitionend", scheduleMeasure, true);
|
|
74
|
+
document.addEventListener("animationend", scheduleMeasure, true);
|
|
75
|
+
return () => {
|
|
76
|
+
observer == null ? void 0 : observer.disconnect();
|
|
77
|
+
media == null ? void 0 : media.removeEventListener("change", scheduleMeasure);
|
|
78
|
+
window.removeEventListener("resize", scheduleMeasure);
|
|
79
|
+
document.removeEventListener("scroll", scheduleMeasure, true);
|
|
80
|
+
document.removeEventListener("transitionend", scheduleMeasure, true);
|
|
81
|
+
document.removeEventListener("animationend", scheduleMeasure, true);
|
|
82
|
+
if (raf.current !== null) cancelAnimationFrame(raf.current);
|
|
83
|
+
raf.current = null;
|
|
84
|
+
};
|
|
85
|
+
}, [ref, boundaryRef, watchRef, scheduleMeasure, mediaQuery]);
|
|
86
|
+
const style = useMemo(
|
|
87
|
+
() => layout.active ? { position: "sticky", top: `${layout.top}px` } : {},
|
|
88
|
+
[layout.top, layout.active]
|
|
89
|
+
);
|
|
90
|
+
const viewportStyle = useMemo(
|
|
91
|
+
() => layout.active ? { maxHeight: layout.maxHeight, overflowY: "auto", overscrollBehavior: "contain" } : {},
|
|
92
|
+
[layout.maxHeight, layout.active]
|
|
93
|
+
);
|
|
94
|
+
return { top: layout.top, style, viewportStyle, recompute: measure };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { useStickyLayout };
|
package/dist/index.cjs
CHANGED
|
@@ -8,6 +8,7 @@ var Icon = require('./components/icon/Icon');
|
|
|
8
8
|
var UserDisplay = require('./components/user-display/UserDisplay');
|
|
9
9
|
var Headline = require('./components/headline/Headline');
|
|
10
10
|
var SectionLabel = require('./components/section-label/SectionLabel');
|
|
11
|
+
var useStickyLayout = require('./hooks/useStickyLayout');
|
|
11
12
|
var PageLayout = require('./components/page-layout/PageLayout');
|
|
12
13
|
var Footer = require('./components/page-layout/components/footer/Footer');
|
|
13
14
|
var Card = require('./components/card/Card');
|
|
@@ -100,6 +101,12 @@ Object.keys(SectionLabel).forEach(function (k) {
|
|
|
100
101
|
get: function () { return SectionLabel[k]; }
|
|
101
102
|
});
|
|
102
103
|
});
|
|
104
|
+
Object.keys(useStickyLayout).forEach(function (k) {
|
|
105
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
get: function () { return useStickyLayout[k]; }
|
|
108
|
+
});
|
|
109
|
+
});
|
|
103
110
|
Object.keys(PageLayout).forEach(function (k) {
|
|
104
111
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
105
112
|
enumerable: true,
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from './components/icon/Icon';
|
|
|
6
6
|
export * from './components/user-display/UserDisplay';
|
|
7
7
|
export * from './components/headline/Headline';
|
|
8
8
|
export * from './components/section-label/SectionLabel';
|
|
9
|
+
export * from './hooks/useStickyLayout';
|
|
9
10
|
export * from './components/page-layout/PageLayout';
|
|
10
11
|
export * from './components/page-layout/components/footer/Footer';
|
|
11
12
|
export * from './components/card/Card';
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export * from './components/icon/Icon';
|
|
|
6
6
|
export * from './components/user-display/UserDisplay';
|
|
7
7
|
export * from './components/headline/Headline';
|
|
8
8
|
export * from './components/section-label/SectionLabel';
|
|
9
|
+
export * from './hooks/useStickyLayout';
|
|
9
10
|
export * from './components/page-layout/PageLayout';
|
|
10
11
|
export * from './components/page-layout/components/footer/Footer';
|
|
11
12
|
export * from './components/card/Card';
|