@dxos/ui-theme 0.8.4-main.c85a9c8dae → 0.8.4-main.e00bdcdb52
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 +397 -471
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +397 -471
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/plugin/node-cjs/{theme.css → main.css} +122 -55
- package/dist/plugin/node-cjs/main.css.map +7 -0
- package/dist/plugin/node-cjs/meta.json +1 -1
- package/dist/plugin/node-cjs/plugins/ThemePlugin.cjs +8 -15
- package/dist/plugin/node-cjs/plugins/ThemePlugin.cjs.map +3 -3
- package/dist/plugin/node-esm/{theme.css → main.css} +122 -55
- package/dist/plugin/node-esm/main.css.map +7 -0
- package/dist/plugin/node-esm/meta.json +1 -1
- package/dist/plugin/node-esm/plugins/ThemePlugin.mjs +8 -15
- package/dist/plugin/node-esm/plugins/ThemePlugin.mjs.map +3 -3
- package/dist/types/src/Theme.stories.d.ts.map +1 -1
- package/dist/types/src/defs.d.ts +2 -2
- package/dist/types/src/defs.d.ts.map +1 -1
- package/dist/types/src/fragments/density.d.ts +1 -4
- package/dist/types/src/fragments/density.d.ts.map +1 -1
- package/dist/types/src/fragments/index.d.ts +0 -5
- package/dist/types/src/fragments/index.d.ts.map +1 -1
- package/dist/types/src/fragments/text.d.ts +0 -5
- package/dist/types/src/fragments/text.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/plugins/ThemePlugin.d.ts +1 -1
- package/dist/types/src/plugins/ThemePlugin.d.ts.map +1 -1
- package/dist/types/src/theme/components/avatar.d.ts.map +1 -1
- package/dist/types/src/theme/components/card.d.ts +3 -2
- package/dist/types/src/theme/components/card.d.ts.map +1 -1
- package/dist/types/src/theme/components/dialog.d.ts.map +1 -1
- package/dist/types/src/theme/components/focus.d.ts +6 -0
- package/dist/types/src/theme/components/focus.d.ts.map +1 -0
- package/dist/types/src/theme/components/icon-button.d.ts +1 -0
- package/dist/types/src/theme/components/icon-button.d.ts.map +1 -1
- package/dist/types/src/theme/components/icon.d.ts +3 -0
- package/dist/types/src/theme/components/icon.d.ts.map +1 -1
- package/dist/types/src/theme/components/index.d.ts +1 -0
- package/dist/types/src/theme/components/index.d.ts.map +1 -1
- package/dist/types/src/theme/components/input.d.ts +8 -8
- package/dist/types/src/theme/components/input.d.ts.map +1 -1
- package/dist/types/src/theme/components/link.d.ts.map +1 -1
- package/dist/types/src/theme/components/list.d.ts.map +1 -1
- package/dist/types/src/theme/components/main.d.ts.map +1 -1
- package/dist/types/src/theme/components/message.d.ts.map +1 -1
- package/dist/types/src/theme/components/popover.d.ts.map +1 -1
- package/dist/types/src/theme/components/scroll-area.d.ts +12 -2
- package/dist/types/src/theme/components/scroll-area.d.ts.map +1 -1
- package/dist/types/src/theme/components/select.d.ts.map +1 -1
- package/dist/types/src/theme/components/status.d.ts +1 -1
- package/dist/types/src/theme/components/status.d.ts.map +1 -1
- package/dist/types/src/theme/components/toast.d.ts.map +1 -1
- package/dist/types/src/theme/components/toolbar.d.ts +0 -1
- package/dist/types/src/theme/components/toolbar.d.ts.map +1 -1
- package/dist/types/src/theme/components/tooltip.d.ts.map +1 -1
- package/dist/types/src/theme/components/treegrid.d.ts.map +1 -1
- package/dist/types/src/theme/index.d.ts +1 -0
- package/dist/types/src/theme/index.d.ts.map +1 -1
- package/dist/types/src/theme/primitives/column.d.ts +25 -3
- package/dist/types/src/theme/primitives/column.d.ts.map +1 -1
- package/dist/types/src/theme/primitives/panel.d.ts +9 -5
- package/dist/types/src/theme/primitives/panel.d.ts.map +1 -1
- package/dist/types/src/theme/theme.d.ts.map +1 -1
- package/dist/types/src/util/elevation.d.ts.map +1 -0
- package/dist/types/src/util/hash-styles.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +3 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/mx.d.ts +52 -4
- package/dist/types/src/util/mx.d.ts.map +1 -1
- package/dist/types/src/util/size.d.ts +27 -0
- package/dist/types/src/util/size.d.ts.map +1 -0
- package/dist/types/src/util/valence.d.ts +4 -0
- package/dist/types/src/util/valence.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -15
- package/src/css/components/button.css +2 -1
- package/src/css/components/{focus-ring.css → focus.css} +15 -1
- package/src/css/components/icon.css +9 -0
- package/src/css/components/panel.css +22 -22
- package/src/css/components/selected.css +30 -0
- package/src/css/components/tag.css +3 -1
- package/src/css/integrations/codemirror.css +5 -3
- package/src/css/integrations/tldraw.css +1 -0
- package/src/css/layout/main.css +0 -7
- package/src/css/layout/size.css +19 -27
- package/src/css/theme/animation.css +31 -0
- package/src/css/theme/palette.css +8 -0
- package/src/css/theme/semantic.css +25 -9
- package/src/css/theme/spacing.css +36 -19
- package/src/css/utilities.css +114 -3
- package/src/defs.ts +1 -1
- package/src/fragments/AUDIT.md +57 -0
- package/src/fragments/density.ts +8 -5
- package/src/fragments/index.ts +1 -6
- package/src/fragments/text.ts +1 -6
- package/src/index.ts +1 -1
- package/src/{theme.css → main.css} +10 -6
- package/src/plugins/ThemePlugin.ts +12 -24
- package/src/plugins/main.css +45 -0
- package/src/theme/components/avatar.ts +3 -4
- package/src/theme/components/button.ts +1 -1
- package/src/theme/components/card.ts +19 -11
- package/src/theme/components/dialog.ts +4 -3
- package/src/theme/components/focus.ts +33 -0
- package/src/theme/components/icon-button.ts +6 -5
- package/src/theme/components/icon.ts +13 -4
- package/src/theme/components/index.ts +1 -0
- package/src/theme/components/input.ts +15 -30
- package/src/theme/components/link.ts +1 -2
- package/src/theme/components/list.ts +4 -4
- package/src/theme/components/menu.ts +4 -4
- package/src/theme/components/message.ts +2 -3
- package/src/theme/components/popover.ts +4 -5
- package/src/theme/components/scroll-area.ts +58 -46
- package/src/theme/components/select.ts +2 -3
- package/src/theme/components/status.ts +5 -5
- package/src/theme/components/toast.ts +2 -3
- package/src/theme/components/toolbar.ts +1 -7
- package/src/theme/components/tooltip.ts +1 -2
- package/src/theme/components/treegrid.ts +1 -1
- package/src/theme/index.ts +1 -0
- package/src/theme/primitives/column.ts +49 -8
- package/src/theme/primitives/panel.ts +19 -23
- package/src/theme/theme.ts +2 -0
- package/src/typings.d.ts +3 -0
- package/src/util/index.ts +3 -0
- package/src/util/mx.ts +119 -8
- package/src/util/size.ts +103 -0
- package/dist/plugin/node-cjs/theme.css.map +0 -7
- package/dist/plugin/node-esm/theme.css.map +0 -7
- package/dist/types/src/fragments/elevation.d.ts.map +0 -1
- package/dist/types/src/fragments/focus.d.ts +0 -4
- package/dist/types/src/fragments/focus.d.ts.map +0 -1
- package/dist/types/src/fragments/selected.d.ts +0 -4
- package/dist/types/src/fragments/selected.d.ts.map +0 -1
- package/dist/types/src/fragments/size.d.ts +0 -7
- package/dist/types/src/fragments/size.d.ts.map +0 -1
- package/dist/types/src/fragments/valence.d.ts +0 -4
- package/dist/types/src/fragments/valence.d.ts.map +0 -1
- package/src/fragments/focus.ts +0 -11
- package/src/fragments/selected.ts +0 -12
- package/src/fragments/size.ts +0 -117
- /package/dist/types/src/{fragments → util}/elevation.d.ts +0 -0
- /package/src/{fragments → util}/elevation.ts +0 -0
- /package/src/{fragments → util}/valence.ts +0 -0
package/src/css/utilities.css
CHANGED
|
@@ -1,7 +1,118 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Tailwind utility classes.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Layout rules for flex-based scroll containment:
|
|
7
|
+
* `flex flex-col`
|
|
8
|
+
* On a container: makes it a flex column so children stack and can use `flex-1`.
|
|
9
|
+
* `flex-1`
|
|
10
|
+
* On a child: grows to fill the flex parent. Requires the parent to be `flex`.
|
|
11
|
+
* `min-h-0` (alongside `flex-1`):
|
|
12
|
+
* Overrides default flex children: `min-height:auto` (sized to content), which prevents shrinking.
|
|
13
|
+
* Allows element to shrink and trigger overflow/scrolling.
|
|
14
|
+
* Always pair with `flex-1` when scroll is needed.
|
|
15
|
+
* `h-full`:
|
|
16
|
+
* Fills 100% of the parent's *computed* height.
|
|
17
|
+
* Use when the parent has a definite height but is not a flex container (e.g. `overflow:hidden` wrapper).
|
|
18
|
+
* Unlike `flex-1`, does not require the parent to be flex.
|
|
19
|
+
*
|
|
20
|
+
* Pattern for a scrollable region inside a flex ancestor:
|
|
21
|
+
* ancestor → `flex flex-col` (or `flex flex-row`)
|
|
22
|
+
* scroll root → `flex-1 min-h-0` (fills ancestor, can shrink)
|
|
23
|
+
* scroll viewport → `h-full overflow-y-scroll` (fills root, scrolls)
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Fills the available space.
|
|
28
|
+
*/
|
|
29
|
+
@utility dx-expander {
|
|
30
|
+
@apply flex-1 min-h-0 min-w-0 h-full w-full;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Container that fills the available space (extends dx-expander with overflow clipping).
|
|
35
|
+
*/
|
|
36
|
+
@utility dx-container {
|
|
37
|
+
@apply dx-expander overflow-hidden;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Column that fills the available space (extends dx-expander with overflow clipping).
|
|
42
|
+
*/
|
|
43
|
+
@utility dx-column {
|
|
44
|
+
@apply flex-1 min-w-0 w-full;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Fullscreen
|
|
49
|
+
*/
|
|
50
|
+
@utility dx-fullscreen {
|
|
51
|
+
@apply absolute inset-0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Visual warning to indicate incorrect usage of `slottable`.
|
|
56
|
+
*/
|
|
57
|
+
@utility dx-slot-warning {
|
|
58
|
+
@apply border border-rose-500 border-dashed;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Pseudo-element overlay for ring indicators (focus, current, etc.).
|
|
63
|
+
*
|
|
64
|
+
* A standard CSS `box-shadow` ring is painted behind child content, so children with
|
|
65
|
+
* opaque backgrounds (e.g., cards, avatars) obscure it. By painting the ring on an
|
|
66
|
+
* absolutely-positioned `::after` pseudo-element that sits above the element's children
|
|
67
|
+
* in stacking order, the ring is always visible regardless of child backgrounds.
|
|
68
|
+
*
|
|
69
|
+
* The pseudo-element inherits `border-radius` from its parent and is `pointer-events-none`
|
|
70
|
+
* so it doesn't interfere with interactions. The ring starts transparent; consumers
|
|
71
|
+
* activate it conditionally (e.g., `focus:after:ring-*`, `aria-[current=true]:after:ring-*`).
|
|
72
|
+
*/
|
|
73
|
+
@utility dx-ring-pseudo {
|
|
74
|
+
@apply relative after:content-[""] after:absolute after:inset-0 after:rounded-[inherit]
|
|
75
|
+
after:pointer-events-none after:ring after:ring-inset after:ring-transparent;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Shimmer text — animates opacity left → right across the contained text.
|
|
80
|
+
* See @keyframes shimmer-text in theme/animation.css for the keyframe definition.
|
|
81
|
+
* Geometry: mask-size 200% 100% with mask-repeat: repeat-x means each tile is
|
|
82
|
+
* 2× the element width; the keyframe slides mask-position-x by 200% (one full
|
|
83
|
+
* tile period), giving a seamless loop. The 5-stop gradient (0.4 → 1.0 → 0.4)
|
|
84
|
+
* produces a single bright pulse per cycle that traverses left → right during
|
|
85
|
+
* the first half, with a brief calm interval during the second half.
|
|
86
|
+
*/
|
|
87
|
+
@utility shimmer-text {
|
|
88
|
+
mask-image: linear-gradient(
|
|
89
|
+
90deg,
|
|
90
|
+
rgba(0, 0, 0, 0.4) 0%,
|
|
91
|
+
rgba(0, 0, 0, 0.4) 30%,
|
|
92
|
+
rgba(0, 0, 0, 1) 50%,
|
|
93
|
+
rgba(0, 0, 0, 0.4) 70%,
|
|
94
|
+
rgba(0, 0, 0, 0.4) 100%
|
|
95
|
+
);
|
|
96
|
+
-webkit-mask-image: linear-gradient(
|
|
97
|
+
90deg,
|
|
98
|
+
rgba(0, 0, 0, 0.4) 0%,
|
|
99
|
+
rgba(0, 0, 0, 0.4) 30%,
|
|
100
|
+
rgba(0, 0, 0, 1) 50%,
|
|
101
|
+
rgba(0, 0, 0, 0.4) 70%,
|
|
102
|
+
rgba(0, 0, 0, 0.4) 100%
|
|
103
|
+
);
|
|
104
|
+
mask-size: 200% 100%;
|
|
105
|
+
-webkit-mask-size: 200% 100%;
|
|
106
|
+
mask-repeat: repeat-x;
|
|
107
|
+
-webkit-mask-repeat: repeat-x;
|
|
108
|
+
animation: shimmer-text 2s linear infinite;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@media (prefers-reduced-motion: reduce) {
|
|
112
|
+
.shimmer-text {
|
|
113
|
+
animation: none;
|
|
114
|
+
mask-image: none;
|
|
115
|
+
-webkit-mask-image: none;
|
|
116
|
+
opacity: 0.6;
|
|
117
|
+
}
|
|
7
118
|
}
|
package/src/defs.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { type ChromaticPalette } from '@dxos/ui-types';
|
|
|
7
7
|
/**
|
|
8
8
|
* Translation namespace for OS-level translations.
|
|
9
9
|
*/
|
|
10
|
-
export const osTranslations = 'dxos.
|
|
10
|
+
export const osTranslations = 'org.dxos.i18n.os';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Available color hues for UI components.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Fragment Definitions Audit
|
|
2
|
+
|
|
3
|
+
External packages importing fragment definitions from `ui-theme/src/fragments`.
|
|
4
|
+
|
|
5
|
+
## Current Fragment Exports
|
|
6
|
+
|
|
7
|
+
| File | Definition | External | Internal |
|
|
8
|
+
| ------------- | ------------------------------------- | -------- | -------- |
|
|
9
|
+
| `density.ts` | `densityBlockSize` | - | 1 |
|
|
10
|
+
| `density.ts` | `coarseBlockSize` | - | 1 |
|
|
11
|
+
| `density.ts` | `coarseDimensions` | - | 1 |
|
|
12
|
+
| `density.ts` | `fineBlockSize` | - | 1 |
|
|
13
|
+
| `density.ts` | `fineDimensions` | - | 1 |
|
|
14
|
+
| `disabled.ts` | `staticDisabled` | - | 1 |
|
|
15
|
+
| `disabled.ts` | `dataDisabled` | - | 1 |
|
|
16
|
+
| `focus.ts` | `focusRing` | 2 | 5 |
|
|
17
|
+
| `focus.ts` | `subduedFocus` | - | 2 |
|
|
18
|
+
| `focus.ts` | `staticFocusRing` | - | 1 |
|
|
19
|
+
| `hover.ts` | `subtleHover` | 4 | - |
|
|
20
|
+
| `hover.ts` | `ghostHover` | 8 | 2 |
|
|
21
|
+
| `hover.ts` | `ghostFocusWithin` | 1 | - |
|
|
22
|
+
| `hover.ts` | `hoverableControls` | 9 | - |
|
|
23
|
+
| `hover.ts` | `groupHoverControlItemWithTransition` | 2 | - |
|
|
24
|
+
| `hover.ts` | `hoverableFocusedKeyboardControls` | 1 | - |
|
|
25
|
+
| `hover.ts` | `hoverableFocusedWithinControls` | 9 | - |
|
|
26
|
+
| `hover.ts` | `hoverableOpenControlItem` | 3 | - |
|
|
27
|
+
| `hover.ts` | `hoverableControlItem` | 7 | - |
|
|
28
|
+
| `text.ts` | `descriptionTextPrimary` | 1 | - |
|
|
29
|
+
| `text.ts` | `descriptionMessage` | 5 | - |
|
|
30
|
+
|
|
31
|
+
## Summary
|
|
32
|
+
|
|
33
|
+
**Total fragments:** 21
|
|
34
|
+
**Total imports (external + internal):** 96
|
|
35
|
+
|
|
36
|
+
- **External:** 63
|
|
37
|
+
- **Internal:** 33
|
|
38
|
+
|
|
39
|
+
**Most imported overall:**
|
|
40
|
+
|
|
41
|
+
- `hoverableControls` (9 external)
|
|
42
|
+
- `hoverableFocusedWithinControls` (9 external)
|
|
43
|
+
- `ghostHover` (8 external + 2 internal = 10 total)
|
|
44
|
+
- `hoverableControlItem` (7 external)
|
|
45
|
+
- `focusRing` (2 external + 5 internal = 7 total)
|
|
46
|
+
|
|
47
|
+
**Internal imports by file:**
|
|
48
|
+
|
|
49
|
+
- `input.ts`: 8 definitions (coarseBlockSize, coarseDimensions, fineBlockSize, fineDimensions, focusRing, staticDisabled, staticFocusRing, subduedFocus)
|
|
50
|
+
- `list.ts`: 3 definitions (densityBlockSize, focusRing, ghostHover)
|
|
51
|
+
- `menu.ts`: 2 definitions (dataDisabled, subduedFocus)
|
|
52
|
+
- `button.ts`, `link.ts`, `popover.ts`, `toast.ts`: 1 definition each (ghostHover, focusRing, focusRing, focusRing)
|
|
53
|
+
|
|
54
|
+
**Completely unused:** 7 fragments
|
|
55
|
+
|
|
56
|
+
- `subtleHover` from `hover.ts`
|
|
57
|
+
- `hoverableOpenControlItem`, `groupHoverControlItemWithTransition` from `hover.ts` (only 2-3 uses)
|
package/src/fragments/density.ts
CHANGED
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import { type Density } from '@dxos/ui-types';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
const fineBlockSize = 'min-h-[2.5rem] pointer-fine:min-h-[2rem]';
|
|
8
|
+
const coarseBlockSize = 'min-h-[2.5rem]';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const fineDimensions = `${fineBlockSize} px-2`;
|
|
11
|
+
const coarseDimensions = `${coarseBlockSize} px-3`;
|
|
12
12
|
|
|
13
|
-
export const
|
|
13
|
+
export const densityDimensions = (density: Density = 'fine') =>
|
|
14
|
+
density === 'fine' ? fineDimensions : coarseDimensions;
|
|
15
|
+
|
|
16
|
+
export const densityBlockSize = (density: Density = 'fine') => (density === 'fine' ? fineBlockSize : coarseBlockSize);
|
package/src/fragments/index.ts
CHANGED
|
@@ -2,14 +2,9 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
// TODO(burdon):
|
|
5
|
+
// TODO(burdon): Remove export of fragments.
|
|
6
6
|
|
|
7
7
|
export * from './density';
|
|
8
8
|
export * from './disabled';
|
|
9
|
-
export * from './elevation';
|
|
10
|
-
export * from './focus';
|
|
11
9
|
export * from './hover';
|
|
12
|
-
export * from './selected';
|
|
13
|
-
export * from './size';
|
|
14
10
|
export * from './text';
|
|
15
|
-
export * from './valence';
|
package/src/fragments/text.ts
CHANGED
|
@@ -2,10 +2,5 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
* Content areas that contain the text editor.
|
|
7
|
-
*/
|
|
8
|
-
export const textBlockWidth = 'w-full max-w-text-content mx-auto';
|
|
9
|
-
|
|
10
|
-
export const descriptionTextPrimary = 'text-sm font-normal text-base-surface-text';
|
|
5
|
+
// TODO(burdon): Replace with Message component.
|
|
11
6
|
export const descriptionMessage = 'text-description border border-dashed border-separator rounded-sm p-4';
|
package/src/index.ts
CHANGED
|
@@ -30,10 +30,12 @@
|
|
|
30
30
|
@import './css/components/button.css';
|
|
31
31
|
@import './css/components/checkbox.css';
|
|
32
32
|
@import './css/components/dialog.css';
|
|
33
|
-
@import './css/components/focus
|
|
33
|
+
@import './css/components/focus.css';
|
|
34
|
+
@import './css/components/icon.css';
|
|
34
35
|
@import './css/components/panel.css';
|
|
35
36
|
@import './css/components/link.css';
|
|
36
37
|
@import './css/components/scrollbar.css';
|
|
38
|
+
@import './css/components/selected.css';
|
|
37
39
|
@import './css/components/surface.css';
|
|
38
40
|
@import './css/components/tag.css';
|
|
39
41
|
@import './css/components/text.css';
|
|
@@ -75,9 +77,11 @@
|
|
|
75
77
|
*/
|
|
76
78
|
@variant dark (&:where(.dark, .dark *));
|
|
77
79
|
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
*/
|
|
81
|
-
@custom-variant is-current (&[aria-current]:not([aria-current="false"]));
|
|
82
|
-
@custom-variant hover-hover (@media (hover: hover));
|
|
80
|
+
/** Mobile */
|
|
81
|
+
@custom-variant pointer-coarse (@media (pointer: coarse));
|
|
82
|
+
/** Web */
|
|
83
83
|
@custom-variant pointer-fine (@media (pointer: fine));
|
|
84
|
+
/** Supports mouse/trackpad (Web) */
|
|
85
|
+
@custom-variant hover-hover (@media (hover: hover));
|
|
86
|
+
/** Active navigation */
|
|
87
|
+
@custom-variant is-current (&[aria-current]:not([aria-current="false"]));
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
/* eslint-disable no-console */
|
|
6
6
|
|
|
7
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
8
|
-
import { dirname, resolve } from 'node:path';
|
|
9
|
-
|
|
10
7
|
import tailwindcss from '@tailwindcss/postcss';
|
|
11
8
|
import autoprefixer from 'autoprefixer';
|
|
9
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
10
|
+
import { dirname, resolve } from 'node:path';
|
|
12
11
|
import postcssImport from 'postcss-import';
|
|
13
12
|
import postcssNesting from 'postcss-nesting';
|
|
14
13
|
import { type HtmlTagDescriptor, type Plugin, type UserConfig } from 'vite';
|
|
@@ -44,16 +43,15 @@ export type ThemePluginOptions = {
|
|
|
44
43
|
*/
|
|
45
44
|
export const ThemePlugin = (options: ThemePluginOptions): Plugin => {
|
|
46
45
|
// Prefer source CSS if available (monorepo dev), fall back to dist for installed package.
|
|
47
|
-
const srcThemePath = resolve(import.meta.dirname, ROOT, 'src/
|
|
48
|
-
const distThemePath = resolve(import.meta.dirname, '../
|
|
46
|
+
const srcThemePath = resolve(import.meta.dirname, ROOT, 'src/main.css');
|
|
47
|
+
const distThemePath = resolve(import.meta.dirname, '../main.css');
|
|
49
48
|
const isMonorepo = existsSync(srcThemePath);
|
|
50
49
|
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const darkModeScriptPath = existsSync(srcDarkModePath) ? srcDarkModePath : distDarkModePath;
|
|
50
|
+
// Static assets shipped via "files": ["src"] in package.json.
|
|
51
|
+
// Both monorepo and installed package resolve to the same src/plugins/ directory.
|
|
52
|
+
const pluginsDir = resolve(import.meta.dirname, ROOT, 'src/plugins');
|
|
53
|
+
const darkModeScriptPath = resolve(pluginsDir, 'dark-mode.ts');
|
|
54
|
+
const mainCssPath = resolve(pluginsDir, 'main.css');
|
|
57
55
|
|
|
58
56
|
const config: ThemePluginOptions = {
|
|
59
57
|
srcCssPath: isMonorepo ? srcThemePath : distThemePath,
|
|
@@ -112,23 +110,13 @@ export const ThemePlugin = (options: ThemePluginOptions): Plugin => {
|
|
|
112
110
|
injectTo: 'head-prepend',
|
|
113
111
|
};
|
|
114
112
|
|
|
115
|
-
// Critical
|
|
116
|
-
//
|
|
117
|
-
// removed before the new one is inserted, briefly leaving all --color-* vars undefined.
|
|
118
|
-
// These static approximations of neutral-50/950 survive that gap.
|
|
119
|
-
// Values are intentionally kept in sync with @theme tokens in semantic.css.
|
|
113
|
+
// Critical styles: font sizing, overscroll, color fallbacks.
|
|
114
|
+
// Loaded from critical.css to keep styles maintainable and out of index.html.
|
|
120
115
|
const criticalTag: HtmlTagDescriptor = {
|
|
121
116
|
tag: 'style',
|
|
122
117
|
attrs: { 'data-dxos-critical': '' },
|
|
123
118
|
injectTo: 'head-prepend',
|
|
124
|
-
children:
|
|
125
|
-
':root { color-scheme: light; }',
|
|
126
|
-
'html { color: oklch(0.145 0 0); background-color: oklch(0.985 0 0); }', // ≈ neutral-950 / neutral-50
|
|
127
|
-
'html.dark { color-scheme: dark; color: oklch(0.985 0 0); background-color: oklch(0.145 0 0); }',
|
|
128
|
-
'@media (prefers-color-scheme: dark) {',
|
|
129
|
-
' html:not(.dark) { color: oklch(0.985 0 0); background-color: oklch(0.145 0 0); }',
|
|
130
|
-
'}',
|
|
131
|
-
].join('\n'),
|
|
119
|
+
children: readFileSync(mainCssPath, 'utf-8'),
|
|
132
120
|
};
|
|
133
121
|
|
|
134
122
|
return [darkModeTag, layersTag, criticalTag];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Critical styles injected into <head> by the Vite ThemePlugin before any stylesheets load.
|
|
3
|
+
* Ensures text is readable and layout is stable on the very first paint.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* Base font size: larger default for touch devices, smaller for precision pointers. */
|
|
7
|
+
html {
|
|
8
|
+
font-size: 20px;
|
|
9
|
+
}
|
|
10
|
+
@media (pointer: fine) {
|
|
11
|
+
html {
|
|
12
|
+
font-size: 16px;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Prevent overscroll bounce and ensure full viewport height. */
|
|
17
|
+
html,
|
|
18
|
+
body {
|
|
19
|
+
overscroll-behavior: none;
|
|
20
|
+
-webkit-overflow-scrolling: touch;
|
|
21
|
+
}
|
|
22
|
+
body {
|
|
23
|
+
height: 100vh;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Pre-CSS color fallbacks so text is readable before and during Vite HMR. */
|
|
27
|
+
/* Values are intentionally kept in sync with @theme tokens in semantic.css. */
|
|
28
|
+
:root {
|
|
29
|
+
color-scheme: light;
|
|
30
|
+
}
|
|
31
|
+
html {
|
|
32
|
+
color: oklch(0.145 0 0);
|
|
33
|
+
background-color: oklch(0.985 0 0);
|
|
34
|
+
}
|
|
35
|
+
html.dark {
|
|
36
|
+
color-scheme: dark;
|
|
37
|
+
color: oklch(0.985 0 0);
|
|
38
|
+
background-color: oklch(0.145 0 0);
|
|
39
|
+
}
|
|
40
|
+
@media (prefers-color-scheme: dark) {
|
|
41
|
+
html:not(.dark) {
|
|
42
|
+
color: oklch(0.985 0 0);
|
|
43
|
+
background-color: oklch(0.145 0 0);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { type ComponentFunction, type Size, type Theme } from '@dxos/ui-types';
|
|
6
6
|
|
|
7
|
-
import { getSize,
|
|
8
|
-
import { mx } from '../../util';
|
|
7
|
+
import { mx, getSize, getHeight } from '../../util';
|
|
9
8
|
|
|
10
9
|
export type AvatarStyleProps = Partial<{
|
|
11
10
|
size: Size;
|
|
@@ -30,7 +29,7 @@ export const avatarDescription: ComponentFunction<AvatarStyleProps> = ({ srOnly
|
|
|
30
29
|
mx('text-description', srOnly && 'sr-only', ...etc);
|
|
31
30
|
|
|
32
31
|
export const avatarFrame: ComponentFunction<AvatarStyleProps> = ({ variant }, ...etc) =>
|
|
33
|
-
mx('
|
|
32
|
+
mx('h-full w-full bg-(--surface-bg)', variant === 'circle' ? 'rounded-full' : 'rounded-sm', ...etc);
|
|
34
33
|
|
|
35
34
|
export const avatarStatusIcon: ComponentFunction<AvatarStyleProps> = ({ status, size = 3 }, ...etc) =>
|
|
36
35
|
mx(
|
|
@@ -75,7 +74,7 @@ export const avatarGroupLabel: ComponentFunction<AvatarStyleProps> = ({ size, sr
|
|
|
75
74
|
srOnly
|
|
76
75
|
? 'sr-only'
|
|
77
76
|
: 'rounded-full truncate text-sm leading-none py-1 px-2 relative z-[1] flex items-center justify-center',
|
|
78
|
-
size &&
|
|
77
|
+
size && getHeight(size),
|
|
79
78
|
...etc,
|
|
80
79
|
);
|
|
81
80
|
|
|
@@ -32,7 +32,7 @@ export type ButtonStyleProps = Partial<{
|
|
|
32
32
|
}>;
|
|
33
33
|
|
|
34
34
|
const buttonRoot: ComponentFunction<ButtonStyleProps> = (_props, ...etc) => {
|
|
35
|
-
return mx('dx-button dx-focus-ring group
|
|
35
|
+
return mx('dx-button dx-focus-ring group [&_span]:truncate', ...etc);
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
const buttonGroup: ComponentFunction<{ elevation?: Elevation }> = (_props, ...etc) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type ComponentFunction, type Theme } from '@dxos/ui-types';
|
|
5
|
+
import { type ComponentFunction, type Density, type Theme } from '@dxos/ui-types';
|
|
6
6
|
|
|
7
7
|
import { mx } from '../../util';
|
|
8
8
|
|
|
@@ -11,30 +11,30 @@ export type CardStyleProps = {
|
|
|
11
11
|
fullWidth?: boolean;
|
|
12
12
|
srOnly?: boolean;
|
|
13
13
|
variant?: 'default' | 'subtitle' | 'description';
|
|
14
|
-
|
|
14
|
+
density?: Density;
|
|
15
15
|
truncate?: boolean;
|
|
16
|
+
padding?: boolean;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
const cardRoot: ComponentFunction<CardStyleProps> = ({ border, fullWidth }, ...etc) =>
|
|
19
20
|
mx(
|
|
20
|
-
'dx-card
|
|
21
|
+
'dx-card dx-card-min-width dx-card-max-width min-h-(--dx-rail-item) group/card relative overflow-hidden',
|
|
21
22
|
border &&
|
|
22
23
|
'bg-card-surface border border-separator dark:border-subdued-separator rounded-xs dx-focus-ring-group-y-indicator',
|
|
23
24
|
fullWidth && 'max-w-none!',
|
|
24
25
|
...etc,
|
|
25
26
|
);
|
|
26
27
|
|
|
27
|
-
const cardToolbar: ComponentFunction<CardStyleProps> = (
|
|
28
|
+
const cardToolbar: ComponentFunction<CardStyleProps> = (_, ...etc) =>
|
|
28
29
|
mx(
|
|
29
|
-
'dx-card__toolbar dx-density-fine bg-transparent col-span-3 !
|
|
30
|
-
coarse && 'grid-cols-[var(--dx-l0-avatar-size)_minmax(0,1fr)_var(--dx-rail-item)]',
|
|
30
|
+
'dx-card__toolbar dx-density-fine bg-transparent p-0! gap-0! col-span-3 grid! grid-cols-subgrid! [contain:none]',
|
|
31
31
|
...etc,
|
|
32
32
|
);
|
|
33
33
|
|
|
34
34
|
const cardTitle: ComponentFunction<CardStyleProps> = (_props, ...etc) => mx('dx-card__title grow truncate', ...etc);
|
|
35
35
|
|
|
36
36
|
const cardContent: ComponentFunction<CardStyleProps> = (_props, ...etc) =>
|
|
37
|
-
mx('dx-card__content contents
|
|
37
|
+
mx('dx-card__content contents pb-1 last:pb-0', ...etc);
|
|
38
38
|
|
|
39
39
|
const cardHeading: ComponentFunction<CardStyleProps> = ({ variant = 'default' }, ...etc) =>
|
|
40
40
|
mx(
|
|
@@ -46,9 +46,9 @@ const cardHeading: ComponentFunction<CardStyleProps> = ({ variant = 'default' },
|
|
|
46
46
|
|
|
47
47
|
const cardText: ComponentFunction<CardStyleProps> = ({ variant = 'default', truncate: _truncate }, ...etc) =>
|
|
48
48
|
mx(
|
|
49
|
-
'dx-card__text
|
|
49
|
+
'dx-card__text items-center overflow-hidden',
|
|
50
50
|
variant === 'default' && 'py-1',
|
|
51
|
-
variant === 'description' && 'py-1.5',
|
|
51
|
+
variant === 'description' && 'py-1.5 text-description',
|
|
52
52
|
...etc,
|
|
53
53
|
);
|
|
54
54
|
|
|
@@ -73,14 +73,22 @@ const cardLink: ComponentFunction<CardStyleProps> = (_props, ...etc) =>
|
|
|
73
73
|
const cardLinkLabel: ComponentFunction<CardStyleProps> = (_props, ...etc) =>
|
|
74
74
|
mx('dx-card__link-label min-w-0 flex-1 truncate', ...etc);
|
|
75
75
|
|
|
76
|
-
const
|
|
77
|
-
mx('dx-
|
|
76
|
+
const cardRow: ComponentFunction<CardStyleProps> = (_, ...etc) =>
|
|
77
|
+
mx('dx-card__row col-span-3 grid grid-cols-subgrid', ...etc);
|
|
78
|
+
|
|
79
|
+
const cardIconBlock: ComponentFunction<CardStyleProps> = ({ padding }, ...etc) =>
|
|
80
|
+
mx(
|
|
81
|
+
'dx-card__icon-block grid h-[var(--dx-rail-item)] w-[var(--dx-rail-item)] place-items-center',
|
|
82
|
+
padding && '[&>*]:p-1',
|
|
83
|
+
...etc,
|
|
84
|
+
);
|
|
78
85
|
|
|
79
86
|
export const cardTheme: Theme<CardStyleProps> = {
|
|
80
87
|
root: cardRoot,
|
|
81
88
|
toolbar: cardToolbar,
|
|
82
89
|
title: cardTitle,
|
|
83
90
|
content: cardContent,
|
|
91
|
+
row: cardRow,
|
|
84
92
|
heading: cardHeading,
|
|
85
93
|
text: cardText,
|
|
86
94
|
'text-span': cardTextSpan,
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { type ComponentFunction, type Elevation, type Theme } from '@dxos/ui-types';
|
|
6
6
|
|
|
7
7
|
import { mx } from '../../util';
|
|
8
|
+
import { withColumn } from '../primitives/column';
|
|
8
9
|
|
|
9
10
|
export type DialogSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
10
11
|
|
|
@@ -35,13 +36,13 @@ export const dialogContent: ComponentFunction<DialogStyleProps> = ({ inOverlayLa
|
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
export const dialogHeader: ComponentFunction<DialogStyleProps> = (_props, ...etc) =>
|
|
38
|
-
mx('dx-dialog__header flex pb-4 items-center justify-between', ...etc);
|
|
39
|
+
mx('dx-dialog__header flex pb-4 items-center justify-between', withColumn.center(), ...etc);
|
|
39
40
|
|
|
40
41
|
export const dialogBody: ComponentFunction<DialogStyleProps> = (_props, ...etc) =>
|
|
41
|
-
mx('dx-dialog__body
|
|
42
|
+
mx('dx-dialog__body dx-expander', withColumn.propagate(), ...etc);
|
|
42
43
|
|
|
43
44
|
export const dialogActionBar: ComponentFunction<DialogStyleProps> = (_props, ...etc) =>
|
|
44
|
-
mx('dx-dialog__actionbar flex items-center pt-4 gap-2 dx-density-coarse', ...etc);
|
|
45
|
+
mx('dx-dialog__actionbar flex items-center pt-4 gap-2 dx-density-coarse', withColumn.center(), ...etc);
|
|
45
46
|
|
|
46
47
|
export const dialogTitle: ComponentFunction<DialogStyleProps> = ({ srOnly }, ...etc) =>
|
|
47
48
|
mx('dx-dialog__title', srOnly && 'sr-only', ...etc);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type ComponentFunction, type Theme } from '@dxos/ui-types';
|
|
6
|
+
|
|
7
|
+
import { mx } from '../../util';
|
|
8
|
+
|
|
9
|
+
export type FocusStyleProps = {
|
|
10
|
+
border?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Focus ring styles shared by Focus.Group and Focus.Item.
|
|
15
|
+
* Uses a `::after` pseudo-element overlay so the ring paints above child content
|
|
16
|
+
* (inset box-shadow alone is obscured by children with backgrounds).
|
|
17
|
+
* The pseudo-element is `pointer-events-none` and absolutely positioned over the element.
|
|
18
|
+
* When `border` is true, a subdued CSS border is always visible (e.g., for grid cell edges).
|
|
19
|
+
*/
|
|
20
|
+
const focusRing: ComponentFunction<FocusStyleProps> = ({ border }, ...etc) =>
|
|
21
|
+
mx(
|
|
22
|
+
'dx-ring-pseudo outline-hidden',
|
|
23
|
+
'focus:after:ring-neutral-focus-indicator',
|
|
24
|
+
'data-[focus-state=active]:after:ring-neutral-focus-indicator',
|
|
25
|
+
'data-[focus-state=error]:after:ring-rose-500',
|
|
26
|
+
border && 'border border-separator',
|
|
27
|
+
...etc,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export const focusTheme: Theme<FocusStyleProps> = {
|
|
31
|
+
group: focusRing,
|
|
32
|
+
item: focusRing,
|
|
33
|
+
};
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
import type { ComponentFunction, Theme } from '@dxos/ui-types';
|
|
6
6
|
|
|
7
7
|
import { mx } from '../../util';
|
|
8
|
-
|
|
9
8
|
import { type ButtonStyleProps } from './button';
|
|
10
9
|
|
|
11
|
-
export type IconButtonStyleProps = ButtonStyleProps & {
|
|
10
|
+
export type IconButtonStyleProps = ButtonStyleProps & {
|
|
11
|
+
iconOnly?: boolean;
|
|
12
|
+
square?: boolean;
|
|
13
|
+
};
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return mx('gap-2', iconOnly && 'p-icon-button-padding min-h-0', ...etc);
|
|
15
|
+
export const iconButtonRoot: ComponentFunction<IconButtonStyleProps> = ({ iconOnly, square }, ...etc) => {
|
|
16
|
+
return mx('px-1.5', !iconOnly && 'gap-2', square && 'aspect-square', ...etc);
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
export const iconButtonTheme: Theme<IconButtonStyleProps> = {
|
|
@@ -4,15 +4,24 @@
|
|
|
4
4
|
|
|
5
5
|
import { type ComponentFunction, type Size, type Theme } from '@dxos/ui-types';
|
|
6
6
|
|
|
7
|
-
import { getSize } from '../../
|
|
8
|
-
import { mx } from '../../util';
|
|
7
|
+
import { getSize, mx } from '../../util';
|
|
9
8
|
|
|
10
9
|
export type IconStyleProps = {
|
|
11
10
|
size?: Size;
|
|
12
11
|
};
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Size can be specified directly, or inherited from a container (e.g., toolbar).
|
|
15
|
+
*/
|
|
16
|
+
export const iconRoot: ComponentFunction<IconStyleProps> = ({ size }, etc) => {
|
|
17
|
+
return mx(
|
|
18
|
+
'shrink-0 text-[var(--icons-color,currentColor)]',
|
|
19
|
+
size
|
|
20
|
+
? getSize(size)
|
|
21
|
+
: '[width:var(--icon-size,var(--dx-default-icons-size))] [height:var(--icon-size,var(--dx-default-icons-size))]',
|
|
22
|
+
etc,
|
|
23
|
+
);
|
|
24
|
+
};
|
|
16
25
|
|
|
17
26
|
export const iconTheme: Theme<IconStyleProps> = {
|
|
18
27
|
root: iconRoot,
|