@dbcdk/react-components 0.0.197 → 0.0.199
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/components/json-viewer/JsonViewer.module.css +53 -0
- package/dist/components/json-viewer/JsonViewerShell.cjs +147 -143
- package/dist/components/json-viewer/JsonViewerShell.js +149 -145
- package/dist/components/line-viewer/LineViewer.cjs +15 -21
- package/dist/components/line-viewer/LineViewer.d.ts +1 -1
- package/dist/components/line-viewer/LineViewer.js +16 -22
- package/dist/components/line-viewer/LineViewer.module.css +58 -3
- package/dist/components/page-layout/PageLayout.module.css +1 -1
- package/dist/components/scroll-fade/ScrollFade.cjs +42 -0
- package/dist/components/scroll-fade/ScrollFade.d.ts +18 -0
- package/dist/components/scroll-fade/ScrollFade.js +36 -0
- package/dist/components/scroll-fade/ScrollFade.module.css +71 -0
- package/dist/components/search-box/SearchBox.cjs +39 -35
- package/dist/components/search-box/SearchBox.d.ts +2 -0
- package/dist/components/search-box/SearchBox.js +39 -35
- package/dist/components/table/Table.cjs +52 -23
- package/dist/components/table/Table.d.ts +1 -1
- package/dist/components/table/Table.js +53 -24
- package/dist/components/table/Table.module.css +4 -0
- package/dist/components/table/Table.types.d.ts +27 -0
- package/dist/components/table/TanstackTable.cjs +63 -106
- package/dist/components/table/TanstackTable.d.ts +5 -0
- package/dist/components/table/TanstackTable.js +66 -106
- package/dist/components/table/columnLayout.utils.cjs +146 -0
- package/dist/components/table/columnLayout.utils.d.ts +44 -0
- package/dist/components/table/columnLayout.utils.js +141 -0
- package/dist/components/table/components/TableHeader.cjs +3 -1
- package/dist/components/table/components/TableHeader.d.ts +2 -1
- package/dist/components/table/components/TableHeader.js +3 -1
- package/dist/components/table/components/TableHeaderCell.cjs +29 -19
- package/dist/components/table/components/TableHeaderCell.d.ts +2 -1
- package/dist/components/table/components/TableHeaderCell.js +29 -19
- package/dist/components/table/hooks/useClientPagination.cjs +66 -0
- package/dist/components/table/hooks/useClientPagination.d.ts +32 -0
- package/dist/components/table/hooks/useClientPagination.js +64 -0
- package/dist/components/table/hooks/useDistributedLayout.cjs +44 -0
- package/dist/components/table/hooks/useDistributedLayout.d.ts +16 -0
- package/dist/components/table/hooks/useDistributedLayout.js +42 -0
- package/dist/components/table/hooks/useElementWidth.cjs +40 -0
- package/dist/components/table/hooks/useElementWidth.d.ts +7 -0
- package/dist/components/table/hooks/useElementWidth.js +38 -0
- package/dist/components/table/hooks/useResizeHeaderExtras.cjs +87 -0
- package/dist/components/table/hooks/useResizeHeaderExtras.d.ts +17 -0
- package/dist/components/table/hooks/useResizeHeaderExtras.js +62 -0
- package/dist/components/table/hooks/useUiSorting.cjs +18 -0
- package/dist/components/table/hooks/useUiSorting.d.ts +3 -0
- package/dist/components/table/hooks/useUiSorting.js +16 -0
- package/dist/components/table/table.utils.cjs +24 -2
- package/dist/components/table/table.utils.d.ts +40 -2
- package/dist/components/table/table.utils.js +20 -2
- package/dist/components/table/tanstackTable.utils.cjs +33 -97
- package/dist/components/table/tanstackTable.utils.d.ts +24 -8
- package/dist/components/table/tanstackTable.utils.js +34 -99
- package/dist/components/xml-viewer/XmlViewer.cjs +15 -21
- package/dist/components/xml-viewer/XmlViewer.d.ts +1 -1
- package/dist/components/xml-viewer/XmlViewer.js +16 -22
- package/dist/components/xml-viewer/XmlViewer.module.css +58 -3
- package/dist/hooks/useScrollOverflow.cjs +71 -0
- package/dist/hooks/useScrollOverflow.d.ts +23 -0
- package/dist/hooks/useScrollOverflow.js +69 -0
- package/dist/hooks/useTableSettings.cjs +2 -1
- package/dist/hooks/useTableSettings.d.ts +1 -0
- package/dist/hooks/useTableSettings.js +2 -1
- package/dist/index.css +1 -0
- package/dist/utils/refs.utils.cjs +13 -0
- package/dist/utils/refs.utils.d.ts +7 -0
- package/dist/utils/refs.utils.js +11 -0
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ var lucideReact = require('lucide-react');
|
|
|
6
6
|
var react = require('react');
|
|
7
7
|
var Menu = require('../../components/menu/Menu');
|
|
8
8
|
var Popover = require('../../components/popover/Popover');
|
|
9
|
+
var ScrollFade = require('../../components/scroll-fade/ScrollFade');
|
|
9
10
|
var usePersistentState = require('../../hooks/usePersistentState');
|
|
10
11
|
var tokenizeXml = require('./tokenizeXml');
|
|
11
12
|
var styles = require('./XmlViewer.module.css');
|
|
@@ -38,7 +39,6 @@ function XmlViewer({
|
|
|
38
39
|
borderless = false
|
|
39
40
|
}) {
|
|
40
41
|
const tokens = react.useMemo(() => tokenizeXml.tokenizeXml(xml), [xml]);
|
|
41
|
-
const codeRef = react.useRef(null);
|
|
42
42
|
const { value: currentAppearance, setValue: setCurrentAppearance } = usePersistentState.usePersistentState({
|
|
43
43
|
initialValue: appearance,
|
|
44
44
|
storageKey: storageKey ? `${storageKey}:appearance` : void 0,
|
|
@@ -57,25 +57,16 @@ function XmlViewer({
|
|
|
57
57
|
const handleCopy = () => {
|
|
58
58
|
void clipboard_utils.copyToClipboard(xml);
|
|
59
59
|
};
|
|
60
|
-
const handleDoubleClick = () => {
|
|
61
|
-
const el = codeRef.current;
|
|
62
|
-
const selection = typeof window !== "undefined" ? window.getSelection() : null;
|
|
63
|
-
if (!el || !selection) return;
|
|
64
|
-
const range = document.createRange();
|
|
65
|
-
range.selectNodeContents(el);
|
|
66
|
-
selection.removeAllRanges();
|
|
67
|
-
selection.addRange(range);
|
|
68
|
-
};
|
|
69
60
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
70
61
|
"section",
|
|
71
62
|
{
|
|
72
63
|
className: [styles__default.default.viewer, borderless ? styles__default.default.borderless : ""].filter(Boolean).join(" "),
|
|
73
64
|
"data-appearance": currentAppearance,
|
|
74
65
|
children: [
|
|
75
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
76
|
-
"
|
|
66
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.toolbar, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
67
|
+
"span",
|
|
77
68
|
{
|
|
78
|
-
className: styles__default.default.
|
|
69
|
+
className: styles__default.default.toolbarButton,
|
|
79
70
|
"data-surface": currentAppearance === "dark" ? "inverse" : void 0,
|
|
80
71
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
81
72
|
Popover.Popover,
|
|
@@ -156,10 +147,11 @@ function XmlViewer({
|
|
|
156
147
|
}
|
|
157
148
|
)
|
|
158
149
|
}
|
|
159
|
-
),
|
|
160
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
150
|
+
) }),
|
|
151
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScrollFade.ScrollFade, { children: (scrollRef) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
161
152
|
"pre",
|
|
162
153
|
{
|
|
154
|
+
ref: scrollRef,
|
|
163
155
|
className: [
|
|
164
156
|
styles__default.default.codePane,
|
|
165
157
|
styles__default.default[size],
|
|
@@ -167,13 +159,15 @@ function XmlViewer({
|
|
|
167
159
|
deleted ? styles__default.default.deleted : ""
|
|
168
160
|
].filter(Boolean).join(" "),
|
|
169
161
|
tabIndex: 0,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
162
|
+
children: [
|
|
163
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.toolbarSpacer, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { variant: "inline", tabIndex: -1, children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { customIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings2, {}) }) }) }),
|
|
164
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: viewMode === "raw" ? xml : tokens.map((token, index) => {
|
|
165
|
+
const tokenClassName = TOKEN_CLASS[token.type];
|
|
166
|
+
return tokenClassName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: tokenClassName, children: token.value }, index) : token.value;
|
|
167
|
+
}) })
|
|
168
|
+
]
|
|
175
169
|
}
|
|
176
|
-
)
|
|
170
|
+
) })
|
|
177
171
|
]
|
|
178
172
|
}
|
|
179
173
|
);
|
|
@@ -16,7 +16,7 @@ export interface XmlViewerProps {
|
|
|
16
16
|
*/
|
|
17
17
|
storageKey?: string;
|
|
18
18
|
/**
|
|
19
|
-
* Removes the outer border, shadow
|
|
19
|
+
* Removes the outer border, shadow, corner radius and padding, so the viewer sits
|
|
20
20
|
* flush in a container that already provides its own framing (e.g. a
|
|
21
21
|
* modal).
|
|
22
22
|
*/
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { TextWrap, ListTree, Code2, Sun, Moon, ClipboardCopy, Settings2 } from 'lucide-react';
|
|
4
|
-
import { useMemo
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
5
|
import { Menu } from '../../components/menu/Menu';
|
|
6
6
|
import { Popover } from '../../components/popover/Popover';
|
|
7
|
+
import { ScrollFade } from '../../components/scroll-fade/ScrollFade';
|
|
7
8
|
import { usePersistentState } from '../../hooks/usePersistentState';
|
|
8
9
|
import { tokenizeXml } from './tokenizeXml';
|
|
9
10
|
import styles from './XmlViewer.module.css';
|
|
@@ -32,7 +33,6 @@ function XmlViewer({
|
|
|
32
33
|
borderless = false
|
|
33
34
|
}) {
|
|
34
35
|
const tokens = useMemo(() => tokenizeXml(xml), [xml]);
|
|
35
|
-
const codeRef = useRef(null);
|
|
36
36
|
const { value: currentAppearance, setValue: setCurrentAppearance } = usePersistentState({
|
|
37
37
|
initialValue: appearance,
|
|
38
38
|
storageKey: storageKey ? `${storageKey}:appearance` : void 0,
|
|
@@ -51,25 +51,16 @@ function XmlViewer({
|
|
|
51
51
|
const handleCopy = () => {
|
|
52
52
|
void copyToClipboard(xml);
|
|
53
53
|
};
|
|
54
|
-
const handleDoubleClick = () => {
|
|
55
|
-
const el = codeRef.current;
|
|
56
|
-
const selection = typeof window !== "undefined" ? window.getSelection() : null;
|
|
57
|
-
if (!el || !selection) return;
|
|
58
|
-
const range = document.createRange();
|
|
59
|
-
range.selectNodeContents(el);
|
|
60
|
-
selection.removeAllRanges();
|
|
61
|
-
selection.addRange(range);
|
|
62
|
-
};
|
|
63
54
|
return /* @__PURE__ */ jsxs(
|
|
64
55
|
"section",
|
|
65
56
|
{
|
|
66
57
|
className: [styles.viewer, borderless ? styles.borderless : ""].filter(Boolean).join(" "),
|
|
67
58
|
"data-appearance": currentAppearance,
|
|
68
59
|
children: [
|
|
69
|
-
/* @__PURE__ */ jsx(
|
|
70
|
-
"
|
|
60
|
+
/* @__PURE__ */ jsx("div", { className: styles.toolbar, children: /* @__PURE__ */ jsx(
|
|
61
|
+
"span",
|
|
71
62
|
{
|
|
72
|
-
className: styles.
|
|
63
|
+
className: styles.toolbarButton,
|
|
73
64
|
"data-surface": currentAppearance === "dark" ? "inverse" : void 0,
|
|
74
65
|
children: /* @__PURE__ */ jsx(
|
|
75
66
|
Popover,
|
|
@@ -150,10 +141,11 @@ function XmlViewer({
|
|
|
150
141
|
}
|
|
151
142
|
)
|
|
152
143
|
}
|
|
153
|
-
),
|
|
154
|
-
/* @__PURE__ */ jsx(
|
|
144
|
+
) }),
|
|
145
|
+
/* @__PURE__ */ jsx(ScrollFade, { children: (scrollRef) => /* @__PURE__ */ jsxs(
|
|
155
146
|
"pre",
|
|
156
147
|
{
|
|
148
|
+
ref: scrollRef,
|
|
157
149
|
className: [
|
|
158
150
|
styles.codePane,
|
|
159
151
|
styles[size],
|
|
@@ -161,13 +153,15 @@ function XmlViewer({
|
|
|
161
153
|
deleted ? styles.deleted : ""
|
|
162
154
|
].filter(Boolean).join(" "),
|
|
163
155
|
tabIndex: 0,
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
156
|
+
children: [
|
|
157
|
+
/* @__PURE__ */ jsx("span", { className: styles.toolbarSpacer, "aria-hidden": "true", children: /* @__PURE__ */ jsx(Button, { variant: "inline", tabIndex: -1, children: /* @__PURE__ */ jsx(Icon, { customIcon: /* @__PURE__ */ jsx(Settings2, {}) }) }) }),
|
|
158
|
+
/* @__PURE__ */ jsx("code", { children: viewMode === "raw" ? xml : tokens.map((token, index) => {
|
|
159
|
+
const tokenClassName = TOKEN_CLASS[token.type];
|
|
160
|
+
return tokenClassName ? /* @__PURE__ */ jsx("span", { className: tokenClassName, children: token.value }, index) : token.value;
|
|
161
|
+
}) })
|
|
162
|
+
]
|
|
169
163
|
}
|
|
170
|
-
)
|
|
164
|
+
) })
|
|
171
165
|
]
|
|
172
166
|
}
|
|
173
167
|
);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
--xml-pane-bg: var(--color-bg-inverse);
|
|
3
3
|
--xml-pane-border: color-mix(in oklab, var(--color-fg-inverse) 12%, transparent);
|
|
4
4
|
--xml-pane-text: var(--color-fg-inverse);
|
|
5
|
+
--scroll-fade-color: var(--xml-pane-bg);
|
|
5
6
|
|
|
6
7
|
--xml-tag: color-mix(in oklab, var(--color-fg-inverse) 66%, var(--color-syntax-accent) 34%);
|
|
7
8
|
--xml-attr-name: color-mix(in oklab, var(--color-fg-inverse) 50%, var(--color-syntax-accent) 50%);
|
|
@@ -14,6 +15,10 @@
|
|
|
14
15
|
--xml-punctuation: color-mix(in oklab, var(--color-fg-inverse) 60%, transparent);
|
|
15
16
|
|
|
16
17
|
position: relative;
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
/* In a parent with a definite height, scroll inside instead of overflowing it. */
|
|
21
|
+
max-height: 100%;
|
|
17
22
|
background: var(--xml-pane-bg);
|
|
18
23
|
border: var(--border-width-thin) solid var(--xml-pane-border);
|
|
19
24
|
border-radius: var(--border-radius-default);
|
|
@@ -41,11 +46,61 @@
|
|
|
41
46
|
box-shadow: none;
|
|
42
47
|
}
|
|
43
48
|
|
|
49
|
+
.borderless .codePane {
|
|
50
|
+
padding: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Zero-height sticky row: sticks within the nearest scrolling ancestor, which may be outside the viewer. */
|
|
44
54
|
.toolbar {
|
|
45
|
-
position:
|
|
46
|
-
top:
|
|
47
|
-
right: var(--spacing-xs);
|
|
55
|
+
position: sticky;
|
|
56
|
+
top: 0;
|
|
48
57
|
z-index: 1;
|
|
58
|
+
display: flex;
|
|
59
|
+
justify-content: flex-end;
|
|
60
|
+
flex: none;
|
|
61
|
+
height: 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.toolbar,
|
|
65
|
+
.toolbarSpacer {
|
|
66
|
+
font-size: var(--font-size-md);
|
|
67
|
+
line-height: normal;
|
|
68
|
+
white-space: normal;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.toolbarButton {
|
|
72
|
+
display: block;
|
|
73
|
+
margin: var(--spacing-xs) var(--spacing-xs) 0 0;
|
|
74
|
+
border-radius: var(--border-radius-default);
|
|
75
|
+
/* Opaque so scrolled text doesn't show through once it's stuck. */
|
|
76
|
+
background: var(--xml-pane-bg);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.toolbarSpacer {
|
|
80
|
+
float: right;
|
|
81
|
+
visibility: hidden;
|
|
82
|
+
margin-block-start: calc(var(--spacing-xs) - var(--spacing-sm));
|
|
83
|
+
margin-inline: var(--spacing-xs) calc(var(--spacing-xs) - var(--spacing-sm));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.borderless .toolbarSpacer {
|
|
87
|
+
margin: 0;
|
|
88
|
+
padding: var(--spacing-xs) var(--spacing-xs) 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* While the pane scrolls vertically, keep the button clear of its scrollbar
|
|
92
|
+
(overlay scrollbars take no space, so nothing else moves it). */
|
|
93
|
+
.viewer:has([data-scrollable-y='true']) .toolbarButton {
|
|
94
|
+
margin-inline-end: var(--spacing-md);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.viewer:has([data-scrollable-y='true']) .toolbarSpacer {
|
|
98
|
+
margin-inline-end: calc(var(--spacing-md) - var(--spacing-sm));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.viewer.borderless:has([data-scrollable-y='true']) .toolbarSpacer {
|
|
102
|
+
margin-inline-end: 0;
|
|
103
|
+
padding-inline-end: var(--spacing-md);
|
|
49
104
|
}
|
|
50
105
|
|
|
51
106
|
.codePane {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var react = require('react');
|
|
5
|
+
|
|
6
|
+
const NONE = {
|
|
7
|
+
top: false,
|
|
8
|
+
bottom: false,
|
|
9
|
+
left: false,
|
|
10
|
+
right: false,
|
|
11
|
+
scrollbarWidth: 0,
|
|
12
|
+
scrollbarHeight: 0
|
|
13
|
+
};
|
|
14
|
+
const THRESHOLD_PX = 1;
|
|
15
|
+
function measureScrollbars(el) {
|
|
16
|
+
const style = getComputedStyle(el);
|
|
17
|
+
const borderX = parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth) || 0;
|
|
18
|
+
const borderY = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth) || 0;
|
|
19
|
+
return {
|
|
20
|
+
scrollbarWidth: Math.max(0, el.offsetWidth - el.clientWidth - borderX),
|
|
21
|
+
scrollbarHeight: Math.max(0, el.offsetHeight - el.clientHeight - borderY)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function measure(el, scrollbars) {
|
|
25
|
+
const { scrollTop, scrollLeft, scrollHeight, scrollWidth, clientHeight, clientWidth } = el;
|
|
26
|
+
return {
|
|
27
|
+
top: scrollTop > THRESHOLD_PX,
|
|
28
|
+
bottom: scrollHeight - clientHeight - scrollTop > THRESHOLD_PX,
|
|
29
|
+
left: scrollLeft > THRESHOLD_PX,
|
|
30
|
+
right: scrollWidth - clientWidth - scrollLeft > THRESHOLD_PX,
|
|
31
|
+
...scrollbars
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function sameOverflow(a, b) {
|
|
35
|
+
return Object.keys(a).every((key) => a[key] === b[key]);
|
|
36
|
+
}
|
|
37
|
+
function useScrollOverflow(el) {
|
|
38
|
+
const [overflow, setOverflow] = react.useState(NONE);
|
|
39
|
+
react.useLayoutEffect(() => {
|
|
40
|
+
if (!el) return;
|
|
41
|
+
let scrollbars = measureScrollbars(el);
|
|
42
|
+
const update = () => {
|
|
43
|
+
const next = measure(el, scrollbars);
|
|
44
|
+
setOverflow((prev) => sameOverflow(prev, next) ? prev : next);
|
|
45
|
+
};
|
|
46
|
+
const updateLayout = () => {
|
|
47
|
+
scrollbars = measureScrollbars(el);
|
|
48
|
+
update();
|
|
49
|
+
};
|
|
50
|
+
update();
|
|
51
|
+
el.addEventListener("scroll", update, { passive: true });
|
|
52
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(updateLayout) : null;
|
|
53
|
+
resizeObserver == null ? void 0 : resizeObserver.observe(el);
|
|
54
|
+
const mutationObserver = typeof MutationObserver !== "undefined" ? new MutationObserver(updateLayout) : null;
|
|
55
|
+
mutationObserver == null ? void 0 : mutationObserver.observe(el, {
|
|
56
|
+
subtree: true,
|
|
57
|
+
childList: true,
|
|
58
|
+
characterData: true,
|
|
59
|
+
attributes: true,
|
|
60
|
+
attributeFilter: ["class", "style"]
|
|
61
|
+
});
|
|
62
|
+
return () => {
|
|
63
|
+
el.removeEventListener("scroll", update);
|
|
64
|
+
resizeObserver == null ? void 0 : resizeObserver.disconnect();
|
|
65
|
+
mutationObserver == null ? void 0 : mutationObserver.disconnect();
|
|
66
|
+
};
|
|
67
|
+
}, [el]);
|
|
68
|
+
return el ? overflow : NONE;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
exports.useScrollOverflow = useScrollOverflow;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Which edges of a scroll container have more content beyond them. */
|
|
2
|
+
export type ScrollOverflow = {
|
|
3
|
+
top: boolean;
|
|
4
|
+
bottom: boolean;
|
|
5
|
+
left: boolean;
|
|
6
|
+
right: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Space taken by classic (non-overlay) scrollbars, in pixels: the vertical
|
|
9
|
+
* scrollbar's width and the horizontal one's height. Lets edge hints stay
|
|
10
|
+
* clear of the scrollbars. 0 for overlay scrollbars.
|
|
11
|
+
*/
|
|
12
|
+
scrollbarWidth: number;
|
|
13
|
+
scrollbarHeight: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Tracks which edges of the scroll container `el` hide more content, so the
|
|
17
|
+
* caller can hint at it (e.g. with edge fades) without restyling the native
|
|
18
|
+
* scrollbars. Updates on scroll, on resize and when the content changes.
|
|
19
|
+
* Takes the element rather than a ref so it follows the element when it's
|
|
20
|
+
* replaced; keep it in state via a callback ref. All edges are `false` on the
|
|
21
|
+
* server and until the first client measurement.
|
|
22
|
+
*/
|
|
23
|
+
export declare function useScrollOverflow(el: HTMLElement | null): ScrollOverflow;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useState, useLayoutEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const NONE = {
|
|
5
|
+
top: false,
|
|
6
|
+
bottom: false,
|
|
7
|
+
left: false,
|
|
8
|
+
right: false,
|
|
9
|
+
scrollbarWidth: 0,
|
|
10
|
+
scrollbarHeight: 0
|
|
11
|
+
};
|
|
12
|
+
const THRESHOLD_PX = 1;
|
|
13
|
+
function measureScrollbars(el) {
|
|
14
|
+
const style = getComputedStyle(el);
|
|
15
|
+
const borderX = parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth) || 0;
|
|
16
|
+
const borderY = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth) || 0;
|
|
17
|
+
return {
|
|
18
|
+
scrollbarWidth: Math.max(0, el.offsetWidth - el.clientWidth - borderX),
|
|
19
|
+
scrollbarHeight: Math.max(0, el.offsetHeight - el.clientHeight - borderY)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function measure(el, scrollbars) {
|
|
23
|
+
const { scrollTop, scrollLeft, scrollHeight, scrollWidth, clientHeight, clientWidth } = el;
|
|
24
|
+
return {
|
|
25
|
+
top: scrollTop > THRESHOLD_PX,
|
|
26
|
+
bottom: scrollHeight - clientHeight - scrollTop > THRESHOLD_PX,
|
|
27
|
+
left: scrollLeft > THRESHOLD_PX,
|
|
28
|
+
right: scrollWidth - clientWidth - scrollLeft > THRESHOLD_PX,
|
|
29
|
+
...scrollbars
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function sameOverflow(a, b) {
|
|
33
|
+
return Object.keys(a).every((key) => a[key] === b[key]);
|
|
34
|
+
}
|
|
35
|
+
function useScrollOverflow(el) {
|
|
36
|
+
const [overflow, setOverflow] = useState(NONE);
|
|
37
|
+
useLayoutEffect(() => {
|
|
38
|
+
if (!el) return;
|
|
39
|
+
let scrollbars = measureScrollbars(el);
|
|
40
|
+
const update = () => {
|
|
41
|
+
const next = measure(el, scrollbars);
|
|
42
|
+
setOverflow((prev) => sameOverflow(prev, next) ? prev : next);
|
|
43
|
+
};
|
|
44
|
+
const updateLayout = () => {
|
|
45
|
+
scrollbars = measureScrollbars(el);
|
|
46
|
+
update();
|
|
47
|
+
};
|
|
48
|
+
update();
|
|
49
|
+
el.addEventListener("scroll", update, { passive: true });
|
|
50
|
+
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(updateLayout) : null;
|
|
51
|
+
resizeObserver == null ? void 0 : resizeObserver.observe(el);
|
|
52
|
+
const mutationObserver = typeof MutationObserver !== "undefined" ? new MutationObserver(updateLayout) : null;
|
|
53
|
+
mutationObserver == null ? void 0 : mutationObserver.observe(el, {
|
|
54
|
+
subtree: true,
|
|
55
|
+
childList: true,
|
|
56
|
+
characterData: true,
|
|
57
|
+
attributes: true,
|
|
58
|
+
attributeFilter: ["class", "style"]
|
|
59
|
+
});
|
|
60
|
+
return () => {
|
|
61
|
+
el.removeEventListener("scroll", update);
|
|
62
|
+
resizeObserver == null ? void 0 : resizeObserver.disconnect();
|
|
63
|
+
mutationObserver == null ? void 0 : mutationObserver.disconnect();
|
|
64
|
+
};
|
|
65
|
+
}, [el]);
|
|
66
|
+
return el ? overflow : NONE;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { useScrollOverflow };
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var react = require('react');
|
|
5
|
+
var table_utils = require('../components/table/table.utils');
|
|
5
6
|
var tableSettings_utils = require('../components/table/tableSettings.utils');
|
|
6
7
|
var localStorage_utils = require('../utils/localStorage.utils');
|
|
7
8
|
|
|
@@ -27,7 +28,7 @@ const localStorageTableSettingsStorage = {
|
|
|
27
28
|
function useTableSettings({
|
|
28
29
|
storageKey,
|
|
29
30
|
tableColumns,
|
|
30
|
-
defaultViewMode =
|
|
31
|
+
defaultViewMode = table_utils.DEFAULT_VIEW_MODE,
|
|
31
32
|
defaultVisibleColumnIds,
|
|
32
33
|
defaultStriped = false,
|
|
33
34
|
storage = localStorageTableSettingsStorage
|
|
@@ -13,6 +13,7 @@ export declare const localStorageTableSettingsStorage: TableSettingsStorage;
|
|
|
13
13
|
export interface UseTableSettingsOptions<T = unknown> {
|
|
14
14
|
storageKey: string;
|
|
15
15
|
tableColumns?: ReadonlyArray<ColumnItem<T> | TableSettingsColumn>;
|
|
16
|
+
/** View mode until the user picks one. Defaults to `'wrapped'`; pass `'compact'` for even row heights. */
|
|
16
17
|
defaultViewMode?: ViewMode;
|
|
17
18
|
defaultVisibleColumnIds?: string[];
|
|
18
19
|
defaultStriped?: boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useMemo, useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import { DEFAULT_VIEW_MODE } from '../components/table/table.utils';
|
|
3
4
|
import { isSettingsColumnHidden, getSettingsColumnId } from '../components/table/tableSettings.utils';
|
|
4
5
|
import { writeLocalStorage, readLocalStorage } from '../utils/localStorage.utils';
|
|
5
6
|
|
|
@@ -25,7 +26,7 @@ const localStorageTableSettingsStorage = {
|
|
|
25
26
|
function useTableSettings({
|
|
26
27
|
storageKey,
|
|
27
28
|
tableColumns,
|
|
28
|
-
defaultViewMode =
|
|
29
|
+
defaultViewMode = DEFAULT_VIEW_MODE,
|
|
29
30
|
defaultVisibleColumnIds,
|
|
30
31
|
defaultStriped = false,
|
|
31
32
|
storage = localStorageTableSettingsStorage
|
package/dist/index.css
CHANGED
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
@import './components/pagination/Pagination.module.css';
|
|
57
57
|
@import './components/panel/Panel.module.css';
|
|
58
58
|
@import './components/popover/Popover.module.css';
|
|
59
|
+
@import './components/scroll-fade/ScrollFade.module.css';
|
|
59
60
|
@import './components/search-box/SearchBox.module.css';
|
|
60
61
|
@import './components/section-label/SectionLabel.module.css';
|
|
61
62
|
@import './components/segmented-progress-bar/SegmentedProgressBar.module.css';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Ref } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Combines refs into one callback ref. Returns a new function on every call,
|
|
4
|
+
* so memoize it (e.g. with `useMemo`) when a stable ref matters, such as when
|
|
5
|
+
* one of the refs sets state.
|
|
6
|
+
*/
|
|
7
|
+
export declare function mergeRefs<T>(...refs: Array<Ref<T> | undefined>): (node: T | null) => void;
|