cx 26.8.0 → 26.9.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 (52) hide show
  1. package/build/charts/Legend.d.ts +8 -1
  2. package/build/charts/Legend.d.ts.map +1 -1
  3. package/build/charts/Legend.js +8 -4
  4. package/build/data/index.d.ts +1 -0
  5. package/build/data/index.d.ts.map +1 -1
  6. package/build/data/index.js +1 -0
  7. package/build/jsx-dev-runtime.d.ts +2 -1
  8. package/build/jsx-dev-runtime.d.ts.map +1 -1
  9. package/build/svg/Svg.d.ts +9 -0
  10. package/build/svg/Svg.d.ts.map +1 -1
  11. package/build/svg/Svg.js +9 -1
  12. package/build/ui/index.d.ts +3 -2
  13. package/build/ui/index.d.ts.map +1 -1
  14. package/build/ui/index.js +1 -1
  15. package/build/util/DOM.d.ts.map +1 -1
  16. package/build/util/DOM.js +16 -4
  17. package/build/util/getActiveElement.d.ts +1 -1
  18. package/build/util/getActiveElement.d.ts.map +1 -1
  19. package/build/util/getActiveElement.js +14 -2
  20. package/build/widgets/form/TextArea.d.ts +4 -0
  21. package/build/widgets/form/TextArea.d.ts.map +1 -1
  22. package/build/widgets/form/TextArea.js +7 -1
  23. package/build/widgets/grid/Grid.d.ts +3 -2
  24. package/build/widgets/grid/Grid.d.ts.map +1 -1
  25. package/build/widgets/nav/MenuItem.js +2 -2
  26. package/build/widgets/overlay/Dropdown.d.ts +4 -4
  27. package/build/widgets/overlay/Dropdown.d.ts.map +1 -1
  28. package/build/widgets/overlay/Dropdown.js +82 -38
  29. package/build/widgets/overlay/Overlay.d.ts.map +1 -1
  30. package/build/widgets/overlay/Overlay.js +7 -3
  31. package/build/widgets/overlay/Window.d.ts.map +1 -1
  32. package/build/widgets/overlay/Window.js +2 -1
  33. package/dist/charts.js +10 -3
  34. package/dist/data.js +1 -0
  35. package/dist/manifest.js +869 -869
  36. package/dist/svg.js +13 -0
  37. package/dist/util.js +31 -9
  38. package/dist/widgets.js +139 -47
  39. package/package.json +1 -1
  40. package/src/charts/Legend.tsx +22 -2
  41. package/src/data/index.ts +31 -30
  42. package/src/jsx-dev-runtime.ts +2 -1
  43. package/src/svg/Svg.tsx +24 -1
  44. package/src/ui/index.ts +3 -6
  45. package/src/util/DOM.ts +15 -4
  46. package/src/util/getActiveElement.ts +16 -2
  47. package/src/widgets/form/TextArea.tsx +10 -1
  48. package/src/widgets/grid/Grid.tsx +3 -2
  49. package/src/widgets/nav/MenuItem.tsx +2 -2
  50. package/src/widgets/overlay/Dropdown.tsx +87 -27
  51. package/src/widgets/overlay/Overlay.tsx +5 -3
  52. package/src/widgets/overlay/Window.tsx +2 -1
package/src/svg/Svg.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  /** @jsxImportSource react */
2
+ import { StringProp } from "../ui/Prop";
2
3
  import { RenderingContext } from "../ui/RenderingContext";
3
4
  import { ResizeManager } from "../ui/ResizeManager";
4
5
  import { VDOM, Widget } from "../ui/Widget";
@@ -18,6 +19,15 @@ interface SvgInstance extends BoundedObjectInstance {
18
19
  }
19
20
 
20
21
  export interface SvgConfig extends BoundedObjectConfig {
22
+ /** ARIA role for the `svg` element. Defaults to `img` when `ariaLabel` is set. */
23
+ role?: StringProp;
24
+
25
+ /**
26
+ * Accessible name for the `svg` element. Setting it announces the drawing as a single graphic
27
+ * instead of as its individual shapes, which is also how a tagged PDF export tags it.
28
+ */
29
+ ariaLabel?: StringProp;
30
+
21
31
  /** Set to `true` to automatically calculate width based on the measured height and `aspectRatio`. */
22
32
  autoWidth?: boolean;
23
33
 
@@ -53,6 +63,16 @@ export class Svg extends BoundedObject<SvgConfig, SvgInstance> {
53
63
  super(config);
54
64
  }
55
65
 
66
+ declareData(...args: any[]) {
67
+ return super.declareData(
68
+ {
69
+ role: undefined,
70
+ ariaLabel: undefined,
71
+ },
72
+ ...args,
73
+ );
74
+ }
75
+
56
76
  initState(context: RenderingContext, instance: SvgInstance) {
57
77
  const size = {
58
78
  width: 0,
@@ -147,6 +167,9 @@ class SvgComponent extends VDOM.Component<SvgComponentProps> {
147
167
  const { instance, data, size, children, eventHandlers } = this.props;
148
168
  const { widget } = instance;
149
169
 
170
+ // An unnamed drawing is left alone: `role="img"` would hide its text and put nothing in its place.
171
+ const role = data.role ?? (data.ariaLabel ? "img" : undefined);
172
+
150
173
  const defs: any[] = [];
151
174
  for (const k in (instance as any).clipRects) {
152
175
  let cr = (instance as any).clipRects[k];
@@ -181,7 +204,7 @@ class SvgComponent extends VDOM.Component<SvgComponentProps> {
181
204
  {...eventHandlers}
182
205
  >
183
206
  {size.width > 0 && size.height > 0 && (
184
- <svg>
207
+ <svg role={role} aria-label={data.ariaLabel}>
185
208
  <defs>{defs}</defs>
186
209
  {children}
187
210
  </svg>
package/src/ui/index.ts CHANGED
@@ -43,9 +43,6 @@ export * from "./exprHelpers";
43
43
 
44
44
  //re-export computable here
45
45
  import { computable } from "../data/computable";
46
- import {
47
- createAccessorModelProxy,
48
- createModel,
49
- AccessorChain,
50
- } from "../data/createAccessorModelProxy";
51
- export { computable, createAccessorModelProxy, createModel, AccessorChain };
46
+ import { createAccessorModelProxy, createModel } from "../data/createAccessorModelProxy";
47
+ export { computable, createAccessorModelProxy, createModel };
48
+ export type { AccessorChain } from "../data/createAccessorModelProxy";
package/src/util/DOM.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isNumber } from "../util/isNumber";
2
+ import { getActiveElement } from "./getActiveElement";
2
3
 
3
4
  type ElementFilter = (el: Element, condition: (el: Element) => boolean) => Element | null;
4
5
 
@@ -51,11 +52,11 @@ export function closestParent(el: Element, condition: (el: any) => boolean): HTM
51
52
  }
52
53
 
53
54
  export function isFocused(el: Element): boolean {
54
- return document.activeElement == el;
55
+ return getActiveElement() == el;
55
56
  }
56
57
 
57
58
  export function isFocusedDeep(el: Element): boolean {
58
- return document.activeElement == el || (!!document.activeElement && el.contains(document.activeElement));
59
+ return isSelfOrDescendant(el, getActiveElement());
59
60
  }
60
61
 
61
62
  const focusableWithoutTabIndex = ["INPUT", "SELECT", "TEXTAREA", "A", "BUTTON"];
@@ -76,13 +77,23 @@ export function isFocusable(el: Element): el is HTMLElement {
76
77
  * @returns {Element}
77
78
  */
78
79
  export function getFocusedElement(): Element | null {
79
- return document.activeElement;
80
+ return getActiveElement();
80
81
  }
81
82
 
82
83
  export function isDescendant(el: Element, descEl: Element): boolean {
83
84
  return el.contains(descEl);
84
85
  }
85
86
 
87
+ //`descEl` may live in a different document than `el` (e.g. focus is inside a same-origin
88
+ //iframe) - Node.contains never crosses document boundaries, so walk out through each
89
+ //frame's <iframe> element in its parent document until we either cross into el's document
90
+ //or run out of ancestor frames.
86
91
  export function isSelfOrDescendant(el: Element, descEl: Element): boolean {
87
- return el == descEl || el.contains(descEl);
92
+ let node: Element | null | undefined = descEl;
93
+ while (node) {
94
+ if (el == node || el.contains(node)) return true;
95
+ let win: Window | null = node.ownerDocument?.defaultView;
96
+ node = win?.frameElement;
97
+ }
98
+ return false;
88
99
  }
@@ -1,4 +1,18 @@
1
1
  //IE sometimes returns null while other browsers always return document.body.
2
- export function getActiveElement(): Element {
3
- return document.activeElement ?? document.body;
2
+ export function getActiveElement(doc: Document = document): Element {
3
+ let active = doc.activeElement ?? doc.body;
4
+
5
+ //when focus is inside a same-origin iframe, `doc.activeElement` only reports the
6
+ //<iframe> element itself - drill into its own document to find the element that's
7
+ //actually focused there (recursively, in case of nested iframes)
8
+ if (active && active.tagName === "IFRAME") {
9
+ const iframe = active as HTMLIFrameElement;
10
+ let frameDoc = iframe.contentDocument;
11
+ if (frameDoc) {
12
+ const inner = getActiveElement(frameDoc);
13
+ return inner ?? active;
14
+ }
15
+ }
16
+
17
+ return active;
4
18
  }
@@ -16,8 +16,13 @@ import { stopPropagation } from "../../util/eventCallbacks";
16
16
  import { KeyCode } from "../../util/KeyCode";
17
17
  import { autoFocus } from "../autoFocus";
18
18
  import { getActiveElement } from "../../util/getActiveElement";
19
+ import { isString } from "../../util/isString";
19
20
  import { NumberProp } from "../../ui/Prop";
20
21
 
22
+ /**
23
+ * `trim` applies to the commit that ends the edit, not to intermediate `input` commits. Whitespace
24
+ * inside the text is never touched.
25
+ */
21
26
  export interface TextAreaConfig extends TextFieldConfig {
22
27
  /** Specifies the number of visible lines. */
23
28
  rows?: NumberProp;
@@ -199,8 +204,12 @@ class Input extends VDOM.Component<InputProps, InputState> {
199
204
  }
200
205
 
201
206
  if (instance.widget.reactOn.indexOf(change) != -1) {
202
- let value = inputValue || widget.emptyValue;
207
+ // Trimming on `input` would strip whitespace the user is still typing, so a trailing
208
+ // newline could never be entered.
209
+ let text = change != "input" && data.trim && isString(inputValue) ? inputValue.trim() : inputValue;
210
+ let value = text || widget.emptyValue;
203
211
  instance.set("value", value);
212
+ if (this.input && text != inputValue) this.input.value = text;
204
213
  }
205
214
  }
206
215
 
@@ -72,10 +72,11 @@ import DropDownIcon from "../icons/sort-asc";
72
72
  import { captureMouse2, getCursorPos } from "../overlay/captureMouse";
73
73
  import { tooltipMouseLeave, tooltipMouseMove } from "../overlay/tooltip-ops";
74
74
  import { createGridCellEditor } from "./createGridCellEditor";
75
- import { GridRow, GridRowComponent, GridRowConfig, GridRowInstance } from "./GridRow";
75
+ import { GridRow, GridRowComponent, GridRowInstance } from "./GridRow";
76
+ import type { GridRowConfig } from "./GridRow";
76
77
  import { Create, CreateConfig } from "../../util";
77
78
  import type { TreeAdapter } from "../../ui/adapter/TreeAdapter";
78
- export { GridRowConfig };
79
+ export type { GridRowConfig };
79
80
 
80
81
  export type GridFetchRecordsResult<T> = T[] | { records: T[]; lastPage?: boolean; totalRecordCount?: number };
81
82
 
@@ -385,7 +385,7 @@ class MenuItemComponent extends VDOM.Component<MenuItemComponentProps, MenuItemC
385
385
  debug(menuFlag, "MenuItem", "mouseLeave", this.el);
386
386
  this.clearAutoFocusTimer();
387
387
 
388
- if (widget.hoverToOpen && document.activeElement == this.el) unfocusElement(this.el!);
388
+ if (widget.hoverToOpen && getActiveElement() == this.el) unfocusElement(this.el!);
389
389
  }
390
390
 
391
391
  tooltipMouseLeave(e, this.props.instance, widget.tooltip);
@@ -486,7 +486,7 @@ class MenuItemComponent extends VDOM.Component<MenuItemComponentProps, MenuItemC
486
486
  let { widget } = this.props.instance;
487
487
  if (widget.dropdown) {
488
488
  oneFocusOut(this, this.el!, this.onFocusOut.bind(this));
489
- debug(menuFlag, "MenuItem", "focus", this.el, document.activeElement);
489
+ debug(menuFlag, "MenuItem", "focus", this.el, getActiveElement());
490
490
  this.clearAutoFocusTimer();
491
491
  if (widget.openOnFocus) this.openDropdown();
492
492
  }
@@ -5,6 +5,7 @@ import { Widget, VDOM } from "../../ui/Widget";
5
5
  import { calculateNaturalElementHeight } from "../../util/calculateNaturalElementHeight";
6
6
  import { closestParent, findFirst, isFocusable } from "../../util/DOM";
7
7
  import { getTopLevelBoundingClientRect } from "../../util/getTopLevelBoundingClientRect";
8
+ import { getParentFrameBoundingClientRect } from "../../util/getParentFrameBoundingClientRect";
8
9
  import { isTouchDevice } from "../../util/isTouchDevice";
9
10
  import {
10
11
  ConfigureOverlayContainerContext,
@@ -224,6 +225,23 @@ export class DropdownBase<
224
225
  component.updateDropdownPosition,
225
226
  );
226
227
 
228
+ //if the related element lives in a different document (e.g. inside a same-origin
229
+ //iframe), that document/window has its own scroll position and its own resize event
230
+ //(which also fires when the <iframe> element itself is resized) - neither is observed
231
+ //by the top-level `window` above or by the relatedElement's parentElement chain, so
232
+ //track every frame window between the related element's document and the top document.
233
+ var frameWindows: Window[] = (component.frameWindows = []);
234
+ var frameWin: Window | null | undefined =
235
+ instance.relatedElement?.ownerDocument?.defaultView;
236
+ while (frameWin && frameWin !== window) {
237
+ frameWindows.push(frameWin);
238
+ frameWin = frameWin.frameElement?.ownerDocument?.defaultView;
239
+ }
240
+ frameWindows.forEach((w) => {
241
+ w.addEventListener("scroll", component.updateDropdownPosition);
242
+ w.addEventListener("resize", component.updateDropdownPosition);
243
+ });
244
+
227
245
  if (this.onDropdownDidMount)
228
246
  instance.invoke("onDropdownDidMount", instance, component);
229
247
 
@@ -246,14 +264,21 @@ export class DropdownBase<
246
264
  }
247
265
 
248
266
  overlayWillUnmount(instance: InstanceType, component: any): void {
249
- var { scrollableParents } = component;
267
+ var { scrollableParents, frameWindows } = component;
250
268
  if (scrollableParents) {
251
269
  scrollableParents.forEach((el: Element) => {
252
270
  el.removeEventListener("scroll", component.updateDropdownPosition);
253
271
  });
254
272
  delete component.scrollableParents;
255
- delete component.updateDropdownPosition;
256
273
  }
274
+ if (frameWindows) {
275
+ frameWindows.forEach((w: Window) => {
276
+ w.removeEventListener("scroll", component.updateDropdownPosition);
277
+ w.removeEventListener("resize", component.updateDropdownPosition);
278
+ });
279
+ delete component.frameWindows;
280
+ }
281
+ delete component.updateDropdownPosition;
257
282
  if (component.offResize) component.offResize();
258
283
 
259
284
  if (this.pipeValidateDropdownPosition)
@@ -278,7 +303,17 @@ export class DropdownBase<
278
303
  updateDropdownPosition(instance: InstanceType, component: any): void {
279
304
  var { el, initialScreenPosition } = component;
280
305
  var { data, relatedElement } = instance;
281
- var parentBounds = getTopLevelBoundingClientRect(relatedElement!);
306
+ var elDocument: Document = el.ownerDocument || document;
307
+
308
+ //if the dropdown renders in the same document as its related element (e.g. not
309
+ //portaled to the top-level body, such as an inline dropdown living inside an
310
+ //iframe together with its field), no cross-document offset should be applied -
311
+ //getBoundingClientRect() is already relative to that shared document/viewport.
312
+ var isSameDocument =
313
+ el && relatedElement && el.ownerDocument === relatedElement.ownerDocument;
314
+ var parentBounds = isSameDocument
315
+ ? relatedElement!.getBoundingClientRect()
316
+ : getTopLevelBoundingClientRect(relatedElement!);
282
317
 
283
318
  //getBoundingClientRect() will return an empty rect if the element is hidden or removed
284
319
  if (
@@ -291,19 +326,33 @@ export class DropdownBase<
291
326
  parentBounds = component.parentBounds;
292
327
  } else component.parentBounds = parentBounds;
293
328
 
294
- if (this.trackMouseX && instance.mousePosition) {
329
+ //instance.mousePosition (set from getCursorPos) is always expressed in top-document
330
+ //coordinates. When the dropdown and its related element share a document that isn't
331
+ //the top document (e.g. both live inside the same iframe), parentBounds above is in
332
+ //that document's own coordinate space, so the mouse position must be translated into
333
+ //the same space before it can replace part of parentBounds.
334
+ var mousePosition = instance.mousePosition;
335
+ if (mousePosition && isSameDocument && elDocument !== document) {
336
+ const frameOffset = getParentFrameBoundingClientRect(relatedElement!);
337
+ mousePosition = {
338
+ x: mousePosition.x - frameOffset.left,
339
+ y: mousePosition.y - frameOffset.top,
340
+ };
341
+ }
342
+
343
+ if (this.trackMouseX && mousePosition) {
295
344
  parentBounds = new DOMRect(
296
- instance.mousePosition.x,
345
+ mousePosition.x,
297
346
  parentBounds.top,
298
347
  0,
299
348
  parentBounds.bottom - parentBounds.top,
300
349
  );
301
350
  }
302
351
 
303
- if (this.trackMouseY && instance.mousePosition) {
352
+ if (this.trackMouseY && mousePosition) {
304
353
  parentBounds = new DOMRect(
305
354
  parentBounds.left,
306
- instance.mousePosition.y,
355
+ mousePosition.y,
307
356
  parentBounds.right - parentBounds.left,
308
357
  0,
309
358
  );
@@ -334,6 +383,7 @@ export class DropdownBase<
334
383
  parentBounds,
335
384
  data.placement,
336
385
  component.lastPlacement,
386
+ elDocument,
337
387
  );
338
388
 
339
389
  var arrowAdjust = this.getArrowAdjust(component);
@@ -346,6 +396,7 @@ export class DropdownBase<
346
396
  el,
347
397
  false,
348
398
  arrowAdjust,
399
+ elDocument,
349
400
  );
350
401
  component.setCustomStyle(style);
351
402
  this.setDirectionClass(component, placement);
@@ -366,6 +417,7 @@ export class DropdownBase<
366
417
  el,
367
418
  true,
368
419
  arrowAdjust,
420
+ elDocument,
369
421
  );
370
422
  component.setCustomStyle(newStyle);
371
423
  }
@@ -412,8 +464,9 @@ export class DropdownBase<
412
464
  el: HTMLElement,
413
465
  noAuto: boolean,
414
466
  arrowAdjust: number = 0,
467
+ elDocument: Document,
415
468
  ): void {
416
- let viewport = getViewportRect(this.screenPadding);
469
+ let viewport = getViewportRect(this.screenPadding, elDocument);
417
470
  style.position = "fixed";
418
471
 
419
472
  if (placement.startsWith("down")) {
@@ -431,7 +484,7 @@ export class DropdownBase<
431
484
  ? Math.max(this.screenPadding, top) + "px"
432
485
  : "auto";
433
486
  style.bottom =
434
- document.documentElement.offsetHeight -
487
+ elDocument.documentElement.clientHeight -
435
488
  (this.cover ? rel.bottom : rel.top) +
436
489
  this.offset +
437
490
  "px";
@@ -450,7 +503,7 @@ export class DropdownBase<
450
503
  break;
451
504
 
452
505
  case "down-left":
453
- style.right = `${document.documentElement.offsetWidth - rel.right - arrowAdjust}px`;
506
+ style.right = `${elDocument.documentElement.clientWidth - rel.right - arrowAdjust}px`;
454
507
  style.left = "auto";
455
508
  break;
456
509
 
@@ -466,7 +519,7 @@ export class DropdownBase<
466
519
  break;
467
520
 
468
521
  case "up-left":
469
- style.right = `${document.documentElement.offsetWidth - rel.right - arrowAdjust}px`;
522
+ style.right = `${elDocument.documentElement.clientWidth - rel.right - arrowAdjust}px`;
470
523
  style.left = "auto";
471
524
  break;
472
525
 
@@ -488,45 +541,45 @@ export class DropdownBase<
488
541
  case "right-up":
489
542
  style.top = "auto";
490
543
  style.right = "auto";
491
- style.bottom = `${document.documentElement.offsetHeight - rel.bottom - arrowAdjust}px`;
544
+ style.bottom = `${elDocument.documentElement.clientHeight - rel.bottom - arrowAdjust}px`;
492
545
  style.left = `${rel.right + this.offset}px`;
493
546
  break;
494
547
 
495
548
  case "left":
496
549
  case "left-center":
497
550
  style.top = `${Math.round((rel.top + rel.bottom - el.offsetHeight) / 2)}px`;
498
- style.right = `${document.documentElement.offsetWidth - rel.left + this.offset}px`;
551
+ style.right = `${elDocument.documentElement.clientWidth - rel.left + this.offset}px`;
499
552
  style.bottom = "auto";
500
553
  style.left = "auto";
501
554
  break;
502
555
 
503
556
  case "left-down":
504
557
  style.top = `${rel.top - arrowAdjust}px`;
505
- style.right = `${document.documentElement.offsetWidth - rel.left + this.offset}px`;
558
+ style.right = `${elDocument.documentElement.clientWidth - rel.left + this.offset}px`;
506
559
  style.bottom = "auto";
507
560
  style.left = "auto";
508
561
  break;
509
562
 
510
563
  case "left-up":
511
564
  style.top = "auto";
512
- style.right = `${document.documentElement.offsetWidth - rel.left + this.offset}px`;
513
- style.bottom = `${document.documentElement.offsetHeight - rel.bottom - arrowAdjust}px`;
565
+ style.right = `${elDocument.documentElement.clientWidth - rel.left + this.offset}px`;
566
+ style.bottom = `${elDocument.documentElement.clientHeight - rel.bottom - arrowAdjust}px`;
514
567
  style.left = "auto";
515
568
  break;
516
569
 
517
570
  case "screen-center":
518
571
  let w = Math.min(
519
572
  contentSize.width,
520
- document.documentElement.offsetWidth - 2 * this.screenPadding,
573
+ elDocument.documentElement.clientWidth - 2 * this.screenPadding,
521
574
  );
522
575
  let h = Math.min(
523
576
  contentSize.height,
524
- document.documentElement.offsetHeight - 2 * this.screenPadding,
577
+ elDocument.documentElement.clientHeight - 2 * this.screenPadding,
525
578
  );
526
- style.top = `${Math.round((document.documentElement.offsetHeight - h) / 2)}px`;
527
- style.right = `${Math.round((document.documentElement.offsetWidth - w) / 2)}px`;
528
- style.bottom = `${Math.round((document.documentElement.offsetHeight - h) / 2)}px`;
529
- style.left = `${Math.round((document.documentElement.offsetWidth - w) / 2)}px`;
579
+ style.top = `${Math.round((elDocument.documentElement.clientHeight - h) / 2)}px`;
580
+ style.right = `${Math.round((elDocument.documentElement.clientWidth - w) / 2)}px`;
581
+ style.bottom = `${Math.round((elDocument.documentElement.clientHeight - h) / 2)}px`;
582
+ style.left = `${Math.round((elDocument.documentElement.clientWidth - w) / 2)}px`;
530
583
  break;
531
584
  }
532
585
  }
@@ -539,8 +592,9 @@ export class DropdownBase<
539
592
  el: HTMLElement,
540
593
  noAuto: boolean,
541
594
  arrowAdjust: number = 0,
595
+ elDocument: Document,
542
596
  ): void {
543
- var viewport = getViewportRect(this.screenPadding);
597
+ var viewport = getViewportRect(this.screenPadding, elDocument);
544
598
 
545
599
  style.position = "absolute";
546
600
 
@@ -647,6 +701,7 @@ export class DropdownBase<
647
701
  el: HTMLElement,
648
702
  noAuto: boolean,
649
703
  arrowAdjust: number = 0,
704
+ elDocument: Document,
650
705
  ): void {
651
706
  switch (this.positioning) {
652
707
  case "absolute":
@@ -658,6 +713,7 @@ export class DropdownBase<
658
713
  el,
659
714
  noAuto,
660
715
  arrowAdjust,
716
+ elDocument,
661
717
  );
662
718
  break;
663
719
 
@@ -671,6 +727,7 @@ export class DropdownBase<
671
727
  el,
672
728
  noAuto,
673
729
  arrowAdjust,
730
+ elDocument,
674
731
  );
675
732
  else
676
733
  this.applyFixedPositioningPlacementStyles(
@@ -681,6 +738,7 @@ export class DropdownBase<
681
738
  el,
682
739
  noAuto,
683
740
  arrowAdjust,
741
+ elDocument,
684
742
  );
685
743
  break;
686
744
 
@@ -693,6 +751,7 @@ export class DropdownBase<
693
751
  el,
694
752
  noAuto,
695
753
  arrowAdjust,
754
+ elDocument,
696
755
  );
697
756
  break;
698
757
  }
@@ -749,13 +808,14 @@ export class DropdownBase<
749
808
  target: any,
750
809
  placement: string,
751
810
  lastPlacement: any,
811
+ elDocument: Document,
752
812
  ): any {
753
813
  var placementOrder = this.placementOrder.split(" ");
754
814
  var best = lastPlacement || placement;
755
815
  var first;
756
816
 
757
817
  var score: Record<string, number> = {};
758
- var viewport = getViewportRect();
818
+ var viewport = getViewportRect(0, elDocument);
759
819
 
760
820
  for (var i = 0; i < placementOrder.length; i++) {
761
821
  var p = placementOrder[i];
@@ -970,11 +1030,11 @@ export class Dropdown extends DropdownBase<DropdownConfig, DropdownInstance> {}
970
1030
  Widget.alias("dropdown", Dropdown);
971
1031
  Localization.registerPrototype("cx/widgets/Dropdown", Dropdown);
972
1032
 
973
- function getViewportRect(padding = 0) {
1033
+ function getViewportRect(padding = 0, elDocument: Document = document) {
974
1034
  return {
975
1035
  left: padding,
976
1036
  top: padding,
977
- right: document.documentElement.offsetWidth - padding,
978
- bottom: document.documentElement.offsetHeight - padding,
1037
+ right: elDocument.documentElement.clientWidth - padding,
1038
+ bottom: elDocument.documentElement.clientHeight - padding,
979
1039
  };
980
1040
  }
@@ -765,9 +765,11 @@ export class OverlayComponent<
765
765
  widget.handleResize(e, instance, this);
766
766
  } else {
767
767
  let prefix = this.getResizePrefix(e);
768
- this.setCustomStyle({
769
- cursor: prefix ? prefix + "-resize" : undefined,
770
- });
768
+ if (prefix) this.setCustomStyle({ cursor: `${prefix}-resize` });
769
+ else if (this.customStyle.cursor) {
770
+ delete this.customStyle.cursor;
771
+ if (this.el) this.el.style.cursor = data.style?.cursor ?? "";
772
+ }
771
773
  }
772
774
  }
773
775
 
@@ -21,6 +21,7 @@ import { isDefined } from "../../util/isDefined";
21
21
  import { isString } from "../../util/isString";
22
22
  import { BooleanProp, StringProp, StyleProp, ClassProp } from "../../ui/Prop";
23
23
  import { RenderingContext } from "../../ui/RenderingContext";
24
+ import { getActiveElement } from "../../util/getActiveElement";
24
25
 
25
26
  export interface WindowConfig extends OverlayConfig {
26
27
  /** Text to be displayed in the header. */
@@ -292,7 +293,7 @@ class WindowComponent extends OverlayComponent<WindowComponentProps, WindowCompo
292
293
  onFocusIn() {
293
294
  super.onFocusIn();
294
295
  if (!this.state.active) {
295
- if (this.containerEl?.contains(document.activeElement)) this.setZIndex(ZIndexManager.next());
296
+ if (this.containerEl?.contains(getActiveElement())) this.setZIndex(ZIndexManager.next());
296
297
  this.setState({ active: true });
297
298
  }
298
299
  }