@dbcdk/react-components 0.0.187 → 0.0.189

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 (40) hide show
  1. package/dist/client.cjs +7 -0
  2. package/dist/client.d.ts +1 -0
  3. package/dist/client.js +1 -0
  4. package/dist/components/badge/Badge.cjs +28 -0
  5. package/dist/components/badge/Badge.d.ts +16 -0
  6. package/dist/components/badge/Badge.js +21 -0
  7. package/dist/components/badge/Badge.module.css +53 -0
  8. package/dist/components/chip/Chip.module.css +2 -1
  9. package/dist/components/circle/Circle.module.css +4 -0
  10. package/dist/components/forms/input-container/InputContainer.cjs +11 -4
  11. package/dist/components/forms/input-container/InputContainer.d.ts +1 -1
  12. package/dist/components/forms/input-container/InputContainer.js +11 -4
  13. package/dist/components/forms/text-area/Textarea.cjs +2 -1
  14. package/dist/components/forms/text-area/Textarea.js +2 -1
  15. package/dist/components/metric-tile/MetricTile.cjs +25 -0
  16. package/dist/components/metric-tile/MetricTile.d.ts +1 -0
  17. package/dist/components/metric-tile/MetricTile.js +25 -0
  18. package/dist/components/metric-tile/MetricTile.module.css +8 -0
  19. package/dist/components/overlay/tooltip/TooltipProvider.cjs +9 -5
  20. package/dist/components/overlay/tooltip/TooltipProvider.js +9 -5
  21. package/dist/components/table/Table.cjs +1 -0
  22. package/dist/components/table/Table.js +1 -0
  23. package/dist/components/table/Table.module.css +10 -5
  24. package/dist/components/table/components/TableHeader.cjs +2 -0
  25. package/dist/components/table/components/TableHeader.d.ts +2 -1
  26. package/dist/components/table/components/TableHeader.js +2 -0
  27. package/dist/components/table/components/TableHeaderCell.cjs +2 -1
  28. package/dist/components/table/components/TableHeaderCell.d.ts +2 -1
  29. package/dist/components/table/components/TableHeaderCell.js +3 -2
  30. package/dist/components/table/components/table-settings/TableSettings.cjs +74 -67
  31. package/dist/components/table/components/table-settings/TableSettings.d.ts +13 -4
  32. package/dist/components/table/components/table-settings/TableSettings.js +75 -69
  33. package/dist/components/tabs/Tabs.module.css +34 -4
  34. package/dist/index.cjs +7 -0
  35. package/dist/index.css +1 -0
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +1 -0
  38. package/dist/styles/styles.css +7 -0
  39. package/dist/styles.css +7 -0
  40. package/package.json +1 -1
package/dist/client.cjs CHANGED
@@ -34,6 +34,7 @@ var SkeletonLoader = require('./components/skeleton-loader/SkeletonLoader');
34
34
  var Page = require('./components/page/Page');
35
35
  var Breadcrumbs = require('./components/breadcrumbs/Breadcrumbs');
36
36
  var Circle = require('./components/circle/Circle');
37
+ var Badge = require('./components/badge/Badge');
37
38
  var Checkbox = require('./components/forms/checkbox/Checkbox');
38
39
  var Switch = require('./components/forms/switch/Switch');
39
40
  var Table = require('./components/table/Table');
@@ -301,6 +302,12 @@ Object.keys(Circle).forEach(function (k) {
301
302
  get: function () { return Circle[k]; }
302
303
  });
303
304
  });
305
+ Object.keys(Badge).forEach(function (k) {
306
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
307
+ enumerable: true,
308
+ get: function () { return Badge[k]; }
309
+ });
310
+ });
304
311
  Object.keys(Checkbox).forEach(function (k) {
305
312
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
306
313
  enumerable: true,
package/dist/client.d.ts CHANGED
@@ -31,6 +31,7 @@ export * from './components/skeleton-loader/SkeletonLoader';
31
31
  export * from './components/page/Page';
32
32
  export * from './components/breadcrumbs/Breadcrumbs';
33
33
  export * from './components/circle/Circle';
34
+ export * from './components/badge/Badge';
34
35
  export * from './components/forms/checkbox/Checkbox';
35
36
  export * from './components/forms/switch/Switch';
36
37
  export * from './components/table/Table';
package/dist/client.js CHANGED
@@ -32,6 +32,7 @@ export * from './components/skeleton-loader/SkeletonLoader';
32
32
  export * from './components/page/Page';
33
33
  export * from './components/breadcrumbs/Breadcrumbs';
34
34
  export * from './components/circle/Circle';
35
+ export * from './components/badge/Badge';
35
36
  export * from './components/forms/checkbox/Checkbox';
36
37
  export * from './components/forms/switch/Switch';
37
38
  export * from './components/table/Table';
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var styles = require('./Badge.module.css');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var styles__default = /*#__PURE__*/_interopDefault(styles);
9
+
10
+ function formatBadgeCount(count, max) {
11
+ return count > max ? `${max}+` : String(count);
12
+ }
13
+ function Badge({
14
+ children,
15
+ count,
16
+ max = 99,
17
+ severity = "error",
18
+ dot = false
19
+ }) {
20
+ const showBadge = dot || typeof count === "number" && count > 0;
21
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.wrapper, children: [
22
+ children,
23
+ showBadge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${styles__default.default.badge} ${styles__default.default[severity]}`, "data-dot": dot || void 0, children: !dot && typeof count === "number" ? formatBadgeCount(count, max) : null })
24
+ ] });
25
+ }
26
+
27
+ exports.Badge = Badge;
28
+ exports.formatBadgeCount = formatBadgeCount;
@@ -0,0 +1,16 @@
1
+ import type { ReactNode, JSX } from 'react';
2
+ import { Severity } from '../../constants/severity.types';
3
+ interface BadgeProps {
4
+ /** The element the badge is overlaid on top of, e.g. an icon. */
5
+ children: ReactNode;
6
+ /** Shown inside the badge, capped at `max`. Omit (with `dot` false) to render nothing. */
7
+ count?: number;
8
+ /** Counts above this render as `${max}+`. */
9
+ max?: number;
10
+ severity?: Severity;
11
+ /** Render a plain dot instead of a count - use when only "something changed" matters, not how much. */
12
+ dot?: boolean;
13
+ }
14
+ export declare function formatBadgeCount(count: number, max: number): string;
15
+ export declare function Badge({ children, count, max, severity, dot, }: BadgeProps): JSX.Element;
16
+ export {};
@@ -0,0 +1,21 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import styles from './Badge.module.css';
3
+
4
+ function formatBadgeCount(count, max) {
5
+ return count > max ? `${max}+` : String(count);
6
+ }
7
+ function Badge({
8
+ children,
9
+ count,
10
+ max = 99,
11
+ severity = "error",
12
+ dot = false
13
+ }) {
14
+ const showBadge = dot || typeof count === "number" && count > 0;
15
+ return /* @__PURE__ */ jsxs("span", { className: styles.wrapper, children: [
16
+ children,
17
+ showBadge && /* @__PURE__ */ jsx("span", { className: `${styles.badge} ${styles[severity]}`, "data-dot": dot || void 0, children: !dot && typeof count === "number" ? formatBadgeCount(count, max) : null })
18
+ ] });
19
+ }
20
+
21
+ export { Badge, formatBadgeCount };
@@ -0,0 +1,53 @@
1
+ .wrapper {
2
+ position: relative;
3
+ display: inline-flex;
4
+ }
5
+
6
+ .badge {
7
+ box-sizing: border-box;
8
+ block-size: 14px;
9
+ min-inline-size: 14px;
10
+ padding-inline: var(--spacing-2xs);
11
+ border-radius: var(--border-radius-rounded);
12
+ font-size: 12px;
13
+ color: var(--color-fg-inverse);
14
+ pointer-events: none;
15
+ justify-content: center;
16
+ align-items: center;
17
+ line-height: 1;
18
+ display: inline-flex;
19
+ position: absolute;
20
+ top: 0;
21
+ right: 0;
22
+ transform: translate(50%, -30%);
23
+ }
24
+
25
+ .badge[data-dot='true'] {
26
+ min-inline-size: 8px;
27
+ inline-size: 8px;
28
+ block-size: 8px;
29
+ padding-inline: 0;
30
+ border-radius: var(--border-radius-round);
31
+ }
32
+
33
+ .neutral {
34
+ background-color: var(--color-neutral);
35
+ }
36
+ .brand {
37
+ background-color: var(--color-brand);
38
+ }
39
+ .accent {
40
+ background-color: var(--color-accent);
41
+ }
42
+ .success {
43
+ background-color: var(--color-status-success);
44
+ }
45
+ .warning {
46
+ background-color: var(--color-status-warning);
47
+ }
48
+ .error {
49
+ background-color: var(--color-status-error);
50
+ }
51
+ .info {
52
+ background-color: var(--color-status-info);
53
+ }
@@ -93,6 +93,7 @@
93
93
  .sm {
94
94
  height: var(--component-size-xs);
95
95
  font-size: var(--font-size-xs);
96
+ padding-inline: var(--spacing-xs);
96
97
  }
97
98
 
98
99
  .md {
@@ -109,7 +110,7 @@
109
110
  .neutral {
110
111
  /* Tinted from the current foreground color instead of a fixed gray, so it
111
112
  stays visible whether it's sitting on a white panel or a muted toolbar. */
112
- --chip-bg: color-mix(in srgb, var(--color-fg-default) 12%, transparent);
113
+ --chip-bg: color-mix(in srgb, var(--color-fg-default) 8%, transparent);
113
114
  --chip-fg: var(--color-fg-default);
114
115
  --chip-border: transparent;
115
116
  --chip-outlined-border: var(--color-border-subtle);
@@ -14,6 +14,10 @@
14
14
  font-size: var(--font-size-xs);
15
15
  }
16
16
 
17
+ .container[data-size='xs'] {
18
+ gap: var(--spacing-xxs);
19
+ }
20
+
17
21
  .circle {
18
22
  position: relative;
19
23
  display: inline-block;
@@ -21,6 +21,7 @@ function InputContainer({
21
21
  orientation = "horizontal",
22
22
  size = "md",
23
23
  labelWidth = "160px",
24
+ labelAlignment = "center",
24
25
  modified = false
25
26
  }) {
26
27
  const renderLabelRow = (label || labelAction) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles__default.default.labelRow} dbc-flex dbc-items-center dbc-gap-md`, children: [
@@ -59,10 +60,16 @@ function InputContainer({
59
60
  width: fullWidth ? "100%" : void 0
60
61
  },
61
62
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles__default.default.horizontal} dbc-flex dbc-flex-column dbc-gap-xs`, "data-size": size, children: [
62
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles__default.default.labelContainer} dbc-flex dbc-items-center dbc-gap-xs`, children: [
63
- renderLabelRow,
64
- children
65
- ] }),
63
+ /* @__PURE__ */ jsxRuntime.jsxs(
64
+ "div",
65
+ {
66
+ className: `${styles__default.default.labelContainer} dbc-flex ${labelAlignment === "top" ? "dbc-items-start" : "dbc-items-center"} dbc-gap-xs`,
67
+ children: [
68
+ renderLabelRow,
69
+ children
70
+ ]
71
+ }
72
+ ),
66
73
  renderMessageRow
67
74
  ] })
68
75
  }
@@ -15,4 +15,4 @@ export interface InputContainerProps {
15
15
  labelAlignment?: 'top' | 'center';
16
16
  modified?: boolean;
17
17
  }
18
- export declare function InputContainer({ label, labelAction, htmlFor, error, helpText, helpTextAddition, fullWidth, required, children, orientation, size, labelWidth, modified, }: InputContainerProps): React.ReactElement;
18
+ export declare function InputContainer({ label, labelAction, htmlFor, error, helpText, helpTextAddition, fullWidth, required, children, orientation, size, labelWidth, labelAlignment, modified, }: InputContainerProps): React.ReactElement;
@@ -15,6 +15,7 @@ function InputContainer({
15
15
  orientation = "horizontal",
16
16
  size = "md",
17
17
  labelWidth = "160px",
18
+ labelAlignment = "center",
18
19
  modified = false
19
20
  }) {
20
21
  const renderLabelRow = (label || labelAction) && /* @__PURE__ */ jsxs("div", { className: `${styles.labelRow} dbc-flex dbc-items-center dbc-gap-md`, children: [
@@ -53,10 +54,16 @@ function InputContainer({
53
54
  width: fullWidth ? "100%" : void 0
54
55
  },
55
56
  children: /* @__PURE__ */ jsxs("div", { className: `${styles.horizontal} dbc-flex dbc-flex-column dbc-gap-xs`, "data-size": size, children: [
56
- /* @__PURE__ */ jsxs("div", { className: `${styles.labelContainer} dbc-flex dbc-items-center dbc-gap-xs`, children: [
57
- renderLabelRow,
58
- children
59
- ] }),
57
+ /* @__PURE__ */ jsxs(
58
+ "div",
59
+ {
60
+ className: `${styles.labelContainer} dbc-flex ${labelAlignment === "top" ? "dbc-items-start" : "dbc-items-center"} dbc-gap-xs`,
61
+ children: [
62
+ renderLabelRow,
63
+ children
64
+ ]
65
+ }
66
+ ),
60
67
  renderMessageRow
61
68
  ] })
62
69
  }
@@ -28,6 +28,7 @@ const Textarea = function Textarea2({
28
28
  label,
29
29
  error,
30
30
  helpText,
31
+ helpTextAddition,
31
32
  orientation = "horizontal",
32
33
  labelWidth = "160px",
33
34
  fullWidth = false,
@@ -97,7 +98,7 @@ const Textarea = function Textarea2({
97
98
  htmlFor: textareaId,
98
99
  error,
99
100
  helpText,
100
- helpTextAddition: showCount ? `${value == null ? void 0 : value.length} tegn i denne boks` : void 0,
101
+ helpTextAddition: helpTextAddition != null ? helpTextAddition : showCount ? `${value == null ? void 0 : value.length} tegn i denne boks` : void 0,
101
102
  orientation,
102
103
  labelWidth,
103
104
  fullWidth,
@@ -22,6 +22,7 @@ const Textarea = function Textarea2({
22
22
  label,
23
23
  error,
24
24
  helpText,
25
+ helpTextAddition,
25
26
  orientation = "horizontal",
26
27
  labelWidth = "160px",
27
28
  fullWidth = false,
@@ -91,7 +92,7 @@ const Textarea = function Textarea2({
91
92
  htmlFor: textareaId,
92
93
  error,
93
94
  helpText,
94
- helpTextAddition: showCount ? `${value == null ? void 0 : value.length} tegn i denne boks` : void 0,
95
+ helpTextAddition: helpTextAddition != null ? helpTextAddition : showCount ? `${value == null ? void 0 : value.length} tegn i denne boks` : void 0,
95
96
  orientation,
96
97
  labelWidth,
97
98
  fullWidth,
@@ -51,6 +51,7 @@ const MetricTileBase = ({
51
51
  label,
52
52
  icon,
53
53
  value,
54
+ onClick,
54
55
  tooltip,
55
56
  size = "md",
56
57
  variant = "filled",
@@ -69,14 +70,38 @@ const MetricTileBase = ({
69
70
  const resolvedValue = (_b = (_a = slots.Value) == null ? void 0 : _a.props.children) != null ? _b : value;
70
71
  const resolvedAdornment = (_c = slots.Adornment) == null ? void 0 : _c.props.children;
71
72
  const showValueRow = resolvedValue != null || resolvedAdornment != null;
73
+ const isClickable = onClick != null;
74
+ const handleKeyDown = (event) => {
75
+ if (!isClickable) return;
76
+ if (event.key === "Enter") {
77
+ event.preventDefault();
78
+ onClick == null ? void 0 : onClick();
79
+ }
80
+ if (event.key === " ") {
81
+ event.preventDefault();
82
+ }
83
+ };
84
+ const handleKeyUp = (event) => {
85
+ if (!isClickable) return;
86
+ if (event.key === " ") {
87
+ event.preventDefault();
88
+ onClick == null ? void 0 : onClick();
89
+ }
90
+ };
72
91
  return /* @__PURE__ */ jsxRuntime.jsx(client.Tooltip, { content: tooltip, placement: "bottom", children: /* @__PURE__ */ jsxRuntime.jsxs(
73
92
  "span",
74
93
  {
75
94
  className: styles__default.default.tile,
95
+ role: isClickable ? "button" : void 0,
96
+ tabIndex: isClickable ? 0 : void 0,
76
97
  "data-severity": severity,
77
98
  "data-size": size,
78
99
  "data-variant": variant,
100
+ "data-clickable": isClickable ? "true" : void 0,
79
101
  style,
102
+ onClick,
103
+ onKeyDown: handleKeyDown,
104
+ onKeyUp: handleKeyUp,
80
105
  children: [
81
106
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.labelRow, children: [
82
107
  icon != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.icon, children: icon }) : null,
@@ -11,6 +11,7 @@ interface MetricTileProps extends PropsWithChildren {
11
11
  label: string;
12
12
  icon?: JSX.Element;
13
13
  value?: string | number;
14
+ onClick?: () => void;
14
15
  tooltip?: ReactNode;
15
16
  size?: MetricTileSize;
16
17
  variant?: MetricTileVariant;
@@ -45,6 +45,7 @@ const MetricTileBase = ({
45
45
  label,
46
46
  icon,
47
47
  value,
48
+ onClick,
48
49
  tooltip,
49
50
  size = "md",
50
51
  variant = "filled",
@@ -63,14 +64,38 @@ const MetricTileBase = ({
63
64
  const resolvedValue = (_b = (_a = slots.Value) == null ? void 0 : _a.props.children) != null ? _b : value;
64
65
  const resolvedAdornment = (_c = slots.Adornment) == null ? void 0 : _c.props.children;
65
66
  const showValueRow = resolvedValue != null || resolvedAdornment != null;
67
+ const isClickable = onClick != null;
68
+ const handleKeyDown = (event) => {
69
+ if (!isClickable) return;
70
+ if (event.key === "Enter") {
71
+ event.preventDefault();
72
+ onClick == null ? void 0 : onClick();
73
+ }
74
+ if (event.key === " ") {
75
+ event.preventDefault();
76
+ }
77
+ };
78
+ const handleKeyUp = (event) => {
79
+ if (!isClickable) return;
80
+ if (event.key === " ") {
81
+ event.preventDefault();
82
+ onClick == null ? void 0 : onClick();
83
+ }
84
+ };
66
85
  return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, placement: "bottom", children: /* @__PURE__ */ jsxs(
67
86
  "span",
68
87
  {
69
88
  className: styles.tile,
89
+ role: isClickable ? "button" : void 0,
90
+ tabIndex: isClickable ? 0 : void 0,
70
91
  "data-severity": severity,
71
92
  "data-size": size,
72
93
  "data-variant": variant,
94
+ "data-clickable": isClickable ? "true" : void 0,
73
95
  style,
96
+ onClick,
97
+ onKeyDown: handleKeyDown,
98
+ onKeyUp: handleKeyUp,
74
99
  children: [
75
100
  /* @__PURE__ */ jsxs("span", { className: styles.labelRow, children: [
76
101
  icon != null ? /* @__PURE__ */ jsx("span", { className: styles.icon, children: icon }) : null,
@@ -19,6 +19,14 @@
19
19
  cursor: default;
20
20
  }
21
21
 
22
+ .tile[data-clickable='true'] {
23
+ cursor: pointer;
24
+ }
25
+
26
+ .tile[data-clickable='true']:focus-visible {
27
+ box-shadow: var(--focus-ring);
28
+ }
29
+
22
30
  .tile[data-size='sm'] {
23
31
  gap: 1px;
24
32
  padding: 6px var(--spacing-sm);
@@ -119,7 +119,7 @@ function TooltipLayer() {
119
119
  const triggerRect = trigger.getBoundingClientRect();
120
120
  const bubbleRect = bubble.getBoundingClientRect();
121
121
  if (bubbleRect.width === 0 || bubbleRect.height === 0) {
122
- if (visible) setVisible(false);
122
+ setVisible((prev) => prev ? false : prev);
123
123
  if (rafRef.current) cancelAnimationFrame(rafRef.current);
124
124
  rafRef.current = requestAnimationFrame(recompute);
125
125
  return;
@@ -158,13 +158,17 @@ function TooltipLayer() {
158
158
  lastPlacementRef.current = chosen;
159
159
  setPlacement(chosen);
160
160
  }
161
- if (!visible) setVisible(true);
162
- }, [active == null ? void 0 : active.open, active == null ? void 0 : active.triggerEl, active == null ? void 0 : active.placement, active == null ? void 0 : active.offset, visible]);
161
+ setVisible((prev) => prev ? prev : true);
162
+ }, [active == null ? void 0 : active.open, active == null ? void 0 : active.triggerEl, active == null ? void 0 : active.placement, active == null ? void 0 : active.offset]);
163
163
  react.useEffect(() => {
164
164
  const nextOpen = !!(active == null ? void 0 : active.open);
165
165
  setOpen((prev) => prev === nextOpen ? prev : nextOpen);
166
- if (nextOpen) setVisible(false);
167
- if (!nextOpen) lastActiveIdRef.current = null;
166
+ if (nextOpen) {
167
+ setVisible(false);
168
+ } else {
169
+ setVisible(false);
170
+ lastActiveIdRef.current = null;
171
+ }
168
172
  }, [active == null ? void 0 : active.open]);
169
173
  react.useLayoutEffect(() => {
170
174
  var _a;
@@ -113,7 +113,7 @@ function TooltipLayer() {
113
113
  const triggerRect = trigger.getBoundingClientRect();
114
114
  const bubbleRect = bubble.getBoundingClientRect();
115
115
  if (bubbleRect.width === 0 || bubbleRect.height === 0) {
116
- if (visible) setVisible(false);
116
+ setVisible((prev) => prev ? false : prev);
117
117
  if (rafRef.current) cancelAnimationFrame(rafRef.current);
118
118
  rafRef.current = requestAnimationFrame(recompute);
119
119
  return;
@@ -152,13 +152,17 @@ function TooltipLayer() {
152
152
  lastPlacementRef.current = chosen;
153
153
  setPlacement(chosen);
154
154
  }
155
- if (!visible) setVisible(true);
156
- }, [active == null ? void 0 : active.open, active == null ? void 0 : active.triggerEl, active == null ? void 0 : active.placement, active == null ? void 0 : active.offset, visible]);
155
+ setVisible((prev) => prev ? prev : true);
156
+ }, [active == null ? void 0 : active.open, active == null ? void 0 : active.triggerEl, active == null ? void 0 : active.placement, active == null ? void 0 : active.offset]);
157
157
  useEffect(() => {
158
158
  const nextOpen = !!(active == null ? void 0 : active.open);
159
159
  setOpen((prev) => prev === nextOpen ? prev : nextOpen);
160
- if (nextOpen) setVisible(false);
161
- if (!nextOpen) lastActiveIdRef.current = null;
160
+ if (nextOpen) {
161
+ setVisible(false);
162
+ } else {
163
+ setVisible(false);
164
+ lastActiveIdRef.current = null;
165
+ }
162
166
  }, [active == null ? void 0 : active.open]);
163
167
  useLayoutEffect(() => {
164
168
  var _a;
@@ -197,6 +197,7 @@ function Table({
197
197
  columns: visibleColumns,
198
198
  hasSelection,
199
199
  selectionMode,
200
+ hasRowContextMenu: Boolean(getContextMenuItems),
200
201
  allRowsSelected,
201
202
  onSelectAllRows,
202
203
  sortById,
@@ -191,6 +191,7 @@ function Table({
191
191
  columns: visibleColumns,
192
192
  hasSelection,
193
193
  selectionMode,
194
+ hasRowContextMenu: Boolean(getContextMenuItems),
194
195
  allRowsSelected,
195
196
  onSelectAllRows,
196
197
  sortById,
@@ -58,6 +58,7 @@
58
58
  --table-component-cell-fg: var(--table-cell-fg);
59
59
  --table-component-cell-border: var(--table-border-subtle);
60
60
  --table-component-divider: var(--table-divider);
61
+ --table-row-actions-reserve-inline: calc(var(--component-size-md) + 4px + var(--spacing-2xs));
61
62
 
62
63
  display: flex;
63
64
  flex-direction: column;
@@ -188,13 +189,13 @@
188
189
  }
189
190
 
190
191
  .md .headerCell {
191
- padding-block: var(--spacing-xs);
192
- padding-inline: var(--spacing-sm);
192
+ padding-block: var(--spacing-xxs);
193
+ padding-inline: var(--spacing-xs);
193
194
  }
194
195
 
195
196
  .md .cell {
196
- padding-block: var(--spacing-xs);
197
- padding-inline: var(--spacing-sm);
197
+ padding-block: var(--spacing-xxs);
198
+ padding-inline: var(--spacing-xs);
198
199
  }
199
200
 
200
201
  .sm .headerCell {
@@ -371,6 +372,10 @@
371
372
  justify-content: flex-start;
372
373
  }
373
374
 
375
+ .thMainWithActionsReserve {
376
+ padding-inline-end: var(--table-row-actions-reserve-inline);
377
+ }
378
+
374
379
  .thMainRight {
375
380
  justify-content: flex-end;
376
381
  }
@@ -620,7 +625,7 @@
620
625
  }
621
626
 
622
627
  .cellContentWithActions {
623
- padding-inline-end: calc(var(--component-size-md) + 4px + var(--spacing-sm));
628
+ padding-inline-end: var(--table-row-actions-reserve-inline);
624
629
  }
625
630
 
626
631
  .contextMenuTrigger:hover,
@@ -13,6 +13,7 @@ function TableHeader({
13
13
  columns,
14
14
  hasSelection,
15
15
  selectionMode,
16
+ hasRowContextMenu,
16
17
  allRowsSelected,
17
18
  onSelectAllRows,
18
19
  sortById,
@@ -42,6 +43,7 @@ function TableHeader({
42
43
  {
43
44
  column,
44
45
  index,
46
+ reserveInlineEnd: hasRowContextMenu && index === columns.length - 1,
45
47
  sortById,
46
48
  sortDirection,
47
49
  onSortChange,
@@ -4,6 +4,7 @@ type Props<T> = {
4
4
  columns: ColumnItem<T>[];
5
5
  hasSelection: boolean;
6
6
  selectionMode: 'single' | 'multiple';
7
+ hasRowContextMenu: boolean;
7
8
  allRowsSelected?: boolean;
8
9
  onSelectAllRows?: (isSelected: boolean) => void;
9
10
  sortById?: string;
@@ -12,5 +13,5 @@ type Props<T> = {
12
13
  headerExtras?: (args: HeaderExtrasArgs<T>) => ReactNode;
13
14
  stickyTop?: string;
14
15
  };
15
- export declare function TableHeader<T>({ columns, hasSelection, selectionMode, allRowsSelected, onSelectAllRows, sortById, sortDirection, onSortChange, headerExtras, stickyTop, }: Props<T>): React.ReactNode;
16
+ export declare function TableHeader<T>({ columns, hasSelection, selectionMode, hasRowContextMenu, allRowsSelected, onSelectAllRows, sortById, sortDirection, onSortChange, headerExtras, stickyTop, }: Props<T>): React.ReactNode;
16
17
  export {};
@@ -7,6 +7,7 @@ function TableHeader({
7
7
  columns,
8
8
  hasSelection,
9
9
  selectionMode,
10
+ hasRowContextMenu,
10
11
  allRowsSelected,
11
12
  onSelectAllRows,
12
13
  sortById,
@@ -36,6 +37,7 @@ function TableHeader({
36
37
  {
37
38
  column,
38
39
  index,
40
+ reserveInlineEnd: hasRowContextMenu && index === columns.length - 1,
39
41
  sortById,
40
42
  sortDirection,
41
43
  onSortChange,
@@ -13,6 +13,7 @@ var styles__default = /*#__PURE__*/_interopDefault(styles);
13
13
  function TableHeaderCell({
14
14
  column,
15
15
  index,
16
+ reserveInlineEnd = false,
16
17
  sortById,
17
18
  sortDirection,
18
19
  onSortChange,
@@ -37,7 +38,7 @@ function TableHeaderCell({
37
38
  "data-divider": column.divider,
38
39
  "data-column-index": index,
39
40
  children: [
40
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: alignClasses.inner, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: alignClasses.main, children: column.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
41
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: alignClasses.inner, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: table_classes.cx(alignClasses.main, reserveInlineEnd && styles__default.default.thMainWithActionsReserve), children: column.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
41
42
  "button",
42
43
  {
43
44
  type: "button",
@@ -3,10 +3,11 @@ import type { ColumnItem, SortDirection } from '../Table.types';
3
3
  type Props<T> = {
4
4
  column: ColumnItem<T>;
5
5
  index: number;
6
+ reserveInlineEnd?: boolean;
6
7
  sortById?: string;
7
8
  sortDirection?: SortDirection;
8
9
  onSortChange?: (column: ColumnItem<T>, direction: SortDirection) => void;
9
10
  extraContent?: ReactNode;
10
11
  };
11
- export declare function TableHeaderCell<T>({ column, index, sortById, sortDirection, onSortChange, extraContent, }: Props<T>): ReactNode;
12
+ export declare function TableHeaderCell<T>({ column, index, reserveInlineEnd, sortById, sortDirection, onSortChange, extraContent, }: Props<T>): ReactNode;
12
13
  export {};
@@ -1,12 +1,13 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { ArrowUp, ArrowDown } from 'lucide-react';
3
- import { getAlignValue, getHeaderAlignClasses } from '../table.classes';
3
+ import { getAlignValue, getHeaderAlignClasses, cx } from '../table.classes';
4
4
  import styles from '../Table.module.css';
5
5
  import { isActiveSort, getAriaSort, getHeaderLabel, shouldToggleOnKey, getNextSortDirection } from '../table.utils';
6
6
 
7
7
  function TableHeaderCell({
8
8
  column,
9
9
  index,
10
+ reserveInlineEnd = false,
10
11
  sortById,
11
12
  sortDirection,
12
13
  onSortChange,
@@ -31,7 +32,7 @@ function TableHeaderCell({
31
32
  "data-divider": column.divider,
32
33
  "data-column-index": index,
33
34
  children: [
34
- /* @__PURE__ */ jsx("div", { className: alignClasses.inner, children: /* @__PURE__ */ jsx("div", { className: alignClasses.main, children: column.sortable ? /* @__PURE__ */ jsxs(
35
+ /* @__PURE__ */ jsx("div", { className: alignClasses.inner, children: /* @__PURE__ */ jsx("div", { className: cx(alignClasses.main, reserveInlineEnd && styles.thMainWithActionsReserve), children: column.sortable ? /* @__PURE__ */ jsxs(
35
36
  "button",
36
37
  {
37
38
  type: "button",
@@ -8,7 +8,7 @@ var Button = require('../../../button/Button');
8
8
  var Menu = require('../../../menu/Menu');
9
9
  var Popover = require('../../../popover/Popover');
10
10
 
11
- function TableSettings({
11
+ function TableSettingsMenuSection({
12
12
  viewMode,
13
13
  handleChangeViewMode,
14
14
  columns = [],
@@ -17,12 +17,12 @@ function TableSettings({
17
17
  columnsLabel = "Kolonner",
18
18
  allPresetLabel = "Alle",
19
19
  standardPresetLabel = "Standard",
20
- buttonSize = "sm",
21
- additionalSettings
20
+ additionalSettings,
21
+ close
22
22
  }) {
23
- const handleViewModeChange = (mode, close) => {
23
+ const handleViewModeChange = (mode, close2) => {
24
24
  handleChangeViewMode(mode === "wrapped" ? "compact" : "wrapped");
25
- close == null ? void 0 : close();
25
+ close2 == null ? void 0 : close2();
26
26
  };
27
27
  const hideableColumns = react.useMemo(() => columns.filter((c) => c.enableHiding !== false), [columns]);
28
28
  const allPresetIds = react.useMemo(() => hideableColumns.map((c) => c.id), [hideableColumns]);
@@ -63,6 +63,73 @@ function TableSettings({
63
63
  return hideableColumns.every((c) => c.id && visibleSet.has(c.id) === std.has(c.id));
64
64
  }, [hideableColumns, visibleSet, standardPresetIds]);
65
65
  const presetRadioName = "table-columns-preset";
66
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
67
+ additionalSettings == null ? void 0 : additionalSettings(close),
68
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { active: viewMode === "wrapped", children: /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", onClick: () => handleViewModeChange(viewMode, close), children: [
69
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListChevronsUpDown, {}),
70
+ "Ombryd tekst"
71
+ ] }) }),
72
+ hideableColumns.length > 0 && onVisibleColumnIdsChange ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
73
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
74
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "6px 10px", fontSize: 12, opacity: 0.7 }, children: columnsLabel }),
75
+ /* @__PURE__ */ jsxRuntime.jsx(
76
+ Menu.Menu.RadioItem,
77
+ {
78
+ name: presetRadioName,
79
+ value: "all",
80
+ checked: isAllActive,
81
+ label: allPresetLabel,
82
+ onValueChange: () => {
83
+ setVisibleIds(
84
+ allPresetIds.filter((id) => typeof id === "string" && Boolean(id))
85
+ );
86
+ close == null ? void 0 : close();
87
+ }
88
+ }
89
+ ),
90
+ /* @__PURE__ */ jsxRuntime.jsx(
91
+ Menu.Menu.RadioItem,
92
+ {
93
+ name: presetRadioName,
94
+ value: "standard",
95
+ checked: isStandardActive,
96
+ label: standardPresetLabel,
97
+ onValueChange: () => {
98
+ setVisibleIds(
99
+ standardPresetIds.filter(
100
+ (id) => typeof id === "string" && Boolean(id)
101
+ )
102
+ );
103
+ close == null ? void 0 : close();
104
+ }
105
+ }
106
+ ),
107
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
108
+ hideableColumns.map((col) => {
109
+ const isVisible = col.id ? visibleSet.has(col.id) : false;
110
+ const disableUncheckingLast = isVisible && visibleCount <= 1;
111
+ const label = col.header;
112
+ return /* @__PURE__ */ jsxRuntime.jsx(
113
+ Menu.Menu.CheckItem,
114
+ {
115
+ checked: isVisible,
116
+ disabled: disableUncheckingLast,
117
+ label,
118
+ onCheckedChange: (nextChecked) => {
119
+ if (disableUncheckingLast) return;
120
+ toggleColumn(col.id, nextChecked);
121
+ }
122
+ },
123
+ col.id
124
+ );
125
+ })
126
+ ] }) : null
127
+ ] });
128
+ }
129
+ function TableSettings({
130
+ buttonSize = "sm",
131
+ ...sectionProps
132
+ }) {
66
133
  return /* @__PURE__ */ jsxRuntime.jsx(
67
134
  Popover.Popover,
68
135
  {
@@ -70,70 +137,10 @@ function TableSettings({
70
137
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, {}),
71
138
  icon
72
139
  ] }),
73
- children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(Menu.Menu, { children: [
74
- additionalSettings == null ? void 0 : additionalSettings(close),
75
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { active: viewMode === "wrapped", children: /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", onClick: () => handleViewModeChange(viewMode, close), children: [
76
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListChevronsUpDown, {}),
77
- "Ombryd tekst"
78
- ] }) }),
79
- hideableColumns.length > 0 && onVisibleColumnIdsChange ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
80
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
81
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "6px 10px", fontSize: 12, opacity: 0.7 }, children: columnsLabel }),
82
- /* @__PURE__ */ jsxRuntime.jsx(
83
- Menu.Menu.RadioItem,
84
- {
85
- name: presetRadioName,
86
- value: "all",
87
- checked: isAllActive,
88
- label: allPresetLabel,
89
- onValueChange: () => {
90
- setVisibleIds(
91
- allPresetIds.filter((id) => typeof id === "string" && Boolean(id))
92
- );
93
- close == null ? void 0 : close();
94
- }
95
- }
96
- ),
97
- /* @__PURE__ */ jsxRuntime.jsx(
98
- Menu.Menu.RadioItem,
99
- {
100
- name: presetRadioName,
101
- value: "standard",
102
- checked: isStandardActive,
103
- label: standardPresetLabel,
104
- onValueChange: () => {
105
- setVisibleIds(
106
- standardPresetIds.filter(
107
- (id) => typeof id === "string" && Boolean(id)
108
- )
109
- );
110
- close == null ? void 0 : close();
111
- }
112
- }
113
- ),
114
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
115
- hideableColumns.map((col) => {
116
- const isVisible = col.id ? visibleSet.has(col.id) : false;
117
- const disableUncheckingLast = isVisible && visibleCount <= 1;
118
- const label = col.header;
119
- return /* @__PURE__ */ jsxRuntime.jsx(
120
- Menu.Menu.CheckItem,
121
- {
122
- checked: isVisible,
123
- disabled: disableUncheckingLast,
124
- label,
125
- onCheckedChange: (nextChecked) => {
126
- if (disableUncheckingLast) return;
127
- toggleColumn(col.id, nextChecked);
128
- }
129
- },
130
- col.id
131
- );
132
- })
133
- ] }) : null
134
- ] })
140
+ children: (close) => /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu, { children: /* @__PURE__ */ jsxRuntime.jsx(TableSettingsMenuSection, { ...sectionProps, close }) })
135
141
  }
136
142
  );
137
143
  }
138
144
 
139
145
  exports.TableSettings = TableSettings;
146
+ exports.TableSettingsMenuSection = TableSettingsMenuSection;
@@ -2,7 +2,7 @@ import { ColumnDef } from '@tanstack/react-table';
2
2
  import type { JSX, ReactNode } from 'react';
3
3
  import { ViewMode } from '../../../../hooks/useTableSettings';
4
4
  import { ButtonSize } from '../../../button/Button';
5
- interface TableSettingsProps<T extends Record<string, any>> {
5
+ export interface TableSettingsMenuSectionProps<T extends Record<string, any>> {
6
6
  handleChangeViewMode: (mode: ViewMode) => void;
7
7
  viewMode: ViewMode;
8
8
  columns?: ColumnDef<T>[];
@@ -11,8 +11,17 @@ interface TableSettingsProps<T extends Record<string, any>> {
11
11
  columnsLabel?: string;
12
12
  allPresetLabel?: string;
13
13
  standardPresetLabel?: string;
14
- buttonSize?: ButtonSize;
15
14
  additionalSettings?: (close?: () => void) => ReactNode;
15
+ /** Called after an action closes the surrounding menu/popover, if any. */
16
+ close?: () => void;
17
+ }
18
+ export interface TableSettingsProps<T extends Record<string, any>> extends Omit<TableSettingsMenuSectionProps<T>, 'close'> {
19
+ buttonSize?: ButtonSize;
16
20
  }
17
- export declare function TableSettings<T extends Record<string, any>>({ viewMode, handleChangeViewMode, columns, visibleColumnIds, onVisibleColumnIdsChange, columnsLabel, allPresetLabel, standardPresetLabel, buttonSize, additionalSettings, }: TableSettingsProps<T>): JSX.Element;
18
- export {};
21
+ /**
22
+ * The table settings menu items (view mode toggle + column visibility), with
23
+ * no `Menu`/`Popover`/trigger wrapper. Use this to fold table settings into
24
+ * another menu; use `TableSettings` for the standalone button + popover.
25
+ */
26
+ export declare function TableSettingsMenuSection<T extends Record<string, any>>({ viewMode, handleChangeViewMode, columns, visibleColumnIds, onVisibleColumnIdsChange, columnsLabel, allPresetLabel, standardPresetLabel, additionalSettings, close, }: TableSettingsMenuSectionProps<T>): JSX.Element;
27
+ export declare function TableSettings<T extends Record<string, any>>({ buttonSize, ...sectionProps }: TableSettingsProps<T>): JSX.Element;
@@ -1,12 +1,12 @@
1
1
  'use client';
2
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
3
  import { ListChevronsUpDown, Settings } from 'lucide-react';
4
4
  import { useMemo } from 'react';
5
5
  import { Button } from '../../../button/Button';
6
6
  import { Menu } from '../../../menu/Menu';
7
7
  import { Popover } from '../../../popover/Popover';
8
8
 
9
- function TableSettings({
9
+ function TableSettingsMenuSection({
10
10
  viewMode,
11
11
  handleChangeViewMode,
12
12
  columns = [],
@@ -15,12 +15,12 @@ function TableSettings({
15
15
  columnsLabel = "Kolonner",
16
16
  allPresetLabel = "Alle",
17
17
  standardPresetLabel = "Standard",
18
- buttonSize = "sm",
19
- additionalSettings
18
+ additionalSettings,
19
+ close
20
20
  }) {
21
- const handleViewModeChange = (mode, close) => {
21
+ const handleViewModeChange = (mode, close2) => {
22
22
  handleChangeViewMode(mode === "wrapped" ? "compact" : "wrapped");
23
- close == null ? void 0 : close();
23
+ close2 == null ? void 0 : close2();
24
24
  };
25
25
  const hideableColumns = useMemo(() => columns.filter((c) => c.enableHiding !== false), [columns]);
26
26
  const allPresetIds = useMemo(() => hideableColumns.map((c) => c.id), [hideableColumns]);
@@ -61,6 +61,73 @@ function TableSettings({
61
61
  return hideableColumns.every((c) => c.id && visibleSet.has(c.id) === std.has(c.id));
62
62
  }, [hideableColumns, visibleSet, standardPresetIds]);
63
63
  const presetRadioName = "table-columns-preset";
64
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
65
+ additionalSettings == null ? void 0 : additionalSettings(close),
66
+ /* @__PURE__ */ jsx(Menu.Item, { active: viewMode === "wrapped", children: /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => handleViewModeChange(viewMode, close), children: [
67
+ /* @__PURE__ */ jsx(ListChevronsUpDown, {}),
68
+ "Ombryd tekst"
69
+ ] }) }),
70
+ hideableColumns.length > 0 && onVisibleColumnIdsChange ? /* @__PURE__ */ jsxs(Fragment, { children: [
71
+ /* @__PURE__ */ jsx(Menu.Separator, {}),
72
+ /* @__PURE__ */ jsx("div", { style: { padding: "6px 10px", fontSize: 12, opacity: 0.7 }, children: columnsLabel }),
73
+ /* @__PURE__ */ jsx(
74
+ Menu.RadioItem,
75
+ {
76
+ name: presetRadioName,
77
+ value: "all",
78
+ checked: isAllActive,
79
+ label: allPresetLabel,
80
+ onValueChange: () => {
81
+ setVisibleIds(
82
+ allPresetIds.filter((id) => typeof id === "string" && Boolean(id))
83
+ );
84
+ close == null ? void 0 : close();
85
+ }
86
+ }
87
+ ),
88
+ /* @__PURE__ */ jsx(
89
+ Menu.RadioItem,
90
+ {
91
+ name: presetRadioName,
92
+ value: "standard",
93
+ checked: isStandardActive,
94
+ label: standardPresetLabel,
95
+ onValueChange: () => {
96
+ setVisibleIds(
97
+ standardPresetIds.filter(
98
+ (id) => typeof id === "string" && Boolean(id)
99
+ )
100
+ );
101
+ close == null ? void 0 : close();
102
+ }
103
+ }
104
+ ),
105
+ /* @__PURE__ */ jsx(Menu.Separator, {}),
106
+ hideableColumns.map((col) => {
107
+ const isVisible = col.id ? visibleSet.has(col.id) : false;
108
+ const disableUncheckingLast = isVisible && visibleCount <= 1;
109
+ const label = col.header;
110
+ return /* @__PURE__ */ jsx(
111
+ Menu.CheckItem,
112
+ {
113
+ checked: isVisible,
114
+ disabled: disableUncheckingLast,
115
+ label,
116
+ onCheckedChange: (nextChecked) => {
117
+ if (disableUncheckingLast) return;
118
+ toggleColumn(col.id, nextChecked);
119
+ }
120
+ },
121
+ col.id
122
+ );
123
+ })
124
+ ] }) : null
125
+ ] });
126
+ }
127
+ function TableSettings({
128
+ buttonSize = "sm",
129
+ ...sectionProps
130
+ }) {
64
131
  return /* @__PURE__ */ jsx(
65
132
  Popover,
66
133
  {
@@ -68,70 +135,9 @@ function TableSettings({
68
135
  /* @__PURE__ */ jsx(Settings, {}),
69
136
  icon
70
137
  ] }),
71
- children: (close) => /* @__PURE__ */ jsxs(Menu, { children: [
72
- additionalSettings == null ? void 0 : additionalSettings(close),
73
- /* @__PURE__ */ jsx(Menu.Item, { active: viewMode === "wrapped", children: /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => handleViewModeChange(viewMode, close), children: [
74
- /* @__PURE__ */ jsx(ListChevronsUpDown, {}),
75
- "Ombryd tekst"
76
- ] }) }),
77
- hideableColumns.length > 0 && onVisibleColumnIdsChange ? /* @__PURE__ */ jsxs(Fragment, { children: [
78
- /* @__PURE__ */ jsx(Menu.Separator, {}),
79
- /* @__PURE__ */ jsx("div", { style: { padding: "6px 10px", fontSize: 12, opacity: 0.7 }, children: columnsLabel }),
80
- /* @__PURE__ */ jsx(
81
- Menu.RadioItem,
82
- {
83
- name: presetRadioName,
84
- value: "all",
85
- checked: isAllActive,
86
- label: allPresetLabel,
87
- onValueChange: () => {
88
- setVisibleIds(
89
- allPresetIds.filter((id) => typeof id === "string" && Boolean(id))
90
- );
91
- close == null ? void 0 : close();
92
- }
93
- }
94
- ),
95
- /* @__PURE__ */ jsx(
96
- Menu.RadioItem,
97
- {
98
- name: presetRadioName,
99
- value: "standard",
100
- checked: isStandardActive,
101
- label: standardPresetLabel,
102
- onValueChange: () => {
103
- setVisibleIds(
104
- standardPresetIds.filter(
105
- (id) => typeof id === "string" && Boolean(id)
106
- )
107
- );
108
- close == null ? void 0 : close();
109
- }
110
- }
111
- ),
112
- /* @__PURE__ */ jsx(Menu.Separator, {}),
113
- hideableColumns.map((col) => {
114
- const isVisible = col.id ? visibleSet.has(col.id) : false;
115
- const disableUncheckingLast = isVisible && visibleCount <= 1;
116
- const label = col.header;
117
- return /* @__PURE__ */ jsx(
118
- Menu.CheckItem,
119
- {
120
- checked: isVisible,
121
- disabled: disableUncheckingLast,
122
- label,
123
- onCheckedChange: (nextChecked) => {
124
- if (disableUncheckingLast) return;
125
- toggleColumn(col.id, nextChecked);
126
- }
127
- },
128
- col.id
129
- );
130
- })
131
- ] }) : null
132
- ] })
138
+ children: (close) => /* @__PURE__ */ jsx(Menu, { children: /* @__PURE__ */ jsx(TableSettingsMenuSection, { ...sectionProps, close }) })
133
139
  }
134
140
  );
135
141
  }
136
142
 
137
- export { TableSettings };
143
+ export { TableSettings, TableSettingsMenuSection };
@@ -32,14 +32,23 @@
32
32
 
33
33
  .tabButtons {
34
34
  display: flex;
35
- flex-wrap: wrap;
35
+ flex-wrap: nowrap;
36
+ overflow-x: auto;
37
+ /* Explicit, not just tidy: leaving this "visible" would compute to "auto"
38
+ too (overflow-x auto + overflow-y visible isn't a valid combination per
39
+ spec), silently turning on a vertical scrollbar/clip that's never needed
40
+ here. */
41
+ overflow-y: hidden;
36
42
  min-width: 0;
37
43
  }
38
44
 
39
- /* Extra content next to the tab buttons, pushed into the free space on the right */
45
+ /* Extra content next to the tab buttons, pushed into the free space on the
46
+ right. It takes the space it needs — .tabButtons scrolls instead of
47
+ squeezing it. */
40
48
  .tabListAddition {
41
49
  display: flex;
42
50
  align-items: center;
51
+ flex-shrink: 0;
43
52
  gap: var(--spacing-sm);
44
53
  margin-inline-start: auto;
45
54
  padding-inline-start: var(--spacing-md);
@@ -49,6 +58,7 @@
49
58
  .tab {
50
59
  display: flex;
51
60
  align-items: stretch;
61
+ flex-shrink: 0;
52
62
  border-radius: 0;
53
63
  border-block-end: 2px solid var(--color-border-default);
54
64
  }
@@ -134,6 +144,7 @@
134
144
  align-items: center;
135
145
  justify-content: center;
136
146
  align-self: stretch;
147
+ flex-shrink: 0;
137
148
 
138
149
  color: var(--color-fg-muted);
139
150
  background: none;
@@ -209,7 +220,17 @@
209
220
  }
210
221
 
211
222
  .filled > .tabList {
212
- border-block-end: 1px solid var(--color-border-subtle);
223
+ position: relative;
224
+ }
225
+
226
+ .filled > .tabList::after {
227
+ content: '';
228
+ position: absolute;
229
+ inset-inline: 0;
230
+ inset-block-end: 0;
231
+ block-size: 1px;
232
+ background: var(--color-border-subtle);
233
+ pointer-events: none;
213
234
  }
214
235
 
215
236
  /* One continuous backdrop behind the whole button row, so the curved gap
@@ -238,7 +259,7 @@
238
259
 
239
260
  .filled > .tabList > .tabButtons > .tab {
240
261
  border: 1px solid transparent;
241
- border-block-end: 0;
262
+ border-block-end-width: 1px;
242
263
  color: var(--color-fg-muted);
243
264
  position: relative;
244
265
  transition:
@@ -265,6 +286,15 @@
265
286
  color: var(--color-fg-default);
266
287
  }
267
288
 
289
+ .filled > .tabList > .tabButtons > .tab.active::after {
290
+ content: '';
291
+ position: absolute;
292
+ inset-inline: -1px;
293
+ inset-block-end: -1px;
294
+ block-size: 1px;
295
+ background: var(--color-bg-surface);
296
+ }
297
+
268
298
  .filled > .tabContent {
269
299
  background: var(--color-bg-surface);
270
300
  border: 1px solid var(--color-border-subtle);
package/dist/index.cjs CHANGED
@@ -18,6 +18,7 @@ var SkeletonLoader = require('./components/skeleton-loader/SkeletonLoader');
18
18
  var Page = require('./components/page/Page');
19
19
  var Breadcrumbs = require('./components/breadcrumbs/Breadcrumbs');
20
20
  var Circle = require('./components/circle/Circle');
21
+ var Badge = require('./components/badge/Badge');
21
22
  var chartColors = require('./constants/chart-colors');
22
23
  var chartColors_types = require('./constants/chart-colors.types');
23
24
  var severity_types = require('./constants/severity.types');
@@ -159,6 +160,12 @@ Object.keys(Circle).forEach(function (k) {
159
160
  get: function () { return Circle[k]; }
160
161
  });
161
162
  });
163
+ Object.keys(Badge).forEach(function (k) {
164
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
165
+ enumerable: true,
166
+ get: function () { return Badge[k]; }
167
+ });
168
+ });
162
169
  Object.keys(chartColors).forEach(function (k) {
163
170
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
164
171
  enumerable: true,
package/dist/index.css CHANGED
@@ -6,6 +6,7 @@
6
6
  @import './components/app-header/AppHeader.module.css';
7
7
  @import './components/attribute-chip/AttributeChip.module.css';
8
8
  @import './components/avatar/Avatar.module.css';
9
+ @import './components/badge/Badge.module.css';
9
10
  @import './components/breadcrumbs/Breadcrumbs.module.css';
10
11
  @import './components/button-select/ButtonSelect.module.css';
11
12
  @import './components/button/Button.module.css';
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export * from './components/skeleton-loader/SkeletonLoader';
16
16
  export * from './components/page/Page';
17
17
  export * from './components/breadcrumbs/Breadcrumbs';
18
18
  export * from './components/circle/Circle';
19
+ export * from './components/badge/Badge';
19
20
  export * from './constants/chart-colors';
20
21
  export * from './constants/chart-colors.types';
21
22
  export * from './constants/severity.types';
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ export * from './components/skeleton-loader/SkeletonLoader';
16
16
  export * from './components/page/Page';
17
17
  export * from './components/breadcrumbs/Breadcrumbs';
18
18
  export * from './components/circle/Circle';
19
+ export * from './components/badge/Badge';
19
20
  export * from './constants/chart-colors';
20
21
  export * from './constants/chart-colors.types';
21
22
  export * from './constants/severity.types';
@@ -303,8 +303,15 @@ tr.dbc-table--hover:hover td:last-child {
303
303
  Scrollbars
304
304
  ========================================================================== */
305
305
 
306
+ /* Firefox equivalent of the thin, muted webkit scrollbar below. */
307
+ * {
308
+ scrollbar-width: thin;
309
+ scrollbar-color: var(--color-border-strong) transparent;
310
+ }
311
+
306
312
  ::-webkit-scrollbar {
307
313
  width: 10px;
314
+ height: 10px;
308
315
  }
309
316
 
310
317
  ::-webkit-scrollbar-track {
package/dist/styles.css CHANGED
@@ -303,8 +303,15 @@ tr.dbc-table--hover:hover td:last-child {
303
303
  Scrollbars
304
304
  ========================================================================== */
305
305
 
306
+ /* Firefox equivalent of the thin, muted webkit scrollbar below. */
307
+ * {
308
+ scrollbar-width: thin;
309
+ scrollbar-color: var(--color-border-strong) transparent;
310
+ }
311
+
306
312
  ::-webkit-scrollbar {
307
313
  width: 10px;
314
+ height: 10px;
308
315
  }
309
316
 
310
317
  ::-webkit-scrollbar-track {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbcdk/react-components",
3
- "version": "0.0.187",
3
+ "version": "0.0.189",
4
4
  "description": "Reusable React components for DBC projects",
5
5
  "license": "ISC",
6
6
  "author": "",