@cdx-ui/primitives 0.1.7 → 0.2.1
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/lib/commonjs/calendar/CalendarRoot.js +3 -1
- package/lib/commonjs/calendar/CalendarRoot.js.map +1 -1
- package/lib/commonjs/calendar/context.js.map +1 -1
- package/lib/commonjs/color/Color.js +69 -0
- package/lib/commonjs/color/Color.js.map +1 -0
- package/lib/commonjs/color/index.js +13 -0
- package/lib/commonjs/color/index.js.map +1 -0
- package/lib/commonjs/color/types.js +2 -0
- package/lib/commonjs/color/types.js.map +1 -0
- package/lib/commonjs/color-area/ColorAreaAccessibility.js +100 -0
- package/lib/commonjs/color-area/ColorAreaAccessibility.js.map +1 -0
- package/lib/commonjs/color-area/ColorAreaAccessibility.web.js +58 -0
- package/lib/commonjs/color-area/ColorAreaAccessibility.web.js.map +1 -0
- package/lib/commonjs/color-area/ColorAreaRoot.js +240 -0
- package/lib/commonjs/color-area/ColorAreaRoot.js.map +1 -0
- package/lib/commonjs/color-area/ColorAreaThumb.js +71 -0
- package/lib/commonjs/color-area/ColorAreaThumb.js.map +1 -0
- package/lib/commonjs/color-area/context.js +11 -0
- package/lib/commonjs/color-area/context.js.map +1 -0
- package/lib/commonjs/color-area/index.js +27 -0
- package/lib/commonjs/color-area/index.js.map +1 -0
- package/lib/commonjs/color-area/types.js +6 -0
- package/lib/commonjs/color-area/types.js.map +1 -0
- package/lib/commonjs/color-area/utils.js +51 -0
- package/lib/commonjs/color-area/utils.js.map +1 -0
- package/lib/commonjs/color-field/ColorFieldInput.js +67 -0
- package/lib/commonjs/color-field/ColorFieldInput.js.map +1 -0
- package/lib/commonjs/color-field/ColorFieldRoot.js +104 -0
- package/lib/commonjs/color-field/ColorFieldRoot.js.map +1 -0
- package/lib/commonjs/color-field/context.js +11 -0
- package/lib/commonjs/color-field/context.js.map +1 -0
- package/lib/commonjs/color-field/index.js +27 -0
- package/lib/commonjs/color-field/index.js.map +1 -0
- package/lib/commonjs/color-field/types.js +6 -0
- package/lib/commonjs/color-field/types.js.map +1 -0
- package/lib/commonjs/color-field/utils.js +60 -0
- package/lib/commonjs/color-field/utils.js.map +1 -0
- package/lib/commonjs/color-picker/ColorPickerRoot.js +69 -0
- package/lib/commonjs/color-picker/ColorPickerRoot.js.map +1 -0
- package/lib/commonjs/color-picker/ColorPickerTrigger.js +98 -0
- package/lib/commonjs/color-picker/ColorPickerTrigger.js.map +1 -0
- package/lib/commonjs/color-picker/context.js +32 -0
- package/lib/commonjs/color-picker/context.js.map +1 -0
- package/lib/commonjs/color-picker/index.js +51 -0
- package/lib/commonjs/color-picker/index.js.map +1 -0
- package/lib/commonjs/color-picker/types.js +6 -0
- package/lib/commonjs/color-picker/types.js.map +1 -0
- package/lib/commonjs/color-slider/ColorSliderRail.js +119 -0
- package/lib/commonjs/color-slider/ColorSliderRail.js.map +1 -0
- package/lib/commonjs/color-slider/ColorSliderRoot.js +153 -0
- package/lib/commonjs/color-slider/ColorSliderRoot.js.map +1 -0
- package/lib/commonjs/color-slider/ColorSliderThumb.js +265 -0
- package/lib/commonjs/color-slider/ColorSliderThumb.js.map +1 -0
- package/lib/commonjs/color-slider/context.js +11 -0
- package/lib/commonjs/color-slider/context.js.map +1 -0
- package/lib/commonjs/color-slider/index.js +34 -0
- package/lib/commonjs/color-slider/index.js.map +1 -0
- package/lib/commonjs/color-slider/types.js +6 -0
- package/lib/commonjs/color-slider/types.js.map +1 -0
- package/lib/commonjs/color-slider/utils.js +75 -0
- package/lib/commonjs/color-slider/utils.js.map +1 -0
- package/lib/commonjs/color-swatch-picker/ColorSwatchPickerItem.js +46 -0
- package/lib/commonjs/color-swatch-picker/ColorSwatchPickerItem.js.map +1 -0
- package/lib/commonjs/color-swatch-picker/ColorSwatchPickerRoot.js +71 -0
- package/lib/commonjs/color-swatch-picker/ColorSwatchPickerRoot.js.map +1 -0
- package/lib/commonjs/color-swatch-picker/context.js +22 -0
- package/lib/commonjs/color-swatch-picker/context.js.map +1 -0
- package/lib/commonjs/color-swatch-picker/index.js +33 -0
- package/lib/commonjs/color-swatch-picker/index.js.map +1 -0
- package/lib/commonjs/color-swatch-picker/types.js +6 -0
- package/lib/commonjs/color-swatch-picker/types.js.map +1 -0
- package/lib/commonjs/date-field/DateFieldRoot.js +5 -1
- package/lib/commonjs/date-field/DateFieldRoot.js.map +1 -1
- package/lib/commonjs/date-field/DateFieldSegment.js +7 -1
- package/lib/commonjs/date-field/DateFieldSegment.js.map +1 -1
- package/lib/commonjs/date-field/context.js.map +1 -1
- package/lib/commonjs/date-picker/DatePickerRoot.js +59 -13
- package/lib/commonjs/date-picker/DatePickerRoot.js.map +1 -1
- package/lib/commonjs/date-picker/context.js.map +1 -1
- package/lib/commonjs/index.js +80 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/react-native-web.d.js +2 -0
- package/lib/commonjs/react-native-web.d.js.map +1 -0
- package/lib/commonjs/slider/useSliderPointer.js +2 -0
- package/lib/commonjs/slider/useSliderPointer.js.map +1 -1
- package/lib/commonjs/utils/createPortal.web.js +10 -1
- package/lib/commonjs/utils/createPortal.web.js.map +1 -1
- package/lib/commonjs/utils/textAncestor.js +25 -0
- package/lib/commonjs/utils/textAncestor.js.map +1 -0
- package/lib/commonjs/utils/textAncestor.web.js +27 -0
- package/lib/commonjs/utils/textAncestor.web.js.map +1 -0
- package/lib/module/calendar/CalendarRoot.js +3 -1
- package/lib/module/calendar/CalendarRoot.js.map +1 -1
- package/lib/module/calendar/context.js.map +1 -1
- package/lib/module/color/Color.js +65 -0
- package/lib/module/color/Color.js.map +1 -0
- package/lib/module/color/index.js +4 -0
- package/lib/module/color/index.js.map +1 -0
- package/lib/module/color/types.js +2 -0
- package/lib/module/color/types.js.map +1 -0
- package/lib/module/color-area/ColorAreaAccessibility.js +96 -0
- package/lib/module/color-area/ColorAreaAccessibility.js.map +1 -0
- package/lib/module/color-area/ColorAreaAccessibility.web.js +54 -0
- package/lib/module/color-area/ColorAreaAccessibility.web.js.map +1 -0
- package/lib/module/color-area/ColorAreaRoot.js +236 -0
- package/lib/module/color-area/ColorAreaRoot.js.map +1 -0
- package/lib/module/color-area/ColorAreaThumb.js +67 -0
- package/lib/module/color-area/ColorAreaThumb.js.map +1 -0
- package/lib/module/color-area/context.js +5 -0
- package/lib/module/color-area/context.js.map +1 -0
- package/lib/module/color-area/index.js +6 -0
- package/lib/module/color-area/index.js.map +1 -0
- package/lib/module/color-area/types.js +4 -0
- package/lib/module/color-area/types.js.map +1 -0
- package/lib/module/color-area/utils.js +45 -0
- package/lib/module/color-area/utils.js.map +1 -0
- package/lib/module/color-field/ColorFieldInput.js +63 -0
- package/lib/module/color-field/ColorFieldInput.js.map +1 -0
- package/lib/module/color-field/ColorFieldRoot.js +100 -0
- package/lib/module/color-field/ColorFieldRoot.js.map +1 -0
- package/lib/module/color-field/context.js +5 -0
- package/lib/module/color-field/context.js.map +1 -0
- package/lib/module/color-field/index.js +6 -0
- package/lib/module/color-field/index.js.map +1 -0
- package/lib/module/color-field/types.js +4 -0
- package/lib/module/color-field/types.js.map +1 -0
- package/lib/module/color-field/utils.js +55 -0
- package/lib/module/color-field/utils.js.map +1 -0
- package/lib/module/color-picker/ColorPickerRoot.js +65 -0
- package/lib/module/color-picker/ColorPickerRoot.js.map +1 -0
- package/lib/module/color-picker/ColorPickerTrigger.js +94 -0
- package/lib/module/color-picker/ColorPickerTrigger.js.map +1 -0
- package/lib/module/color-picker/context.js +25 -0
- package/lib/module/color-picker/context.js.map +1 -0
- package/lib/module/color-picker/index.js +6 -0
- package/lib/module/color-picker/index.js.map +1 -0
- package/lib/module/color-picker/types.js +4 -0
- package/lib/module/color-picker/types.js.map +1 -0
- package/lib/module/color-slider/ColorSliderRail.js +115 -0
- package/lib/module/color-slider/ColorSliderRail.js.map +1 -0
- package/lib/module/color-slider/ColorSliderRoot.js +149 -0
- package/lib/module/color-slider/ColorSliderRoot.js.map +1 -0
- package/lib/module/color-slider/ColorSliderThumb.js +261 -0
- package/lib/module/color-slider/ColorSliderThumb.js.map +1 -0
- package/lib/module/color-slider/context.js +5 -0
- package/lib/module/color-slider/context.js.map +1 -0
- package/lib/module/color-slider/index.js +7 -0
- package/lib/module/color-slider/index.js.map +1 -0
- package/lib/module/color-slider/types.js +4 -0
- package/lib/module/color-slider/types.js.map +1 -0
- package/lib/module/color-slider/utils.js +66 -0
- package/lib/module/color-slider/utils.js.map +1 -0
- package/lib/module/color-swatch-picker/ColorSwatchPickerItem.js +42 -0
- package/lib/module/color-swatch-picker/ColorSwatchPickerItem.js.map +1 -0
- package/lib/module/color-swatch-picker/ColorSwatchPickerRoot.js +67 -0
- package/lib/module/color-swatch-picker/ColorSwatchPickerRoot.js.map +1 -0
- package/lib/module/color-swatch-picker/context.js +15 -0
- package/lib/module/color-swatch-picker/context.js.map +1 -0
- package/lib/module/color-swatch-picker/index.js +6 -0
- package/lib/module/color-swatch-picker/index.js.map +1 -0
- package/lib/module/color-swatch-picker/types.js +4 -0
- package/lib/module/color-swatch-picker/types.js.map +1 -0
- package/lib/module/date-field/DateFieldRoot.js +6 -2
- package/lib/module/date-field/DateFieldRoot.js.map +1 -1
- package/lib/module/date-field/DateFieldSegment.js +7 -1
- package/lib/module/date-field/DateFieldSegment.js.map +1 -1
- package/lib/module/date-field/context.js.map +1 -1
- package/lib/module/date-picker/DatePickerRoot.js +62 -16
- package/lib/module/date-picker/DatePickerRoot.js.map +1 -1
- package/lib/module/date-picker/context.js.map +1 -1
- package/lib/module/index.js +7 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/react-native-web.d.js +2 -0
- package/lib/module/react-native-web.d.js.map +1 -0
- package/lib/module/slider/useSliderPointer.js +2 -0
- package/lib/module/slider/useSliderPointer.js.map +1 -1
- package/lib/module/utils/createPortal.web.js +9 -1
- package/lib/module/utils/createPortal.web.js.map +1 -1
- package/lib/module/utils/textAncestor.js +20 -0
- package/lib/module/utils/textAncestor.js.map +1 -0
- package/lib/module/utils/textAncestor.web.js +22 -0
- package/lib/module/utils/textAncestor.web.js.map +1 -0
- package/lib/typescript/calendar/CalendarRoot.d.ts.map +1 -1
- package/lib/typescript/calendar/context.d.ts +1 -0
- package/lib/typescript/calendar/context.d.ts.map +1 -1
- package/lib/typescript/calendar/types.d.ts +7 -0
- package/lib/typescript/calendar/types.d.ts.map +1 -1
- package/lib/typescript/color/Color.d.ts +3 -0
- package/lib/typescript/color/Color.d.ts.map +1 -0
- package/lib/typescript/color/index.d.ts +3 -0
- package/lib/typescript/color/index.d.ts.map +1 -0
- package/lib/typescript/color/types.d.ts +13 -0
- package/lib/typescript/color/types.d.ts.map +1 -0
- package/lib/typescript/color-area/ColorAreaAccessibility.d.ts +8 -0
- package/lib/typescript/color-area/ColorAreaAccessibility.d.ts.map +1 -0
- package/lib/typescript/color-area/ColorAreaAccessibility.web.d.ts +8 -0
- package/lib/typescript/color-area/ColorAreaAccessibility.web.d.ts.map +1 -0
- package/lib/typescript/color-area/ColorAreaRoot.d.ts +7 -0
- package/lib/typescript/color-area/ColorAreaRoot.d.ts.map +1 -0
- package/lib/typescript/color-area/ColorAreaThumb.d.ts +6 -0
- package/lib/typescript/color-area/ColorAreaThumb.d.ts.map +1 -0
- package/lib/typescript/color-area/context.d.ts +6 -0
- package/lib/typescript/color-area/context.d.ts.map +1 -0
- package/lib/typescript/color-area/index.d.ts +5 -0
- package/lib/typescript/color-area/index.d.ts.map +1 -0
- package/lib/typescript/color-area/types.d.ts +65 -0
- package/lib/typescript/color-area/types.d.ts.map +1 -0
- package/lib/typescript/color-area/utils.d.ts +5 -0
- package/lib/typescript/color-area/utils.d.ts.map +1 -0
- package/lib/typescript/color-field/ColorFieldInput.d.ts +5 -0
- package/lib/typescript/color-field/ColorFieldInput.d.ts.map +1 -0
- package/lib/typescript/color-field/ColorFieldRoot.d.ts +7 -0
- package/lib/typescript/color-field/ColorFieldRoot.d.ts.map +1 -0
- package/lib/typescript/color-field/context.d.ts +6 -0
- package/lib/typescript/color-field/context.d.ts.map +1 -0
- package/lib/typescript/color-field/index.d.ts +7 -0
- package/lib/typescript/color-field/index.d.ts.map +1 -0
- package/lib/typescript/color-field/types.d.ts +39 -0
- package/lib/typescript/color-field/types.d.ts.map +1 -0
- package/lib/typescript/color-field/utils.d.ts +5 -0
- package/lib/typescript/color-field/utils.d.ts.map +1 -0
- package/lib/typescript/color-picker/ColorPickerRoot.d.ts +7 -0
- package/lib/typescript/color-picker/ColorPickerRoot.d.ts.map +1 -0
- package/lib/typescript/color-picker/ColorPickerTrigger.d.ts +4 -0
- package/lib/typescript/color-picker/ColorPickerTrigger.d.ts.map +1 -0
- package/lib/typescript/color-picker/context.d.ts +19 -0
- package/lib/typescript/color-picker/context.d.ts.map +1 -0
- package/lib/typescript/color-picker/index.d.ts +5 -0
- package/lib/typescript/color-picker/index.d.ts.map +1 -0
- package/lib/typescript/color-picker/types.d.ts +24 -0
- package/lib/typescript/color-picker/types.d.ts.map +1 -0
- package/lib/typescript/color-slider/ColorSliderRail.d.ts +6 -0
- package/lib/typescript/color-slider/ColorSliderRail.d.ts.map +1 -0
- package/lib/typescript/color-slider/ColorSliderRoot.d.ts +7 -0
- package/lib/typescript/color-slider/ColorSliderRoot.d.ts.map +1 -0
- package/lib/typescript/color-slider/ColorSliderThumb.d.ts +6 -0
- package/lib/typescript/color-slider/ColorSliderThumb.d.ts.map +1 -0
- package/lib/typescript/color-slider/context.d.ts +6 -0
- package/lib/typescript/color-slider/context.d.ts.map +1 -0
- package/lib/typescript/color-slider/index.d.ts +6 -0
- package/lib/typescript/color-slider/index.d.ts.map +1 -0
- package/lib/typescript/color-slider/types.d.ts +82 -0
- package/lib/typescript/color-slider/types.d.ts.map +1 -0
- package/lib/typescript/color-slider/utils.d.ts +12 -0
- package/lib/typescript/color-slider/utils.d.ts.map +1 -0
- package/lib/typescript/color-swatch-picker/ColorSwatchPickerItem.d.ts +6 -0
- package/lib/typescript/color-swatch-picker/ColorSwatchPickerItem.d.ts.map +1 -0
- package/lib/typescript/color-swatch-picker/ColorSwatchPickerRoot.d.ts +7 -0
- package/lib/typescript/color-swatch-picker/ColorSwatchPickerRoot.d.ts.map +1 -0
- package/lib/typescript/color-swatch-picker/context.d.ts +8 -0
- package/lib/typescript/color-swatch-picker/context.d.ts.map +1 -0
- package/lib/typescript/color-swatch-picker/index.d.ts +5 -0
- package/lib/typescript/color-swatch-picker/index.d.ts.map +1 -0
- package/lib/typescript/color-swatch-picker/types.d.ts +26 -0
- package/lib/typescript/color-swatch-picker/types.d.ts.map +1 -0
- package/lib/typescript/date-field/DateFieldRoot.d.ts.map +1 -1
- package/lib/typescript/date-field/DateFieldSegment.d.ts.map +1 -1
- package/lib/typescript/date-field/context.d.ts +2 -0
- package/lib/typescript/date-field/context.d.ts.map +1 -1
- package/lib/typescript/date-picker/DatePickerRoot.d.ts +29 -3
- package/lib/typescript/date-picker/DatePickerRoot.d.ts.map +1 -1
- package/lib/typescript/date-picker/context.d.ts +1 -0
- package/lib/typescript/date-picker/context.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +7 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/slider/useSliderPointer.d.ts.map +1 -1
- package/lib/typescript/utils/createPortal.web.d.ts +6 -2
- package/lib/typescript/utils/createPortal.web.d.ts.map +1 -1
- package/lib/typescript/utils/textAncestor.d.ts +13 -0
- package/lib/typescript/utils/textAncestor.d.ts.map +1 -0
- package/lib/typescript/utils/textAncestor.web.d.ts +15 -0
- package/lib/typescript/utils/textAncestor.web.d.ts.map +1 -0
- package/package.json +4 -3
- package/src/calendar/CalendarRoot.tsx +3 -0
- package/src/calendar/context.tsx +1 -0
- package/src/calendar/types.ts +7 -0
- package/src/color/Color.ts +95 -0
- package/src/color/index.ts +2 -0
- package/src/color/types.ts +19 -0
- package/src/color-area/ColorAreaAccessibility.tsx +94 -0
- package/src/color-area/ColorAreaAccessibility.web.tsx +52 -0
- package/src/color-area/ColorAreaRoot.tsx +326 -0
- package/src/color-area/ColorAreaThumb.tsx +56 -0
- package/src/color-area/context.tsx +5 -0
- package/src/color-area/index.ts +10 -0
- package/src/color-area/types.ts +69 -0
- package/src/color-area/utils.ts +51 -0
- package/src/color-field/ColorFieldInput.tsx +66 -0
- package/src/color-field/ColorFieldRoot.tsx +132 -0
- package/src/color-field/context.tsx +5 -0
- package/src/color-field/index.ts +11 -0
- package/src/color-field/types.ts +46 -0
- package/src/color-field/utils.ts +75 -0
- package/src/color-picker/ColorPickerRoot.tsx +91 -0
- package/src/color-picker/ColorPickerTrigger.tsx +96 -0
- package/src/color-picker/context.tsx +47 -0
- package/src/color-picker/index.ts +12 -0
- package/src/color-picker/types.ts +25 -0
- package/src/color-slider/ColorSliderRail.tsx +130 -0
- package/src/color-slider/ColorSliderRoot.tsx +222 -0
- package/src/color-slider/ColorSliderThumb.tsx +294 -0
- package/src/color-slider/context.tsx +5 -0
- package/src/color-slider/index.ts +16 -0
- package/src/color-slider/types.ts +94 -0
- package/src/color-slider/utils.ts +79 -0
- package/src/color-swatch-picker/ColorSwatchPickerItem.tsx +54 -0
- package/src/color-swatch-picker/ColorSwatchPickerRoot.tsx +94 -0
- package/src/color-swatch-picker/context.tsx +22 -0
- package/src/color-swatch-picker/index.ts +4 -0
- package/src/color-swatch-picker/types.ts +29 -0
- package/src/date-field/DateFieldRoot.tsx +4 -1
- package/src/date-field/DateFieldSegment.tsx +19 -3
- package/src/date-field/context.tsx +2 -0
- package/src/date-picker/DatePickerRoot.tsx +127 -18
- package/src/date-picker/context.tsx +1 -0
- package/src/index.ts +7 -0
- package/src/react-native-web.d.ts +6 -0
- package/src/slider/useSliderPointer.ts +3 -0
- package/src/utils/createPortal.web.ts +9 -3
- package/src/utils/textAncestor.ts +19 -0
- package/src/utils/textAncestor.web.ts +19 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { PressableProps, ViewProps } from 'react-native';
|
|
3
|
+
import type { Color } from '../color';
|
|
4
|
+
|
|
5
|
+
export type ColorSliderOrientation = 'horizontal' | 'vertical';
|
|
6
|
+
|
|
7
|
+
export type ColorSliderConfiguration =
|
|
8
|
+
| {
|
|
9
|
+
readonly colorSpace: 'rgb';
|
|
10
|
+
readonly channel: 'red' | 'green' | 'blue';
|
|
11
|
+
}
|
|
12
|
+
| {
|
|
13
|
+
readonly colorSpace: 'hsl';
|
|
14
|
+
readonly channel: 'hue' | 'saturation' | 'lightness';
|
|
15
|
+
}
|
|
16
|
+
| {
|
|
17
|
+
readonly colorSpace: 'hsb';
|
|
18
|
+
readonly channel: 'hue' | 'saturation' | 'brightness';
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export interface ColorSliderCommonProps extends Omit<ViewProps, 'children'> {
|
|
22
|
+
/** Current controlled color. */
|
|
23
|
+
readonly value?: Color;
|
|
24
|
+
/** Initial color for uncontrolled usage. */
|
|
25
|
+
readonly defaultValue?: Color;
|
|
26
|
+
/** Called while the selected channel changes. */
|
|
27
|
+
readonly onValueChange?: (value: Color) => void;
|
|
28
|
+
/** Called when a pointer, keyboard, or screen reader interaction completes. */
|
|
29
|
+
readonly onValueChangeComplete?: (value: Color) => void;
|
|
30
|
+
/** Slider axis. @default `'horizontal'` */
|
|
31
|
+
readonly orientation?: ColorSliderOrientation;
|
|
32
|
+
/** Channel increment. Defaults to the channel's natural increment. */
|
|
33
|
+
readonly step?: number;
|
|
34
|
+
/** Shift-arrow and page-key increment. @default `10` */
|
|
35
|
+
readonly pageStep?: number;
|
|
36
|
+
/** Disables pointer, keyboard, and screen reader interaction. @default `false` */
|
|
37
|
+
readonly isDisabled?: boolean;
|
|
38
|
+
readonly children?: ReactNode;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type IColorSliderProps = ColorSliderCommonProps & ColorSliderConfiguration;
|
|
42
|
+
|
|
43
|
+
export interface IColorSliderRailProps extends ViewProps {
|
|
44
|
+
readonly asChild?: boolean;
|
|
45
|
+
readonly children?: ReactNode;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface IColorSliderThumbProps extends PressableProps {
|
|
49
|
+
readonly asChild?: boolean;
|
|
50
|
+
readonly children?: ReactNode;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ColorSliderSize {
|
|
54
|
+
readonly width: number;
|
|
55
|
+
readonly height: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ColorSliderLayout extends ColorSliderSize {
|
|
59
|
+
readonly x: number;
|
|
60
|
+
readonly y: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type ColorSliderContextValue = ColorSliderConfiguration & {
|
|
64
|
+
readonly value: Color;
|
|
65
|
+
readonly channelValue: number;
|
|
66
|
+
readonly valueLabel: string;
|
|
67
|
+
readonly min: number;
|
|
68
|
+
readonly max: number;
|
|
69
|
+
readonly step: number;
|
|
70
|
+
readonly pageStep: number;
|
|
71
|
+
readonly percent: number;
|
|
72
|
+
readonly orientation: ColorSliderOrientation;
|
|
73
|
+
readonly isDisabled: boolean;
|
|
74
|
+
readonly isDragging: boolean;
|
|
75
|
+
readonly accessibilityLabel?: string;
|
|
76
|
+
readonly layout: ColorSliderLayout | null;
|
|
77
|
+
readonly thumbSize: ColorSliderSize;
|
|
78
|
+
readonly gradientColors: readonly string[];
|
|
79
|
+
readonly setLayout: (layout: ColorSliderLayout) => void;
|
|
80
|
+
readonly setThumbSize: (size: ColorSliderSize) => void;
|
|
81
|
+
readonly setIsDragging: (dragging: boolean) => void;
|
|
82
|
+
readonly setChannelValue: (value: number, complete?: boolean) => void;
|
|
83
|
+
readonly setValueFromRatio: (ratio: number, complete?: boolean) => void;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export interface ColorSliderKeyboardEvent {
|
|
87
|
+
readonly nativeEvent?: {
|
|
88
|
+
readonly key?: string;
|
|
89
|
+
readonly shiftKey?: boolean;
|
|
90
|
+
};
|
|
91
|
+
readonly key?: string;
|
|
92
|
+
readonly shiftKey?: boolean;
|
|
93
|
+
preventDefault?: () => void;
|
|
94
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Color } from '../color';
|
|
2
|
+
import type { ColorSliderConfiguration } from './types';
|
|
3
|
+
|
|
4
|
+
const HUE_STOPS = [0, 60, 120, 180, 240, 300, 360] as const;
|
|
5
|
+
|
|
6
|
+
export function clampColorSliderValue(value: number, min: number, max: number): number {
|
|
7
|
+
return Math.min(max, Math.max(min, value));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getColorSliderRange({ colorSpace, channel }: ColorSliderConfiguration): {
|
|
11
|
+
min: number;
|
|
12
|
+
max: number;
|
|
13
|
+
} {
|
|
14
|
+
if (colorSpace === 'rgb') {
|
|
15
|
+
return { min: 0, max: 255 };
|
|
16
|
+
}
|
|
17
|
+
if (channel === 'hue') {
|
|
18
|
+
return { min: 0, max: 360 };
|
|
19
|
+
}
|
|
20
|
+
return { min: 0, max: 100 };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getColorSliderChannelValue(
|
|
24
|
+
color: Color,
|
|
25
|
+
configuration: ColorSliderConfiguration,
|
|
26
|
+
): number {
|
|
27
|
+
if (configuration.colorSpace === 'rgb') {
|
|
28
|
+
return color.getChannel('rgb', configuration.channel);
|
|
29
|
+
}
|
|
30
|
+
if (configuration.colorSpace === 'hsl') {
|
|
31
|
+
return color.getChannel('hsl', configuration.channel);
|
|
32
|
+
}
|
|
33
|
+
return color.getChannel('hsb', configuration.channel);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function withColorSliderChannel(
|
|
37
|
+
color: Color,
|
|
38
|
+
configuration: ColorSliderConfiguration,
|
|
39
|
+
value: number,
|
|
40
|
+
): Color {
|
|
41
|
+
if (configuration.colorSpace === 'rgb') {
|
|
42
|
+
return color.withChannel('rgb', configuration.channel, value);
|
|
43
|
+
}
|
|
44
|
+
if (configuration.colorSpace === 'hsl') {
|
|
45
|
+
return color.withChannel('hsl', configuration.channel, value);
|
|
46
|
+
}
|
|
47
|
+
return color.withChannel('hsb', configuration.channel, value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function formatColorSliderValue(
|
|
51
|
+
value: number,
|
|
52
|
+
configuration: ColorSliderConfiguration,
|
|
53
|
+
): string {
|
|
54
|
+
const formatted = Number.isInteger(value) ? String(value) : value.toFixed(1);
|
|
55
|
+
if (configuration.channel === 'hue') {
|
|
56
|
+
return `${formatted}°`;
|
|
57
|
+
}
|
|
58
|
+
if (configuration.colorSpace !== 'rgb') {
|
|
59
|
+
return `${formatted}%`;
|
|
60
|
+
}
|
|
61
|
+
return formatted;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function getColorSliderGradientColors(
|
|
65
|
+
color: Color,
|
|
66
|
+
configuration: ColorSliderConfiguration,
|
|
67
|
+
): readonly string[] {
|
|
68
|
+
if (configuration.channel === 'hue') {
|
|
69
|
+
return HUE_STOPS.map((value) =>
|
|
70
|
+
withColorSliderChannel(color, configuration, value).toString('hex'),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const { min, max } = getColorSliderRange(configuration);
|
|
75
|
+
return [
|
|
76
|
+
withColorSliderChannel(color, configuration, min).toString('hex'),
|
|
77
|
+
withColorSliderChannel(color, configuration, max).toString('hex'),
|
|
78
|
+
];
|
|
79
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { forwardRef, useEffect, useMemo, type ComponentRef } from 'react';
|
|
2
|
+
import { Pressable } from 'react-native';
|
|
3
|
+
import { RadioRoot } from '../radio';
|
|
4
|
+
import { ColorSwatchPickerItemProvider, useColorSwatchPickerContext } from './context';
|
|
5
|
+
import type { IColorSwatchPickerItemProps } from './types';
|
|
6
|
+
|
|
7
|
+
export interface ColorSwatchPickerItemProps extends IColorSwatchPickerItemProps {
|
|
8
|
+
asChild?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ColorSwatchPickerItem = forwardRef<
|
|
12
|
+
ComponentRef<typeof Pressable>,
|
|
13
|
+
ColorSwatchPickerItemProps
|
|
14
|
+
>(
|
|
15
|
+
(
|
|
16
|
+
{
|
|
17
|
+
asChild,
|
|
18
|
+
color,
|
|
19
|
+
isDisabled,
|
|
20
|
+
disabled,
|
|
21
|
+
accessibilityLabel,
|
|
22
|
+
'aria-label': ariaLabelProp,
|
|
23
|
+
children,
|
|
24
|
+
...props
|
|
25
|
+
},
|
|
26
|
+
ref,
|
|
27
|
+
) => {
|
|
28
|
+
const { registerColor } = useColorSwatchPickerContext();
|
|
29
|
+
const colorValue = color.toString('hex');
|
|
30
|
+
const label = ariaLabelProp ?? accessibilityLabel ?? colorValue;
|
|
31
|
+
const contextValue = useMemo(() => ({ color }), [color]);
|
|
32
|
+
|
|
33
|
+
useEffect(() => registerColor(color), [color, registerColor]);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<ColorSwatchPickerItemProvider value={contextValue}>
|
|
37
|
+
<RadioRoot
|
|
38
|
+
ref={ref}
|
|
39
|
+
asChild={asChild}
|
|
40
|
+
value={colorValue}
|
|
41
|
+
isDisabled={!!(isDisabled || disabled)}
|
|
42
|
+
disabled={disabled}
|
|
43
|
+
aria-label={label}
|
|
44
|
+
accessibilityLabel={label}
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
{children}
|
|
48
|
+
</RadioRoot>
|
|
49
|
+
</ColorSwatchPickerItemProvider>
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
ColorSwatchPickerItem.displayName = 'ColorSwatchPickerItem';
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { forwardRef, useCallback, useMemo, useRef, type ComponentRef } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { useControllableState } from '@cdx-ui/utils';
|
|
4
|
+
import { RadioGroup } from '../radio';
|
|
5
|
+
import { useOptionalColorPickerContext } from '../color-picker';
|
|
6
|
+
import type { Color } from '../color';
|
|
7
|
+
import { ColorSwatchPickerProvider } from './context';
|
|
8
|
+
import type { IColorSwatchPickerProps } from './types';
|
|
9
|
+
|
|
10
|
+
export interface ColorSwatchPickerRootProps extends IColorSwatchPickerProps {
|
|
11
|
+
asChild?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const ColorSwatchPickerRoot = forwardRef<
|
|
15
|
+
ComponentRef<typeof View>,
|
|
16
|
+
ColorSwatchPickerRootProps
|
|
17
|
+
>(
|
|
18
|
+
(
|
|
19
|
+
{
|
|
20
|
+
asChild,
|
|
21
|
+
value: valueProp,
|
|
22
|
+
defaultValue,
|
|
23
|
+
onValueChange,
|
|
24
|
+
isDisabled,
|
|
25
|
+
accessibilityLabel,
|
|
26
|
+
children,
|
|
27
|
+
...props
|
|
28
|
+
},
|
|
29
|
+
ref,
|
|
30
|
+
) => {
|
|
31
|
+
const picker = useOptionalColorPickerContext();
|
|
32
|
+
const usesPickerContext =
|
|
33
|
+
picker !== null && valueProp === undefined && defaultValue === undefined;
|
|
34
|
+
|
|
35
|
+
const [localValue, setLocalValue] = useControllableState<Color>({
|
|
36
|
+
prop: valueProp,
|
|
37
|
+
defaultProp: defaultValue,
|
|
38
|
+
onChange: onValueChange,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const value = usesPickerContext ? picker.value : localValue;
|
|
42
|
+
const colorsRef = useRef(new Map<string, Color>());
|
|
43
|
+
|
|
44
|
+
const registerColor = useCallback((color: Color) => {
|
|
45
|
+
const key = color.toString('hex');
|
|
46
|
+
colorsRef.current.set(key, color);
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
if (colorsRef.current.get(key) === color) {
|
|
50
|
+
colorsRef.current.delete(key);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
const handleValueChange = useCallback(
|
|
56
|
+
(key: string) => {
|
|
57
|
+
const color = colorsRef.current.get(key);
|
|
58
|
+
|
|
59
|
+
if (!color) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (usesPickerContext) {
|
|
64
|
+
onValueChange?.(color);
|
|
65
|
+
picker.onValueChange(color);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setLocalValue(color);
|
|
70
|
+
},
|
|
71
|
+
[onValueChange, picker, setLocalValue, usesPickerContext],
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const contextValue = useMemo(() => ({ registerColor }), [registerColor]);
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<ColorSwatchPickerProvider value={contextValue}>
|
|
78
|
+
<RadioGroup
|
|
79
|
+
ref={ref}
|
|
80
|
+
asChild={asChild}
|
|
81
|
+
value={value?.toString('hex')}
|
|
82
|
+
onChange={handleValueChange}
|
|
83
|
+
isDisabled={isDisabled}
|
|
84
|
+
aria-label={props['aria-label'] ?? accessibilityLabel}
|
|
85
|
+
{...props}
|
|
86
|
+
>
|
|
87
|
+
{children}
|
|
88
|
+
</RadioGroup>
|
|
89
|
+
</ColorSwatchPickerProvider>
|
|
90
|
+
);
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
ColorSwatchPickerRoot.displayName = 'ColorSwatchPickerRoot';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createContext as createReactContext, useContext } from 'react';
|
|
2
|
+
import { createContext } from '@cdx-ui/utils';
|
|
3
|
+
import type { ColorSwatchPickerContextValue, ColorSwatchPickerItemContextValue } from './types';
|
|
4
|
+
|
|
5
|
+
export const [ColorSwatchPickerProvider, useColorSwatchPickerContext] =
|
|
6
|
+
createContext<ColorSwatchPickerContextValue>('ColorSwatchPickerContext');
|
|
7
|
+
|
|
8
|
+
const ColorSwatchPickerItemContext = createReactContext<ColorSwatchPickerItemContextValue | null>(
|
|
9
|
+
null,
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
export const ColorSwatchPickerItemProvider = ColorSwatchPickerItemContext.Provider;
|
|
13
|
+
|
|
14
|
+
export function useColorSwatchPickerItemContext(): ColorSwatchPickerItemContextValue {
|
|
15
|
+
const context = useContext(ColorSwatchPickerItemContext);
|
|
16
|
+
|
|
17
|
+
if (!context) {
|
|
18
|
+
throw new Error('ColorSwatchPicker item slots must be used within ColorSwatchPicker.Item');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return context;
|
|
22
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { ColorSwatchPickerRoot, type ColorSwatchPickerRootProps } from './ColorSwatchPickerRoot';
|
|
2
|
+
export { ColorSwatchPickerItem, type ColorSwatchPickerItemProps } from './ColorSwatchPickerItem';
|
|
3
|
+
export { useColorSwatchPickerContext, useColorSwatchPickerItemContext } from './context';
|
|
4
|
+
export type { IColorSwatchPickerItemProps, IColorSwatchPickerProps } from './types';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { PressableProps, ViewProps } from 'react-native';
|
|
3
|
+
import type { Color } from '../color';
|
|
4
|
+
|
|
5
|
+
export interface IColorSwatchPickerProps extends Omit<ViewProps, 'children'> {
|
|
6
|
+
value?: Color;
|
|
7
|
+
defaultValue?: Color;
|
|
8
|
+
onValueChange?: (value: Color) => void;
|
|
9
|
+
isDisabled?: boolean;
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface IColorSwatchPickerItemProps extends Omit<PressableProps, 'children'> {
|
|
14
|
+
color: Color;
|
|
15
|
+
isDisabled?: boolean;
|
|
16
|
+
isHovered?: boolean;
|
|
17
|
+
isActive?: boolean;
|
|
18
|
+
isFocused?: boolean;
|
|
19
|
+
isFocusVisible?: boolean;
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ColorSwatchPickerContextValue {
|
|
24
|
+
registerColor: (color: Color) => () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ColorSwatchPickerItemContextValue {
|
|
28
|
+
color: Color;
|
|
29
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { forwardRef, useMemo, type ComponentRef, type ReactNode } from 'react';
|
|
2
2
|
import { View, type ViewProps } from 'react-native';
|
|
3
3
|
import { getDateFieldSegments, resolveDateComponentLabels } from '@cdx-ui/formatters';
|
|
4
|
-
import { useControllableState, useFormControl } from '@cdx-ui/utils';
|
|
4
|
+
import { useControllableState, useFormControl, useFormControlContext } from '@cdx-ui/utils';
|
|
5
5
|
import { Slot } from '../slot';
|
|
6
6
|
import { dataAttributes, mergeDataAttributes } from '../utils/dataAttributes';
|
|
7
7
|
import { DateFieldContext, type DateFieldValue } from './context';
|
|
@@ -39,6 +39,7 @@ export const DateFieldRoot = forwardRef<ComponentRef<typeof View>, DateFieldRoot
|
|
|
39
39
|
isInvalid,
|
|
40
40
|
isRequired,
|
|
41
41
|
});
|
|
42
|
+
const { errorMessage } = useFormControlContext();
|
|
42
43
|
|
|
43
44
|
const [value, setValue] = useControllableState<DateFieldValue>({
|
|
44
45
|
prop: valueProp,
|
|
@@ -75,6 +76,7 @@ export const DateFieldRoot = forwardRef<ComponentRef<typeof View>, DateFieldRoot
|
|
|
75
76
|
disabled: !!formControl.disabled,
|
|
76
77
|
readOnly: !!formControl.readOnly,
|
|
77
78
|
invalid: !!formControl['aria-invalid'],
|
|
79
|
+
errorMessage,
|
|
78
80
|
...segmentState,
|
|
79
81
|
}),
|
|
80
82
|
[
|
|
@@ -87,6 +89,7 @@ export const DateFieldRoot = forwardRef<ComponentRef<typeof View>, DateFieldRoot
|
|
|
87
89
|
formControl.disabled,
|
|
88
90
|
formControl.readOnly,
|
|
89
91
|
formControl['aria-invalid'],
|
|
92
|
+
errorMessage,
|
|
90
93
|
segmentState,
|
|
91
94
|
],
|
|
92
95
|
);
|
|
@@ -23,8 +23,16 @@ export const DateFieldSegment = forwardRef<ComponentRef<typeof Text>, DateFieldS
|
|
|
23
23
|
({ asChild, segment, segmentIndex: segmentIndexProp, style, ...props }, ref) => {
|
|
24
24
|
const contextSegmentIndex = useDateFieldSegmentIndex();
|
|
25
25
|
const segmentIndex = segmentIndexProp ?? contextSegmentIndex;
|
|
26
|
-
const {
|
|
27
|
-
|
|
26
|
+
const {
|
|
27
|
+
disabled,
|
|
28
|
+
readOnly,
|
|
29
|
+
invalid,
|
|
30
|
+
errorMessage,
|
|
31
|
+
focusedSegmentIndex,
|
|
32
|
+
focusSegment,
|
|
33
|
+
getSegmentDisplayText,
|
|
34
|
+
labels,
|
|
35
|
+
} = useDateFieldContext();
|
|
28
36
|
const isFocused = focusedSegmentIndex === segmentIndex;
|
|
29
37
|
const displayText = getSegmentDisplayText(segmentIndex);
|
|
30
38
|
|
|
@@ -52,11 +60,19 @@ export const DateFieldSegment = forwardRef<ComponentRef<typeof Text>, DateFieldS
|
|
|
52
60
|
);
|
|
53
61
|
|
|
54
62
|
if (segment.isEditable && !asChild) {
|
|
63
|
+
// `aria-invalid` only reaches web screen readers; native ones need it in the name and hint.
|
|
64
|
+
const announceInvalid = invalid && Platform.OS !== 'web';
|
|
55
65
|
return (
|
|
56
66
|
<Pressable
|
|
57
67
|
accessibilityRole="spinbutton"
|
|
58
|
-
accessibilityLabel={getDateSegmentAccessibilityLabel(
|
|
68
|
+
accessibilityLabel={getDateSegmentAccessibilityLabel(
|
|
69
|
+
segment.type,
|
|
70
|
+
labels,
|
|
71
|
+
announceInvalid,
|
|
72
|
+
)}
|
|
73
|
+
accessibilityHint={announceInvalid ? errorMessage : undefined}
|
|
59
74
|
accessibilityState={{ disabled, selected: isFocused }}
|
|
75
|
+
aria-invalid={invalid || undefined}
|
|
60
76
|
disabled={disabled || readOnly}
|
|
61
77
|
onPress={handlePress}
|
|
62
78
|
onPressIn={preventWebFocusSteal}
|
|
@@ -20,6 +20,8 @@ export interface DateFieldContextValue {
|
|
|
20
20
|
disabled: boolean;
|
|
21
21
|
readOnly: boolean;
|
|
22
22
|
invalid: boolean;
|
|
23
|
+
/** Message the enclosing `Field` shows for the invalid state, if any. */
|
|
24
|
+
errorMessage?: string;
|
|
23
25
|
focusedSegmentIndex: number | null;
|
|
24
26
|
focusSegment: (index: number) => void;
|
|
25
27
|
blurSegment: (index: number) => void;
|
|
@@ -2,15 +2,28 @@ import {
|
|
|
2
2
|
forwardRef,
|
|
3
3
|
useCallback,
|
|
4
4
|
useEffect,
|
|
5
|
+
useLayoutEffect,
|
|
5
6
|
useMemo,
|
|
6
7
|
useRef,
|
|
7
8
|
type ComponentRef,
|
|
8
9
|
type ReactNode,
|
|
9
10
|
} from 'react';
|
|
10
11
|
import { View, type ViewProps } from 'react-native';
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
import {
|
|
13
|
+
formatDateValidationMessage,
|
|
14
|
+
getDateValidationReason,
|
|
15
|
+
resolveDateComponentLabels,
|
|
16
|
+
type DateComponentLabels,
|
|
17
|
+
type DateId,
|
|
18
|
+
type DateValidationReason,
|
|
19
|
+
} from '@cdx-ui/formatters';
|
|
20
|
+
import {
|
|
21
|
+
FormControlContext,
|
|
22
|
+
mergeRefs,
|
|
23
|
+
useControllableState,
|
|
24
|
+
useFormControlContext,
|
|
25
|
+
useReportFormControlValidation,
|
|
26
|
+
} from '@cdx-ui/utils';
|
|
14
27
|
import { DateFieldRoot } from '../date-field/DateFieldRoot';
|
|
15
28
|
import { Slot } from '../slot';
|
|
16
29
|
import { dataAttributes, mergeDataAttributes } from '../utils/dataAttributes';
|
|
@@ -29,12 +42,41 @@ export interface DatePickerRootProps extends Omit<ViewProps, 'children'> {
|
|
|
29
42
|
onOpenChange?: (open: boolean) => void;
|
|
30
43
|
isDisabled?: boolean;
|
|
31
44
|
isReadOnly?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Forces the invalid state. OR-ed with the picker's own validation: setting `true` marks the
|
|
47
|
+
* field invalid, but `false` never hides a `minValue` / `maxValue` / `isDateUnavailable` violation.
|
|
48
|
+
*/
|
|
32
49
|
isInvalid?: boolean;
|
|
33
50
|
isRequired?: boolean;
|
|
34
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Earliest selectable date, applied to the embedded calendar and to typed entry. Build with
|
|
53
|
+
* `dateId(...)`.
|
|
54
|
+
*/
|
|
35
55
|
minValue?: DateId;
|
|
36
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Latest selectable date, applied to the embedded calendar and to typed entry. Build with
|
|
58
|
+
* `dateId(...)`.
|
|
59
|
+
*/
|
|
37
60
|
maxValue?: DateId;
|
|
61
|
+
/**
|
|
62
|
+
* Returns `true` for dates that cannot be selected, such as weekends or holidays. The calendar
|
|
63
|
+
* renders them disabled; a typed unavailable date is kept and emitted but renders invalid. Pass
|
|
64
|
+
* a stable (memoized) function.
|
|
65
|
+
*/
|
|
66
|
+
isDateUnavailable?: (date: DateId) => boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Called when the committed value starts or stops violating `minValue`, `maxValue`, or
|
|
69
|
+
* `isDateUnavailable`, and again when the formatted message changes while the reason stays
|
|
70
|
+
* the same — a new bound, `locale`, or `labels` while the value is still `beforeMin`, for
|
|
71
|
+
* example. Receives the reason and its `labels` message formatted in `locale`, or `undefined`
|
|
72
|
+
* for both once the value is valid or cleared. Fires before paint, so state set here renders
|
|
73
|
+
* in the same frame as the invalid styling. Not needed to show the message: an empty
|
|
74
|
+
* `Field.Error` anywhere in the enclosing `Field` already renders it.
|
|
75
|
+
*/
|
|
76
|
+
onValidationChange?: (
|
|
77
|
+
reason: DateValidationReason | undefined,
|
|
78
|
+
message: string | undefined,
|
|
79
|
+
) => void;
|
|
38
80
|
name?: string;
|
|
39
81
|
locale?: string;
|
|
40
82
|
labels?: Partial<DateComponentLabels>;
|
|
@@ -57,6 +99,8 @@ export const DatePickerRoot = forwardRef<ComponentRef<typeof View>, DatePickerRo
|
|
|
57
99
|
isRequired,
|
|
58
100
|
minValue,
|
|
59
101
|
maxValue,
|
|
102
|
+
isDateUnavailable,
|
|
103
|
+
onValidationChange,
|
|
60
104
|
locale = 'en-US',
|
|
61
105
|
labels: labelsProp,
|
|
62
106
|
...props
|
|
@@ -83,6 +127,59 @@ export const DatePickerRoot = forwardRef<ComponentRef<typeof View>, DatePickerRo
|
|
|
83
127
|
defaultProp: value,
|
|
84
128
|
});
|
|
85
129
|
|
|
130
|
+
const validationReason = useMemo(
|
|
131
|
+
() =>
|
|
132
|
+
value === undefined
|
|
133
|
+
? undefined
|
|
134
|
+
: getDateValidationReason(value, { minValue, maxValue, isDateUnavailable }),
|
|
135
|
+
[isDateUnavailable, maxValue, minValue, value],
|
|
136
|
+
);
|
|
137
|
+
const resolvedInvalid = !!isInvalid || validationReason !== undefined;
|
|
138
|
+
const validationMessage = useMemo(
|
|
139
|
+
() =>
|
|
140
|
+
validationReason === undefined
|
|
141
|
+
? undefined
|
|
142
|
+
: formatDateValidationMessage(
|
|
143
|
+
labels,
|
|
144
|
+
validationReason,
|
|
145
|
+
{ minValue, maxValue },
|
|
146
|
+
{ locale },
|
|
147
|
+
),
|
|
148
|
+
[labels, locale, maxValue, minValue, validationReason],
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const onValidationChangeRef = useRef(onValidationChange);
|
|
152
|
+
onValidationChangeRef.current = onValidationChange;
|
|
153
|
+
const reportedValidationRef = useRef<{
|
|
154
|
+
reason: DateValidationReason | undefined;
|
|
155
|
+
message: string | undefined;
|
|
156
|
+
}>({ reason: undefined, message: undefined });
|
|
157
|
+
useLayoutEffect(() => {
|
|
158
|
+
const reported = reportedValidationRef.current;
|
|
159
|
+
if (reported.reason === validationReason && reported.message === validationMessage) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
reportedValidationRef.current = { reason: validationReason, message: validationMessage };
|
|
163
|
+
onValidationChangeRef.current?.(validationReason, validationMessage);
|
|
164
|
+
}, [validationMessage, validationReason]);
|
|
165
|
+
|
|
166
|
+
const reportsToField = useReportFormControlValidation(resolvedInvalid, validationMessage);
|
|
167
|
+
|
|
168
|
+
// Without an enclosing `Field` there is nothing to report to, so provide the picker's
|
|
169
|
+
// validation to its own children (`Field.Error`, `Field.Helper`, the input group).
|
|
170
|
+
const parentFormControl = useFormControlContext();
|
|
171
|
+
const standaloneFormControl = useMemo(
|
|
172
|
+
() =>
|
|
173
|
+
reportsToField
|
|
174
|
+
? undefined
|
|
175
|
+
: {
|
|
176
|
+
...parentFormControl,
|
|
177
|
+
isInvalid: !!parentFormControl.isInvalid || resolvedInvalid,
|
|
178
|
+
errorMessage: validationMessage,
|
|
179
|
+
},
|
|
180
|
+
[parentFormControl, reportsToField, resolvedInvalid, validationMessage],
|
|
181
|
+
);
|
|
182
|
+
|
|
86
183
|
const surfacesRef = useRef<Set<PickerSurfaceType>>(new Set());
|
|
87
184
|
const anchorRef = useRef<ComponentRef<typeof View>>(null);
|
|
88
185
|
const triggerRef = useRef<ComponentRef<typeof View>>(null);
|
|
@@ -133,6 +230,7 @@ export const DatePickerRoot = forwardRef<ComponentRef<typeof View>, DatePickerRo
|
|
|
133
230
|
disabled,
|
|
134
231
|
minValue,
|
|
135
232
|
maxValue,
|
|
233
|
+
isDateUnavailable,
|
|
136
234
|
locale,
|
|
137
235
|
labels,
|
|
138
236
|
registerSurface,
|
|
@@ -149,6 +247,7 @@ export const DatePickerRoot = forwardRef<ComponentRef<typeof View>, DatePickerRo
|
|
|
149
247
|
disabled,
|
|
150
248
|
minValue,
|
|
151
249
|
maxValue,
|
|
250
|
+
isDateUnavailable,
|
|
152
251
|
locale,
|
|
153
252
|
labels,
|
|
154
253
|
registerSurface,
|
|
@@ -157,6 +256,22 @@ export const DatePickerRoot = forwardRef<ComponentRef<typeof View>, DatePickerRo
|
|
|
157
256
|
|
|
158
257
|
const Comp = asChild ? Slot : View;
|
|
159
258
|
|
|
259
|
+
const field = (
|
|
260
|
+
<DateFieldRoot
|
|
261
|
+
value={value}
|
|
262
|
+
onValueChange={(next) => setValue(next as DateId | undefined)}
|
|
263
|
+
mode="date"
|
|
264
|
+
locale={locale}
|
|
265
|
+
labels={labelsProp}
|
|
266
|
+
isDisabled={disabled}
|
|
267
|
+
isReadOnly={isReadOnly}
|
|
268
|
+
isInvalid={resolvedInvalid}
|
|
269
|
+
isRequired={isRequired}
|
|
270
|
+
>
|
|
271
|
+
{children}
|
|
272
|
+
</DateFieldRoot>
|
|
273
|
+
);
|
|
274
|
+
|
|
160
275
|
return (
|
|
161
276
|
<DatePickerContext.Provider value={contextValue}>
|
|
162
277
|
<Comp
|
|
@@ -164,19 +279,13 @@ export const DatePickerRoot = forwardRef<ComponentRef<typeof View>, DatePickerRo
|
|
|
164
279
|
{...props}
|
|
165
280
|
{...mergeDataAttributes(props, dataAttributes({ disabled, open }))}
|
|
166
281
|
>
|
|
167
|
-
|
|
168
|
-
value={
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
isReadOnly={isReadOnly}
|
|
175
|
-
isInvalid={isInvalid}
|
|
176
|
-
isRequired={isRequired}
|
|
177
|
-
>
|
|
178
|
-
{children}
|
|
179
|
-
</DateFieldRoot>
|
|
282
|
+
{standaloneFormControl ? (
|
|
283
|
+
<FormControlContext.Provider value={standaloneFormControl}>
|
|
284
|
+
{field}
|
|
285
|
+
</FormControlContext.Provider>
|
|
286
|
+
) : (
|
|
287
|
+
field
|
|
288
|
+
)}
|
|
180
289
|
</Comp>
|
|
181
290
|
</DatePickerContext.Provider>
|
|
182
291
|
);
|
|
@@ -14,6 +14,7 @@ export interface DatePickerContextValue {
|
|
|
14
14
|
disabled: boolean;
|
|
15
15
|
minValue?: DateId;
|
|
16
16
|
maxValue?: DateId;
|
|
17
|
+
isDateUnavailable?: (date: DateId) => boolean;
|
|
17
18
|
locale: string;
|
|
18
19
|
labels: DateComponentLabels;
|
|
19
20
|
registerSurface: (type: PickerSurfaceType) => void;
|