@central-ui/react 0.1.2 → 0.2.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/LICENSE +49 -0
- package/dist/components/accordion/index.d.ts +4 -3
- package/dist/components/accordion/index.js +7 -4
- package/dist/components/autocomplete/index.d.ts +14 -25
- package/dist/components/autocomplete/index.js +70 -54
- package/dist/components/avatar/index.d.ts +1 -2
- package/dist/components/avatar/index.js +0 -1
- package/dist/components/badge/index.d.ts +0 -1
- package/dist/components/badge/index.js +2 -2
- package/dist/components/banner/index.d.ts +1 -1
- package/dist/components/banner/index.js +23 -25
- package/dist/components/barchart/index.d.ts +106 -0
- package/dist/components/barchart/index.js +122 -0
- package/dist/components/breadcrumb/index.d.ts +0 -1
- package/dist/components/breadcrumb/index.js +6 -7
- package/dist/components/button/index.d.ts +2 -3
- package/dist/components/button/index.js +11 -12
- package/dist/components/card/index.d.ts +0 -1
- package/dist/components/card/index.js +0 -1
- package/dist/components/checkbox/index.d.ts +13 -11
- package/dist/components/checkbox/index.js +51 -31
- package/dist/components/chip/index.d.ts +1 -1
- package/dist/components/chip/index.js +2 -3
- package/dist/components/combobox/index.d.ts +18 -30
- package/dist/components/combobox/index.js +90 -67
- package/dist/components/datepicker/index.d.ts +18 -31
- package/dist/components/datepicker/index.js +81 -99
- package/dist/components/dialog/index.d.ts +14 -27
- package/dist/components/dialog/index.js +17 -18
- package/dist/components/divider/index.d.ts +0 -1
- package/dist/components/divider/index.js +0 -1
- package/dist/components/donutchart/index.d.ts +100 -0
- package/dist/components/donutchart/index.js +178 -0
- package/dist/components/drawer/index.d.ts +12 -21
- package/dist/components/drawer/index.js +34 -36
- package/dist/components/empty/index.d.ts +1 -2
- package/dist/components/empty/index.js +2 -4
- package/dist/components/fileupload/index.d.ts +4 -9
- package/dist/components/fileupload/index.js +26 -38
- package/dist/components/form/index.d.ts +0 -1
- package/dist/components/form/index.js +0 -1
- package/dist/components/horizontalbarchart/index.d.ts +120 -0
- package/dist/components/horizontalbarchart/index.js +193 -0
- package/dist/components/input/index.d.ts +22 -22
- package/dist/components/input/index.js +76 -105
- package/dist/components/linechart/index.d.ts +114 -0
- package/dist/components/linechart/index.js +139 -0
- package/dist/components/menu/index.d.ts +9 -11
- package/dist/components/menu/index.js +42 -39
- package/dist/components/metric/index.d.ts +0 -1
- package/dist/components/metric/index.js +0 -1
- package/dist/components/numberinput/index.d.ts +14 -21
- package/dist/components/numberinput/index.js +40 -53
- package/dist/components/otpinput/index.d.ts +14 -9
- package/dist/components/otpinput/index.js +25 -18
- package/dist/components/page/index.d.ts +0 -1
- package/dist/components/page/index.js +1 -3
- package/dist/components/passwordinput/index.d.ts +14 -11
- package/dist/components/passwordinput/index.js +36 -45
- package/dist/components/popover/index.d.ts +21 -19
- package/dist/components/popover/index.js +34 -15
- package/dist/components/radio/index.d.ts +13 -9
- package/dist/components/radio/index.js +69 -60
- package/dist/components/ratinginput/index.d.ts +13 -8
- package/dist/components/ratinginput/index.js +37 -17
- package/dist/components/select/index.d.ts +25 -28
- package/dist/components/select/index.js +67 -38
- package/dist/components/skeleton/index.d.ts +0 -1
- package/dist/components/skeleton/index.js +0 -1
- package/dist/components/slider/index.d.ts +14 -9
- package/dist/components/slider/index.js +64 -63
- package/dist/components/spinner/index.d.ts +1 -2
- package/dist/components/spinner/index.js +2 -3
- package/dist/components/splitter/index.d.ts +1 -2
- package/dist/components/splitter/index.js +5 -6
- package/dist/components/stepper/index.d.ts +8 -20
- package/dist/components/stepper/index.js +15 -16
- package/dist/components/switch/index.d.ts +12 -10
- package/dist/components/switch/index.js +46 -30
- package/dist/components/table/index.d.ts +3 -3
- package/dist/components/table/index.js +14 -13
- package/dist/components/tabs/index.d.ts +0 -1
- package/dist/components/tabs/index.js +1 -2
- package/dist/components/textarea/index.d.ts +14 -11
- package/dist/components/textarea/index.js +37 -46
- package/dist/components/textlink/index.d.ts +3 -1
- package/dist/components/textlink/index.js +4 -1
- package/dist/components/toast/index.d.ts +8 -14
- package/dist/components/toast/index.js +48 -48
- package/dist/components/toggle/index.d.ts +0 -1
- package/dist/components/toggle/index.js +17 -24
- package/dist/components/tooltip/index.d.ts +11 -13
- package/dist/components/tooltip/index.js +12 -9
- package/dist/components/tour/index.d.ts +154 -0
- package/dist/components/tour/index.js +280 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -1
- package/dist/types/Icon.d.ts +0 -1
- package/dist/types/Icon.js +0 -1
- package/dist/types/Style.d.ts +0 -1
- package/dist/types/Style.js +0 -1
- package/dist/types/Tone.d.ts +0 -1
- package/dist/types/Tone.js +0 -1
- package/dist/types/Validation.d.ts +12 -0
- package/dist/types/Validation.js +1 -0
- package/dist/utils/ArkStateToDataAttributes.d.ts +0 -1
- package/dist/utils/ArkStateToDataAttributes.js +0 -1
- package/dist/utils/Tone.d.ts +0 -1
- package/dist/utils/Tone.js +0 -1
- package/dist/utils/Validation.d.ts +14 -0
- package/dist/utils/Validation.js +23 -0
- package/dist/utils/asChild.d.ts +41 -0
- package/dist/utils/asChild.js +15 -0
- package/dist/utils/icons.d.ts +24 -0
- package/dist/utils/icons.js +160 -0
- package/dist/utils/useForwardClickToInput.d.ts +0 -1
- package/dist/utils/useForwardClickToInput.js +0 -1
- package/dist/utils/virtualization/useVirtualizedAutocomplete.d.ts +0 -1
- package/dist/utils/virtualization/useVirtualizedAutocomplete.js +0 -1
- package/dist/utils/virtualization/useVirtualizedCombobox.d.ts +0 -1
- package/dist/utils/virtualization/useVirtualizedCombobox.js +0 -1
- package/dist/utils/virtualization/useVirtualizedTable.d.ts +0 -1
- package/dist/utils/virtualization/useVirtualizedTable.js +0 -1
- package/package.json +12 -11
- package/src/presets/shopify-polaris/shopify-polaris-autocomplete.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-barchart.css +64 -0
- package/src/presets/shopify-polaris/shopify-polaris-checkbox.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-combobox.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-datepicker.css +4 -4
- package/src/presets/shopify-polaris/shopify-polaris-dialog.css +16 -0
- package/src/presets/shopify-polaris/shopify-polaris-donutchart.css +172 -0
- package/src/presets/shopify-polaris/shopify-polaris-drawer.css +16 -0
- package/src/presets/shopify-polaris/shopify-polaris-fileupload.css +1 -1
- package/src/presets/shopify-polaris/shopify-polaris-horizontalbarchart.css +60 -0
- package/src/presets/shopify-polaris/shopify-polaris-input.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-linechart.css +68 -0
- package/src/presets/shopify-polaris/shopify-polaris-menu.css +16 -0
- package/src/presets/shopify-polaris/shopify-polaris-numberinput.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-otpinput.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-passwordinput.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-popover.css +29 -0
- package/src/presets/shopify-polaris/shopify-polaris-radio.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-ratinginput.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-select.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-slider.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-stepper.css +16 -0
- package/src/presets/shopify-polaris/shopify-polaris-switch.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-textarea.css +2 -2
- package/src/presets/shopify-polaris/shopify-polaris-tooltip.css +16 -0
- package/src/presets/shopify-polaris/shopify-polaris.css +4 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-autocomplete.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-barchart.css +64 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-checkbox.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-combobox.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-datepicker.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-dialog.css +9 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-donutchart.css +172 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-drawer.css +9 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-fileupload.css +1 -1
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-horizontalbarchart.css +60 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-input.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-linechart.css +68 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-menu.css +9 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-numberinput.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-otpinput.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-passwordinput.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-popover.css +22 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-radio.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-ratinginput.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-slider.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-stepper.css +9 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-switch.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-textarea.css +2 -2
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy-tooltip.css +9 -0
- package/src/presets/shopify-polaris-legacy/shopify-polaris-legacy.css +4 -0
- package/dist/components/accordion/index.d.ts.map +0 -1
- package/dist/components/accordion/index.js.map +0 -1
- package/dist/components/autocomplete/index.d.ts.map +0 -1
- package/dist/components/autocomplete/index.js.map +0 -1
- package/dist/components/avatar/index.d.ts.map +0 -1
- package/dist/components/avatar/index.js.map +0 -1
- package/dist/components/badge/index.d.ts.map +0 -1
- package/dist/components/badge/index.js.map +0 -1
- package/dist/components/banner/index.d.ts.map +0 -1
- package/dist/components/banner/index.js.map +0 -1
- package/dist/components/breadcrumb/index.d.ts.map +0 -1
- package/dist/components/breadcrumb/index.js.map +0 -1
- package/dist/components/button/index.d.ts.map +0 -1
- package/dist/components/button/index.js.map +0 -1
- package/dist/components/card/index.d.ts.map +0 -1
- package/dist/components/card/index.js.map +0 -1
- package/dist/components/checkbox/index.d.ts.map +0 -1
- package/dist/components/checkbox/index.js.map +0 -1
- package/dist/components/chip/index.d.ts.map +0 -1
- package/dist/components/chip/index.js.map +0 -1
- package/dist/components/combobox/index.d.ts.map +0 -1
- package/dist/components/combobox/index.js.map +0 -1
- package/dist/components/datepicker/index.d.ts.map +0 -1
- package/dist/components/datepicker/index.js.map +0 -1
- package/dist/components/dialog/index.d.ts.map +0 -1
- package/dist/components/dialog/index.js.map +0 -1
- package/dist/components/divider/index.d.ts.map +0 -1
- package/dist/components/divider/index.js.map +0 -1
- package/dist/components/drawer/index.d.ts.map +0 -1
- package/dist/components/drawer/index.js.map +0 -1
- package/dist/components/empty/index.d.ts.map +0 -1
- package/dist/components/empty/index.js.map +0 -1
- package/dist/components/fileupload/index.d.ts.map +0 -1
- package/dist/components/fileupload/index.js.map +0 -1
- package/dist/components/form/index.d.ts.map +0 -1
- package/dist/components/form/index.js.map +0 -1
- package/dist/components/input/index.d.ts.map +0 -1
- package/dist/components/input/index.js.map +0 -1
- package/dist/components/menu/index.d.ts.map +0 -1
- package/dist/components/menu/index.js.map +0 -1
- package/dist/components/metric/index.d.ts.map +0 -1
- package/dist/components/metric/index.js.map +0 -1
- package/dist/components/numberinput/index.d.ts.map +0 -1
- package/dist/components/numberinput/index.js.map +0 -1
- package/dist/components/otpinput/index.d.ts.map +0 -1
- package/dist/components/otpinput/index.js.map +0 -1
- package/dist/components/page/index.d.ts.map +0 -1
- package/dist/components/page/index.js.map +0 -1
- package/dist/components/passwordinput/index.d.ts.map +0 -1
- package/dist/components/passwordinput/index.js.map +0 -1
- package/dist/components/popover/index.d.ts.map +0 -1
- package/dist/components/popover/index.js.map +0 -1
- package/dist/components/radio/index.d.ts.map +0 -1
- package/dist/components/radio/index.js.map +0 -1
- package/dist/components/ratinginput/index.d.ts.map +0 -1
- package/dist/components/ratinginput/index.js.map +0 -1
- package/dist/components/select/index.d.ts.map +0 -1
- package/dist/components/select/index.js.map +0 -1
- package/dist/components/skeleton/index.d.ts.map +0 -1
- package/dist/components/skeleton/index.js.map +0 -1
- package/dist/components/slider/index.d.ts.map +0 -1
- package/dist/components/slider/index.js.map +0 -1
- package/dist/components/spinner/index.d.ts.map +0 -1
- package/dist/components/spinner/index.js.map +0 -1
- package/dist/components/splitter/index.d.ts.map +0 -1
- package/dist/components/splitter/index.js.map +0 -1
- package/dist/components/stepper/index.d.ts.map +0 -1
- package/dist/components/stepper/index.js.map +0 -1
- package/dist/components/switch/index.d.ts.map +0 -1
- package/dist/components/switch/index.js.map +0 -1
- package/dist/components/table/index.d.ts.map +0 -1
- package/dist/components/table/index.js.map +0 -1
- package/dist/components/tabs/index.d.ts.map +0 -1
- package/dist/components/tabs/index.js.map +0 -1
- package/dist/components/textarea/index.d.ts.map +0 -1
- package/dist/components/textarea/index.js.map +0 -1
- package/dist/components/textlink/index.d.ts.map +0 -1
- package/dist/components/textlink/index.js.map +0 -1
- package/dist/components/toast/index.d.ts.map +0 -1
- package/dist/components/toast/index.js.map +0 -1
- package/dist/components/toggle/index.d.ts.map +0 -1
- package/dist/components/toggle/index.js.map +0 -1
- package/dist/components/tooltip/index.d.ts.map +0 -1
- package/dist/components/tooltip/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/types/Icon.d.ts.map +0 -1
- package/dist/types/Icon.js.map +0 -1
- package/dist/types/Style.d.ts.map +0 -1
- package/dist/types/Style.js.map +0 -1
- package/dist/types/Tone.d.ts.map +0 -1
- package/dist/types/Tone.js.map +0 -1
- package/dist/utils/ArkStateToDataAttributes.d.ts.map +0 -1
- package/dist/utils/ArkStateToDataAttributes.js.map +0 -1
- package/dist/utils/Tone.d.ts.map +0 -1
- package/dist/utils/Tone.js.map +0 -1
- package/dist/utils/useForwardClickToInput.d.ts.map +0 -1
- package/dist/utils/useForwardClickToInput.js.map +0 -1
- package/dist/utils/virtualization/useVirtualizedAutocomplete.d.ts.map +0 -1
- package/dist/utils/virtualization/useVirtualizedAutocomplete.js.map +0 -1
- package/dist/utils/virtualization/useVirtualizedCombobox.d.ts.map +0 -1
- package/dist/utils/virtualization/useVirtualizedCombobox.js.map +0 -1
- package/dist/utils/virtualization/useVirtualizedTable.d.ts.map +0 -1
- package/dist/utils/virtualization/useVirtualizedTable.js.map +0 -1
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Input as BaseInput } from '@base-ui/react/input';
|
|
3
|
-
import { LoaderCircle, X } from
|
|
4
|
-
import { useRef } from 'react';
|
|
3
|
+
import { LoaderCircle, X } from "../../utils/icons.js";
|
|
5
4
|
import { useForwardClickToInput } from "../../utils/useForwardClickToInput.js";
|
|
6
|
-
import { cloneElement, createContext, forwardRef, useContext, useEffect, useId,
|
|
5
|
+
import { cloneElement, createContext, forwardRef, useContext, useEffect, useId, useRef, useState } from 'react';
|
|
7
6
|
import { twMerge } from 'tailwind-merge';
|
|
8
|
-
import {
|
|
7
|
+
import { readValidation, validationAttributes, validationMessageContent } from "../../utils/Validation.js";
|
|
9
8
|
/**
|
|
10
|
-
* Keep configuration such as value, name
|
|
9
|
+
* Keep configuration such as value, name and validation on Root. Input is the editable control; InputGroup and Container organize it. Optional addon controls already have their own behavior where named, such as clearing.
|
|
11
10
|
*
|
|
12
11
|
* @example Complete composition
|
|
13
12
|
* import { Input } from '@central-ui/react'
|
|
@@ -44,13 +43,14 @@ import { ToneProvider, useToneContext } from "../../utils/Tone.js";
|
|
|
44
43
|
* )
|
|
45
44
|
* }
|
|
46
45
|
*/
|
|
47
|
-
export function Root({ children, id,
|
|
46
|
+
export function Root({ children, id, validation, value, defaultValue, onValueChange, disabled = false, readOnly = false, required = false, ...coreProps }) {
|
|
47
|
+
//1. Holding the value when nothing controls it from outside
|
|
48
|
+
const [valueInternalState, setValueInternalState] = useState(defaultValue ?? '');
|
|
49
|
+
//2. Holding the ids of Description, Error and Success, so Input announces them to screen readers through aria-describedby
|
|
50
|
+
const [describedByIds, setDescribedByIds] = useState([]);
|
|
51
|
+
//3. Sharing everything with the parts
|
|
48
52
|
const generatedId = useId();
|
|
49
53
|
const inputRef = useRef(null);
|
|
50
|
-
const [valueInternalState, setValueInternalState] = useState(defaultValue ?? '');
|
|
51
|
-
const [connections, setConnections] = useState({
|
|
52
|
-
descriptionIds: [],
|
|
53
|
-
});
|
|
54
54
|
return (_jsx(InputContext.Provider, { value: {
|
|
55
55
|
inputId: id ?? generatedId,
|
|
56
56
|
disabled,
|
|
@@ -58,51 +58,35 @@ export function Root({ children, id, tone = 'neutral', value, defaultValue, onVa
|
|
|
58
58
|
required,
|
|
59
59
|
inputRef,
|
|
60
60
|
value: value ?? valueInternalState,
|
|
61
|
-
setValueInternalState,
|
|
62
61
|
defaultValue,
|
|
63
62
|
controlled: value !== undefined,
|
|
63
|
+
setValueInternalState,
|
|
64
64
|
onValueChange,
|
|
65
|
+
validation: readValidation(validation),
|
|
65
66
|
coreProps,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}, children:
|
|
67
|
+
describedByIds,
|
|
68
|
+
setDescribedByIds,
|
|
69
|
+
}, children: children }));
|
|
69
70
|
}
|
|
70
71
|
export const Input = /* @__PURE__ */ forwardRef(function Input({ disableStyle, className, 'aria-describedby': describedBy, ...props }, ref) {
|
|
71
72
|
const context = useInputContext();
|
|
72
|
-
const
|
|
73
|
-
|
|
73
|
+
const attributes = usePartAttributes();
|
|
74
|
+
// Resetting the internal value when the surrounding html form resets, since the input is always controlled by Root's value
|
|
74
75
|
useEffect(() => {
|
|
75
|
-
const form = inputRef.current?.form;
|
|
76
|
+
const form = context.inputRef.current?.form;
|
|
76
77
|
if (!form || context.controlled)
|
|
77
78
|
return;
|
|
78
|
-
const reset = (event) =>
|
|
79
|
-
queueMicrotask(() => {
|
|
80
|
-
if (!event.defaultPrevented)
|
|
81
|
-
context.setValueInternalState(context.defaultValue ?? '');
|
|
82
|
-
});
|
|
83
|
-
};
|
|
79
|
+
const reset = (event) => queueMicrotask(() => !event.defaultPrevented && context.setValueInternalState(context.defaultValue ?? ''));
|
|
84
80
|
form.addEventListener('reset', reset);
|
|
85
81
|
return () => form.removeEventListener('reset', reset);
|
|
86
|
-
}, [
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
context.coreProps.form,
|
|
91
|
-
]);
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
context.inputRef.current = inputRef.current;
|
|
94
|
-
return () => {
|
|
95
|
-
context.inputRef.current = null;
|
|
96
|
-
};
|
|
97
|
-
}, [context.inputRef]);
|
|
98
|
-
return (_jsx(BaseInput, { ...context.coreProps, ...props, id: context.inputId, disabled: context.disabled, readOnly: context.readOnly, required: context.required, value: context.value, "data-tone": tone, "aria-invalid": tone === 'invalid' || props['aria-invalid'] || undefined, "aria-describedby": [describedBy, ...context.connections.descriptionIds]
|
|
99
|
-
.filter(Boolean)
|
|
100
|
-
.join(' ') || undefined, ref: (element) => {
|
|
101
|
-
inputRef.current = element;
|
|
82
|
+
}, [context.controlled, context.defaultValue, context.setValueInternalState, context.coreProps.form]);
|
|
83
|
+
return (_jsx(BaseInput, { ...attributes, ...context.coreProps, ...props, id: context.inputId, disabled: context.disabled, readOnly: context.readOnly, required: context.required, value: context.value, "aria-invalid": context.validation.state === 'error' || props['aria-invalid'] || undefined, "aria-describedby": [describedBy, ...context.describedByIds].filter(Boolean).join(' ') || undefined, ref: (element) => {
|
|
84
|
+
// Sharing the element with Root's parts, like the clear button, while still forwarding the caller's ref
|
|
85
|
+
context.inputRef.current = element;
|
|
102
86
|
if (typeof ref === 'function')
|
|
103
|
-
ref(inputRef.current);
|
|
87
|
+
ref(context.inputRef.current);
|
|
104
88
|
else if (ref)
|
|
105
|
-
ref.current = inputRef.current;
|
|
89
|
+
ref.current = context.inputRef.current;
|
|
106
90
|
}, onValueChange: (nextValue, details) => {
|
|
107
91
|
context.onValueChange?.(nextValue, details);
|
|
108
92
|
if (!details.isCanceled && !context.controlled)
|
|
@@ -111,76 +95,68 @@ export const Input = /* @__PURE__ */ forwardRef(function Input({ disableStyle, c
|
|
|
111
95
|
});
|
|
112
96
|
export const InputGroup = /* @__PURE__ */ forwardRef(function InputGroup({ disableStyle, className, onClick, ...props }, ref) {
|
|
113
97
|
const attributes = usePartAttributes();
|
|
98
|
+
// Focusing the input when clicking anywhere in the group, like on its padding or an addon text
|
|
114
99
|
const forwardClick = useForwardClickToInput('input:not([type="hidden"])', onClick);
|
|
115
|
-
return
|
|
100
|
+
return _jsx("div", { ...attributes, ...props, ref: ref, onClick: forwardClick, "data-component": "input-inputgroup", "data-style-disabled": disableStyle ? '' : undefined, className: className });
|
|
116
101
|
});
|
|
117
102
|
export const Container = /* @__PURE__ */ forwardRef(function Container({ disableStyle, className, ...props }, ref) {
|
|
118
103
|
const attributes = usePartAttributes();
|
|
119
|
-
return
|
|
104
|
+
return _jsx("div", { ...attributes, ...props, ref: ref, "data-component": "input-container", "data-style-disabled": disableStyle ? '' : undefined, className: className });
|
|
120
105
|
});
|
|
121
106
|
/** Labels the associated control automatically. Supply the visible text; do not wire a second label association. */
|
|
122
|
-
export const Label = /* @__PURE__ */ forwardRef(function Label({ disableStyle, className,
|
|
107
|
+
export const Label = /* @__PURE__ */ forwardRef(function Label({ disableStyle, className, ...props }, ref) {
|
|
123
108
|
const context = useInputContext();
|
|
124
|
-
const labelId = id ?? context.inputId + '-label';
|
|
125
109
|
const attributes = usePartAttributes();
|
|
126
|
-
|
|
127
|
-
context.setConnections((current) => ({ ...current, labelId }));
|
|
128
|
-
return () => context.setConnections((current) => ({
|
|
129
|
-
...current,
|
|
130
|
-
labelId: current.labelId === labelId ? undefined : current.labelId,
|
|
131
|
-
}));
|
|
132
|
-
}, [labelId, context.setConnections]);
|
|
133
|
-
return (_jsx("label", { ...attributes, ...props, id: labelId, ref: ref, htmlFor: context.inputId, "data-component": "input-label", "data-style-disabled": disableStyle ? '' : undefined, className: className }));
|
|
110
|
+
return _jsx("label", { ...attributes, ...props, ref: ref, htmlFor: context.inputId, "data-component": "input-label", "data-style-disabled": disableStyle ? '' : undefined, className: className });
|
|
134
111
|
});
|
|
135
112
|
export const Description = /* @__PURE__ */ forwardRef(function Description({ disableStyle, className, id, ...props }, ref) {
|
|
136
|
-
const
|
|
113
|
+
const describedById = useDescribedById(id);
|
|
137
114
|
const attributes = usePartAttributes();
|
|
138
|
-
return
|
|
115
|
+
return _jsx("div", { ...attributes, ...props, id: describedById, ref: ref, "data-component": "input-description", "data-style-disabled": disableStyle ? '' : undefined, className: className });
|
|
139
116
|
});
|
|
140
|
-
/**
|
|
141
|
-
export const Error = /* @__PURE__ */ forwardRef(function Error({
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
|
|
117
|
+
/** Shows itself only while Root's validation is `'error'`: with no children it shows the message from `['error', message]`, a function children formats that message, and other children replace it. */
|
|
118
|
+
export const Error = /* @__PURE__ */ forwardRef(function Error({ children, ...props }, ref) {
|
|
119
|
+
const context = useInputContext();
|
|
120
|
+
const content = validationMessageContent(context.validation, 'error', children);
|
|
121
|
+
if (content === undefined)
|
|
122
|
+
return null;
|
|
123
|
+
return _jsx(Message, { ...props, ref: ref, role: "alert", component: "input-error", children: content });
|
|
124
|
+
});
|
|
125
|
+
/** Shows itself only while Root's validation is `'success'`: with no children it shows the message from `['success', message]`, a function children formats that message, and other children replace it. */
|
|
126
|
+
export const Success = /* @__PURE__ */ forwardRef(function Success({ children, ...props }, ref) {
|
|
127
|
+
const context = useInputContext();
|
|
128
|
+
const content = validationMessageContent(context.validation, 'success', children);
|
|
129
|
+
if (content === undefined)
|
|
130
|
+
return null;
|
|
131
|
+
return _jsx(Message, { ...props, ref: ref, role: "status", component: "input-success", children: content });
|
|
145
132
|
});
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
133
|
+
// The shared body of Error and Success, mounted only while they show, so only visible messages describe the input
|
|
134
|
+
const Message = /* @__PURE__ */ forwardRef(function Message({ disableStyle, className, id, component, ...props }, ref) {
|
|
135
|
+
const describedById = useDescribedById(id);
|
|
149
136
|
const attributes = usePartAttributes();
|
|
150
|
-
return
|
|
137
|
+
return _jsx("div", { "aria-atomic": "true", ...attributes, ...props, id: describedById, ref: ref, "data-component": component, "data-style-disabled": disableStyle ? '' : undefined, className: className });
|
|
151
138
|
});
|
|
152
139
|
export const Addon = /* @__PURE__ */ forwardRef(function Addon({ disableStyle, className, variant = 'normal', ...props }, ref) {
|
|
153
140
|
const attributes = usePartAttributes();
|
|
154
|
-
return
|
|
141
|
+
return _jsx("div", { ...attributes, ...props, ref: ref, "data-variant": variant, "data-component": "input-addon", "data-style-disabled": disableStyle ? '' : undefined, className: className });
|
|
155
142
|
});
|
|
156
143
|
export const AddonText = /* @__PURE__ */ forwardRef(function AddonText({ disableStyle, className, ...props }, ref) {
|
|
157
144
|
const attributes = usePartAttributes();
|
|
158
|
-
return
|
|
145
|
+
return _jsx("span", { ...attributes, ...props, ref: ref, "data-component": "input-addontext", "data-style-disabled": disableStyle ? '' : undefined, className: className });
|
|
159
146
|
});
|
|
160
147
|
/** Supply the decorative icon as a child. Its classes are preserved; interaction belongs to the surrounding control. */
|
|
161
|
-
export function AddonIcon(
|
|
162
|
-
|
|
163
|
-
return cloneElement(children, {
|
|
164
|
-
...attributes,
|
|
165
|
-
...props,
|
|
166
|
-
'aria-hidden': true,
|
|
167
|
-
strokeWidth: props.strokeWidth ?? children.props.strokeWidth ?? 1.5,
|
|
168
|
-
...{
|
|
169
|
-
'data-component': 'input-addonicon',
|
|
170
|
-
'data-style-disabled': disableStyle ? '' : undefined,
|
|
171
|
-
},
|
|
172
|
-
className: twMerge(children.props.className, className),
|
|
173
|
-
});
|
|
148
|
+
export function AddonIcon(props) {
|
|
149
|
+
return _jsx(ClonedIcon, { ...props, component: "input-addonicon" });
|
|
174
150
|
}
|
|
175
151
|
export const AddonButton = /* @__PURE__ */ forwardRef(function AddonButton({ disableStyle, className, disabled, type = 'button', ...props }, ref) {
|
|
176
152
|
const context = useInputContext();
|
|
177
153
|
const attributes = usePartAttributes();
|
|
178
|
-
return
|
|
154
|
+
return _jsx("button", { ...attributes, ...props, ref: ref, type: type, disabled: disabled || context.disabled || context.readOnly, "data-component": "input-addonbutton", "data-style-disabled": disableStyle ? '' : undefined, className: className });
|
|
179
155
|
});
|
|
180
156
|
/** Built-in icon; no children needed. Use it inside its matching control. */
|
|
181
157
|
export const AddonLoadingIcon = /* @__PURE__ */ forwardRef(function AddonLoadingIcon({ disableStyle, className, strokeWidth = 1.5, ...props }, ref) {
|
|
182
158
|
const attributes = usePartAttributes();
|
|
183
|
-
return
|
|
159
|
+
return _jsx(LoaderCircle, { ...attributes, "aria-hidden": true, ...props, ref: ref, strokeWidth: strokeWidth, "data-component": "input-addonloadingicon", "data-style-disabled": disableStyle ? '' : undefined, className: className });
|
|
184
160
|
});
|
|
185
161
|
/** Clears the control automatically; no clearing click handler needed. Supply the clear icon and an accessible name. */
|
|
186
162
|
export const AddonClearButton = /* @__PURE__ */ forwardRef(function AddonClearButton({ disableStyle, className, disabled, onClick, ...props }, ref) {
|
|
@@ -188,28 +164,29 @@ export const AddonClearButton = /* @__PURE__ */ forwardRef(function AddonClearBu
|
|
|
188
164
|
const attributes = usePartAttributes();
|
|
189
165
|
return (_jsx("button", { ...attributes, "aria-label": "Clear text", ...props, ref: ref, type: "button", disabled: disabled || context.disabled || context.readOnly, onClick: (event) => {
|
|
190
166
|
onClick?.(event);
|
|
191
|
-
if (event.defaultPrevented)
|
|
192
|
-
return;
|
|
193
167
|
const input = context.inputRef.current;
|
|
194
|
-
if (!input)
|
|
168
|
+
if (event.defaultPrevented || !input)
|
|
195
169
|
return;
|
|
170
|
+
// Emptying through the native value setter then dispatching an input event, so the change goes through the same path as typing, reaching onValueChange and the form
|
|
196
171
|
Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set.call(input, '');
|
|
197
172
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
198
173
|
input.focus();
|
|
199
174
|
}, "data-component": "input-addonclearbutton", "data-style-disabled": disableStyle ? '' : undefined, className: className }));
|
|
200
175
|
});
|
|
201
176
|
/** A default icon is supplied. Omit children for the usual case; pass an icon only to replace that visual. */
|
|
202
|
-
export function AddonClearButtonIcon({
|
|
177
|
+
export function AddonClearButtonIcon({ children = _jsx(X, {}), ...props }) {
|
|
178
|
+
return _jsx(ClonedIcon, { ...props, component: "input-addonclearbuttonicon", children: children });
|
|
179
|
+
}
|
|
180
|
+
// The shared body of AddonIcon and AddonClearButtonIcon: decorates the supplied icon element, keeping its own classes and stroke
|
|
181
|
+
function ClonedIcon({ disableStyle, children, className, component, ...props }) {
|
|
203
182
|
const attributes = usePartAttributes();
|
|
204
183
|
return cloneElement(children, {
|
|
205
184
|
...attributes,
|
|
206
185
|
...props,
|
|
207
186
|
'aria-hidden': true,
|
|
208
187
|
strokeWidth: props.strokeWidth ?? children.props.strokeWidth ?? 1.5,
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
'data-style-disabled': disableStyle ? '' : undefined,
|
|
212
|
-
},
|
|
188
|
+
'data-component': component,
|
|
189
|
+
'data-style-disabled': disableStyle ? '' : undefined,
|
|
213
190
|
className: twMerge(children.props.className, className),
|
|
214
191
|
});
|
|
215
192
|
}
|
|
@@ -220,30 +197,24 @@ function useInputContext() {
|
|
|
220
197
|
throw new globalThis.Error('Parts must be inside Root');
|
|
221
198
|
return context;
|
|
222
199
|
}
|
|
200
|
+
// The state attributes every part carries, so presets can style any part from Root's state
|
|
223
201
|
function usePartAttributes() {
|
|
224
202
|
const context = useInputContext();
|
|
225
|
-
const tone = useToneContext();
|
|
226
203
|
return {
|
|
227
204
|
'data-disabled': context.disabled ? '' : undefined,
|
|
228
205
|
'data-readonly': context.readOnly ? '' : undefined,
|
|
229
206
|
'data-required': context.required ? '' : undefined,
|
|
230
|
-
|
|
207
|
+
...validationAttributes(context.validation),
|
|
231
208
|
};
|
|
232
209
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const messageId = id ?? generatedId;
|
|
210
|
+
// Registering a part's id in Input's aria-describedby while the part is mounted
|
|
211
|
+
function useDescribedById(id) {
|
|
236
212
|
const context = useInputContext();
|
|
213
|
+
const generatedId = useId();
|
|
214
|
+
const describedById = id ?? generatedId;
|
|
237
215
|
useEffect(() => {
|
|
238
|
-
context.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
return () => context.setConnections((current) => ({
|
|
243
|
-
...current,
|
|
244
|
-
descriptionIds: current.descriptionIds.filter((id) => id !== messageId),
|
|
245
|
-
}));
|
|
246
|
-
}, [messageId, context.setConnections]);
|
|
247
|
-
return messageId;
|
|
216
|
+
context.setDescribedByIds((current) => [...current, describedById]);
|
|
217
|
+
return () => context.setDescribedByIds((current) => current.filter((currentId) => currentId !== describedById));
|
|
218
|
+
}, [describedById, context.setDescribedByIds]);
|
|
219
|
+
return describedById;
|
|
248
220
|
}
|
|
249
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
import { Area as RechartsArea, ComposedChart as RechartsComposedChart } from 'recharts';
|
|
3
|
+
import type { LineProps as RechartsLineProps, TooltipProps as RechartsTooltipProps, XAxisProps as RechartsXAxisProps, YAxisProps as RechartsYAxisProps } from 'recharts';
|
|
4
|
+
import type { StyleProps } from '../../types/Style.ts';
|
|
5
|
+
/** Every record needs a unique `label` (the category) and a numeric `value` (the point height). Extra fields are kept for the tooltip. */
|
|
6
|
+
type Datum = {
|
|
7
|
+
label: string;
|
|
8
|
+
value: number;
|
|
9
|
+
};
|
|
10
|
+
export type RootProps<Data extends Datum = Datum> = Pick<ComponentProps<typeof RechartsComposedChart>, 'accessibilityLayer' | 'desc'> & {
|
|
11
|
+
/** Unique labels are equally spaced categories, including when they contain dates. */
|
|
12
|
+
data: readonly Data[];
|
|
13
|
+
'aria-label': string;
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* Converts a record's `label` into display text.
|
|
17
|
+
* Used by the X axis ticks and the tooltip label, so both always read the same.
|
|
18
|
+
* Use it for dates (e.g. `'2026-10-12'` → `'October 12, 2026'`) or to shorten long categories.
|
|
19
|
+
* @default (label) => label
|
|
20
|
+
*/
|
|
21
|
+
labelToString?: (label: string) => string;
|
|
22
|
+
/**
|
|
23
|
+
* Converts a record's `value` into display text.
|
|
24
|
+
* Used by the Y axis ticks and the tooltip value, so both always read the same.
|
|
25
|
+
* Use it for currency, percentages, or units (e.g. `1240` → `'$1,240'`).
|
|
26
|
+
* @default (value) => value.toLocaleString()
|
|
27
|
+
*/
|
|
28
|
+
valueToString?: (value: number) => string;
|
|
29
|
+
/**
|
|
30
|
+
* Whether the Y axis may place ticks at fractional values.
|
|
31
|
+
* Keep it `false` for counts (orders, visitors) so the axis never shows `0.5 orders`.
|
|
32
|
+
* Set it to `true` for continuous measures where fractions are meaningful, such as small currency amounts or ratings.
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
allowDecimals?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* How the line, and the shaded area under it, bend between points.
|
|
38
|
+
* - `'monotone'`: smooth, but never overshoots a real value. The usual choice for trends like revenue or traffic.
|
|
39
|
+
* - `'linear'`: straight segments with sharp corners. Use it when each point is a distinct measurement and smoothing would imply values in between.
|
|
40
|
+
* - `'step'`: flat steps that jump at each point. Use it for values that hold until they change, such as prices, plans, or inventory levels.
|
|
41
|
+
* @default 'monotone'
|
|
42
|
+
*/
|
|
43
|
+
curve?: 'monotone' | 'linear' | 'step';
|
|
44
|
+
};
|
|
45
|
+
/** Provides the chart data, formatting, and accessibility settings to its parts. Renders no element. */
|
|
46
|
+
export declare function Root<Data extends Datum>({ children, labelToString, valueToString, allowDecimals, curve, ...chart }: RootProps<Data>): import("react").JSX.Element;
|
|
47
|
+
export type ContainerProps = Pick<ComponentProps<typeof RechartsComposedChart>, 'children' | 'height' | 'className' | 'style' | 'id' | 'margin' | 'ref' | 'tabIndex'> & {
|
|
48
|
+
/**
|
|
49
|
+
* The vertical line that follows the pointer across the chart.
|
|
50
|
+
* Shown by default, with or without a Tooltip, so readers can line a point up with its axis label.
|
|
51
|
+
* Pass `false` for static charts where hover feedback adds noise. Style it through `data-component="linechart-hoverguide"`.
|
|
52
|
+
* @default true
|
|
53
|
+
*/
|
|
54
|
+
hoverGuide?: LineSwitch;
|
|
55
|
+
};
|
|
56
|
+
/** Recharts supplies its own responsive container, so no extra wrapper is needed. */
|
|
57
|
+
export declare function Container({ height, className, style, children, hoverGuide, ...props }: ContainerProps): import("react").JSX.Element;
|
|
58
|
+
/** On/off only: style it through its data-component in a preset, so each export keeps one className. */
|
|
59
|
+
type LineSwitch = boolean;
|
|
60
|
+
export type XAxisProps = Pick<RechartsXAxisProps, 'hide' | 'tickSize'> & {
|
|
61
|
+
/** Classes for the tick labels, e.g. `fill-neutral-500`. Keep the font size at 12px: Recharts measures labels at that size to skip overlapping ones. */
|
|
62
|
+
className?: string;
|
|
63
|
+
/** Space between the labels and the plot area, in pixels. */
|
|
64
|
+
labelGap?: number;
|
|
65
|
+
/** The line along the axis. Hidden by default. */
|
|
66
|
+
axisLine?: LineSwitch;
|
|
67
|
+
/** The small marks at each tick. Hidden by default. */
|
|
68
|
+
tickLine?: LineSwitch;
|
|
69
|
+
};
|
|
70
|
+
export declare function XAxis({ className, labelGap, axisLine, tickLine, ...props }: XAxisProps): import("react").JSX.Element;
|
|
71
|
+
export type YAxisProps = Pick<RechartsYAxisProps, 'hide' | 'tickSize' | 'width'> & {
|
|
72
|
+
/** Classes for the tick labels, e.g. `fill-neutral-500`. Keep the font size at 12px: Recharts measures labels at that size to skip overlapping ones. */
|
|
73
|
+
className?: string;
|
|
74
|
+
/** Space between the labels and the plot area, in pixels. */
|
|
75
|
+
labelGap?: number;
|
|
76
|
+
/** The line along the axis. Hidden by default. */
|
|
77
|
+
axisLine?: LineSwitch;
|
|
78
|
+
/** The small marks at each tick. Hidden by default. */
|
|
79
|
+
tickLine?: LineSwitch;
|
|
80
|
+
};
|
|
81
|
+
export declare function YAxis({ className, labelGap, axisLine, tickLine, ...props }: YAxisProps): import("react").JSX.Element;
|
|
82
|
+
export type GridProps = {
|
|
83
|
+
/** Classes for every grid line, e.g. `stroke-neutral-200 [stroke-dasharray:4_4]`. */
|
|
84
|
+
className?: string;
|
|
85
|
+
};
|
|
86
|
+
/** Horizontal lines only, one per Y value tick. */
|
|
87
|
+
export declare function Grid({ className }: GridProps): import("react").JSX.Element;
|
|
88
|
+
export type LineProps = Pick<RechartsLineProps, 'hide' | 'name'> & {
|
|
89
|
+
/** Classes for the line, e.g. `stroke-sky-500`. It is 2px wide by default; override with `stroke-3`. */
|
|
90
|
+
className?: string;
|
|
91
|
+
/** The dot on the hovered point. Pass `false` to hide it; style it through `data-component="linechart-activedot"`. */
|
|
92
|
+
activeDot?: LineSwitch;
|
|
93
|
+
};
|
|
94
|
+
export declare function Line({ className, activeDot, ...props }: LineProps): import("react").JSX.Element;
|
|
95
|
+
export type AreaProps = Pick<ComponentProps<typeof RechartsArea>, 'hide'> & {
|
|
96
|
+
/** Classes for the shading, e.g. `fill-sky-500/10`. */
|
|
97
|
+
className?: string;
|
|
98
|
+
};
|
|
99
|
+
/** Optional shading under the line. Render it before Line so the line draws on top. */
|
|
100
|
+
export declare function Area({ className, ...props }: AreaProps): import("react").JSX.Element;
|
|
101
|
+
export type TooltipProps<Data extends Datum = Datum> = Pick<RechartsTooltipProps<number, string>, 'offset' | 'allowEscapeViewBox' | 'portal'> & {
|
|
102
|
+
/** Receives the hovered record and returns the popup. */
|
|
103
|
+
children: (datum: Data) => ReactNode;
|
|
104
|
+
};
|
|
105
|
+
/** Renders no element: hands its popup to the Container. For extra fields, specify the record type: Tooltip<(typeof data)[number]>. */
|
|
106
|
+
export declare function Tooltip<Data extends Datum = Datum>({ children, offset, allowEscapeViewBox, portal, }: TooltipProps<Data>): null;
|
|
107
|
+
export declare function TooltipPopup({ disableStyle, className, ...props }: ComponentProps<'div'> & StyleProps): import("react").JSX.Element;
|
|
108
|
+
export declare function TooltipTitle({ disableStyle, className, ...props }: ComponentProps<'p'> & StyleProps): import("react").JSX.Element;
|
|
109
|
+
/** Shows the hovered record's label, formatted by `labelToString` on Root. */
|
|
110
|
+
export declare function TooltipLabel({ disableStyle, className, ...props }: Omit<ComponentProps<'p'>, 'children'> & StyleProps): import("react").JSX.Element;
|
|
111
|
+
/** Shows the hovered record's value, formatted by `valueToString` on Root. */
|
|
112
|
+
export declare function TooltipValue({ disableStyle, className, ...props }: Omit<ComponentProps<'p'>, 'children'> & StyleProps): import("react").JSX.Element;
|
|
113
|
+
export declare function TooltipColorIndicator({ disableStyle, className, ...props }: ComponentProps<'span'> & StyleProps): import("react").JSX.Element;
|
|
114
|
+
export {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useLayoutEffect, useState } from 'react';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
import { Area as RechartsArea, CartesianGrid as RechartsGrid, ComposedChart as RechartsComposedChart, Curve as RechartsCurve, Line as RechartsLine, Tooltip as RechartsTooltip, XAxis as RechartsXAxis, YAxis as RechartsYAxis, } from 'recharts';
|
|
5
|
+
const ChartContext = /* @__PURE__ */ createContext(null);
|
|
6
|
+
/** Provides the chart data, formatting, and accessibility settings to its parts. Renders no element. */
|
|
7
|
+
export function Root({ children, labelToString = (label) => label, valueToString = (value) => value.toLocaleString(), allowDecimals = false, curve = 'monotone', ...chart }) {
|
|
8
|
+
return (_jsx(ChartContext.Provider, { value: { ...chart, labelToString, valueToString, allowDecimals, curve }, children: children }));
|
|
9
|
+
}
|
|
10
|
+
function useChart(part) {
|
|
11
|
+
const chart = useContext(ChartContext);
|
|
12
|
+
if (!chart)
|
|
13
|
+
throw new Error(`LineChart.${part} must be inside LineChart.Root`);
|
|
14
|
+
return chart;
|
|
15
|
+
}
|
|
16
|
+
/** Lets a Tooltip part hand its content to the Container, which owns the single Recharts tooltip. */
|
|
17
|
+
const TooltipSlotContext = /* @__PURE__ */ createContext(null);
|
|
18
|
+
/** Recharts supplies its own responsive container, so no extra wrapper is needed. */
|
|
19
|
+
export function Container({ height = 300, className, style, children, hoverGuide = true, ...props }) {
|
|
20
|
+
const chart = useChart('Container');
|
|
21
|
+
const [tooltip, setTooltip] = useState(null);
|
|
22
|
+
return (_jsxs(RechartsComposedChart, { margin: { top: 12, right: 12, bottom: 0, left: 0 }, ...props, data: chart.data, accessibilityLayer: chart.accessibilityLayer, desc: chart.desc, title: chart['aria-label'], className: twMerge('min-w-0 w-full', className), style: { ...style, background: 'transparent' }, height: height, width: "100%", responsive: true, layout: "horizontal", children: [_jsx(TooltipSlotContext.Provider, { value: setTooltip, children: children }), _jsx(RechartsTooltip, { offset: 12, ...tooltip?.props,
|
|
23
|
+
// Native popup slide, timed to match the hover guide's transition.
|
|
24
|
+
animationDuration: 200, animationEasing: "ease-out", shared: true, cursor: hoverGuide && _jsx(HoverGuide, {}), content: (state) => {
|
|
25
|
+
if (!tooltip || !state.active || !state.payload.length)
|
|
26
|
+
return null;
|
|
27
|
+
// Recharts types the payload as unknown; payload[0] is always the hovered record.
|
|
28
|
+
const datum = state.payload[0].payload;
|
|
29
|
+
return (_jsx(TooltipContext.Provider, { value: datum, children: tooltip.render(datum) }));
|
|
30
|
+
} })] }));
|
|
31
|
+
}
|
|
32
|
+
const lineProps = (line, part) =>
|
|
33
|
+
// Recharts forwards data attributes at runtime; its types omit them.
|
|
34
|
+
(line && { 'data-component': part });
|
|
35
|
+
export function XAxis({ className, labelGap = 8, axisLine = false, tickLine = false, ...props }) {
|
|
36
|
+
const chart = useChart('XAxis');
|
|
37
|
+
return (_jsx(RechartsXAxis, { height: "auto", ...props, axisLine: lineProps(axisLine, 'linechart-xaxis-line'), tickLine: lineProps(tickLine, 'linechart-xaxis-tickline'), tick: {
|
|
38
|
+
className,
|
|
39
|
+
'data-component': 'linechart-xaxis-ticklabel',
|
|
40
|
+
}, tickMargin: labelGap, tickFormatter: chart.labelToString,
|
|
41
|
+
// Recharts measures labels at this size when it hides overlapping ones.
|
|
42
|
+
fontSize: 12, dataKey: "label", type: "category",
|
|
43
|
+
// Points sit on the chart edges instead of in the middle of bar-style slots.
|
|
44
|
+
scale: "point", label: false, angle: 0,
|
|
45
|
+
// Drops labels at a steady step when they would overlap, so the remaining ones stay evenly spaced.
|
|
46
|
+
interval: "equidistantPreserveStart", minTickGap: 8 }));
|
|
47
|
+
}
|
|
48
|
+
export function YAxis({ className, labelGap = 8, axisLine = false, tickLine = false, ...props }) {
|
|
49
|
+
const chart = useChart('YAxis');
|
|
50
|
+
return (_jsx(RechartsYAxis, { width: "auto", ...props, axisLine: lineProps(axisLine, 'linechart-yaxis-line'), tickLine: lineProps(tickLine, 'linechart-yaxis-tickline'), tick: {
|
|
51
|
+
className,
|
|
52
|
+
'data-component': 'linechart-yaxis-ticklabel',
|
|
53
|
+
}, tickMargin: labelGap, tickFormatter: chart.valueToString, allowDecimals: chart.allowDecimals, fontSize: 12, type: "number", label: false, angle: 0,
|
|
54
|
+
// Always include zero so the line has a baseline, and never collapse the range when every value is 0.
|
|
55
|
+
domain: ([minimum, maximum]) => [
|
|
56
|
+
Math.min(0, minimum),
|
|
57
|
+
Math.max(Math.min(0, minimum) + 1, maximum, 0),
|
|
58
|
+
], interval: "preserveStartEnd", minTickGap: 8 }));
|
|
59
|
+
}
|
|
60
|
+
/** Horizontal lines only, one per Y value tick. */
|
|
61
|
+
export function Grid({ className }) {
|
|
62
|
+
return (_jsx(RechartsGrid
|
|
63
|
+
// Recharts' native line slot: each line gets the class and a data-component hook.
|
|
64
|
+
, {
|
|
65
|
+
// Recharts' native line slot: each line gets the class and a data-component hook.
|
|
66
|
+
horizontal: { className, 'data-component': 'linechart-gridline' }, vertical: false, fill: "none" }));
|
|
67
|
+
}
|
|
68
|
+
export function Line({ className, activeDot = true, ...props }) {
|
|
69
|
+
const chart = useChart('Line');
|
|
70
|
+
return (_jsx(RechartsLine, { strokeWidth: 2, ...props,
|
|
71
|
+
// Recharts' native shape slot renders the line ourselves, so className and data attributes land on the drawn path.
|
|
72
|
+
shape: (line) => (_jsx(RechartsCurve, { ...line, className: className, "data-component": "linechart-line", "data-curve": chart.curve })), activeDot: activeDot &&
|
|
73
|
+
{
|
|
74
|
+
r: 4,
|
|
75
|
+
strokeWidth: 2,
|
|
76
|
+
// Recharts forwards data attributes at runtime; its types omit them.
|
|
77
|
+
'data-component': 'linechart-activedot',
|
|
78
|
+
}, dataKey: "value", type: chart.curve,
|
|
79
|
+
// Points only appear on hover; at rest the line stays clean.
|
|
80
|
+
dot: false, isAnimationActive: false }));
|
|
81
|
+
}
|
|
82
|
+
/** Optional shading under the line. Render it before Line so the line draws on top. */
|
|
83
|
+
export function Area({ className, ...props }) {
|
|
84
|
+
const chart = useChart('Area');
|
|
85
|
+
return (_jsx(RechartsArea, { ...props, shape: (area) => (_jsx(RechartsCurve, { ...area, className: className, "data-component": "linechart-area", "data-curve": chart.curve, stroke: "none" })), dataKey: "value", type: chart.curve, stroke: "none",
|
|
86
|
+
// The Line owns the hover dot; the area is only a backdrop.
|
|
87
|
+
activeDot: false, tooltipType: "none", isAnimationActive: false }));
|
|
88
|
+
}
|
|
89
|
+
const TooltipContext = /* @__PURE__ */ createContext(null);
|
|
90
|
+
/** Renders no element: hands its popup to the Container. For extra fields, specify the record type: Tooltip<(typeof data)[number]>. */
|
|
91
|
+
export function Tooltip({ children, offset, allowEscapeViewBox, portal, }) {
|
|
92
|
+
const setTooltip = useContext(TooltipSlotContext);
|
|
93
|
+
if (!setTooltip)
|
|
94
|
+
throw new Error('LineChart.Tooltip must be inside LineChart.Container');
|
|
95
|
+
useLayoutEffect(() => {
|
|
96
|
+
setTooltip({
|
|
97
|
+
render: children,
|
|
98
|
+
props: { offset, allowEscapeViewBox, portal },
|
|
99
|
+
});
|
|
100
|
+
return () => setTooltip(null);
|
|
101
|
+
}, [setTooltip, children, offset, allowEscapeViewBox, portal]);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
/** Recharts gives a line chart's cursor the guide's two end points. */
|
|
105
|
+
function HoverGuide({ points, }) {
|
|
106
|
+
if (!points || points.length < 2)
|
|
107
|
+
return null;
|
|
108
|
+
const [start, end] = points;
|
|
109
|
+
return (_jsx("line", { "data-component": "linechart-hoverguide",
|
|
110
|
+
// Draw at x=0 and move with a transform, so CSS can slide it between points (Recharts' cursor has no animation of its own).
|
|
111
|
+
x1: 0, x2: 0, y1: start.y, y2: end.y,
|
|
112
|
+
// The slide between points is built in.
|
|
113
|
+
className: "transition-transform duration-200 ease-out motion-reduce:transition-none", style: { transform: `translateX(${start.x}px)` }, pointerEvents: "none" }));
|
|
114
|
+
}
|
|
115
|
+
export function TooltipPopup({ disableStyle, className, ...props }) {
|
|
116
|
+
return (_jsx("div", { ...props, "data-component": "linechart-tooltip", "data-style-disabled": disableStyle ? '' : undefined, className: className }));
|
|
117
|
+
}
|
|
118
|
+
export function TooltipTitle({ disableStyle, className, ...props }) {
|
|
119
|
+
return (_jsx("p", { ...props, "data-component": "linechart-tooltiptitle", "data-style-disabled": disableStyle ? '' : undefined, className: className }));
|
|
120
|
+
}
|
|
121
|
+
/** Shows the hovered record's label, formatted by `labelToString` on Root. */
|
|
122
|
+
export function TooltipLabel({ disableStyle, className, ...props }) {
|
|
123
|
+
const chart = useChart('TooltipLabel');
|
|
124
|
+
const datum = useContext(TooltipContext);
|
|
125
|
+
if (!datum)
|
|
126
|
+
throw new Error('LineChart.TooltipLabel must be inside LineChart.Tooltip');
|
|
127
|
+
return (_jsx("p", { ...props, "data-component": "linechart-tooltiplabel", "data-style-disabled": disableStyle ? '' : undefined, className: className, children: chart.labelToString(datum.label) }));
|
|
128
|
+
}
|
|
129
|
+
/** Shows the hovered record's value, formatted by `valueToString` on Root. */
|
|
130
|
+
export function TooltipValue({ disableStyle, className, ...props }) {
|
|
131
|
+
const chart = useChart('TooltipValue');
|
|
132
|
+
const datum = useContext(TooltipContext);
|
|
133
|
+
if (!datum)
|
|
134
|
+
throw new Error('LineChart.TooltipValue must be inside LineChart.Tooltip');
|
|
135
|
+
return (_jsx("p", { ...props, "data-component": "linechart-tooltipvalue", "data-style-disabled": disableStyle ? '' : undefined, className: className, children: chart.valueToString(datum.value) }));
|
|
136
|
+
}
|
|
137
|
+
export function TooltipColorIndicator({ disableStyle, className, ...props }) {
|
|
138
|
+
return (_jsx("span", { "aria-hidden": "true", ...props, "data-component": "linechart-tooltipcolorindicator", "data-style-disabled": disableStyle ? '' : undefined, className: className }));
|
|
139
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { StyleProps } from '../../types/Style.ts';
|
|
2
|
+
import type { AsChildProps } from '../../utils/asChild.ts';
|
|
2
3
|
import { Menu as BaseMenu } from '@base-ui/react/menu';
|
|
3
4
|
import type { ComponentPropsWithRef, ReactElement } from 'react';
|
|
4
5
|
import type { SVGIconProps } from '../../types/Icon.ts';
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* OpenButton renders its own trigger button; pass asChild to give its behavior to your own button instead. Popup already includes its portal and positioner. Choose ButtonItem for actions and LinkItem for navigation. Use the matching checkbox/radio composition for persistent choices; submenu parts belong in SubMenuRoot.
|
|
7
8
|
*
|
|
8
9
|
* @example Complete composition
|
|
9
10
|
* import { Button, Menu } from '@central-ui/react'
|
|
@@ -11,9 +12,9 @@ import type { SVGIconProps } from '../../types/Icon.ts';
|
|
|
11
12
|
* function Example() {
|
|
12
13
|
* return (
|
|
13
14
|
* <Menu.Root>
|
|
14
|
-
* <Menu.
|
|
15
|
+
* <Menu.OpenButton asChild>
|
|
15
16
|
* <Button.default variant="primary">Options</Button.default>
|
|
16
|
-
* </Menu.
|
|
17
|
+
* </Menu.OpenButton>
|
|
17
18
|
* <Menu.Popup>
|
|
18
19
|
* <Menu.Group>
|
|
19
20
|
* <Menu.GroupLabel>Account</Menu.GroupLabel>
|
|
@@ -47,19 +48,17 @@ import type { SVGIconProps } from '../../types/Icon.ts';
|
|
|
47
48
|
* </Menu.Popup>
|
|
48
49
|
* </Menu.SubMenuRoot>
|
|
49
50
|
*/
|
|
50
|
-
export declare
|
|
51
|
+
export declare function Root<Payload = unknown>(props: BaseMenu.Root.Props<Payload>): import("react").JSX.Element;
|
|
51
52
|
export declare const SubMenuRoot: typeof BaseMenu.SubmenuRoot;
|
|
52
|
-
/**
|
|
53
|
-
export declare const
|
|
53
|
+
/** Opens the menu. Pass asChild to give this behavior to your own element, like your app's Button. */
|
|
54
|
+
export declare const OpenButton: import("react").ForwardRefExoticComponent<Omit<Omit<BaseMenu.Trigger.Props<unknown>, "className" | "render"> & {
|
|
54
55
|
className?: string;
|
|
55
|
-
|
|
56
|
-
children: ReactElement;
|
|
57
|
-
}, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
|
|
56
|
+
} & AsChildProps & StyleProps, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
|
|
58
57
|
export type PopupProps = Omit<ComponentPropsWithRef<typeof BaseMenu.Popup>, 'className'> & {
|
|
59
58
|
className?: string;
|
|
60
59
|
} & Pick<BaseMenu.Portal.Props, 'container' | 'keepMounted'> & Pick<BaseMenu.Positioner.Props, 'anchor' | 'positionMethod' | 'side' | 'sideOffset' | 'align' | 'alignOffset' | 'collisionBoundary' | 'collisionPadding' | 'sticky' | 'arrowPadding' | 'disableAnchorTracking' | 'collisionAvoidance'> & StyleProps;
|
|
61
60
|
/** Already includes the portal and positioner. Keep it in the matching Root and let the native open state control visibility. */
|
|
62
|
-
export declare function Popup({ disableStyle, container, keepMounted, anchor, positionMethod, side, sideOffset, align, alignOffset, collisionBoundary, collisionPadding, sticky, arrowPadding, disableAnchorTracking, collisionAvoidance, className, style, ...props }: PopupProps
|
|
61
|
+
export declare function Popup({ disableStyle, container, keepMounted, anchor, positionMethod, side, sideOffset, align, alignOffset, collisionBoundary, collisionPadding, sticky, arrowPadding, disableAnchorTracking, collisionAvoidance, className, style, ...props }: PopupProps): import("react").JSX.Element;
|
|
63
62
|
export declare const Arrow: import("react").ForwardRefExoticComponent<Omit<Omit<import("react").SVGProps<SVGSVGElement>, "children" | "dangerouslySetInnerHTML"> & StyleProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
|
|
64
63
|
export declare const Group: import("react").ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react").ContextMenuGroupProps, "className"> & {
|
|
65
64
|
className?: string;
|
|
@@ -112,4 +111,3 @@ export declare const RadioLabel: import("react").ForwardRefExoticComponent<Omit<
|
|
|
112
111
|
export declare const RadioItemIndicator: import("react").ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react").ContextMenuRadioItemIndicatorProps, "className"> & {
|
|
113
112
|
className?: string;
|
|
114
113
|
} & StyleProps, "ref"> & import("react").RefAttributes<HTMLSpanElement>>;
|
|
115
|
-
//# sourceMappingURL=index.d.ts.map
|