@dxos/ui-theme 0.0.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.
Files changed (97) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +25 -0
  3. package/package.json +80 -0
  4. package/src/Tokens.stories.tsx +88 -0
  5. package/src/config/index.ts +6 -0
  6. package/src/config/tailwind.ts +250 -0
  7. package/src/config/tokens/alias-colors.ts +39 -0
  8. package/src/config/tokens/index.ts +92 -0
  9. package/src/config/tokens/lengths.ts +97 -0
  10. package/src/config/tokens/physical-colors.ts +125 -0
  11. package/src/config/tokens/semantic-colors.ts +27 -0
  12. package/src/config/tokens/sememes-calls.ts +17 -0
  13. package/src/config/tokens/sememes-codemirror.ts +50 -0
  14. package/src/config/tokens/sememes-hue.ts +54 -0
  15. package/src/config/tokens/sememes-sheet.ts +62 -0
  16. package/src/config/tokens/sememes-system.ts +302 -0
  17. package/src/config/tokens/sizes.ts +7 -0
  18. package/src/config/tokens/types.ts +9 -0
  19. package/src/docs/theme.drawio.svg +635 -0
  20. package/src/index.ts +19 -0
  21. package/src/plugins/esbuild-plugin.ts +65 -0
  22. package/src/plugins/plugin.ts +130 -0
  23. package/src/plugins/resolveContent.ts +51 -0
  24. package/src/styles/components/README.md +6 -0
  25. package/src/styles/components/anchored-overflow.ts +20 -0
  26. package/src/styles/components/avatar.ts +96 -0
  27. package/src/styles/components/breadcrumb.ts +29 -0
  28. package/src/styles/components/button.ts +48 -0
  29. package/src/styles/components/dialog.ts +36 -0
  30. package/src/styles/components/icon-button.ts +20 -0
  31. package/src/styles/components/icon.ts +19 -0
  32. package/src/styles/components/index.ts +27 -0
  33. package/src/styles/components/input.ts +177 -0
  34. package/src/styles/components/link.ts +26 -0
  35. package/src/styles/components/list.ts +46 -0
  36. package/src/styles/components/main.ts +36 -0
  37. package/src/styles/components/menu.ts +60 -0
  38. package/src/styles/components/message.ts +36 -0
  39. package/src/styles/components/popover.ts +40 -0
  40. package/src/styles/components/scroll-area.ts +43 -0
  41. package/src/styles/components/select.ts +60 -0
  42. package/src/styles/components/separator.ts +24 -0
  43. package/src/styles/components/status.ts +32 -0
  44. package/src/styles/components/tag.ts +23 -0
  45. package/src/styles/components/toast.ts +55 -0
  46. package/src/styles/components/toolbar.ts +29 -0
  47. package/src/styles/components/tooltip.ts +29 -0
  48. package/src/styles/components/treegrid.ts +37 -0
  49. package/src/styles/fragments/density.ts +17 -0
  50. package/src/styles/fragments/dimension.ts +8 -0
  51. package/src/styles/fragments/disabled.ts +6 -0
  52. package/src/styles/fragments/elevation.ts +29 -0
  53. package/src/styles/fragments/focus.ts +16 -0
  54. package/src/styles/fragments/group.ts +12 -0
  55. package/src/styles/fragments/hover.ts +25 -0
  56. package/src/styles/fragments/index.ts +20 -0
  57. package/src/styles/fragments/layout.ts +7 -0
  58. package/src/styles/fragments/motion.ts +6 -0
  59. package/src/styles/fragments/ornament.ts +10 -0
  60. package/src/styles/fragments/selected.ts +45 -0
  61. package/src/styles/fragments/shimmer.ts +9 -0
  62. package/src/styles/fragments/size.ts +117 -0
  63. package/src/styles/fragments/surface.ts +29 -0
  64. package/src/styles/fragments/text.ts +12 -0
  65. package/src/styles/fragments/valence.ts +46 -0
  66. package/src/styles/index.ts +7 -0
  67. package/src/styles/layers/README.md +15 -0
  68. package/src/styles/layers/anchored-overflow.css +9 -0
  69. package/src/styles/layers/animation.css +17 -0
  70. package/src/styles/layers/attention.css +8 -0
  71. package/src/styles/layers/base.css +25 -0
  72. package/src/styles/layers/button.css +76 -0
  73. package/src/styles/layers/can-scroll.css +26 -0
  74. package/src/styles/layers/checkbox.css +50 -0
  75. package/src/styles/layers/dialog.css +42 -0
  76. package/src/styles/layers/drag-preview.css +18 -0
  77. package/src/styles/layers/focus-ring.css +224 -0
  78. package/src/styles/layers/hues.css +110 -0
  79. package/src/styles/layers/index.css +26 -0
  80. package/src/styles/layers/main.css +160 -0
  81. package/src/styles/layers/native.css +20 -0
  82. package/src/styles/layers/positioning.css +23 -0
  83. package/src/styles/layers/size.css +397 -0
  84. package/src/styles/layers/surfaces.css +31 -0
  85. package/src/styles/layers/tag.css +132 -0
  86. package/src/styles/layers/tldraw.css +91 -0
  87. package/src/styles/layers/tokens.css +45 -0
  88. package/src/styles/layers/typography.css +157 -0
  89. package/src/styles/theme.ts +69 -0
  90. package/src/tailwind.ts +5 -0
  91. package/src/theme.css +9 -0
  92. package/src/types.ts +7 -0
  93. package/src/typings.d.ts +8 -0
  94. package/src/util/hash-styles.ts +168 -0
  95. package/src/util/index.ts +6 -0
  96. package/src/util/mx.ts +51 -0
  97. package/src/util/withLogical.ts +114 -0
package/src/index.ts ADDED
@@ -0,0 +1,19 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import { type TailwindConfig, tailwindConfig } from './config';
6
+
7
+ export { cardMinInlineSize, cardMaxInlineSize, hues, userDefaultTokenSet } from './config';
8
+ export * from './styles';
9
+ export * from './types';
10
+ export * from './util';
11
+
12
+ const tokens: TailwindConfig['theme'] = tailwindConfig({}).theme;
13
+
14
+ export { tokens };
15
+
16
+ /**
17
+ * Translation namespace for OS-level translations.
18
+ */
19
+ export const osTranslations = 'dxos.org/i18n/os';
@@ -0,0 +1,65 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import { cp, mkdir } from 'node:fs/promises';
6
+ import { basename, join, relative, resolve } from 'node:path';
7
+
8
+ import autoprefixer from 'autoprefixer';
9
+ import type { Plugin } from 'esbuild';
10
+ import stylePlugin from 'esbuild-style-plugin';
11
+ import tailwindcss from 'tailwindcss';
12
+ import type { ThemeConfig } from 'tailwindcss/types/config';
13
+
14
+ import { tailwindConfig } from '../config';
15
+
16
+ import { resolveKnownPeers } from './resolveContent';
17
+
18
+ export const ThemePlugins = async (options: {
19
+ content: string[];
20
+ root?: string;
21
+ outdir: string;
22
+ extensions?: Partial<ThemeConfig>[];
23
+ }): Promise<Plugin[]> => {
24
+ const resolvedContent = options.root ? await resolveKnownPeers(options.content, options.root) : options.content;
25
+ return [
26
+ // TODO(thure): This really shouldn’t be this way, but after hours of searching for a reasonable way to do this I came up empty. The prior art I found was mainly this thread, though it’s only tangentially related: https://github.com/evanw/esbuild/issues/800#issuecomment-786151076
27
+ {
28
+ name: 'esbuild-plugin-dxos-ui-theme-resolvers',
29
+ setup: async (build) => {
30
+ const fontsDir = join(options.outdir, 'node_modules/@dxos/ui-theme/fonts');
31
+ try {
32
+ await mkdir(fontsDir);
33
+ } catch {}
34
+ build.onResolve({ filter: /\.woff2$/ }, async (args) => {
35
+ const depPath = resolve(args.resolveDir, args.path);
36
+ const destPath = join(fontsDir, basename(args.path));
37
+ try {
38
+ await cp(depPath, destPath);
39
+ } catch {}
40
+ return {
41
+ path: `./${relative(options.outdir, join('fonts', basename(args.path)))}`,
42
+ external: true,
43
+ };
44
+ });
45
+ },
46
+ },
47
+ // TODO(thure): theme.css must be part of entryPoints in order to be processed with `stylePlugin`, but this should not be necessary. ESBuild would not load theme.css using stylePlugin if referenced within index.ts(x) as with the Vite plugin.
48
+ // TODO(thure): Note also that because it is an entryPoint, the developer has to reference the built theme.css from `index.html`, which is inflexible and possibly inconvenient.
49
+ // TODO(zhenyasav): autoprefixer version misalignment with esbuild-style-plugin requires the `as any`.
50
+ stylePlugin({
51
+ postcss: {
52
+ plugins: [
53
+ tailwindcss(
54
+ tailwindConfig({
55
+ env: process.env.NODE_ENV,
56
+ content: resolvedContent,
57
+ extensions: options.extensions,
58
+ }),
59
+ ),
60
+ autoprefixer as any,
61
+ ],
62
+ },
63
+ }),
64
+ ];
65
+ };
@@ -0,0 +1,130 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ /* eslint-disable no-console */
6
+
7
+ import { readFile, writeFile } from 'node:fs/promises';
8
+ import { resolve } from 'node:path';
9
+
10
+ import chTokens from '@ch-ui/tokens/postcss';
11
+ import autoprefixer from 'autoprefixer';
12
+ import postcss from 'postcss';
13
+ import postcssImport from 'postcss-import';
14
+ import tailwindcss from 'tailwindcss';
15
+ import nesting from 'tailwindcss/nesting/index.js';
16
+ import { type ThemeConfig } from 'tailwindcss/types/config';
17
+ import { type Plugin, type UserConfig } from 'vite';
18
+
19
+ import { tailwindConfig, tokenSet } from '../config';
20
+
21
+ import { resolveKnownPeers } from './resolveContent';
22
+
23
+ export type ThemePluginOptions = {
24
+ jit?: boolean;
25
+ cssPath?: string;
26
+ srcCssPath?: string;
27
+ virtualFileId?: string;
28
+ content?: string[];
29
+ root?: string;
30
+ verbose?: boolean;
31
+ extensions?: Partial<ThemeConfig>[];
32
+ };
33
+
34
+ let environment!: string;
35
+
36
+ /**
37
+ * Configures PostCSS pipeline for theme.css processing.
38
+ * @param environment - The current environment (development/production).
39
+ * @param config - Theme plugin configuration options.
40
+ * @returns Array of PostCSS plugins.
41
+ */
42
+ const createPostCSSPipeline = (environment: string, config: ThemePluginOptions): postcss.Transformer[] => [
43
+ // Handles @import statements in CSS.
44
+ postcssImport(),
45
+ // Processes CSS nesting syntax.
46
+ nesting,
47
+ // Processes custom design tokens.
48
+ chTokens({ config: () => tokenSet }),
49
+ // Processes Tailwind directives and utilities.
50
+ tailwindcss(
51
+ tailwindConfig({
52
+ env: environment,
53
+ content: config.content,
54
+ extensions: config.extensions,
55
+ }),
56
+ ),
57
+ // Adds vendor prefixes.
58
+ autoprefixer as any,
59
+ ];
60
+
61
+ /**
62
+ * Vite plugin to configure theme.
63
+ */
64
+ export const ThemePlugin = (options: ThemePluginOptions): Plugin => {
65
+ const config: ThemePluginOptions = {
66
+ jit: true,
67
+ cssPath: resolve(import.meta.dirname, '../theme.css'),
68
+ srcCssPath: resolve(import.meta.dirname, '../../../../src/theme.css'),
69
+ virtualFileId: '@dxos-theme',
70
+ ...options,
71
+ };
72
+
73
+ if (process.env.DEBUG) {
74
+ console.log('ThemePlugin config:\n', JSON.stringify(config, null, 2));
75
+ }
76
+
77
+ return {
78
+ name: 'vite-plugin-dxos-ui-theme',
79
+ config: async ({ root }, env): Promise<UserConfig> => {
80
+ environment = env.mode;
81
+ const content = root ? await resolveKnownPeers(config.content ?? [], root) : config.content;
82
+ if (options.verbose) {
83
+ console.log('content', content);
84
+ }
85
+
86
+ return {
87
+ css: {
88
+ postcss: {
89
+ plugins: createPostCSSPipeline(environment, config),
90
+ },
91
+ },
92
+ };
93
+ },
94
+ resolveId: (id) => {
95
+ if (id === config.virtualFileId) {
96
+ return config.cssPath;
97
+ }
98
+ },
99
+ handleHotUpdate: async ({ file, server }) => {
100
+ // NOTE(ZaymonFC): Changes to *any* CSS file triggers this step. We might want to refine this.
101
+ // Ignore the output file to prevent infinite loops.
102
+ if (file.endsWith('.css') && file !== config.cssPath) {
103
+ try {
104
+ // Get reference to the theme virtual module.
105
+ const module = server.moduleGraph.getModuleById(config.cssPath!);
106
+ if (module) {
107
+ // Read the source theme file that imports all other CSS files.
108
+ const css = await readFile(config.srcCssPath!, 'utf8');
109
+ const processor = postcss(createPostCSSPipeline(environment, config));
110
+ console.log('[theme-plugin] Reprocessing CSS with PostCSS.');
111
+ const result = await processor.process(css, {
112
+ from: config.srcCssPath,
113
+ to: config.cssPath,
114
+ });
115
+
116
+ if (result.css) {
117
+ await writeFile(config.cssPath!, result.css);
118
+ // Return the module to trigger HMR update.
119
+ return [];
120
+ }
121
+ }
122
+ } catch (err) {
123
+ console.error('[theme-plugin] Error:', err);
124
+ }
125
+ }
126
+ },
127
+ };
128
+ };
129
+
130
+ ThemePlugin.foo = 'bar';
@@ -0,0 +1,51 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { promisify } from 'node:util';
6
+
7
+ import Glob from 'glob';
8
+
9
+ const glob = promisify(Glob.glob);
10
+
11
+ // TODO(burdon): Comment.
12
+ const knownIndirectPeers = [
13
+ '@dxos/devtools',
14
+ '@dxos/react-*',
15
+ '@dxos/react-ui-*',
16
+ // TODO(thure): glob v7 runs out of memory if we do a `**` search, and this is (hopefully) the only L3 content package; find a better solution.
17
+ '@dxos/react-ui-table/node_modules/@dxos/react-ui-searchlist',
18
+ '@dxos/shell',
19
+ ];
20
+
21
+ const knownDirectPeers = ['@dxos/plugin-*', ...knownIndirectPeers];
22
+
23
+ const packageNamePattern = /.*node_modules\/(.+?)$/;
24
+ const packageName = (path: string) => path.match(packageNamePattern)?.[1];
25
+
26
+ const flatten = (acc: string[], group: string[]) => [...acc, ...group];
27
+ const dedupe = (acc: Record<string, string>, path: string) => {
28
+ const name = packageName(path);
29
+ if (name && !acc[name]) {
30
+ acc[name] = path;
31
+ }
32
+
33
+ return acc;
34
+ };
35
+
36
+ export const resolveKnownPeers = async (content: string[], cwd: string): Promise<string[]> => {
37
+ const globOptions = { cwd, absolute: true };
38
+
39
+ const directPeers = await Promise.all(knownDirectPeers.map((peer) => glob(`./node_modules/${peer}`, globOptions)));
40
+
41
+ // NOTE(thure): With glob v7, JS runs out of memory if `**` is used, so this limits the search to @dxos/plugin-*/node_modules
42
+ const indirectPeers = await Promise.all(
43
+ knownIndirectPeers.map((peer) => glob(`./node_modules/@dxos/plugin-*/node_modules/${peer}`, globOptions)),
44
+ );
45
+
46
+ const knownPeerContent = Object.values(
47
+ indirectPeers.reduce(flatten, []).reduce(dedupe, directPeers.reduce(flatten, []).reduce(dedupe, {})),
48
+ ).map((value) => `${value}/dist/lib/**/*.mjs`);
49
+
50
+ return [...content, ...knownPeerContent];
51
+ };
@@ -0,0 +1,6 @@
1
+ # react-ui-theme
2
+
3
+ References:
4
+ - https://tailwindcss-radix.vercel.app
5
+ - https://github.com/ecklf/tailwindcss-radix
6
+ - https://www.radix-ui.com/primitives/docs/components
@@ -0,0 +1,20 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type ComponentFunction, type Theme } from '@dxos/ui-types';
6
+
7
+ import { mx } from '../../util';
8
+
9
+ export type AnchoredOverflowStyleProps = {};
10
+
11
+ export const anchoredOverflowRoot: ComponentFunction<AnchoredOverflowStyleProps> = (_props, ...etc) =>
12
+ mx('overflow-anchored overflow-auto', ...etc);
13
+
14
+ export const anchoredOverflowAnchor: ComponentFunction<AnchoredOverflowStyleProps> = (_props, ...etc) =>
15
+ mx('overflow-anchor is-px bs-px', ...etc);
16
+
17
+ export const anchoredOverflowTheme: Theme<AnchoredOverflowStyleProps> = {
18
+ root: anchoredOverflowRoot,
19
+ anchor: anchoredOverflowAnchor,
20
+ };
@@ -0,0 +1,96 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type ComponentFunction, type Size, type Theme } from '@dxos/ui-types';
6
+
7
+ import { mx } from '../../util';
8
+ import { descriptionText, getSize, getSizeHeight } from '../fragments';
9
+
10
+ export type AvatarStyleProps = Partial<{
11
+ size: Size;
12
+ srOnly: boolean;
13
+ status: 'active' | 'inactive' | 'current' | 'error' | 'warning' | 'internal';
14
+ animation: 'pulse' | 'none';
15
+ variant: 'circle' | 'square';
16
+ inGroup: boolean;
17
+ }>;
18
+
19
+ export const avatarRoot: ComponentFunction<AvatarStyleProps> = ({ size = 10, inGroup }, ...etc) =>
20
+ mx(
21
+ 'relative inline-flex shrink-0',
22
+ getSize(size),
23
+ inGroup && (size === 'px' || size <= 3 ? '-mie-1' : '-mie-2'),
24
+ ...etc,
25
+ );
26
+
27
+ export const avatarLabel: ComponentFunction<AvatarStyleProps> = ({ srOnly }, ...etc) => mx(srOnly && 'sr-only', ...etc);
28
+
29
+ export const avatarDescription: ComponentFunction<AvatarStyleProps> = ({ srOnly }, ...etc) =>
30
+ mx(descriptionText, srOnly && 'sr-only', ...etc);
31
+
32
+ export const avatarFrame: ComponentFunction<AvatarStyleProps> = ({ variant }, ...etc) =>
33
+ mx('is-full bs-full bg-[--surface-bg]', variant === 'circle' ? 'rounded-full' : 'rounded', ...etc);
34
+
35
+ export const avatarStatusIcon: ComponentFunction<AvatarStyleProps> = ({ status, size = 3 }, ...etc) =>
36
+ mx(
37
+ 'absolute block-end-0 inline-end-0',
38
+ getSize(size),
39
+ status === 'inactive'
40
+ ? 'text-amber-350 dark:text-amber-250'
41
+ : status === 'active'
42
+ ? 'text-emerald-350 dark:text-emerald-250'
43
+ : 'text-neutral-350 dark:text-neutral-250',
44
+ ...etc,
45
+ );
46
+
47
+ export const avatarRing: ComponentFunction<AvatarStyleProps> = ({ status, variant, animation }, ...etc) =>
48
+ mx(
49
+ 'absolute inset-0 border-2',
50
+ variant === 'circle' ? 'rounded-full' : 'rounded',
51
+ status === 'current'
52
+ ? 'border-primary-400 dark:border-primary-500'
53
+ : status === 'active'
54
+ ? 'border-emerald-400 dark:border-emerald-400'
55
+ : status === 'error'
56
+ ? 'border-rose-400 dark:border-rose-500'
57
+ : status === 'warning'
58
+ ? 'border-amber-400 dark:border-amber-500'
59
+ : status === 'inactive'
60
+ ? 'border-separator'
61
+ : status === 'internal'
62
+ ? 'border-fuchsia-600'
63
+ : 'border-[color:var(--surface-bg)]',
64
+ animation === 'pulse' ? 'animate-halo-pulse' : '',
65
+ ...etc,
66
+ );
67
+
68
+ export const avatarFallbackText: ComponentFunction<AvatarStyleProps> = (_props, ...etc) => mx('fill-white', ...etc);
69
+
70
+ export const avatarGroup: ComponentFunction<AvatarStyleProps> = (_props, ...etc) =>
71
+ mx('inline-flex items-center', ...etc);
72
+
73
+ export const avatarGroupLabel: ComponentFunction<AvatarStyleProps> = ({ size, srOnly }, ...etc) =>
74
+ mx(
75
+ srOnly
76
+ ? 'sr-only'
77
+ : 'rounded-full truncate text-sm leading-none plb-1 pli-2 relative z-[1] flex items-center justify-center',
78
+ size && getSizeHeight(size),
79
+ ...etc,
80
+ );
81
+
82
+ export const avatarGroupDescription: ComponentFunction<AvatarStyleProps> = ({ srOnly }, ...etc) =>
83
+ mx(srOnly ? 'sr-only' : descriptionText, ...etc);
84
+
85
+ export const avatarTheme: Theme<AvatarStyleProps> = {
86
+ root: avatarRoot,
87
+ label: avatarLabel,
88
+ description: avatarDescription,
89
+ statusIcon: avatarStatusIcon,
90
+ frame: avatarFrame,
91
+ ring: avatarRing,
92
+ fallbackText: avatarFallbackText,
93
+ group: avatarGroup,
94
+ groupLabel: avatarGroupLabel,
95
+ groupDescription: avatarGroupDescription,
96
+ };
@@ -0,0 +1,29 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type ComponentFunction, type Theme } from '@dxos/ui-types';
6
+
7
+ import { mx } from '../../util';
8
+
9
+ export type breadcrumbStyleProps = {};
10
+
11
+ export const breadcrumbRoot: ComponentFunction<breadcrumbStyleProps> = (_props, ...etc) =>
12
+ mx('shrink-0 flex items-center', ...etc);
13
+
14
+ export const breadcrumbList: ComponentFunction<breadcrumbStyleProps> = (_props, ...etc) => mx('contents', ...etc);
15
+
16
+ export const breadcrumbListItem: ComponentFunction<breadcrumbStyleProps> = (_props, ...etc) => mx('contents', ...etc);
17
+
18
+ export const breadcrumbCurrent: ComponentFunction<breadcrumbStyleProps> = (_props, ...etc) => mx(...etc);
19
+
20
+ export const breadcrumbSeparator: ComponentFunction<breadcrumbStyleProps> = (_props, ...etc) =>
21
+ mx('opacity-50', ...etc);
22
+
23
+ export const breadcrumbTheme: Theme<breadcrumbStyleProps> = {
24
+ root: breadcrumbRoot,
25
+ list: breadcrumbList,
26
+ listItem: breadcrumbListItem,
27
+ current: breadcrumbCurrent,
28
+ separator: breadcrumbSeparator,
29
+ };
@@ -0,0 +1,48 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import type { ComponentFunction, Density, Elevation, Theme } from '@dxos/ui-types';
6
+
7
+ import { mx } from '../../util';
8
+ import { ghostHover } from '../fragments';
9
+
10
+ export const primaryButtonColors =
11
+ 'text-accentSurfaceText bg-accentSurface hover:bg-accentSurfaceHover aria-pressed:bg-primary-500 dark:aria-pressed:bg-primary-500 data-[state=open]:bg-primary-500 dark:data-[state=open]:bg-primary-500 aria-checked:bg-primary-500 dark:aria-checked:bg-primary-500 aria-checked:text-primary-100';
12
+
13
+ export const staticDefaultButtonColors = 'bg-inputSurface';
14
+
15
+ export const defaultButtonColors = mx(
16
+ staticDefaultButtonColors,
17
+ 'data-[state=open]:bg-inputSurface aria-pressed:text-accentText aria-pressed:bg-baseSurface aria-checked:text-accentText aria-checked:bg-baseSurface',
18
+ );
19
+
20
+ export const ghostButtonColors = mx(
21
+ ghostHover,
22
+ 'hover:text-inherit data-[state=open]:bg-inputSurface aria-pressed:text-accentText aria-pressed:bg-baseSurface aria-checked:text-accentText aria-checked:bg-baseSurface',
23
+ );
24
+
25
+ export type ButtonStyleProps = Partial<{
26
+ inGroup?: boolean;
27
+ textWrap?: boolean;
28
+ density: Density;
29
+ elevation: Elevation;
30
+ disabled: boolean;
31
+ variant: 'default' | 'primary' | 'ghost' | 'outline';
32
+ }>;
33
+
34
+ export const buttonRoot: ComponentFunction<ButtonStyleProps> = (_props, ...etc) => {
35
+ return mx('dx-button dx-focus-ring group max-is-full [&_span]:truncate', ...etc);
36
+ };
37
+
38
+ export const buttonGroup: ComponentFunction<{ elevation?: Elevation }> = (_props, ...etc) => {
39
+ return mx(
40
+ 'inline-flex rounded-sm [&>:first-child]:rounded-is-sm [&>:last-child]:rounded-ie-sm [&>button]:relative',
41
+ ...etc,
42
+ );
43
+ };
44
+
45
+ export const buttonTheme: Theme<ButtonStyleProps> = {
46
+ root: buttonRoot,
47
+ group: buttonGroup,
48
+ };
@@ -0,0 +1,36 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type ComponentFunction, type Elevation, type Theme } from '@dxos/ui-types';
6
+
7
+ import { mx } from '../../util';
8
+ import { descriptionText } from '../fragments';
9
+
10
+ export type DialogStyleProps = {
11
+ srOnly?: boolean;
12
+ inOverlayLayout?: boolean;
13
+ elevation?: Elevation;
14
+ };
15
+
16
+ export const dialogOverlay: ComponentFunction<DialogStyleProps> = (_props, ...etc) => mx('dx-dialog__overlay', ...etc);
17
+
18
+ export const dialogContent: ComponentFunction<DialogStyleProps> = ({ inOverlayLayout }, ...etc) =>
19
+ mx(
20
+ '@container dx-dialog__content dx-focus-ring modal-surface density-coarse',
21
+ !inOverlayLayout && 'fixed z-50 top-[50%] left-[50%] -translate-x-[50%] -translate-y-[50%]',
22
+ ...etc,
23
+ );
24
+
25
+ export const dialogTitle: ComponentFunction<DialogStyleProps> = ({ srOnly }, ...etc) =>
26
+ mx('dx-dialog__title', srOnly && 'sr-only', ...etc);
27
+
28
+ export const dialogDescription: ComponentFunction<DialogStyleProps> = ({ srOnly }, ...etc) =>
29
+ mx('dx-dialog__description', descriptionText, srOnly && 'sr-only', ...etc);
30
+
31
+ export const dialogTheme: Theme<DialogStyleProps> = {
32
+ overlay: dialogOverlay,
33
+ content: dialogContent,
34
+ title: dialogTitle,
35
+ description: dialogDescription,
36
+ };
@@ -0,0 +1,20 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import type { ComponentFunction, Theme } from '@dxos/ui-types';
6
+
7
+ import { mx } from '../../util';
8
+
9
+ import { type ButtonStyleProps } from './button';
10
+
11
+ export type IconButtonStyleProps = ButtonStyleProps & { iconOnly?: boolean };
12
+
13
+ // TODO(burdon): Gap/font size should depend on density.
14
+ export const iconButtonRoot: ComponentFunction<IconButtonStyleProps> = ({ iconOnly }, ...etc) => {
15
+ return mx('gap-2', iconOnly && 'p-iconButtonPadding min-bs-0', ...etc);
16
+ };
17
+
18
+ export const iconButtonTheme: Theme<IconButtonStyleProps> = {
19
+ root: iconButtonRoot,
20
+ };
@@ -0,0 +1,19 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type ComponentFunction, type Size, type Theme } from '@dxos/ui-types';
6
+
7
+ import { mx } from '../../util';
8
+ import { getSize } from '../fragments';
9
+
10
+ export type IconStyleProps = {
11
+ size?: Size;
12
+ };
13
+
14
+ export const iconRoot: ComponentFunction<IconStyleProps> = ({ size }, etc) =>
15
+ mx('shrink-0 bs-[1em] is-[1em] text-[var(--icons-color,currentColor)]', size && getSize(size), etc);
16
+
17
+ export const iconTheme: Theme<IconStyleProps> = {
18
+ root: iconRoot,
19
+ };
@@ -0,0 +1,27 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './anchored-overflow';
6
+ export * from './avatar';
7
+ export * from './breadcrumb';
8
+ export * from './button';
9
+ export * from './dialog';
10
+ export * from './icon';
11
+ export * from './icon-button';
12
+ export * from './input';
13
+ export * from './link';
14
+ export * from './list';
15
+ export * from './main';
16
+ export * from './menu';
17
+ export * from './message';
18
+ export * from './popover';
19
+ export * from './scroll-area';
20
+ export * from './select';
21
+ export * from './separator';
22
+ export * from './status';
23
+ export * from './tag';
24
+ export * from './toast';
25
+ export * from './toolbar';
26
+ export * from './tooltip';
27
+ export * from './treegrid';