material 3.3.1 → 3.3.3

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 (153) hide show
  1. package/README.md +2 -2
  2. package/dist/components/slider/config.js +0 -46
  3. package/dist/components/slider/features/controller.js +805 -171
  4. package/dist/components/slider/features/dom.js +29 -62
  5. package/dist/components/slider/features/index.js +1 -3
  6. package/dist/components/slider/features/states.js +2 -30
  7. package/dist/components/slider/slider.js +3 -6
  8. package/dist/components/slider/types.d.ts +0 -26
  9. package/dist/components/tooltip/api.js +53 -97
  10. package/dist/core/canvas/resize.d.ts +1 -1
  11. package/dist/core/canvas/resize.js +24 -11
  12. package/dist/core/dom/classes.js +17 -118
  13. package/dist/core/dom/create.d.ts +0 -2
  14. package/dist/core/dom/create.js +0 -72
  15. package/dist/core/utils/mobile.js +9 -29
  16. package/dist/elements/css/tooltip.css +1 -1
  17. package/dist/elements/css/tooltip.js +1 -1
  18. package/dist/elements/preupgrade/badge.css +1 -1
  19. package/dist/elements/preupgrade/bottom-app-bar.css +1 -1
  20. package/dist/elements/preupgrade/bottom-sheet.css +1 -1
  21. package/dist/elements/preupgrade/button-group.css +1 -1
  22. package/dist/elements/preupgrade/button.css +1 -1
  23. package/dist/elements/preupgrade/card.css +1 -1
  24. package/dist/elements/preupgrade/carousel.css +1 -1
  25. package/dist/elements/preupgrade/checkbox.css +1 -1
  26. package/dist/elements/preupgrade/chips.css +1 -1
  27. package/dist/elements/preupgrade/datepicker.css +1 -1
  28. package/dist/elements/preupgrade/dialog.css +1 -1
  29. package/dist/elements/preupgrade/divider.css +1 -1
  30. package/dist/elements/preupgrade/drawer.css +1 -1
  31. package/dist/elements/preupgrade/extended-fab.css +1 -1
  32. package/dist/elements/preupgrade/fab-menu.css +1 -1
  33. package/dist/elements/preupgrade/fab.css +1 -1
  34. package/dist/elements/preupgrade/icon-button.css +1 -1
  35. package/dist/elements/preupgrade/list.css +1 -1
  36. package/dist/elements/preupgrade/loading-indicator.css +1 -1
  37. package/dist/elements/preupgrade/menu.css +1 -1
  38. package/dist/elements/preupgrade/navigation-bar.css +1 -1
  39. package/dist/elements/preupgrade/navigation-rail.css +1 -1
  40. package/dist/elements/preupgrade/progress.css +1 -1
  41. package/dist/elements/preupgrade/radios.css +1 -1
  42. package/dist/elements/preupgrade/search.css +1 -1
  43. package/dist/elements/preupgrade/select.css +1 -1
  44. package/dist/elements/preupgrade/side-sheet.css +1 -1
  45. package/dist/elements/preupgrade/slider.css +1 -1
  46. package/dist/elements/preupgrade/snackbar.css +1 -1
  47. package/dist/elements/preupgrade/split-button.css +1 -1
  48. package/dist/elements/preupgrade/switch.css +1 -1
  49. package/dist/elements/preupgrade/tabs.css +1 -1
  50. package/dist/elements/preupgrade/text-field.css +1 -1
  51. package/dist/elements/preupgrade/timepicker.css +1 -1
  52. package/dist/elements/preupgrade/toolbar.css +1 -1
  53. package/dist/elements/preupgrade/tooltip.css +1 -1
  54. package/dist/elements/preupgrade/top-app-bar.css +1 -1
  55. package/dist/elements/preupgrade.css +1 -1
  56. package/dist/package.json +1 -1
  57. package/dist/styles/badge.css +1 -1
  58. package/dist/styles/base.css +1 -1
  59. package/dist/styles/bottom-app-bar.css +1 -1
  60. package/dist/styles/bottom-sheet.css +1 -1
  61. package/dist/styles/button-group.css +1 -1
  62. package/dist/styles/button.css +1 -1
  63. package/dist/styles/card.css +1 -1
  64. package/dist/styles/carousel.css +1 -1
  65. package/dist/styles/checkbox.css +1 -1
  66. package/dist/styles/chips.css +1 -1
  67. package/dist/styles/contrast.css +1 -1
  68. package/dist/styles/datepicker.css +1 -1
  69. package/dist/styles/dialog.css +1 -1
  70. package/dist/styles/divider.css +1 -1
  71. package/dist/styles/drawer.css +1 -1
  72. package/dist/styles/extended-fab.css +1 -1
  73. package/dist/styles/fab-menu.css +1 -1
  74. package/dist/styles/fab.css +1 -1
  75. package/dist/styles/icon-button.css +1 -1
  76. package/dist/styles/list.css +1 -1
  77. package/dist/styles/loading-indicator.css +1 -1
  78. package/dist/styles/menu.css +1 -1
  79. package/dist/styles/navigation-bar.css +1 -1
  80. package/dist/styles/navigation-rail.css +1 -1
  81. package/dist/styles/progress.css +1 -1
  82. package/dist/styles/radios.css +1 -1
  83. package/dist/styles/search.css +1 -1
  84. package/dist/styles/select.css +1 -1
  85. package/dist/styles/side-sheet.css +1 -1
  86. package/dist/styles/slider.css +1 -1
  87. package/dist/styles/snackbar.css +1 -1
  88. package/dist/styles/split-button.css +1 -1
  89. package/dist/styles/switch.css +1 -1
  90. package/dist/styles/tabs.css +1 -1
  91. package/dist/styles/text-field.css +1 -1
  92. package/dist/styles/timepicker.css +1 -1
  93. package/dist/styles/toolbar.css +1 -1
  94. package/dist/styles/tooltip.css +2 -2
  95. package/dist/styles/top-app-bar.css +1 -1
  96. package/dist/styles/typography.css +1 -1
  97. package/dist/styles/utilities.css +1 -1
  98. package/dist/styles.css +2 -2
  99. package/dist/themes/autumn-contrast.css +1 -1
  100. package/dist/themes/autumn.css +1 -1
  101. package/dist/themes/baseline-contrast.css +1 -1
  102. package/dist/themes/baseline.css +1 -1
  103. package/dist/themes/brownbeige-contrast.css +1 -1
  104. package/dist/themes/brownbeige.css +1 -1
  105. package/dist/themes/content-contrast.css +1 -1
  106. package/dist/themes/content.css +1 -1
  107. package/dist/themes/desert-contrast.css +1 -1
  108. package/dist/themes/desert.css +1 -1
  109. package/dist/themes/expressive-contrast.css +1 -1
  110. package/dist/themes/expressive.css +1 -1
  111. package/dist/themes/fidelity-contrast.css +1 -1
  112. package/dist/themes/fidelity.css +1 -1
  113. package/dist/themes/forest-contrast.css +1 -1
  114. package/dist/themes/forest.css +1 -1
  115. package/dist/themes/fruit-salad-contrast.css +1 -1
  116. package/dist/themes/fruit-salad.css +1 -1
  117. package/dist/themes/highcontrast-contrast.css +1 -1
  118. package/dist/themes/highcontrast.css +1 -1
  119. package/dist/themes/monochrome-contrast.css +1 -1
  120. package/dist/themes/monochrome.css +1 -1
  121. package/dist/themes/neutral-contrast.css +1 -1
  122. package/dist/themes/neutral.css +1 -1
  123. package/dist/themes/ocean-contrast.css +1 -1
  124. package/dist/themes/ocean.css +1 -1
  125. package/dist/themes/rainbow-contrast.css +1 -1
  126. package/dist/themes/rainbow.css +1 -1
  127. package/dist/themes/sageivory-contrast.css +1 -1
  128. package/dist/themes/sageivory.css +1 -1
  129. package/dist/themes/spring-contrast.css +1 -1
  130. package/dist/themes/spring.css +1 -1
  131. package/dist/themes/summer-contrast.css +1 -1
  132. package/dist/themes/summer.css +1 -1
  133. package/dist/themes/sunset-contrast.css +1 -1
  134. package/dist/themes/sunset.css +1 -1
  135. package/dist/themes/tealcaramel-contrast.css +1 -1
  136. package/dist/themes/tealcaramel.css +1 -1
  137. package/dist/themes/vibrant-contrast.css +1 -1
  138. package/dist/themes/vibrant.css +1 -1
  139. package/package.json +1 -1
  140. package/src/styles/components/_tooltip.scss +3 -16
  141. package/dist/components/card/features.js +0 -217
  142. package/dist/components/chips/chip/constants.js +0 -18
  143. package/dist/components/chips/chip/index.js +0 -1
  144. package/dist/components/chips/schema.js +0 -46
  145. package/dist/components/progress/features/index.js +0 -4
  146. package/dist/components/progress/features/resize-observer.js +0 -40
  147. package/dist/components/slider/api.js +0 -108
  148. package/dist/components/slider/features/handlers.js +0 -379
  149. package/dist/components/slider/features/range.js +0 -70
  150. package/dist/components/slider/features/tracks.js +0 -287
  151. package/dist/components/tabs/scroll-indicators.js +0 -78
  152. package/dist/components/tabs/state.js +0 -44
  153. package/dist/core/utils/validate.js +0 -114
@@ -8,7 +8,6 @@ export const withDom = (config) => (component) => {
8
8
  const value = config.value !== undefined ? config.value : min;
9
9
  const isDisabled = config.disabled === true;
10
10
  const formatter = config.valueFormatter || ((val) => val.toString());
11
- const valuePercent = ((value - min) / (max - min)) * 100;
12
11
  const container = createElement({
13
12
  tag: "div",
14
13
  className: getClass("slider__container"),
@@ -20,83 +19,56 @@ export const withDom = (config) => (component) => {
20
19
  const label = config.label || "";
21
20
  const handleLabel = config.range && label ? `${label} minimum` : label;
22
21
  const secondHandleLabel = label ? `${label} maximum` : "";
23
- const handleAttributes = {
24
- role: "slider",
25
- "aria-valuemin": String(min),
26
- "aria-valuemax": String(max),
27
- "aria-valuenow": String(value),
28
- "aria-orientation": config.orientation === "vertical" ? "vertical" : "horizontal",
29
- tabindex: isDisabled ? "-1" : "0",
30
- "aria-disabled": isDisabled ? "true" : "false",
31
- "data-value": String(value),
32
- "data-handle-index": "0",
33
- };
34
- if (handleLabel) {
35
- handleAttributes["aria-label"] = handleLabel;
36
- }
37
- const handle = createElement({
38
- tag: "div",
39
- className: getClass("slider__handle"),
40
- attributes: handleAttributes,
41
- container: container,
42
- });
43
- setStyles(handle, {
44
- left: `${valuePercent}%`,
45
- });
46
- const valueBubble = createElement({
47
- tag: "div",
48
- className: getClass("slider__value"),
49
- attributes: {
50
- "aria-hidden": "true",
51
- "data-handle-index": "0",
52
- },
53
- text: formatter(value),
54
- container: container,
55
- });
56
- setStyles(valueBubble, {
57
- left: `${valuePercent}%`,
58
- });
59
- let secondHandle;
60
- let secondValueBubble;
61
- if (config.range) {
62
- const secondValue = config.secondValue !== undefined ? config.secondValue : max;
63
- const secondValuePercent = ((secondValue - min) / (max - min)) * 100;
64
- const secondHandleAttributes = {
22
+ const handleElement = (index, handleValue, name) => {
23
+ const attributes = {
65
24
  role: "slider",
66
25
  "aria-valuemin": String(min),
67
26
  "aria-valuemax": String(max),
68
- "aria-valuenow": String(secondValue),
27
+ "aria-valuenow": String(handleValue),
69
28
  "aria-orientation": config.orientation === "vertical" ? "vertical" : "horizontal",
70
29
  tabindex: isDisabled ? "-1" : "0",
71
30
  "aria-disabled": isDisabled ? "true" : "false",
72
- "data-value": String(secondValue),
73
- "data-handle-index": "1",
31
+ "data-value": String(handleValue),
32
+ "data-handle-index": String(index),
74
33
  };
75
- if (secondHandleLabel) {
76
- secondHandleAttributes["aria-label"] = secondHandleLabel;
34
+ if (name) {
35
+ attributes["aria-label"] = name;
77
36
  }
78
- secondHandle = createElement({
37
+ const element = createElement({
79
38
  tag: "div",
80
39
  className: getClass("slider__handle"),
81
- attributes: secondHandleAttributes,
40
+ attributes,
82
41
  container: container,
83
42
  });
84
- setStyles(secondHandle, {
85
- left: `${secondValuePercent}%`,
43
+ setStyles(element, {
44
+ left: `${((handleValue - min) / (max - min)) * 100}%`,
86
45
  });
87
- secondValueBubble = createElement({
46
+ return element;
47
+ };
48
+ const bubbleElement = (index, bubbleValue) => {
49
+ const element = createElement({
88
50
  tag: "div",
89
51
  className: getClass("slider__value"),
90
52
  attributes: {
91
53
  "aria-hidden": "true",
92
- "data-handle-index": "1",
54
+ "data-handle-index": String(index),
93
55
  },
94
- text: formatter(secondValue),
56
+ text: formatter(bubbleValue),
95
57
  container: container,
96
58
  });
97
- setStyles(secondValueBubble, {
98
- left: `${secondValuePercent}%`,
59
+ setStyles(element, {
60
+ left: `${((bubbleValue - min) / (max - min)) * 100}%`,
99
61
  });
62
+ return element;
63
+ };
64
+ const handle = handleElement(0, value, handleLabel);
65
+ const valueBubble = bubbleElement(0, value);
66
+ let secondHandle;
67
+ let secondValueBubble;
68
+ if (config.range) {
69
+ const secondValue = config.secondValue !== undefined ? config.secondValue : max;
70
+ secondHandle = handleElement(1, secondValue, secondHandleLabel);
71
+ secondValueBubble = bubbleElement(1, secondValue);
100
72
  }
101
73
  const name = config.name;
102
74
  const formFields = name
@@ -115,10 +87,5 @@ export const withDom = (config) => (component) => {
115
87
  secondHandle,
116
88
  secondValueBubble,
117
89
  formFields,
118
- getContainer: () => container,
119
- getHandle: () => handle,
120
- getValueBubble: () => valueBubble,
121
- getSecondHandle: () => secondHandle || null,
122
- getSecondValueBubble: () => secondValueBubble || null,
123
90
  };
124
91
  };
@@ -1,5 +1,3 @@
1
- export { withRange } from "./range.js";
2
1
  export { withStates } from "./states.js";
3
- export { withController } from "./controller.js";
4
- export { withTracks } from "./tracks.js";
2
+ export { withController, withTracks } from "./controller.js";
5
3
  export { withDom } from "./dom.js";
@@ -1,8 +1,7 @@
1
1
  import { SLIDER_COLORS } from "../types.js";
2
- import { SLIDER_SIZES } from "../constants.js";
3
2
  export const withStates = (config) => (component) => {
4
- const handle = component.handle ?? component.structure?.handle;
5
- const secondHandle = component.secondHandle ?? component.structure?.secondHandle;
3
+ const handle = component.handle;
4
+ const secondHandle = component.secondHandle;
6
5
  const setFieldsDisabled = (disabled) => {
7
6
  for (const field of component.formFields ?? []) {
8
7
  if (field)
@@ -44,11 +43,6 @@ export const withStates = (config) => (component) => {
44
43
  function getActiveColor() {
45
44
  return (Object.values(SLIDER_COLORS).find((colorName) => component.element.classList.contains(`${component.getClass("slider")}--${colorName}`)) || SLIDER_COLORS.PRIMARY);
46
45
  }
47
- function getActiveSize() {
48
- const sizeKeys = Object.keys(SLIDER_SIZES);
49
- const foundKey = sizeKeys.find((sizeKey) => component.element.classList.contains(`${component.getClass("slider")}--${sizeKey.toLowerCase()}`));
50
- return foundKey || "XS";
51
- }
52
46
  if (config.disabled === true)
53
47
  disableComponent();
54
48
  return Object.assign(component, {
@@ -78,28 +72,6 @@ export const withStates = (config) => (component) => {
78
72
  getColor() {
79
73
  return getActiveColor();
80
74
  },
81
- setSize(size) {
82
- const sizeKeys = Object.keys(SLIDER_SIZES);
83
- sizeKeys.forEach((sizeKey) => {
84
- component.element.classList.remove(`${component.getClass("slider")}--${sizeKey.toLowerCase()}`);
85
- });
86
- let sizeKey;
87
- if (typeof size === "string" && size in SLIDER_SIZES) {
88
- sizeKey = size;
89
- }
90
- else if (typeof size === "number") {
91
- const entry = Object.entries(SLIDER_SIZES).find(([, value]) => value === size);
92
- sizeKey = entry ? entry[0] : "XS";
93
- }
94
- else {
95
- sizeKey = "XS";
96
- }
97
- component.element.classList.add(`${component.getClass("slider")}--${sizeKey.toLowerCase()}`);
98
- return this;
99
- },
100
- getSize() {
101
- return getActiveSize();
102
- },
103
75
  showTicks(show) {
104
76
  config.ticks = show;
105
77
  component.renderTracks?.();
@@ -1,15 +1,12 @@
1
1
  import { pipe } from "../../core/compose/pipe.js";
2
2
  import { createBase, withElement } from "../../core/compose/component.js";
3
3
  import { withEvents, withLifecycle, withIcon, withTextLabel, } from "../../core/compose/features/index.js";
4
- import { withRange, withStates, withController, withTracks, withDom, } from "./features/index.js";
5
- import { withAPI } from "./api.js";
6
- import { createBaseConfig, getElementConfig, getApiConfig } from "./config.js";
4
+ import { withStates, withController, withTracks, withDom, } from "./features/index.js";
5
+ import { createBaseConfig, getElementConfig } from "./config.js";
7
6
  const createSlider = (config = {}) => {
8
7
  const baseConfig = createBaseConfig(config);
9
8
  try {
10
- const component = pipe(createBase, withEvents(), withElement(getElementConfig(baseConfig)), withRange(baseConfig), withDom(baseConfig), withTextLabel(baseConfig), withIcon(baseConfig), withLifecycle(), withStates(baseConfig), withTracks(baseConfig), withController(baseConfig, () => slider))(baseConfig);
11
- const apiOptions = getApiConfig(component);
12
- const slider = withAPI(apiOptions)(component);
9
+ const slider = pipe(createBase, withEvents(), withElement(getElementConfig(baseConfig)), withDom(baseConfig), withTextLabel(baseConfig), withIcon(baseConfig), withLifecycle(), withStates(baseConfig), withTracks(baseConfig), withController(baseConfig, () => slider))(baseConfig);
13
10
  if (baseConfig.on && typeof slider.on === "function") {
14
11
  Object.entries(baseConfig.on).forEach(([event, handler]) => {
15
12
  if (typeof handler === "function") {
@@ -47,10 +47,8 @@ export interface SliderEvent {
47
47
  }
48
48
  export type SliderActiveHandle = "first" | "second" | null;
49
49
  export interface SliderState {
50
- component: SliderStateComponent;
51
50
  value: number;
52
51
  secondValue: number | null;
53
- previousValue?: number;
54
52
  min: number;
55
53
  max: number;
56
54
  step: number;
@@ -67,7 +65,6 @@ export interface SliderStateComponent {
67
65
  valueBubble?: HTMLElement | null;
68
66
  secondHandle?: HTMLElement | null;
69
67
  secondValueBubble?: HTMLElement | null;
70
- components?: Record<string, HTMLElement | null | undefined>;
71
68
  getClass: (name: string) => string;
72
69
  emit: (event: string, data: unknown) => unknown;
73
70
  disabled?: {
@@ -80,31 +77,8 @@ export interface SliderStateComponent {
80
77
  destroy?: () => void;
81
78
  mount?: () => void;
82
79
  };
83
- slider?: {
84
- setValue?: (value: number, triggerEvent?: boolean) => unknown;
85
- };
86
80
  }
87
81
  export type SliderPointerEvent = MouseEvent | TouchEvent;
88
- export interface SliderElements {
89
- container?: HTMLElement | null;
90
- handle?: HTMLElement | null;
91
- valueBubble?: HTMLElement | null;
92
- secondHandle?: HTMLElement | null;
93
- secondValueBubble?: HTMLElement | null;
94
- [key: string]: HTMLElement | null | undefined;
95
- }
96
- export interface SliderUiRenderer {
97
- getPercentage: (value: number) => number;
98
- getValueFromPosition: (position: number) => number;
99
- roundToStep: (value: number) => number;
100
- clamp: (value: number, min?: number, max?: number) => number;
101
- showValueBubble: (bubbleElement: HTMLElement | null, show: boolean) => void;
102
- updateUi: () => void;
103
- render: () => void;
104
- }
105
- export interface SliderEventHelpers {
106
- triggerEvent: (eventName: string, originalEvent?: Event | null) => void;
107
- }
108
82
  export interface SliderEvents extends TouchEvents {
109
83
  change: (payload: SliderEvent) => void;
110
84
  input: (payload: SliderEvent) => void;
@@ -40,106 +40,62 @@ export const withAPI = ({ lifecycle }) => (component) => {
40
40
  if (!target)
41
41
  return { top: 0, left: 0 };
42
42
  component.element.style.left = "0px";
43
- const tooltipWidth = component.element.offsetWidth;
44
- const tooltipHeight = component.element.offsetHeight;
43
+ const styles = getComputedStyle(component.element);
44
+ const tooltipWidth = parseFloat(styles.width);
45
+ const tooltipHeight = parseFloat(styles.height);
45
46
  const targetRect = target.getBoundingClientRect();
46
47
  const offset = DEFAULT_OFFSET;
47
48
  let top = 0;
48
49
  let left = 0;
49
- let arrowPosition;
50
- switch (position) {
51
- case TOOLTIP_POSITIONS.TOP:
52
- top = targetRect.top - tooltipHeight - offset;
53
- left =
54
- targetRect.left +
55
- targetRect.width / 2 -
56
- tooltipWidth / 2;
57
- arrowPosition = "bottom";
58
- break;
59
- case TOOLTIP_POSITIONS.TOP_START:
60
- top = targetRect.top - tooltipHeight - offset;
61
- left = targetRect.left;
62
- arrowPosition = "bottom-start";
63
- break;
64
- case TOOLTIP_POSITIONS.TOP_END:
65
- top = targetRect.top - tooltipHeight - offset;
66
- left =
67
- targetRect.left + targetRect.width - tooltipWidth;
68
- arrowPosition = "bottom-end";
69
- break;
70
- case TOOLTIP_POSITIONS.RIGHT:
71
- top =
72
- targetRect.top +
73
- targetRect.height / 2 -
74
- tooltipHeight / 2;
75
- left = targetRect.left + targetRect.width + offset;
76
- arrowPosition = "left";
77
- break;
78
- case TOOLTIP_POSITIONS.RIGHT_START:
79
- top = targetRect.top;
80
- left = targetRect.left + targetRect.width + offset;
81
- arrowPosition = "left-start";
82
- break;
83
- case TOOLTIP_POSITIONS.RIGHT_END:
84
- top =
85
- targetRect.top + targetRect.height - tooltipHeight;
86
- left = targetRect.left + targetRect.width + offset;
87
- arrowPosition = "left-end";
88
- break;
89
- case TOOLTIP_POSITIONS.BOTTOM:
90
- top = targetRect.top + targetRect.height + offset;
91
- left =
92
- targetRect.left +
93
- targetRect.width / 2 -
94
- tooltipWidth / 2;
95
- arrowPosition = "top";
96
- break;
97
- case TOOLTIP_POSITIONS.BOTTOM_START:
98
- top = targetRect.top + targetRect.height + offset;
99
- left = targetRect.left;
100
- arrowPosition = "top-start";
101
- break;
102
- case TOOLTIP_POSITIONS.BOTTOM_END:
103
- top = targetRect.top + targetRect.height + offset;
104
- left =
105
- targetRect.left + targetRect.width - tooltipWidth;
106
- arrowPosition = "top-end";
107
- break;
108
- case TOOLTIP_POSITIONS.LEFT:
109
- top =
110
- targetRect.top +
111
- targetRect.height / 2 -
112
- tooltipHeight / 2;
113
- left = targetRect.left - tooltipWidth - offset;
114
- arrowPosition = "right";
115
- break;
116
- case TOOLTIP_POSITIONS.LEFT_START:
117
- top = targetRect.top;
118
- left = targetRect.left - tooltipWidth - offset;
119
- arrowPosition = "right-start";
120
- break;
121
- case TOOLTIP_POSITIONS.LEFT_END:
122
- top =
123
- targetRect.top + targetRect.height - tooltipHeight;
124
- left = targetRect.left - tooltipWidth - offset;
125
- arrowPosition = "right-end";
126
- break;
127
- default:
128
- top = targetRect.top + targetRect.height + offset;
129
- left =
130
- targetRect.left +
131
- targetRect.width / 2 -
132
- tooltipWidth / 2;
133
- arrowPosition = "top";
50
+ const [side, anchor] = position.split("-");
51
+ const vertical = side !== "left" && side !== "right";
52
+ const align = anchor === "start" ? 0 : anchor === "end" ? 1 : 0.5;
53
+ if (vertical) {
54
+ top = side === "top"
55
+ ? targetRect.top - tooltipHeight - offset
56
+ : targetRect.bottom + offset;
57
+ left = targetRect.left + (targetRect.width - tooltipWidth) * align;
58
+ }
59
+ else {
60
+ left = side === "left"
61
+ ? targetRect.left - tooltipWidth - offset
62
+ : targetRect.right + offset;
63
+ top = targetRect.top + (targetRect.height - tooltipHeight) * align;
134
64
  }
135
65
  const windowWidth = window.innerWidth;
136
- if (left < 0) {
137
- left = 0;
66
+ const windowHeight = window.innerHeight;
67
+ let suffix = anchor ? `-${anchor}` : "";
68
+ if (vertical) {
69
+ if (top < 0)
70
+ top = targetRect.bottom + offset;
71
+ else if (top + tooltipHeight > windowHeight) {
72
+ top = targetRect.top - tooltipHeight - offset;
73
+ }
138
74
  }
139
- else if (left + tooltipWidth > windowWidth) {
140
- left = windowWidth - tooltipWidth;
75
+ const clampedX = left < 0 || left + tooltipWidth > windowWidth;
76
+ const clampedY = top < 0 || top + tooltipHeight > windowHeight;
77
+ left = Math.max(0, Math.min(windowWidth - tooltipWidth, left));
78
+ top = Math.max(0, Math.min(windowHeight - tooltipHeight, top));
79
+ if (vertical ? clampedX : clampedY) {
80
+ const from = vertical ? left : top;
81
+ const size = vertical ? tooltipWidth : tooltipHeight;
82
+ const targetFrom = vertical ? targetRect.left : targetRect.top;
83
+ const targetTo = vertical ? targetRect.right : targetRect.bottom;
84
+ const spanAt = [from + 8, from + size / 2 - 8, from + size - 24];
85
+ const meet = spanAt.findIndex((x) => x + 16 > targetFrom && x < targetTo);
86
+ suffix = ["-start", "", "-end"][meet < 0 ? 2 : meet];
141
87
  }
142
- return { top, left, arrowPosition };
88
+ return {
89
+ top,
90
+ left,
91
+ arrowPosition: (vertical
92
+ ? top + tooltipHeight <= targetRect.top
93
+ ? "bottom"
94
+ : "top"
95
+ : left + tooltipWidth <= targetRect.left
96
+ ? "right"
97
+ : "left") + suffix,
98
+ };
143
99
  };
144
100
  const addTargetEvents = (targetEl) => {
145
101
  if (showOnHover) {
@@ -264,7 +220,7 @@ export const withAPI = ({ lifecycle }) => (component) => {
264
220
  isVisible = true;
265
221
  this.updatePosition();
266
222
  window.addEventListener("resize", handleWindowResize);
267
- window.addEventListener("scroll", handleWindowScroll);
223
+ window.addEventListener("scroll", handleWindowScroll, true);
268
224
  document.addEventListener("keydown", handleDocumentKeydown);
269
225
  };
270
226
  if (immediate) {
@@ -289,7 +245,7 @@ export const withAPI = ({ lifecycle }) => (component) => {
289
245
  component.element.classList.remove(`${component.getClass("tooltip")}--visible`);
290
246
  isVisible = false;
291
247
  window.removeEventListener("resize", handleWindowResize);
292
- window.removeEventListener("scroll", handleWindowScroll);
248
+ window.removeEventListener("scroll", handleWindowScroll, true);
293
249
  document.removeEventListener("keydown", handleDocumentKeydown);
294
250
  if (topLayer) {
295
251
  if (layerTimer !== null)
@@ -316,8 +272,8 @@ export const withAPI = ({ lifecycle }) => (component) => {
316
272
  if (!target)
317
273
  return this;
318
274
  const { top, left, arrowPosition } = calculatePosition();
319
- component.element.style.top = `${Math.round(top)}px`;
320
- component.element.style.left = `${Math.round(left)}px`;
275
+ component.element.style.top = `${top}px`;
276
+ component.element.style.left = `${left}px`;
321
277
  if (arrowPosition) {
322
278
  arrowElement.className = `${component.getClass("tooltip")}__arrow`;
323
279
  arrowElement.classList.add(`${component.getClass("tooltip")}__arrow--${arrowPosition}`);
@@ -339,7 +295,7 @@ export const withAPI = ({ lifecycle }) => (component) => {
339
295
  undescribe(target);
340
296
  }
341
297
  window.removeEventListener("resize", handleWindowResize);
342
- window.removeEventListener("scroll", handleWindowScroll);
298
+ window.removeEventListener("scroll", handleWindowScroll, true);
343
299
  document.removeEventListener("keydown", handleDocumentKeydown);
344
300
  component.element.removeEventListener("mouseenter", handleTooltipMouseEnter);
345
301
  component.element.removeEventListener("mouseleave", handleTooltipMouseLeave);
@@ -1 +1 @@
1
- export declare const observeCanvasResize: (element: HTMLElement, _canvas: HTMLCanvasElement, onResize: () => void) => (() => void);
1
+ export declare const observeCanvasResize: (element: HTMLElement, canvas: HTMLCanvasElement | null | undefined, onResize: () => void) => (() => void);
@@ -1,4 +1,4 @@
1
- export const observeCanvasResize = (element, _canvas, onResize) => {
1
+ export const observeCanvasResize = (element, canvas, onResize) => {
2
2
  let timeoutId = null;
3
3
  const debouncedResize = () => {
4
4
  if (timeoutId)
@@ -7,6 +7,21 @@ export const observeCanvasResize = (element, _canvas, onResize) => {
7
7
  onResize();
8
8
  }, 100);
9
9
  };
10
+ const view = canvas ? element.ownerDocument?.defaultView ?? null : null;
11
+ let resolution = null;
12
+ function onResolutionChange() {
13
+ resolution?.removeEventListener("change", onResolutionChange);
14
+ armResolution();
15
+ debouncedResize();
16
+ }
17
+ function armResolution() {
18
+ if (!view?.matchMedia)
19
+ return;
20
+ resolution = view.matchMedia(`(resolution: ${view.devicePixelRatio || 1}dppx)`);
21
+ resolution.addEventListener("change", onResolutionChange);
22
+ }
23
+ armResolution();
24
+ let stopWidth;
10
25
  if (typeof ResizeObserver !== 'undefined') {
11
26
  let seen = -1;
12
27
  const observer = new ResizeObserver((entries) => {
@@ -19,18 +34,16 @@ export const observeCanvasResize = (element, _canvas, onResize) => {
19
34
  }
20
35
  });
21
36
  observer.observe(element);
22
- return () => {
23
- if (timeoutId)
24
- clearTimeout(timeoutId);
25
- observer.disconnect();
26
- };
37
+ stopWidth = () => observer.disconnect();
27
38
  }
28
39
  else {
29
40
  window.addEventListener('resize', debouncedResize);
30
- return () => {
31
- if (timeoutId)
32
- clearTimeout(timeoutId);
33
- window.removeEventListener('resize', debouncedResize);
34
- };
41
+ stopWidth = () => window.removeEventListener('resize', debouncedResize);
35
42
  }
43
+ return () => {
44
+ if (timeoutId)
45
+ clearTimeout(timeoutId);
46
+ resolution?.removeEventListener("change", onResolutionChange);
47
+ stopWidth();
48
+ };
36
49
  };
@@ -56,134 +56,33 @@ export const normalizeClasses = (...classes) => {
56
56
  }
57
57
  return result;
58
58
  };
59
- export const addClass = (element, ...classes) => {
60
- if (classes.length === 0)
61
- return element;
62
- if (classes.length === 1 && Array.isArray(classes[0])) {
63
- return addClass(element, ...classes[0]);
64
- }
65
- if (classes.length === 1 && typeof classes[0] === "string") {
66
- const cls = classes[0];
67
- if (cls && !cls.includes(" ")) {
68
- const prefixed = cls;
69
- if (!prefixed.includes(" ")) {
70
- element.classList.add(prefixed);
71
- return element;
72
- }
73
- }
74
- }
75
- const normalized = normalizeClasses(...classes);
76
- for (const cls of normalized) {
77
- const prefixed = cls;
78
- if (prefixed.includes(" ")) {
79
- prefixed.split(" ").forEach((c) => {
80
- const trimmed = c.trim();
81
- if (trimmed)
82
- element.classList.add(trimmed);
83
- });
84
- }
85
- else {
86
- element.classList.add(prefixed);
87
- }
59
+ const forEachClass = (classes, apply) => {
60
+ if (classes.length === 1 &&
61
+ typeof classes[0] === "string" &&
62
+ classes[0] &&
63
+ !classes[0].includes(" ")) {
64
+ apply(classes[0]);
65
+ return;
88
66
  }
67
+ for (const name of normalizeClasses(...classes))
68
+ apply(name);
69
+ };
70
+ export const addClass = (element, ...classes) => {
71
+ forEachClass(classes, (name) => element.classList.add(name));
89
72
  return element;
90
73
  };
91
74
  export const removeClass = (element, ...classes) => {
92
- if (classes.length === 0)
93
- return element;
94
- if (classes.length === 1 && Array.isArray(classes[0])) {
95
- return removeClass(element, ...classes[0]);
96
- }
97
- if (classes.length === 1 && typeof classes[0] === "string") {
98
- const cls = classes[0];
99
- if (cls && !cls.includes(" ")) {
100
- const prefixed = cls;
101
- if (!prefixed.includes(" ")) {
102
- element.classList.remove(prefixed);
103
- return element;
104
- }
105
- }
106
- }
107
- const normalized = normalizeClasses(...classes);
108
- for (const cls of normalized) {
109
- const prefixed = cls;
110
- if (prefixed.includes(" ")) {
111
- prefixed.split(" ").forEach((c) => {
112
- const trimmed = c.trim();
113
- if (trimmed)
114
- element.classList.remove(trimmed);
115
- });
116
- }
117
- else {
118
- element.classList.remove(prefixed);
119
- }
120
- }
75
+ forEachClass(classes, (name) => element.classList.remove(name));
121
76
  return element;
122
77
  };
123
78
  export const toggleClass = (element, ...classes) => {
124
- if (classes.length === 1 && Array.isArray(classes[0])) {
125
- return toggleClass(element, ...classes[0]);
126
- }
127
- if (classes.length === 1 && typeof classes[0] === "string") {
128
- const cls = classes[0];
129
- if (cls && !cls.includes(" ")) {
130
- const prefixed = cls;
131
- if (!prefixed.includes(" ")) {
132
- element.classList.toggle(prefixed);
133
- return element;
134
- }
135
- }
136
- }
137
- const normalized = normalizeClasses(...classes);
138
- for (const cls of normalized) {
139
- const prefixed = cls;
140
- if (prefixed.includes(" ")) {
141
- prefixed.split(" ").forEach((c) => {
142
- const trimmed = c.trim();
143
- if (trimmed)
144
- element.classList.toggle(trimmed);
145
- });
146
- }
147
- else {
148
- element.classList.toggle(prefixed);
149
- }
150
- }
79
+ forEachClass(classes, (name) => element.classList.toggle(name));
151
80
  return element;
152
81
  };
153
82
  export const hasClass = (element, ...classes) => {
154
- if (classes.length === 0)
155
- return true;
156
- if (classes.length === 1 && Array.isArray(classes[0])) {
157
- return hasClass(element, ...classes[0]);
158
- }
159
- if (classes.length === 1 && typeof classes[0] === "string") {
160
- const cls = classes[0];
161
- if (cls && !cls.includes(" ")) {
162
- const prefixed = cls;
163
- if (!prefixed.includes(" ")) {
164
- return element.classList.contains(prefixed);
165
- }
166
- }
167
- }
168
- const normalized = normalizeClasses(...classes);
169
- for (const cls of normalized) {
170
- const prefixed = cls;
171
- if (prefixed.includes(" ")) {
172
- const tokens = prefixed
173
- .split(" ")
174
- .map((c) => c.trim())
175
- .filter(Boolean);
176
- for (const token of tokens) {
177
- if (!element.classList.contains(token)) {
178
- return false;
179
- }
180
- }
181
- }
182
- else {
183
- if (!element.classList.contains(prefixed)) {
184
- return false;
185
- }
186
- }
83
+ for (const name of normalizeClasses(...classes)) {
84
+ if (!element.classList.contains(name))
85
+ return false;
187
86
  }
188
87
  return true;
189
88
  };