vccs 0.4.1 → 0.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 (56) hide show
  1. package/dist/cartesian/axis/YAxis.d.ts +5 -5
  2. package/dist/cartesian/cartesian-axis/CartesianAxis.d.ts +12 -1
  3. package/dist/cartesian/cartesianPositionToCSSTranslate.d.ts +15 -0
  4. package/dist/cartesian/getCartesianPosition.d.ts +45 -0
  5. package/dist/cartesian/index.d.ts +1 -0
  6. package/dist/cartesian/type.d.ts +8 -0
  7. package/dist/chart/{RechartsWrapper.d.ts → ChartsWrapper.d.ts} +16 -1
  8. package/dist/chart/Surface.d.ts +2 -2
  9. package/dist/chart/generateCategoricalChart.d.ts +4 -0
  10. package/dist/components/Tooltip.d.ts +1 -1
  11. package/dist/components/legend/hooks/useLegend.d.ts +3 -0
  12. package/dist/components/legend/type.d.ts +18 -2
  13. package/dist/components/legend/utils.d.ts +9 -0
  14. package/dist/container/Surface.d.ts +3 -3
  15. package/dist/es/cartesian/axis/XAxis.mjs +11 -5
  16. package/dist/es/cartesian/axis/YAxis.mjs +62 -9
  17. package/dist/es/cartesian/cartesian-axis/CartesianAxis.mjs +6 -1
  18. package/dist/es/cartesian/cartesianPositionToCSSTranslate.mjs +28 -0
  19. package/dist/es/cartesian/getCartesianPosition.mjs +176 -0
  20. package/dist/es/chart/{RechartsWrapper.mjs → ChartsWrapper.mjs} +26 -6
  21. package/dist/es/chart/Sankey.mjs +2 -2
  22. package/dist/es/chart/SunburstChart.mjs +2 -2
  23. package/dist/es/chart/Surface.vue_vue_type_script_setup_true_lang.mjs +7 -1
  24. package/dist/es/chart/Treemap.mjs +2 -2
  25. package/dist/es/chart/generateCategoricalChart.mjs +53 -49
  26. package/dist/es/components/legend/Legend.mjs +5 -3
  27. package/dist/es/components/legend/hooks/useLegend.mjs +50 -9
  28. package/dist/es/components/legend/type.mjs +9 -1
  29. package/dist/es/components/legend/utils.mjs +12 -1
  30. package/dist/es/container/ResponsiveContainer.vue_vue_type_script_setup_true_lang.mjs +2 -11
  31. package/dist/es/container/Surface.mjs +5 -1
  32. package/dist/es/hooks/useResponsiveSize.mjs +27 -0
  33. package/dist/es/hooks/useRoundedSize.mjs +31 -0
  34. package/dist/es/shape/Sector.mjs +1 -1
  35. package/dist/es/state/cartesianAxisSlice.mjs +13 -2
  36. package/dist/es/state/legendSlice.mjs +2 -0
  37. package/dist/es/state/selectors/axisSelectors.mjs +3 -3
  38. package/dist/es/state/selectors/barSelectors.mjs +1 -1
  39. package/dist/es/state/selectors/pieSelectors.mjs +1 -1
  40. package/dist/es/state/selectors/polarAxisSelectors.mjs +1 -1
  41. package/dist/es/state/selectors/radialBarSelectors.mjs +1 -1
  42. package/dist/es/state/selectors/selectChartOffset.mjs +7 -4
  43. package/dist/es/state/selectors/selectLegendArea.mjs +19 -0
  44. package/dist/es/state/selectors/tooltipSelectors.mjs +1 -1
  45. package/dist/es/state/touchEventsMiddleware.mjs +1 -1
  46. package/dist/es/utils/YAxisUtils.mjs +29 -0
  47. package/dist/es/utils/chart.mjs +1 -1
  48. package/dist/es/utils/legend.mjs +23 -1
  49. package/dist/hooks/useResponsiveSize.d.ts +22 -0
  50. package/dist/hooks/useRoundedSize.d.ts +22 -0
  51. package/dist/state/cartesianAxisSlice.d.ts +11 -3
  52. package/dist/state/legendSlice.d.ts +3 -0
  53. package/dist/state/selectors/selectLegendArea.d.ts +7 -0
  54. package/dist/types/axis.d.ts +11 -1
  55. package/dist/utils/YAxisUtils.d.ts +20 -0
  56. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { isPercent } from "../utils/validate.mjs";
2
2
  import { normalizeStyle as normalizeStyle$1 } from "../utils/style.mjs";
3
+ import { useRoundedSize } from "../hooks/useRoundedSize.mjs";
3
4
  import { provideSizeContext } from "./useSizeContext.mjs";
4
5
  import { Fragment, cloneVNode, computed, createElementBlock, createVNode, defineComponent, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, ref, toRef, useSlots } from "vue";
5
6
  import { useThrottleFn } from "@vueuse/core";
@@ -30,7 +31,7 @@ var ResponsiveContainer_vue_vue_type_script_setup_true_lang_default = /* @__PURE
30
31
  const props = __props;
31
32
  const slots = useSlots();
32
33
  const debounce = toRef(props, "debounce");
33
- const sizes = ref({
34
+ const { size: sizes, setSize: setContainerSize } = useRoundedSize({
34
35
  width: props.initialDimension.width,
35
36
  height: props.initialDimension.height
36
37
  });
@@ -57,16 +58,6 @@ var ResponsiveContainer_vue_vue_type_script_setup_true_lang_default = /* @__PURE
57
58
  calculatedWidth: finalCalculatedWidth,
58
59
  calculatedHeight
59
60
  });
60
- function setContainerSize(width, height) {
61
- const roundedWidth = Math.round(width);
62
- const roundedHeight = Math.round(height);
63
- const { width: containerWidth, height: containerHeight } = sizes.value;
64
- if (containerWidth === roundedWidth && containerHeight === roundedHeight) return;
65
- sizes.value = {
66
- width: roundedWidth,
67
- height: roundedHeight
68
- };
69
- }
70
61
  const handleResize = useThrottleFn((entries) => {
71
62
  const { width: containerWidth, height: containerHeight } = entries[0].contentRect;
72
63
  setContainerSize(containerWidth, containerHeight);
@@ -21,7 +21,11 @@ var Surface = /* @__PURE__ */ defineComponent({
21
21
  },
22
22
  class: classProp,
23
23
  style: {
24
- type: Object,
24
+ type: [
25
+ String,
26
+ Object,
27
+ Array
28
+ ],
25
29
  default: void 0
26
30
  },
27
31
  title: {
@@ -0,0 +1,27 @@
1
+ import { validateWidthHeight } from "../utils/validate.mjs";
2
+ import { useRoundedSize } from "./useRoundedSize.mjs";
3
+ import { computed } from "vue";
4
+ //#region src/hooks/useResponsiveSize.ts
5
+ /**
6
+ * Owns the chart's size resolution: in responsive mode the size is measured
7
+ * from the wrapper div (via `handleResize`), otherwise it comes from props.
8
+ *
9
+ * Render gating (`return null` when the size is invalid) stays with the
10
+ * caller — the rules differ between the compact and normal branches.
11
+ */
12
+ function useResponsiveSize(props) {
13
+ const { size: responsiveSize, setSize: handleResize } = useRoundedSize();
14
+ const effectiveWidth = computed(() => props.responsive ? responsiveSize.value.width : props.width ?? 0);
15
+ const effectiveHeight = computed(() => props.responsive ? responsiveSize.value.height : props.height ?? 0);
16
+ return {
17
+ effectiveWidth,
18
+ effectiveHeight,
19
+ hasValidSize: computed(() => validateWidthHeight({
20
+ width: effectiveWidth.value,
21
+ height: effectiveHeight.value
22
+ })),
23
+ handleResize
24
+ };
25
+ }
26
+ //#endregion
27
+ export { useResponsiveSize };
@@ -0,0 +1,31 @@
1
+ import { ref } from "vue";
2
+ //#region src/hooks/useRoundedSize.ts
3
+ /**
4
+ * Shared size-state core: a size ref plus a setter that rounds to
5
+ * integers and ignores no-change updates.
6
+ *
7
+ * Adapters: `useResponsiveSize` (chart sizing) and `ResponsiveContainer`.
8
+ * ResponsiveContainer is planned for removal (see ADR-0001); when it goes,
9
+ * this module stays behind as the chart's size-state implementation.
10
+ */
11
+ function useRoundedSize(initial = {
12
+ width: 0,
13
+ height: 0
14
+ }) {
15
+ const size = ref(initial);
16
+ function setSize(width, height) {
17
+ const roundedWidth = Math.round(width);
18
+ const roundedHeight = Math.round(height);
19
+ if (size.value.width === roundedWidth && size.value.height === roundedHeight) return;
20
+ size.value = {
21
+ width: roundedWidth,
22
+ height: roundedHeight
23
+ };
24
+ }
25
+ return {
26
+ size,
27
+ setSize
28
+ };
29
+ }
30
+ //#endregion
31
+ export { useRoundedSize };
@@ -1,6 +1,6 @@
1
1
  import { classProp } from "../types/common.mjs";
2
- import { RADIAN, polarToCartesian } from "../utils/polar.mjs";
3
2
  import { getPercentValue, mathSign } from "../utils/data.mjs";
3
+ import { RADIAN, polarToCartesian } from "../utils/polar.mjs";
4
4
  import { createVNode, defineComponent, mergeProps } from "vue";
5
5
  //#region src/shape/Sector.tsx
6
6
  /**
@@ -25,6 +25,17 @@ var cartesianAxisSlice = createSlice({
25
25
  removeYAxis(state, action) {
26
26
  delete state.yAxis[action.payload.id];
27
27
  },
28
+ updateYAxisWidth(state, action) {
29
+ const { id, width } = action.payload;
30
+ const axis = state.yAxis[id];
31
+ if (axis) {
32
+ const history = axis.widthHistory || [];
33
+ if (history.length === 3 && history[0] === history[2] && width === history[1] && width !== axis.width && Math.abs(width - (history[0] ?? 0)) <= 1) return;
34
+ const newHistory = [...history, width].slice(-3);
35
+ axis.width = width;
36
+ axis.widthHistory = newHistory;
37
+ }
38
+ },
28
39
  addZAxis(state, action) {
29
40
  state.zAxis[action.payload.id] = castDraft(action.payload);
30
41
  },
@@ -33,7 +44,7 @@ var cartesianAxisSlice = createSlice({
33
44
  }
34
45
  }
35
46
  });
36
- var { addXAxis, removeXAxis, addYAxis, removeYAxis, addZAxis, removeZAxis } = cartesianAxisSlice.actions;
47
+ var { addXAxis, removeXAxis, addYAxis, removeYAxis, addZAxis, removeZAxis, updateYAxisWidth } = cartesianAxisSlice.actions;
37
48
  var cartesianAxisReducer = cartesianAxisSlice.reducer;
38
49
  //#endregion
39
- export { addXAxis, addYAxis, addZAxis, cartesianAxisReducer, removeXAxis, removeYAxis, removeZAxis };
50
+ export { addXAxis, addYAxis, addZAxis, cartesianAxisReducer, removeXAxis, removeYAxis, removeZAxis, updateYAxisWidth };
@@ -24,6 +24,8 @@ var legendSlice = createSlice({
24
24
  state.settings.align = action.payload.align;
25
25
  state.settings.layout = action.payload.layout;
26
26
  state.settings.verticalAlign = action.payload.verticalAlign;
27
+ state.settings.position = action.payload.position;
28
+ state.settings.offset = action.payload.offset;
27
29
  },
28
30
  addLegendPayload(state, action) {
29
31
  state.payload.push(castDraft(action.payload));
@@ -2,11 +2,11 @@ import { isCategoricalAxis, isNan, isNumOrStr, isNumber, isWellBehavedNumber } f
2
2
  import { selectChartDataWithIndexes, selectChartDataWithIndexesIfNotInPanorama } from "./dataSelectors.mjs";
3
3
  import { selectChartHeight, selectChartWidth } from "./containerSelectors.mjs";
4
4
  import { selectAllXAxes, selectAllYAxes } from "./selectAllAxes.mjs";
5
+ import { getPercentValue, hasDuplicate, mathSign } from "../../utils/data.mjs";
5
6
  import { selectChartOffset } from "./selectChartOffset.mjs";
6
7
  import { selectBrushDimensions, selectBrushSettings } from "./brushSelectors.mjs";
7
8
  import { selectBarCategoryGap, selectChartName, selectStackOffsetType } from "./rootPropsSelectors.mjs";
8
9
  import { combineAxisRangeWithReverse } from "./combiners/combineAxisRangeWithReverse.mjs";
9
- import { getPercentValue, hasDuplicate, mathSign } from "../../utils/data.mjs";
10
10
  import { selectChartLayout } from "./common.mjs";
11
11
  import { selectAngleAxis, selectAngleAxisRange, selectRadiusAxis, selectRadiusAxisRange } from "./polarAxisSelectors.mjs";
12
12
  import { pickAxisType } from "./pickAxisType.mjs";
@@ -639,7 +639,7 @@ function getXAxisSize(offset, axisSettings) {
639
639
  }
640
640
  function getYAxisSize(offset, axisSettings) {
641
641
  return {
642
- width: axisSettings.width,
642
+ width: typeof axisSettings.width === "number" ? axisSettings.width : 60,
643
643
  height: offset.height
644
644
  };
645
645
  }
@@ -712,7 +712,7 @@ function selectYAxisPosition(state, axisId) {
712
712
  }
713
713
  var selectYAxisSize = createSelector(selectChartOffset, selectYAxisSettings, (offset, axisSettings) => {
714
714
  return {
715
- width: axisSettings.width,
715
+ width: typeof axisSettings.width === "number" ? axisSettings.width : 60,
716
716
  height: offset.height
717
717
  };
718
718
  });
@@ -1,8 +1,8 @@
1
1
  import { isNullish } from "../../utils/validate.mjs";
2
2
  import { selectChartDataWithIndexesIfNotInPanorama } from "./dataSelectors.mjs";
3
+ import { getPercentValue } from "../../utils/data.mjs";
3
4
  import { selectChartOffset } from "./selectChartOffset.mjs";
4
5
  import { selectBarCategoryGap, selectBarGap, selectRootBarSize, selectRootMaxBarSize } from "./rootPropsSelectors.mjs";
5
- import { getPercentValue } from "../../utils/data.mjs";
6
6
  import { selectChartLayout } from "./common.mjs";
7
7
  import { getBandSizeOfAxis } from "../../utils/chart.mjs";
8
8
  import { selectAxisWithScale, selectCartesianAxisSize, selectStackGroups, selectTicksOfGraphicalItem, selectUnfilteredCartesianItems } from "./axisSelectors.mjs";
@@ -1,8 +1,8 @@
1
1
  import { isNumber } from "../../utils/validate.mjs";
2
2
  import { selectChartDataAndAlwaysIgnoreIndexes } from "./dataSelectors.mjs";
3
+ import { getPercentValue, mathSign } from "../../utils/data.mjs";
3
4
  import { selectChartOffset } from "./selectChartOffset.mjs";
4
5
  import { getMaxRadius, polarToCartesian } from "../../utils/polar.mjs";
5
- import { getPercentValue, mathSign } from "../../utils/data.mjs";
6
6
  import { getValueByDataKey } from "../../utils/chart.mjs";
7
7
  import { selectUnfilteredPolarItems } from "./polarSelectors.mjs";
8
8
  import { createSelector } from "@reduxjs/toolkit";
@@ -1,8 +1,8 @@
1
1
  import { selectChartHeight, selectChartWidth } from "./containerSelectors.mjs";
2
+ import { getPercentValue } from "../../utils/data.mjs";
2
3
  import { selectChartOffset } from "./selectChartOffset.mjs";
3
4
  import { combineAxisRangeWithReverse } from "./combiners/combineAxisRangeWithReverse.mjs";
4
5
  import { getMaxRadius } from "../../utils/polar.mjs";
5
- import { getPercentValue } from "../../utils/data.mjs";
6
6
  import { selectChartLayout } from "./common.mjs";
7
7
  import { createSelector } from "@reduxjs/toolkit";
8
8
  //#region src/state/selectors/polarAxisSelectors.ts
@@ -1,7 +1,7 @@
1
1
  import { isCategoricalAxis, isNullish } from "../../utils/validate.mjs";
2
2
  import { selectChartDataAndAlwaysIgnoreIndexes, selectChartDataWithIndexes } from "./dataSelectors.mjs";
3
- import { selectBarCategoryGap, selectBarGap, selectRootBarSize, selectRootMaxBarSize, selectStackOffsetType } from "./rootPropsSelectors.mjs";
4
3
  import { mathSign } from "../../utils/data.mjs";
4
+ import { selectBarCategoryGap, selectBarGap, selectRootBarSize, selectRootMaxBarSize, selectStackOffsetType } from "./rootPropsSelectors.mjs";
5
5
  import { selectChartLayout } from "./common.mjs";
6
6
  import { selectAngleAxis, selectPolarViewBox, selectRadiusAxis } from "./polarAxisSelectors.mjs";
7
7
  import { getBandSizeOfAxis, getBaseValueOfBar, getCateCoordinateOfBar, getValueByDataKey, truncateByDomain } from "../../utils/chart.mjs";
@@ -18,10 +18,13 @@ var selectChartOffset = createSelector([
18
18
  ], (chartWidth, chartHeight, margin, brushHeight, xAxes, yAxes, legendSettings, legendSize) => {
19
19
  const offsetH = yAxes.reduce((result, entry) => {
20
20
  const { orientation } = entry;
21
- if (!entry.mirror && !entry.hide) return {
22
- ...result,
23
- [orientation]: result[orientation] + entry.width
24
- };
21
+ if (!entry.mirror && !entry.hide) {
22
+ const width = typeof entry.width === "number" ? entry.width : 60;
23
+ return {
24
+ ...result,
25
+ [orientation]: result[orientation] + width
26
+ };
27
+ }
25
28
  return result;
26
29
  }, {
27
30
  left: margin.left || 0,
@@ -0,0 +1,19 @@
1
+ import { selectChartHeight, selectChartWidth, selectMargin } from "./containerSelectors.mjs";
2
+ import { createSelector } from "@reduxjs/toolkit";
3
+ //#region src/state/selectors/selectLegendArea.ts
4
+ /**
5
+ * The margin-inset chart area. Outside-positioned legends are placed here,
6
+ * beyond any axes.
7
+ */
8
+ var selectLegendArea = createSelector([
9
+ selectChartWidth,
10
+ selectChartHeight,
11
+ selectMargin
12
+ ], (chartWidth, chartHeight, margin) => ({
13
+ x: margin?.left || 0,
14
+ y: margin?.top || 0,
15
+ width: Math.max(chartWidth - (margin?.left || 0) - (margin?.right || 0), 0),
16
+ height: Math.max(chartHeight - (margin?.top || 0) - (margin?.bottom || 0), 0)
17
+ }));
18
+ //#endregion
19
+ export { selectLegendArea };
@@ -1,10 +1,10 @@
1
1
  import { isCategoricalAxis } from "../../utils/validate.mjs";
2
2
  import { selectChartDataWithIndexes } from "./dataSelectors.mjs";
3
3
  import { selectChartHeight, selectChartWidth } from "./containerSelectors.mjs";
4
+ import { findEntryInArray, mathSign } from "../../utils/data.mjs";
4
5
  import { selectChartOffset } from "./selectChartOffset.mjs";
5
6
  import { selectChartName, selectStackOffsetType } from "./rootPropsSelectors.mjs";
6
7
  import { combineAxisRangeWithReverse } from "./combiners/combineAxisRangeWithReverse.mjs";
7
- import { findEntryInArray, mathSign } from "../../utils/data.mjs";
8
8
  import { selectChartLayout } from "./common.mjs";
9
9
  import { getTooltipEntry, getValueByDataKey } from "../../utils/chart.mjs";
10
10
  import { combineAppliedNumericalValuesIncludingErrorValues, combineAppliedValues, combineAreasDomain, combineAxisDomain, combineAxisDomainWithNiceTicks, combineCategoricalDomain, combineDisplayedData, combineDomainOfStackGroups, combineDotsDomain, combineDuplicateDomain, combineGraphicalItemsData, combineGraphicalItemsSettings, combineLinesDomain, combineNiceTicks, combineNumericalDomain, combineRealScaleType, combineScaleFunction, combineStackGroups, filterGraphicalNotStackedItems, filterReferenceElements, getDomainDefinition, itemAxisPredicate, mergeDomains, selectAxisRange, selectAxisSettings, selectHasBar, selectReferenceAreas, selectReferenceDots, selectReferenceLines } from "./axisSelectors.mjs";
@@ -1,7 +1,7 @@
1
+ import { DATA_ITEM_DATAKEY_ATTRIBUTE_NAME, DATA_ITEM_INDEX_ATTRIBUTE_NAME } from "../utils/const.mjs";
1
2
  import { getChartPointer } from "../utils/chart.mjs";
2
3
  import { selectTooltipEventType } from "./selectors/selectTooltipEventType.mjs";
3
4
  import { setActiveMouseOverItemIndex, setMouseOverAxisIndex } from "./tooltipSlice.mjs";
4
- import { DATA_ITEM_DATAKEY_ATTRIBUTE_NAME, DATA_ITEM_INDEX_ATTRIBUTE_NAME } from "../utils/const.mjs";
5
5
  import { selectActivePropsFromChartPointer } from "./selectors/selectActivePropsFromChartPointer.mjs";
6
6
  import { selectTooltipCoordinate } from "./selectors/touchSelectors.mjs";
7
7
  import { createAction, createListenerMiddleware } from "@reduxjs/toolkit";
@@ -0,0 +1,29 @@
1
+ //#region src/utils/YAxisUtils.ts
2
+ /**
3
+ * Calculates the width of the Y-axis based on the tick labels and the axis label.
4
+ * @param params - The parameters object.
5
+ * @param [params.ticks] - An array-like object of tick elements, each with a `getBoundingClientRect` method.
6
+ * @param [params.label] - The axis label element, with a `getBoundingClientRect` method.
7
+ * @param [params.labelGapWithTick] - The gap between the label and the tick.
8
+ * @param [params.tickSize] - The length of the tick line.
9
+ * @param [params.tickMargin] - The margin between the tick line and the tick text.
10
+ * @returns The calculated width of the Y-axis.
11
+ */
12
+ function getCalculatedYAxisWidth({ ticks, label, labelGapWithTick = 5, tickSize = 0, tickMargin = 0 }) {
13
+ let maxTickWidth = 0;
14
+ if (ticks) {
15
+ Array.from(ticks).forEach((tickNode) => {
16
+ if (tickNode) {
17
+ const bbox = tickNode.getBoundingClientRect();
18
+ if (bbox.width > maxTickWidth) maxTickWidth = bbox.width;
19
+ }
20
+ });
21
+ const labelWidth = label ? label.getBoundingClientRect().width : 0;
22
+ const tickWidth = (tickSize ?? 0) + (tickMargin ?? 0);
23
+ const updatedYAxisWidth = maxTickWidth + tickWidth + labelWidth + (label ? labelGapWithTick : 0);
24
+ return Math.round(updatedYAxisWidth);
25
+ }
26
+ return 0;
27
+ }
28
+ //#endregion
29
+ export { getCalculatedYAxisWidth };
@@ -1,6 +1,6 @@
1
1
  import { isNan, isNullish, isNumOrStr, isNumber } from "./validate.mjs";
2
- import { formatAngleOfSector, getAngleOfPoint, polarToCartesian, reverseFormatAngleOfSector } from "./polar.mjs";
3
2
  import { findEntryInArray, mathSign } from "./data.mjs";
3
+ import { formatAngleOfSector, getAngleOfPoint, polarToCartesian, reverseFormatAngleOfSector } from "./polar.mjs";
4
4
  import { toRaw } from "vue";
5
5
  import { stack, stackOffsetExpand, stackOffsetNone, stackOffsetSilhouette, stackOffsetWiggle, stackOrderNone } from "victory-vendor/d3-shape";
6
6
  import { get, isNaN, sortBy } from "lodash-es";
@@ -1,9 +1,31 @@
1
1
  import { isNumber } from "./validate.mjs";
2
+ import { isOutsidePosition } from "../cartesian/getCartesianPosition.mjs";
2
3
  //#region src/utils/legend.ts
3
4
  function appendOffsetOfLegend(offset, legendSettings, legendSize) {
4
5
  if (legendSettings && legendSize) {
5
6
  const { width: boxWidth, height: boxHeight } = legendSize;
6
- const { align, verticalAlign, layout } = legendSettings;
7
+ const { align, verticalAlign, layout, position, offset: legendOffset = 0 } = legendSettings;
8
+ if (position != null) {
9
+ if (isOutsidePosition(position)) {
10
+ if (position === "top" && isNumber(offset.top)) return {
11
+ ...offset,
12
+ top: offset.top + (boxHeight || 0) + legendOffset
13
+ };
14
+ if (position === "bottom" && isNumber(offset.bottom)) return {
15
+ ...offset,
16
+ bottom: offset.bottom + (boxHeight || 0) + legendOffset
17
+ };
18
+ if (position === "left" && isNumber(offset.left)) return {
19
+ ...offset,
20
+ left: offset.left + (boxWidth || 0) + legendOffset
21
+ };
22
+ if (position === "right" && isNumber(offset.right)) return {
23
+ ...offset,
24
+ right: offset.right + (boxWidth || 0) + legendOffset
25
+ };
26
+ }
27
+ return offset;
28
+ }
7
29
  if ((layout === "vertical" || layout === "horizontal" && verticalAlign === "middle") && align !== "center" && isNumber(offset[align])) return {
8
30
  ...offset,
9
31
  [align]: offset[align] + (boxWidth || 0)
@@ -0,0 +1,22 @@
1
+ import { ComputedRef } from 'vue';
2
+ import { CategoricalChartPropsWithOutSvg } from '../chart/generateCategoricalChart';
3
+ type ResponsiveSizeProps = Pick<CategoricalChartPropsWithOutSvg, 'responsive' | 'width' | 'height'>;
4
+ interface UseResponsiveSizeResult {
5
+ /** Final width: measured from the wrapper when `responsive`, otherwise from props. */
6
+ effectiveWidth: ComputedRef<number>;
7
+ /** Final height: measured from the wrapper when `responsive`, otherwise from props. */
8
+ effectiveHeight: ComputedRef<number>;
9
+ /** Whether the effective size passes validateWidthHeight. Render policy is the caller's decision. */
10
+ hasValidSize: ComputedRef<boolean>;
11
+ /** Feeds the wrapper's ResizeObserver callback. Rounds and ignores no-change updates. */
12
+ handleResize: (width: number, height: number) => void;
13
+ }
14
+ /**
15
+ * Owns the chart's size resolution: in responsive mode the size is measured
16
+ * from the wrapper div (via `handleResize`), otherwise it comes from props.
17
+ *
18
+ * Render gating (`return null` when the size is invalid) stays with the
19
+ * caller — the rules differ between the compact and normal branches.
20
+ */
21
+ export declare function useResponsiveSize(props: ResponsiveSizeProps): UseResponsiveSizeResult;
22
+ export {};
@@ -0,0 +1,22 @@
1
+ export interface RoundedSize {
2
+ width: number;
3
+ height: number;
4
+ }
5
+ /**
6
+ * Shared size-state core: a size ref plus a setter that rounds to
7
+ * integers and ignores no-change updates.
8
+ *
9
+ * Adapters: `useResponsiveSize` (chart sizing) and `ResponsiveContainer`.
10
+ * ResponsiveContainer is planned for removal (see ADR-0001); when it goes,
11
+ * this module stays behind as the chart's size-state implementation.
12
+ */
13
+ export declare function useRoundedSize(initial?: RoundedSize): {
14
+ size: import('vue').Ref<{
15
+ width: number;
16
+ height: number;
17
+ }, RoundedSize | {
18
+ width: number;
19
+ height: number;
20
+ }>;
21
+ setSize: (width: number, height: number) => void;
22
+ };
@@ -1,7 +1,7 @@
1
1
  import { AxisRange } from './selectors/axisSelectors';
2
2
  import { SVGAttributes } from 'vue';
3
3
  import { RechartsScale, ScaleType } from '../types/scale';
4
- import { AxisDomain, AxisDomainType, AxisInterval } from '../types/axis';
4
+ import { AxisDomain, AxisDomainType, AxisInterval, YAxisWidth } from '../types/axis';
5
5
  import { DataKey } from '../types';
6
6
  import { AxisTick, TickFormatter } from '../types/tick';
7
7
  export type AxisId = string | number;
@@ -68,8 +68,13 @@ export type XAxisSettings = CartesianAxisSettings & {
68
68
  };
69
69
  export type YAxisSettings = CartesianAxisSettings & {
70
70
  padding: YAxisPadding;
71
- width: number;
71
+ width: YAxisWidth;
72
72
  orientation: YAxisOrientation;
73
+ /**
74
+ * Internal: recent measured widths, used to detect A→B→A oscillation
75
+ * when width is measured dynamically (width === 'auto').
76
+ */
77
+ widthHistory?: number[];
73
78
  };
74
79
  /**
75
80
  * Z axis is special because it's never displayed. It controls the size of Scatter dots,
@@ -83,6 +88,9 @@ type AxisMapState = {
83
88
  yAxis: Record<AxisId, YAxisSettings>;
84
89
  zAxis: Record<AxisId, ZAxisSettings>;
85
90
  };
86
- export declare const addXAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<XAxisSettings, "cartesianAxis/addXAxis">, removeXAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<XAxisSettings, "cartesianAxis/removeXAxis">, addYAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<YAxisSettings, "cartesianAxis/addYAxis">, removeYAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<YAxisSettings, "cartesianAxis/removeYAxis">, addZAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<ZAxisSettings, "cartesianAxis/addZAxis">, removeZAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<ZAxisSettings, "cartesianAxis/removeZAxis">;
91
+ export declare const addXAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<XAxisSettings, "cartesianAxis/addXAxis">, removeXAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<XAxisSettings, "cartesianAxis/removeXAxis">, addYAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<YAxisSettings, "cartesianAxis/addYAxis">, removeYAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<YAxisSettings, "cartesianAxis/removeYAxis">, addZAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<ZAxisSettings, "cartesianAxis/addZAxis">, removeZAxis: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<ZAxisSettings, "cartesianAxis/removeZAxis">, updateYAxisWidth: import('@reduxjs/toolkit').ActionCreatorWithOptionalPayload<{
92
+ id: AxisId;
93
+ width: number;
94
+ }, "cartesianAxis/updateYAxisWidth">;
87
95
  export declare const cartesianAxisReducer: import('@reduxjs/toolkit').Reducer<AxisMapState>;
88
96
  export {};
@@ -1,9 +1,12 @@
1
1
  import { HorizontalAlignmentType, LegendPayload, VerticalAlignmentType } from '../components/DefaultLegendContent';
2
+ import { CartesianPosition } from '../cartesian/getCartesianPosition';
2
3
  import { LayoutType, Size } from '../types';
3
4
  export type LegendSettings = {
4
5
  layout: LayoutType;
5
6
  align: HorizontalAlignmentType;
6
7
  verticalAlign: VerticalAlignmentType;
8
+ position?: CartesianPosition;
9
+ offset?: number;
7
10
  };
8
11
  /**
9
12
  * The properties inside this state update independently of each other and quite often.
@@ -0,0 +1,7 @@
1
+ import { CartesianViewBoxRequired } from '../../cartesian/type';
2
+ import { RechartsRootState } from '../store';
3
+ /**
4
+ * The margin-inset chart area. Outside-positioned legends are placed here,
5
+ * beyond any axes.
6
+ */
7
+ export declare const selectLegendArea: (state: RechartsRootState) => CartesianViewBoxRequired;
@@ -63,10 +63,20 @@ export type YAxisPadding = {
63
63
  bottom?: number;
64
64
  } | 'gap' | 'no-gap';
65
65
  export type YAxisOrientation = 'left' | 'right';
66
+ /**
67
+ * Width of the Y axis in pixels.
68
+ * `auto` will attempt to resize the axis based on its content.
69
+ */
70
+ export type YAxisWidth = number | 'auto';
66
71
  export type YAxisSettings = CartesianAxisSettings & {
67
72
  padding: YAxisPadding;
68
- width: number;
73
+ width: YAxisWidth;
69
74
  orientation: YAxisOrientation;
75
+ /**
76
+ * Internal: recent measured widths, used to detect A→B→A oscillation
77
+ * when width is measured dynamically (width === 'auto').
78
+ */
79
+ widthHistory?: number[];
70
80
  };
71
81
  export type AxisRange = readonly [number, number];
72
82
  /**
@@ -0,0 +1,20 @@
1
+ type IGetBoundingClient = Pick<Element, 'getBoundingClientRect'>;
2
+ /**
3
+ * Calculates the width of the Y-axis based on the tick labels and the axis label.
4
+ * @param params - The parameters object.
5
+ * @param [params.ticks] - An array-like object of tick elements, each with a `getBoundingClientRect` method.
6
+ * @param [params.label] - The axis label element, with a `getBoundingClientRect` method.
7
+ * @param [params.labelGapWithTick] - The gap between the label and the tick.
8
+ * @param [params.tickSize] - The length of the tick line.
9
+ * @param [params.tickMargin] - The margin between the tick line and the tick text.
10
+ * @returns The calculated width of the Y-axis.
11
+ */
12
+ export declare function getCalculatedYAxisWidth({ ticks, label, labelGapWithTick, // Default gap between label and tick
13
+ tickSize, tickMargin, }: {
14
+ ticks: ArrayLike<IGetBoundingClient> | null;
15
+ label: IGetBoundingClient | null | undefined;
16
+ labelGapWithTick: number | undefined;
17
+ tickSize: number | undefined;
18
+ tickMargin: number | undefined;
19
+ }): number;
20
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vccs",
3
3
  "type": "module",
4
- "version": "0.4.1",
4
+ "version": "0.6.0",
5
5
  "description": "Composable charting components for Vue 3 — an unofficial port of Recharts",
6
6
  "author": "rick-hup",
7
7
  "license": "MIT",