@dxos/ui-theme 0.9.1-main.c7dcc2e112 → 0.10.0
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/lib/browser/index.mjs +37 -7
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +37 -7
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/plugin/node-cjs/main.css +11 -8
- package/dist/plugin/node-cjs/main.css.map +2 -2
- package/dist/plugin/node-cjs/meta.json +1 -1
- package/dist/plugin/node-esm/main.css +11 -8
- package/dist/plugin/node-esm/main.css.map +2 -2
- package/dist/plugin/node-esm/meta.json +1 -1
- package/dist/types/src/util/index.d.ts +2 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/mx.d.ts.map +1 -1
- package/dist/types/src/util/tv.d.ts +27 -0
- package/dist/types/src/util/tv.d.ts.map +1 -0
- package/dist/types/src/util/tv.test.d.ts +2 -0
- package/dist/types/src/util/tv.test.d.ts.map +1 -0
- package/dist/types/src/util/tw-merge-config.d.ts +17 -0
- package/dist/types/src/util/tw-merge-config.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -6
- package/src/Theme.stories.tsx +1 -1
- package/src/css/components/button.css +7 -1
- package/src/css/components/tag.css +2 -2
- package/src/css/theme/semantic.css +42 -36
- package/src/css/theme/spacing.css +6 -4
- package/src/util/index.ts +2 -0
- package/src/util/mx.ts +5 -35
- package/src/util/tv.test.ts +38 -0
- package/src/util/tv.ts +45 -0
- package/src/util/tw-merge-config.ts +46 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/ui-theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "A set of design system tokens to use with DXOS UI.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -48,21 +48,22 @@
|
|
|
48
48
|
"postcss-nesting": "^13.0.1",
|
|
49
49
|
"tailwind-merge": "^3.5.0",
|
|
50
50
|
"tailwind-scrollbar": "^4.0.0",
|
|
51
|
+
"tailwind-variants": "^3.2.2",
|
|
51
52
|
"tailwindcss": "^4.3.0",
|
|
52
53
|
"tailwindcss-radix": "^4.0.2",
|
|
53
|
-
"@dxos/log": "0.
|
|
54
|
-
"@dxos/node-std": "0.
|
|
55
|
-
"@dxos/util": "0.
|
|
54
|
+
"@dxos/log": "0.10.0",
|
|
55
|
+
"@dxos/node-std": "0.10.0",
|
|
56
|
+
"@dxos/util": "0.10.0"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"@types/lodash.merge": "^4.6.6",
|
|
59
60
|
"@types/postcss-import": "^14.0.3",
|
|
60
61
|
"esbuild": "0.28.1",
|
|
61
62
|
"vite": "^8.0.16",
|
|
62
|
-
"@dxos/ui-types": "0.
|
|
63
|
+
"@dxos/ui-types": "0.10.0"
|
|
63
64
|
},
|
|
64
65
|
"peerDependencies": {
|
|
65
|
-
"react": "~19.2.
|
|
66
|
+
"react": "~19.2.7"
|
|
66
67
|
},
|
|
67
68
|
"publishConfig": {
|
|
68
69
|
"access": "public"
|
package/src/Theme.stories.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { type Meta } from '@storybook/react-vite';
|
|
6
6
|
import React, { useLayoutEffect, useRef, useState } from 'react';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { hues, hueShades } from './defs';
|
|
9
9
|
import { mx } from './util';
|
|
10
10
|
|
|
11
11
|
// prettier-ignore
|
|
@@ -18,9 +18,15 @@
|
|
|
18
18
|
color: var(--dx-valence-text, inherit);
|
|
19
19
|
background: var(--dx-valence-bg, var(--color-input-bg));
|
|
20
20
|
}
|
|
21
|
+
/* Toggle / tab group: the selected item reads as standard text on a surface-relative fill (selected-surface
|
|
22
|
+
* tracks the enclosing --surface-bg, so it stays visible on any surface); unselected items recede to subdued. */
|
|
21
23
|
&[aria-pressed='true'],
|
|
22
24
|
&[aria-checked='true'] {
|
|
23
|
-
@apply text-
|
|
25
|
+
@apply text-base-fg bg-selected-surface;
|
|
26
|
+
}
|
|
27
|
+
&[aria-pressed='false'],
|
|
28
|
+
&[aria-checked='false'] {
|
|
29
|
+
@apply text-description;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
/* Disabled styles */
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
.dx-tag--anchor {
|
|
13
13
|
/* NOTE: Margin offsets padding so that border is flush with text. This should only apply to anchor tags inside of Codemirror. */
|
|
14
|
-
@apply inline cursor-pointer px-[4px] py-0.5;
|
|
14
|
+
@apply inline-block cursor-pointer px-[4px] py-0.5;
|
|
15
15
|
/** TODO(burdon): Configure secondary color. */
|
|
16
|
-
@apply bg-input-surface ring ring-neutral-border rounded-sm;
|
|
16
|
+
@apply bg-input-surface ring-inset ring ring-neutral-border rounded-sm;
|
|
17
17
|
&:hover {
|
|
18
18
|
@apply bg-hover-surface;
|
|
19
19
|
}
|
|
@@ -26,13 +26,14 @@
|
|
|
26
26
|
* These are private (--dx-*) knobs — use named surface tokens in components, not these directly.
|
|
27
27
|
*/
|
|
28
28
|
--dx-elevation-0: light-dark(var(--color-neutral-300), var(--color-neutral-950));
|
|
29
|
-
--dx-elevation-1: light-dark(var(--color-neutral-
|
|
30
|
-
--dx-elevation-2: light-dark(var(--color-neutral-
|
|
31
|
-
--dx-elevation-3: light-dark(var(--color-neutral-125), var(--color-neutral-
|
|
32
|
-
--dx-elevation-4: light-dark(var(--color-neutral-
|
|
33
|
-
--dx-elevation-5: light-dark(var(--color-neutral-
|
|
34
|
-
--dx-elevation-6: light-dark(var(--color-neutral-
|
|
35
|
-
--dx-elevation-7: light-dark(
|
|
29
|
+
--dx-elevation-1: light-dark(var(--color-neutral-300), var(--color-neutral-925));
|
|
30
|
+
--dx-elevation-2: light-dark(var(--color-neutral-200), var(--color-neutral-900));
|
|
31
|
+
--dx-elevation-3: light-dark(var(--color-neutral-125), var(--color-neutral-875));
|
|
32
|
+
--dx-elevation-4: light-dark(var(--color-neutral-125), var(--color-neutral-850));
|
|
33
|
+
--dx-elevation-5: light-dark(var(--color-neutral-100), var(--color-neutral-825));
|
|
34
|
+
--dx-elevation-6: light-dark(var(--color-neutral-75), var(--color-neutral-800));
|
|
35
|
+
--dx-elevation-7: light-dark(var(--color-neutral-50), var(--color-neutral-775));
|
|
36
|
+
--dx-elevation-8: light-dark(white, var(--color-neutral-750));
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
39
|
* Elevation 0
|
|
@@ -50,71 +51,75 @@
|
|
|
50
51
|
* Elevation 1
|
|
51
52
|
*/
|
|
52
53
|
|
|
53
|
-
--color-
|
|
54
|
+
--color-card-surface: var(--dx-elevation-1);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Elevation 2
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
--color-base-surface: var(--dx-elevation-2);
|
|
54
61
|
--color-base-fg: light-dark(var(--color-neutral-950), var(--color-neutral-150));
|
|
55
62
|
|
|
63
|
+
/* Map attention to focus-surface logic so that elements acting as active attention zones highlight correctly on focus. */
|
|
64
|
+
--color-attention-surface: var(--dx-elevation-2);
|
|
65
|
+
--color-attention-contains: oklch(from var(--color-accent-bg) l c h / 0.3);
|
|
66
|
+
|
|
56
67
|
/**
|
|
57
|
-
* Elevation
|
|
68
|
+
* Elevation 3
|
|
58
69
|
*/
|
|
59
70
|
|
|
60
|
-
--color-header-surface: var(--dx-elevation-
|
|
71
|
+
--color-header-surface: var(--dx-elevation-3);
|
|
61
72
|
|
|
62
|
-
--color-sidebar-surface: var(--dx-elevation-
|
|
73
|
+
--color-sidebar-surface: var(--dx-elevation-3);
|
|
63
74
|
/* Sidebar body text. Default sits one ramp stop below the current/selected emphasis. */
|
|
64
75
|
--color-sidebar-fg: light-dark(var(--color-neutral-700), var(--color-neutral-250));
|
|
65
76
|
--color-sidebar-current-fg: light-dark(var(--color-neutral-950), var(--color-neutral-75));
|
|
66
77
|
|
|
67
78
|
/* Sidebar / panel layout levels */
|
|
68
|
-
--color-l0-surface: var(--dx-elevation-
|
|
69
|
-
--color-l1-surface: var(--dx-elevation-
|
|
70
|
-
--color-r0-surface: var(--dx-elevation-
|
|
71
|
-
--color-r1-surface: var(--dx-elevation-
|
|
79
|
+
--color-l0-surface: var(--dx-elevation-2);
|
|
80
|
+
--color-l1-surface: var(--dx-elevation-3);
|
|
81
|
+
--color-r0-surface: var(--dx-elevation-3);
|
|
82
|
+
--color-r1-surface: var(--dx-elevation-3);
|
|
72
83
|
|
|
73
84
|
/**
|
|
74
|
-
* Elevation
|
|
85
|
+
* Elevation 4
|
|
75
86
|
*/
|
|
76
87
|
|
|
77
|
-
--color-
|
|
78
|
-
|
|
79
|
-
/* Map attention to focus-surface logic so that elements acting as active attention zones highlight correctly on focus. */
|
|
80
|
-
--color-attention-surface: var(--dx-elevation-3);
|
|
81
|
-
--color-attention-contains: oklch(from var(--color-accent-bg) l c h / 0.3);
|
|
88
|
+
--color-toolbar-surface: var(--dx-elevation-4);
|
|
82
89
|
|
|
83
90
|
/**
|
|
84
|
-
* Elevation
|
|
91
|
+
* Elevation 5
|
|
85
92
|
*/
|
|
86
93
|
|
|
87
94
|
/* Focus — a raised content surface (one level above card) so an attended pane reads as lifted. */
|
|
88
|
-
--color-focus-surface: var(--dx-elevation-
|
|
95
|
+
--color-focus-surface: var(--dx-elevation-5);
|
|
89
96
|
--color-focus-ring: light-dark(var(--color-blue-400), var(--color-blue-600));
|
|
90
97
|
--color-focus-ring-subtle: light-dark(var(--color-neutral-300), var(--color-neutral-600));
|
|
91
98
|
|
|
92
|
-
--color-group-surface: var(--dx-elevation-
|
|
99
|
+
--color-group-surface: var(--dx-elevation-5);
|
|
93
100
|
/* Subtle alternate of group-surface for zebra striping (e.g. calendar months) — offset off
|
|
94
101
|
* elevation-4 via relative oklch so it tracks the ramp: darker in light mode, lighter in dark. */
|
|
95
102
|
--color-group-alt-surface: light-dark(
|
|
96
|
-
oklch(from var(--dx-elevation-
|
|
97
|
-
oklch(from var(--dx-elevation-
|
|
103
|
+
oklch(from var(--dx-elevation-5) calc(l - 0.03) c h),
|
|
104
|
+
oklch(from var(--dx-elevation-5) calc(l + 0.03) c h)
|
|
98
105
|
);
|
|
99
106
|
|
|
100
|
-
--color-input-surface: var(--dx-elevation-
|
|
107
|
+
--color-input-surface: var(--dx-elevation-5);
|
|
101
108
|
|
|
102
109
|
/**
|
|
103
|
-
* Elevation
|
|
110
|
+
* Elevation 6
|
|
104
111
|
*/
|
|
105
112
|
|
|
106
|
-
--color-
|
|
107
|
-
|
|
108
|
-
--color-modal-surface: var(--dx-elevation-5);
|
|
113
|
+
--color-modal-surface: var(--dx-elevation-6);
|
|
109
114
|
|
|
110
115
|
/**
|
|
111
|
-
* Elevation
|
|
116
|
+
* Elevation 7
|
|
112
117
|
*/
|
|
113
118
|
|
|
114
|
-
--color-popover-surface: var(--dx-elevation-
|
|
119
|
+
--color-popover-surface: var(--dx-elevation-7);
|
|
115
120
|
|
|
116
121
|
/**
|
|
117
|
-
* Elevation
|
|
122
|
+
* Elevation 8
|
|
118
123
|
*/
|
|
119
124
|
|
|
120
125
|
/**
|
|
@@ -198,9 +203,10 @@
|
|
|
198
203
|
--color-un-accent-hover: var(--color-neutral-500);
|
|
199
204
|
|
|
200
205
|
/* Separator */
|
|
201
|
-
--color-primary-separator: light-dark(var(--color-neutral-
|
|
206
|
+
--color-primary-separator: light-dark(var(--color-neutral-200), var(--color-neutral-800));
|
|
202
207
|
--color-separator: light-dark(var(--color-neutral-200), var(--color-neutral-700));
|
|
203
|
-
--color-
|
|
208
|
+
--color-input-separator: light-dark(var(--color-neutral-250), var(--color-neutral-750));
|
|
209
|
+
--color-subdued-separator: light-dark(var(--color-neutral-250), var(--color-neutral-775));
|
|
204
210
|
--color-active-separator: light-dark(var(--color-blue-500), var(--color-blue-500));
|
|
205
211
|
|
|
206
212
|
/* Scrollbar */
|
|
@@ -84,10 +84,12 @@
|
|
|
84
84
|
--dx-lacuna-4: 0.5rem;
|
|
85
85
|
--dx-lacuna-6: 0.75rem;
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
--dx-gutter-sm:
|
|
89
|
-
|
|
90
|
-
--dx-gutter-
|
|
87
|
+
/* Form: 8px */
|
|
88
|
+
--dx-gutter-sm: 0.5rem;
|
|
89
|
+
/* Dialog: 16px */
|
|
90
|
+
--dx-gutter-md: 1rem;
|
|
91
|
+
/* Card: 32px */
|
|
92
|
+
--dx-gutter-lg: 2rem;
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
:root {
|
package/src/util/index.ts
CHANGED
package/src/util/mx.ts
CHANGED
|
@@ -4,45 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
import { extendTailwindMerge, validators } from 'tailwind-merge';
|
|
6
6
|
|
|
7
|
-
type AdditionalClassGroups
|
|
7
|
+
import { type AdditionalClassGroups, twMergeConfig } from './tw-merge-config';
|
|
8
8
|
|
|
9
9
|
export const mx = extendTailwindMerge<AdditionalClassGroups>({
|
|
10
10
|
extend: {
|
|
11
|
+
...twMergeConfig.extend,
|
|
11
12
|
classGroups: {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
'font-thin',
|
|
16
|
-
'font-extralight',
|
|
17
|
-
'font-light',
|
|
18
|
-
'font-normal',
|
|
19
|
-
'font-medium',
|
|
20
|
-
'font-semibold',
|
|
21
|
-
'font-bold',
|
|
22
|
-
'font-extrabold',
|
|
23
|
-
'font-black',
|
|
24
|
-
// Arbitrary numbers
|
|
25
|
-
validators.isArbitraryNumber,
|
|
26
|
-
],
|
|
27
|
-
|
|
28
|
-
density: ['dx-density-sm', 'dx-density-md', 'dx-density-lg'],
|
|
29
|
-
|
|
30
|
-
'dx-focus-ring': [
|
|
31
|
-
'dx-focus-ring',
|
|
32
|
-
'dx-focus-ring-inset',
|
|
33
|
-
'dx-focus-ring-always',
|
|
34
|
-
'dx-focus-ring-inset-always',
|
|
35
|
-
'dx-focus-ring-group',
|
|
36
|
-
'dx-focus-ring-group-x',
|
|
37
|
-
'dx-focus-ring-group-y',
|
|
38
|
-
'dx-focus-ring-group-always',
|
|
39
|
-
'dx-focus-ring-group-x-always',
|
|
40
|
-
'dx-focus-ring-group-y-always',
|
|
41
|
-
'dx-focus-ring-inset-over-all',
|
|
42
|
-
'dx-focus-ring-inset-over-all-always',
|
|
43
|
-
'dx-focus-ring-main',
|
|
44
|
-
'dx-focus-ring-main-always',
|
|
45
|
-
],
|
|
13
|
+
...twMergeConfig.extend.classGroups,
|
|
14
|
+
// Arbitrary numeric font-weights require a validator (not expressible as a plain string token).
|
|
15
|
+
'font-weight': [...twMergeConfig.extend.classGroups['font-weight'], validators.isArbitraryNumber],
|
|
46
16
|
},
|
|
47
17
|
},
|
|
48
18
|
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { mx } from './mx';
|
|
8
|
+
import { bridgeTv, tv } from './tv';
|
|
9
|
+
|
|
10
|
+
describe('tv', () => {
|
|
11
|
+
test('resolves standard tailwind conflicts like mx', ({ expect }) => {
|
|
12
|
+
const recipe = tv({ base: 'text-sm', variants: { big: { true: 'text-lg' } } });
|
|
13
|
+
expect(recipe({ big: true })).toBe(mx('text-sm', 'text-lg'));
|
|
14
|
+
expect(recipe({ big: true })).toContain('text-lg');
|
|
15
|
+
expect(recipe({ big: true })).not.toContain('text-sm');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('keeps dxos custom color tokens (text-base-fg over text-description)', ({ expect }) => {
|
|
19
|
+
const recipe = tv({ base: 'text-description', variants: { strong: { true: 'text-base-fg' } } });
|
|
20
|
+
expect(recipe({ strong: true })).toBe(mx('text-description', 'text-base-fg'));
|
|
21
|
+
expect(recipe({ strong: true })).toContain('text-base-fg');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('bridgeTv', () => {
|
|
26
|
+
test('adapts a slots recipe into Theme<P> functions with overrides', ({ expect }) => {
|
|
27
|
+
const recipe = tv({
|
|
28
|
+
slots: { root: 'p-1', label: 'text-sm' },
|
|
29
|
+
variants: { variant: { settings: { root: 'p-4', label: 'text-lg' } } },
|
|
30
|
+
});
|
|
31
|
+
const theme = bridgeTv(recipe, ['root', 'label']);
|
|
32
|
+
expect(typeof theme.root).toBe('function');
|
|
33
|
+
expect(theme.root({ variant: 'settings' })).toContain('p-4');
|
|
34
|
+
// consumer override wins via per-slot merge.
|
|
35
|
+
expect(theme.label({ variant: 'settings' }, 'text-xl')).toContain('text-xl');
|
|
36
|
+
expect(theme.label({ variant: 'settings' }, 'text-xl')).not.toContain('text-lg');
|
|
37
|
+
});
|
|
38
|
+
});
|
package/src/util/tv.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createTV } from 'tailwind-variants';
|
|
6
|
+
|
|
7
|
+
import { type ClassNameArray, type ClassNameValue, type Theme } from '@dxos/ui-types';
|
|
8
|
+
|
|
9
|
+
import { twMergeConfig } from './tw-merge-config';
|
|
10
|
+
|
|
11
|
+
export type { VariantProps } from 'tailwind-variants';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Shared tailwind-variants instance bound to the dxos tailwind-merge config (see {@link twMergeConfig}),
|
|
15
|
+
* so recipes resolve class conflicts identically to {@link mx}. All component theme recipes import this,
|
|
16
|
+
* never the bare `tailwind-variants` package.
|
|
17
|
+
*/
|
|
18
|
+
export const tv = createTV({ twMerge: true, twMergeConfig });
|
|
19
|
+
|
|
20
|
+
type SlotsRecipe<P extends Record<string, any>, S extends string> = (
|
|
21
|
+
props?: P,
|
|
22
|
+
) => Record<S, (opts?: { class?: ClassNameValue }) => string>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The {@link Theme} sub-tree produced by {@link bridgeTv}, with each slot's resolver explicitly typed
|
|
26
|
+
* so call sites (and tests) stay fully typed instead of falling back to `any`.
|
|
27
|
+
*/
|
|
28
|
+
export type BridgedTheme<P extends Record<string, any>, S extends string> = Theme<P> & {
|
|
29
|
+
[K in S]: (styleProps: P, ...etc: ClassNameArray) => string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Adapt a tailwind-variants slots recipe into the existing {@link Theme} shape (a map of
|
|
34
|
+
* {@link import('@dxos/ui-types').ComponentFunction}) so it can register in the `tx` theme tree and be
|
|
35
|
+
* consumed via `tx('component.slot', styleProps, ...classNames)`. Slots are enumerated explicitly (not
|
|
36
|
+
* via Proxy) so unknown paths resolve to `undefined` exactly as `getDeep` does today, and the result is
|
|
37
|
+
* a plain, inspectable object. Derive `slots` from `Object.keys(recipe())` at the call site.
|
|
38
|
+
*/
|
|
39
|
+
export const bridgeTv = <P extends Record<string, any>, S extends string>(
|
|
40
|
+
recipe: SlotsRecipe<P, S>,
|
|
41
|
+
slots: readonly S[],
|
|
42
|
+
): BridgedTheme<P, S> =>
|
|
43
|
+
Object.fromEntries(
|
|
44
|
+
slots.map((slot) => [slot, (styleProps: P, ...etc: ClassNameArray) => recipe(styleProps)[slot]({ class: etc })]),
|
|
45
|
+
) as BridgedTheme<P, S>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shared tailwind-merge configuration. The single source for both {@link mx} (extendTailwindMerge)
|
|
7
|
+
* and the {@link tv} instance (createTV `twMergeConfig`) so conflict resolution can't drift —
|
|
8
|
+
* notably for dxos custom tokens (`text-base-fg`, density, focus-ring).
|
|
9
|
+
*/
|
|
10
|
+
export const twMergeConfig = {
|
|
11
|
+
extend: {
|
|
12
|
+
classGroups: {
|
|
13
|
+
'font-family': ['font-body', 'font-mono'],
|
|
14
|
+
'font-weight': [
|
|
15
|
+
'font-thin',
|
|
16
|
+
'font-extralight',
|
|
17
|
+
'font-light',
|
|
18
|
+
'font-normal',
|
|
19
|
+
'font-medium',
|
|
20
|
+
'font-semibold',
|
|
21
|
+
'font-bold',
|
|
22
|
+
'font-extrabold',
|
|
23
|
+
'font-black',
|
|
24
|
+
],
|
|
25
|
+
'density': ['dx-density-sm', 'dx-density-md', 'dx-density-lg'],
|
|
26
|
+
'dx-focus-ring': [
|
|
27
|
+
'dx-focus-ring',
|
|
28
|
+
'dx-focus-ring-inset',
|
|
29
|
+
'dx-focus-ring-always',
|
|
30
|
+
'dx-focus-ring-inset-always',
|
|
31
|
+
'dx-focus-ring-group',
|
|
32
|
+
'dx-focus-ring-group-x',
|
|
33
|
+
'dx-focus-ring-group-y',
|
|
34
|
+
'dx-focus-ring-group-always',
|
|
35
|
+
'dx-focus-ring-group-x-always',
|
|
36
|
+
'dx-focus-ring-group-y-always',
|
|
37
|
+
'dx-focus-ring-inset-over-all',
|
|
38
|
+
'dx-focus-ring-inset-over-all-always',
|
|
39
|
+
'dx-focus-ring-main',
|
|
40
|
+
'dx-focus-ring-main-always',
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
} as const;
|
|
45
|
+
|
|
46
|
+
export type AdditionalClassGroups = 'density' | 'dx-focus-ring';
|