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