@dbcdk/react-components 0.0.19 → 0.0.21

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 (46) hide show
  1. package/dist/components/button/Button.module.css +21 -10
  2. package/dist/components/chip/Chip.d.ts +3 -2
  3. package/dist/components/chip/Chip.js +2 -1
  4. package/dist/components/chip/Chip.module.css +107 -67
  5. package/dist/components/code-block/CodeBlock.js +28 -19
  6. package/dist/components/code-block/CodeBlock.module.css +69 -67
  7. package/dist/components/filter-field/FilterField.d.ts +2 -1
  8. package/dist/components/filter-field/FilterField.js +4 -9
  9. package/dist/components/filter-field/FilterField.module.css +203 -152
  10. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.d.ts +2 -3
  11. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.js +3 -5
  12. package/dist/components/filtering/chip-multi-toggle/ChipMultiToggle.module.css +13 -13
  13. package/dist/components/forms/input/Input.d.ts +1 -1
  14. package/dist/components/forms/input/Input.js +3 -9
  15. package/dist/components/forms/input/Input.module.css +106 -17
  16. package/dist/components/hyperlink/Hyperlink.module.css +14 -3
  17. package/dist/components/interval-select/IntervalSelect.js +2 -2
  18. package/dist/components/overlay/modal/Modal.d.ts +2 -1
  19. package/dist/components/overlay/modal/Modal.js +6 -6
  20. package/dist/components/overlay/modal/Modal.module.css +52 -19
  21. package/dist/components/popover/Popover.module.css +4 -1
  22. package/dist/components/segmented-progress-bar/SegmentedProgressBar.d.ts +4 -2
  23. package/dist/components/segmented-progress-bar/SegmentedProgressBar.js +17 -19
  24. package/dist/components/segmented-progress-bar/SegmentedProgressBar.module.css +128 -20
  25. package/dist/components/sidebar/Sidebar.d.ts +2 -1
  26. package/dist/components/sidebar/Sidebar.js +2 -2
  27. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +2 -3
  28. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +2 -4
  29. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +2 -1
  30. package/dist/components/table/Table.d.ts +6 -6
  31. package/dist/components/table/Table.js +153 -78
  32. package/dist/components/table/Table.module.css +335 -171
  33. package/dist/components/table/TanstackTable.d.ts +1 -1
  34. package/dist/components/table/TanstackTable.js +14 -12
  35. package/dist/components/table/table.utils.d.ts +1 -1
  36. package/dist/components/table/table.utils.js +2 -3
  37. package/dist/components/table/tanstackTable.utils.d.ts +9 -10
  38. package/dist/components/table/tanstackTable.utils.js +50 -30
  39. package/dist/hooks/useViewportFill.d.ts +6 -5
  40. package/dist/hooks/useViewportFill.js +43 -41
  41. package/dist/src/styles/styles.css +9 -3
  42. package/dist/styles/styles.css +9 -3
  43. package/dist/styles/themes/dbc/base.css +0 -3
  44. package/dist/styles/themes/dbc/dark.css +44 -12
  45. package/dist/styles/themes/dbc/light.css +33 -7
  46. package/package.json +1 -1
@@ -2,7 +2,7 @@ import type { CSSProperties, ReactNode } from 'react';
2
2
  import type { ColumnItem } from './Table';
3
3
  export type SortDirection = 'asc' | 'desc' | null;
4
4
  export declare function getVisibleColumns<T>(columns: Array<ColumnItem<T>>): Array<ColumnItem<T>>;
5
- export declare function getColumnStyle(columnId: string, columnStyles: Partial<Record<string, CSSProperties>> | undefined, alignment?: 'left' | 'right' | 'center', verticalAlignment?: 'top' | 'middle' | 'bottom'): CSSProperties;
5
+ export declare function getColumnStyle(columnId: string, columnStyles: Partial<Record<string, CSSProperties>> | undefined, alignment?: 'left' | 'right' | 'center', verticalAlignment?: 'top' | 'middle' | 'bottom', divider?: boolean): CSSProperties;
6
6
  export declare function getHeaderLabel(header: string | (() => ReactNode)): ReactNode;
7
7
  export declare function isActiveSort(sortById: string | undefined, columnId: string): boolean;
8
8
  export declare function getAriaSort(sortable: boolean | undefined, active: boolean, direction: SortDirection): 'ascending' | 'descending' | 'none';
@@ -1,15 +1,14 @@
1
1
  export function getVisibleColumns(columns) {
2
2
  return columns.filter(c => !c.hidden);
3
3
  }
4
- export function getColumnStyle(columnId, columnStyles, alignment, verticalAlignment) {
5
- var _a;
4
+ export function getColumnStyle(columnId, columnStyles, alignment, verticalAlignment, divider) {
6
5
  const baseStyle = columnStyles === null || columnStyles === void 0 ? void 0 : columnStyles[columnId];
7
6
  return {
8
7
  ...(baseStyle !== null && baseStyle !== void 0 ? baseStyle : {}),
9
8
  ...(alignment === 'right' ? { fontVariantNumeric: 'tabular-nums' } : null),
10
9
  verticalAlign: verticalAlignment !== null && verticalAlignment !== void 0 ? verticalAlignment : 'top',
11
10
  textAlign: alignment !== null && alignment !== void 0 ? alignment : 'left',
12
- minWidth: (_a = baseStyle === null || baseStyle === void 0 ? void 0 : baseStyle.minWidth) !== null && _a !== void 0 ? _a : 0,
11
+ ...(divider ? { borderLeft: '1px solid var(--color-border-subtle)' } : null),
13
12
  };
14
13
  }
15
14
  export function getHeaderLabel(header) {
@@ -1,5 +1,4 @@
1
- import type { ColumnDef, SortingState, VisibilityState, Column } from '@tanstack/react-table';
2
- import type { CSSProperties } from 'react';
1
+ import type { ColumnDef, ColumnSizingState, SortingState, VisibilityState } from '@tanstack/react-table';
3
2
  import type { ColumnItem } from './Table';
4
3
  type AnyRecord = Record<string, any>;
5
4
  export declare function getColumnId<T>(def: ColumnDef<T, any>, index: number): string;
@@ -10,13 +9,13 @@ export declare function getSortPropsFromSorting(sorting: SortingState): {
10
9
  sortById?: string;
11
10
  sortDirection: 'asc' | 'desc' | null;
12
11
  };
13
- /**
14
- * Builds `columnStyles` where TanStack is source of truth.
15
- * Keep this util pure by passing in the leaf columns and the set of allowed IDs.
16
- */
17
- export declare function buildColumnStyles(leafColumns: Array<Pick<Column<any, any>, 'id' | 'getSize' | 'columnDef'>>, allowedIds: Set<string>, defaults?: {
18
- minWidth: number;
19
- maxWidth: number;
20
- }): Record<string, CSSProperties>;
21
12
  export declare function columnItemsToIdSet<T>(items: Array<ColumnItem<T>>): Set<string>;
13
+ export declare function buildDistributedGridTemplateColumns(args: {
14
+ table: any;
15
+ allowedIds: Set<string>;
16
+ hasSelection: boolean;
17
+ selectionPx: number;
18
+ defaultMinPx: number;
19
+ columnSizing: ColumnSizingState;
20
+ }): string;
22
21
  export {};
@@ -1,8 +1,8 @@
1
1
  export function getColumnId(def, index) {
2
2
  const d = def;
3
- if (d.id != null && String(d.id).length)
3
+ if (d.id != null && String(d.id).length > 0)
4
4
  return String(d.id);
5
- if (d.accessorKey != null && String(d.accessorKey).length)
5
+ if (d.accessorKey != null && String(d.accessorKey).length > 0)
6
6
  return String(d.accessorKey);
7
7
  return `col_${index}`;
8
8
  }
@@ -19,11 +19,12 @@ export function buildColumnVisibilityFromVisibleIds(defs, visibleColumnIds) {
19
19
  }
20
20
  export function mapDefsToColumnItems(defs, columnVisibility) {
21
21
  return defs.map((def, index) => {
22
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
22
+ var _a, _b, _c, _d, _e, _f;
23
23
  const id = getColumnId(def, index);
24
24
  const accessorKey = def.accessorKey;
25
25
  const accessorFn = def.accessorFn;
26
26
  const cell = def.cell;
27
+ const meta = (_b = ((_a = def.meta) !== null && _a !== void 0 ? _a : {})) !== null && _b !== void 0 ? _b : {};
27
28
  let render;
28
29
  if (typeof cell === 'function') {
29
30
  render = (row) => cell({
@@ -44,19 +45,20 @@ export function mapDefsToColumnItems(defs, columnVisibility) {
44
45
  else {
45
46
  render = () => null;
46
47
  }
47
- const isVisible = (_a = columnVisibility[id]) !== null && _a !== void 0 ? _a : true;
48
+ const isVisible = (_c = columnVisibility[id]) !== null && _c !== void 0 ? _c : true;
48
49
  return {
49
50
  id,
50
51
  header: def.header,
51
52
  accessor: accessorKey,
52
- sortable: (_b = def.enableSorting) !== null && _b !== void 0 ? _b : !!accessorKey,
53
+ sortable: (_d = def.enableSorting) !== null && _d !== void 0 ? _d : !!accessorKey,
53
54
  render,
54
55
  hidden: !isVisible,
55
- align: (_d = (_c = def.meta) === null || _c === void 0 ? void 0 : _c.align) !== null && _d !== void 0 ? _d : undefined,
56
- verticalAlign: (_f = (_e = def.meta) === null || _e === void 0 ? void 0 : _e.verticalAlign) !== null && _f !== void 0 ? _f : undefined,
57
- emptyPlaceholder: (_h = (_g = def.meta) === null || _g === void 0 ? void 0 : _g.emptyPlaceholder) !== null && _h !== void 0 ? _h : '-',
58
- allowWrap: (_k = (_j = def.meta) === null || _j === void 0 ? void 0 : _j.allowWrap) !== null && _k !== void 0 ? _k : false,
59
- severity: (_m = (_l = def.meta) === null || _l === void 0 ? void 0 : _l.severity) !== null && _m !== void 0 ? _m : undefined,
56
+ align: meta.align,
57
+ verticalAlign: meta.verticalAlign,
58
+ emptyPlaceholder: (_e = meta.emptyPlaceholder) !== null && _e !== void 0 ? _e : '-',
59
+ allowWrap: (_f = meta.allowWrap) !== null && _f !== void 0 ? _f : false,
60
+ severity: meta.severity,
61
+ divider: meta.divider,
60
62
  };
61
63
  });
62
64
  }
@@ -76,29 +78,47 @@ export function getSortPropsFromSorting(sorting) {
76
78
  sortDirection: s ? (s.desc ? 'desc' : 'asc') : null,
77
79
  };
78
80
  }
79
- /**
80
- * Builds `columnStyles` where TanStack is source of truth.
81
- * Keep this util pure by passing in the leaf columns and the set of allowed IDs.
82
- */
83
- export function buildColumnStyles(leafColumns, allowedIds, defaults = { minWidth: 80, maxWidth: 800 }) {
84
- var _a, _b;
85
- const styles = {};
86
- for (const c of leafColumns) {
87
- const id = c.id;
88
- if (!allowedIds.has(id))
89
- continue;
90
- const anyDef = c.columnDef;
91
- styles[id] = {
92
- width: c.getSize(),
93
- minWidth: (_a = anyDef.minSize) !== null && _a !== void 0 ? _a : defaults.minWidth,
94
- maxWidth: (_b = anyDef.maxSize) !== null && _b !== void 0 ? _b : defaults.maxWidth,
95
- };
96
- }
97
- return styles;
98
- }
99
81
  export function columnItemsToIdSet(items) {
100
82
  const s = new Set();
101
83
  for (const c of items)
102
84
  s.add(c.id);
103
85
  return s;
104
86
  }
87
+ function clamp(value, min, max) {
88
+ const lowerBounded = Math.max(min, value);
89
+ if (max == null || !Number.isFinite(max))
90
+ return lowerBounded;
91
+ return Math.min(lowerBounded, max);
92
+ }
93
+ export function buildDistributedGridTemplateColumns(args) {
94
+ var _a, _b, _c, _d;
95
+ const { table, allowedIds, hasSelection, selectionPx, defaultMinPx, columnSizing } = args;
96
+ const parts = [];
97
+ const leaf = table.getVisibleLeafColumns().filter((c) => allowedIds.has(c.id));
98
+ if (hasSelection)
99
+ parts.push(`${selectionPx}px`);
100
+ for (const c of leaf) {
101
+ const def = c.columnDef;
102
+ const meta = ((_b = ((_a = def.meta) !== null && _a !== void 0 ? _a : {})) !== null && _b !== void 0 ? _b : {});
103
+ const min = Math.max(1, Number((_c = def.minSize) !== null && _c !== void 0 ? _c : defaultMinPx));
104
+ const hasMax = def.maxSize != null;
105
+ const max = hasMax ? Math.max(min, Number(def.maxSize)) : undefined;
106
+ const weight = Math.max(1, Number((_d = meta.weight) !== null && _d !== void 0 ? _d : 1));
107
+ const resizedPxRaw = columnSizing[c.id];
108
+ const resizedPx = resizedPxRaw != null ? Math.round(clamp(Number(resizedPxRaw), min, max)) : undefined;
109
+ if (resizedPx != null) {
110
+ parts.push(`${resizedPx}px`);
111
+ continue;
112
+ }
113
+ if (hasMax && max === min) {
114
+ parts.push(`${Math.round(min)}px`);
115
+ continue;
116
+ }
117
+ if (hasMax && max != null) {
118
+ parts.push(`minmax(${Math.round(min)}px, ${Math.round(max)}px)`);
119
+ continue;
120
+ }
121
+ parts.push(`minmax(${Math.round(min)}px, ${weight}fr)`);
122
+ }
123
+ return parts.join(' ');
124
+ }
@@ -3,12 +3,13 @@ type Options = {
3
3
  bottomOffset?: number;
4
4
  min?: number;
5
5
  includeMarginTop?: boolean;
6
+ /**
7
+ * Optional element to observe in addition to the target itself.
8
+ * Useful when a nearby wrapper changes height and pushes the table.
9
+ */
10
+ watchRef?: RefObject<HTMLElement | null>;
6
11
  };
7
- /**
8
- * Computes the remaining viewport space below the element and returns a style
9
- * with `maxHeight` + `overflow: auto`.
10
- */
11
- export declare function useViewportFill<T extends HTMLElement>(ref: RefObject<T>, { bottomOffset, min, includeMarginTop }?: Options): {
12
+ export declare function useViewportFill<T extends HTMLElement>(ref: RefObject<T>, { bottomOffset, min, includeMarginTop, watchRef }?: Options): {
12
13
  maxHeight: number;
13
14
  style: CSSProperties;
14
15
  recompute: () => void;
@@ -1,12 +1,8 @@
1
1
  'use client';
2
2
  import { useCallback, useEffect, useLayoutEffect, useRef, useState, } from 'react';
3
3
  const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
4
- /**
5
- * Computes the remaining viewport space below the element and returns a style
6
- * with `maxHeight` + `overflow: auto`.
7
- */
8
- export function useViewportFill(ref, { bottomOffset = 0, min = 120, includeMarginTop = false } = {}) {
9
- const [maxHeight, setMaxHeight] = useState(0);
4
+ export function useViewportFill(ref, { bottomOffset = 0, min = 120, includeMarginTop = false, watchRef } = {}) {
5
+ const [maxHeight, setMaxHeight] = useState(min);
10
6
  const raf = useRef(null);
11
7
  const measure = useCallback(() => {
12
8
  if (typeof window === 'undefined' || !ref.current)
@@ -15,56 +11,62 @@ export function useViewportFill(ref, { bottomOffset = 0, min = 120, includeMargi
15
11
  const rect = el.getBoundingClientRect();
16
12
  let top = rect.top;
17
13
  if (includeMarginTop) {
18
- const mt = parseFloat(getComputedStyle(el).marginTop || '0') || 0;
14
+ const mt = parseFloat(window.getComputedStyle(el).marginTop || '0') || 0;
19
15
  top -= mt;
20
16
  }
21
- const raw = window.innerHeight - bottomOffset - top;
22
- const next = Math.max(min, Math.floor(raw));
23
- setMaxHeight(next);
17
+ const next = Math.max(min, Math.floor(window.innerHeight - bottomOffset - top));
18
+ setMaxHeight(prev => (prev !== next ? next : prev));
24
19
  }, [ref, bottomOffset, min, includeMarginTop]);
25
- // Initial + dependency-triggered measurement
20
+ const scheduleMeasure = useCallback(() => {
21
+ if (typeof window === 'undefined')
22
+ return;
23
+ if (raf.current != null)
24
+ cancelAnimationFrame(raf.current);
25
+ raf.current = window.requestAnimationFrame(measure);
26
+ }, [measure]);
26
27
  useIsomorphicLayoutEffect(() => {
27
28
  measure();
28
29
  }, [measure]);
29
30
  useEffect(() => {
30
- if (typeof window === 'undefined')
31
+ var _a;
32
+ if (typeof window === 'undefined' || !ref.current)
31
33
  return;
32
- const onFrame = () => {
33
- if (raf.current)
34
- cancelAnimationFrame(raf.current);
35
- raf.current = requestAnimationFrame(measure);
36
- };
37
- window.addEventListener('scroll', onFrame, { passive: true });
38
- window.addEventListener('resize', onFrame);
34
+ const target = ref.current;
35
+ const extra = (_a = watchRef === null || watchRef === void 0 ? void 0 : watchRef.current) !== null && _a !== void 0 ? _a : null;
36
+ const parent = target.parentElement;
37
+ const onResizeOrScroll = () => scheduleMeasure();
38
+ const onTransitionOrAnimationEnd = () => scheduleMeasure();
39
+ window.addEventListener('resize', onResizeOrScroll);
40
+ window.addEventListener('scroll', onResizeOrScroll, { passive: true });
41
+ // Cheap and often enough for collapsible filter panels.
42
+ document.addEventListener('transitionend', onTransitionOrAnimationEnd, true);
43
+ document.addEventListener('animationend', onTransitionOrAnimationEnd, true);
39
44
  let ro = null;
40
- if ('ResizeObserver' in window && ref.current) {
41
- ro = new ResizeObserver(onFrame);
42
- ro.observe(ref.current);
43
- }
44
- // MutationObserver to detect DOM changes that may affect position
45
- let mo = null;
46
- if ('MutationObserver' in window && ref.current) {
47
- mo = new MutationObserver(onFrame);
48
- // Observe parent node for subtree changes
49
- const parent = ref.current.parentNode;
50
- if (parent) {
51
- mo.observe(parent, { childList: true, subtree: true });
52
- }
45
+ if ('ResizeObserver' in window) {
46
+ ro = new ResizeObserver(() => scheduleMeasure());
47
+ ro.observe(target);
48
+ if (parent && parent !== target)
49
+ ro.observe(parent);
50
+ if (extra && extra !== target && extra !== parent)
51
+ ro.observe(extra);
53
52
  }
54
53
  return () => {
55
- window.removeEventListener('scroll', onFrame);
56
- window.removeEventListener('resize', onFrame);
57
- if (ro)
58
- ro.disconnect();
59
- if (mo)
60
- mo.disconnect();
61
- if (raf.current)
54
+ window.removeEventListener('resize', onResizeOrScroll);
55
+ window.removeEventListener('scroll', onResizeOrScroll);
56
+ document.removeEventListener('transitionend', onTransitionOrAnimationEnd, true);
57
+ document.removeEventListener('animationend', onTransitionOrAnimationEnd, true);
58
+ ro === null || ro === void 0 ? void 0 : ro.disconnect();
59
+ if (raf.current != null) {
62
60
  cancelAnimationFrame(raf.current);
61
+ }
63
62
  };
64
- }, [measure, ref]);
63
+ }, [ref, watchRef, scheduleMeasure]);
65
64
  return {
66
65
  maxHeight,
67
- style: { height: maxHeight, overflow: 'auto' },
66
+ style: {
67
+ maxHeight,
68
+ overflow: 'auto',
69
+ },
68
70
  recompute: measure,
69
71
  };
70
72
  }
@@ -54,24 +54,30 @@ body.dbc-app {
54
54
  max-width: 1600px;
55
55
  }
56
56
 
57
+ .dbc-overflow-auto {
58
+ overflow: auto;
59
+ }
60
+
57
61
  .dbc-font-mono {
58
62
  font-family: monospace;
59
63
  }
60
64
 
61
65
  .dbc-table {
62
66
  --card-label-width: 260px;
63
-
64
67
  border-collapse: collapse;
65
68
  font-size: var(--font-size-sm);
66
69
  line-height: var(--line-height-normal);
67
70
  }
68
71
 
72
+ .dbc-table--hover tr:hover {
73
+ background-color: var(--color-bg-contextual);
74
+ }
75
+
69
76
  .dbc-table tr + tr th,
70
77
  .dbc-table tr + tr td {
71
78
  padding-block: var(--spacing-xxs);
72
79
  }
73
80
 
74
- /* LABELS (th) → match .metaLabel */
75
81
  .dbc-table th {
76
82
  white-space: nowrap;
77
83
  text-align: left;
@@ -118,7 +124,7 @@ body.dbc-app {
118
124
  color: var(--color-fg-subtle);
119
125
  }
120
126
 
121
- .dbc-small-text {
127
+ .dbc-sm-text {
122
128
  font-size: var(--font-size-xs);
123
129
  }
124
130
 
@@ -54,24 +54,30 @@ body.dbc-app {
54
54
  max-width: 1600px;
55
55
  }
56
56
 
57
+ .dbc-overflow-auto {
58
+ overflow: auto;
59
+ }
60
+
57
61
  .dbc-font-mono {
58
62
  font-family: monospace;
59
63
  }
60
64
 
61
65
  .dbc-table {
62
66
  --card-label-width: 260px;
63
-
64
67
  border-collapse: collapse;
65
68
  font-size: var(--font-size-sm);
66
69
  line-height: var(--line-height-normal);
67
70
  }
68
71
 
72
+ .dbc-table--hover tr:hover {
73
+ background-color: var(--color-bg-contextual);
74
+ }
75
+
69
76
  .dbc-table tr + tr th,
70
77
  .dbc-table tr + tr td {
71
78
  padding-block: var(--spacing-xxs);
72
79
  }
73
80
 
74
- /* LABELS (th) → match .metaLabel */
75
81
  .dbc-table th {
76
82
  white-space: nowrap;
77
83
  text-align: left;
@@ -118,7 +124,7 @@ body.dbc-app {
118
124
  color: var(--color-fg-subtle);
119
125
  }
120
126
 
121
- .dbc-small-text {
127
+ .dbc-sm-text {
122
128
  font-size: var(--font-size-xs);
123
129
  }
124
130
 
@@ -118,9 +118,6 @@
118
118
  /* Skeletons & loaders (structure shared; colors overridden per theme if desired) */
119
119
  --spinner-size: 16px;
120
120
  --spinner-stroke: 2px;
121
-
122
- /* Logical spacing */
123
- --space-inline-sm: 8px;
124
121
  }
125
122
 
126
123
  /* Reduced motion (shared) */
@@ -1,6 +1,6 @@
1
1
  html[data-theme='dark'] {
2
2
  /* ==========================================================================
3
- * PRIMITIVES
3
+ * PRIMITIVES (THEME-DEPENDENT)
4
4
  * ======================================================================= */
5
5
 
6
6
  /* Brand blues */
@@ -18,6 +18,14 @@ html[data-theme='dark'] {
18
18
  --dbc-neutral-200: #374151;
19
19
  --dbc-neutral-100: #1f2937;
20
20
 
21
+ /* Added fixed surface neutrals */
22
+ --dbc-surface-muted: #1f2937;
23
+ --dbc-surface-strong: #111827;
24
+
25
+ /* Contextual warm neutrals */
26
+ --dbc-contextual-200: #1b1712;
27
+ --dbc-contextual-100: #15120e;
28
+
21
29
  /* Accents */
22
30
  --dbc-pink-500: #f472b6;
23
31
  --dbc-pink-600: #db2777;
@@ -47,7 +55,7 @@ html[data-theme='dark'] {
47
55
  --dbc-info-300: #38bdf8;
48
56
 
49
57
  /* ==========================================================================
50
- * SEMANTIC COLORS
58
+ * SEMANTIC COLORS (THEME-DEPENDENT)
51
59
  * ======================================================================= */
52
60
 
53
61
  --color-brand: var(--dbc-blue-500);
@@ -57,11 +65,15 @@ html[data-theme='dark'] {
57
65
  /* Backgrounds & surfaces */
58
66
  --color-bg-page: #111827;
59
67
  --color-bg-surface: #111827;
60
- --color-bg-surface-subtle: rgba(255, 255, 255, 0.05);
61
- --color-bg-surface-strong: #0f172a;
68
+ --color-bg-surface-subtle: var(--dbc-surface-muted);
69
+ --color-bg-surface-strong: var(--dbc-surface-strong);
62
70
 
63
- --color-bg-contextual: #0b1220;
64
- --color-bg-contextual-subtle: #0f172a;
71
+ --color-bg-toolbar: #1f2937;
72
+ --color-bg-toolbar-hover: #263244;
73
+
74
+ /* Contextual surfaces */
75
+ --color-bg-contextual: var(--dbc-contextual-200);
76
+ --color-bg-contextual-subtle: var(--dbc-contextual-100);
65
77
 
66
78
  /* Interaction backgrounds */
67
79
  --color-bg-hover-subtle: var(--opac-bg-light);
@@ -73,10 +85,10 @@ html[data-theme='dark'] {
73
85
 
74
86
  --color-neutral: var(--dbc-neutral-200);
75
87
 
76
- /* Borders (mirror light’s alpha approach, but with white) */
88
+ /* Borders */
77
89
  --color-border-subtle: rgba(255, 255, 255, 0.12);
78
- --color-border-default: rgba(255, 255, 255, 0.12);
79
- --color-border-strong: rgba(255, 255, 255, 0.24);
90
+ --color-border-default: rgba(255, 255, 255, 0.18);
91
+ --color-border-strong: rgba(255, 255, 255, 0.28);
80
92
  --color-border-selected: var(--color-brand);
81
93
 
82
94
  /* Text */
@@ -138,6 +150,21 @@ html[data-theme='dark'] {
138
150
  --button-bg-primary-hover: var(--color-brand-hover);
139
151
  --button-fg-primary: var(--color-fg-on-brand);
140
152
 
153
+ /* Tables */
154
+ --table-header-bg: #182230;
155
+ --table-row-bg: #111827;
156
+ --table-row-bg-alt: #141d2a;
157
+ --table-row-bg-hover: #172131;
158
+ --table-row-bg-selected: var(--dbc-blue-100);
159
+ --table-row-bg-selected-hover: var(--dbc-blue-150);
160
+
161
+ --table-border-subtle: rgba(255, 255, 255, 0.08);
162
+ --table-border-header: rgba(255, 255, 255, 0.12);
163
+ --table-divider: rgba(255, 255, 255, 0.08);
164
+
165
+ --table-header-fg: var(--color-fg-muted);
166
+ --table-cell-fg: var(--color-fg-default);
167
+
141
168
  /* ==========================================================================
142
169
  * THEME-SPECIFIC NON-COLOR TOKENS (VISUAL EFFECTS)
143
170
  * ======================================================================= */
@@ -151,14 +178,14 @@ html[data-theme='dark'] {
151
178
  --opac-bg-default-invert: rgba(0, 0, 0, 0.1);
152
179
  --opac-bg-dark-invert: rgba(0, 0, 0, 0.15);
153
180
 
154
- /* Shadows (stronger for dark surfaces) */
181
+ /* Shadows */
155
182
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.2);
156
183
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.35);
157
184
  --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.32);
158
185
  --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);
159
186
  --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.45);
160
187
 
161
- /* Data viz (invert sequential so it reads on dark bg) */
188
+ /* Data viz */
162
189
  --viz-cat-1: #2563eb;
163
190
  --viz-cat-2: #16a34a;
164
191
  --viz-cat-3: #f59e0b;
@@ -175,10 +202,15 @@ html[data-theme='dark'] {
175
202
  --skeleton-pulse: #4b5563;
176
203
  }
177
204
 
178
- /* High-contrast variant */
205
+ /* High-contrast variant (theme override) */
179
206
  :root[data-theme='dark'][data-contrast='high'] {
180
207
  --color-border-subtle: #9ca3af;
181
208
  --color-border-default: #e5e7eb;
182
209
  --color-border-strong: #f9fafb;
210
+
211
+ --table-border-subtle: #6b7280;
212
+ --table-border-header: #9ca3af;
213
+ --table-divider: #9ca3af;
214
+
183
215
  --focus-ring: 0 0 0 3px #e5e7eb;
184
216
  }
@@ -18,6 +18,14 @@ html[data-theme='light'] {
18
18
  --dbc-neutral-200: #e5e7eb;
19
19
  --dbc-neutral-100: #f3f4f6;
20
20
 
21
+ /* Added fixed surface neutrals */
22
+ --dbc-surface-muted: #f8fafc;
23
+ --dbc-surface-strong: #f3f4f6;
24
+
25
+ /* Contextual warm neutrals */
26
+ --dbc-contextual-200: #f4f2ee;
27
+ --dbc-contextual-100: #faf8f5;
28
+
21
29
  /* Accents */
22
30
  --dbc-pink-500: #ec4899;
23
31
  --dbc-pink-600: #be185d;
@@ -57,11 +65,15 @@ html[data-theme='light'] {
57
65
  /* Backgrounds & surfaces */
58
66
  --color-bg-page: #ffffff;
59
67
  --color-bg-surface: #ffffff;
60
- --color-bg-surface-subtle: rgba(0, 0, 0, 0.02);
61
- --color-bg-surface-strong: #f9fafb;
68
+ --color-bg-surface-subtle: var(--dbc-surface-muted);
69
+ --color-bg-surface-strong: var(--dbc-surface-strong);
70
+
71
+ --color-bg-toolbar: #f3f4f6;
72
+ --color-bg-toolbar-hover: #eef0f3;
62
73
 
63
- --color-bg-contextual: #f4f2ee;
64
- --color-bg-contextual-subtle: #faf8f5;
74
+ /* Contextual surfaces */
75
+ --color-bg-contextual: var(--dbc-contextual-200);
76
+ --color-bg-contextual-subtle: var(--dbc-contextual-100);
65
77
 
66
78
  /* Interaction backgrounds */
67
79
  --color-bg-hover-subtle: var(--opac-bg-light);
@@ -74,9 +86,9 @@ html[data-theme='light'] {
74
86
  --color-neutral: var(--dbc-neutral-200);
75
87
 
76
88
  /* Borders */
77
- --color-border-subtle: rgba(0, 0, 0, 0.12);
78
- --color-border-default: rgba(0, 0, 0, 0.12);
79
- --color-border-strong: rgba(0, 0, 0, 0.24);
89
+ --color-border-subtle: #e5e7eb;
90
+ --color-border-default: #d1d5db;
91
+ --color-border-strong: #9ca3af;
80
92
  --color-border-selected: var(--color-brand);
81
93
 
82
94
  /* Text */
@@ -138,6 +150,20 @@ html[data-theme='light'] {
138
150
  --button-bg-primary-hover: var(--color-brand-hover);
139
151
  --button-fg-primary: var(--color-fg-on-brand);
140
152
 
153
+ --table-header-bg: #f5f6f8;
154
+ --table-row-bg: #ffffff;
155
+ --table-row-bg-alt: #f7f9fc;
156
+ --table-row-bg-hover: #f6f8fb;
157
+ --table-row-bg-selected: var(--dbc-blue-100);
158
+ --table-row-bg-selected-hover: var(--dbc-blue-150);
159
+
160
+ --table-border-subtle: #eef1f4;
161
+ --table-border-header: #e2e6ea;
162
+ --table-divider: #e8ebef;
163
+
164
+ --table-header-fg: var(--color-fg-muted);
165
+ --table-cell-fg: var(--color-fg-default);
166
+
141
167
  /* ==========================================================================
142
168
  * THEME-SPECIFIC NON-COLOR TOKENS (VISUAL EFFECTS)
143
169
  * ======================================================================= */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbcdk/react-components",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "Reusable React components for DBC projects",
5
5
  "license": "ISC",
6
6
  "author": "",