@ctrl-ui/react 0.8.20 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +1 -0
  2. package/dist/action-bar.d.ts +1 -2
  3. package/dist/action-bar.js +7 -8
  4. package/dist/blocks/design-canvas-inspector.js +4 -1
  5. package/dist/blocks/file-explorer.js +1 -1
  6. package/dist/chat-message.js +4 -13
  7. package/dist/hooks/use-textarea-trigger-menu.d.ts +21 -3
  8. package/dist/hooks/use-textarea-trigger-menu.js +36 -40
  9. package/dist/hooks/use-user-ask.d.ts +1 -0
  10. package/dist/hooks/use-user-ask.js +5 -1
  11. package/dist/knob-contracts/audio-recorder-knobs.d.ts +1 -1
  12. package/dist/knob-contracts/audio-recorder-knobs.js +2 -1
  13. package/dist/knob-contracts/chart-knobs.d.ts +4 -0
  14. package/dist/knob-contracts/chart-knobs.js +24 -0
  15. package/dist/knob-contracts/choice-knobs.d.ts +1 -1
  16. package/dist/knob-contracts/choice-knobs.js +1 -0
  17. package/dist/knob-contracts/dockable-panel-knobs.d.ts +1 -1
  18. package/dist/knob-contracts/dockable-panel-knobs.js +2 -1
  19. package/dist/knob-contracts/emoji-picker-knobs.d.ts +1 -1
  20. package/dist/knob-contracts/emoji-picker-knobs.js +1 -0
  21. package/dist/knob-contracts/empty-knobs.d.ts +1 -1
  22. package/dist/knob-contracts/empty-knobs.js +2 -1
  23. package/dist/knob-contracts/icon-picker-knobs.d.ts +1 -1
  24. package/dist/knob-contracts/icon-picker-knobs.js +3 -1
  25. package/dist/knob-contracts/resizable-knobs.d.ts +1 -1
  26. package/dist/knob-contracts/resizable-knobs.js +2 -2
  27. package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
  28. package/dist/knob-contracts/sidebar-knobs.js +3 -1
  29. package/dist/knob-contracts/tabs-knobs.d.ts +1 -1
  30. package/dist/knob-contracts/tabs-knobs.js +2 -1
  31. package/dist/knob-contracts/tree-knobs.d.ts +1 -1
  32. package/dist/knob-contracts/tree-knobs.js +2 -1
  33. package/dist/lib/color.d.ts +2 -6
  34. package/dist/lib/color.js +45 -28
  35. package/dist/lib/contrast.d.ts +6 -0
  36. package/dist/lib/contrast.js +33 -1
  37. package/dist/lib/gradient.d.ts +17 -0
  38. package/dist/lib/gradient.js +69 -0
  39. package/dist/markdown-editor/drag-handle.js +73 -10
  40. package/dist/markdown-editor/drag-preview.d.ts +3 -0
  41. package/dist/markdown-editor/drag-preview.js +31 -0
  42. package/dist/markdown-editor/extensions.d.ts +2 -2
  43. package/dist/markdown-editor/extensions.js +25 -3
  44. package/dist/markdown-editor/suggestions.js +5 -5
  45. package/dist/markdown-editor/task-item.d.ts +3 -0
  46. package/dist/markdown-editor/task-item.js +50 -0
  47. package/dist/markdown-editor/toolbar.js +122 -63
  48. package/dist/markdown-editor.js +3 -3
  49. package/dist/skin.d.ts +0 -1
  50. package/dist/styles/index.css +3 -2
  51. package/dist/styles/recipes/action-bar.css +1 -1
  52. package/dist/styles/recipes/activity.css +1 -1
  53. package/dist/styles/recipes/alert.css +9 -10
  54. package/dist/styles/recipes/app-shell-header.css +2 -2
  55. package/dist/styles/recipes/audio-recorder.css +15 -4
  56. package/dist/styles/recipes/audio-visualizer.css +4 -4
  57. package/dist/styles/recipes/avatar.css +3 -3
  58. package/dist/styles/recipes/badge.css +2 -2
  59. package/dist/styles/recipes/button.css +2 -5
  60. package/dist/styles/recipes/card.css +0 -2
  61. package/dist/styles/recipes/chart.css +378 -0
  62. package/dist/styles/recipes/chat-composer-attachment.css +3 -3
  63. package/dist/styles/recipes/chat-composer.css +3 -3
  64. package/dist/styles/recipes/chat-layout.css +2 -2
  65. package/dist/styles/recipes/chat-message-social.css +1 -1
  66. package/dist/styles/recipes/chat-message.css +1 -1
  67. package/dist/styles/recipes/choice.css +9 -3
  68. package/dist/styles/recipes/code-diff.css +1 -1
  69. package/dist/styles/recipes/code.css +1 -1
  70. package/dist/styles/recipes/color-picker-details.css +17 -11
  71. package/dist/styles/recipes/color-picker-values.css +17 -7
  72. package/dist/styles/recipes/color-picker.css +88 -70
  73. package/dist/styles/recipes/context.css +2 -2
  74. package/dist/styles/recipes/dockable-panel.css +9 -2
  75. package/dist/styles/recipes/dynamic-notification-motion.css +1 -55
  76. package/dist/styles/recipes/dynamic-notification.css +0 -1
  77. package/dist/styles/recipes/emoji-picker.css +35 -19
  78. package/dist/styles/recipes/empty.css +19 -14
  79. package/dist/styles/recipes/field-parts.css +2 -2
  80. package/dist/styles/recipes/field.css +6 -4
  81. package/dist/styles/recipes/filter-bar.css +10 -10
  82. package/dist/styles/recipes/flow.css +5 -3
  83. package/dist/styles/recipes/gradient-editor.css +8 -0
  84. package/dist/styles/recipes/icon-picker.css +45 -10
  85. package/dist/styles/recipes/inline-attachment.css +4 -4
  86. package/dist/styles/recipes/inline-citation.css +2 -2
  87. package/dist/styles/recipes/item.css +4 -4
  88. package/dist/styles/recipes/markdown-editor.css +35 -24
  89. package/dist/styles/recipes/markdown.css +23 -27
  90. package/dist/styles/recipes/page-layout.css +13 -11
  91. package/dist/styles/recipes/popup-controls.css +2 -2
  92. package/dist/styles/recipes/popup-lists.css +3 -3
  93. package/dist/styles/recipes/popup.css +11 -9
  94. package/dist/styles/recipes/range.css +4 -5
  95. package/dist/styles/recipes/resizable.css +15 -10
  96. package/dist/styles/recipes/resize-handle.css +2 -2
  97. package/dist/styles/recipes/scroll-area.css +1 -1
  98. package/dist/styles/recipes/sidebar-menu.css +5 -15
  99. package/dist/styles/recipes/sidebar-mobile.css +4 -4
  100. package/dist/styles/recipes/sidebar-parts.css +26 -1
  101. package/dist/styles/recipes/sidebar.css +18 -31
  102. package/dist/styles/recipes/skeleton.css +10 -5
  103. package/dist/styles/recipes/stepper.css +1 -1
  104. package/dist/styles/recipes/switch.css +12 -11
  105. package/dist/styles/recipes/table-of-contents.css +6 -8
  106. package/dist/styles/recipes/table.css +4 -4
  107. package/dist/styles/recipes/tabs.css +10 -5
  108. package/dist/styles/recipes/task-list.css +3 -3
  109. package/dist/styles/recipes/tree.css +10 -3
  110. package/dist/styles/recipes/user-ask-details.css +5 -4
  111. package/dist/styles/recipes/user-ask.css +5 -5
  112. package/dist/styles/theme.css +158 -177
  113. package/dist/ui/chart-cartesian.d.ts +801 -0
  114. package/dist/ui/chart-cartesian.js +420 -0
  115. package/dist/ui/chart-colors.d.ts +7 -0
  116. package/dist/ui/chart-colors.js +27 -0
  117. package/dist/ui/chart-curves.d.ts +7 -0
  118. package/dist/ui/chart-curves.js +87 -0
  119. package/dist/ui/chart-marks.d.ts +68 -0
  120. package/dist/ui/chart-marks.js +227 -0
  121. package/dist/ui/chart-polar.d.ts +103 -0
  122. package/dist/ui/chart-polar.js +124 -0
  123. package/dist/ui/chart-series.d.ts +36 -0
  124. package/dist/ui/chart-series.js +71 -0
  125. package/dist/ui/chart.d.ts +32 -0
  126. package/dist/ui/chart.js +257 -0
  127. package/dist/ui/color-picker-area.d.ts +16 -0
  128. package/dist/ui/color-picker-area.js +175 -0
  129. package/dist/ui/color-picker-context.d.ts +27 -0
  130. package/dist/ui/color-picker-context.js +87 -0
  131. package/dist/ui/color-picker-contrast.d.ts +20 -0
  132. package/dist/ui/color-picker-contrast.js +129 -0
  133. package/dist/ui/color-picker-sliders.d.ts +15 -0
  134. package/dist/ui/color-picker-sliders.js +146 -0
  135. package/dist/ui/color-picker-swatches.d.ts +23 -0
  136. package/dist/ui/color-picker-swatches.js +94 -0
  137. package/dist/ui/color-picker-values.d.ts +59 -0
  138. package/dist/ui/color-picker-values.js +244 -0
  139. package/dist/ui/color-picker.d.ts +15 -110
  140. package/dist/ui/color-picker.js +30 -759
  141. package/dist/ui/emoji-picker.d.ts +10 -1
  142. package/dist/ui/emoji-picker.js +71 -14
  143. package/dist/ui/flow.js +1 -1
  144. package/dist/ui/gradient-editor-controls.d.ts +19 -0
  145. package/dist/ui/gradient-editor-controls.js +75 -0
  146. package/dist/ui/gradient-editor.d.ts +23 -22
  147. package/dist/ui/gradient-editor.js +77 -123
  148. package/dist/ui/icon-picker.d.ts +1 -1
  149. package/dist/ui/icon-picker.js +11 -6
  150. package/dist/ui/markdown-elements.d.ts +3 -1
  151. package/dist/ui/markdown-elements.js +62 -22
  152. package/dist/ui/markdown-heading.d.ts +9 -0
  153. package/dist/ui/markdown-heading.js +25 -0
  154. package/dist/ui/resizable.js +24 -9
  155. package/dist/ui/sidebar-provider.js +3 -12
  156. package/dist/ui/typography.d.ts +1 -0
  157. package/dist/ui/typography.js +12 -3
  158. package/dist/user-ask.js +4 -8
  159. package/package.json +7 -3
  160. package/dist/ui/emoji-icon-picker.d.ts +0 -13
  161. package/dist/ui/emoji-icon-picker.js +0 -50
@@ -0,0 +1,129 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { formatColor, hsvaToRgba, parseColor } from "../lib/color.js";
4
+ import { useColorPicker } from "./color-picker-context.js";
5
+ import { TARGET_RATIO, contrastFailBands, contrastOf, fixColorForContrast, formatContrastRatio, nextFixLevel, wcagLevels } from "../lib/contrast.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/ui/color-picker-contrast.tsx
8
+ function ColorPickerContrast({ background = "#ffffff", passLabel = "Passes", failLabel = "Fails", className, ...props }) {
9
+ const { hsva, setFromString, disabled } = useColorPicker();
10
+ const bg = parseColor(background);
11
+ if (!bg) return null;
12
+ const bgRgba = hsvaToRgba(bg);
13
+ const ratio = contrastOf(hsva, bgRgba);
14
+ const levels = wcagLevels(ratio);
15
+ const target = nextFixLevel(levels);
16
+ const applyFix = () => {
17
+ if (!target) return;
18
+ const fixed = fixColorForContrast(hsva, bgRgba, TARGET_RATIO[target]);
19
+ if (fixed) setFromString(formatColor(fixed, "hex"));
20
+ };
21
+ return /* @__PURE__ */ jsxs("div", {
22
+ "data-control-ui": "color-picker",
23
+ "data-control-family": "color-picker",
24
+ "data-slot": "contrast",
25
+ className: cn("flex items-center", className),
26
+ ...props,
27
+ children: [
28
+ /* @__PURE__ */ jsxs("span", {
29
+ "data-control-ui": "color-picker",
30
+ "data-control-family": "color-picker",
31
+ "data-slot": "contrast-ratio",
32
+ children: [formatContrastRatio(ratio), ":1"]
33
+ }),
34
+ /* @__PURE__ */ jsx(WcagPill, {
35
+ ok: levels.AA,
36
+ passLabel,
37
+ failLabel,
38
+ children: "AA"
39
+ }),
40
+ /* @__PURE__ */ jsx(WcagPill, {
41
+ ok: levels.AAA,
42
+ passLabel,
43
+ failLabel,
44
+ children: "AAA"
45
+ }),
46
+ target ? /* @__PURE__ */ jsxs("button", {
47
+ type: "button",
48
+ "data-control-ui": "color-picker",
49
+ "data-control-family": "color-picker",
50
+ "data-slot": "contrast-fix",
51
+ disabled,
52
+ onClick: applyFix,
53
+ className: "ms-auto cursor-pointer disabled:cursor-not-allowed",
54
+ children: ["Fix for ", target]
55
+ }) : null
56
+ ]
57
+ });
58
+ }
59
+ function WcagPill({ ok, passLabel, failLabel, children }) {
60
+ return /* @__PURE__ */ jsxs("span", {
61
+ "data-control-ui": "color-picker",
62
+ "data-control-family": "color-picker",
63
+ "data-slot": "contrast-level",
64
+ "data-passing": ok ? "true" : void 0,
65
+ className: "inline-flex items-center",
66
+ children: [
67
+ /* @__PURE__ */ jsx("span", {
68
+ "aria-hidden": "true",
69
+ children: ok ? "✓" : "✕"
70
+ }),
71
+ /* @__PURE__ */ jsx("span", {
72
+ className: "sr-only",
73
+ children: ok ? passLabel : failLabel
74
+ }),
75
+ " ",
76
+ children
77
+ ]
78
+ });
79
+ }
80
+ const AREA_EDGE_MARGIN = .5;
81
+ const isInsideArea = (brightness) => brightness > AREA_EDGE_MARGIN && brightness < 99.5;
82
+ function failRegionClipPath(bands) {
83
+ const brightEdge = bands.map((band) => `${band.saturation}% ${100 - band.failsTo}%`);
84
+ const darkEdge = bands.toReversed().map((band) => `${band.saturation}% ${100 - band.failsFrom}%`);
85
+ return `polygon(${[...brightEdge, ...darkEdge].join(", ")})`;
86
+ }
87
+ function thresholdPath(bands, edge) {
88
+ return bands.flatMap((band, column) => {
89
+ const next = bands[column + 1];
90
+ if (!next || !(isInsideArea(band[edge]) || isInsideArea(next[edge]))) return [];
91
+ return [`M${band.saturation} ${100 - band[edge]}L${next.saturation} ${100 - next[edge]}`];
92
+ }).join("");
93
+ }
94
+ function ColorPickerAreaContrast({ background = "#ffffff", level = "AA", className, ...props }) {
95
+ const { hsva } = useColorPicker();
96
+ const bg = parseColor(background);
97
+ if (!bg) return null;
98
+ const bands = contrastFailBands(hsva, hsvaToRgba(bg), TARGET_RATIO[level]);
99
+ return /* @__PURE__ */ jsxs("span", {
100
+ "data-control-ui": "color-picker",
101
+ "data-control-family": "color-picker",
102
+ "data-slot": "area-contrast",
103
+ "aria-hidden": true,
104
+ className: cn("pointer-events-none absolute inset-0", className),
105
+ ...props,
106
+ children: [/* @__PURE__ */ jsx("span", {
107
+ "data-control-ui": "color-picker",
108
+ "data-control-family": "color-picker",
109
+ "data-slot": "area-contrast-fail",
110
+ className: "absolute inset-0",
111
+ style: { clipPath: failRegionClipPath(bands) }
112
+ }), /* @__PURE__ */ jsx("svg", {
113
+ "data-control-ui": "color-picker",
114
+ "data-control-family": "color-picker",
115
+ "data-slot": "area-contrast-threshold",
116
+ "aria-hidden": "true",
117
+ viewBox: "0 0 100 100",
118
+ preserveAspectRatio: "none",
119
+ fill: "none",
120
+ className: "absolute inset-0 size-full",
121
+ children: /* @__PURE__ */ jsx("path", {
122
+ d: thresholdPath(bands, "failsFrom") + thresholdPath(bands, "failsTo"),
123
+ vectorEffect: "non-scaling-stroke"
124
+ })
125
+ })]
126
+ });
127
+ }
128
+ //#endregion
129
+ export { ColorPickerAreaContrast, ColorPickerContrast };
@@ -0,0 +1,15 @@
1
+ import { ColorPickerKnobStyle } from "../knob-contracts/color-picker-knobs.js";
2
+ import { CSSProperties, ComponentProps } from "react";
3
+ //#region src/ui/color-picker-sliders.d.ts
4
+ export type ColorPickerSliderProps = Pick<ComponentProps<"div">, "className" | "aria-label" | "aria-labelledby"> & {
5
+ style?: CSSProperties & ColorPickerKnobStyle;
6
+ };
7
+ export type ColorPickerHueProps = ColorPickerSliderProps;
8
+ export type ColorPickerSaturationProps = ColorPickerSliderProps;
9
+ export type ColorPickerBrightnessProps = ColorPickerSliderProps;
10
+ export type ColorPickerAlphaProps = ColorPickerSliderProps;
11
+ export declare function ColorPickerHue(props: ColorPickerHueProps): import("react").JSX.Element;
12
+ export declare function ColorPickerSaturation(props: ColorPickerSaturationProps): import("react").JSX.Element;
13
+ export declare function ColorPickerBrightness(props: ColorPickerBrightnessProps): import("react").JSX.Element;
14
+ export declare function ColorPickerAlpha(props: ColorPickerAlphaProps): import("react").JSX.Element | null;
15
+ //#endregion
@@ -0,0 +1,146 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { formatColor } from "../lib/color.js";
4
+ import { useColorPicker } from "./color-picker-context.js";
5
+ import { jsx } from "react/jsx-runtime";
6
+ import { Slider } from "@base-ui/react/slider";
7
+ //#region src/ui/color-picker-sliders.tsx
8
+ const THUMB_HALF_SIZE = "calc(var(--_color-picker-thumb-size) / 2)";
9
+ const HUE_TRACK_STOPS = [
10
+ "hsl(0 100% 50%)",
11
+ "hsl(60 100% 50%)",
12
+ "hsl(120 100% 50%)",
13
+ "hsl(180 100% 50%)",
14
+ "hsl(240 100% 50%)",
15
+ "hsl(300 100% 50%)",
16
+ "hsl(360 100% 50%)"
17
+ ];
18
+ const opaqueHex = (hsva) => formatColor({
19
+ ...hsva,
20
+ a: 1
21
+ }, "hex");
22
+ const SLIDER_AXES = {
23
+ h: {
24
+ label: "Hue",
25
+ max: 360,
26
+ step: 1,
27
+ format: {
28
+ style: "unit",
29
+ unit: "degree"
30
+ },
31
+ trackStops: () => HUE_TRACK_STOPS
32
+ },
33
+ s: {
34
+ label: "Saturation",
35
+ max: 100,
36
+ step: 1,
37
+ format: {
38
+ style: "unit",
39
+ unit: "percent"
40
+ },
41
+ trackStops: (hsva) => [opaqueHex({
42
+ ...hsva,
43
+ s: 0
44
+ }), opaqueHex({
45
+ ...hsva,
46
+ s: 100
47
+ })]
48
+ },
49
+ v: {
50
+ label: "Brightness",
51
+ max: 100,
52
+ step: 1,
53
+ format: {
54
+ style: "unit",
55
+ unit: "percent"
56
+ },
57
+ trackStops: (hsva) => [opaqueHex({
58
+ ...hsva,
59
+ v: 0
60
+ }), opaqueHex({
61
+ ...hsva,
62
+ v: 100
63
+ })]
64
+ },
65
+ a: {
66
+ label: "Opacity",
67
+ max: 1,
68
+ step: .01,
69
+ format: { style: "percent" },
70
+ trackStops: (hsva) => ["transparent", opaqueHex(hsva)]
71
+ }
72
+ };
73
+ function edgeAlignedTrackStyle(stops) {
74
+ const lastIndex = stops.length - 1;
75
+ return { "--_color-picker-slider-track-image": `linear-gradient(to right, ${stops.map((stop, index) => {
76
+ if (index === 0) return `${stop} ${THUMB_HALF_SIZE}`;
77
+ if (index === lastIndex) return `${stop} calc(100% - ${THUMB_HALF_SIZE})`;
78
+ return stop;
79
+ }).join(", ")})` };
80
+ }
81
+ function ColorPickerSlider({ axis, className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }) {
82
+ const { hsva, setHsva, disabled } = useColorPicker();
83
+ const { label, max, step, format, trackStops } = SLIDER_AXES[axis];
84
+ return /* @__PURE__ */ jsx(Slider.Root, {
85
+ "data-control-ui": "color-picker",
86
+ "data-control-family": "color-picker",
87
+ "data-slot": "slider",
88
+ format,
89
+ "aria-label": ariaLabelledBy === void 0 ? ariaLabel ?? label : ariaLabel,
90
+ "aria-labelledby": ariaLabelledBy,
91
+ value: hsva[axis],
92
+ min: 0,
93
+ max,
94
+ step,
95
+ disabled,
96
+ thumbAlignment: "edge",
97
+ onValueChange: (next) => setHsva({ [axis]: next }),
98
+ className: cn("relative flex w-full cursor-pointer touch-pan-y select-none items-center data-[disabled]:cursor-not-allowed", className),
99
+ ...props,
100
+ children: /* @__PURE__ */ jsx(Slider.Control, {
101
+ className: "flex h-full w-full items-center",
102
+ children: /* @__PURE__ */ jsx(Slider.Track, {
103
+ "data-control-ui": "color-picker",
104
+ "data-control-family": "color-picker",
105
+ "data-slot": "slider-track",
106
+ className: "relative w-full",
107
+ style: edgeAlignedTrackStyle(trackStops(hsva)),
108
+ children: /* @__PURE__ */ jsx(Slider.Thumb, {
109
+ "data-control-ui": "color-picker",
110
+ "data-control-family": "color-picker",
111
+ "data-slot": "slider-thumb",
112
+ "data-focus-ring": "within",
113
+ className: "block"
114
+ })
115
+ })
116
+ })
117
+ });
118
+ }
119
+ function ColorPickerHue(props) {
120
+ return /* @__PURE__ */ jsx(ColorPickerSlider, {
121
+ axis: "h",
122
+ ...props
123
+ });
124
+ }
125
+ function ColorPickerSaturation(props) {
126
+ return /* @__PURE__ */ jsx(ColorPickerSlider, {
127
+ axis: "s",
128
+ ...props
129
+ });
130
+ }
131
+ function ColorPickerBrightness(props) {
132
+ return /* @__PURE__ */ jsx(ColorPickerSlider, {
133
+ axis: "v",
134
+ ...props
135
+ });
136
+ }
137
+ function ColorPickerAlpha(props) {
138
+ const { alpha } = useColorPicker();
139
+ if (!alpha) return null;
140
+ return /* @__PURE__ */ jsx(ColorPickerSlider, {
141
+ axis: "a",
142
+ ...props
143
+ });
144
+ }
145
+ //#endregion
146
+ export { ColorPickerAlpha, ColorPickerBrightness, ColorPickerHue, ColorPickerSaturation };
@@ -0,0 +1,23 @@
1
+ import { ColorPickerKnobStyle } from "../knob-contracts/color-picker-knobs.js";
2
+ import { CSSProperties, ComponentProps, ReactNode } from "react";
3
+ //#region src/ui/color-picker-swatches.d.ts
4
+ export type ColorPickerSwatchesProps = ComponentProps<"div"> & {
5
+ colors?: string[];
6
+ label?: ReactNode;
7
+ } & {
8
+ style?: CSSProperties & ColorPickerKnobStyle;
9
+ };
10
+ export type ColorPickerSwatchProps = Omit<Omit<ComponentProps<"button">, "color">, "style"> & {
11
+ style?: CSSProperties & ColorPickerKnobStyle;
12
+ } & {
13
+ color: string;
14
+ };
15
+ export type ColorPickerSwatchAddProps = Omit<Omit<ComponentProps<"button">, "onClick">, "style"> & {
16
+ style?: CSSProperties & ColorPickerKnobStyle;
17
+ } & {
18
+ onAdd?: (value: string) => void;
19
+ };
20
+ export declare function ColorPickerSwatches({ colors, label, className, children, ...props }: ColorPickerSwatchesProps): import("react").JSX.Element;
21
+ export declare function ColorPickerSwatch({ color, className, "aria-label": ariaLabel, ...props }: ColorPickerSwatchProps): import("react").JSX.Element;
22
+ export declare function ColorPickerSwatchAdd({ onAdd, className, children, ...props }: ColorPickerSwatchAddProps): import("react").JSX.Element;
23
+ //#endregion
@@ -0,0 +1,94 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { formatColor, parseColor } from "../lib/color.js";
4
+ import { useColorPicker } from "./color-picker-context.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/ui/color-picker-swatches.tsx
7
+ function ColorPickerSwatches({ colors, label, className, children, ...props }) {
8
+ return /* @__PURE__ */ jsxs("div", {
9
+ "data-control-ui": "color-picker",
10
+ "data-control-family": "color-picker",
11
+ "data-slot": "swatches-group",
12
+ className: "grid",
13
+ children: [label ? /* @__PURE__ */ jsx("span", {
14
+ "data-control-ui": "color-picker",
15
+ "data-control-family": "color-picker",
16
+ "data-slot": "swatches-label",
17
+ children: label
18
+ }) : null, /* @__PURE__ */ jsxs("div", {
19
+ "data-control-ui": "color-picker",
20
+ "data-control-family": "color-picker",
21
+ "data-slot": "swatches",
22
+ className: cn("flex flex-wrap", className),
23
+ ...props,
24
+ children: [colors?.map((color) => /* @__PURE__ */ jsx(ColorPickerSwatch, { color }, color)), children]
25
+ })]
26
+ });
27
+ }
28
+ function ColorPickerSwatch({ color, className, "aria-label": ariaLabel, ...props }) {
29
+ const { setFromString, valueString, disabled } = useColorPicker();
30
+ const selected = sameColor(valueString, color);
31
+ return /* @__PURE__ */ jsxs("button", {
32
+ type: "button",
33
+ "data-control-ui": "color-picker",
34
+ "data-control-family": "color-picker",
35
+ "data-slot": "swatch",
36
+ "data-selected": selected ? "true" : void 0,
37
+ "aria-pressed": selected,
38
+ "aria-label": ariaLabel ?? `Set color ${color}`,
39
+ title: color,
40
+ disabled,
41
+ onClick: () => setFromString(color),
42
+ className: cn("relative shrink-0 cursor-pointer overflow-hidden disabled:cursor-not-allowed", className),
43
+ ...props,
44
+ children: [/* @__PURE__ */ jsx("span", {
45
+ "data-control-ui": "color-picker",
46
+ "data-control-family": "color-picker",
47
+ "data-slot": "swatch-checker",
48
+ "aria-hidden": true,
49
+ className: "absolute inset-0"
50
+ }), /* @__PURE__ */ jsx("span", {
51
+ "data-control-ui": "color-picker",
52
+ "data-control-family": "color-picker",
53
+ "data-slot": "swatch-color",
54
+ "aria-hidden": true,
55
+ className: "absolute inset-0",
56
+ style: { backgroundColor: color }
57
+ })]
58
+ });
59
+ }
60
+ function ColorPickerSwatchAdd({ onAdd, className, children, ...props }) {
61
+ const { valueString, disabled } = useColorPicker();
62
+ return /* @__PURE__ */ jsx("button", {
63
+ type: "button",
64
+ "data-control-ui": "color-picker",
65
+ "data-control-family": "color-picker",
66
+ "data-slot": "swatch-add",
67
+ "aria-label": "Add current color",
68
+ disabled,
69
+ onClick: () => onAdd?.(valueString),
70
+ className: cn("relative flex shrink-0 cursor-pointer items-center justify-center disabled:cursor-not-allowed", className),
71
+ ...props,
72
+ children: children ?? /* @__PURE__ */ jsx(PlusIcon, {})
73
+ });
74
+ }
75
+ function sameColor(a, b) {
76
+ const pa = parseColor(a);
77
+ const pb = parseColor(b);
78
+ if (!pa || !pb) return false;
79
+ return formatColor(pa, "hex", { alpha: true }) === formatColor(pb, "hex", { alpha: true });
80
+ }
81
+ function PlusIcon() {
82
+ return /* @__PURE__ */ jsx("svg", {
83
+ viewBox: "0 0 16 16",
84
+ className: "size-3.5",
85
+ fill: "none",
86
+ stroke: "currentColor",
87
+ strokeWidth: "1.5",
88
+ strokeLinecap: "round",
89
+ "aria-hidden": "true",
90
+ children: /* @__PURE__ */ jsx("path", { d: "M8 3v10M3 8h10" })
91
+ });
92
+ }
93
+ //#endregion
94
+ export { ColorPickerSwatch, ColorPickerSwatchAdd, ColorPickerSwatches };
@@ -0,0 +1,59 @@
1
+ import { ControlSize } from "../control-variants.js";
2
+ import { ButtonKnobStyle } from "../knob-contracts/button-knobs.js";
3
+ import { ColorPickerKnobStyle } from "../knob-contracts/color-picker-knobs.js";
4
+ import { ChannelId, ColorFormat } from "../lib/color.js";
5
+ import { CSSProperties, ComponentProps, ReactNode } from "react";
6
+ //#region src/ui/color-picker-values.d.ts
7
+ export type ColorPickerEyeDropperProps = Omit<Omit<ComponentProps<"button">, "onError">, "style"> & {
8
+ style?: CSSProperties & ButtonKnobStyle;
9
+ };
10
+ export type ColorPickerInputProps = Omit<Omit<ComponentProps<"input">, "value" | "defaultValue" | "onChange" | "size">, "style"> & {
11
+ style?: CSSProperties & ColorPickerKnobStyle;
12
+ } & {
13
+ size?: ControlSize;
14
+ invalidLabel?: string;
15
+ };
16
+ export type ColorPickerFormatSelectProps = {
17
+ formats?: ColorFormat[];
18
+ size?: ControlSize;
19
+ className?: string;
20
+ "aria-label"?: string;
21
+ "aria-labelledby"?: string;
22
+ style?: CSSProperties & ButtonKnobStyle;
23
+ };
24
+ export type ColorPickerChannelsProps = ComponentProps<"div"> & {
25
+ style?: CSSProperties & ColorPickerKnobStyle;
26
+ };
27
+ export type ColorPickerChannelProps = Omit<Omit<ComponentProps<"div">, "children" | "aria-label">, "style"> & {
28
+ style?: CSSProperties & ColorPickerKnobStyle;
29
+ } & {
30
+ channel: ChannelId;
31
+ label?: ReactNode;
32
+ "aria-label"?: string;
33
+ };
34
+ export type ColorPickerOutputProps = Omit<Omit<ComponentProps<"div">, "children">, "style"> & {
35
+ style?: CSSProperties & ColorPickerKnobStyle;
36
+ } & {
37
+ children?: ReactNode;
38
+ renderValue?: (state: {
39
+ value: string;
40
+ }) => ReactNode;
41
+ };
42
+ export declare function ColorPickerInput({ size, className, invalidLabel, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, onFocus, onBlur, onKeyDown, ...props }: ColorPickerInputProps): import("react").JSX.Element;
43
+ export declare function ColorPickerFormatSelect({ formats, size, className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, style }: ColorPickerFormatSelectProps): import("react").JSX.Element;
44
+ export declare function ColorPickerChannels({ className, children, ...props }: ColorPickerChannelsProps): import("react").JSX.Element;
45
+ export declare function ColorPickerChannel({ channel, label, className, "aria-label": ariaLabel, ...props }: ColorPickerChannelProps): import("react").JSX.Element | null;
46
+ declare global {
47
+ interface Window {
48
+ EyeDropper?: {
49
+ new (): {
50
+ open: () => Promise<{
51
+ sRGBHex: string;
52
+ }>;
53
+ };
54
+ };
55
+ }
56
+ }
57
+ export declare function ColorPickerEyeDropper({ className, children, ...props }: ColorPickerEyeDropperProps): import("react").JSX.Element | null;
58
+ export declare function ColorPickerOutput({ className, children, renderValue, ...props }: ColorPickerOutputProps): import("react").JSX.Element;
59
+ //#endregion