@zag-js/focus-visible 1.43.0 → 1.43.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/index.js CHANGED
@@ -34,6 +34,20 @@ function isValidKey(e) {
34
34
  return !(e.metaKey || !(0, import_dom_query.isMac)() && e.altKey || e.ctrlKey || e.key === "Control" || e.key === "Shift" || e.key === "Meta");
35
35
  }
36
36
  var nonTextInputTypes = /* @__PURE__ */ new Set(["checkbox", "radio", "range", "color", "file", "image", "button", "submit", "reset"]);
37
+ var interactiveContentSelector = [
38
+ "a[href]",
39
+ "audio[controls]",
40
+ "button",
41
+ "details",
42
+ "embed",
43
+ "iframe",
44
+ "img[controls]",
45
+ "img[usemap]",
46
+ "input",
47
+ "select",
48
+ "textarea",
49
+ "video[controls]"
50
+ ].join(",");
37
51
  function isKeyboardFocusEvent(isTextInput, modality, e) {
38
52
  const eventTarget = e ? (0, import_dom_query.getEventTarget)(e) : null;
39
53
  const doc = (0, import_dom_query.getDocument)(eventTarget);
@@ -46,7 +60,9 @@ var currentModality = null;
46
60
  var changeHandlers = /* @__PURE__ */ new Set();
47
61
  var listenerMap = /* @__PURE__ */ new Map();
48
62
  var hasEventBeforeFocus = false;
63
+ var pendingLabelControl = null;
49
64
  var hasBlurredWindowRecently = false;
65
+ var lastPointerPosition = null;
50
66
  var ignoreFocusEvent = false;
51
67
  var FOCUS_VISIBLE_INPUT_KEYS = {
52
68
  Tab: true,
@@ -58,6 +74,7 @@ function triggerChangeHandlers(modality, e) {
58
74
  }
59
75
  }
60
76
  function handleKeyboardEvent(e) {
77
+ pendingLabelControl = null;
61
78
  hasEventBeforeFocus = true;
62
79
  if (isValidKey(e)) {
63
80
  currentModality = "keyboard";
@@ -65,33 +82,50 @@ function handleKeyboardEvent(e) {
65
82
  }
66
83
  }
67
84
  function handlePointerEvent(e) {
85
+ const isMove = e.type === "pointermove" || e.type === "mousemove";
86
+ if (isMove && lastPointerPosition?.x === e.clientX && lastPointerPosition?.y === e.clientY) return;
87
+ lastPointerPosition = { x: e.clientX, y: e.clientY };
68
88
  currentModality = "pointer";
69
89
  if (e.type === "mousedown" || e.type === "pointerdown") {
90
+ pendingLabelControl = null;
70
91
  hasEventBeforeFocus = true;
71
92
  triggerChangeHandlers("pointer", e);
72
93
  }
73
94
  }
74
95
  function handleClickEvent(e) {
75
96
  if ((0, import_dom_query.isVirtualClick)(e)) {
97
+ pendingLabelControl = null;
76
98
  hasEventBeforeFocus = true;
77
99
  currentModality = "virtual";
100
+ return;
78
101
  }
102
+ pendingLabelControl = null;
103
+ const target = (0, import_dom_query.getEventTarget)(e);
104
+ const label = target?.closest("label");
105
+ const control = label?.control;
106
+ if (!label || !control || control.matches(":disabled")) return;
107
+ const interactive = target?.closest(interactiveContentSelector);
108
+ if (interactive && label.contains(interactive) && interactive !== control) return;
109
+ if (control !== (0, import_dom_query.getActiveElement)(label.ownerDocument)) pendingLabelControl = control;
79
110
  }
80
111
  function handleFocusEvent(e) {
81
112
  const target = (0, import_dom_query.getEventTarget)(e);
113
+ const isLabelActivationFocus = target === pendingLabelControl;
82
114
  if (target === (0, import_dom_query.getWindow)(target) || target === (0, import_dom_query.getDocument)(target) || ignoreFocusEvent || !e.isTrusted) {
83
115
  return;
84
116
  }
85
- if (!hasEventBeforeFocus && !hasBlurredWindowRecently) {
117
+ if (!hasEventBeforeFocus && !isLabelActivationFocus && !hasBlurredWindowRecently) {
86
118
  currentModality = "virtual";
87
119
  triggerChangeHandlers("virtual", e);
88
120
  }
89
121
  hasEventBeforeFocus = false;
122
+ pendingLabelControl = null;
90
123
  hasBlurredWindowRecently = false;
91
124
  }
92
125
  function handleWindowBlur() {
93
126
  if (ignoreFocusEvent) return;
94
127
  hasEventBeforeFocus = false;
128
+ pendingLabelControl = null;
95
129
  hasBlurredWindowRecently = true;
96
130
  }
97
131
  function setupGlobalFocusEvents(root) {
package/dist/index.mjs CHANGED
@@ -4,6 +4,20 @@ function isValidKey(e) {
4
4
  return !(e.metaKey || !isMac() && e.altKey || e.ctrlKey || e.key === "Control" || e.key === "Shift" || e.key === "Meta");
5
5
  }
6
6
  var nonTextInputTypes = /* @__PURE__ */ new Set(["checkbox", "radio", "range", "color", "file", "image", "button", "submit", "reset"]);
7
+ var interactiveContentSelector = [
8
+ "a[href]",
9
+ "audio[controls]",
10
+ "button",
11
+ "details",
12
+ "embed",
13
+ "iframe",
14
+ "img[controls]",
15
+ "img[usemap]",
16
+ "input",
17
+ "select",
18
+ "textarea",
19
+ "video[controls]"
20
+ ].join(",");
7
21
  function isKeyboardFocusEvent(isTextInput, modality, e) {
8
22
  const eventTarget = e ? getEventTarget(e) : null;
9
23
  const doc = getDocument(eventTarget);
@@ -16,7 +30,9 @@ var currentModality = null;
16
30
  var changeHandlers = /* @__PURE__ */ new Set();
17
31
  var listenerMap = /* @__PURE__ */ new Map();
18
32
  var hasEventBeforeFocus = false;
33
+ var pendingLabelControl = null;
19
34
  var hasBlurredWindowRecently = false;
35
+ var lastPointerPosition = null;
20
36
  var ignoreFocusEvent = false;
21
37
  var FOCUS_VISIBLE_INPUT_KEYS = {
22
38
  Tab: true,
@@ -28,6 +44,7 @@ function triggerChangeHandlers(modality, e) {
28
44
  }
29
45
  }
30
46
  function handleKeyboardEvent(e) {
47
+ pendingLabelControl = null;
31
48
  hasEventBeforeFocus = true;
32
49
  if (isValidKey(e)) {
33
50
  currentModality = "keyboard";
@@ -35,33 +52,50 @@ function handleKeyboardEvent(e) {
35
52
  }
36
53
  }
37
54
  function handlePointerEvent(e) {
55
+ const isMove = e.type === "pointermove" || e.type === "mousemove";
56
+ if (isMove && lastPointerPosition?.x === e.clientX && lastPointerPosition?.y === e.clientY) return;
57
+ lastPointerPosition = { x: e.clientX, y: e.clientY };
38
58
  currentModality = "pointer";
39
59
  if (e.type === "mousedown" || e.type === "pointerdown") {
60
+ pendingLabelControl = null;
40
61
  hasEventBeforeFocus = true;
41
62
  triggerChangeHandlers("pointer", e);
42
63
  }
43
64
  }
44
65
  function handleClickEvent(e) {
45
66
  if (isVirtualClick(e)) {
67
+ pendingLabelControl = null;
46
68
  hasEventBeforeFocus = true;
47
69
  currentModality = "virtual";
70
+ return;
48
71
  }
72
+ pendingLabelControl = null;
73
+ const target = getEventTarget(e);
74
+ const label = target?.closest("label");
75
+ const control = label?.control;
76
+ if (!label || !control || control.matches(":disabled")) return;
77
+ const interactive = target?.closest(interactiveContentSelector);
78
+ if (interactive && label.contains(interactive) && interactive !== control) return;
79
+ if (control !== getActiveElement(label.ownerDocument)) pendingLabelControl = control;
49
80
  }
50
81
  function handleFocusEvent(e) {
51
82
  const target = getEventTarget(e);
83
+ const isLabelActivationFocus = target === pendingLabelControl;
52
84
  if (target === getWindow(target) || target === getDocument(target) || ignoreFocusEvent || !e.isTrusted) {
53
85
  return;
54
86
  }
55
- if (!hasEventBeforeFocus && !hasBlurredWindowRecently) {
87
+ if (!hasEventBeforeFocus && !isLabelActivationFocus && !hasBlurredWindowRecently) {
56
88
  currentModality = "virtual";
57
89
  triggerChangeHandlers("virtual", e);
58
90
  }
59
91
  hasEventBeforeFocus = false;
92
+ pendingLabelControl = null;
60
93
  hasBlurredWindowRecently = false;
61
94
  }
62
95
  function handleWindowBlur() {
63
96
  if (ignoreFocusEvent) return;
64
97
  hasEventBeforeFocus = false;
98
+ pendingLabelControl = null;
65
99
  hasBlurredWindowRecently = true;
66
100
  }
67
101
  function setupGlobalFocusEvents(root) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/focus-visible",
3
- "version": "1.43.0",
3
+ "version": "1.43.2",
4
4
  "description": "Focus visible polyfill utility based on WICG",
5
5
  "keywords": [
6
6
  "js",
@@ -28,7 +28,7 @@
28
28
  "clean-package": "../../../clean-package.config.json",
29
29
  "main": "dist/index.js",
30
30
  "dependencies": {
31
- "@zag-js/dom-query": "1.43.0"
31
+ "@zag-js/dom-query": "1.43.2"
32
32
  },
33
33
  "devDependencies": {
34
34
  "clean-package": "2.2.0"