@dxos/lit-ui 0.8.4-main.1f223c7 → 0.8.4-main.21d9917

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/package.json CHANGED
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "@dxos/lit-ui",
3
- "version": "0.8.4-main.1f223c7",
3
+ "version": "0.8.4-main.21d9917",
4
4
  "description": "Web Components for DXOS using Lit",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/dxos/dxos"
10
+ },
7
11
  "license": "MIT",
8
12
  "author": "DXOS.org",
9
- "sideEffects": true,
13
+ "sideEffects": [
14
+ "*.css",
15
+ "*.pcss"
16
+ ],
10
17
  "type": "module",
11
18
  "exports": {
12
19
  ".": {
@@ -38,14 +45,14 @@
38
45
  "dist"
39
46
  ],
40
47
  "dependencies": {
41
- "@lit/react": "^1.0.5",
42
- "lit": "^3.2.0",
43
- "@dxos/react-hooks": "0.8.4-main.1f223c7",
44
- "@dxos/react-ui-types": "0.8.4-main.1f223c7",
45
- "@dxos/util": "0.8.4-main.1f223c7"
48
+ "@lit/react": "^1.0.8",
49
+ "lit": "^3.3.1",
50
+ "@dxos/ui-types": "0.8.4-main.21d9917",
51
+ "@dxos/util": "0.8.4-main.21d9917",
52
+ "@dxos/react-hooks": "0.8.4-main.21d9917"
46
53
  },
47
54
  "devDependencies": {
48
- "@dxos/test-utils": "0.8.4-main.1f223c7"
55
+ "@dxos/test-utils": "0.8.4-main.21d9917"
49
56
  },
50
57
  "publishConfig": {
51
58
  "access": "public"
package/src/defs.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- // TODO(thure): I was unable to bring this in from `react-ui-types` because toolbox.ts would not acknowledge
5
+ // TODO(thure): I was unable to bring this in from `ui-types` because toolbox.ts would not acknowledge
6
6
  // `"@dxos/lit-ui": [ "packages/ui/lit-ui/src/index.ts" ]` in tsconfig.paths.json. How is this meant to work? How is it
7
7
  // okay with `react-hooks`?
8
8
  export type Size =
@@ -8,7 +8,7 @@
8
8
  import { LitElement } from 'lit';
9
9
  import { customElement, property } from 'lit/decorators.js';
10
10
 
11
- import { DxAnchorActivate } from '@dxos/react-ui-types';
11
+ import { DxAnchorActivate } from '@dxos/ui-types';
12
12
 
13
13
  @customElement('dx-anchor')
14
14
  export class DxAnchor extends LitElement {
@@ -26,7 +26,7 @@ export class DxAnchor extends LitElement {
26
26
  override connectedCallback (): void {
27
27
  super.connectedCallback();
28
28
  this.tabIndex = 0;
29
- this.classList.add('dx-focus-ring');
29
+ this.classList.add(this.getAttribute('data-visible-focus')==='false' ? 'outline-none' : 'dx-focus-ring');
30
30
  if(this.rootclassname){
31
31
  this.classList.add(this.rootclassname);
32
32
  }
@@ -3,17 +3,19 @@
3
3
  //
4
4
 
5
5
  import '@dxos-theme';
6
-
7
6
  import './dx-avatar.pcss';
7
+
8
8
  import { html } from 'lit';
9
9
 
10
10
  import { type DxAvatarProps } from './dx-avatar';
11
11
 
12
12
  export default {
13
13
  title: 'dx-avatar',
14
- parameters: { layout: 'fullscreen' },
14
+ parameters: {
15
+ layout: 'centered',
16
+ },
15
17
  };
16
18
 
17
- export const Basic = (props: DxAvatarProps) => {
19
+ export const Basic = (_props: DxAvatarProps) => {
18
20
  return html`<dx-avatar hue="teal" fallback="Composer user" icon="/icons.svg#ph--basketball--regular"></dx-avatar>`;
19
21
  };
@@ -20,7 +20,7 @@ dx-avatar {
20
20
  @apply relative inline-flex shrink-0;
21
21
 
22
22
  .dx-avatar__frame {
23
- @apply is-full bs-full bg-[--surface-bg];
23
+ @apply is-full bs-full;
24
24
  }
25
25
 
26
26
  .dx-avatar__frame, .dx-avatar__ring {
@@ -7,7 +7,6 @@ import { customElement, property, state } from 'lit/decorators.js';
7
7
  import { styleMap } from 'lit/directives/style-map.js';
8
8
 
9
9
  import { makeId } from '@dxos/react-hooks';
10
- import { getFirstTwoRenderableChars } from '@dxos/util';
11
10
 
12
11
  import { type Size } from '../defs';
13
12
 
@@ -37,6 +36,7 @@ export type DxAvatarProps = Partial<
37
36
  >
38
37
  >;
39
38
 
39
+ // TODO(burdon): Needs popover.
40
40
  @customElement('dx-avatar')
41
41
  export class DxAvatar extends LitElement {
42
42
  private maskId: string;
@@ -71,7 +71,7 @@ export class DxAvatar extends LitElement {
71
71
  hue: string | undefined = undefined;
72
72
 
73
73
  @property({ type: String })
74
- hueVariant: 'fill' | 'surface' = 'fill';
74
+ hueVariant: 'fill' | 'surface' | 'transparent' = 'fill';
75
75
 
76
76
  @property({ type: String })
77
77
  size: Size = 10;
@@ -113,13 +113,17 @@ export class DxAvatar extends LitElement {
113
113
  const r = sizePx / 2 - ringGap - ringWidth;
114
114
  const isTextOnly = Boolean(this.fallback && /[0-9a-zA-Z]+/.test(this.fallback));
115
115
  const fontScale = (isTextOnly ? 3 : 3.6) * (1 / 1.612);
116
- const bg = this.hue
117
- ? this.hueVariant === 'surface'
118
- ? `var(--dx-${this.hue}Surface)`
119
- : `var(--dx-${this.hue === 'neutral' ? 'inputSurface' : `${this.hue}Fill`})`
120
- : 'var(--surface-bg)';
116
+ const bg =
117
+ this.hueVariant === 'transparent'
118
+ ? 'transparent'
119
+ : this.hue
120
+ ? this.hueVariant === 'surface'
121
+ ? `var(--dx-${this.hue}Surface)`
122
+ : `var(--dx-${this.hue === 'neutral' ? 'inputSurface' : `${this.hue}Fill`})`
123
+ : 'var(--surface-bg)';
121
124
  const fg =
122
125
  this.hue && this.hueVariant === 'surface' ? `var(--dx-${this.hue}SurfaceText)` : 'var(--dx-accentSurfaceText)';
126
+
123
127
  return html`<span
124
128
  role="none"
125
129
  class=${`dx-avatar${this.rootClassName ? ` ${this.rootClassName}` : ''}`}
@@ -139,59 +143,67 @@ export class DxAvatar extends LitElement {
139
143
  ${
140
144
  this.variant === 'circle'
141
145
  ? svg`<circle fill="white" cx="50%" cy="50%" r=${r} />`
142
- : svg`<rect
143
- fill="white"
144
- width=${2 * r}
145
- height=${2 * r}
146
- x=${ringGap + ringWidth}
147
- y=${ringGap + ringWidth}
148
- rx=${rx}
149
- />`
146
+ : svg`
147
+ <rect
148
+ fill="white"
149
+ width=${2 * r}
150
+ height=${2 * r}
151
+ x=${ringGap + ringWidth}
152
+ y=${ringGap + ringWidth}
153
+ rx=${rx}
154
+ />`
150
155
  }
151
156
  </mask>
152
157
  </defs>
153
158
  ${
154
159
  this.variant === 'circle'
155
- ? svg` <circle
156
- cx="50%"
157
- cy="50%"
158
- r=${r}
159
- fill=${bg}
160
- />`
161
- : svg` <rect
162
- fill=${bg}
163
- x=${ringGap + ringWidth}
164
- y=${ringGap + ringWidth}
165
- width=${2 * r}
166
- height=${2 * r}
167
- rx=${rx}
168
- />`
160
+ ? svg`
161
+ <circle
162
+ cx="50%"
163
+ cy="50%"
164
+ r=${r}
165
+ fill=${bg}
166
+ />`
167
+ : svg`
168
+ <rect
169
+ fill=${bg}
170
+ x=${ringGap + ringWidth}
171
+ y=${ringGap + ringWidth}
172
+ width=${2 * r}
173
+ height=${2 * r}
174
+ rx=${rx}
175
+ />`
169
176
  }
170
177
  ${
171
178
  this.icon
172
- ? svg`<use
179
+ ? svg`
180
+ <use
173
181
  class="dx-avatar__icon"
174
182
  href=${this.icon}
175
183
  x=${sizePx / 5}
176
184
  y=${sizePx / 5}
177
185
  width=${(3 * sizePx) / 5}
178
186
  height=${(3 * sizePx) / 5} />`
179
- : svg`<text
187
+ : // NOTE: Firefox currently doesn't fully support alignment-baseline.
188
+ svg`
189
+ <text
180
190
  x="50%"
181
191
  y="50%"
182
192
  class="dx-avatar__fallback-text"
183
193
  fill=${fg}
184
194
  text-anchor="middle"
185
195
  alignment-baseline="central"
196
+ dominant-baseline="middle"
186
197
  font-size=${this.size === 'px' ? '200%' : this.size * fontScale}
187
198
  mask=${`url(#${this.maskId})`}
188
199
  >
189
- ${getFirstTwoRenderableChars(this.fallback)}
200
+ ${/\p{Emoji_Presentation}/u.test(this.fallback) ? this.fallback : getInitials(this.fallback)}
190
201
  </text>`
191
202
  }
192
203
  ${
193
204
  this.imgSrc &&
194
- svg`<image
205
+ svg`
206
+ <image
195
207
  width="100%"
196
208
  height="100%"
197
209
  preserveAspectRatio="xMidYMid slice"
@@ -211,3 +223,17 @@ export class DxAvatar extends LitElement {
211
223
  return this;
212
224
  }
213
225
  }
226
+
227
+ /**
228
+ * Returns the first two renderable characters from a string that are separated by non-word characters.
229
+ * Handles Unicode characters correctly.
230
+ */
231
+ const getInitials = (label = ''): string[] => {
232
+ return label
233
+ .trim()
234
+ .split(/\s+/)
235
+ .map((str) => str.replace(/[^\p{L}\p{N}\s]/gu, ''))
236
+ .filter(Boolean)
237
+ .slice(0, 2)
238
+ .map((word) => word[0].toUpperCase());
239
+ };
package/src/index.ts CHANGED
@@ -4,5 +4,5 @@
4
4
 
5
5
  export * from './dx-anchor';
6
6
  export * from './dx-avatar';
7
- export * from './dx-tag-picker';
8
7
  export * from './dx-icon';
8
+ export * from './dx-tag-picker';
package/src/react.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  import { type EventName, createComponent } from '@lit/react';
6
6
  import React, { type ComponentPropsWithRef } from 'react';
7
7
 
8
- import { type DxAnchorActivate } from '@dxos/react-ui-types';
8
+ import { DX_ANCHOR_ACTIVATE, type DxAnchorActivate } from '@dxos/ui-types';
9
9
 
10
10
  import {
11
11
  type DxTagPickerItemClick,
@@ -20,7 +20,7 @@ export const DxAnchor = createComponent({
20
20
  elementClass: NaturalDxAnchor,
21
21
  react: React,
22
22
  events: {
23
- onActivate: 'dx-anchor-activate' as EventName<DxAnchorActivate>,
23
+ onActivate: DX_ANCHOR_ACTIVATE as EventName<DxAnchorActivate>,
24
24
  },
25
25
  });
26
26