@wordpress/dom 5.0.0 → 5.1.0

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.
Files changed (210) hide show
  1. package/README.md +1 -1
  2. package/build/data-transfer.cjs +20 -38
  3. package/build/data-transfer.cjs.map +1 -7
  4. package/build/dom/caret-range-from-point.cjs +31 -38
  5. package/build/dom/caret-range-from-point.cjs.map +1 -7
  6. package/build/dom/clean-node-list.cjs +87 -132
  7. package/build/dom/clean-node-list.cjs.map +1 -7
  8. package/build/dom/compute-caret-rect.cjs +35 -35
  9. package/build/dom/compute-caret-rect.cjs.map +1 -7
  10. package/build/dom/document-has-selection.cjs +35 -30
  11. package/build/dom/document-has-selection.cjs.map +1 -7
  12. package/build/dom/document-has-text-selection.cjs +24 -30
  13. package/build/dom/document-has-text-selection.cjs.map +1 -7
  14. package/build/dom/document-has-uncollapsed-selection.cjs +34 -29
  15. package/build/dom/document-has-uncollapsed-selection.cjs.map +1 -7
  16. package/build/dom/get-computed-style.cjs +14 -30
  17. package/build/dom/get-computed-style.cjs.map +1 -7
  18. package/build/dom/get-offset-parent.cjs +40 -39
  19. package/build/dom/get-offset-parent.cjs.map +1 -7
  20. package/build/dom/get-range-height.cjs +18 -31
  21. package/build/dom/get-range-height.cjs.map +1 -7
  22. package/build/dom/get-rectangle-from-range.cjs +82 -128
  23. package/build/dom/get-rectangle-from-range.cjs.map +1 -7
  24. package/build/dom/get-scroll-container.cjs +46 -50
  25. package/build/dom/get-scroll-container.cjs.map +1 -7
  26. package/build/dom/hidden-caret-range-from-point.cjs +48 -42
  27. package/build/dom/hidden-caret-range-from-point.cjs.map +1 -7
  28. package/build/dom/index.cjs +233 -110
  29. package/build/dom/input-field-has-uncollapsed-selection.cjs +48 -43
  30. package/build/dom/input-field-has-uncollapsed-selection.cjs.map +1 -7
  31. package/build/dom/insert-after.cjs +17 -27
  32. package/build/dom/insert-after.cjs.map +1 -7
  33. package/build/dom/is-edge.cjs +82 -97
  34. package/build/dom/is-edge.cjs.map +1 -7
  35. package/build/dom/is-element.cjs +12 -25
  36. package/build/dom/is-element.cjs.map +1 -7
  37. package/build/dom/is-empty.cjs +23 -37
  38. package/build/dom/is-empty.cjs.map +1 -7
  39. package/build/dom/is-entirely-selected.cjs +70 -67
  40. package/build/dom/is-entirely-selected.cjs.map +1 -7
  41. package/build/dom/is-form-element.cjs +33 -33
  42. package/build/dom/is-form-element.cjs.map +1 -7
  43. package/build/dom/is-horizontal-edge.cjs +31 -28
  44. package/build/dom/is-horizontal-edge.cjs.map +1 -7
  45. package/build/dom/is-html-input-element.cjs +12 -25
  46. package/build/dom/is-html-input-element.cjs.map +1 -7
  47. package/build/dom/is-input-or-text-area.cjs +12 -25
  48. package/build/dom/is-input-or-text-area.cjs.map +1 -7
  49. package/build/dom/is-number-input.cjs +36 -33
  50. package/build/dom/is-number-input.cjs.map +1 -7
  51. package/build/dom/is-rtl.cjs +30 -28
  52. package/build/dom/is-rtl.cjs.map +1 -7
  53. package/build/dom/is-selection-forward.cjs +26 -39
  54. package/build/dom/is-selection-forward.cjs.map +1 -7
  55. package/build/dom/is-text-field.cjs +45 -42
  56. package/build/dom/is-text-field.cjs.map +1 -7
  57. package/build/dom/is-vertical-edge.cjs +31 -28
  58. package/build/dom/is-vertical-edge.cjs.map +1 -7
  59. package/build/dom/place-caret-at-edge.cjs +75 -78
  60. package/build/dom/place-caret-at-edge.cjs.map +1 -7
  61. package/build/dom/place-caret-at-horizontal-edge.cjs +29 -28
  62. package/build/dom/place-caret-at-horizontal-edge.cjs.map +1 -7
  63. package/build/dom/place-caret-at-vertical-edge.cjs +30 -28
  64. package/build/dom/place-caret-at-vertical-edge.cjs.map +1 -7
  65. package/build/dom/remove-invalid-html.cjs +35 -31
  66. package/build/dom/remove-invalid-html.cjs.map +1 -7
  67. package/build/dom/remove.cjs +15 -27
  68. package/build/dom/remove.cjs.map +1 -7
  69. package/build/dom/replace-tag.cjs +21 -32
  70. package/build/dom/replace-tag.cjs.map +1 -7
  71. package/build/dom/replace.cjs +34 -32
  72. package/build/dom/replace.cjs.map +1 -7
  73. package/build/dom/safe-html.cjs +45 -46
  74. package/build/dom/safe-html.cjs.map +1 -7
  75. package/build/dom/scroll-if-no-range.cjs +24 -37
  76. package/build/dom/scroll-if-no-range.cjs.map +1 -7
  77. package/build/dom/strip-html.cjs +33 -31
  78. package/build/dom/strip-html.cjs.map +1 -7
  79. package/build/dom/types.cjs +4 -18
  80. package/build/dom/unwrap.cjs +17 -31
  81. package/build/dom/unwrap.cjs.map +1 -7
  82. package/build/dom/wrap.cjs +17 -28
  83. package/build/dom/wrap.cjs.map +1 -7
  84. package/build/focusable.cjs +99 -76
  85. package/build/focusable.cjs.map +1 -7
  86. package/build/index.cjs +57 -38
  87. package/build/index.cjs.map +1 -7
  88. package/build/phrasing-content.cjs +163 -159
  89. package/build/phrasing-content.cjs.map +1 -7
  90. package/build/tabbable.cjs +123 -78
  91. package/build/tabbable.cjs.map +1 -7
  92. package/build/types.cjs +4 -18
  93. package/build/utils/assert-is-defined.cjs +8 -33
  94. package/build/utils/assert-is-defined.cjs.map +1 -7
  95. package/build-module/data-transfer.mjs +16 -14
  96. package/build-module/data-transfer.mjs.map +1 -7
  97. package/build-module/dom/caret-range-from-point.mjs +27 -18
  98. package/build-module/dom/caret-range-from-point.mjs.map +1 -7
  99. package/build-module/dom/clean-node-list.mjs +60 -105
  100. package/build-module/dom/clean-node-list.mjs.map +1 -7
  101. package/build-module/dom/compute-caret-rect.mjs +16 -12
  102. package/build-module/dom/compute-caret-rect.mjs.map +1 -7
  103. package/build-module/dom/document-has-selection.mjs +13 -6
  104. package/build-module/dom/document-has-selection.mjs.map +1 -7
  105. package/build-module/dom/document-has-text-selection.mjs +20 -10
  106. package/build-module/dom/document-has-text-selection.mjs.map +1 -7
  107. package/build-module/dom/document-has-uncollapsed-selection.mjs +14 -6
  108. package/build-module/dom/document-has-uncollapsed-selection.mjs.map +1 -7
  109. package/build-module/dom/get-computed-style.mjs +10 -10
  110. package/build-module/dom/get-computed-style.mjs.map +1 -7
  111. package/build-module/dom/get-offset-parent.mjs +20 -16
  112. package/build-module/dom/get-offset-parent.mjs.map +1 -7
  113. package/build-module/dom/get-range-height.mjs +14 -11
  114. package/build-module/dom/get-range-height.mjs.map +1 -7
  115. package/build-module/dom/get-rectangle-from-range.mjs +78 -108
  116. package/build-module/dom/get-rectangle-from-range.mjs.map +1 -7
  117. package/build-module/dom/get-scroll-container.mjs +28 -28
  118. package/build-module/dom/get-scroll-container.mjs.map +1 -7
  119. package/build-module/dom/hidden-caret-range-from-point.mjs +28 -19
  120. package/build-module/dom/hidden-caret-range-from-point.mjs.map +1 -7
  121. package/build-module/dom/index.mjs +28 -58
  122. package/build-module/dom/input-field-has-uncollapsed-selection.mjs +28 -20
  123. package/build-module/dom/input-field-has-uncollapsed-selection.mjs.map +1 -7
  124. package/build-module/dom/insert-after.mjs +13 -7
  125. package/build-module/dom/insert-after.mjs.map +1 -7
  126. package/build-module/dom/is-edge.mjs +53 -69
  127. package/build-module/dom/is-edge.mjs.map +1 -7
  128. package/build-module/dom/is-element.mjs +8 -5
  129. package/build-module/dom/is-element.mjs.map +1 -7
  130. package/build-module/dom/is-empty.mjs +19 -17
  131. package/build-module/dom/is-empty.mjs.map +1 -7
  132. package/build-module/dom/is-entirely-selected.mjs +51 -44
  133. package/build-module/dom/is-entirely-selected.mjs.map +1 -7
  134. package/build-module/dom/is-form-element.mjs +15 -11
  135. package/build-module/dom/is-form-element.mjs.map +1 -7
  136. package/build-module/dom/is-horizontal-edge.mjs +13 -6
  137. package/build-module/dom/is-horizontal-edge.mjs.map +1 -7
  138. package/build-module/dom/is-html-input-element.mjs +8 -5
  139. package/build-module/dom/is-html-input-element.mjs.map +1 -7
  140. package/build-module/dom/is-input-or-text-area.mjs +8 -5
  141. package/build-module/dom/is-input-or-text-area.mjs.map +1 -7
  142. package/build-module/dom/is-number-input.mjs +16 -10
  143. package/build-module/dom/is-number-input.mjs.map +1 -7
  144. package/build-module/dom/is-rtl.mjs +12 -6
  145. package/build-module/dom/is-rtl.mjs.map +1 -7
  146. package/build-module/dom/is-selection-forward.mjs +22 -19
  147. package/build-module/dom/is-selection-forward.mjs.map +1 -7
  148. package/build-module/dom/is-text-field.mjs +27 -20
  149. package/build-module/dom/is-text-field.mjs.map +1 -7
  150. package/build-module/dom/is-vertical-edge.mjs +13 -6
  151. package/build-module/dom/is-vertical-edge.mjs.map +1 -7
  152. package/build-module/dom/place-caret-at-edge.mjs +51 -52
  153. package/build-module/dom/place-caret-at-edge.mjs.map +1 -7
  154. package/build-module/dom/place-caret-at-horizontal-edge.mjs +11 -6
  155. package/build-module/dom/place-caret-at-horizontal-edge.mjs.map +1 -7
  156. package/build-module/dom/place-caret-at-vertical-edge.mjs +12 -6
  157. package/build-module/dom/place-caret-at-vertical-edge.mjs.map +1 -7
  158. package/build-module/dom/remove-invalid-html.mjs +17 -9
  159. package/build-module/dom/remove-invalid-html.mjs.map +1 -7
  160. package/build-module/dom/remove.mjs +11 -7
  161. package/build-module/dom/remove.mjs.map +1 -7
  162. package/build-module/dom/replace-tag.mjs +17 -12
  163. package/build-module/dom/replace-tag.mjs.map +1 -7
  164. package/build-module/dom/replace.mjs +13 -8
  165. package/build-module/dom/replace.mjs.map +1 -7
  166. package/build-module/dom/safe-html.mjs +27 -24
  167. package/build-module/dom/safe-html.mjs.map +1 -7
  168. package/build-module/dom/scroll-if-no-range.mjs +20 -13
  169. package/build-module/dom/scroll-if-no-range.mjs.map +1 -7
  170. package/build-module/dom/strip-html.mjs +15 -9
  171. package/build-module/dom/strip-html.mjs.map +1 -7
  172. package/build-module/dom/types.mjs +0 -1
  173. package/build-module/dom/unwrap.mjs +13 -11
  174. package/build-module/dom/unwrap.mjs.map +1 -7
  175. package/build-module/dom/wrap.mjs +13 -8
  176. package/build-module/dom/wrap.mjs.map +1 -7
  177. package/build-module/focusable.mjs +95 -52
  178. package/build-module/focusable.mjs.map +1 -7
  179. package/build-module/index.mjs +11 -5
  180. package/build-module/index.mjs.map +1 -7
  181. package/build-module/phrasing-content.mjs +157 -133
  182. package/build-module/phrasing-content.mjs.map +1 -7
  183. package/build-module/tabbable.mjs +116 -51
  184. package/build-module/tabbable.mjs.map +1 -7
  185. package/build-module/types.mjs +0 -1
  186. package/build-module/utils/assert-is-defined.mjs +4 -9
  187. package/build-module/utils/assert-is-defined.mjs.map +1 -7
  188. package/build-types/dom/clean-node-list.d.ts +2 -2
  189. package/build-types/dom/clean-node-list.d.ts.map +1 -1
  190. package/build-types/dom/is-edge.d.ts.map +1 -1
  191. package/build-types/dom/remove-invalid-html.d.ts +4 -4
  192. package/build-types/dom/remove-invalid-html.d.ts.map +1 -1
  193. package/package.json +4 -4
  194. package/src/dom/clean-node-list.ts +2 -2
  195. package/src/dom/is-edge.ts +35 -43
  196. package/src/dom/remove-invalid-html.ts +4 -4
  197. package/src/dom/test/{get-rectangle-from-range.browser.test.js → get-rectangle-from-range.browser.test.ts} +25 -25
  198. package/src/test/{dom.jsdom.test.js → dom.jsdom.test.ts} +9 -6
  199. package/src/test/{focusable.browser.test.js → focusable.browser.test.ts} +14 -13
  200. package/src/test/{tabbable.browser.test.js → tabbable.browser.test.ts} +3 -2
  201. package/build/dom/index.cjs.map +0 -7
  202. package/build/dom/types.cjs.map +0 -7
  203. package/build/types.cjs.map +0 -7
  204. package/build-module/dom/index.mjs.map +0 -7
  205. package/build-module/dom/types.mjs.map +0 -7
  206. package/build-module/types.mjs.map +0 -7
  207. /package/src/dom/test/{safe-html.jsdom.test.js → safe-html.jsdom.test.ts} +0 -0
  208. /package/src/dom/test/{strip-html.jsdom.test.js → strip-html.jsdom.test.ts} +0 -0
  209. /package/src/test/{focusable-area.jsdom.test.js → focusable-area.jsdom.test.ts} +0 -0
  210. /package/src/test/{utils.js → utils.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/dom",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "description": "DOM utilities module for WordPress.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -42,13 +42,13 @@
42
42
  "types": "build-types",
43
43
  "sideEffects": false,
44
44
  "dependencies": {
45
- "@wordpress/deprecated": "^5.0.0"
45
+ "@wordpress/deprecated": "^5.1.0"
46
46
  },
47
47
  "devDependencies": {
48
- "vitest": "^5.0.3"
48
+ "vitest": "^5.0.5"
49
49
  },
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
- "gitHead": "8d30f92cbbde3ddf781c8799443c649befbbcb88"
53
+ "gitHead": "9b70363b9f93cff0583a1f3153738d383cf5a49e"
54
54
  }
@@ -15,13 +15,13 @@ const noop = () => {};
15
15
  * @param nodeList The nodeList to filter.
16
16
  * @param doc The document of the nodeList.
17
17
  * @param schema Schema for the HTML.
18
- * @param inline Whether to clean for inline mode.
18
+ * @param [inline] Whether to clean for inline mode.
19
19
  */
20
20
  export default function cleanNodeList(
21
21
  nodeList: NodeList,
22
22
  doc: Document,
23
23
  schema: Schema,
24
- inline: boolean
24
+ inline?: boolean
25
25
  ) {
26
26
  Array.from( nodeList ).forEach(
27
27
  ( node: Node & { nextElementSibling?: unknown } ) => {
@@ -5,7 +5,6 @@ import isSelectionForward from './is-selection-forward';
5
5
  import hiddenCaretRangeFromPoint from './hidden-caret-range-from-point';
6
6
  import { assertIsDefined } from '../utils/assert-is-defined';
7
7
  import isInputOrTextArea from './is-input-or-text-area';
8
- import { scrollIfNoRange } from './scroll-if-no-range';
9
8
 
10
9
  /**
11
10
  * Check whether the selection is at the edge of the container. Checks for
@@ -82,53 +81,48 @@ export default function isEdge(
82
81
  return false;
83
82
  }
84
83
 
84
+ // A line above the selection (or below, when going down) means it is not
85
+ // at the vertical edge. Unlike hit-testing a point, a range measures
86
+ // lines outside the viewport too.
87
+ const contentRange = ownerDocument.createRange();
88
+ contentRange.selectNodeContents( container );
89
+ const hasLineBeyond = Array.from( contentRange.getClientRects() ).some(
90
+ ( rect ) =>
91
+ rect.height > 0 &&
92
+ ( isReverse
93
+ ? rect.bottom <= rangeRect.top + 1
94
+ : rect.top >= rangeRect.bottom - 1 )
95
+ );
96
+
97
+ if ( hasLineBeyond ) {
98
+ return false;
99
+ }
100
+
101
+ if ( onlyVertical ) {
102
+ return true;
103
+ }
104
+
85
105
  // In the case of RTL scripts, the horizontal edge is at the opposite side.
86
106
  const isReverseDir = isRTL( container ) ? ! isReverse : isReverse;
87
107
  const containerRect = container.getBoundingClientRect();
88
108
 
89
- // To check if a selection is at the edge, we insert a test selection at the
90
- // edge of the container and check if the selections have the same vertical
91
- // or horizontal position. If they do, the selection is at the edge.
92
- // This method proves to be better than a DOM-based calculation for the
93
- // horizontal edge, since it ignores empty textnodes and a trailing line
94
- // break element. In other words, we need to check visual positioning, not
95
- // DOM positioning.
96
- // It also proves better than using the computed style for the vertical
97
- // edge, because we cannot know the padding and line height reliably in
98
- // pixels. `getComputedStyle` may return a value with different units.
109
+ // The selection is on the edge line. To check if it is at the horizontal
110
+ // edge of that line, we hit-test a point at the container's edge on that
111
+ // line and check if the caret there has the same position. This proves
112
+ // better than a DOM-based calculation, since it ignores empty text nodes
113
+ // and a trailing line break element. The line is within the viewport when
114
+ // the selection is; otherwise the browser handles the key.
99
115
  const x = isReverseDir ? containerRect.left + 1 : containerRect.right - 1;
100
- const y = isReverse ? containerRect.top + 1 : containerRect.bottom - 1;
101
-
102
- // The test point can only be hit-tested when it is within the viewport
103
- // (`caretRangeFromPoint` returns nothing for a point outside it, upon
104
- // which `scrollIfNoRange` scrolls the container's edge into view to
105
- // measure, e.g. on every arrow press within a container taller than the
106
- // viewport). When the edge is outside the viewport and the selection is
107
- // within it, they are at least a viewport boundary apart along that
108
- // axis, so the selection cannot be at the edge. Check each axis
109
- // separately: the vertical check must not be short-circuited by a
110
- // horizontally overflowing container, and vice versa.
111
- const isFarFromVerticalEdge =
112
- ( y < 0 || y > defaultView.innerHeight ) &&
113
- rangeRect.top >= 0 &&
114
- rangeRect.bottom <= defaultView.innerHeight;
115
- const isFarFromHorizontalEdge =
116
- ( x < 0 || x > defaultView.innerWidth ) &&
117
- rangeRect.left >= 0 &&
118
- rangeRect.right <= defaultView.innerWidth;
119
-
120
- if (
121
- isFarFromVerticalEdge ||
122
- ( ! onlyVertical && isFarFromHorizontalEdge )
123
- ) {
124
- return false;
125
- }
116
+ const y = isReverse ? rangeRect.top + 1 : rangeRect.bottom - 1;
126
117
 
127
- const testRange = scrollIfNoRange( container, isReverse, () =>
128
- hiddenCaretRangeFromPoint( ownerDocument, x, y, container )
118
+ const testRange = hiddenCaretRangeFromPoint(
119
+ ownerDocument,
120
+ x,
121
+ y,
122
+ container
129
123
  );
130
124
 
131
- if ( ! testRange ) {
125
+ if ( ! testRange || ! container.contains( testRange.startContainer ) ) {
132
126
  return false;
133
127
  }
134
128
 
@@ -148,7 +142,5 @@ export default function isEdge(
148
142
  const hasVerticalDiff = Math.abs( verticalDiff ) <= 1;
149
143
  const hasHorizontalDiff = Math.abs( horizontalDiff ) <= 1;
150
144
 
151
- return onlyVertical
152
- ? hasVerticalDiff
153
- : hasVerticalDiff && hasHorizontalDiff;
145
+ return hasVerticalDiff && hasHorizontalDiff;
154
146
  }
@@ -4,16 +4,16 @@ import type { Schema } from './types';
4
4
  /**
5
5
  * Given a schema, unwraps or removes nodes, attributes and classes on HTML.
6
6
  *
7
- * @param {string} HTML The HTML to clean up.
8
- * @param {Schema} schema Schema for the HTML.
9
- * @param {boolean} inline Whether to clean for inline mode.
7
+ * @param {string} HTML The HTML to clean up.
8
+ * @param {Schema} schema Schema for the HTML.
9
+ * @param {boolean} [inline] Whether to clean for inline mode.
10
10
  *
11
11
  * @return {string} The cleaned up HTML.
12
12
  */
13
13
  export default function removeInvalidHTML(
14
14
  HTML: string,
15
15
  schema: Schema,
16
- inline: boolean
16
+ inline?: boolean
17
17
  ): string {
18
18
  const doc = document.implementation.createHTMLDocument( '' );
19
19
 
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
2
  import getRectangleFromRange from '../get-rectangle-from-range';
3
3
 
4
4
  describe( 'getRectangleFromRange', () => {
5
- let container;
5
+ let container: HTMLDivElement;
6
6
 
7
7
  beforeEach( () => {
8
8
  container = document.createElement( 'div' );
@@ -13,7 +13,7 @@ describe( 'getRectangleFromRange', () => {
13
13
  container.remove();
14
14
  } );
15
15
 
16
- function collapsedRange( node, offset ) {
16
+ function collapsedRange( node: Node, offset: number ) {
17
17
  const range = document.createRange();
18
18
  range.setStart( node, offset );
19
19
  range.collapse( true );
@@ -21,26 +21,26 @@ describe( 'getRectangleFromRange', () => {
21
21
  }
22
22
 
23
23
  // The caret rectangle the browser gives for a position in a text node.
24
- function caretBox( node, offset ) {
24
+ function caretBox( node: Node, offset: number ) {
25
25
  return collapsedRange( node, offset ).getClientRects()[ 0 ].toJSON();
26
26
  }
27
27
 
28
- function box( rect ) {
29
- return rect.toJSON();
28
+ function box( rect: DOMRect | null ) {
29
+ return rect!.toJSON();
30
30
  }
31
31
 
32
32
  it( 'measures a position after the last child of an element at the end of its text', () => {
33
33
  container.innerHTML = '<div>wordpress.org</div>';
34
- const element = container.firstChild;
34
+ const element = container.firstChild as HTMLDivElement;
35
35
  const range = collapsedRange( element, 1 );
36
- const mutations = [];
36
+ const mutations: MutationRecord[] = [];
37
37
  new window.MutationObserver( ( records ) =>
38
38
  mutations.push( ...records )
39
39
  ).observe( element, { childList: true, subtree: true } );
40
40
 
41
41
  expect( range.getClientRects() ).toHaveLength( 0 );
42
42
  expect( box( getRectangleFromRange( range ) ) ).toEqual(
43
- caretBox( element.firstChild, 13 )
43
+ caretBox( element.firstChild!, 13 )
44
44
  );
45
45
  expect( range.startContainer ).toBe( element );
46
46
  return Promise.resolve().then( () => {
@@ -50,20 +50,20 @@ describe( 'getRectangleFromRange', () => {
50
50
 
51
51
  it( 'measures a position before the first child of an element at the start of its text', () => {
52
52
  container.innerHTML = '<div><em>abc</em>def</div>';
53
- const element = container.firstChild;
53
+ const element = container.firstChild as HTMLDivElement;
54
54
 
55
55
  expect(
56
56
  box( getRectangleFromRange( collapsedRange( element, 0 ) ) )
57
- ).toEqual( caretBox( element.querySelector( 'em' ).firstChild, 0 ) );
57
+ ).toEqual( caretBox( element.querySelector( 'em' )!.firstChild!, 0 ) );
58
58
  } );
59
59
 
60
60
  it( 'measures a position after a line break at the start of the next line', () => {
61
61
  container.innerHTML = '<p>abc<br>def</p>';
62
- const paragraph = container.firstChild;
63
- const nextLine = caretBox( paragraph.lastChild, 0 );
62
+ const paragraph = container.firstChild as HTMLParagraphElement;
63
+ const nextLine = caretBox( paragraph.lastChild!, 0 );
64
64
 
65
65
  expect( nextLine.top ).toBeGreaterThan(
66
- caretBox( paragraph.firstChild, 3 ).top
66
+ caretBox( paragraph.firstChild!, 3 ).top
67
67
  );
68
68
  expect(
69
69
  box( getRectangleFromRange( collapsedRange( paragraph, 2 ) ) )
@@ -73,11 +73,11 @@ describe( 'getRectangleFromRange', () => {
73
73
  it( 'returns null for a position between texts on different lines', () => {
74
74
  container.innerHTML =
75
75
  '<p style="width: 3ch; font-family: monospace; overflow-wrap: anywhere;">abc<em>def</em></p>';
76
- const paragraph = container.firstChild;
76
+ const paragraph = container.firstChild as HTMLParagraphElement;
77
77
 
78
78
  expect(
79
- caretBox( paragraph.lastChild.firstChild, 0 ).top
80
- ).toBeGreaterThan( caretBox( paragraph.firstChild, 3 ).top );
79
+ caretBox( paragraph.lastChild!.firstChild!, 0 ).top
80
+ ).toBeGreaterThan( caretBox( paragraph.firstChild!, 3 ).top );
81
81
  expect(
82
82
  getRectangleFromRange( collapsedRange( paragraph, 1 ) )
83
83
  ).toBeNull();
@@ -85,40 +85,40 @@ describe( 'getRectangleFromRange', () => {
85
85
 
86
86
  it( 'measures a position between texts on the same line', () => {
87
87
  container.innerHTML = '<p>abc<em>def</em></p>';
88
- const paragraph = container.firstChild;
88
+ const paragraph = container.firstChild as HTMLParagraphElement;
89
89
 
90
90
  expect(
91
91
  box( getRectangleFromRange( collapsedRange( paragraph, 1 ) ) )
92
- ).toEqual( caretBox( paragraph.lastChild.firstChild, 0 ) );
92
+ ).toEqual( caretBox( paragraph.lastChild!.firstChild!, 0 ) );
93
93
  } );
94
94
 
95
95
  it( 'measures a position inside an empty inline element beside the text next to it', () => {
96
96
  container.innerHTML =
97
97
  '<p><span data-rich-text-placeholder="Type"></span></p>';
98
- const paragraph = container.firstChild;
99
- const placeholder = paragraph.querySelector( 'span' );
98
+ const paragraph = container.firstChild as HTMLParagraphElement;
99
+ const placeholder = paragraph.querySelector( 'span' )!;
100
100
 
101
101
  expect(
102
102
  box( getRectangleFromRange( collapsedRange( placeholder, 0 ) ) )
103
- ).toEqual( caretBox( paragraph.firstChild, 1 ) );
103
+ ).toEqual( caretBox( paragraph.firstChild!, 1 ) );
104
104
  } );
105
105
 
106
106
  it( 'measures a position inside a line break at the end of the text before it', () => {
107
107
  container.innerHTML = '<p>abc<br>def</p>';
108
- const paragraph = container.firstChild;
108
+ const paragraph = container.firstChild as HTMLParagraphElement;
109
109
 
110
110
  expect(
111
111
  box(
112
112
  getRectangleFromRange(
113
- collapsedRange( paragraph.querySelector( 'br' ), 0 )
113
+ collapsedRange( paragraph.querySelector( 'br' )!, 0 )
114
114
  )
115
115
  )
116
- ).toEqual( caretBox( paragraph.firstChild, 3 ) );
116
+ ).toEqual( caretBox( paragraph.firstChild!, 3 ) );
117
117
  } );
118
118
 
119
119
  it( 'returns null for a position with no text on either side', () => {
120
120
  container.innerHTML = '<p><br></p>';
121
- const paragraph = container.firstChild;
121
+ const paragraph = container.firstChild as HTMLParagraphElement;
122
122
 
123
123
  expect(
124
124
  getRectangleFromRange( collapsedRange( paragraph, 1 ) )
@@ -10,7 +10,7 @@ import {
10
10
  import { getPhrasingContentSchema } from '../phrasing-content';
11
11
 
12
12
  describe( 'DOM', () => {
13
- let parent;
13
+ let parent: HTMLDivElement;
14
14
 
15
15
  beforeEach( () => {
16
16
  parent = document.createElement( 'div' );
@@ -110,9 +110,8 @@ describe( 'DOM', () => {
110
110
  /**
111
111
  * A sampling of input types expected not to be text eligible.
112
112
  *
113
- * @type {string[]}
114
113
  */
115
- const NON_TEXT_INPUT_TYPES = [
114
+ const NON_TEXT_INPUT_TYPES: string[] = [
116
115
  'button',
117
116
  'checkbox',
118
117
  'hidden',
@@ -129,9 +128,13 @@ describe( 'DOM', () => {
129
128
  /**
130
129
  * A sampling of input types expected to be text eligible.
131
130
  *
132
- * @type {string[]}
133
131
  */
134
- const TEXT_INPUT_TYPES = [ 'text', 'password', 'search', 'url' ];
132
+ const TEXT_INPUT_TYPES: string[] = [
133
+ 'text',
134
+ 'password',
135
+ 'search',
136
+ 'url',
137
+ ];
135
138
 
136
139
  it( 'should return false for non-text input elements', () => {
137
140
  NON_TEXT_INPUT_TYPES.forEach( ( type ) => {
@@ -325,7 +328,7 @@ describe( 'removeInvalidHTML', () => {
325
328
  } );
326
329
 
327
330
  describe( 'isEmpty', () => {
328
- function isEmptyHTML( HTML ) {
331
+ function isEmptyHTML( HTML: string ) {
329
332
  const doc = document.implementation.createHTMLDocument( '' );
330
333
 
331
334
  doc.body.innerHTML = HTML;
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
2
  import { find } from '../focusable';
3
3
 
4
4
  describe( 'focusable.find() CSS visibility', () => {
5
- let node;
5
+ let node: HTMLDivElement;
6
6
 
7
7
  beforeEach( () => {
8
8
  node = document.createElement( 'div' );
@@ -28,7 +28,7 @@ describe( 'focusable.find() CSS visibility', () => {
28
28
  'excludes inputs with %s even when they have layout boxes',
29
29
  ( _, html ) => {
30
30
  node.innerHTML = html;
31
- const input = node.querySelector( 'input' );
31
+ const input = node.querySelector( 'input' )!;
32
32
  const checkVisibility = vi.spyOn( input, 'checkVisibility' );
33
33
 
34
34
  expect( input.offsetWidth ).toBeGreaterThan( 0 );
@@ -46,7 +46,7 @@ describe( 'focusable.find() CSS visibility', () => {
46
46
  it( 'includes inputs that restore visibility inside a hidden ancestor', () => {
47
47
  node.style.visibility = 'hidden';
48
48
  node.innerHTML = '<input style="visibility: visible">';
49
- const input = node.querySelector( 'input' );
49
+ const input = node.querySelector( 'input' )!;
50
50
 
51
51
  input.focus();
52
52
  expect( input ).toHaveFocus();
@@ -56,7 +56,7 @@ describe( 'focusable.find() CSS visibility', () => {
56
56
  it( 'uses the owning window for the computed-style fallback', () => {
57
57
  const iframe = document.createElement( 'iframe' );
58
58
  node.appendChild( iframe );
59
- const iframeDocument = iframe.contentDocument;
59
+ const iframeDocument = iframe.contentDocument!;
60
60
  iframeDocument.body.innerHTML = `
61
61
  <div style="visibility: hidden">
62
62
  <input>
@@ -72,7 +72,7 @@ describe( 'focusable.find() CSS visibility', () => {
72
72
  checkVisibility: { value: undefined },
73
73
  } );
74
74
  const getComputedStyle = vi.spyOn(
75
- iframeDocument.defaultView,
75
+ iframeDocument.defaultView!,
76
76
  'getComputedStyle'
77
77
  );
78
78
 
@@ -82,11 +82,12 @@ describe( 'focusable.find() CSS visibility', () => {
82
82
  } );
83
83
  } );
84
84
 
85
- const createElement = ( type ) => document.createElement( type );
85
+ const createElement = < K extends keyof HTMLElementTagNameMap >( type: K ) =>
86
+ document.createElement( type );
86
87
  const IMAGE_SOURCE =
87
88
  'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
88
89
 
89
- function findFocusable( context ) {
90
+ function findFocusable( context: Element ) {
90
91
  if ( ! context.isConnected ) {
91
92
  document.body.appendChild( context );
92
93
  }
@@ -125,7 +126,7 @@ describe( 'focusable', () => {
125
126
  it( 'finds nested focusable child', () => {
126
127
  const node = createElement( 'div' );
127
128
  node.appendChild( createElement( 'div' ) );
128
- node.firstChild.appendChild( createElement( 'input' ) );
129
+ node.firstChild!.appendChild( createElement( 'input' ) );
129
130
 
130
131
  const focusable = findFocusable( node );
131
132
 
@@ -150,8 +151,8 @@ describe( 'focusable', () => {
150
151
  </map>
151
152
  <img src="${ IMAGE_SOURCE }" usemap="#testfocus" width="40" height="40" alt="">
152
153
  `;
153
- const area = node.querySelector( 'area' );
154
- const image = node.querySelector( 'img' );
154
+ const area = node.querySelector( 'area' )!;
155
+ const image = node.querySelector( 'img' )!;
155
156
 
156
157
  document.body.appendChild( node );
157
158
  await image.decode();
@@ -171,7 +172,7 @@ describe( 'focusable', () => {
171
172
  </map>
172
173
  <img src="${ IMAGE_SOURCE }" usemap="#testfocus" width="40" height="40" alt="" style="visibility: hidden">
173
174
  `;
174
- const image = node.querySelector( 'img' );
175
+ const image = node.querySelector( 'img' )!;
175
176
 
176
177
  document.body.appendChild( node );
177
178
 
@@ -203,8 +204,8 @@ describe( 'focusable', () => {
203
204
  </div>
204
205
  <img src="${ IMAGE_SOURCE }" usemap="#testfocus" width="40" height="40" alt="">
205
206
  `;
206
- const area = node.querySelector( 'area' );
207
- const image = node.querySelector( 'img' );
207
+ const area = node.querySelector( 'area' )!;
208
+ const image = node.querySelector( 'img' )!;
208
209
 
209
210
  document.body.appendChild( node );
210
211
  await image.decode();
@@ -1,9 +1,10 @@
1
1
  import { beforeEach, describe, expect, it } from 'vitest';
2
2
  import { find } from '../tabbable';
3
3
 
4
- const createElement = ( type ) => document.createElement( type );
4
+ const createElement = < K extends keyof HTMLElementTagNameMap >( type: K ) =>
5
+ document.createElement( type );
5
6
 
6
- function findTabbable( context ) {
7
+ function findTabbable( context: Element ) {
7
8
  document.body.appendChild( context );
8
9
  return find( context );
9
10
  }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/dom/index.ts"],
4
- "sourcesContent": ["export { default as computeCaretRect } from './compute-caret-rect';\nexport { default as documentHasTextSelection } from './document-has-text-selection';\nexport { default as documentHasUncollapsedSelection } from './document-has-uncollapsed-selection';\nexport { default as documentHasSelection } from './document-has-selection';\nexport { default as getRectangleFromRange } from './get-rectangle-from-range';\nexport { default as getScrollContainer } from './get-scroll-container';\nexport { default as getOffsetParent } from './get-offset-parent';\nexport { default as isEntirelySelected } from './is-entirely-selected';\nexport { default as isFormElement } from './is-form-element';\nexport { default as isHorizontalEdge } from './is-horizontal-edge';\nexport { default as isNumberInput } from './is-number-input';\nexport { default as isTextField } from './is-text-field';\nexport { default as isVerticalEdge } from './is-vertical-edge';\nexport { default as placeCaretAtHorizontalEdge } from './place-caret-at-horizontal-edge';\nexport { default as placeCaretAtVerticalEdge } from './place-caret-at-vertical-edge';\nexport { default as replace } from './replace';\nexport { default as remove } from './remove';\nexport { default as insertAfter } from './insert-after';\nexport { default as unwrap } from './unwrap';\nexport { default as replaceTag } from './replace-tag';\nexport { default as wrap } from './wrap';\nexport { default as __unstableStripHTML } from './strip-html';\nexport { default as isEmpty } from './is-empty';\nexport { default as removeInvalidHTML } from './remove-invalid-html';\nexport { default as isRTL } from './is-rtl';\nexport { default as safeHTML } from './safe-html';\nexport { default as isSelectionForward } from './is-selection-forward';\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCAA4C;AAC5C,yCAAoD;AACpD,gDAA2D;AAC3D,oCAAgD;AAChD,sCAAiD;AACjD,kCAA8C;AAC9C,+BAA2C;AAC3C,kCAA8C;AAC9C,6BAAyC;AACzC,gCAA4C;AAC5C,6BAAyC;AACzC,2BAAuC;AACvC,8BAA0C;AAC1C,4CAAsD;AACtD,0CAAoD;AACpD,qBAAmC;AACnC,oBAAkC;AAClC,0BAAuC;AACvC,oBAAkC;AAClC,yBAAsC;AACtC,kBAAgC;AAChC,wBAA+C;AAC/C,sBAAmC;AACnC,iCAA6C;AAC7C,oBAAiC;AACjC,uBAAoC;AACpC,kCAA8C;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/dom/types.ts"],
4
- "sourcesContent": ["export interface SchemaItem {\n\t/**\n\t * Attributes.\n\t */\n\tattributes?: string[];\n\t/**\n\t * Classnames or RegExp to test against. Use '*' to keep all classes.\n\t */\n\tclasses?: ( string | RegExp )[];\n\t/**\n\t * Child schemas.\n\t */\n\tchildren?: '*' | { [ tag: string ]: SchemaItem };\n\t/**\n\t * Selectors to test required children against. Leave empty or undefined if there are no requirements.\n\t */\n\trequire?: string[];\n\t/**\n\t * Whether to allow nodes without children.\n\t */\n\tallowEmpty?: boolean;\n\t/**\n\t * Function to test whether a node is a match. If left undefined any node will be assumed to match.\n\t */\n\tisMatch?: ( node: Node ) => boolean;\n}\n\nexport type Schema = { [ tag: string ]: SchemaItem };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/types.ts"],
4
- "sourcesContent": ["export interface SemanticElementDefinition {\n\t/**\n\t * Content attributes\n\t */\n\tattributes?: string[];\n\t/**\n\t * Allowed child elements, or `'*'` for any\n\t */\n\tchildren?: ContentSchema | '*';\n}\n\nexport type ContentSchema = Record< string, SemanticElementDefinition >;\n\nexport interface FindFocusableOptions {\n\t/**\n\t * If set, only return elements that are sequentially focusable.\n\t * Non-interactive elements with a negative `tabindex` are focusable but\n\t * not sequentially focusable.\n\t */\n\tsequential?: boolean;\n}\n\nexport type MaybeHTMLInputElement = HTMLElement & {\n\ttype?: string;\n\tchecked?: boolean;\n\tname?: string;\n};\n\nexport interface ObjectTabbable {\n\telement: HTMLElement;\n\tindex: number;\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/dom/index.ts"],
4
- "sourcesContent": ["export { default as computeCaretRect } from './compute-caret-rect';\nexport { default as documentHasTextSelection } from './document-has-text-selection';\nexport { default as documentHasUncollapsedSelection } from './document-has-uncollapsed-selection';\nexport { default as documentHasSelection } from './document-has-selection';\nexport { default as getRectangleFromRange } from './get-rectangle-from-range';\nexport { default as getScrollContainer } from './get-scroll-container';\nexport { default as getOffsetParent } from './get-offset-parent';\nexport { default as isEntirelySelected } from './is-entirely-selected';\nexport { default as isFormElement } from './is-form-element';\nexport { default as isHorizontalEdge } from './is-horizontal-edge';\nexport { default as isNumberInput } from './is-number-input';\nexport { default as isTextField } from './is-text-field';\nexport { default as isVerticalEdge } from './is-vertical-edge';\nexport { default as placeCaretAtHorizontalEdge } from './place-caret-at-horizontal-edge';\nexport { default as placeCaretAtVerticalEdge } from './place-caret-at-vertical-edge';\nexport { default as replace } from './replace';\nexport { default as remove } from './remove';\nexport { default as insertAfter } from './insert-after';\nexport { default as unwrap } from './unwrap';\nexport { default as replaceTag } from './replace-tag';\nexport { default as wrap } from './wrap';\nexport { default as __unstableStripHTML } from './strip-html';\nexport { default as isEmpty } from './is-empty';\nexport { default as removeInvalidHTML } from './remove-invalid-html';\nexport { default as isRTL } from './is-rtl';\nexport { default as safeHTML } from './safe-html';\nexport { default as isSelectionForward } from './is-selection-forward';\n"],
5
- "mappings": ";AAAA,SAAoB,WAAXA,gBAAmC;AAC5C,SAAoB,WAAXA,gBAA2C;AACpD,SAAoB,WAAXA,gBAAkD;AAC3D,SAAoB,WAAXA,gBAAuC;AAChD,SAAoB,WAAXA,gBAAwC;AACjD,SAAoB,WAAXA,gBAAqC;AAC9C,SAAoB,WAAXA,gBAAkC;AAC3C,SAAoB,WAAXA,gBAAqC;AAC9C,SAAoB,WAAXA,iBAAgC;AACzC,SAAoB,WAAXA,iBAAmC;AAC5C,SAAoB,WAAXA,iBAAgC;AACzC,SAAoB,WAAXA,iBAA8B;AACvC,SAAoB,WAAXA,iBAAiC;AAC1C,SAAoB,WAAXA,iBAA6C;AACtD,SAAoB,WAAXA,iBAA2C;AACpD,SAAoB,WAAXA,iBAA0B;AACnC,SAAoB,WAAXA,iBAAyB;AAClC,SAAoB,WAAXA,iBAA8B;AACvC,SAAoB,WAAXA,iBAAyB;AAClC,SAAoB,WAAXA,iBAA6B;AACtC,SAAoB,WAAXA,iBAAuB;AAChC,SAAoB,WAAXA,iBAAsC;AAC/C,SAAoB,WAAXA,iBAA0B;AACnC,SAAoB,WAAXA,iBAAoC;AAC7C,SAAoB,WAAXA,iBAAwB;AACjC,SAAoB,WAAXA,iBAA2B;AACpC,SAAoB,WAAXA,iBAAqC;",
6
- "names": ["default"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
File without changes