@webjsdev/ui 0.3.3 → 0.3.5
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 +1 -1
- package/packages/registry/components/alert-dialog.ts +9 -2
- package/packages/registry/components/dialog.ts +9 -2
- package/packages/registry/components/dropdown-menu.ts +12 -5
- package/packages/registry/components/hover-card.ts +10 -4
- package/packages/registry/components/tabs.ts +3 -3
- package/packages/registry/components/toggle-group.ts +3 -3
- package/packages/registry/components/tooltip.ts +10 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webjsdev/ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An AI-first component library - class-helper functions for visuals, custom elements only where state matters. Source-copied into your repo, you own it. Works with any Tailwind v4 project.",
|
|
6
6
|
"bin": {
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
* Design tokens used: --background, --border, --muted-foreground.
|
|
65
65
|
*/
|
|
66
66
|
import { WebComponent, html } from '@webjsdev/core';
|
|
67
|
+
import { ref, createRef } from '@webjsdev/core/directives';
|
|
67
68
|
import { buttonClass, type ButtonVariant, type ButtonSize } from './button.ts';
|
|
68
69
|
|
|
69
70
|
export const alertDialogContentClass = (): string =>
|
|
@@ -228,18 +229,23 @@ export class UiAlertDialogContent extends WebComponent {
|
|
|
228
229
|
};
|
|
229
230
|
declare size: 'default' | 'sm';
|
|
230
231
|
|
|
232
|
+
// ref to the own-rendered native <dialog>. render() creates it, so a
|
|
233
|
+
// ref() binding is the lit-idiomatic handle (no querySelector against
|
|
234
|
+
// a string selector into the component's own output).
|
|
235
|
+
#dialog = createRef<HTMLDialogElement>();
|
|
236
|
+
|
|
231
237
|
constructor() {
|
|
232
238
|
super();
|
|
233
239
|
this.size = 'default';
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
showModal(): void {
|
|
237
|
-
const native = this.
|
|
243
|
+
const native = this.#dialog.value;
|
|
238
244
|
if (native && !native.open) native.showModal();
|
|
239
245
|
}
|
|
240
246
|
|
|
241
247
|
close(): void {
|
|
242
|
-
const native = this.
|
|
248
|
+
const native = this.#dialog.value;
|
|
243
249
|
if (native?.open) native.close();
|
|
244
250
|
}
|
|
245
251
|
|
|
@@ -248,6 +254,7 @@ export class UiAlertDialogContent extends WebComponent {
|
|
|
248
254
|
return html`<dialog
|
|
249
255
|
data-slot="alert-dialog-native"
|
|
250
256
|
class=${NATIVE_DIALOG_CLASS}
|
|
257
|
+
${ref(this.#dialog)}
|
|
251
258
|
@cancel=${this._onNativeCancel}
|
|
252
259
|
@close=${this._onNativeClose}
|
|
253
260
|
><div
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
* Design tokens used: --background, --border, --muted-foreground.
|
|
65
65
|
*/
|
|
66
66
|
import { WebComponent, html, unsafeHTML } from '@webjsdev/core';
|
|
67
|
+
import { ref, createRef } from '@webjsdev/core/directives';
|
|
67
68
|
import { buttonClass } from './button.ts';
|
|
68
69
|
|
|
69
70
|
// --------------------------------------------------------------------------
|
|
@@ -262,18 +263,23 @@ export class UiDialogContent extends WebComponent {
|
|
|
262
263
|
};
|
|
263
264
|
declare showCloseButton: string;
|
|
264
265
|
|
|
266
|
+
// ref to the own-rendered native <dialog>. render() creates it, so a
|
|
267
|
+
// ref() binding is the lit-idiomatic handle (no querySelector against
|
|
268
|
+
// a string selector into the component's own output).
|
|
269
|
+
#dialog = createRef<HTMLDialogElement>();
|
|
270
|
+
|
|
265
271
|
constructor() {
|
|
266
272
|
super();
|
|
267
273
|
this.showCloseButton = 'true';
|
|
268
274
|
}
|
|
269
275
|
|
|
270
276
|
showModal(): void {
|
|
271
|
-
const native = this.
|
|
277
|
+
const native = this.#dialog.value;
|
|
272
278
|
if (native && !native.open) native.showModal();
|
|
273
279
|
}
|
|
274
280
|
|
|
275
281
|
close(): void {
|
|
276
|
-
const native = this.
|
|
282
|
+
const native = this.#dialog.value;
|
|
277
283
|
if (native?.open) native.close();
|
|
278
284
|
}
|
|
279
285
|
|
|
@@ -283,6 +289,7 @@ export class UiDialogContent extends WebComponent {
|
|
|
283
289
|
return html`<dialog
|
|
284
290
|
data-slot="dialog-native"
|
|
285
291
|
class=${NATIVE_DIALOG_CLASS}
|
|
292
|
+
${ref(this.#dialog)}
|
|
286
293
|
@close=${this._onNativeClose}
|
|
287
294
|
@click=${this._onNativeBackdropClick}
|
|
288
295
|
><div
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
* Design tokens used: --popover, --popover-foreground, --accent,
|
|
75
75
|
* --accent-foreground, --destructive, --muted-foreground, --border.
|
|
76
76
|
*/
|
|
77
|
-
import { WebComponent, html, unsafeHTML } from '@webjsdev/core';
|
|
77
|
+
import { WebComponent, html, unsafeHTML, signal } from '@webjsdev/core';
|
|
78
78
|
import { positionFloating, type PopoverSide, type PopoverAlign } from './popover.ts';
|
|
79
79
|
|
|
80
80
|
// --------------------------------------------------------------------------
|
|
@@ -348,6 +348,12 @@ export class UiDropdownMenuItem extends WebComponent {
|
|
|
348
348
|
declare variant: 'default' | 'destructive';
|
|
349
349
|
declare inset: boolean;
|
|
350
350
|
|
|
351
|
+
// Keyboard / pointer highlight state for the own-rendered menuitem. A
|
|
352
|
+
// local signal bound with ?data-highlighted keeps the highlight in the
|
|
353
|
+
// declarative template instead of an imperative setAttribute on
|
|
354
|
+
// e.currentTarget (the lit-idiomatic form).
|
|
355
|
+
#highlighted = signal(false);
|
|
356
|
+
|
|
351
357
|
constructor() {
|
|
352
358
|
super();
|
|
353
359
|
this.variant = 'default';
|
|
@@ -361,6 +367,7 @@ export class UiDropdownMenuItem extends WebComponent {
|
|
|
361
367
|
tabindex="-1"
|
|
362
368
|
data-variant=${this.variant}
|
|
363
369
|
?data-inset=${this.inset}
|
|
370
|
+
?data-highlighted=${this.#highlighted.get()}
|
|
364
371
|
class=${dropdownMenuItemClass()}
|
|
365
372
|
@click=${this._onClick}
|
|
366
373
|
@pointerenter=${this._onPointerEnter}
|
|
@@ -381,12 +388,12 @@ export class UiDropdownMenuItem extends WebComponent {
|
|
|
381
388
|
el.focus();
|
|
382
389
|
};
|
|
383
390
|
|
|
384
|
-
_onFocus = (
|
|
385
|
-
|
|
391
|
+
_onFocus = (): void => {
|
|
392
|
+
this.#highlighted.set(true);
|
|
386
393
|
};
|
|
387
394
|
|
|
388
|
-
_onBlur = (
|
|
389
|
-
|
|
395
|
+
_onBlur = (): void => {
|
|
396
|
+
this.#highlighted.set(false);
|
|
390
397
|
};
|
|
391
398
|
}
|
|
392
399
|
UiDropdownMenuItem.register('ui-dropdown-menu-item');
|
|
@@ -55,8 +55,14 @@ export const hoverCardContentClass = (): string =>
|
|
|
55
55
|
export class UiHoverCard extends WebComponent {
|
|
56
56
|
static properties = {
|
|
57
57
|
open: { type: Boolean, reflect: true },
|
|
58
|
+
openDelay: { type: Number },
|
|
59
|
+
closeDelay: { type: Number },
|
|
58
60
|
};
|
|
59
61
|
declare open: boolean;
|
|
62
|
+
// `openDelay` / `closeDelay` ride the `open-delay` / `close-delay`
|
|
63
|
+
// attributes (shadcn parity), read as typed props.
|
|
64
|
+
declare openDelay: number;
|
|
65
|
+
declare closeDelay: number;
|
|
60
66
|
|
|
61
67
|
_showTimer: number | undefined;
|
|
62
68
|
_hideTimer: number | undefined;
|
|
@@ -64,6 +70,8 @@ export class UiHoverCard extends WebComponent {
|
|
|
64
70
|
constructor() {
|
|
65
71
|
super();
|
|
66
72
|
this.open = false;
|
|
73
|
+
this.openDelay = 700;
|
|
74
|
+
this.closeDelay = 300;
|
|
67
75
|
}
|
|
68
76
|
|
|
69
77
|
// Back-compat getter.
|
|
@@ -71,14 +79,12 @@ export class UiHoverCard extends WebComponent {
|
|
|
71
79
|
|
|
72
80
|
show(): void {
|
|
73
81
|
clearTimeout(this._hideTimer);
|
|
74
|
-
|
|
75
|
-
this._showTimer = window.setTimeout(() => { this.open = true; }, delay);
|
|
82
|
+
this._showTimer = window.setTimeout(() => { this.open = true; }, this.openDelay);
|
|
76
83
|
}
|
|
77
84
|
|
|
78
85
|
hide(): void {
|
|
79
86
|
clearTimeout(this._showTimer);
|
|
80
|
-
|
|
81
|
-
this._hideTimer = window.setTimeout(() => { this.open = false; }, delay);
|
|
87
|
+
this._hideTimer = window.setTimeout(() => { this.open = false; }, this.closeDelay);
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
render() {
|
|
@@ -177,9 +177,9 @@ export class UiTabsTrigger extends WebComponent {
|
|
|
177
177
|
this.value = '';
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
// render() runs server-side too
|
|
181
|
-
//
|
|
182
|
-
//
|
|
180
|
+
// render() runs server-side too. webjs resolves closest() at SSR against
|
|
181
|
+
// the enclosing-element ancestor chain, so the active tab is marked in the
|
|
182
|
+
// first paint (no hydration flash). The typeof guard stays defensive.
|
|
183
183
|
get _tabs(): UiTabs | null {
|
|
184
184
|
if (typeof this.closest !== 'function') return null;
|
|
185
185
|
return this.closest('ui-tabs') as UiTabs | null;
|
|
@@ -173,9 +173,9 @@ export class UiToggleGroupItem extends WebComponent {
|
|
|
173
173
|
this.pressed = false;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
// render() runs server-side too.
|
|
177
|
-
//
|
|
178
|
-
//
|
|
176
|
+
// render() runs server-side too. webjs resolves closest() at SSR against
|
|
177
|
+
// the enclosing-element ancestor chain, so the pressed item is marked in
|
|
178
|
+
// the first paint (no hydration flash). The typeof guard stays defensive.
|
|
179
179
|
get _group(): UiToggleGroup | null {
|
|
180
180
|
if (typeof this.closest !== 'function') return null;
|
|
181
181
|
return this.closest('ui-toggle-group') as UiToggleGroup | null;
|
|
@@ -64,8 +64,14 @@ let lastTooltipHideAt = 0;
|
|
|
64
64
|
export class UiTooltip extends WebComponent {
|
|
65
65
|
static properties = {
|
|
66
66
|
open: { type: Boolean, reflect: true },
|
|
67
|
+
delayDuration: { type: Number },
|
|
68
|
+
skipDelayDuration: { type: Number },
|
|
67
69
|
};
|
|
68
70
|
declare open: boolean;
|
|
71
|
+
// `delayDuration` / `skipDelayDuration` ride the `delay-duration` /
|
|
72
|
+
// `skip-delay-duration` attributes (shadcn parity), read as typed props.
|
|
73
|
+
declare delayDuration: number;
|
|
74
|
+
declare skipDelayDuration: number;
|
|
69
75
|
|
|
70
76
|
_showTimer: number | undefined;
|
|
71
77
|
_hideTimer: number | undefined;
|
|
@@ -73,6 +79,8 @@ export class UiTooltip extends WebComponent {
|
|
|
73
79
|
constructor() {
|
|
74
80
|
super();
|
|
75
81
|
this.open = false;
|
|
82
|
+
this.delayDuration = 700;
|
|
83
|
+
this.skipDelayDuration = 300;
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
// Back-compat getter for tests + external code that read `el.isOpen`
|
|
@@ -82,8 +90,8 @@ export class UiTooltip extends WebComponent {
|
|
|
82
90
|
show(): void {
|
|
83
91
|
clearTimeout(this._showTimer);
|
|
84
92
|
clearTimeout(this._hideTimer);
|
|
85
|
-
const delay =
|
|
86
|
-
const skipDelay =
|
|
93
|
+
const delay = this.delayDuration;
|
|
94
|
+
const skipDelay = this.skipDelayDuration;
|
|
87
95
|
const sinceLastHide = Date.now() - lastTooltipHideAt;
|
|
88
96
|
if (lastTooltipHideAt > 0 && sinceLastHide < skipDelay) {
|
|
89
97
|
this.open = true;
|