bits-ui 2.17.0 → 2.17.2
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/bits/menu/menu.svelte.js +6 -1
- package/dist/bits/slider/slider.svelte.js +7 -0
- package/dist/bits/time-field/time-field.svelte.d.ts +1 -0
- package/dist/bits/time-field/time-field.svelte.js +34 -13
- package/dist/bits/utilities/dismissible-layer/use-dismissable-layer.svelte.js +2 -2
- package/dist/bits/utilities/hidden-input.svelte +7 -2
- package/package.json +1 -1
|
@@ -1149,6 +1149,11 @@ export class MenuSubTriggerState {
|
|
|
1149
1149
|
if (!this.item.opts.disabled.current &&
|
|
1150
1150
|
!this.submenu.opts.open.current &&
|
|
1151
1151
|
!this.#openTimer) {
|
|
1152
|
+
const openDelay = this.opts.openDelay.current;
|
|
1153
|
+
if (openDelay <= 0) {
|
|
1154
|
+
this.submenu.onOpen();
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1152
1157
|
this.#openTimer = this.content.domContext.setTimeout(() => {
|
|
1153
1158
|
if (this.submenu.root.isPointerInTransit) {
|
|
1154
1159
|
this.#clearOpenTimer();
|
|
@@ -1156,7 +1161,7 @@ export class MenuSubTriggerState {
|
|
|
1156
1161
|
}
|
|
1157
1162
|
this.submenu.onOpen();
|
|
1158
1163
|
this.#clearOpenTimer();
|
|
1159
|
-
},
|
|
1164
|
+
}, openDelay);
|
|
1160
1165
|
}
|
|
1161
1166
|
}
|
|
1162
1167
|
onpointerleave(e) {
|
|
@@ -11,6 +11,7 @@ import { createBitsAttrs, boolToStr, boolToEmptyStrOrUndef } from "../../interna
|
|
|
11
11
|
import { kbd } from "../../internal/kbd.js";
|
|
12
12
|
import { isElementOrSVGElement } from "../../internal/is.js";
|
|
13
13
|
import { isValidIndex } from "../../internal/arrays.js";
|
|
14
|
+
import { SvelteResizeObserver } from "../../internal/svelte-resize-observer.svelte.js";
|
|
14
15
|
import { linearScale } from "../../internal/math.js";
|
|
15
16
|
const sliderAttrs = createBitsAttrs({
|
|
16
17
|
component: "slider",
|
|
@@ -21,6 +22,7 @@ class SliderBaseRootState {
|
|
|
21
22
|
opts;
|
|
22
23
|
attachment;
|
|
23
24
|
isActive = $state(false);
|
|
25
|
+
#layoutVersion = $state(0);
|
|
24
26
|
direction = $derived.by(() => {
|
|
25
27
|
if (this.opts.orientation.current === "horizontal") {
|
|
26
28
|
return this.opts.dir.current === "rtl" ? "rl" : "lr";
|
|
@@ -38,7 +40,11 @@ class SliderBaseRootState {
|
|
|
38
40
|
this.opts = opts;
|
|
39
41
|
this.attachment = attachRef(opts.ref);
|
|
40
42
|
this.domContext = new DOMContext(this.opts.ref);
|
|
43
|
+
new SvelteResizeObserver(() => this.opts.ref.current, this.#handleLayoutChange);
|
|
41
44
|
}
|
|
45
|
+
#handleLayoutChange = () => {
|
|
46
|
+
this.#layoutVersion += 1;
|
|
47
|
+
};
|
|
42
48
|
isThumbActive(_index) {
|
|
43
49
|
return this.isActive;
|
|
44
50
|
}
|
|
@@ -54,6 +60,7 @@ class SliderBaseRootState {
|
|
|
54
60
|
return Array.from(node.querySelectorAll(sliderAttrs.selector("thumb")));
|
|
55
61
|
};
|
|
56
62
|
getThumbScale = () => {
|
|
63
|
+
void this.#layoutVersion;
|
|
57
64
|
// If trackPadding is explicitly set, use it directly instead of calculating from thumb size
|
|
58
65
|
const trackPadding = this.opts.trackPadding?.current;
|
|
59
66
|
if (trackPadding !== undefined && trackPadding > 0) {
|
|
@@ -64,6 +64,7 @@ export declare class TimeFieldRootState<T extends TimeValue = Time> {
|
|
|
64
64
|
descriptionNode: HTMLElement | null;
|
|
65
65
|
validationNode: HTMLElement | null;
|
|
66
66
|
states: import("../../shared/date/types.js").TimeSegmentStateMap;
|
|
67
|
+
hourInputDayPeriodHint: TimeSegmentObj["dayPeriod"];
|
|
67
68
|
dayPeriodNode: HTMLElement | null;
|
|
68
69
|
name: string;
|
|
69
70
|
readonly maxValueTime: Time | undefined;
|
|
@@ -47,6 +47,15 @@ const SEGMENT_CONFIGS = {
|
|
|
47
47
|
padZero: true,
|
|
48
48
|
},
|
|
49
49
|
};
|
|
50
|
+
function get24HourValueFromTypedHour(hour, dayPeriod) {
|
|
51
|
+
const parsedHour = Number.parseInt(hour);
|
|
52
|
+
if (Number.isNaN(parsedHour))
|
|
53
|
+
return hour;
|
|
54
|
+
if (dayPeriod === "AM") {
|
|
55
|
+
return parsedHour === 12 ? "0" : `${parsedHour}`;
|
|
56
|
+
}
|
|
57
|
+
return parsedHour < 12 ? `${parsedHour + 12}` : `${parsedHour}`;
|
|
58
|
+
}
|
|
50
59
|
export class TimeFieldRootState {
|
|
51
60
|
static create(opts, rangeRoot) {
|
|
52
61
|
return TimeFieldRootContext.set(new TimeFieldRootState(opts, rangeRoot));
|
|
@@ -79,6 +88,7 @@ export class TimeFieldRootState {
|
|
|
79
88
|
descriptionNode = $state(null);
|
|
80
89
|
validationNode = $state(null);
|
|
81
90
|
states = initTimeSegmentStates();
|
|
91
|
+
hourInputDayPeriodHint = null;
|
|
82
92
|
dayPeriodNode = $state(null);
|
|
83
93
|
name = $state("");
|
|
84
94
|
maxValueTime = $derived.by(() => {
|
|
@@ -389,9 +399,14 @@ export class TimeFieldRootState {
|
|
|
389
399
|
const next = cb(prev[part]);
|
|
390
400
|
this.states.hour.updating = next;
|
|
391
401
|
if (next !== null && prev.dayPeriod !== null) {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
402
|
+
if (this.hourCycle !== 24 && this.hourInputDayPeriodHint !== null) {
|
|
403
|
+
prev.dayPeriod = this.hourInputDayPeriodHint;
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
const dayPeriod = this.formatter.dayPeriod(toDate(this.#toDateValue(this.timeRef.set({ hour: Number.parseInt(next) }))), this.hourCycle);
|
|
407
|
+
if (dayPeriod === "AM" || dayPeriod === "PM") {
|
|
408
|
+
prev.dayPeriod = dayPeriod;
|
|
409
|
+
}
|
|
395
410
|
}
|
|
396
411
|
}
|
|
397
412
|
newSegmentValues = { ...prev, [part]: next };
|
|
@@ -407,17 +422,22 @@ export class TimeFieldRootState {
|
|
|
407
422
|
newSegmentValues = { ...prev, [part]: next };
|
|
408
423
|
}
|
|
409
424
|
this.segmentValues = newSegmentValues;
|
|
425
|
+
const segmentObjForValue = part === "hour" &&
|
|
426
|
+
this.hourCycle !== 24 &&
|
|
427
|
+
this.hourInputDayPeriodHint !== null &&
|
|
428
|
+
newSegmentValues.hour !== null
|
|
429
|
+
? {
|
|
430
|
+
...newSegmentValues,
|
|
431
|
+
hour: get24HourValueFromTypedHour(newSegmentValues.hour, this.hourInputDayPeriodHint),
|
|
432
|
+
}
|
|
433
|
+
: newSegmentValues;
|
|
410
434
|
if (areAllTimeSegmentsFilled(newSegmentValues, this.#fieldNode)) {
|
|
411
435
|
this.setValue(getTimeValueFromSegments({
|
|
412
|
-
segmentObj:
|
|
436
|
+
segmentObj: segmentObjForValue,
|
|
413
437
|
fieldNode: this.#fieldNode,
|
|
414
438
|
timeRef: this.timeRef,
|
|
415
439
|
}));
|
|
416
440
|
}
|
|
417
|
-
else {
|
|
418
|
-
// this.setValue(undefined);
|
|
419
|
-
// this.segmentValues = newSegmentValues;
|
|
420
|
-
}
|
|
421
441
|
}
|
|
422
442
|
handleSegmentClick(e) {
|
|
423
443
|
if (this.disabled.current) {
|
|
@@ -794,11 +814,12 @@ class TimeFieldHourSegmentState extends BaseTimeSegmentState {
|
|
|
794
814
|
super(opts, root, "hour", SEGMENT_CONFIGS.hour);
|
|
795
815
|
}
|
|
796
816
|
onkeydown(e) {
|
|
817
|
+
const oldUpdateSegment = this.root.updateSegment.bind(this.root);
|
|
797
818
|
if (isNumberString(e.key)) {
|
|
798
|
-
|
|
799
|
-
|
|
819
|
+
this.root.hourInputDayPeriodHint =
|
|
820
|
+
this.root.hourCycle === 24 ? null : this.root.segmentValues.dayPeriod;
|
|
800
821
|
this.root.updateSegment = (part, cb) => {
|
|
801
|
-
|
|
822
|
+
oldUpdateSegment(part, cb);
|
|
802
823
|
// after updating hour, check if we need to display "12" instead of "0"
|
|
803
824
|
if (part === "hour" && "hour" in this.root.segmentValues) {
|
|
804
825
|
const hourValue = this.root.segmentValues.hour;
|
|
@@ -808,11 +829,11 @@ class TimeFieldHourSegmentState extends BaseTimeSegmentState {
|
|
|
808
829
|
this.root.segmentValues.hour = "12";
|
|
809
830
|
}
|
|
810
831
|
}
|
|
811
|
-
return result;
|
|
812
832
|
};
|
|
813
833
|
}
|
|
814
834
|
super.onkeydown(e);
|
|
815
|
-
this.root.updateSegment =
|
|
835
|
+
this.root.updateSegment = oldUpdateSegment;
|
|
836
|
+
this.root.hourInputDayPeriodHint = null;
|
|
816
837
|
}
|
|
817
838
|
}
|
|
818
839
|
class TimeFieldMinuteSegmentState extends BaseTimeSegmentState {
|
|
@@ -191,11 +191,11 @@ function isValidEvent(e, node) {
|
|
|
191
191
|
if (!isElementOrSVGElement(target))
|
|
192
192
|
return false;
|
|
193
193
|
const targetIsContextMenuTrigger = Boolean(target.closest(`[${CONTEXT_MENU_TRIGGER_ATTR}]`));
|
|
194
|
+
const nodeIsContextMenu = Boolean(node.closest(`[${CONTEXT_MENU_CONTENT_ATTR}]`));
|
|
194
195
|
if ("button" in e && e.button > 0 && !targetIsContextMenuTrigger)
|
|
195
196
|
return false;
|
|
196
197
|
if ("button" in e && e.button === 0 && targetIsContextMenuTrigger)
|
|
197
|
-
return
|
|
198
|
-
const nodeIsContextMenu = Boolean(node.closest(`[${CONTEXT_MENU_CONTENT_ATTR}]`));
|
|
198
|
+
return nodeIsContextMenu;
|
|
199
199
|
if (targetIsContextMenuTrigger && nodeIsContextMenu)
|
|
200
200
|
return false;
|
|
201
201
|
const ownerDocument = getOwnerDocument(target);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { mergeProps,
|
|
2
|
+
import { mergeProps, srOnlyStyles } from "svelte-toolbelt";
|
|
3
3
|
import type { HTMLInputAttributes } from "svelte/elements";
|
|
4
4
|
|
|
5
5
|
let { value = $bindable(), ...restProps }: HTMLInputAttributes = $props();
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
mergeProps(restProps, {
|
|
9
9
|
"aria-hidden": "true",
|
|
10
10
|
tabindex: -1,
|
|
11
|
-
style:
|
|
11
|
+
style: {
|
|
12
|
+
...srOnlyStyles,
|
|
13
|
+
position: "absolute",
|
|
14
|
+
top: "0",
|
|
15
|
+
left: "0",
|
|
16
|
+
},
|
|
12
17
|
})
|
|
13
18
|
);
|
|
14
19
|
</script>
|