@kubit-ui-web/react-charts 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/dist/cjs/charts/lineChart/fragments/lineChartPath.d.ts.map +1 -1
  2. package/dist/cjs/charts/lineChart/fragments/lineChartPath.js +8 -4
  3. package/dist/cjs/components/focusRing/components/FocusRingInline.d.ts +25 -0
  4. package/dist/cjs/components/focusRing/components/FocusRingInline.d.ts.map +1 -0
  5. package/dist/cjs/components/focusRing/components/FocusRingInline.js +37 -0
  6. package/dist/cjs/components/focusRing/components/FocusRingRenderer.d.ts +13 -0
  7. package/dist/cjs/components/focusRing/components/FocusRingRenderer.d.ts.map +1 -0
  8. package/dist/cjs/components/focusRing/components/FocusRingRenderer.js +25 -0
  9. package/dist/cjs/components/focusRing/components/FocusRingSeparate.d.ts +40 -0
  10. package/dist/cjs/components/focusRing/components/FocusRingSeparate.d.ts.map +1 -0
  11. package/dist/cjs/components/focusRing/components/FocusRingSeparate.js +45 -0
  12. package/dist/cjs/components/focusRing/focusRing.css +14 -0
  13. package/dist/cjs/components/focusRing/focusRing.d.ts +35 -0
  14. package/dist/cjs/components/focusRing/focusRing.d.ts.map +1 -0
  15. package/dist/cjs/components/focusRing/focusRing.js +44 -0
  16. package/dist/cjs/components/focusRing/focusRing.types.d.ts +40 -0
  17. package/dist/cjs/components/focusRing/focusRing.types.d.ts.map +1 -0
  18. package/dist/cjs/components/focusRing/focusRing.types.js +1 -0
  19. package/dist/cjs/components/focusRing/hooks/useFocusRingData.d.ts +27 -0
  20. package/dist/cjs/components/focusRing/hooks/useFocusRingData.d.ts.map +1 -0
  21. package/dist/cjs/components/focusRing/hooks/useFocusRingData.js +67 -0
  22. package/dist/cjs/components/focusRing/index.d.ts +3 -0
  23. package/dist/cjs/components/focusRing/index.d.ts.map +1 -0
  24. package/dist/cjs/components/focusRing/index.js +1 -0
  25. package/dist/cjs/components/focusRing/utils/composeRefs.d.ts +7 -0
  26. package/dist/cjs/components/focusRing/utils/composeRefs.d.ts.map +1 -0
  27. package/dist/cjs/components/focusRing/utils/composeRefs.js +16 -0
  28. package/dist/cjs/components/focusRing/utils/createAdaptiveFocusRings.d.ts +24 -0
  29. package/dist/cjs/components/focusRing/utils/createAdaptiveFocusRings.d.ts.map +1 -0
  30. package/dist/cjs/components/focusRing/utils/createAdaptiveFocusRings.js +141 -0
  31. package/dist/cjs/components/focusRing/utils/createBoundingBoxFocusRings.d.ts +33 -0
  32. package/dist/cjs/components/focusRing/utils/createBoundingBoxFocusRings.d.ts.map +1 -0
  33. package/dist/cjs/components/focusRing/utils/createBoundingBoxFocusRings.js +126 -0
  34. package/dist/cjs/components/focusRing/utils/utils.types.d.ts +52 -0
  35. package/dist/cjs/components/focusRing/utils/utils.types.d.ts.map +1 -0
  36. package/dist/cjs/components/focusRing/utils/utils.types.js +1 -0
  37. package/dist/cjs/components/index.d.ts +1 -0
  38. package/dist/cjs/components/index.d.ts.map +1 -1
  39. package/dist/cjs/components/index.js +1 -0
  40. package/dist/cjs/components/plot/plot.d.ts.map +1 -1
  41. package/dist/cjs/components/plot/plot.js +7 -19
  42. package/dist/cjs/components/zoomArea/components/SelectionArea.d.ts +3 -23
  43. package/dist/cjs/components/zoomArea/components/SelectionArea.d.ts.map +1 -1
  44. package/dist/cjs/components/zoomArea/components/SelectionArea.js +7 -39
  45. package/dist/cjs/components/zoomArea/components/ZoomHandler.d.ts +3 -3
  46. package/dist/cjs/components/zoomArea/components/ZoomHandler.d.ts.map +1 -1
  47. package/dist/cjs/components/zoomArea/components/ZoomHandler.js +2 -15
  48. package/dist/cjs/components/zoomArea/components/index.d.ts +1 -1
  49. package/dist/cjs/components/zoomArea/components/index.d.ts.map +1 -1
  50. package/dist/cjs/components/zoomArea/components/index.js +1 -1
  51. package/dist/cjs/components/zoomArea/zoomArea.js +6 -6
  52. package/dist/cjs/components/zoomArea/zoomArea.type.d.ts +1 -1
  53. package/dist/cjs/components/zoomArea/zoomArea.type.d.ts.map +1 -1
  54. package/dist/cjs/types/focusConfig.type.d.ts +15 -3
  55. package/dist/cjs/types/focusConfig.type.d.ts.map +1 -1
  56. package/dist/cjs/types/focusConfig.type.js +14 -1
  57. package/dist/esm/charts/lineChart/fragments/lineChartPath.d.ts.map +1 -1
  58. package/dist/esm/charts/lineChart/fragments/lineChartPath.js +8 -4
  59. package/dist/esm/components/focusRing/components/FocusRingInline.d.ts +25 -0
  60. package/dist/esm/components/focusRing/components/FocusRingInline.d.ts.map +1 -0
  61. package/dist/esm/components/focusRing/components/FocusRingInline.js +37 -0
  62. package/dist/esm/components/focusRing/components/FocusRingRenderer.d.ts +13 -0
  63. package/dist/esm/components/focusRing/components/FocusRingRenderer.d.ts.map +1 -0
  64. package/dist/esm/components/focusRing/components/FocusRingRenderer.js +25 -0
  65. package/dist/esm/components/focusRing/components/FocusRingSeparate.d.ts +40 -0
  66. package/dist/esm/components/focusRing/components/FocusRingSeparate.d.ts.map +1 -0
  67. package/dist/esm/components/focusRing/components/FocusRingSeparate.js +45 -0
  68. package/dist/esm/components/focusRing/focusRing.css +14 -0
  69. package/dist/esm/components/focusRing/focusRing.d.ts +35 -0
  70. package/dist/esm/components/focusRing/focusRing.d.ts.map +1 -0
  71. package/dist/esm/components/focusRing/focusRing.js +44 -0
  72. package/dist/esm/components/focusRing/focusRing.types.d.ts +40 -0
  73. package/dist/esm/components/focusRing/focusRing.types.d.ts.map +1 -0
  74. package/dist/esm/components/focusRing/focusRing.types.js +1 -0
  75. package/dist/esm/components/focusRing/hooks/useFocusRingData.d.ts +27 -0
  76. package/dist/esm/components/focusRing/hooks/useFocusRingData.d.ts.map +1 -0
  77. package/dist/esm/components/focusRing/hooks/useFocusRingData.js +67 -0
  78. package/dist/esm/components/focusRing/index.d.ts +3 -0
  79. package/dist/esm/components/focusRing/index.d.ts.map +1 -0
  80. package/dist/esm/components/focusRing/index.js +1 -0
  81. package/dist/esm/components/focusRing/utils/composeRefs.d.ts +7 -0
  82. package/dist/esm/components/focusRing/utils/composeRefs.d.ts.map +1 -0
  83. package/dist/esm/components/focusRing/utils/composeRefs.js +16 -0
  84. package/dist/esm/components/focusRing/utils/createAdaptiveFocusRings.d.ts +24 -0
  85. package/dist/esm/components/focusRing/utils/createAdaptiveFocusRings.d.ts.map +1 -0
  86. package/dist/esm/components/focusRing/utils/createAdaptiveFocusRings.js +141 -0
  87. package/dist/esm/components/focusRing/utils/createBoundingBoxFocusRings.d.ts +33 -0
  88. package/dist/esm/components/focusRing/utils/createBoundingBoxFocusRings.d.ts.map +1 -0
  89. package/dist/esm/components/focusRing/utils/createBoundingBoxFocusRings.js +126 -0
  90. package/dist/esm/components/focusRing/utils/utils.types.d.ts +52 -0
  91. package/dist/esm/components/focusRing/utils/utils.types.d.ts.map +1 -0
  92. package/dist/esm/components/focusRing/utils/utils.types.js +1 -0
  93. package/dist/esm/components/index.d.ts +1 -0
  94. package/dist/esm/components/index.d.ts.map +1 -1
  95. package/dist/esm/components/index.js +1 -0
  96. package/dist/esm/components/plot/plot.d.ts.map +1 -1
  97. package/dist/esm/components/plot/plot.js +7 -19
  98. package/dist/esm/components/zoomArea/components/SelectionArea.d.ts +3 -23
  99. package/dist/esm/components/zoomArea/components/SelectionArea.d.ts.map +1 -1
  100. package/dist/esm/components/zoomArea/components/SelectionArea.js +7 -39
  101. package/dist/esm/components/zoomArea/components/ZoomHandler.d.ts +3 -3
  102. package/dist/esm/components/zoomArea/components/ZoomHandler.d.ts.map +1 -1
  103. package/dist/esm/components/zoomArea/components/ZoomHandler.js +2 -15
  104. package/dist/esm/components/zoomArea/components/index.d.ts +1 -1
  105. package/dist/esm/components/zoomArea/components/index.d.ts.map +1 -1
  106. package/dist/esm/components/zoomArea/components/index.js +1 -1
  107. package/dist/esm/components/zoomArea/zoomArea.js +6 -6
  108. package/dist/esm/components/zoomArea/zoomArea.type.d.ts +1 -1
  109. package/dist/esm/components/zoomArea/zoomArea.type.d.ts.map +1 -1
  110. package/dist/esm/types/focusConfig.type.d.ts +15 -3
  111. package/dist/esm/types/focusConfig.type.d.ts.map +1 -1
  112. package/dist/esm/types/focusConfig.type.js +14 -1
  113. package/dist/kubit-ui-web-react-charts.cjs.js +1 -1
  114. package/dist/kubit-ui-web-react-charts.es.js +1 -1
  115. package/dist/kubit-ui-web-react-charts.umd.js +1 -1
  116. package/dist/react-charts.css +1 -1
  117. package/dist/types/charts/lineChart/fragments/lineChartPath.d.ts.map +1 -1
  118. package/dist/types/components/focusRing/components/FocusRingInline.d.ts +25 -0
  119. package/dist/types/components/focusRing/components/FocusRingInline.d.ts.map +1 -0
  120. package/dist/types/components/focusRing/components/FocusRingRenderer.d.ts +13 -0
  121. package/dist/types/components/focusRing/components/FocusRingRenderer.d.ts.map +1 -0
  122. package/dist/types/components/focusRing/components/FocusRingSeparate.d.ts +40 -0
  123. package/dist/types/components/focusRing/components/FocusRingSeparate.d.ts.map +1 -0
  124. package/dist/types/components/focusRing/focusRing.d.ts +34 -0
  125. package/dist/types/components/focusRing/focusRing.d.ts.map +1 -0
  126. package/dist/types/components/focusRing/focusRing.types.d.ts +40 -0
  127. package/dist/types/components/focusRing/focusRing.types.d.ts.map +1 -0
  128. package/dist/types/components/focusRing/hooks/useFocusRingData.d.ts +27 -0
  129. package/dist/types/components/focusRing/hooks/useFocusRingData.d.ts.map +1 -0
  130. package/dist/types/components/focusRing/index.d.ts +3 -0
  131. package/dist/types/components/focusRing/index.d.ts.map +1 -0
  132. package/dist/types/components/focusRing/utils/composeRefs.d.ts +7 -0
  133. package/dist/types/components/focusRing/utils/composeRefs.d.ts.map +1 -0
  134. package/dist/types/components/focusRing/utils/createAdaptiveFocusRings.d.ts +24 -0
  135. package/dist/types/components/focusRing/utils/createAdaptiveFocusRings.d.ts.map +1 -0
  136. package/dist/types/components/focusRing/utils/createBoundingBoxFocusRings.d.ts +33 -0
  137. package/dist/types/components/focusRing/utils/createBoundingBoxFocusRings.d.ts.map +1 -0
  138. package/dist/types/components/focusRing/utils/utils.types.d.ts +52 -0
  139. package/dist/types/components/focusRing/utils/utils.types.d.ts.map +1 -0
  140. package/dist/types/components/index.d.ts +1 -0
  141. package/dist/types/components/index.d.ts.map +1 -1
  142. package/dist/types/components/plot/plot.d.ts.map +1 -1
  143. package/dist/types/components/zoomArea/components/SelectionArea.d.ts +3 -23
  144. package/dist/types/components/zoomArea/components/SelectionArea.d.ts.map +1 -1
  145. package/dist/types/components/zoomArea/components/ZoomHandler.d.ts +3 -3
  146. package/dist/types/components/zoomArea/components/ZoomHandler.d.ts.map +1 -1
  147. package/dist/types/components/zoomArea/components/index.d.ts +1 -1
  148. package/dist/types/components/zoomArea/components/index.d.ts.map +1 -1
  149. package/dist/types/components/zoomArea/zoomArea.type.d.ts +1 -1
  150. package/dist/types/components/zoomArea/zoomArea.type.d.ts.map +1 -1
  151. package/dist/types/types/focusConfig.type.d.ts +15 -3
  152. package/dist/types/types/focusConfig.type.d.ts.map +1 -1
  153. package/package.json +1 -1
  154. package/dist/cjs/utils/calculateFocusOutline/calculateFocusOutline.d.ts +0 -73
  155. package/dist/cjs/utils/calculateFocusOutline/calculateFocusOutline.d.ts.map +0 -1
  156. package/dist/cjs/utils/calculateFocusOutline/calculateFocusOutline.js +0 -80
  157. package/dist/esm/utils/calculateFocusOutline/calculateFocusOutline.d.ts +0 -73
  158. package/dist/esm/utils/calculateFocusOutline/calculateFocusOutline.d.ts.map +0 -1
  159. package/dist/esm/utils/calculateFocusOutline/calculateFocusOutline.js +0 -80
  160. package/dist/types/utils/calculateFocusOutline/calculateFocusOutline.d.ts +0 -73
  161. package/dist/types/utils/calculateFocusOutline/calculateFocusOutline.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/focusRing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1 @@
1
+ export { FocusRing } from './focusRing';
@@ -0,0 +1,7 @@
1
+ import type { ForwardedRef } from 'react';
2
+ /**
3
+ * Composes multiple refs into a single ref callback
4
+ * Allows using both internal and external refs simultaneously
5
+ */
6
+ export declare function composeRefs<T>(...refs: Array<ForwardedRef<T> | undefined>): (instance: T | null) => void;
7
+ //# sourceMappingURL=composeRefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composeRefs.d.ts","sourceRoot":"","sources":["../../../../../src/components/focusRing/utils/composeRefs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,GAAG,IAAI,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,GAC1C,CAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAU9B"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Composes multiple refs into a single ref callback
3
+ * Allows using both internal and external refs simultaneously
4
+ */
5
+ export function composeRefs(...refs) {
6
+ return (instance) => {
7
+ refs.forEach(ref => {
8
+ if (typeof ref === 'function') {
9
+ ref(instance);
10
+ }
11
+ else if (ref) {
12
+ ref.current = instance;
13
+ }
14
+ });
15
+ };
16
+ }
@@ -0,0 +1,24 @@
1
+ import type { FocusConfig } from '../../../types/focusConfig.type';
2
+ import type { FocusRingLayers } from './utils.types';
3
+ /**
4
+ * SVG geometric attributes that define shape position and dimensions.
5
+ * These attributes are extracted from the original element to create focus rings.
6
+ * Also used by MutationObserver to detect when focus rings need to be regenerated.
7
+ */
8
+ export declare const SVG_GEOMETRIC_ATTRIBUTES: string[];
9
+ /**
10
+ * Creates adaptive focus ring layers from a DOM SVGElement.
11
+ *
12
+ * This function reads properties directly from the DOM element and creates
13
+ * props objects for rendering new SVG elements with scaled stroke-width for the focus rings.
14
+ * The focus rings adapt to the exact shape of the element (circle → circle, path → path, etc.)
15
+ *
16
+ * This unified approach works for both targetRef and children modes by
17
+ * reading from the mounted DOM element.
18
+ *
19
+ * @param element - The SVG graphics element to create focus rings for
20
+ * @param focusConfig - Focus ring configuration (colors, widths, gap)
21
+ * @returns Focus ring layers (outer and inner props) or null if not supported
22
+ */
23
+ export declare function createAdaptiveFocusRings(element: SVGGraphicsElement, focusConfig: Required<FocusConfig>): FocusRingLayers | undefined;
24
+ //# sourceMappingURL=createAdaptiveFocusRings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createAdaptiveFocusRings.d.ts","sourceRoot":"","sources":["../../../../../src/components/focusRing/utils/createAdaptiveFocusRings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,UAsBpC,CAAC;AAqBF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,GACjC,eAAe,GAAG,SAAS,CAkE7B"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * SVG geometric attributes that define shape position and dimensions.
3
+ * These attributes are extracted from the original element to create focus rings.
4
+ * Also used by MutationObserver to detect when focus rings need to be regenerated.
5
+ */
6
+ export const SVG_GEOMETRIC_ATTRIBUTES = [
7
+ // Circle attributes
8
+ 'cx',
9
+ 'cy',
10
+ 'r',
11
+ // Rectangle and general positioning attributes
12
+ 'x',
13
+ 'y',
14
+ 'width',
15
+ 'height',
16
+ // Ellipse attributes (cx, cy already included)
17
+ 'rx',
18
+ 'ry',
19
+ // Path attributes
20
+ 'd',
21
+ // Polygon and polyline attributes
22
+ 'points',
23
+ // Line attributes
24
+ 'x1',
25
+ 'y1',
26
+ 'x2',
27
+ 'y2',
28
+ ];
29
+ /**
30
+ * SVG presentation attributes that affect stroke appearance.
31
+ * These are preserved for focus rings when they match the original element's style.
32
+ */
33
+ const SVG_STROKE_ATTRIBUTES = [
34
+ 'stroke-dasharray',
35
+ 'stroke-dashoffset',
36
+ 'stroke-linecap',
37
+ 'stroke-linejoin',
38
+ 'stroke-miterlimit',
39
+ 'stroke-opacity',
40
+ ];
41
+ /**
42
+ * SVG element types that support adaptive focus rings.
43
+ * These are geometric shapes that can be properly outlined with focus rings.
44
+ */
45
+ const SUPPORTED_SVG_TYPES = ['circle', 'rect', 'ellipse', 'path', 'polygon', 'polyline', 'line'];
46
+ /**
47
+ * Creates adaptive focus ring layers from a DOM SVGElement.
48
+ *
49
+ * This function reads properties directly from the DOM element and creates
50
+ * props objects for rendering new SVG elements with scaled stroke-width for the focus rings.
51
+ * The focus rings adapt to the exact shape of the element (circle → circle, path → path, etc.)
52
+ *
53
+ * This unified approach works for both targetRef and children modes by
54
+ * reading from the mounted DOM element.
55
+ *
56
+ * @param element - The SVG graphics element to create focus rings for
57
+ * @param focusConfig - Focus ring configuration (colors, widths, gap)
58
+ * @returns Focus ring layers (outer and inner props) or null if not supported
59
+ */
60
+ export function createAdaptiveFocusRings(element, focusConfig) {
61
+ const elementType = element.tagName.toLowerCase();
62
+ // Validate that we have a valid SVG element
63
+ if (!SUPPORTED_SVG_TYPES.includes(elementType)) {
64
+ return undefined;
65
+ }
66
+ // Read original stroke width from DOM
67
+ const strokeWidthAttr = element.getAttribute('stroke-width') || element.getAttribute('strokeWidth');
68
+ const originalStrokeWidth = parseFloat(strokeWidthAttr || '0');
69
+ // Read fill attribute to detect open lines
70
+ const fillAttr = element.getAttribute('fill');
71
+ const isOpenLine = elementType === 'line' ||
72
+ elementType === 'polyline' ||
73
+ (elementType === 'path' && fillAttr === 'none');
74
+ // Calculate stroke widths for focus rings
75
+ // IMPORTANT: For ALL shapes, we need to account for the original stroke width
76
+ // so that focus rings appear OUTSIDE the element's stroke, not covered by it
77
+ const outerStrokeWidth = originalStrokeWidth + (focusConfig.outlineStrokeWidth + focusConfig.innerStrokeWidth) * 2;
78
+ const innerStrokeWidth = originalStrokeWidth + focusConfig.innerStrokeWidth * 2;
79
+ // Read stroke line props for open lines
80
+ const strokeLinecap = isOpenLine ? element.getAttribute('stroke-linecap') || 'round' : undefined;
81
+ const strokeLinejoin = isOpenLine ? element.getAttribute('stroke-linejoin') || 'round' : 'miter';
82
+ const strokeMiterlimit = isOpenLine ? undefined : '10';
83
+ // Extract relevant attributes from the DOM element
84
+ // This automatically preserves all geometric attributes (cx, cy, r, x, y, width, height, d, points, etc.)
85
+ const allAttributes = extractRelevantAttributes(element);
86
+ // The renderer will create the React elements and add data-testid
87
+ return {
88
+ innerRing: {
89
+ props: {
90
+ ...allAttributes,
91
+ className: 'focus-ring-inner',
92
+ fill: 'none',
93
+ stroke: focusConfig.innerColor,
94
+ strokeLinecap,
95
+ strokeLinejoin,
96
+ strokeMiterlimit,
97
+ strokeWidth: innerStrokeWidth,
98
+ },
99
+ type: elementType,
100
+ },
101
+ outerRing: {
102
+ props: {
103
+ ...allAttributes,
104
+ className: 'focus-ring-outer',
105
+ fill: 'none',
106
+ stroke: focusConfig.outlineColor,
107
+ strokeLinecap,
108
+ strokeLinejoin,
109
+ strokeMiterlimit,
110
+ strokeWidth: outerStrokeWidth,
111
+ },
112
+ type: elementType,
113
+ },
114
+ };
115
+ }
116
+ /**
117
+ * Extracts relevant SVG attributes from a DOM SVGElement for focus ring creation.
118
+ * Uses an allowlist approach: only geometric and stroke attributes are included.
119
+ * This ensures focus rings inherit the correct shape and appearance while avoiding
120
+ * React-incompatible attributes or those that would cause DOM conflicts.
121
+ *
122
+ * @param element - The SVG element to extract attributes from
123
+ * @returns Object containing only the allowed attributes
124
+ */
125
+ function extractRelevantAttributes(element) {
126
+ const attrs = {};
127
+ // Create a Set of allowed attributes for fast lookup
128
+ const allowedAttributes = new Set([
129
+ ...SVG_GEOMETRIC_ATTRIBUTES,
130
+ ...SVG_STROKE_ATTRIBUTES,
131
+ ]);
132
+ // Iterate through all attributes of the element
133
+ for (let i = 0; i < element.attributes.length; i++) {
134
+ const attr = element.attributes[i];
135
+ // Only include attributes that are in the allowlist
136
+ if (allowedAttributes.has(attr.name)) {
137
+ attrs[attr.name] = attr.value;
138
+ }
139
+ }
140
+ return attrs;
141
+ }
@@ -0,0 +1,33 @@
1
+ import type { FocusConfig } from '../../../types/focusConfig.type';
2
+ import type { ElementBounds, FocusRingLayers, RectangleFocusOutline } from './utils.types';
3
+ /**
4
+ * Calculates the dimensions of the focus outlines (outer and inner) for a bounding-box.
5
+ * This function is used internally by createBoundingBoxFocusRings and always produces
6
+ * rectangular focus rings.
7
+ *
8
+ * @param bounds - Element bounds information from DOM detection
9
+ * @param config - Focus stroke configuration (widths and gap)
10
+ * @returns Rectangle dimensions for outer and inner focus rings
11
+ */
12
+ export declare const calculateBoundingBoxFocusRings: (bounds: ElementBounds, config: {
13
+ outlineStrokeWidth: number;
14
+ innerStrokeWidth: number;
15
+ gap: number;
16
+ }) => RectangleFocusOutline;
17
+ /**
18
+ * Creates bounding-box focus ring layers with calculated dimensions.
19
+ *
20
+ * This function:
21
+ * 1. Detects element bounds from DOM using getBBox()
22
+ * 2. Calculates geometric dimensions using calculateBoundingBoxFocusRings
23
+ * 3. Wraps the result in the same FocusRingLayers structure as createAdaptiveFocusRings
24
+ * 4. Includes all rendering props (colors, strokes, etc.)
25
+ *
26
+ * This provides a unified API for both adaptive and bounding-box strategies.
27
+ *
28
+ * @param element - The SVG graphics element to create focus rings for
29
+ * @param focusConfig - Focus ring configuration (colors, widths, gap)
30
+ * @returns Focus ring layers in the same format as createAdaptiveFocusRings, or null if detection fails
31
+ */
32
+ export declare function createBoundingBoxFocusRings(element: SVGGraphicsElement, focusConfig: Required<FocusConfig>): FocusRingLayers | undefined;
33
+ //# sourceMappingURL=createBoundingBoxFocusRings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createBoundingBoxFocusRings.d.ts","sourceRoot":"","sources":["../../../../../src/components/focusRing/utils/createBoundingBoxFocusRings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE3F;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,GACzC,QAAQ,aAAa,EACrB,QAAQ;IACN,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;CACb,KACA,qBAkCF,CAAC;AAiCF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,GACjC,eAAe,GAAG,SAAS,CA0C7B"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Calculates the dimensions of the focus outlines (outer and inner) for a bounding-box.
3
+ * This function is used internally by createBoundingBoxFocusRings and always produces
4
+ * rectangular focus rings.
5
+ *
6
+ * @param bounds - Element bounds information from DOM detection
7
+ * @param config - Focus stroke configuration (widths and gap)
8
+ * @returns Rectangle dimensions for outer and inner focus rings
9
+ */
10
+ export const calculateBoundingBoxFocusRings = (bounds, config) => {
11
+ const { elementHeight, elementPosition, elementStrokeWidth, elementWidth } = bounds;
12
+ const { gap, innerStrokeWidth, outlineStrokeWidth } = config;
13
+ // Calculate inner rectangle dimensions
14
+ // Height and width must grow on both sides to ensure the inner rectangle
15
+ // is positioned correctly without gaps
16
+ const innerWidth = elementWidth + elementStrokeWidth + innerStrokeWidth + gap * 2;
17
+ const innerHeight = elementHeight + elementStrokeWidth + innerStrokeWidth + gap * 2;
18
+ const innerX = elementPosition.x - innerWidth / 2;
19
+ const innerY = elementPosition.y - innerHeight / 2;
20
+ // Calculate outer rectangle dimensions
21
+ // Must account for the fact that both inner and outer strokes extend outward from their borders
22
+ // Inner stroke extends innerStrokeWidth/2 on each side, outer stroke extends outlineStrokeWidth/2 on each side
23
+ const outerWidth = innerWidth + innerStrokeWidth + outlineStrokeWidth;
24
+ const outerHeight = innerHeight + innerStrokeWidth + outlineStrokeWidth;
25
+ const outerX = elementPosition.x - outerWidth / 2;
26
+ const outerY = elementPosition.y - outerHeight / 2;
27
+ return {
28
+ inner: {
29
+ height: innerHeight,
30
+ width: innerWidth,
31
+ x: innerX,
32
+ y: innerY,
33
+ },
34
+ outer: {
35
+ height: outerHeight,
36
+ width: outerWidth,
37
+ x: outerX,
38
+ y: outerY,
39
+ },
40
+ };
41
+ };
42
+ /**
43
+ * Helper function to detect element bounds from the DOM.
44
+ * Uses getBBox() for accurate measurements including transforms.
45
+ *
46
+ * @param element - SVG element to detect
47
+ * @returns Element bounds information or null if detection fails
48
+ */
49
+ function detectElementBoundsFromDOM(element) {
50
+ try {
51
+ const bbox = element.getBBox();
52
+ if (bbox.width <= 0 || bbox.height <= 0) {
53
+ return null;
54
+ }
55
+ const computedStyle = window.getComputedStyle(element);
56
+ const strokeWidth = parseFloat(computedStyle.strokeWidth || '0');
57
+ return {
58
+ elementHeight: bbox.height,
59
+ elementPosition: {
60
+ x: bbox.x + bbox.width / 2,
61
+ y: bbox.y + bbox.height / 2,
62
+ },
63
+ elementStrokeWidth: strokeWidth,
64
+ elementWidth: bbox.width,
65
+ };
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ /**
72
+ * Creates bounding-box focus ring layers with calculated dimensions.
73
+ *
74
+ * This function:
75
+ * 1. Detects element bounds from DOM using getBBox()
76
+ * 2. Calculates geometric dimensions using calculateBoundingBoxFocusRings
77
+ * 3. Wraps the result in the same FocusRingLayers structure as createAdaptiveFocusRings
78
+ * 4. Includes all rendering props (colors, strokes, etc.)
79
+ *
80
+ * This provides a unified API for both adaptive and bounding-box strategies.
81
+ *
82
+ * @param element - The SVG graphics element to create focus rings for
83
+ * @param focusConfig - Focus ring configuration (colors, widths, gap)
84
+ * @returns Focus ring layers in the same format as createAdaptiveFocusRings, or null if detection fails
85
+ */
86
+ export function createBoundingBoxFocusRings(element, focusConfig) {
87
+ // Detect element bounds from DOM
88
+ const bounds = detectElementBoundsFromDOM(element);
89
+ if (!bounds) {
90
+ return undefined;
91
+ }
92
+ const dimensions = calculateBoundingBoxFocusRings(bounds, {
93
+ gap: focusConfig.gap,
94
+ innerStrokeWidth: focusConfig.innerStrokeWidth,
95
+ outlineStrokeWidth: focusConfig.outlineStrokeWidth,
96
+ });
97
+ // The renderer will create the React elements and add data-testid
98
+ return {
99
+ innerRing: {
100
+ props: {
101
+ className: 'focus-ring-inner',
102
+ fill: 'none',
103
+ height: dimensions.inner.height,
104
+ stroke: focusConfig.innerColor,
105
+ strokeWidth: focusConfig.innerStrokeWidth,
106
+ width: dimensions.inner.width,
107
+ x: dimensions.inner.x,
108
+ y: dimensions.inner.y,
109
+ },
110
+ type: 'rect',
111
+ },
112
+ outerRing: {
113
+ props: {
114
+ className: 'focus-ring-outer',
115
+ fill: 'none',
116
+ height: dimensions.outer.height,
117
+ stroke: focusConfig.outlineColor,
118
+ strokeWidth: focusConfig.outlineStrokeWidth,
119
+ width: dimensions.outer.width,
120
+ x: dimensions.outer.x,
121
+ y: dimensions.outer.y,
122
+ },
123
+ type: 'rect',
124
+ },
125
+ };
126
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Props for rendering a focus ring element
3
+ */
4
+ export interface FocusRingElementProps {
5
+ /** SVG element type (e.g., 'circle', 'rect', 'path') */
6
+ type: string;
7
+ /** Props to pass to React.createElement */
8
+ props: Record<string, unknown>;
9
+ }
10
+ /**
11
+ * Result of creating focus ring layers
12
+ */
13
+ export interface FocusRingLayers {
14
+ /** Outer focus ring element props (blue) */
15
+ outerRing: FocusRingElementProps;
16
+ /** Inner focus ring element props (white) */
17
+ innerRing: FocusRingElementProps;
18
+ }
19
+ /**
20
+ * Element bounds information from DOM detection
21
+ */
22
+ export interface ElementBounds {
23
+ /** Element width in pixels */
24
+ elementWidth: number;
25
+ /** Element height in pixels */
26
+ elementHeight: number;
27
+ /** Position of the element center */
28
+ elementPosition: {
29
+ x: number;
30
+ y: number;
31
+ };
32
+ /** Stroke width of the element */
33
+ elementStrokeWidth: number;
34
+ }
35
+ /**
36
+ * Dimensions for rectangle focus outlines
37
+ */
38
+ export interface RectangleFocusOutline {
39
+ outer: {
40
+ x: number;
41
+ y: number;
42
+ width: number;
43
+ height: number;
44
+ };
45
+ inner: {
46
+ x: number;
47
+ y: number;
48
+ width: number;
49
+ height: number;
50
+ };
51
+ }
52
+ //# sourceMappingURL=utils.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/focusRing/utils/utils.types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,SAAS,EAAE,qBAAqB,CAAC;IACjC,6CAA6C;IAC7C,SAAS,EAAE,qBAAqB,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,qCAAqC;IACrC,eAAe,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,kCAAkC;IAClC,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE;QACL,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,EAAE;QACL,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,7 @@
1
1
  export * from './axisChart';
2
2
  export * from './bar';
3
3
  export * from './chartText';
4
+ export * from './focusRing';
4
5
  export * from './foreignObject';
5
6
  export * from './line';
6
7
  export * from './node';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC"}
@@ -1,6 +1,7 @@
1
1
  export * from './axisChart';
2
2
  export * from './bar';
3
3
  export * from './chartText';
4
+ export * from './focusRing';
4
5
  export * from './foreignObject';
5
6
  export * from './line';
6
7
  export * from './node';
@@ -1 +1 @@
1
- {"version":3,"file":"plot.d.ts","sourceRoot":"","sources":["../../../../src/components/plot/plot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAc,MAAM,OAAO,CAAC;AAYtD,OAAO,YAAY,CAAC;AACpB,OAAO,EAAiB,KAAK,SAAS,EAAsB,MAAM,cAAc,CAAC;AA+IjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,IAAI,EAAgC,CAAC,CAAC,GAAG,MAAM,EAC1D,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG;IACpB,GAAG,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;CAChC,KACE,GAAG,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"plot.d.ts","sourceRoot":"","sources":["../../../../src/components/plot/plot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAc,MAAM,OAAO,CAAC;AAStD,OAAO,YAAY,CAAC;AACpB,OAAO,EAAiB,KAAK,SAAS,EAAsB,MAAM,cAAc,CAAC;AA2GjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,IAAI,EAAgC,CAAC,CAAC,GAAG,MAAM,EAC1D,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG;IACpB,GAAG,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,CAAC;CAChC,KACE,GAAG,CAAC,OAAO,CAAC"}
@@ -1,8 +1,8 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef } from 'react';
3
+ import { FocusRing } from '../../components/focusRing/focusRing';
3
4
  import { useFocus } from '../../hooks/useFocus/useFocus';
4
5
  import { useHover } from '../../hooks/useHover/useHover';
5
- import { calculateFocusOutline, getFocusConfig, } from '../../utils/calculateFocusOutline/calculateFocusOutline';
6
6
  import { Circle } from './components/circle/circle';
7
7
  import { Square } from './components/square/square';
8
8
  import { Triangle } from './components/triangle/triangle';
@@ -15,25 +15,13 @@ const Component = {
15
15
  [PlotType.TRIANGLE]: Triangle,
16
16
  };
17
17
  const PlotComponent = ({ className, data, dataTestId = 'plot', fill, fillOpacity, focusConfig, hasHoverEffect, hoverConfig, id, label, onBlur, onClick, onFocus, onKeyDown, onMouseEnter, onMouseLeave, opacity, position = { x: 0, y: 0 }, size = PlotSize.MEDIUM, stroke, strokeWidth, tabIndex, type = PlotType.CIRCLE, ...props }, ref) => {
18
- const { handleBlur, handleFocus, isFocused } = useFocus(onFocus, onBlur);
19
18
  const { handleMouseEnter, handleMouseLeave, isHovered } = useHover(onMouseEnter, onMouseLeave);
19
+ const { handleBlur, handleFocus, isFocused } = useFocus(onFocus, onBlur);
20
20
  // Extract properties from hoverConfig with default values
21
21
  const { fill: hoverFill = fill, opacity: hoverOpacity = 0.3, scale: hoverScale = 1.3, stroke: hoverStroke = fill, strokeWidth: hoverStrokeWidth = 0, } = hoverConfig || {};
22
- // Extract properties from focusConfig with default values
23
- const resolvedFocusConfig = getFocusConfig(focusConfig);
24
- // Calculate focus outline dimensions using the utility
22
+ // Calculate size in pixels
25
23
  const sizeInPixels = typeof size === 'number' ? size : PLOT_SIZE_MAP[size];
26
- const focusOutline = calculateFocusOutline({
27
- elementHeight: sizeInPixels,
28
- elementPosition: position,
29
- elementStrokeWidth: strokeWidth,
30
- elementType: 'rectangle',
31
- elementWidth: sizeInPixels,
32
- gap: resolvedFocusConfig.gap,
33
- innerStrokeWidth: resolvedFocusConfig.innerStrokeWidth,
34
- outlineStrokeWidth: resolvedFocusConfig.outlineStrokeWidth,
35
- });
36
- // Properties for the main plot shape - no hover styles applied to the main component
24
+ // Properties for the main plot shape - focus handlers managed by FocusRing
37
25
  const plotShapeProps = {
38
26
  ...props,
39
27
  ['aria-label']: label,
@@ -53,12 +41,12 @@ const PlotComponent = ({ className, data, dataTestId = 'plot', fill, fillOpacity
53
41
  role: 'button',
54
42
  size: sizeInPixels,
55
43
  stroke, // Maintains original stroke color
56
- strokeWidth: hasHoverEffect && isHovered && !isFocused ? 0 : strokeWidth,
44
+ strokeWidth: hasHoverEffect && isHovered ? 0 : strokeWidth, // Removed isFocused dependency
57
45
  tabIndex,
58
46
  };
59
47
  // Get the correct component based on type
60
48
  const PlotShape = Component[type];
61
- return (_jsxs(_Fragment, { children: [hasHoverEffect && isHovered && !isFocused && (_jsx(PlotShape, { dataTestId: `${dataTestId}-hover`, fill: hoverFill, opacity: hoverOpacity, position: position, size: sizeInPixels * hoverScale, stroke: hoverStroke, strokeWidth: hoverStrokeWidth })), isFocused && focusOutline.type === 'rectangle' && (_jsxs("g", { children: [_jsx("rect", { className: "plot-focus-outer", "data-testid": `${dataTestId}-focus-outer`, fill: "none", height: focusOutline.outer.height, stroke: resolvedFocusConfig.outlineColor, strokeWidth: resolvedFocusConfig.outlineStrokeWidth, width: focusOutline.outer.width, x: focusOutline.outer.x, y: focusOutline.outer.y }), _jsx("rect", { className: "plot-focus-inner", "data-testid": `${dataTestId}-focus-inner`, fill: "none", height: focusOutline.inner.height, stroke: resolvedFocusConfig.innerColor, strokeWidth: resolvedFocusConfig.innerStrokeWidth, width: focusOutline.inner.width, x: focusOutline.inner.x, y: focusOutline.inner.y })] })), _jsx(PlotShape, { ref: ref, ...plotShapeProps })] }));
49
+ return (_jsxs(_Fragment, { children: [hasHoverEffect && isHovered && !isFocused && (_jsx(PlotShape, { dataTestId: `${dataTestId}-hover`, fill: hoverFill, opacity: hoverOpacity, position: position, size: sizeInPixels * hoverScale, stroke: hoverStroke, strokeWidth: hoverStrokeWidth })), _jsx(FocusRing, { dataTestId: dataTestId, focusConfig: { ...focusConfig, variant: focusConfig?.variant ?? 'bounding-box' }, isFocused: isFocused, children: _jsx(PlotShape, { ref: ref, ...plotShapeProps }) })] }));
62
50
  };
63
51
  /**
64
52
  * `Plot` component which renders an interactive point in a chart with hover effects and accessibility features.
@@ -1,5 +1,4 @@
1
- import type { FC, KeyboardEvent, MouseEvent, TouchEvent } from 'react';
2
- import type { FocusConfig } from '../../../types/focusConfig.type';
1
+ import { type KeyboardEvent, type MouseEvent, type TouchEvent } from 'react';
3
2
  import type { ZoomAreaSelectionConfig, ZoomRange } from '../zoomArea.type';
4
3
  /**
5
4
 
@@ -31,27 +30,8 @@ interface SelectionAreaProps {
31
30
  onBlur: () => void;
32
31
  }
33
32
  /**
34
- * Props for the SelectionAreaFocusRing component
33
+ * Selection area overlay - the interactive rectangle that users can drag and focus
35
34
  */
36
- interface SelectionAreaFocusRingProps {
37
- /** Start X position */
38
- startX: number;
39
- /** End X position */
40
- endX: number;
41
- /** Chart height */
42
- height: number;
43
- /** Whether the selection area is focused */
44
- isFocused: boolean;
45
- /** Custom focus configuration (already resolved) */
46
- focusConfig: Required<FocusConfig>;
47
- }
48
- /**
49
- * Focus ring for the selection area - rendered separately to control z-order
50
- */
51
- export declare const SelectionAreaFocusRing: FC<SelectionAreaFocusRingProps>;
52
- /**
53
- * Selection area overlay
54
- */
55
- export declare const SelectionArea: FC<SelectionAreaProps>;
35
+ export declare const SelectionArea: import("react").ForwardRefExoticComponent<SelectionAreaProps & import("react").RefAttributes<SVGRectElement>>;
56
36
  export {};
57
37
  //# sourceMappingURL=SelectionArea.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SelectionArea.d.ts","sourceRoot":"","sources":["../../../../../src/components/zoomArea/components/SelectionArea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAI5D,OAAO,KAAK,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE3E;;;;GAIG;AACH,UAAU,kBAAkB;IAC1B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,YAAY,EAAE,SAAS,CAAC;IACxB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,eAAe,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC;IACnD,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB;IACrB,WAAW,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACzC,YAAY,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;GAEG;AACH,UAAU,2BAA2B;IACnC,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,SAAS,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,EAAE,CAAC,2BAA2B,CA+DlE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CAqDhD,CAAC"}
1
+ {"version":3,"file":"SelectionArea.d.ts","sourceRoot":"","sources":["../../../../../src/components/zoomArea/components/SelectionArea.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAc,MAAM,OAAO,CAAC;AAGzF,OAAO,KAAK,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE3E;;;;GAIG;AACH,UAAU,kBAAkB;IAC1B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,YAAY,EAAE,SAAS,CAAC;IACxB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,eAAe,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC;IACnD,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB;IACrB,WAAW,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACzC,YAAY,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,+GA2DzB,CAAC"}
@@ -1,48 +1,16 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { calculateFocusOutline } from '../../../utils/calculateFocusOutline/calculateFocusOutline';
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
3
  import { isFullRange } from '../utils/rangeAndPositions';
4
4
  /**
5
- * Focus ring for the selection area - rendered separately to control z-order
5
+ * Selection area overlay - the interactive rectangle that users can drag and focus
6
6
  */
7
- export const SelectionAreaFocusRing = ({ endX, focusConfig, height, isFocused, startX, }) => {
8
- if (!isFocused) {
9
- return null;
10
- }
11
- // Calculate selection area dimensions
12
- const selectionWidth = endX - startX;
13
- const selectionHeight = height;
14
- const centerX = startX + selectionWidth / 2;
15
- const centerY = height / 2;
16
- // Calculate focus ring dimensions using the new util
17
- const focusOutline = calculateFocusOutline({
18
- elementHeight: selectionHeight,
19
- elementPosition: { x: centerX, y: centerY },
20
- elementStrokeWidth: 0, // Selection area typically has no border
21
- elementType: 'rectangle',
22
- elementWidth: selectionWidth,
23
- gap: focusConfig.gap,
24
- innerStrokeWidth: focusConfig.innerStrokeWidth,
25
- outlineStrokeWidth: focusConfig.outlineStrokeWidth,
26
- });
27
- // Use resolved configuration values directly
28
- const outlineColor = focusConfig.outlineColor;
29
- const innerColor = focusConfig.innerColor;
30
- const outlineStrokeWidth = focusConfig.outlineStrokeWidth;
31
- const innerStrokeWidth = focusConfig.innerStrokeWidth;
32
- if (focusOutline.type !== 'rectangle') {
33
- return null;
34
- }
35
- return (_jsxs("g", { pointerEvents: "none", children: [_jsx("rect", { fill: "none", height: focusOutline.outer.height, stroke: outlineColor, strokeWidth: outlineStrokeWidth, width: focusOutline.outer.width, x: focusOutline.outer.x, y: focusOutline.outer.y }), _jsx("rect", { fill: "none", height: focusOutline.inner.height, stroke: innerColor, strokeWidth: innerStrokeWidth, width: focusOutline.inner.width, x: focusOutline.inner.x, y: focusOutline.inner.y })] }));
36
- };
37
- /**
38
- * Selection area overlay
39
- */
40
- export const SelectionArea = ({ currentRange, dataLength, dataTestId, endX, height, onBlur, onFocus, onKeyDown, onMouseDown, onTouchStart, screenReaderText, selectionConfig, startX, }) => {
7
+ export const SelectionArea = forwardRef(({ currentRange, dataLength, dataTestId, endX, height, onBlur, onFocus, onKeyDown, onMouseDown, onTouchStart, screenReaderText, selectionConfig, startX, }, ref) => {
41
8
  // Check if overlay should be hidden based on design specs:
42
9
  // "Only visible when a range is defined"
43
10
  const shouldHideOverlay = selectionConfig.hideOverlayOnFullRange && isFullRange(currentRange, dataLength);
44
- return (_jsx(_Fragment, { children: _jsx("rect", { "aria-label": screenReaderText, "aria-valuemax": dataLength - 1, "aria-valuemin": 0, "aria-valuetext": screenReaderText, cursor: "grab", "data-testid": dataTestId, fill: selectionConfig.fill, fillOpacity: selectionConfig.fillOpacity, height: height, role: "slider", stroke: selectionConfig.stroke, strokeWidth: selectionConfig.strokeWidth, style: {
11
+ return (_jsx(_Fragment, { children: _jsx("rect", { ref: ref, "aria-label": screenReaderText, "aria-valuemax": dataLength - 1, "aria-valuemin": 0, "aria-valuetext": screenReaderText, cursor: "grab", "data-testid": dataTestId, fill: selectionConfig.fill, fillOpacity: selectionConfig.fillOpacity, height: height, role: "slider", stroke: selectionConfig.stroke, strokeWidth: selectionConfig.strokeWidth, style: {
45
12
  outline: 'none',
46
13
  visibility: shouldHideOverlay ? 'hidden' : 'visible',
47
14
  }, tabIndex: 0, width: endX - startX, x: startX, y: 0, onBlur: onBlur, onFocus: onFocus, onKeyDown: onKeyDown, onMouseDown: onMouseDown, onTouchStart: onTouchStart }) }));
48
- };
15
+ });
16
+ SelectionArea.displayName = 'SelectionArea';
@@ -17,12 +17,12 @@ interface ZoomHandlerProps {
17
17
  min: number;
18
18
  /** Maximum allowed value */
19
19
  max: number;
20
- /** Whether this handler is focused */
20
+ /** Whether the handler is focused (controlled mode) */
21
21
  isFocused: boolean;
22
22
  /** Custom handler configuration */
23
23
  handlerConfig?: ZoomAreaHandlerConfig;
24
- /** Custom focus configuration (already resolved) */
25
- focusConfig: Required<FocusConfig>;
24
+ /** Focus ring configuration */
25
+ focusConfig?: FocusConfig;
26
26
  /** Text announced by screen readers */
27
27
  screenReaderText?: string;
28
28
  /** Data test ID */