@kubit-ui-web/react-charts 1.5.1 → 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.
- package/dist/cjs/components/focusRing/components/FocusRingInline.d.ts +25 -0
- package/dist/cjs/components/focusRing/components/FocusRingInline.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/components/FocusRingInline.js +37 -0
- package/dist/cjs/components/focusRing/components/FocusRingRenderer.d.ts +13 -0
- package/dist/cjs/components/focusRing/components/FocusRingRenderer.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/components/FocusRingRenderer.js +25 -0
- package/dist/cjs/components/focusRing/components/FocusRingSeparate.d.ts +40 -0
- package/dist/cjs/components/focusRing/components/FocusRingSeparate.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/components/FocusRingSeparate.js +45 -0
- package/dist/cjs/components/focusRing/focusRing.css +14 -0
- package/dist/cjs/components/focusRing/focusRing.d.ts +35 -0
- package/dist/cjs/components/focusRing/focusRing.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/focusRing.js +44 -0
- package/dist/cjs/components/focusRing/focusRing.types.d.ts +40 -0
- package/dist/cjs/components/focusRing/focusRing.types.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/focusRing.types.js +1 -0
- package/dist/cjs/components/focusRing/hooks/useFocusRingData.d.ts +27 -0
- package/dist/cjs/components/focusRing/hooks/useFocusRingData.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/hooks/useFocusRingData.js +67 -0
- package/dist/cjs/components/focusRing/index.d.ts +3 -0
- package/dist/cjs/components/focusRing/index.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/index.js +1 -0
- package/dist/cjs/components/focusRing/utils/composeRefs.d.ts +7 -0
- package/dist/cjs/components/focusRing/utils/composeRefs.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/utils/composeRefs.js +16 -0
- package/dist/cjs/components/focusRing/utils/createAdaptiveFocusRings.d.ts +24 -0
- package/dist/cjs/components/focusRing/utils/createAdaptiveFocusRings.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/utils/createAdaptiveFocusRings.js +141 -0
- package/dist/cjs/components/focusRing/utils/createBoundingBoxFocusRings.d.ts +33 -0
- package/dist/cjs/components/focusRing/utils/createBoundingBoxFocusRings.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/utils/createBoundingBoxFocusRings.js +126 -0
- package/dist/cjs/components/focusRing/utils/utils.types.d.ts +52 -0
- package/dist/cjs/components/focusRing/utils/utils.types.d.ts.map +1 -0
- package/dist/cjs/components/focusRing/utils/utils.types.js +1 -0
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.d.ts.map +1 -1
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/components/plot/plot.d.ts.map +1 -1
- package/dist/cjs/components/plot/plot.js +7 -19
- package/dist/cjs/components/zoomArea/components/SelectionArea.d.ts +3 -23
- package/dist/cjs/components/zoomArea/components/SelectionArea.d.ts.map +1 -1
- package/dist/cjs/components/zoomArea/components/SelectionArea.js +7 -39
- package/dist/cjs/components/zoomArea/components/ZoomHandler.d.ts +3 -3
- package/dist/cjs/components/zoomArea/components/ZoomHandler.d.ts.map +1 -1
- package/dist/cjs/components/zoomArea/components/ZoomHandler.js +2 -15
- package/dist/cjs/components/zoomArea/components/index.d.ts +1 -1
- package/dist/cjs/components/zoomArea/components/index.d.ts.map +1 -1
- package/dist/cjs/components/zoomArea/components/index.js +1 -1
- package/dist/cjs/components/zoomArea/zoomArea.js +6 -6
- package/dist/cjs/components/zoomArea/zoomArea.type.d.ts +1 -1
- package/dist/cjs/components/zoomArea/zoomArea.type.d.ts.map +1 -1
- package/dist/cjs/types/focusConfig.type.d.ts +15 -3
- package/dist/cjs/types/focusConfig.type.d.ts.map +1 -1
- package/dist/cjs/types/focusConfig.type.js +14 -1
- package/dist/esm/components/focusRing/components/FocusRingInline.d.ts +25 -0
- package/dist/esm/components/focusRing/components/FocusRingInline.d.ts.map +1 -0
- package/dist/esm/components/focusRing/components/FocusRingInline.js +37 -0
- package/dist/esm/components/focusRing/components/FocusRingRenderer.d.ts +13 -0
- package/dist/esm/components/focusRing/components/FocusRingRenderer.d.ts.map +1 -0
- package/dist/esm/components/focusRing/components/FocusRingRenderer.js +25 -0
- package/dist/esm/components/focusRing/components/FocusRingSeparate.d.ts +40 -0
- package/dist/esm/components/focusRing/components/FocusRingSeparate.d.ts.map +1 -0
- package/dist/esm/components/focusRing/components/FocusRingSeparate.js +45 -0
- package/dist/esm/components/focusRing/focusRing.css +14 -0
- package/dist/esm/components/focusRing/focusRing.d.ts +35 -0
- package/dist/esm/components/focusRing/focusRing.d.ts.map +1 -0
- package/dist/esm/components/focusRing/focusRing.js +44 -0
- package/dist/esm/components/focusRing/focusRing.types.d.ts +40 -0
- package/dist/esm/components/focusRing/focusRing.types.d.ts.map +1 -0
- package/dist/esm/components/focusRing/focusRing.types.js +1 -0
- package/dist/esm/components/focusRing/hooks/useFocusRingData.d.ts +27 -0
- package/dist/esm/components/focusRing/hooks/useFocusRingData.d.ts.map +1 -0
- package/dist/esm/components/focusRing/hooks/useFocusRingData.js +67 -0
- package/dist/esm/components/focusRing/index.d.ts +3 -0
- package/dist/esm/components/focusRing/index.d.ts.map +1 -0
- package/dist/esm/components/focusRing/index.js +1 -0
- package/dist/esm/components/focusRing/utils/composeRefs.d.ts +7 -0
- package/dist/esm/components/focusRing/utils/composeRefs.d.ts.map +1 -0
- package/dist/esm/components/focusRing/utils/composeRefs.js +16 -0
- package/dist/esm/components/focusRing/utils/createAdaptiveFocusRings.d.ts +24 -0
- package/dist/esm/components/focusRing/utils/createAdaptiveFocusRings.d.ts.map +1 -0
- package/dist/esm/components/focusRing/utils/createAdaptiveFocusRings.js +141 -0
- package/dist/esm/components/focusRing/utils/createBoundingBoxFocusRings.d.ts +33 -0
- package/dist/esm/components/focusRing/utils/createBoundingBoxFocusRings.d.ts.map +1 -0
- package/dist/esm/components/focusRing/utils/createBoundingBoxFocusRings.js +126 -0
- package/dist/esm/components/focusRing/utils/utils.types.d.ts +52 -0
- package/dist/esm/components/focusRing/utils/utils.types.d.ts.map +1 -0
- package/dist/esm/components/focusRing/utils/utils.types.js +1 -0
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/plot/plot.d.ts.map +1 -1
- package/dist/esm/components/plot/plot.js +7 -19
- package/dist/esm/components/zoomArea/components/SelectionArea.d.ts +3 -23
- package/dist/esm/components/zoomArea/components/SelectionArea.d.ts.map +1 -1
- package/dist/esm/components/zoomArea/components/SelectionArea.js +7 -39
- package/dist/esm/components/zoomArea/components/ZoomHandler.d.ts +3 -3
- package/dist/esm/components/zoomArea/components/ZoomHandler.d.ts.map +1 -1
- package/dist/esm/components/zoomArea/components/ZoomHandler.js +2 -15
- package/dist/esm/components/zoomArea/components/index.d.ts +1 -1
- package/dist/esm/components/zoomArea/components/index.d.ts.map +1 -1
- package/dist/esm/components/zoomArea/components/index.js +1 -1
- package/dist/esm/components/zoomArea/zoomArea.js +6 -6
- package/dist/esm/components/zoomArea/zoomArea.type.d.ts +1 -1
- package/dist/esm/components/zoomArea/zoomArea.type.d.ts.map +1 -1
- package/dist/esm/types/focusConfig.type.d.ts +15 -3
- package/dist/esm/types/focusConfig.type.d.ts.map +1 -1
- package/dist/esm/types/focusConfig.type.js +14 -1
- package/dist/kubit-ui-web-react-charts.cjs.js +1 -1
- package/dist/kubit-ui-web-react-charts.es.js +1 -1
- package/dist/kubit-ui-web-react-charts.umd.js +1 -1
- package/dist/react-charts.css +1 -1
- package/dist/types/components/focusRing/components/FocusRingInline.d.ts +25 -0
- package/dist/types/components/focusRing/components/FocusRingInline.d.ts.map +1 -0
- package/dist/types/components/focusRing/components/FocusRingRenderer.d.ts +13 -0
- package/dist/types/components/focusRing/components/FocusRingRenderer.d.ts.map +1 -0
- package/dist/types/components/focusRing/components/FocusRingSeparate.d.ts +40 -0
- package/dist/types/components/focusRing/components/FocusRingSeparate.d.ts.map +1 -0
- package/dist/types/components/focusRing/focusRing.d.ts +34 -0
- package/dist/types/components/focusRing/focusRing.d.ts.map +1 -0
- package/dist/types/components/focusRing/focusRing.types.d.ts +40 -0
- package/dist/types/components/focusRing/focusRing.types.d.ts.map +1 -0
- package/dist/types/components/focusRing/hooks/useFocusRingData.d.ts +27 -0
- package/dist/types/components/focusRing/hooks/useFocusRingData.d.ts.map +1 -0
- package/dist/types/components/focusRing/index.d.ts +3 -0
- package/dist/types/components/focusRing/index.d.ts.map +1 -0
- package/dist/types/components/focusRing/utils/composeRefs.d.ts +7 -0
- package/dist/types/components/focusRing/utils/composeRefs.d.ts.map +1 -0
- package/dist/types/components/focusRing/utils/createAdaptiveFocusRings.d.ts +24 -0
- package/dist/types/components/focusRing/utils/createAdaptiveFocusRings.d.ts.map +1 -0
- package/dist/types/components/focusRing/utils/createBoundingBoxFocusRings.d.ts +33 -0
- package/dist/types/components/focusRing/utils/createBoundingBoxFocusRings.d.ts.map +1 -0
- package/dist/types/components/focusRing/utils/utils.types.d.ts +52 -0
- package/dist/types/components/focusRing/utils/utils.types.d.ts.map +1 -0
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/components/index.d.ts.map +1 -1
- package/dist/types/components/plot/plot.d.ts.map +1 -1
- package/dist/types/components/zoomArea/components/SelectionArea.d.ts +3 -23
- package/dist/types/components/zoomArea/components/SelectionArea.d.ts.map +1 -1
- package/dist/types/components/zoomArea/components/ZoomHandler.d.ts +3 -3
- package/dist/types/components/zoomArea/components/ZoomHandler.d.ts.map +1 -1
- package/dist/types/components/zoomArea/components/index.d.ts +1 -1
- package/dist/types/components/zoomArea/components/index.d.ts.map +1 -1
- package/dist/types/components/zoomArea/zoomArea.type.d.ts +1 -1
- package/dist/types/components/zoomArea/zoomArea.type.d.ts.map +1 -1
- package/dist/types/types/focusConfig.type.d.ts +15 -3
- package/dist/types/types/focusConfig.type.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/cjs/utils/calculateFocusOutline/calculateFocusOutline.d.ts +0 -73
- package/dist/cjs/utils/calculateFocusOutline/calculateFocusOutline.d.ts.map +0 -1
- package/dist/cjs/utils/calculateFocusOutline/calculateFocusOutline.js +0 -80
- package/dist/esm/utils/calculateFocusOutline/calculateFocusOutline.d.ts +0 -73
- package/dist/esm/utils/calculateFocusOutline/calculateFocusOutline.d.ts.map +0 -1
- package/dist/esm/utils/calculateFocusOutline/calculateFocusOutline.js +0 -80
- package/dist/types/utils/calculateFocusOutline/calculateFocusOutline.d.ts +0 -73
- package/dist/types/utils/calculateFocusOutline/calculateFocusOutline.d.ts.map +0 -1
|
@@ -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 +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 +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;
|
|
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,
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
|
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 })),
|
|
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
|
|
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
|
-
*
|
|
33
|
+
* Selection area overlay - the interactive rectangle that users can drag and focus
|
|
35
34
|
*/
|
|
36
|
-
|
|
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,
|
|
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,
|
|
2
|
-
import {
|
|
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
|
-
*
|
|
5
|
+
* Selection area overlay - the interactive rectangle that users can drag and focus
|
|
6
6
|
*/
|
|
7
|
-
export const
|
|
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
|
|
20
|
+
/** Whether the handler is focused (controlled mode) */
|
|
21
21
|
isFocused: boolean;
|
|
22
22
|
/** Custom handler configuration */
|
|
23
23
|
handlerConfig?: ZoomAreaHandlerConfig;
|
|
24
|
-
/**
|
|
25
|
-
focusConfig
|
|
24
|
+
/** Focus ring configuration */
|
|
25
|
+
focusConfig?: FocusConfig;
|
|
26
26
|
/** Text announced by screen readers */
|
|
27
27
|
screenReaderText?: string;
|
|
28
28
|
/** Data test ID */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZoomHandler.d.ts","sourceRoot":"","sources":["../../../../../src/components/zoomArea/components/ZoomHandler.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ZoomHandler.d.ts","sourceRoot":"","sources":["../../../../../src/components/zoomArea/components/ZoomHandler.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAGnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAyBhF;;GAEG;AACH,UAAU,gBAAgB;IACxB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,OAAO,gBAAgB,CAAC;IACpC,iBAAiB;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,SAAS,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,+BAA+B;IAC/B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,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;AAmBD;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA+DlD,CAAC"}
|