bits-ui 2.16.0 → 2.16.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.
@@ -1,7 +1,7 @@
1
1
  import type { Updater } from "svelte/store";
2
2
  import { Time } from "@internationalized/date";
3
3
  import { type WritableBox, DOMContext, type ReadableBoxedValues, type WritableBoxedValues } from "svelte-toolbelt";
4
- import type { BitsFocusEvent, BitsKeyboardEvent, BitsMouseEvent, RefAttachment, WithRefOpts } from "../../internal/types.js";
4
+ import type { BitsFocusEvent, BitsInputEvent, BitsKeyboardEvent, BitsMouseEvent, RefAttachment, WithRefOpts } from "../../internal/types.js";
5
5
  import type { TimeSegmentObj, SegmentPart, HourCycle, TimeValidator, TimeOnInvalid, EditableTimeSegmentPart } from "../../shared/date/types.js";
6
6
  import { type TimeFormatter } from "../../internal/date-time/formatter.js";
7
7
  import { type Announcer } from "../../internal/date-time/announcer.js";
@@ -288,6 +288,7 @@ declare class TimeFieldDayPeriodSegmentState {
288
288
  readonly root: TimeFieldRootState;
289
289
  readonly attachment: RefAttachment;
290
290
  constructor(opts: TimeFieldDayPeriodSegmentStateOpts, root: TimeFieldRootState);
291
+ onbeforeinput(e: BitsInputEvent): void;
291
292
  onkeydown(e: BitsKeyboardEvent): void;
292
293
  readonly props: {
293
294
  "aria-invalid": "true" | undefined;
@@ -305,6 +306,7 @@ declare class TimeFieldDayPeriodSegmentState {
305
306
  "aria-valuenow": number;
306
307
  "aria-valuetext": string;
307
308
  onkeydown: (e: BitsKeyboardEvent) => void;
309
+ onbeforeinput: (e: BitsInputEvent) => void;
308
310
  onclick: (e: BitsMouseEvent) => void;
309
311
  role: string;
310
312
  contenteditable: string;
@@ -335,6 +337,7 @@ declare class TimeFieldDayPeriodSegmentState {
335
337
  "aria-valuenow": number;
336
338
  "aria-valuetext": string;
337
339
  onkeydown: (e: BitsKeyboardEvent) => void;
340
+ onbeforeinput: (e: BitsInputEvent) => void;
338
341
  onclick: (e: BitsMouseEvent) => void;
339
342
  role: string;
340
343
  spellcheck: boolean;
@@ -836,6 +836,22 @@ class TimeFieldDayPeriodSegmentState {
836
836
  this.#announcer = this.root.announcer;
837
837
  this.attachment = attachRef(opts.ref, (v) => (this.root.dayPeriodNode = v));
838
838
  this.onkeydown = this.onkeydown.bind(this);
839
+ this.onbeforeinput = this.onbeforeinput.bind(this);
840
+ }
841
+ onbeforeinput(e) {
842
+ if (this.root.disabled.current)
843
+ return;
844
+ const data = typeof e.data === "string" ? e.data.trim().toLowerCase() : "";
845
+ if (!data)
846
+ return;
847
+ e.preventDefault();
848
+ if (data === "a" || data === "p") {
849
+ this.root.updateSegment("dayPeriod", () => {
850
+ const next = data === "a" ? "AM" : "PM";
851
+ this.#announcer.announce(next);
852
+ return next;
853
+ });
854
+ }
839
855
  }
840
856
  onkeydown(e) {
841
857
  if (e.ctrlKey || e.metaKey || this.root.disabled.current)
@@ -894,6 +910,7 @@ class TimeFieldDayPeriodSegmentState {
894
910
  "aria-valuenow": valueNow,
895
911
  "aria-valuetext": valueText,
896
912
  onkeydown: this.onkeydown,
913
+ onbeforeinput: this.onbeforeinput,
897
914
  onclick: this.root.handleSegmentClick,
898
915
  ...this.root.getBaseSegmentAttrs("dayPeriod", this.opts.id.current),
899
916
  ...this.attachment,
@@ -55,6 +55,21 @@ export function useFloating(options) {
55
55
  placement: placementOption,
56
56
  strategy: strategyOption,
57
57
  }).then((position) => {
58
+ const referenceNode = reference.current;
59
+ const referenceHidden = isReferenceHidden(referenceNode);
60
+ if (referenceHidden) {
61
+ // keep last good coordinates when the anchor disappears to avoid
62
+ // a transient jump to viewport origin before close propagates.
63
+ middlewareData = {
64
+ ...middlewareData,
65
+ hide: {
66
+ // oxlint-disable-next-line no-explicit-any
67
+ ...middlewareData.hide,
68
+ referenceHidden: true,
69
+ },
70
+ };
71
+ return;
72
+ }
58
73
  // ignore bad coordinates that cause jumping during close transitions
59
74
  if (!openOption && x !== 0 && y !== 0) {
60
75
  // if we had a good position and now getting coordinates near
@@ -156,3 +171,12 @@ export function useFloating(options) {
156
171
  },
157
172
  };
158
173
  }
174
+ function isReferenceHidden(node) {
175
+ if (!(node instanceof Element))
176
+ return false;
177
+ if (!node.isConnected)
178
+ return true;
179
+ if (node instanceof HTMLElement && node.hidden)
180
+ return true;
181
+ return node.getClientRects().length === 0;
182
+ }
@@ -90,4 +90,5 @@ export type BitsPointerEvent<T extends HTMLElement = HTMLElement> = BitsEvent<Po
90
90
  export type BitsKeyboardEvent<T extends HTMLElement = HTMLElement> = BitsEvent<KeyboardEvent, T>;
91
91
  export type BitsMouseEvent<T extends HTMLElement = HTMLElement> = BitsEvent<MouseEvent, T>;
92
92
  export type BitsFocusEvent<T extends HTMLElement = HTMLElement> = BitsEvent<FocusEvent, T>;
93
+ export type BitsInputEvent<T extends HTMLElement = HTMLElement> = BitsEvent<InputEvent, T>;
93
94
  export type RefAttachment<T extends HTMLElement = HTMLElement> = ReturnType<typeof attachRef<T>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bits-ui",
3
- "version": "2.16.0",
3
+ "version": "2.16.2",
4
4
  "license": "MIT",
5
5
  "repository": "github:huntabyte/bits-ui",
6
6
  "funding": "https://github.com/sponsors/huntabyte",