blockly 13.0.0-beta.0 → 13.0.0-beta.1

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 (279) hide show
  1. package/blockly.min.js +1093 -364
  2. package/blockly.mjs +1 -1
  3. package/blockly_compressed.js +1036 -364
  4. package/blockly_compressed.js.map +1 -1
  5. package/core/block_aria_composer.d.ts +119 -0
  6. package/core/block_svg.d.ts +21 -1
  7. package/core/blockly.d.ts +1 -1
  8. package/core/bubbles/mini_workspace_bubble.d.ts +4 -1
  9. package/core/bubbles/text_bubble.d.ts +4 -1
  10. package/core/dragging/block_drag_strategy.d.ts +45 -3
  11. package/core/field.d.ts +15 -17
  12. package/core/field_input.d.ts +23 -0
  13. package/core/focus_manager.d.ts +47 -2
  14. package/core/inputs/input.d.ts +15 -0
  15. package/core/interfaces/i_focusable_node.d.ts +3 -1
  16. package/core/keyboard_nav/keyboard_mover.d.ts +16 -5
  17. package/core/keyboard_nav/navigation_policies/bubble_navigation_policy.d.ts +63 -0
  18. package/core/keyboard_nav/navigation_policies/icon_navigation_policy.d.ts +2 -2
  19. package/core/keyboard_nav/navigators/flyout_navigator.d.ts +1 -1
  20. package/core/shortcut_items.d.ts +11 -1
  21. package/core/shortcut_registry.d.ts +6 -0
  22. package/core/toolbox/toolbox.d.ts +5 -11
  23. package/core/utils/aria.d.ts +9 -61
  24. package/core/utils/dom.d.ts +1 -1
  25. package/core/utils/shortcut_formatting.d.ts +5 -7
  26. package/core/variables.d.ts +1 -1
  27. package/index.mjs +1 -1
  28. package/msg/ab.js +57 -0
  29. package/msg/ab.mjs +57 -0
  30. package/msg/ace.js +57 -0
  31. package/msg/ace.mjs +57 -0
  32. package/msg/af.js +57 -0
  33. package/msg/af.mjs +57 -0
  34. package/msg/am.js +57 -0
  35. package/msg/am.mjs +57 -0
  36. package/msg/ar.js +57 -0
  37. package/msg/ar.mjs +57 -0
  38. package/msg/ast.js +57 -0
  39. package/msg/ast.mjs +57 -0
  40. package/msg/az.js +57 -0
  41. package/msg/az.mjs +57 -0
  42. package/msg/ba.js +57 -0
  43. package/msg/ba.mjs +57 -0
  44. package/msg/bcc.js +57 -0
  45. package/msg/bcc.mjs +57 -0
  46. package/msg/be-tarask.js +57 -0
  47. package/msg/be-tarask.mjs +57 -0
  48. package/msg/be.js +57 -0
  49. package/msg/be.mjs +57 -0
  50. package/msg/bg.js +57 -0
  51. package/msg/bg.mjs +57 -0
  52. package/msg/bn.js +57 -0
  53. package/msg/bn.mjs +57 -0
  54. package/msg/br.js +57 -0
  55. package/msg/br.mjs +57 -0
  56. package/msg/bs.js +57 -0
  57. package/msg/bs.mjs +57 -0
  58. package/msg/ca.js +57 -0
  59. package/msg/ca.mjs +57 -0
  60. package/msg/cdo.js +57 -0
  61. package/msg/cdo.mjs +57 -0
  62. package/msg/ce.js +57 -0
  63. package/msg/ce.mjs +57 -0
  64. package/msg/cs.js +57 -0
  65. package/msg/cs.mjs +57 -0
  66. package/msg/da.js +57 -0
  67. package/msg/da.mjs +57 -0
  68. package/msg/de.js +57 -0
  69. package/msg/de.mjs +57 -0
  70. package/msg/diq.js +57 -0
  71. package/msg/diq.mjs +57 -0
  72. package/msg/dtp.js +57 -0
  73. package/msg/dtp.mjs +57 -0
  74. package/msg/dty.js +57 -0
  75. package/msg/dty.mjs +57 -0
  76. package/msg/ee.js +57 -0
  77. package/msg/ee.mjs +57 -0
  78. package/msg/el.js +57 -0
  79. package/msg/el.mjs +57 -0
  80. package/msg/en-gb.js +57 -0
  81. package/msg/en-gb.mjs +57 -0
  82. package/msg/en.js +57 -0
  83. package/msg/en.mjs +57 -0
  84. package/msg/eo.js +57 -0
  85. package/msg/eo.mjs +57 -0
  86. package/msg/es.js +57 -0
  87. package/msg/es.mjs +57 -0
  88. package/msg/et.js +57 -0
  89. package/msg/et.mjs +57 -0
  90. package/msg/eu.js +57 -0
  91. package/msg/eu.mjs +57 -0
  92. package/msg/fa.js +57 -0
  93. package/msg/fa.mjs +57 -0
  94. package/msg/fi.js +57 -0
  95. package/msg/fi.mjs +57 -0
  96. package/msg/fo.js +57 -0
  97. package/msg/fo.mjs +57 -0
  98. package/msg/fr.js +57 -0
  99. package/msg/fr.mjs +57 -0
  100. package/msg/frr.js +57 -0
  101. package/msg/frr.mjs +57 -0
  102. package/msg/gl.js +57 -0
  103. package/msg/gl.mjs +57 -0
  104. package/msg/gn.js +57 -0
  105. package/msg/gn.mjs +57 -0
  106. package/msg/gor.js +57 -0
  107. package/msg/gor.mjs +57 -0
  108. package/msg/ha.js +57 -0
  109. package/msg/ha.mjs +57 -0
  110. package/msg/hak.js +57 -0
  111. package/msg/hak.mjs +57 -0
  112. package/msg/he.js +57 -0
  113. package/msg/he.mjs +57 -0
  114. package/msg/hi.js +57 -0
  115. package/msg/hi.mjs +57 -0
  116. package/msg/hr.js +57 -0
  117. package/msg/hr.mjs +57 -0
  118. package/msg/hrx.js +57 -0
  119. package/msg/hrx.mjs +57 -0
  120. package/msg/hsb.js +57 -0
  121. package/msg/hsb.mjs +57 -0
  122. package/msg/hu.js +57 -0
  123. package/msg/hu.mjs +57 -0
  124. package/msg/hy.js +57 -0
  125. package/msg/hy.mjs +57 -0
  126. package/msg/ia.js +57 -0
  127. package/msg/ia.mjs +57 -0
  128. package/msg/id.js +57 -0
  129. package/msg/id.mjs +57 -0
  130. package/msg/ig.js +57 -0
  131. package/msg/ig.mjs +57 -0
  132. package/msg/inh.js +57 -0
  133. package/msg/inh.mjs +57 -0
  134. package/msg/is.js +57 -0
  135. package/msg/is.mjs +57 -0
  136. package/msg/it.js +57 -0
  137. package/msg/it.mjs +57 -0
  138. package/msg/ja.js +57 -0
  139. package/msg/ja.mjs +57 -0
  140. package/msg/ka.js +57 -0
  141. package/msg/ka.mjs +57 -0
  142. package/msg/kab.js +57 -0
  143. package/msg/kab.mjs +57 -0
  144. package/msg/kbd-cyrl.js +57 -0
  145. package/msg/kbd-cyrl.mjs +57 -0
  146. package/msg/km.js +57 -0
  147. package/msg/km.mjs +57 -0
  148. package/msg/kn.js +57 -0
  149. package/msg/kn.mjs +57 -0
  150. package/msg/ko.js +57 -0
  151. package/msg/ko.mjs +57 -0
  152. package/msg/ksh.js +57 -0
  153. package/msg/ksh.mjs +57 -0
  154. package/msg/ku-latn.js +57 -0
  155. package/msg/ku-latn.mjs +57 -0
  156. package/msg/ky.js +57 -0
  157. package/msg/ky.mjs +57 -0
  158. package/msg/la.js +57 -0
  159. package/msg/la.mjs +57 -0
  160. package/msg/lb.js +57 -0
  161. package/msg/lb.mjs +57 -0
  162. package/msg/lki.js +57 -0
  163. package/msg/lki.mjs +57 -0
  164. package/msg/lo.js +57 -0
  165. package/msg/lo.mjs +57 -0
  166. package/msg/lrc.js +57 -0
  167. package/msg/lrc.mjs +57 -0
  168. package/msg/lt.js +57 -0
  169. package/msg/lt.mjs +57 -0
  170. package/msg/lv.js +57 -0
  171. package/msg/lv.mjs +57 -0
  172. package/msg/mg.js +57 -0
  173. package/msg/mg.mjs +57 -0
  174. package/msg/mk.js +57 -0
  175. package/msg/mk.mjs +57 -0
  176. package/msg/ml.js +57 -0
  177. package/msg/ml.mjs +57 -0
  178. package/msg/mnw.js +57 -0
  179. package/msg/mnw.mjs +57 -0
  180. package/msg/ms.js +57 -0
  181. package/msg/ms.mjs +57 -0
  182. package/msg/my.js +57 -0
  183. package/msg/my.mjs +57 -0
  184. package/msg/mzn.js +57 -0
  185. package/msg/mzn.mjs +57 -0
  186. package/msg/nb.js +57 -0
  187. package/msg/nb.mjs +57 -0
  188. package/msg/ne.js +57 -0
  189. package/msg/ne.mjs +57 -0
  190. package/msg/nl.js +57 -0
  191. package/msg/nl.mjs +57 -0
  192. package/msg/oc.js +57 -0
  193. package/msg/oc.mjs +57 -0
  194. package/msg/olo.js +57 -0
  195. package/msg/olo.mjs +57 -0
  196. package/msg/pa.js +57 -0
  197. package/msg/pa.mjs +57 -0
  198. package/msg/pl.js +57 -0
  199. package/msg/pl.mjs +57 -0
  200. package/msg/pms.js +57 -0
  201. package/msg/pms.mjs +57 -0
  202. package/msg/ps.js +57 -0
  203. package/msg/ps.mjs +57 -0
  204. package/msg/pt-br.js +57 -0
  205. package/msg/pt-br.mjs +57 -0
  206. package/msg/pt.js +57 -0
  207. package/msg/pt.mjs +57 -0
  208. package/msg/ro.js +57 -0
  209. package/msg/ro.mjs +57 -0
  210. package/msg/ru.js +57 -0
  211. package/msg/ru.mjs +57 -0
  212. package/msg/sc.js +57 -0
  213. package/msg/sc.mjs +57 -0
  214. package/msg/sco.js +57 -0
  215. package/msg/sco.mjs +57 -0
  216. package/msg/sd.js +57 -0
  217. package/msg/sd.mjs +57 -0
  218. package/msg/shn.js +57 -0
  219. package/msg/shn.mjs +57 -0
  220. package/msg/si.js +57 -0
  221. package/msg/si.mjs +57 -0
  222. package/msg/sk.js +57 -0
  223. package/msg/sk.mjs +57 -0
  224. package/msg/skr-arab.js +57 -0
  225. package/msg/skr-arab.mjs +57 -0
  226. package/msg/sl.js +57 -0
  227. package/msg/sl.mjs +57 -0
  228. package/msg/smn.js +57 -0
  229. package/msg/smn.mjs +57 -0
  230. package/msg/sq.js +57 -0
  231. package/msg/sq.mjs +57 -0
  232. package/msg/sr-latn.js +57 -0
  233. package/msg/sr-latn.mjs +57 -0
  234. package/msg/sr.js +57 -0
  235. package/msg/sr.mjs +57 -0
  236. package/msg/sv.js +57 -0
  237. package/msg/sv.mjs +57 -0
  238. package/msg/sw.js +57 -0
  239. package/msg/sw.mjs +57 -0
  240. package/msg/ta.js +57 -0
  241. package/msg/ta.mjs +57 -0
  242. package/msg/tcy.js +57 -0
  243. package/msg/tcy.mjs +57 -0
  244. package/msg/tdd.js +57 -0
  245. package/msg/tdd.mjs +57 -0
  246. package/msg/te.js +57 -0
  247. package/msg/te.mjs +57 -0
  248. package/msg/th.js +57 -0
  249. package/msg/th.mjs +57 -0
  250. package/msg/ti.js +57 -0
  251. package/msg/ti.mjs +57 -0
  252. package/msg/tl.js +57 -0
  253. package/msg/tl.mjs +57 -0
  254. package/msg/tlh.js +57 -0
  255. package/msg/tlh.mjs +57 -0
  256. package/msg/tr.js +57 -0
  257. package/msg/tr.mjs +57 -0
  258. package/msg/ug-arab.js +57 -0
  259. package/msg/ug-arab.mjs +57 -0
  260. package/msg/uk.js +57 -0
  261. package/msg/uk.mjs +57 -0
  262. package/msg/ur.js +57 -0
  263. package/msg/ur.mjs +57 -0
  264. package/msg/uz.js +57 -0
  265. package/msg/uz.mjs +57 -0
  266. package/msg/vi.js +57 -0
  267. package/msg/vi.mjs +57 -0
  268. package/msg/xmf.js +57 -0
  269. package/msg/xmf.mjs +57 -0
  270. package/msg/yo.js +57 -0
  271. package/msg/yo.mjs +57 -0
  272. package/msg/zgh.js +57 -0
  273. package/msg/zgh.mjs +57 -0
  274. package/msg/zh-hans.js +57 -0
  275. package/msg/zh-hans.mjs +57 -0
  276. package/msg/zh-hant.js +57 -0
  277. package/msg/zh-hant.mjs +57 -0
  278. package/package.json +1 -1
  279. package/core/keyboard_nav/navigation_policies/block_comment_navigation_policy.d.ts +0 -63
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Raspberry Pi Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { BlockSvg } from './block_svg.js';
7
+ import { RenderedConnection } from './blockly.js';
8
+ import type { Input } from './inputs/input.js';
9
+ import { Verbosity } from './utils/aria.js';
10
+ /**
11
+ * Prepositions to use when describing the relationship between two blocks based
12
+ * on their connection types.
13
+ */
14
+ export declare enum ConnectionPreposition {
15
+ UNKNOWN = 0,
16
+ BEFORE = 1,
17
+ AFTER = 2,
18
+ AROUND = 3,
19
+ INSIDE = 4
20
+ }
21
+ /**
22
+ * Returns an ARIA representation of the specified block.
23
+ *
24
+ * The returned label will contain a complete context of the block, including:
25
+ * - Whether it begins a block stack or statement input stack.
26
+ * - Its constituent editable and non-editable fields.
27
+ * - Properties, including: disabled, collapsed, replaceable (a shadow), etc.
28
+ * - Its parent toolbox category.
29
+ * - Whether it has inputs.
30
+ *
31
+ * Beyond this, the returned label is specifically assembled with commas in
32
+ * select locations with the intention of better 'prosody' in the screen reader
33
+ * readouts since there's a lot of information being shared with the user. The
34
+ * returned label also places more important information earlier in the label so
35
+ * that the user gets the most important context as soon as possible in case
36
+ * they wish to stop readout early.
37
+ *
38
+ * The returned label will be specialized based on whether the block is part of a
39
+ * flyout.
40
+ *
41
+ * @internal
42
+ * @param block The block for which an ARIA representation should be created.
43
+ * @param verbosity How much detail to include in the description.
44
+ * @returns The ARIA representation for the specified block.
45
+ */
46
+ export declare function computeAriaLabel(block: BlockSvg, verbosity?: Verbosity): string;
47
+ /**
48
+ * Sets the ARIA role and role description for the specified block, accounting
49
+ * for whether the block is part of a flyout.
50
+ *
51
+ * @internal
52
+ * @param block The block to set ARIA role and roledescription attributes on.
53
+ */
54
+ export declare function configureAriaRole(block: BlockSvg): void;
55
+ /**
56
+ * Returns a list of ARIA labels for the 'field row' for the specified Input.
57
+ *
58
+ * 'Field row' essentially means the horizontal run of readable fields that
59
+ * precede the Input. Together, these provide the domain context for the input,
60
+ * particularly in the context of connections. In some cases, there may not be
61
+ * any readable fields immediately prior to the Input. In that case, if the
62
+ * `lookback` attribute is specified, all of the fields on the row immediately
63
+ * above the Input will be used instead.
64
+ *
65
+ * @internal
66
+ * @param input The Input to compute a description/context label for.
67
+ * @param lookback If true, will use labels for fields on the previous row if
68
+ * the given input's row has no fields itself.
69
+ * @returns A list of labels for fields on the same row (or previous row, if
70
+ * lookback is specified) as the given input.
71
+ */
72
+ export declare function computeFieldRowLabel(input: Input, lookback: boolean, verbosity?: Verbosity): string[];
73
+ /**
74
+ * Returns a list of accessibility labels for fields and inputs on a block.
75
+ * Each entry in the returned array corresponds to one of: (a) a label for a
76
+ * continuous run of non-interactable fields, (b) a label for an editable field,
77
+ * (c) a label for an input. When an input contains nested blocks/fields/inputs,
78
+ * their contents are returned as a single item in the array per top-level
79
+ * input.
80
+ *
81
+ * @internal
82
+ * @param block The block to retrieve a list of field/input labels for.
83
+ * @returns A list of field/input labels for the given block.
84
+ */
85
+ export declare function getInputLabels(block: BlockSvg, verbosity?: Verbosity): string[];
86
+ /**
87
+ * Returns a subset of labels for inputs on the given block, ending at the
88
+ * specified input.
89
+ *
90
+ * The subset is determined based on the input type:
91
+ * - For non-statement inputs, only the label for the given input is returned.
92
+ * - For statement inputs, labels are collected from the start of the current
93
+ * statement section up to and including the given input. A statement section
94
+ * begins immediately after the previous statement input, or at the start of
95
+ * the block if none exists.
96
+ *
97
+ * @internal
98
+ * @param block The block to retrieve a list of field/input labels for.
99
+ * @param input The input that defines the end of the subset.
100
+ * @returns A list of field/input labels for the given block.
101
+ */
102
+ export declare function getInputLabelsSubset(block: BlockSvg, input: Input, verbosity?: Verbosity): string[];
103
+ /**
104
+ * Returns a translated string describing an in-progress move of a block to a new
105
+ * connection, suitable for announcement on the ARIA live region. The returned string
106
+ * will be assembled based on the types of the local and neighbour connections and
107
+ * the presence of any readable fields on the block's inputs. If multiple potential
108
+ * candidate connections are present, additional context will be included in the
109
+ * returned string to help disambiguate between them.
110
+ *
111
+ * @param local The moving side of the candidate connection pair
112
+ * @param neighbour The target side of the candidate connection pair
113
+ * @param disambiguationPolicy A function that determines whether it's useful to
114
+ * include parent input labels for disambiguation.
115
+ * @param isMoveStart Whether this announcement is for the start of a move. If false,
116
+ * skip announcing the block label since it should have already been announced.
117
+ */
118
+ export declare function computeMoveLabel(local: RenderedConnection, neighbour: RenderedConnection, disambiguationPolicy: (forLocal: boolean) => boolean, isMoveStart?: boolean): string;
119
+ //# sourceMappingURL=block_aria_composer.d.ts.map
@@ -28,6 +28,7 @@ import { IIcon } from './interfaces/i_icon.js';
28
28
  import { RenderedConnection } from './rendered_connection.js';
29
29
  import type { IPathObject } from './renderers/common/i_path_object.js';
30
30
  import type { BlockStyle } from './theme.js';
31
+ import * as aria from './utils/aria.js';
31
32
  import { Coordinate } from './utils/coordinate.js';
32
33
  import { Rect } from './utils/rect.js';
33
34
  import { FlyoutItemInfo } from './utils/toolbox.js';
@@ -734,7 +735,7 @@ export declare class BlockSvg extends Block implements IBoundedElement, IContext
734
735
  * main workspace. If this block has a single full-block field, that field
735
736
  * will be focused. Otherwise, this is a no-op.
736
737
  */
737
- performAction(): void;
738
+ performAction(e?: KeyboardEvent): void;
738
739
  /**
739
740
  * Returns a set of all of the parent blocks of the given block.
740
741
  *
@@ -756,5 +757,24 @@ export declare class BlockSvg extends Block implements IBoundedElement, IContext
756
757
  * @internal
757
758
  */
758
759
  getRowId(): string;
760
+ /**
761
+ * Updates the ARIA label, role and roledescription for this block.
762
+ */
763
+ private recomputeAriaAttributes;
764
+ /**
765
+ * Returns a description of this block suitable for screenreaders or use in
766
+ * ARIA attributes.
767
+ *
768
+ * @param verbosity How much detail to include in the description.
769
+ * @returns An accessibility description of this block.
770
+ */
771
+ getAriaLabel(verbosity: aria.Verbosity): string;
772
+ /**
773
+ * Count the number of blocks in this stack (connected by next connections)
774
+ * and return a label to describe it. Uses the standard label if there is only one block.
775
+ *
776
+ * @internal
777
+ */
778
+ getStackBlocksCountLabel(): string;
759
779
  }
760
780
  //# sourceMappingURL=block_svg.d.ts.map
package/core/blockly.d.ts CHANGED
@@ -270,8 +270,8 @@ export declare const VARIABLE_DYNAMIC_CATEGORY_NAME: string;
270
270
  */
271
271
  export declare const PROCEDURE_CATEGORY_NAME: string;
272
272
  export * from './interfaces/i_navigation_policy.js';
273
- export * from './keyboard_nav/navigation_policies/block_comment_navigation_policy.js';
274
273
  export * from './keyboard_nav/navigation_policies/block_navigation_policy.js';
274
+ export * from './keyboard_nav/navigation_policies/bubble_navigation_policy.js';
275
275
  export * from './keyboard_nav/navigation_policies/comment_bar_button_navigation_policy.js';
276
276
  export * from './keyboard_nav/navigation_policies/comment_editor_navigation_policy.js';
277
277
  export * from './keyboard_nav/navigation_policies/connection_navigation_policy.js';
@@ -5,6 +5,8 @@
5
5
  */
6
6
  import type { BlocklyOptions } from '../blockly_options.js';
7
7
  import { Abstract as AbstractEvent } from '../events/events_abstract.js';
8
+ import type { IFocusableNode } from '../interfaces/i_focusable_node.js';
9
+ import type { IHasBubble } from '../interfaces/i_has_bubble.js';
8
10
  import { Options } from '../options.js';
9
11
  import { Coordinate } from '../utils/coordinate.js';
10
12
  import type { Rect } from '../utils/rect.js';
@@ -18,6 +20,7 @@ export declare class MiniWorkspaceBubble extends Bubble {
18
20
  readonly workspace: WorkspaceSvg;
19
21
  protected anchor: Coordinate;
20
22
  protected ownerRect?: Rect | undefined;
23
+ protected owner?: (IHasBubble & IFocusableNode) | undefined;
21
24
  /**
22
25
  * The minimum amount of change to the mini workspace view to trigger
23
26
  * resizing the bubble.
@@ -38,7 +41,7 @@ export declare class MiniWorkspaceBubble extends Bubble {
38
41
  */
39
42
  private autoLayout;
40
43
  /** @internal */
41
- constructor(workspaceOptions: BlocklyOptions, workspace: WorkspaceSvg, anchor: Coordinate, ownerRect?: Rect | undefined);
44
+ constructor(workspaceOptions: BlocklyOptions, workspace: WorkspaceSvg, anchor: Coordinate, ownerRect?: Rect | undefined, owner?: (IHasBubble & IFocusableNode) | undefined);
42
45
  dispose(): void;
43
46
  /** @internal */
44
47
  getWorkspace(): WorkspaceSvg;
@@ -3,6 +3,8 @@
3
3
  * Copyright 2023 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
+ import type { IFocusableNode } from '../interfaces/i_focusable_node.js';
7
+ import type { IHasBubble } from '../interfaces/i_has_bubble.js';
6
8
  import { Coordinate } from '../utils/coordinate.js';
7
9
  import { Rect } from '../utils/rect.js';
8
10
  import { WorkspaceSvg } from '../workspace_svg.js';
@@ -15,8 +17,9 @@ export declare class TextBubble extends Bubble {
15
17
  readonly workspace: WorkspaceSvg;
16
18
  protected anchor: Coordinate;
17
19
  protected ownerRect?: Rect | undefined;
20
+ protected owner?: (IHasBubble & IFocusableNode) | undefined;
18
21
  private paragraph;
19
- constructor(text: string, workspace: WorkspaceSvg, anchor: Coordinate, ownerRect?: Rect | undefined);
22
+ constructor(text: string, workspace: WorkspaceSvg, anchor: Coordinate, ownerRect?: Rect | undefined, owner?: (IHasBubble & IFocusableNode) | undefined);
20
23
  /** @returns the current text of this text bubble. */
21
24
  getText(): string;
22
25
  /** Sets the current text of this text bubble, and updates the display. */
@@ -6,7 +6,6 @@
6
6
  import type { BlockSvg } from '../block_svg.js';
7
7
  import type { IDragStrategy } from '../interfaces/i_draggable.js';
8
8
  import { DragDisposition } from '../interfaces/i_draggable.js';
9
- import { Direction } from '../keyboard_nav/keyboard_mover.js';
10
9
  import type { RenderedConnection } from '../rendered_connection.js';
11
10
  import { Coordinate } from '../utils.js';
12
11
  /** Represents a valid pair of connections between the dragging block and a block on the workspace. */
@@ -57,6 +56,21 @@ export declare class BlockDragStrategy implements IDragStrategy {
57
56
  * and return a newly instantiated block when e.g. dragging from a flyout.
58
57
  */
59
58
  protected getTargetBlock(): BlockSvg;
59
+ /**
60
+ * Announces a move on the ARIA live region for assistive technologies.
61
+ *
62
+ * @param isMoveStart Whether this announcement is for the start of a move. If false,
63
+ * skip announcing the block label since it should have already been announced at the
64
+ * start of the move.
65
+ */
66
+ private announceMove;
67
+ /**
68
+ * Checks if there are multiple compatible connections for the specified side of the pair.
69
+ *
70
+ * @param forLocal Whether we are considering the local or neighbour side of the pair
71
+ * @returns True if there are multiple compatible connections, false otherwise
72
+ */
73
+ private hasMultipleCompatibleConnections;
60
74
  /**
61
75
  * Handles any setup for starting the drag, including disconnecting the block
62
76
  * from any parent blocks.
@@ -141,6 +155,14 @@ export declare class BlockDragStrategy implements IDragStrategy {
141
155
  * compatible type (input, output, etc) and connection check.
142
156
  */
143
157
  private getConnectionCandidate;
158
+ /**
159
+ * Returns the closest connection candidate for the given block.
160
+ *
161
+ * @param block The block to find a connection for.
162
+ * @param delta The distance the block has traveled since dragging began.
163
+ * @returns The closest available connection candidate, if any.
164
+ */
165
+ private getClosestCandidate;
144
166
  /**
145
167
  * Get the radius to use when searching for a nearby valid connection.
146
168
  */
@@ -169,10 +191,30 @@ export declare class BlockDragStrategy implements IDragStrategy {
169
191
  /**
170
192
  * Get the nearest valid candidate connection in traversal order.
171
193
  *
172
- * @param direction The cardinal direction in which the block is being moved.
194
+ * @param delta The distance the block has moved since this drag began.
173
195
  * @returns A candidate connection and radius, or null if none was found.
174
196
  */
175
- findTraversalCandidate(direction: Direction): ConnectionCandidate | null;
197
+ findTraversalCandidate(delta: Coordinate): ConnectionCandidate | null;
198
+ /**
199
+ * Returns whether or not the given block is at a terminal position (start or
200
+ * end) of the blocks on the workspace. This helps distinguish between a block
201
+ * that is at the end of the line because all valid connections have been
202
+ * visited and the proposed constrained move destination is now to drop it on
203
+ * the workspace as a top-level block (in which case it will be in a terminal
204
+ * position), and a block that just entered move mode as a top-level block,
205
+ * and should therefore still be able to move to another connection point
206
+ * even if looping is disabled.
207
+ *
208
+ * @param block The block to check.
209
+ * @param direction The current dragging direction.
210
+ * @returns True if the block is at the start or end of its possible positions
211
+ * on the workspace.
212
+ */
213
+ private isInTerminalPosition;
214
+ /**
215
+ * Converts a connection pair to a connection candidate with a default
216
+ * distance of 0.
217
+ */
176
218
  private pairToCandidate;
177
219
  /**
178
220
  * Returns the cardinal direction that the block being dragged would have to
package/core/field.d.ts CHANGED
@@ -200,22 +200,20 @@ export declare abstract class Field<T = any> implements IKeyboardAccessible, IRe
200
200
  * Gets an ARIA-friendly label representation of this field's value.
201
201
  *
202
202
  * Note that implementations should generally always override this value to
203
- * ensure a non-null value is returned since the default implementation relies
204
- * on 'getValue' which may return null, and a null return value for this
203
+ * ensure a non-null value is returned. The default implementation relies on
204
+ * 'getText' which may return an empty string. A null return value from this
205
205
  * function will prompt ARIA label generation to skip the field's value
206
- * entirely when there may be a better contextual placeholder to use, instead,
207
- * specific to the field.
206
+ * entirely when there may be a better contextual placeholder to use isstead.
208
207
  *
209
- * For example, a text input field may have a value of null when empty. To
210
- * avoid hiding this field from screen reader, implementations should ensure
211
- * that if the value is null, this function would return an appropriate,
212
- * localized value such as "empty text".
208
+ * For example, to avoid hiding an empty text input field from screen reader,
209
+ * implementations should ensure that if the text is an empty string, this
210
+ * function would return an appropriate, localized value such as "empty text".
213
211
  *
214
212
  * Implementations are responsible for, and encouraged to, return a localized
215
213
  * version of the ARIA representation of the field's value.
216
214
  *
217
- * @returns An ARIA representation of the field's value, or null if no value
218
- * is currently defined or known for the field.
215
+ * @returns An ARIA representation of the field's text, or null if no text is
216
+ * currently defined or known for the field.
219
217
  */
220
218
  getAriaValue(): string | null;
221
219
  /**
@@ -237,11 +235,9 @@ export declare abstract class Field<T = any> implements IKeyboardAccessible, IRe
237
235
  * checkboxes represent their checked/non-checked status (i.e. value) through
238
236
  * a separate ARIA property.
239
237
  *
240
- * It's possible this returns an empty string if the field doesn't supply type
241
- * or value information for certain cases (such as a null value). This can
242
- * lead to the field being potentially COMPLETELY HIDDEN for screen reader
243
- * navigation so it's crucial for implementations to ensure a non-empty value
244
- * is returned here.
238
+ * It's not expected that this method, under normal operations, returns an empty
239
+ * string. If the field's value is empty then it will return a localized
240
+ * placeholder indicating that its value is empty.
245
241
  *
246
242
  * @param includeTypeInfo Whether to include the field's type information in
247
243
  * the returned label, if available.
@@ -282,9 +278,11 @@ export declare abstract class Field<T = any> implements IKeyboardAccessible, IRe
282
278
  */
283
279
  protected createBorderRect_(): void;
284
280
  /**
285
- * Create a field text element. Not to be overridden by subclasses. Instead
281
+ * Create a field text element. Not to be overridden by subclasses. Instead,
286
282
  * modify the result of the function inside initView, or create a separate
287
- * function to call.
283
+ * function to call. Aria state is hidden; use the aria label for the field
284
+ * and/or containing block to expose content to screen readers. Text content
285
+ * for custom blocks can be set after creation.
288
286
  */
289
287
  protected createTextElement_(): void;
290
288
  /**
@@ -263,6 +263,29 @@ export declare abstract class FieldInput<T extends InputTypes> extends Field<str
263
263
  * @returns The value to store.
264
264
  */
265
265
  protected getValueFromEditorText_(text: string): any;
266
+ /**
267
+ * Gets an ARIA-friendly label representation of this field's type.
268
+ *
269
+ * Implementations are responsible for, and encouraged to, return a localized
270
+ * version of the ARIA representation of the field's type.
271
+ *
272
+ * @returns An ARIA representation of the field's type or a default if it is
273
+ * unspecified.
274
+ */
275
+ getAriaTypeName(): string | null;
276
+ /**
277
+ * Gets an ARIA-friendly label representation of this field's value.
278
+ *
279
+ * Implementations are responsible for, and encouraged to, return a localized
280
+ * version of the ARIA representation of the field's value.
281
+ *
282
+ * @returns An ARIA representation of the field's text.
283
+ */
284
+ getAriaValue(): string | null;
285
+ /**
286
+ * Recomputes the ARIA role and label for this field.
287
+ */
288
+ private recomputeAriaContext;
266
289
  }
267
290
  /**
268
291
  * Config options for the input field.
@@ -7,11 +7,15 @@ import type { IFocusableNode } from './interfaces/i_focusable_node.js';
7
7
  import type { IFocusableTree } from './interfaces/i_focusable_tree.js';
8
8
  /**
9
9
  * Type declaration for returning focus to FocusManager upon completing an
10
- * ephemeral UI flow (such as a dialog).
10
+ * ephemeral UI flow (such as a dialog). Normally, the FocusManager will refocus
11
+ * the previously-focused element. If callers do not wish for the FocusManager
12
+ * to do so, they may call this method with `restoreFocus` set to false to
13
+ * prevent automatic refocusing and leave focus where it is.
14
+ *
11
15
  *
12
16
  * See FocusManager.takeEphemeralFocus for more details.
13
17
  */
14
- export type ReturnEphemeralFocus = () => void;
18
+ export type ReturnEphemeralFocus = (restoreFocus?: boolean) => void;
15
19
  /**
16
20
  * A per-page singleton that manages Blockly focus across one or more
17
21
  * IFocusableTrees, and bidirectionally synchronizes this focus with the DOM.
@@ -56,6 +60,20 @@ export declare class FocusManager {
56
60
  private lockFocusStateChanges;
57
61
  private recentlyLostAllFocus;
58
62
  private isUpdatingFocusedNode;
63
+ /**
64
+ * Root element in which popovers (WidgetDiv, DropDownDiv) currently live.
65
+ */
66
+ private popoverFocusRoot?;
67
+ /**
68
+ * Set of callbacks to invoke if the popover focus root loses focus.
69
+ */
70
+ private popoverFocusLossHandlers;
71
+ /**
72
+ * Handler for focusout in the popover focus root that selectively
73
+ * invokes the popover focus loss handlers if focus has truly transitioned
74
+ * outside of the focus root, and not e.g. to a different popover.
75
+ */
76
+ private popoverFocusOutHandler;
59
77
  constructor(addGlobalEventListener: (type: string, listener: EventListener) => void);
60
78
  /**
61
79
  * Registers a new IFocusableTree for automatic focus management.
@@ -260,6 +278,33 @@ export declare class FocusManager {
260
278
  * but may change across page loads.
261
279
  */
262
280
  static getFocusManager(): FocusManager;
281
+ /**
282
+ * Sets the current popover focus root. Generally this is active
283
+ * workspace's injection div or the explicitly specified parent container for
284
+ * the WidgetDiv, DropDownDiv, etc.
285
+ *
286
+ * @internal
287
+ * @param newRoot The new element that contains all popovers.
288
+ */
289
+ setPopoverFocusRoot(newRoot: HTMLElement): void;
290
+ /**
291
+ * Registers a callback to be invoked if the popover focus root loses
292
+ * focus. This should only be called by popovers that need to react to
293
+ * focus changes by e.g. hiding themselves and resigning ephemeral focus.
294
+ *
295
+ * @internal
296
+ * @param handler A callback function.
297
+ */
298
+ registerPopoverFocusLossHandler(handler: () => void): void;
299
+ /**
300
+ * Unregisters a previously-registered popover focus loss handler. This
301
+ * should only be invoked by popovers when they no longer need to be
302
+ * notified of focus loss, typically when they are hidden.
303
+ *
304
+ * @internal
305
+ * @param handler A previously-registered callback function.
306
+ */
307
+ unregisterPopoverFocusLossHandler(handler: () => void): void;
263
308
  }
264
309
  /** Convenience function for FocusManager.getFocusManager. */
265
310
  export declare function getFocusManager(): FocusManager;
@@ -14,6 +14,7 @@ import type { BlockSvg } from '../block_svg.js';
14
14
  import type { Connection } from '../connection.js';
15
15
  import { ConnectionType } from '../connection_type.js';
16
16
  import type { Field } from '../field.js';
17
+ import { Verbosity } from '../utils/aria.js';
17
18
  import { Align } from './align.js';
18
19
  import { inputTypes } from './input_types.js';
19
20
  /** Class for an input with optional fields. */
@@ -149,5 +150,19 @@ export declare class Input {
149
150
  * @internal
150
151
  */
151
152
  getRowId(): string;
153
+ /**
154
+ * Returns an accessibility label describing this input, including the labels
155
+ * of any fields on the input and the labels of any connected blocks, to help
156
+ * disambiguate this input from others on the same block.
157
+ *
158
+ * @internal
159
+ */
160
+ getLabel(verbosity?: Verbosity): string;
161
+ /**
162
+ * Returns the index of this input on its source block.
163
+ *
164
+ * @internal
165
+ */
166
+ getIndex(): number;
152
167
  }
153
168
  //# sourceMappingURL=input.d.ts.map
@@ -97,8 +97,10 @@ export interface IFocusableNode {
97
97
  * Optional method invoked when this node has focus and the user acts on it by
98
98
  * pressing Enter or Space. Behavior should generally be similar to the node
99
99
  * being clicked on.
100
+ *
101
+ * @param e The event that triggered this action, if any.
100
102
  */
101
- performAction?(): void;
103
+ performAction?(e?: Event): void;
102
104
  }
103
105
  /**
104
106
  * Determines whether the provided object fulfills the contract of
@@ -1,8 +1,3 @@
1
- /**
2
- * @license
3
- * Copyright 2026 Raspberry Pi Foundation
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
1
  import type { IDraggable } from '../interfaces/i_draggable.js';
7
2
  /**
8
3
  * Cardinal directions in which a move can proceed.
@@ -113,6 +108,22 @@ export declare class KeyboardMover {
113
108
  * Repositions the move indicator to the corner of the item being moved.
114
109
  */
115
110
  private repositionMoveIndicator;
111
+ /**
112
+ * Returns a bounding box used for positioning the move indicator on a block.
113
+ * Blocks require special treatment because `BlockSvg.getBoundingRectangle()`
114
+ * includes the bounds of nested and subsequent blocks. Since the move
115
+ * indicator is positioned at the top right corner of the bounds, this can
116
+ * result in it appearing to float in empty space when e.g. a small block has
117
+ * a much wider block nested inside a statement input. BlockSvg also provides
118
+ * `getBoundingRectangleWithoutChildren()`, which addresses that case, but is
119
+ * insufficient because in the case of nested *value* blocks in a row, the
120
+ * child blocks' bounds should contribute to the bounding box.
121
+ *
122
+ * @param block The block to retrieve an adjusted bounding box for.
123
+ * @returns A bounding box for the given block whose top-right corner
124
+ * corresponds to the maximum visual extent of the given block's row.
125
+ */
126
+ private positionForBlockMoveIndicator;
116
127
  /**
117
128
  * Common clean-up for finish/abort run before terminating the move.
118
129
  */
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Bubble } from '../../bubbles/bubble.js';
7
+ import type { IFocusableNode } from '../../interfaces/i_focusable_node.js';
8
+ import type { INavigationPolicy } from '../../interfaces/i_navigation_policy.js';
9
+ /**
10
+ * Set of rules controlling keyboard navigation from a Bubble.
11
+ */
12
+ export declare class BubbleNavigationPolicy implements INavigationPolicy<Bubble> {
13
+ /**
14
+ * Returns the first child of the given bubble.
15
+ *
16
+ * @param _current The bubble to return the first child of.
17
+ * @returns Null.
18
+ */
19
+ getFirstChild(_current: Bubble): IFocusableNode | null;
20
+ /**
21
+ * Returns the parent of the given bubble.
22
+ *
23
+ * @param current The bubble to return the parent of.
24
+ * @returns The parent block of the given bubble.
25
+ */
26
+ getParent(current: Bubble): IFocusableNode | null;
27
+ /**
28
+ * Returns the next peer node of the given bubble.
29
+ *
30
+ * @param current The bubble to find the following element of.
31
+ * @returns The next navigable item on the bubble's icon's parent block.
32
+ */
33
+ getNextSibling(current: Bubble): IFocusableNode | null;
34
+ /**
35
+ * Returns the previous peer node of the given bubble.
36
+ *
37
+ * @param current The bubble to find the preceding element of.
38
+ * @returns The previous navigable item on the bubble's icon's parent block.
39
+ */
40
+ getPreviousSibling(current: Bubble): IFocusableNode | null;
41
+ /**
42
+ * Returns the row ID of the given bubble.
43
+ *
44
+ * @param current The bubble to retrieve the row ID of.
45
+ * @returns The row ID of the given bubble.
46
+ */
47
+ getRowId(current: Bubble): string;
48
+ /**
49
+ * Returns whether or not the given bubble can be navigated to.
50
+ *
51
+ * @param current The instance to check for navigability.
52
+ * @returns True if the given bubble can be focused.
53
+ */
54
+ isNavigable(current: Bubble): boolean;
55
+ /**
56
+ * Returns whether the given object can be navigated from by this policy.
57
+ *
58
+ * @param current The object to check if this policy applies to.
59
+ * @returns True if the object is an Bubble.
60
+ */
61
+ isApplicable(current: any): current is Bubble;
62
+ }
63
+ //# sourceMappingURL=bubble_navigation_policy.d.ts.map
@@ -13,10 +13,10 @@ export declare class IconNavigationPolicy implements INavigationPolicy<Icon> {
13
13
  /**
14
14
  * Returns the first child of the given icon.
15
15
  *
16
- * @param current The icon to return the first child of.
16
+ * @param _current The icon to return the first child of.
17
17
  * @returns Null.
18
18
  */
19
- getFirstChild(current: Icon): IFocusableNode | null;
19
+ getFirstChild(_current: Icon): IFocusableNode | null;
20
20
  /**
21
21
  * Returns the parent of the given icon.
22
22
  *
@@ -3,8 +3,8 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { IFocusableNode } from '../../blockly.js';
7
6
  import type { IFlyout } from '../../interfaces/i_flyout.js';
7
+ import type { IFocusableNode } from '../../interfaces/i_focusable_node.js';
8
8
  import { Navigator } from './navigator.js';
9
9
  /**
10
10
  * Navigator that handles keyboard navigation within a flyout.
@@ -33,7 +33,9 @@ export declare enum names {
33
33
  NEXT_STACK = "next_stack",
34
34
  PREVIOUS_STACK = "previous_stack",
35
35
  INFORMATION = "information",
36
- PERFORM_ACTION = "perform_action"
36
+ PERFORM_ACTION = "perform_action",
37
+ DUPLICATE = "duplicate",
38
+ CLEANUP = "cleanup"
37
39
  }
38
40
  /**
39
41
  * Keyboard shortcut to hide chaff on escape.
@@ -102,6 +104,14 @@ export declare function registerStackNavigation(): void;
102
104
  * Registers keyboard shortcut to perform an action on the focused element.
103
105
  */
104
106
  export declare function registerPerformAction(): void;
107
+ /**
108
+ * Registers keyboard shortcut to duplicate a block or workspace comment.
109
+ */
110
+ export declare function registerDuplicate(): void;
111
+ /**
112
+ * Registers keyboard shortcut to clean up the workspace.
113
+ */
114
+ export declare function registerCleanup(): void;
105
115
  /**
106
116
  * Registers all default keyboard shortcut item. This should be called once per
107
117
  * instance of KeyboardShortcutRegistry.