@patternmode/swatch 0.9.2 → 0.10.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/README.md +38 -0
- package/dist/DistributionBar/distribution-bar-math.d.ts +29 -0
- package/dist/DistributionBar/distribution-bar-math.d.ts.map +1 -0
- package/dist/DistributionBar/distribution-bar-root.d.ts +56 -0
- package/dist/DistributionBar/distribution-bar-root.d.ts.map +1 -0
- package/dist/DistributionBar/index.d.ts +2 -2
- package/dist/DistributionBar/index.d.ts.map +1 -1
- package/dist/Swatch/swatch-atmosphere.d.ts +9 -0
- package/dist/Swatch/swatch-atmosphere.d.ts.map +1 -0
- package/dist/Swatch/swatch-colors.d.ts +4 -0
- package/dist/Swatch/swatch-colors.d.ts.map +1 -0
- package/dist/Swatch/swatch-root.d.ts +3 -0
- package/dist/Swatch/swatch-root.d.ts.map +1 -0
- package/dist/Swatch/swatch-types.d.ts +158 -0
- package/dist/Swatch/swatch-types.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +267 -239
- package/dist/index.mjs.map +1 -1
- package/dist/swatch.d.ts +4 -4
- package/dist/swatch.d.ts.map +1 -1
- package/package.json +4 -3
- package/dist/DistributionBar/DistributionBarMath.d.ts +0 -15
- package/dist/DistributionBar/DistributionBarMath.d.ts.map +0 -1
- package/dist/DistributionBar/DistributionBarRoot.d.ts +0 -28
- package/dist/DistributionBar/DistributionBarRoot.d.ts.map +0 -1
- package/dist/Swatch/SwatchAtmosphere.d.ts +0 -15
- package/dist/Swatch/SwatchAtmosphere.d.ts.map +0 -1
- package/dist/Swatch/SwatchColors.d.ts +0 -4
- package/dist/Swatch/SwatchColors.d.ts.map +0 -1
- package/dist/Swatch/SwatchRoot.d.ts +0 -3
- package/dist/Swatch/SwatchRoot.d.ts.map +0 -1
- package/dist/Swatch/SwatchTypes.d.ts +0 -69
- package/dist/Swatch/SwatchTypes.d.ts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -2,16 +2,27 @@ import { PATTERNMODE_SIZES, PATTERNMODE_SIZE_VALUES, getObjectSizingStyle, joinC
|
|
|
2
2
|
import { LazyMotion, domMax, m } from "motion/react";
|
|
3
3
|
import { useRef } from "react";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
import { Slot, Slottable } from "@radix-ui/react-slot";
|
|
6
|
+
//#region src/DistributionBar/distribution-bar-math.ts
|
|
7
|
+
const sanitizeValue = (value) => Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
8
|
+
const clamp$1 = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
9
|
+
const roundValue = (value) => Number(value.toFixed(1));
|
|
10
|
+
/** Sums sanitized segment weights, treating invalid or negative values as 0. */
|
|
11
|
+
const getDistributionTotal = (segments) => segments.reduce((sum, segment) => sum + sanitizeValue(segment.value), 0);
|
|
12
|
+
/** Returns the percentage position of the boundary after `boundaryIndex`. */
|
|
13
|
+
const getDistributionBoundaryPercent = (segments, boundaryIndex) => {
|
|
10
14
|
const total = getDistributionTotal(segments);
|
|
11
15
|
if (total <= 0) return 0;
|
|
12
16
|
return roundValue(segments.slice(0, boundaryIndex + 1).reduce((sum, segment) => sum + sanitizeValue(segment.value), 0) / total * 100);
|
|
13
|
-
}
|
|
14
|
-
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Moves the boundary between two adjacent segments while preserving their sum.
|
|
20
|
+
*
|
|
21
|
+
* `deltaValue` is applied to the left segment and subtracted from the right
|
|
22
|
+
* segment. `minValue` prevents either side of the pair from collapsing below a
|
|
23
|
+
* caller-defined minimum.
|
|
24
|
+
*/
|
|
25
|
+
const moveDistributionBoundary = (segments, boundaryIndex, deltaValue, minValue) => {
|
|
15
26
|
const left = segments[boundaryIndex];
|
|
16
27
|
const right = segments[boundaryIndex + 1];
|
|
17
28
|
if (!(left && right)) return segments;
|
|
@@ -30,8 +41,9 @@ function moveDistributionBoundary(segments, boundaryIndex, deltaValue, minValue)
|
|
|
30
41
|
};
|
|
31
42
|
return segment;
|
|
32
43
|
});
|
|
33
|
-
}
|
|
34
|
-
|
|
44
|
+
};
|
|
45
|
+
/** Removes a segment and redistributes its weight proportionally to the rest. */
|
|
46
|
+
const removeDistributionSegment = (segments, segmentId) => {
|
|
35
47
|
if (segments.length <= 1) return segments;
|
|
36
48
|
const removed = segments.find((segment) => segment.id === segmentId);
|
|
37
49
|
if (!removed) return segments;
|
|
@@ -59,25 +71,111 @@ function removeDistributionSegment(segments, segmentId) {
|
|
|
59
71
|
value: nextValue
|
|
60
72
|
};
|
|
61
73
|
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
function sanitizeValue(value) {
|
|
70
|
-
return Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
71
|
-
}
|
|
72
|
-
function clamp$1(value, min, max) {
|
|
73
|
-
return Math.min(Math.max(value, min), max);
|
|
74
|
-
}
|
|
75
|
-
function roundValue(value) {
|
|
76
|
-
return Number(value.toFixed(1));
|
|
77
|
-
}
|
|
74
|
+
};
|
|
75
|
+
/** Updates non-weight segment metadata such as label or color. */
|
|
76
|
+
const updateDistributionSegment = (segments, segmentId, update) => segments.map((segment) => segment.id === segmentId ? {
|
|
77
|
+
...segment,
|
|
78
|
+
...update
|
|
79
|
+
} : segment);
|
|
78
80
|
//#endregion
|
|
79
|
-
//#region src/DistributionBar/
|
|
80
|
-
|
|
81
|
+
//#region src/DistributionBar/distribution-bar-root.tsx
|
|
82
|
+
const getRenderableDistributionValue = (value) => Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
83
|
+
const getDerivedDistributionPercentage = (value, total) => {
|
|
84
|
+
if (!(total > 0 && Number.isFinite(value))) return 0;
|
|
85
|
+
return Math.round(Math.max(0, value) / total * 100);
|
|
86
|
+
};
|
|
87
|
+
const getDistributionDisplayTotal = (segments, emptyValue) => getDistributionTotal(segments) + getRenderableDistributionValue(emptyValue);
|
|
88
|
+
const getDistributionDisplayAccessibleLabel = (segments, emptyValue, emptyLabel, total) => {
|
|
89
|
+
const segmentLabels = segments.map((segment) => `${segment.label ?? segment.id} ${getDerivedDistributionPercentage(segment.value, total)}%`);
|
|
90
|
+
if (emptyValue > 0) segmentLabels.push(`${emptyLabel} ${getDerivedDistributionPercentage(emptyValue, total)}%`);
|
|
91
|
+
return segmentLabels.join(", ");
|
|
92
|
+
};
|
|
93
|
+
const DistributionSegments = ({ emptyValue = 0, onSegmentSelect, segments, selectedSegmentId, total }) => /* @__PURE__ */ jsxs("div", {
|
|
94
|
+
className: "patternmode-distribution-bar__segments",
|
|
95
|
+
children: [segments.map((segment) => {
|
|
96
|
+
const segmentStyle = {
|
|
97
|
+
"--patternmode-distribution-segment-color": segment.color,
|
|
98
|
+
width: total > 0 ? `${getRenderableDistributionValue(segment.value) / total * 100}%` : "0%"
|
|
99
|
+
};
|
|
100
|
+
const isSelected = selectedSegmentId === segment.id;
|
|
101
|
+
if (onSegmentSelect) return /* @__PURE__ */ jsx("button", {
|
|
102
|
+
"aria-label": `${segment.label ?? segment.id} ${getDerivedDistributionPercentage(segment.value, total)}%`,
|
|
103
|
+
"aria-pressed": isSelected,
|
|
104
|
+
className: "patternmode-distribution-bar__segment",
|
|
105
|
+
"data-selected": isSelected ? "true" : void 0,
|
|
106
|
+
onClick: () => onSegmentSelect(segment),
|
|
107
|
+
style: segmentStyle,
|
|
108
|
+
type: "button"
|
|
109
|
+
}, segment.id);
|
|
110
|
+
return /* @__PURE__ */ jsx("div", {
|
|
111
|
+
"aria-hidden": "true",
|
|
112
|
+
className: "patternmode-distribution-bar__segment",
|
|
113
|
+
"data-selected": isSelected ? "true" : void 0,
|
|
114
|
+
style: segmentStyle
|
|
115
|
+
}, segment.id);
|
|
116
|
+
}), emptyValue > 0 ? /* @__PURE__ */ jsx("div", {
|
|
117
|
+
"aria-hidden": "true",
|
|
118
|
+
className: "patternmode-distribution-bar__segment patternmode-distribution-bar__segment--empty",
|
|
119
|
+
style: { width: total > 0 ? `${getRenderableDistributionValue(emptyValue) / total * 100}%` : "0%" }
|
|
120
|
+
}) : null]
|
|
121
|
+
});
|
|
122
|
+
const DistributionSegmentLegend = ({ emptyLabel, emptyValue = 0, segments, total }) => /* @__PURE__ */ jsxs("div", {
|
|
123
|
+
className: "patternmode-distribution-bar__legend",
|
|
124
|
+
children: [segments.map((segment) => /* @__PURE__ */ jsxs("span", { children: [
|
|
125
|
+
/* @__PURE__ */ jsx("span", {
|
|
126
|
+
"aria-hidden": "true",
|
|
127
|
+
className: "patternmode-distribution-bar__swatch",
|
|
128
|
+
style: { "--patternmode-distribution-segment-color": segment.color }
|
|
129
|
+
}),
|
|
130
|
+
segment.label ?? segment.id,
|
|
131
|
+
" ",
|
|
132
|
+
getDerivedDistributionPercentage(segment.value, total),
|
|
133
|
+
"%"
|
|
134
|
+
] }, segment.id)), emptyValue > 0 && emptyLabel ? /* @__PURE__ */ jsxs("span", { children: [
|
|
135
|
+
/* @__PURE__ */ jsx("span", {
|
|
136
|
+
"aria-hidden": "true",
|
|
137
|
+
className: "patternmode-distribution-bar__swatch patternmode-distribution-bar__swatch--empty"
|
|
138
|
+
}),
|
|
139
|
+
emptyLabel,
|
|
140
|
+
" ",
|
|
141
|
+
getDerivedDistributionPercentage(emptyValue, total),
|
|
142
|
+
"%"
|
|
143
|
+
] }) : null]
|
|
144
|
+
});
|
|
145
|
+
const DistributionSummaryLegend = ({ assignedLabel, emptyLabel, emptyValue, total }) => {
|
|
146
|
+
const emptyPercentage = getDerivedDistributionPercentage(emptyValue, total);
|
|
147
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
148
|
+
className: "patternmode-distribution-bar__legend",
|
|
149
|
+
children: [/* @__PURE__ */ jsxs("span", { children: [
|
|
150
|
+
Math.max(0, 100 - emptyPercentage),
|
|
151
|
+
"% ",
|
|
152
|
+
assignedLabel
|
|
153
|
+
] }), emptyValue > 0 ? /* @__PURE__ */ jsxs("span", { children: [
|
|
154
|
+
emptyPercentage,
|
|
155
|
+
"% ",
|
|
156
|
+
emptyLabel
|
|
157
|
+
] }) : null]
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
const DistributionBarHandle = ({ "aria-label": ariaLabel, boundaryPercent, onDrag, onDragEnd, onDragStart, onKeyDown }) => /* @__PURE__ */ jsx(LazyMotion, {
|
|
161
|
+
features: domMax,
|
|
162
|
+
children: /* @__PURE__ */ jsx(m.button, {
|
|
163
|
+
"aria-label": ariaLabel,
|
|
164
|
+
className: "patternmode-distribution-bar__handle",
|
|
165
|
+
drag: "x",
|
|
166
|
+
dragElastic: 0,
|
|
167
|
+
dragMomentum: false,
|
|
168
|
+
dragSnapToOrigin: true,
|
|
169
|
+
onDrag: (_event, info) => onDrag(info),
|
|
170
|
+
onDragEnd: (_event, info) => onDragEnd(info),
|
|
171
|
+
onDragStart,
|
|
172
|
+
onKeyDown,
|
|
173
|
+
style: { left: `calc(${boundaryPercent}% - 1.375rem)` },
|
|
174
|
+
transformTemplate: () => "none",
|
|
175
|
+
type: "button"
|
|
176
|
+
})
|
|
177
|
+
});
|
|
178
|
+
const DistributionDisplay = ({ "aria-label": ariaLabel, assignedLabel = "assigned", className, emptyLabel = "unassigned", emptyValue = 0, legend = "segments", onSegmentSelect, segments, selectedSegmentId, ...props }) => {
|
|
81
179
|
const total = getDistributionDisplayTotal(segments, emptyValue);
|
|
82
180
|
const interactive = Boolean(onSegmentSelect);
|
|
83
181
|
const accessibleLabel = ariaLabel ?? getDistributionDisplayAccessibleLabel(segments, emptyValue, emptyLabel, total);
|
|
@@ -119,29 +217,29 @@ function DistributionDisplay({ "aria-label": ariaLabel, assignedLabel = "assigne
|
|
|
119
217
|
"data-slot": "distribution-display",
|
|
120
218
|
children: content
|
|
121
219
|
});
|
|
122
|
-
}
|
|
123
|
-
|
|
220
|
+
};
|
|
221
|
+
const DistributionBar = ({ "aria-label": ariaLabel, className, legend = "segments", minValue = 4, onChange, segments, step = 1, ...props }) => {
|
|
124
222
|
const trackRef = useRef(null);
|
|
125
223
|
const dragStartSegmentsRef = useRef(null);
|
|
126
224
|
const total = getDistributionTotal(segments);
|
|
127
|
-
|
|
225
|
+
const moveBoundary = (boundaryIndex, deltaValue, sourceSegments = segments) => {
|
|
128
226
|
onChange?.(moveDistributionBoundary(sourceSegments, boundaryIndex, deltaValue, minValue));
|
|
129
|
-
}
|
|
130
|
-
|
|
227
|
+
};
|
|
228
|
+
const handleDragStart = () => {
|
|
131
229
|
dragStartSegmentsRef.current = segments;
|
|
132
|
-
}
|
|
133
|
-
|
|
230
|
+
};
|
|
231
|
+
const handleDrag = (boundaryIndex, info) => {
|
|
134
232
|
const sourceSegments = dragStartSegmentsRef.current ?? segments;
|
|
135
233
|
const sourceTotal = getDistributionTotal(sourceSegments);
|
|
136
234
|
const trackWidth = trackRef.current?.getBoundingClientRect().width ?? 0;
|
|
137
235
|
if (!(trackWidth > 0 && sourceTotal > 0)) return;
|
|
138
236
|
moveBoundary(boundaryIndex, info.offset.x / trackWidth * sourceTotal, sourceSegments);
|
|
139
|
-
}
|
|
140
|
-
|
|
237
|
+
};
|
|
238
|
+
const handleDragEnd = (boundaryIndex, info) => {
|
|
141
239
|
handleDrag(boundaryIndex, info);
|
|
142
240
|
dragStartSegmentsRef.current = null;
|
|
143
|
-
}
|
|
144
|
-
|
|
241
|
+
};
|
|
242
|
+
const handleKeyDown = (event, boundaryIndex) => {
|
|
145
243
|
if (event.key === "ArrowLeft") {
|
|
146
244
|
event.preventDefault();
|
|
147
245
|
moveBoundary(boundaryIndex, -step);
|
|
@@ -150,7 +248,7 @@ function DistributionBar({ "aria-label": ariaLabel, className, legend = "segment
|
|
|
150
248
|
event.preventDefault();
|
|
151
249
|
moveBoundary(boundaryIndex, step);
|
|
152
250
|
}
|
|
153
|
-
}
|
|
251
|
+
};
|
|
154
252
|
return /* @__PURE__ */ jsxs("fieldset", {
|
|
155
253
|
...props,
|
|
156
254
|
"aria-label": ariaLabel,
|
|
@@ -179,115 +277,9 @@ function DistributionBar({ "aria-label": ariaLabel, className, legend = "segment
|
|
|
179
277
|
total
|
|
180
278
|
}) : null]
|
|
181
279
|
});
|
|
182
|
-
}
|
|
183
|
-
function DistributionSegments({ emptyValue = 0, onSegmentSelect, segments, selectedSegmentId, total }) {
|
|
184
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
185
|
-
className: "patternmode-distribution-bar__segments",
|
|
186
|
-
children: [segments.map((segment) => {
|
|
187
|
-
const segmentStyle = {
|
|
188
|
-
"--patternmode-distribution-segment-color": segment.color,
|
|
189
|
-
width: total > 0 ? `${getRenderableDistributionValue(segment.value) / total * 100}%` : "0%"
|
|
190
|
-
};
|
|
191
|
-
const isSelected = selectedSegmentId === segment.id;
|
|
192
|
-
if (onSegmentSelect) return /* @__PURE__ */ jsx("button", {
|
|
193
|
-
"aria-label": `${segment.label ?? segment.id} ${getDerivedDistributionPercentage(segment.value, total)}%`,
|
|
194
|
-
"aria-pressed": isSelected,
|
|
195
|
-
className: "patternmode-distribution-bar__segment",
|
|
196
|
-
"data-selected": isSelected ? "true" : void 0,
|
|
197
|
-
onClick: () => onSegmentSelect(segment),
|
|
198
|
-
style: segmentStyle,
|
|
199
|
-
type: "button"
|
|
200
|
-
}, segment.id);
|
|
201
|
-
return /* @__PURE__ */ jsx("div", {
|
|
202
|
-
"aria-hidden": "true",
|
|
203
|
-
className: "patternmode-distribution-bar__segment",
|
|
204
|
-
"data-selected": isSelected ? "true" : void 0,
|
|
205
|
-
style: segmentStyle
|
|
206
|
-
}, segment.id);
|
|
207
|
-
}), emptyValue > 0 ? /* @__PURE__ */ jsx("div", {
|
|
208
|
-
"aria-hidden": "true",
|
|
209
|
-
className: "patternmode-distribution-bar__segment patternmode-distribution-bar__segment--empty",
|
|
210
|
-
style: { width: total > 0 ? `${getRenderableDistributionValue(emptyValue) / total * 100}%` : "0%" }
|
|
211
|
-
}) : null]
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
function DistributionSegmentLegend({ emptyLabel, emptyValue = 0, segments, total }) {
|
|
215
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
216
|
-
className: "patternmode-distribution-bar__legend",
|
|
217
|
-
children: [segments.map((segment) => /* @__PURE__ */ jsxs("span", { children: [
|
|
218
|
-
/* @__PURE__ */ jsx("span", {
|
|
219
|
-
"aria-hidden": "true",
|
|
220
|
-
className: "patternmode-distribution-bar__swatch",
|
|
221
|
-
style: { "--patternmode-distribution-segment-color": segment.color }
|
|
222
|
-
}),
|
|
223
|
-
segment.label ?? segment.id,
|
|
224
|
-
" ",
|
|
225
|
-
getDerivedDistributionPercentage(segment.value, total),
|
|
226
|
-
"%"
|
|
227
|
-
] }, segment.id)), emptyValue > 0 && emptyLabel ? /* @__PURE__ */ jsxs("span", { children: [
|
|
228
|
-
/* @__PURE__ */ jsx("span", {
|
|
229
|
-
"aria-hidden": "true",
|
|
230
|
-
className: "patternmode-distribution-bar__swatch patternmode-distribution-bar__swatch--empty"
|
|
231
|
-
}),
|
|
232
|
-
emptyLabel,
|
|
233
|
-
" ",
|
|
234
|
-
getDerivedDistributionPercentage(emptyValue, total),
|
|
235
|
-
"%"
|
|
236
|
-
] }) : null]
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
function DistributionSummaryLegend({ assignedLabel, emptyLabel, emptyValue, total }) {
|
|
240
|
-
const emptyPercentage = getDerivedDistributionPercentage(emptyValue, total);
|
|
241
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
242
|
-
className: "patternmode-distribution-bar__legend",
|
|
243
|
-
children: [/* @__PURE__ */ jsxs("span", { children: [
|
|
244
|
-
Math.max(0, 100 - emptyPercentage),
|
|
245
|
-
"% ",
|
|
246
|
-
assignedLabel
|
|
247
|
-
] }), emptyValue > 0 ? /* @__PURE__ */ jsxs("span", { children: [
|
|
248
|
-
emptyPercentage,
|
|
249
|
-
"% ",
|
|
250
|
-
emptyLabel
|
|
251
|
-
] }) : null]
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
function getDistributionDisplayTotal(segments, emptyValue) {
|
|
255
|
-
return getDistributionTotal(segments) + getRenderableDistributionValue(emptyValue);
|
|
256
|
-
}
|
|
257
|
-
function getDistributionDisplayAccessibleLabel(segments, emptyValue, emptyLabel, total) {
|
|
258
|
-
const segmentLabels = segments.map((segment) => `${segment.label ?? segment.id} ${getDerivedDistributionPercentage(segment.value, total)}%`);
|
|
259
|
-
if (emptyValue > 0) segmentLabels.push(`${emptyLabel} ${getDerivedDistributionPercentage(emptyValue, total)}%`);
|
|
260
|
-
return segmentLabels.join(", ");
|
|
261
|
-
}
|
|
262
|
-
function getDerivedDistributionPercentage(value, total) {
|
|
263
|
-
if (!(total > 0 && Number.isFinite(value))) return 0;
|
|
264
|
-
return Math.round(Math.max(0, value) / total * 100);
|
|
265
|
-
}
|
|
266
|
-
function getRenderableDistributionValue(value) {
|
|
267
|
-
return Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
268
|
-
}
|
|
269
|
-
function DistributionBarHandle({ "aria-label": ariaLabel, boundaryPercent, onDrag, onDragEnd, onDragStart, onKeyDown }) {
|
|
270
|
-
return /* @__PURE__ */ jsx(LazyMotion, {
|
|
271
|
-
features: domMax,
|
|
272
|
-
children: /* @__PURE__ */ jsx(m.button, {
|
|
273
|
-
"aria-label": ariaLabel,
|
|
274
|
-
className: "patternmode-distribution-bar__handle",
|
|
275
|
-
drag: "x",
|
|
276
|
-
dragElastic: 0,
|
|
277
|
-
dragMomentum: false,
|
|
278
|
-
dragSnapToOrigin: true,
|
|
279
|
-
onDrag: (_event, info) => onDrag(info),
|
|
280
|
-
onDragEnd: (_event, info) => onDragEnd(info),
|
|
281
|
-
onDragStart,
|
|
282
|
-
onKeyDown,
|
|
283
|
-
style: { left: `calc(${boundaryPercent}% - 1.375rem)` },
|
|
284
|
-
transformTemplate: () => "none",
|
|
285
|
-
type: "button"
|
|
286
|
-
})
|
|
287
|
-
});
|
|
288
|
-
}
|
|
280
|
+
};
|
|
289
281
|
//#endregion
|
|
290
|
-
//#region src/Swatch/
|
|
282
|
+
//#region src/Swatch/swatch-atmosphere.ts
|
|
291
283
|
/**
|
|
292
284
|
* Per-pool layout for the atmosphere fill:
|
|
293
285
|
* `[focal x%, focal y%, base alpha (0-255), radius delta %, gravity sign]`.
|
|
@@ -346,7 +338,19 @@ const POOLS = [
|
|
|
346
338
|
* Density controls how far each pool reaches; gravity shifts the pools
|
|
347
339
|
* vertically. Returns `undefined` when there are no colors.
|
|
348
340
|
*/
|
|
349
|
-
|
|
341
|
+
const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
342
|
+
const normalizeHex$1 = (color) => {
|
|
343
|
+
const value = color.trim().replace(/^#/u, "");
|
|
344
|
+
if (/^[\da-f]{3}$/iu.test(value)) return [...value].map((part) => part + part).join("");
|
|
345
|
+
if (/^[\da-f]{6}$/iu.test(value)) return value;
|
|
346
|
+
return null;
|
|
347
|
+
};
|
|
348
|
+
const withAlpha = (color, alpha) => {
|
|
349
|
+
const hex = normalizeHex$1(color);
|
|
350
|
+
if (hex) return `#${hex}${Math.round(clamp(alpha, 0, 255)).toString(16).padStart(2, "0")}`;
|
|
351
|
+
return `color-mix(in srgb, ${color} ${Math.round(clamp(alpha, 0, 255) / 255 * 100)}%, transparent)`;
|
|
352
|
+
};
|
|
353
|
+
const getSwatchAtmosphereBackground = (colors, options = {}) => {
|
|
350
354
|
if (!colors || colors.length === 0) return;
|
|
351
355
|
const density = clamp(options.density ?? .5, 0, 1);
|
|
352
356
|
const gravity = clamp(options.gravity ?? 0, -1, 1);
|
|
@@ -361,32 +365,30 @@ function getSwatchAtmosphereBackground(colors, options = {}) {
|
|
|
361
365
|
const radius = Math.max(8, reach + radiusDelta);
|
|
362
366
|
return `radial-gradient(ellipse at ${x}% ${focalY}%, ${withAlpha(color, alpha)} 0%, transparent ${radius}%)`;
|
|
363
367
|
}).join(", ");
|
|
364
|
-
}
|
|
365
|
-
function withAlpha(color, alpha) {
|
|
366
|
-
const hex = normalizeHex$1(color);
|
|
367
|
-
if (hex) return `#${hex}${Math.round(clamp(alpha, 0, 255)).toString(16).padStart(2, "0")}`;
|
|
368
|
-
return `color-mix(in srgb, ${color} ${Math.round(clamp(alpha, 0, 255) / 255 * 100)}%, transparent)`;
|
|
369
|
-
}
|
|
370
|
-
function normalizeHex$1(color) {
|
|
371
|
-
const value = color.trim().replace(/^#/, "");
|
|
372
|
-
if (/^[\da-f]{3}$/i.test(value)) return [...value].map((part) => part + part).join("");
|
|
373
|
-
if (/^[\da-f]{6}$/i.test(value)) return value;
|
|
374
|
-
return null;
|
|
375
|
-
}
|
|
376
|
-
function clamp(value, min, max) {
|
|
377
|
-
return Math.min(max, Math.max(min, value));
|
|
378
|
-
}
|
|
368
|
+
};
|
|
379
369
|
//#endregion
|
|
380
|
-
//#region src/Swatch/
|
|
381
|
-
|
|
370
|
+
//#region src/Swatch/swatch-colors.ts
|
|
371
|
+
const normalizeHex = (hex) => {
|
|
372
|
+
const value = hex.trim().replace(/^#/u, "");
|
|
373
|
+
if (/^[\da-f]{3}$/iu.test(value)) return [...value].map((part) => part + part).join("");
|
|
374
|
+
if (/^[\da-f]{6}$/iu.test(value)) return value;
|
|
375
|
+
return null;
|
|
376
|
+
};
|
|
377
|
+
const toColorStop = (stop) => typeof stop === "string" ? { color: stop } : stop;
|
|
378
|
+
const getRatioWeight = (ratio) => {
|
|
379
|
+
if (ratio === void 0) return 1;
|
|
380
|
+
return Number.isFinite(ratio) ? Math.max(0, ratio) : 0;
|
|
381
|
+
};
|
|
382
|
+
const formatPercent = (value) => `${Number.isInteger(value) ? value : Number(value.toFixed(2))}%`;
|
|
383
|
+
const isLightColor = (color) => {
|
|
382
384
|
const normalized = normalizeHex(color);
|
|
383
385
|
if (!normalized) return false;
|
|
384
386
|
const red = Number.parseInt(normalized.slice(0, 2), 16);
|
|
385
387
|
const green = Number.parseInt(normalized.slice(2, 4), 16);
|
|
386
388
|
const blue = Number.parseInt(normalized.slice(4, 6), 16);
|
|
387
389
|
return (.299 * red + .587 * green + .114 * blue) / 255 > .62;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
+
};
|
|
391
|
+
const getSwatchColorsBackground = (colors) => {
|
|
390
392
|
if (!colors || colors.length === 0) return;
|
|
391
393
|
if (colors.length === 1) return toColorStop(colors[0]).color;
|
|
392
394
|
const stops = colors.map(toColorStop);
|
|
@@ -402,25 +404,9 @@ function getSwatchColorsBackground(colors) {
|
|
|
402
404
|
cursor = end;
|
|
403
405
|
return `${stop.color} ${formatPercent(start)} ${formatPercent(end)}`;
|
|
404
406
|
}).join(", ")})`;
|
|
405
|
-
}
|
|
406
|
-
function normalizeHex(hex) {
|
|
407
|
-
const value = hex.trim().replace(/^#/, "");
|
|
408
|
-
if (/^[\da-f]{3}$/i.test(value)) return [...value].map((part) => part + part).join("");
|
|
409
|
-
if (/^[\da-f]{6}$/i.test(value)) return value;
|
|
410
|
-
return null;
|
|
411
|
-
}
|
|
412
|
-
function toColorStop(stop) {
|
|
413
|
-
return typeof stop === "string" ? { color: stop } : stop;
|
|
414
|
-
}
|
|
415
|
-
function getRatioWeight(ratio) {
|
|
416
|
-
if (ratio === void 0) return 1;
|
|
417
|
-
return Number.isFinite(ratio) ? Math.max(0, ratio) : 0;
|
|
418
|
-
}
|
|
419
|
-
function formatPercent(value) {
|
|
420
|
-
return `${Number.isInteger(value) ? value : Number(value.toFixed(2))}%`;
|
|
421
|
-
}
|
|
407
|
+
};
|
|
422
408
|
//#endregion
|
|
423
|
-
//#region src/Swatch/
|
|
409
|
+
//#region src/Swatch/swatch-types.ts
|
|
424
410
|
const SWATCH_SIZES = [
|
|
425
411
|
...PATTERNMODE_SIZES,
|
|
426
412
|
"4xl",
|
|
@@ -442,19 +428,77 @@ const SWATCH_SHAPES = [
|
|
|
442
428
|
"block"
|
|
443
429
|
];
|
|
444
430
|
const SWATCH_TEXTURES = ["atmosphere"];
|
|
445
|
-
|
|
446
|
-
return { [variableName]: SWATCH_SIZE_VALUES[size] };
|
|
447
|
-
}
|
|
431
|
+
const getSwatchSizeVariableStyle = (size, variableName = "--patternmode-swatch-size") => ({ [variableName]: SWATCH_SIZE_VALUES[size] });
|
|
448
432
|
//#endregion
|
|
449
|
-
//#region src/Swatch/
|
|
450
|
-
|
|
433
|
+
//#region src/Swatch/swatch-root.tsx
|
|
434
|
+
const SwatchContent = ({ children, flat, Icon, mediaStyle, selected, unavailable }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
435
|
+
/* @__PURE__ */ jsx("span", {
|
|
436
|
+
"aria-hidden": "true",
|
|
437
|
+
className: "patternmode-swatch__fill"
|
|
438
|
+
}),
|
|
439
|
+
children ? /* @__PURE__ */ jsx("span", {
|
|
440
|
+
className: "patternmode-swatch__media",
|
|
441
|
+
style: mediaStyle,
|
|
442
|
+
children
|
|
443
|
+
}) : null,
|
|
444
|
+
flat ? null : /* @__PURE__ */ jsx("span", {
|
|
445
|
+
"aria-hidden": "true",
|
|
446
|
+
className: "patternmode-swatch__scrim"
|
|
447
|
+
}),
|
|
448
|
+
selected && Icon ? /* @__PURE__ */ jsx("span", {
|
|
449
|
+
className: "patternmode-swatch__icon",
|
|
450
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
451
|
+
"aria-hidden": "true",
|
|
452
|
+
focusable: "false"
|
|
453
|
+
})
|
|
454
|
+
}) : null,
|
|
455
|
+
unavailable ? /* @__PURE__ */ jsx("span", {
|
|
456
|
+
"aria-hidden": "true",
|
|
457
|
+
className: "patternmode-swatch__slash"
|
|
458
|
+
}) : null
|
|
459
|
+
] });
|
|
460
|
+
const getSwatchFill = ({ background, color, colors, density, gravity, texture }) => {
|
|
451
461
|
const colorsBackground = getSwatchColorsBackground(colors);
|
|
452
462
|
const atmosphereBackground = texture === "atmosphere" ? getSwatchAtmosphereBackground(colors, {
|
|
453
463
|
density,
|
|
454
464
|
gravity
|
|
455
465
|
}) : void 0;
|
|
456
|
-
|
|
457
|
-
|
|
466
|
+
return {
|
|
467
|
+
colorsBackground,
|
|
468
|
+
fill: background ?? atmosphereBackground ?? colorsBackground ?? color
|
|
469
|
+
};
|
|
470
|
+
};
|
|
471
|
+
const getSwatchTone = ({ background, color, colorsBackground, isLight }) => {
|
|
472
|
+
if (isLight !== void 0) return isLight ? "light" : "dark";
|
|
473
|
+
if (color && !background && !colorsBackground && isLightColor(color)) return "light";
|
|
474
|
+
return "dark";
|
|
475
|
+
};
|
|
476
|
+
const getSwatchDataProps = ({ flat, lightTone, raised, selected, shape, showRing, size, unavailable }) => ({
|
|
477
|
+
"data-flat": flat ? "true" : void 0,
|
|
478
|
+
"data-raised": raised ? "true" : void 0,
|
|
479
|
+
"data-selected": selected ? "true" : void 0,
|
|
480
|
+
"data-shape": shape,
|
|
481
|
+
"data-show-ring": showRing ? "true" : "false",
|
|
482
|
+
"data-size": size,
|
|
483
|
+
"data-slot": "swatch",
|
|
484
|
+
"data-tone": lightTone,
|
|
485
|
+
"data-unavailable": unavailable ? "true" : void 0
|
|
486
|
+
});
|
|
487
|
+
const Swatch = ({ "aria-label": ariaLabel, asChild = false, background, children, className, color, colors, density, flat = false, gravity, icon: Icon, isLight, objectFit, objectPosition, onRemove, raised = false, removeLabel, role: _role, selected = false, shape = "circle", showRing = true, size = "base", style, texture, unavailable = false, ...props }) => {
|
|
488
|
+
const { colorsBackground, fill } = getSwatchFill({
|
|
489
|
+
background,
|
|
490
|
+
color,
|
|
491
|
+
colors,
|
|
492
|
+
density,
|
|
493
|
+
gravity,
|
|
494
|
+
texture
|
|
495
|
+
});
|
|
496
|
+
const lightTone = getSwatchTone({
|
|
497
|
+
background,
|
|
498
|
+
color,
|
|
499
|
+
colorsBackground,
|
|
500
|
+
isLight
|
|
501
|
+
});
|
|
458
502
|
const resolvedRemoveLabel = removeLabel ?? (ariaLabel ? `Remove ${ariaLabel}` : "Remove");
|
|
459
503
|
const rootStyle = {
|
|
460
504
|
...getSwatchSizeVariableStyle(size),
|
|
@@ -465,49 +509,41 @@ function Swatch({ "aria-label": ariaLabel, background, children, className, colo
|
|
|
465
509
|
fit: objectFit,
|
|
466
510
|
position: objectPosition
|
|
467
511
|
});
|
|
468
|
-
|
|
512
|
+
const dataProps = getSwatchDataProps({
|
|
513
|
+
flat,
|
|
514
|
+
lightTone,
|
|
515
|
+
raised,
|
|
516
|
+
selected,
|
|
517
|
+
shape,
|
|
518
|
+
showRing,
|
|
519
|
+
size,
|
|
520
|
+
unavailable
|
|
521
|
+
});
|
|
522
|
+
const handleRemove = (event) => {
|
|
469
523
|
event.stopPropagation();
|
|
470
524
|
onRemove?.();
|
|
471
|
-
}
|
|
472
|
-
const swatchContent = /* @__PURE__ */
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
children: /* @__PURE__ */ jsx(Icon, {
|
|
489
|
-
"aria-hidden": "true",
|
|
490
|
-
focusable: "false"
|
|
491
|
-
})
|
|
492
|
-
}) : null,
|
|
493
|
-
unavailable ? /* @__PURE__ */ jsx("span", {
|
|
494
|
-
"aria-hidden": "true",
|
|
495
|
-
className: "patternmode-swatch__slash"
|
|
496
|
-
}) : null
|
|
497
|
-
] });
|
|
525
|
+
};
|
|
526
|
+
const swatchContent = /* @__PURE__ */ jsx(SwatchContent, {
|
|
527
|
+
flat,
|
|
528
|
+
Icon,
|
|
529
|
+
mediaStyle,
|
|
530
|
+
selected,
|
|
531
|
+
unavailable,
|
|
532
|
+
children: asChild ? void 0 : children
|
|
533
|
+
});
|
|
534
|
+
if (asChild) return /* @__PURE__ */ jsxs(Slot, {
|
|
535
|
+
...props,
|
|
536
|
+
...dataProps,
|
|
537
|
+
"aria-label": ariaLabel,
|
|
538
|
+
className: joinClassNames("patternmode-swatch", className),
|
|
539
|
+
style: rootStyle,
|
|
540
|
+
children: [swatchContent, /* @__PURE__ */ jsx(Slottable, { children })]
|
|
541
|
+
});
|
|
498
542
|
if (onRemove) return /* @__PURE__ */ jsxs("fieldset", {
|
|
499
543
|
...props,
|
|
544
|
+
...dataProps,
|
|
500
545
|
"aria-label": ariaLabel,
|
|
501
546
|
className: joinClassNames("patternmode-swatch", className),
|
|
502
|
-
"data-flat": flat ? "true" : void 0,
|
|
503
|
-
"data-raised": raised ? "true" : void 0,
|
|
504
|
-
"data-selected": selected ? "true" : void 0,
|
|
505
|
-
"data-shape": shape,
|
|
506
|
-
"data-show-ring": showRing ? "true" : "false",
|
|
507
|
-
"data-size": size,
|
|
508
|
-
"data-slot": "swatch",
|
|
509
|
-
"data-tone": light ? "light" : "dark",
|
|
510
|
-
"data-unavailable": unavailable ? "true" : void 0,
|
|
511
547
|
style: rootStyle,
|
|
512
548
|
children: [swatchContent, /* @__PURE__ */ jsx("button", {
|
|
513
549
|
"aria-label": resolvedRemoveLabel,
|
|
@@ -524,21 +560,13 @@ function Swatch({ "aria-label": ariaLabel, background, children, className, colo
|
|
|
524
560
|
});
|
|
525
561
|
return /* @__PURE__ */ jsx("figure", {
|
|
526
562
|
...props,
|
|
563
|
+
...dataProps,
|
|
527
564
|
"aria-label": ariaLabel,
|
|
528
565
|
className: joinClassNames("patternmode-swatch", className),
|
|
529
|
-
"data-flat": flat ? "true" : void 0,
|
|
530
|
-
"data-raised": raised ? "true" : void 0,
|
|
531
|
-
"data-selected": selected ? "true" : void 0,
|
|
532
|
-
"data-shape": shape,
|
|
533
|
-
"data-show-ring": showRing ? "true" : "false",
|
|
534
|
-
"data-size": size,
|
|
535
|
-
"data-slot": "swatch",
|
|
536
|
-
"data-tone": light ? "light" : "dark",
|
|
537
|
-
"data-unavailable": unavailable ? "true" : void 0,
|
|
538
566
|
style: rootStyle,
|
|
539
567
|
children: swatchContent
|
|
540
568
|
});
|
|
541
|
-
}
|
|
569
|
+
};
|
|
542
570
|
//#endregion
|
|
543
571
|
export { DistributionBar, DistributionDisplay, SWATCH_SHAPES, SWATCH_SIZES, SWATCH_SIZE_VALUES, SWATCH_TEXTURES, Swatch, getDistributionBoundaryPercent, getDistributionTotal, getSwatchAtmosphereBackground, getSwatchColorsBackground, getSwatchSizeVariableStyle, moveDistributionBoundary, removeDistributionSegment, updateDistributionSegment };
|
|
544
572
|
|