@patternmode/swatch 0.10.2 → 0.10.4
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/dist/DistributionBar/distribution-bar-math.d.ts +6 -6
- package/dist/DistributionBar/distribution-bar-math.d.ts.map +1 -1
- package/dist/DistributionBar/distribution-bar-root.d.ts.map +1 -1
- package/dist/Swatch/swatch-atmosphere.d.ts.map +1 -1
- package/dist/Swatch/swatch-colors.d.ts +0 -1
- package/dist/Swatch/swatch-colors.d.ts.map +1 -1
- package/dist/Swatch/swatch-root.d.ts +1 -1
- package/dist/Swatch/swatch-root.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +57 -50
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { WeightedColorSegment } from "@patternmode/system";
|
|
2
|
+
/**
|
|
3
|
+
* Weighted segment used by DistributionBar and DistributionDisplay. Extends the
|
|
4
|
+
* shared {@link WeightedColorSegment} with a required stable `id` for editing.
|
|
5
|
+
*/
|
|
6
|
+
export interface DistributionBarSegment extends WeightedColorSegment {
|
|
4
7
|
id: string;
|
|
5
|
-
label?: string;
|
|
6
|
-
/** Relative weight, not a persisted percentage. Invalid or negative values render as 0. */
|
|
7
|
-
value: number;
|
|
8
8
|
}
|
|
9
9
|
/** Segment metadata update; weight changes happen through boundary movement. */
|
|
10
10
|
export type DistributionBarSegmentUpdate = Partial<Omit<DistributionBarSegment, "value">> & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"distribution-bar-math.d.ts","sourceRoot":"","sources":["../../src/DistributionBar/distribution-bar-math.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"distribution-bar-math.d.ts","sourceRoot":"","sources":["../../src/DistributionBar/distribution-bar-math.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEhE;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,gFAAgF;AAChF,MAAM,MAAM,4BAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC,GAAG;IAC1F,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAOF,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,GAAI,UAAU,sBAAsB,EAAE,KAAG,MACC,CAAC;AAE5E,6EAA6E;AAC7E,eAAO,MAAM,8BAA8B,GACzC,UAAU,sBAAsB,EAAE,EAClC,eAAe,MAAM,KACpB,MAUF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,GACnC,UAAU,sBAAsB,EAAE,EAClC,eAAe,MAAM,EACrB,YAAY,MAAM,EAClB,UAAU,MAAM,KACf,sBAAsB,EAyBxB,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,yBAAyB,GACpC,UAAU,sBAAsB,EAAE,EAClC,WAAW,MAAM,KAChB,sBAAsB,EAmCxB,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,yBAAyB,GACpC,UAAU,sBAAsB,EAAE,EAClC,WAAW,MAAM,EACjB,QAAQ,4BAA4B,KACnC,sBAAsB,EACoE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"distribution-bar-root.d.ts","sourceRoot":"","sources":["../../src/DistributionBar/distribution-bar-root.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAiB,cAAc,EAAiB,MAAM,OAAO,CAAC;AAO1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,cAAc,CAAC,WAAW,CAAC,EAC3B,MAAM,GAAG,UAAU,CACpB;IACC,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,KAAK,CAAC;IACxC;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAC5D,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAChD,cAAc,CAAC,mBAAmB,CAAC,EACnC,UAAU,CACX;IACC;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,sBAAsB,EAAE,KAAK,IAAI,CAAC;IACxD,6EAA6E;IAC7E,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"distribution-bar-root.d.ts","sourceRoot":"","sources":["../../src/DistributionBar/distribution-bar-root.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAiB,cAAc,EAAiB,MAAM,OAAO,CAAC;AAO1E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,cAAc,CAAC,WAAW,CAAC,EAC3B,MAAM,GAAG,UAAU,CACpB;IACC,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,KAAK,CAAC;IACxC;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAC5D,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAChD,cAAc,CAAC,mBAAmB,CAAC,EACnC,UAAU,CACX;IACC;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,sBAAsB,EAAE,KAAK,IAAI,CAAC;IACxD,6EAA6E;IAC7E,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAuND,eAAO,MAAM,mBAAmB,GAAI,+IAWjC,wBAAwB,gCAwD1B,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,8FAS7B,oBAAoB,gCA8FtB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swatch-atmosphere.d.ts","sourceRoot":"","sources":["../../src/Swatch/swatch-atmosphere.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"swatch-atmosphere.d.ts","sourceRoot":"","sources":["../../src/Swatch/swatch-atmosphere.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAyCD,eAAO,MAAM,6BAA6B,GACxC,QAAQ,eAAe,EAAE,GAAG,SAAS,EACrC,UAAS,uBAA4B,KACpC,MAAM,GAAG,SA6BX,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import type { SwatchColorStop } from "./swatch-types";
|
|
2
|
-
export declare const isLightColor: (color: string) => boolean;
|
|
3
2
|
export declare const getSwatchColorsBackground: (colors: SwatchColorStop[] | undefined, blend?: "smooth" | "step") => string | undefined;
|
|
4
3
|
//# sourceMappingURL=swatch-colors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swatch-colors.d.ts","sourceRoot":"","sources":["../../src/Swatch/swatch-colors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"swatch-colors.d.ts","sourceRoot":"","sources":["../../src/Swatch/swatch-colors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAYtD,eAAO,MAAM,yBAAyB,GACpC,QAAQ,eAAe,EAAE,GAAG,SAAS,EACrC,QAAO,QAAQ,GAAG,MAAe,KAChC,MAAM,GAAG,SAkDX,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { SwatchProps } from "./swatch-types";
|
|
2
|
-
export declare const Swatch: ({ "aria-label": ariaLabel, asChild, background, blend, children, className, color, colors, density, flat, gravity, icon: Icon, isLight, objectFit, objectPosition, onRemove, raised, removeLabel,
|
|
2
|
+
export declare const Swatch: ({ "aria-label": ariaLabel, asChild, background, blend, children, className, color, colors, density, flat, gravity, icon: Icon, isLight, objectFit, objectPosition, onRemove, raised, removeLabel, selected, shape, showRing, size, style, texture, unavailable, ...props }: SwatchProps) => import("react").JSX.Element;
|
|
3
3
|
//# sourceMappingURL=swatch-root.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swatch-root.d.ts","sourceRoot":"","sources":["../../src/Swatch/swatch-root.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"swatch-root.d.ts","sourceRoot":"","sources":["../../src/Swatch/swatch-root.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAuKlD,eAAO,MAAM,MAAM,GAAI,4QA2BpB,WAAW,gCA6Fb,CAAC"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,EACjC,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,8BAA8B,EAC9B,oBAAoB,EACpB,6BAA6B,EAC7B,yBAAyB,EACzB,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,MAAM,EACN,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,yBAAyB,GAC1B,MAAM,UAAU,CAAC"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import { PATTERNMODE_SIZES, PATTERNMODE_SIZE_VALUES, getObjectSizingStyle, isLightColor, joinClassNames, sanitizeWeight } from "@patternmode/system";
|
|
2
3
|
import { LazyMotion, domMax, m } from "motion/react";
|
|
3
|
-
import { useRef } from "react";
|
|
4
|
+
import { useRef, useState } from "react";
|
|
4
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { hexToRgb, rgbToHex } from "@instruments/colorscope/convert";
|
|
5
7
|
import { Slot, Slottable } from "@radix-ui/react-slot";
|
|
6
8
|
//#region src/DistributionBar/distribution-bar-math.ts
|
|
7
|
-
const sanitizeValue = (value) => Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
8
9
|
const clamp$1 = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
9
10
|
const roundValue = (value) => Number(value.toFixed(1));
|
|
10
11
|
/** Sums sanitized segment weights, treating invalid or negative values as 0. */
|
|
11
|
-
const getDistributionTotal = (segments) => segments.reduce((sum, segment) => sum +
|
|
12
|
+
const getDistributionTotal = (segments) => segments.reduce((sum, segment) => sum + sanitizeWeight(segment.value), 0);
|
|
12
13
|
/** Returns the percentage position of the boundary after `boundaryIndex`. */
|
|
13
14
|
const getDistributionBoundaryPercent = (segments, boundaryIndex) => {
|
|
14
15
|
const total = getDistributionTotal(segments);
|
|
15
16
|
if (total <= 0) return 0;
|
|
16
|
-
return roundValue(segments.slice(0, boundaryIndex + 1).reduce((sum, segment) => sum +
|
|
17
|
+
return roundValue(segments.slice(0, boundaryIndex + 1).reduce((sum, segment) => sum + sanitizeWeight(segment.value), 0) / total * 100);
|
|
17
18
|
};
|
|
18
19
|
/**
|
|
19
20
|
* Moves the boundary between two adjacent segments while preserving their sum.
|
|
@@ -26,9 +27,9 @@ const moveDistributionBoundary = (segments, boundaryIndex, deltaValue, minValue)
|
|
|
26
27
|
const left = segments[boundaryIndex];
|
|
27
28
|
const right = segments[boundaryIndex + 1];
|
|
28
29
|
if (!(left && right)) return segments;
|
|
29
|
-
const pairTotal =
|
|
30
|
+
const pairTotal = sanitizeWeight(left.value) + sanitizeWeight(right.value);
|
|
30
31
|
const clampedMin = Math.max(0, Math.min(minValue, pairTotal / 2));
|
|
31
|
-
const nextLeft = clamp$1(
|
|
32
|
+
const nextLeft = clamp$1(sanitizeWeight(left.value) + deltaValue, clampedMin, pairTotal - clampedMin);
|
|
32
33
|
const nextRight = pairTotal - nextLeft;
|
|
33
34
|
return segments.map((segment, index) => {
|
|
34
35
|
if (index === boundaryIndex) return {
|
|
@@ -48,7 +49,7 @@ const removeDistributionSegment = (segments, segmentId) => {
|
|
|
48
49
|
const removed = segments.find((segment) => segment.id === segmentId);
|
|
49
50
|
if (!removed) return segments;
|
|
50
51
|
const remaining = segments.filter((segment) => segment.id !== segmentId);
|
|
51
|
-
const removedValue =
|
|
52
|
+
const removedValue = sanitizeWeight(removed.value);
|
|
52
53
|
const remainingTotal = getDistributionTotal(remaining);
|
|
53
54
|
if (remainingTotal <= 0) {
|
|
54
55
|
const equalValue = removedValue / remaining.length;
|
|
@@ -64,7 +65,7 @@ const removeDistributionSegment = (segments, segmentId) => {
|
|
|
64
65
|
...segment,
|
|
65
66
|
value: roundValue(originalTotal - assignedValue)
|
|
66
67
|
};
|
|
67
|
-
const nextValue = roundValue(
|
|
68
|
+
const nextValue = roundValue(sanitizeWeight(segment.value) + removedValue * sanitizeWeight(segment.value) / remainingTotal);
|
|
68
69
|
assignedValue += nextValue;
|
|
69
70
|
return {
|
|
70
71
|
...segment,
|
|
@@ -79,12 +80,8 @@ const updateDistributionSegment = (segments, segmentId, update) => segments.map(
|
|
|
79
80
|
} : segment);
|
|
80
81
|
//#endregion
|
|
81
82
|
//#region src/DistributionBar/distribution-bar-root.tsx
|
|
82
|
-
const
|
|
83
|
-
const
|
|
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);
|
|
83
|
+
const getDerivedDistributionPercentage = (value, total) => total > 0 ? Math.round(sanitizeWeight(value) / total * 100) : 0;
|
|
84
|
+
const getDistributionDisplayTotal = (segments, emptyValue) => getDistributionTotal(segments) + sanitizeWeight(emptyValue);
|
|
88
85
|
const getDistributionDisplayAccessibleLabel = (segments, emptyValue, emptyLabel, total) => {
|
|
89
86
|
const segmentLabels = segments.map((segment) => `${segment.label ?? segment.id} ${getDerivedDistributionPercentage(segment.value, total)}%`);
|
|
90
87
|
if (emptyValue > 0) segmentLabels.push(`${emptyLabel} ${getDerivedDistributionPercentage(emptyValue, total)}%`);
|
|
@@ -95,7 +92,7 @@ const DistributionSegments = ({ emptyValue = 0, onSegmentSelect, segments, selec
|
|
|
95
92
|
children: [segments.map((segment) => {
|
|
96
93
|
const segmentStyle = {
|
|
97
94
|
"--patternmode-distribution-segment-color": segment.color,
|
|
98
|
-
width: total > 0 ? `${
|
|
95
|
+
width: total > 0 ? `${sanitizeWeight(segment.value) / total * 100}%` : "0%"
|
|
99
96
|
};
|
|
100
97
|
const isSelected = selectedSegmentId === segment.id;
|
|
101
98
|
if (onSegmentSelect) return /* @__PURE__ */ jsx("button", {
|
|
@@ -118,7 +115,7 @@ const DistributionSegments = ({ emptyValue = 0, onSegmentSelect, segments, selec
|
|
|
118
115
|
}), emptyValue > 0 ? /* @__PURE__ */ jsx("div", {
|
|
119
116
|
"aria-hidden": "true",
|
|
120
117
|
className: "patternmode-distribution-bar__segment patternmode-distribution-bar__segment--empty",
|
|
121
|
-
style: { width: total > 0 ? `${
|
|
118
|
+
style: { width: total > 0 ? `${sanitizeWeight(emptyValue) / total * 100}%` : "0%" }
|
|
122
119
|
}) : null]
|
|
123
120
|
});
|
|
124
121
|
const DistributionSegmentLegend = ({ emptyLabel, emptyValue = 0, segments, total }) => /* @__PURE__ */ jsxs("div", {
|
|
@@ -164,10 +161,15 @@ const DistributionSummaryLegend = ({ assignedLabel, emptyLabel, emptyValue, tota
|
|
|
164
161
|
] }) : null]
|
|
165
162
|
});
|
|
166
163
|
};
|
|
167
|
-
const DistributionBarHandle = ({ "aria-label": ariaLabel, boundaryPercent, onDrag, onDragEnd, onDragStart, onKeyDown }) => /* @__PURE__ */ jsx(LazyMotion, {
|
|
164
|
+
const DistributionBarHandle = ({ "aria-label": ariaLabel, "aria-valuenow": ariaValueNow, "aria-valuetext": ariaValueText, boundaryPercent, onDrag, onDragEnd, onDragStart, onKeyDown }) => /* @__PURE__ */ jsx(LazyMotion, {
|
|
168
165
|
features: domMax,
|
|
169
166
|
children: /* @__PURE__ */ jsx(m.button, {
|
|
170
167
|
"aria-label": ariaLabel,
|
|
168
|
+
"aria-orientation": "horizontal",
|
|
169
|
+
"aria-valuemax": 100,
|
|
170
|
+
"aria-valuemin": 0,
|
|
171
|
+
"aria-valuenow": ariaValueNow,
|
|
172
|
+
"aria-valuetext": ariaValueText,
|
|
171
173
|
className: "patternmode-distribution-bar__handle",
|
|
172
174
|
drag: "x",
|
|
173
175
|
dragElastic: 0,
|
|
@@ -181,7 +183,9 @@ const DistributionBarHandle = ({ "aria-label": ariaLabel, boundaryPercent, onDra
|
|
|
181
183
|
},
|
|
182
184
|
onDragStart,
|
|
183
185
|
onKeyDown,
|
|
186
|
+
role: "slider",
|
|
184
187
|
style: { left: `calc(${boundaryPercent}% - 1.375rem)` },
|
|
188
|
+
tabIndex: 0,
|
|
185
189
|
transformTemplate: () => "none",
|
|
186
190
|
type: "button"
|
|
187
191
|
})
|
|
@@ -232,12 +236,14 @@ const DistributionDisplay = ({ "aria-label": ariaLabel, assignedLabel = "assigne
|
|
|
232
236
|
const DistributionBar = ({ "aria-label": ariaLabel, className, legend = "segments", minValue = 4, onChange, segments, step = 1, ...props }) => {
|
|
233
237
|
const trackRef = useRef(null);
|
|
234
238
|
const dragStartSegmentsRef = useRef(null);
|
|
239
|
+
const [dragging, setDragging] = useState(false);
|
|
235
240
|
const total = getDistributionTotal(segments);
|
|
236
241
|
const moveBoundary = (boundaryIndex, deltaValue, sourceSegments = segments) => {
|
|
237
242
|
onChange?.(moveDistributionBoundary(sourceSegments, boundaryIndex, deltaValue, minValue));
|
|
238
243
|
};
|
|
239
244
|
const handleDragStart = () => {
|
|
240
245
|
dragStartSegmentsRef.current = segments;
|
|
246
|
+
setDragging(true);
|
|
241
247
|
};
|
|
242
248
|
const handleDrag = (boundaryIndex, info) => {
|
|
243
249
|
const sourceSegments = dragStartSegmentsRef.current ?? segments;
|
|
@@ -249,6 +255,7 @@ const DistributionBar = ({ "aria-label": ariaLabel, className, legend = "segment
|
|
|
249
255
|
const handleDragEnd = (boundaryIndex, info) => {
|
|
250
256
|
handleDrag(boundaryIndex, info);
|
|
251
257
|
dragStartSegmentsRef.current = null;
|
|
258
|
+
setDragging(false);
|
|
252
259
|
};
|
|
253
260
|
const handleKeyDown = (event, boundaryIndex) => {
|
|
254
261
|
if (event.key === "ArrowLeft") {
|
|
@@ -264,6 +271,7 @@ const DistributionBar = ({ "aria-label": ariaLabel, className, legend = "segment
|
|
|
264
271
|
...props,
|
|
265
272
|
"aria-label": ariaLabel,
|
|
266
273
|
className: joinClassNames("patternmode-distribution-bar", className),
|
|
274
|
+
"data-dragging": dragging ? "true" : void 0,
|
|
267
275
|
"data-slot": "distribution-bar",
|
|
268
276
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
269
277
|
className: "patternmode-distribution-bar__track",
|
|
@@ -274,8 +282,14 @@ const DistributionBar = ({ "aria-label": ariaLabel, className, legend = "segment
|
|
|
274
282
|
}), segments.slice(0, -1).map((segment, boundaryIndex) => {
|
|
275
283
|
const nextSegment = segments[boundaryIndex + 1];
|
|
276
284
|
const boundaryPercent = getDistributionBoundaryPercent(segments, boundaryIndex);
|
|
285
|
+
const label = `Adjust ${segment.label ?? segment.id} and ${nextSegment?.label ?? nextSegment?.id} distribution`;
|
|
286
|
+
const leftValue = sanitizeWeight(segment.value);
|
|
287
|
+
const pairTotal = leftValue + sanitizeWeight(nextSegment?.value ?? 0);
|
|
288
|
+
const leftShare = pairTotal > 0 ? Math.round(leftValue / pairTotal * 100) : 0;
|
|
277
289
|
return /* @__PURE__ */ jsx(DistributionBarHandle, {
|
|
278
|
-
"aria-label":
|
|
290
|
+
"aria-label": label,
|
|
291
|
+
"aria-valuenow": leftShare,
|
|
292
|
+
"aria-valuetext": `${segment.label ?? segment.id} ${leftShare}%, ${nextSegment?.label ?? nextSegment?.id} ${100 - leftShare}%`,
|
|
279
293
|
boundaryPercent,
|
|
280
294
|
onDrag: (info) => {
|
|
281
295
|
handleDrag(boundaryIndex, info);
|
|
@@ -356,15 +370,12 @@ const POOLS = [
|
|
|
356
370
|
* vertically. Returns `undefined` when there are no colors.
|
|
357
371
|
*/
|
|
358
372
|
const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
359
|
-
const normalizeHex$1 = (color) => {
|
|
360
|
-
const value = color.trim().replace(/^#/u, "");
|
|
361
|
-
if (/^[\da-f]{3}$/iu.test(value)) return `${value[0]}${value[0]}${value[1]}${value[1]}${value[2]}${value[2]}`;
|
|
362
|
-
if (/^[\da-f]{6}$/iu.test(value)) return value;
|
|
363
|
-
return null;
|
|
364
|
-
};
|
|
365
373
|
const withAlpha = (color, alpha) => {
|
|
366
|
-
const
|
|
367
|
-
if (
|
|
374
|
+
const rgb = hexToRgb(color);
|
|
375
|
+
if (rgb !== null) {
|
|
376
|
+
const suffix = Math.round(clamp(alpha, 0, 255)).toString(16).padStart(2, "0");
|
|
377
|
+
return `${rgbToHex(rgb.r, rgb.g, rgb.b)}${suffix}`;
|
|
378
|
+
}
|
|
368
379
|
return `color-mix(in srgb, ${color} ${Math.round(clamp(alpha, 0, 255) / 255 * 100)}%, transparent)`;
|
|
369
380
|
};
|
|
370
381
|
const getSwatchAtmosphereBackground = (colors, options = {}) => {
|
|
@@ -387,35 +398,31 @@ const getSwatchAtmosphereBackground = (colors, options = {}) => {
|
|
|
387
398
|
};
|
|
388
399
|
//#endregion
|
|
389
400
|
//#region src/Swatch/swatch-colors.ts
|
|
390
|
-
const normalizeHex = (hex) => {
|
|
391
|
-
const value = hex.trim().replace(/^#/u, "");
|
|
392
|
-
if (/^[\da-f]{3}$/iu.test(value)) return `${value[0]}${value[0]}${value[1]}${value[1]}${value[2]}${value[2]}`;
|
|
393
|
-
if (/^[\da-f]{6}$/iu.test(value)) return value;
|
|
394
|
-
return null;
|
|
395
|
-
};
|
|
396
401
|
const toColorStop = (stop) => typeof stop === "string" ? { color: stop } : stop;
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
return Number.isFinite(ratio) ? Math.max(0, ratio) : 0;
|
|
400
|
-
};
|
|
402
|
+
/** Missing ratios default to equal weight; finite/negative handling is shared. */
|
|
403
|
+
const getRatioWeight = (ratio) => ratio === void 0 ? 1 : sanitizeWeight(ratio);
|
|
401
404
|
const formatPercent = (value) => `${Number.isInteger(value) ? value : Number(value.toFixed(2))}%`;
|
|
402
|
-
const isLightColor = (color) => {
|
|
403
|
-
const normalized = normalizeHex(color);
|
|
404
|
-
if (normalized === null) return false;
|
|
405
|
-
const red = Number.parseInt(normalized.slice(0, 2), 16);
|
|
406
|
-
const green = Number.parseInt(normalized.slice(2, 4), 16);
|
|
407
|
-
const blue = Number.parseInt(normalized.slice(4, 6), 16);
|
|
408
|
-
return (.299 * red + .587 * green + .114 * blue) / 255 > .62;
|
|
409
|
-
};
|
|
410
405
|
const getSwatchColorsBackground = (colors, blend = "step") => {
|
|
411
406
|
if (colors === void 0 || colors.length === 0) return;
|
|
412
407
|
const [singleColor] = colors;
|
|
413
408
|
if (colors.length === 1 && singleColor !== void 0) return toColorStop(singleColor).color;
|
|
414
409
|
const stops = colors.map(toColorStop);
|
|
415
|
-
if (blend === "smooth")
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
410
|
+
if (blend === "smooth") {
|
|
411
|
+
const weights = stops.map((stop) => getRatioWeight(stop.ratio));
|
|
412
|
+
const weightTotal = weights.reduce((sum, weight) => sum + weight, 0);
|
|
413
|
+
const useEvenSpacing = weightTotal <= 0 || weights.every((weight) => weight === weights[0]);
|
|
414
|
+
let cursor = 0;
|
|
415
|
+
return `linear-gradient(in oklab 90deg, ${stops.map((stop, index) => {
|
|
416
|
+
let position;
|
|
417
|
+
if (useEvenSpacing) position = stops.length === 1 ? 0 : index / (stops.length - 1) * 100;
|
|
418
|
+
else {
|
|
419
|
+
const share = (weights[index] ?? 0) / weightTotal * 100;
|
|
420
|
+
position = cursor + share / 2;
|
|
421
|
+
cursor += share;
|
|
422
|
+
}
|
|
423
|
+
return `${stop.color} ${formatPercent(position)}`;
|
|
424
|
+
}).join(", ")})`;
|
|
425
|
+
}
|
|
419
426
|
const weights = stops.map((stop) => getRatioWeight(stop.ratio));
|
|
420
427
|
const rawTotal = weights.reduce((sum, ratio) => sum + ratio, 0);
|
|
421
428
|
const useEqualWeights = rawTotal <= 0;
|
|
@@ -533,7 +540,7 @@ const RemovableSwatch = ({ ariaLabel, children, className, dataProps, onRemove,
|
|
|
533
540
|
})]
|
|
534
541
|
});
|
|
535
542
|
};
|
|
536
|
-
const Swatch = ({ "aria-label": ariaLabel, asChild = false, background, blend = "step", children, className, color, colors, density, flat = false, gravity, icon: Icon, isLight, objectFit, objectPosition, onRemove, raised = false, removeLabel,
|
|
543
|
+
const Swatch = ({ "aria-label": ariaLabel, asChild = false, background, blend = "step", children, className, color, colors, density, flat = false, gravity, icon: Icon, isLight, objectFit, objectPosition, onRemove, raised = false, removeLabel, selected = false, shape = "circle", showRing = true, size = "base", style, texture, unavailable = false, ...props }) => {
|
|
537
544
|
const { colorsBackground, fill } = getSwatchFill({
|
|
538
545
|
background,
|
|
539
546
|
blend,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["clamp","normalizeHex"],"sources":["../src/DistributionBar/distribution-bar-math.ts","../src/DistributionBar/distribution-bar-root.tsx","../src/Swatch/swatch-atmosphere.ts","../src/Swatch/swatch-colors.ts","../src/Swatch/swatch-types.ts","../src/Swatch/swatch-root.tsx"],"sourcesContent":["/** Weighted segment used by DistributionBar and DistributionDisplay. */\nexport interface DistributionBarSegment {\n color: string;\n id: string;\n label?: string;\n /** Relative weight, not a persisted percentage. Invalid or negative values render as 0. */\n value: number;\n}\n\n/** Segment metadata update; weight changes happen through boundary movement. */\nexport type DistributionBarSegmentUpdate = Partial<Omit<DistributionBarSegment, \"value\">> & {\n value?: never;\n};\n\nconst sanitizeValue = (value: number): number => (Number.isFinite(value) ? Math.max(0, value) : 0);\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(Math.max(value, min), max);\n\nconst roundValue = (value: number): number => Number(value.toFixed(1));\n\n/** Sums sanitized segment weights, treating invalid or negative values as 0. */\nexport const getDistributionTotal = (segments: DistributionBarSegment[]): number =>\n segments.reduce((sum, segment) => sum + sanitizeValue(segment.value), 0);\n\n/** Returns the percentage position of the boundary after `boundaryIndex`. */\nexport const getDistributionBoundaryPercent = (\n segments: DistributionBarSegment[],\n boundaryIndex: number,\n): number => {\n const total = getDistributionTotal(segments);\n if (total <= 0) {\n return 0;\n }\n\n const boundaryValue = segments\n .slice(0, boundaryIndex + 1)\n .reduce((sum, segment) => sum + sanitizeValue(segment.value), 0);\n return roundValue((boundaryValue / total) * 100);\n};\n\n/**\n * Moves the boundary between two adjacent segments while preserving their sum.\n *\n * `deltaValue` is applied to the left segment and subtracted from the right\n * segment. `minValue` prevents either side of the pair from collapsing below a\n * caller-defined minimum.\n */\nexport const moveDistributionBoundary = (\n segments: DistributionBarSegment[],\n boundaryIndex: number,\n deltaValue: number,\n minValue: number,\n): DistributionBarSegment[] => {\n const left = segments[boundaryIndex];\n const right = segments[boundaryIndex + 1];\n if (!(left && right)) {\n return segments;\n }\n\n const pairTotal = sanitizeValue(left.value) + sanitizeValue(right.value);\n const clampedMin = Math.max(0, Math.min(minValue, pairTotal / 2));\n const nextLeft = clamp(\n sanitizeValue(left.value) + deltaValue,\n clampedMin,\n pairTotal - clampedMin,\n );\n const nextRight = pairTotal - nextLeft;\n\n return segments.map((segment, index) => {\n if (index === boundaryIndex) {\n return { ...segment, value: roundValue(nextLeft) };\n }\n if (index === boundaryIndex + 1) {\n return { ...segment, value: roundValue(nextRight) };\n }\n return segment;\n });\n};\n\n/** Removes a segment and redistributes its weight proportionally to the rest. */\nexport const removeDistributionSegment = (\n segments: DistributionBarSegment[],\n segmentId: string,\n): DistributionBarSegment[] => {\n if (segments.length <= 1) {\n return segments;\n }\n\n const removed = segments.find((segment) => segment.id === segmentId);\n if (!removed) {\n return segments;\n }\n\n const remaining = segments.filter((segment) => segment.id !== segmentId);\n const removedValue = sanitizeValue(removed.value);\n const remainingTotal = getDistributionTotal(remaining);\n if (remainingTotal <= 0) {\n const equalValue = removedValue / remaining.length;\n return remaining.map((segment) => ({\n ...segment,\n value: roundValue(equalValue),\n }));\n }\n\n let assignedValue = 0;\n const originalTotal = getDistributionTotal(segments);\n return remaining.map((segment, index) => {\n if (index === remaining.length - 1) {\n return { ...segment, value: roundValue(originalTotal - assignedValue) };\n }\n\n const nextValue = roundValue(\n sanitizeValue(segment.value) + (removedValue * sanitizeValue(segment.value)) / remainingTotal,\n );\n assignedValue += nextValue;\n return { ...segment, value: nextValue };\n });\n};\n\n/** Updates non-weight segment metadata such as label or color. */\nexport const updateDistributionSegment = (\n segments: DistributionBarSegment[],\n segmentId: string,\n update: DistributionBarSegmentUpdate,\n): DistributionBarSegment[] =>\n segments.map((segment) => (segment.id === segmentId ? { ...segment, ...update } : segment));\n","import { joinClassNames } from \"@patternmode/system\";\nimport { domMax, LazyMotion, m } from \"motion/react\";\nimport type { PanInfo } from \"motion/react\";\nimport type { CSSProperties, HTMLAttributes, KeyboardEvent } from \"react\";\nimport { useRef } from \"react\";\nimport {\n getDistributionBoundaryPercent,\n getDistributionTotal,\n moveDistributionBoundary,\n} from \"./distribution-bar-math\";\nimport type { DistributionBarSegment } from \"./distribution-bar-math\";\n\nexport interface DistributionDisplayProps extends Omit<\n HTMLAttributes<HTMLElement>,\n \"role\" | \"onSelect\"\n> {\n /** Label used in summary legends for assigned segment weight. */\n assignedLabel?: string;\n /** Label used when `emptyValue` contributes unassigned weight. */\n emptyLabel?: string;\n /**\n * Extra unassigned weight included in derived percentage calculations.\n *\n * Default `0`.\n */\n emptyValue?: number;\n /**\n * Legend style for the read-only display.\n *\n * Default `\"segments\"`.\n */\n legend?: \"segments\" | \"summary\" | false;\n /**\n * When provided, each segment renders as a button and selecting one\n * invokes this callback. Pair with `selectedSegmentId` to mark a segment\n * as selected (renders a ring). Read-only by default.\n */\n onSegmentSelect?: (segment: DistributionBarSegment) => void;\n segments: DistributionBarSegment[];\n /** Id of the selected segment — renders a ring on that segment. */\n selectedSegmentId?: string;\n}\n\nexport interface DistributionBarProps extends Omit<\n HTMLAttributes<HTMLFieldSetElement>,\n \"onChange\"\n> {\n /**\n * Show the per-segment legend below the bar, or hide it.\n *\n * Default `\"segments\"`.\n */\n legend?: \"segments\" | false;\n /**\n * Minimum weight each side of a dragged boundary must retain.\n *\n * Default `4`.\n */\n minValue?: number;\n /** Receives the full next segment list after drag or keyboard boundary moves. */\n onChange?: (segments: DistributionBarSegment[]) => void;\n /** Weighted segments; displayed percentages are derived from their total. */\n segments: DistributionBarSegment[];\n /**\n * Keyboard adjustment amount for boundary handles.\n *\n * Default `1`.\n */\n step?: number;\n}\n\ninterface DistributionSegmentsProps {\n emptyValue?: number;\n onSegmentSelect?: (segment: DistributionBarSegment) => void;\n segments: DistributionBarSegment[];\n selectedSegmentId?: string;\n total: number;\n}\n\ninterface DistributionSegmentLegendProps {\n emptyLabel?: string;\n emptyValue?: number;\n segments: DistributionBarSegment[];\n total: number;\n}\n\ninterface DistributionSummaryLegendProps {\n assignedLabel: string;\n emptyLabel: string;\n emptyValue: number;\n total: number;\n}\n\ninterface DistributionBarHandleProps {\n \"aria-label\": string;\n boundaryPercent: number;\n onDrag: (info: PanInfo) => void;\n onDragEnd: (info: PanInfo) => void;\n onDragStart: () => void;\n onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => void;\n}\n\ntype DistributionSegmentStyle = CSSProperties &\n Partial<Record<`--${string}`, number | string | undefined>>;\n\nconst getRenderableDistributionValue = (value: number): number =>\n Number.isFinite(value) ? Math.max(0, value) : 0;\n\nconst getDerivedDistributionPercentage = (value: number, total: number): number => {\n if (!(total > 0 && Number.isFinite(value))) {\n return 0;\n }\n\n return Math.round((Math.max(0, value) / total) * 100);\n};\n\nconst getDistributionDisplayTotal = (\n segments: DistributionBarSegment[],\n emptyValue: number,\n): number => getDistributionTotal(segments) + getRenderableDistributionValue(emptyValue);\n\nconst getDistributionDisplayAccessibleLabel = (\n segments: DistributionBarSegment[],\n emptyValue: number,\n emptyLabel: string,\n total: number,\n): string => {\n const segmentLabels = segments.map(\n (segment) =>\n `${segment.label ?? segment.id} ${getDerivedDistributionPercentage(segment.value, total)}%`,\n );\n if (emptyValue > 0) {\n segmentLabels.push(`${emptyLabel} ${getDerivedDistributionPercentage(emptyValue, total)}%`);\n }\n\n return segmentLabels.join(\", \");\n};\n\nconst DistributionSegments = ({\n emptyValue = 0,\n onSegmentSelect,\n segments,\n selectedSegmentId,\n total,\n}: DistributionSegmentsProps) => (\n <div className=\"patternmode-distribution-bar__segments\">\n {segments.map((segment) => {\n const segmentStyle = {\n \"--patternmode-distribution-segment-color\": segment.color,\n width:\n total > 0 ? `${(getRenderableDistributionValue(segment.value) / total) * 100}%` : \"0%\",\n } satisfies DistributionSegmentStyle;\n const isSelected = selectedSegmentId === segment.id;\n\n if (onSegmentSelect) {\n return (\n <button\n aria-label={`${segment.label ?? segment.id} ${getDerivedDistributionPercentage(segment.value, total)}%`}\n aria-pressed={isSelected}\n className=\"patternmode-distribution-bar__segment\"\n data-selected={isSelected ? \"true\" : undefined}\n key={segment.id}\n onClick={() => {\n onSegmentSelect(segment);\n }}\n style={segmentStyle}\n type=\"button\"\n />\n );\n }\n\n return (\n <div\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__segment\"\n data-selected={isSelected ? \"true\" : undefined}\n key={segment.id}\n style={segmentStyle}\n />\n );\n })}\n {emptyValue > 0 ? (\n <div\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__segment patternmode-distribution-bar__segment--empty\"\n style={{\n width:\n total > 0 ? `${(getRenderableDistributionValue(emptyValue) / total) * 100}%` : \"0%\",\n }}\n />\n ) : null}\n </div>\n);\n\nconst DistributionSegmentLegend = ({\n emptyLabel,\n emptyValue = 0,\n segments,\n total,\n}: DistributionSegmentLegendProps) => (\n <div className=\"patternmode-distribution-bar__legend\">\n {segments.map((segment) => {\n const segmentStyle = {\n \"--patternmode-distribution-segment-color\": segment.color,\n backgroundColor: undefined,\n } satisfies DistributionSegmentStyle;\n\n return (\n <span key={segment.id}>\n <span\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__swatch\"\n style={segmentStyle}\n />\n {segment.label ?? segment.id} {getDerivedDistributionPercentage(segment.value, total)}%\n </span>\n );\n })}\n {emptyValue > 0 && emptyLabel !== undefined && emptyLabel !== \"\" ? (\n <span>\n <span\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__swatch patternmode-distribution-bar__swatch--empty\"\n />\n {emptyLabel} {getDerivedDistributionPercentage(emptyValue, total)}%\n </span>\n ) : null}\n </div>\n);\n\nconst DistributionSummaryLegend = ({\n assignedLabel,\n emptyLabel,\n emptyValue,\n total,\n}: DistributionSummaryLegendProps) => {\n const emptyPercentage = getDerivedDistributionPercentage(emptyValue, total);\n\n return (\n <div className=\"patternmode-distribution-bar__legend\">\n <span>\n {Math.max(0, 100 - emptyPercentage)}% {assignedLabel}\n </span>\n {emptyValue > 0 ? (\n <span>\n {emptyPercentage}% {emptyLabel}\n </span>\n ) : null}\n </div>\n );\n};\n\nconst DistributionBarHandle = ({\n \"aria-label\": ariaLabel,\n boundaryPercent,\n onDrag,\n onDragEnd,\n onDragStart,\n onKeyDown,\n}: DistributionBarHandleProps) => (\n <LazyMotion features={domMax}>\n <m.button\n aria-label={ariaLabel}\n className=\"patternmode-distribution-bar__handle\"\n drag=\"x\"\n dragElastic={0}\n dragMomentum={false}\n dragSnapToOrigin\n onDrag={(_event, info) => {\n onDrag(info);\n }}\n onDragEnd={(_event, info) => {\n onDragEnd(info);\n }}\n onDragStart={onDragStart}\n onKeyDown={onKeyDown}\n style={{ left: `calc(${boundaryPercent}% - 1.375rem)` }}\n transformTemplate={() => \"none\"}\n type=\"button\"\n />\n </LazyMotion>\n);\n\nexport const DistributionDisplay = ({\n \"aria-label\": ariaLabel,\n assignedLabel = \"assigned\",\n className,\n emptyLabel = \"unassigned\",\n emptyValue = 0,\n legend = \"segments\",\n onSegmentSelect,\n segments,\n selectedSegmentId,\n ...props\n}: DistributionDisplayProps) => {\n const total = getDistributionDisplayTotal(segments, emptyValue);\n const interactive = Boolean(onSegmentSelect);\n const accessibleLabel =\n ariaLabel ?? getDistributionDisplayAccessibleLabel(segments, emptyValue, emptyLabel, total);\n\n const content = (\n <>\n <div className=\"patternmode-distribution-bar__track\">\n <DistributionSegments\n emptyValue={emptyValue}\n onSegmentSelect={onSegmentSelect}\n segments={segments}\n selectedSegmentId={selectedSegmentId}\n total={total}\n />\n </div>\n {legend === \"segments\" ? (\n <DistributionSegmentLegend\n emptyLabel={emptyLabel}\n emptyValue={emptyValue}\n segments={segments}\n total={total}\n />\n ) : null}\n {legend === \"summary\" ? (\n <DistributionSummaryLegend\n assignedLabel={assignedLabel}\n emptyLabel={emptyLabel}\n emptyValue={emptyValue}\n total={total}\n />\n ) : null}\n </>\n );\n const sharedClassName = joinClassNames(\"patternmode-distribution-display\", className);\n\n return interactive ? (\n <fieldset\n {...props}\n aria-label={accessibleLabel}\n className={sharedClassName}\n data-slot=\"distribution-display\"\n >\n {content}\n </fieldset>\n ) : (\n <figure\n {...props}\n aria-label={accessibleLabel}\n className={sharedClassName}\n data-slot=\"distribution-display\"\n >\n {content}\n </figure>\n );\n};\n\nexport const DistributionBar = ({\n \"aria-label\": ariaLabel,\n className,\n legend = \"segments\",\n minValue = 4,\n onChange,\n segments,\n step = 1,\n ...props\n}: DistributionBarProps) => {\n const trackRef = useRef<HTMLDivElement>(null);\n const dragStartSegmentsRef = useRef<DistributionBarSegment[] | null>(null);\n const total = getDistributionTotal(segments);\n\n const moveBoundary = (boundaryIndex: number, deltaValue: number, sourceSegments = segments) => {\n onChange?.(moveDistributionBoundary(sourceSegments, boundaryIndex, deltaValue, minValue));\n };\n\n const handleDragStart = () => {\n dragStartSegmentsRef.current = segments;\n };\n\n const handleDrag = (boundaryIndex: number, info: PanInfo) => {\n const sourceSegments = dragStartSegmentsRef.current ?? segments;\n const sourceTotal = getDistributionTotal(sourceSegments);\n const trackWidth = trackRef.current?.getBoundingClientRect().width ?? 0;\n if (!(trackWidth > 0 && sourceTotal > 0)) {\n return;\n }\n\n moveBoundary(boundaryIndex, (info.offset.x / trackWidth) * sourceTotal, sourceSegments);\n };\n\n const handleDragEnd = (boundaryIndex: number, info: PanInfo) => {\n handleDrag(boundaryIndex, info);\n dragStartSegmentsRef.current = null;\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>, boundaryIndex: number) => {\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n moveBoundary(boundaryIndex, -step);\n }\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n moveBoundary(boundaryIndex, step);\n }\n };\n\n return (\n <fieldset\n {...props}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-distribution-bar\", className)}\n data-slot=\"distribution-bar\"\n >\n <div className=\"patternmode-distribution-bar__track\" ref={trackRef}>\n <DistributionSegments segments={segments} total={total} />\n {segments.slice(0, -1).map((segment, boundaryIndex) => {\n const nextSegment = segments[boundaryIndex + 1];\n const boundaryPercent = getDistributionBoundaryPercent(segments, boundaryIndex);\n const label = `Adjust ${segment.label ?? segment.id} and ${\n nextSegment?.label ?? nextSegment?.id\n } distribution`;\n return (\n <DistributionBarHandle\n aria-label={label}\n boundaryPercent={boundaryPercent}\n key={`${segment.id}-${nextSegment?.id ?? \"end\"}`}\n onDrag={(info) => {\n handleDrag(boundaryIndex, info);\n }}\n onDragEnd={(info) => {\n handleDragEnd(boundaryIndex, info);\n }}\n onDragStart={handleDragStart}\n onKeyDown={(event) => {\n handleKeyDown(event, boundaryIndex);\n }}\n />\n );\n })}\n </div>\n {legend === \"segments\" ? (\n <DistributionSegmentLegend segments={segments} total={total} />\n ) : null}\n </fieldset>\n );\n};\n","import type { SwatchColorStop } from \"./swatch-types\";\n\nexport interface SwatchAtmosphereOptions {\n /** 0 = diffuse, wide wash · 1 = dense, tight pools. Default 0.5. */\n density?: number;\n /** -1 = grounds (pools sink) · 1 = lifts (pools rise). Default 0. */\n gravity?: number;\n}\n\n/**\n * Per-pool layout for the atmosphere fill:\n * `[focal x%, focal y%, base alpha (0-255), radius delta %, gravity sign]`.\n *\n * The first three entries reproduce the original three-pool blend identity\n * gradient exactly; further entries extend the pattern for palettes with\n * more than three colors.\n */\nconst POOLS: readonly (readonly [number, number, number, number, number])[] = [\n [30, 42, 0xcc, 0, -1],\n [72, 58, 0x99, -5, 1],\n [45, 65, 0x77, 8, -1],\n [62, 32, 0x66, 3, 1],\n [24, 72, 0x55, -3, -1],\n [80, 40, 0x44, 6, 1],\n];\n\n/**\n * Build a soft, layered radial \"atmosphere\" background from color stops — a\n * stack of overlapping elliptical pools rather than a flat or linear fill.\n * Density controls how far each pool reaches; gravity shifts the pools\n * vertically. Returns `undefined` when there are no colors.\n */\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(max, Math.max(min, value));\n\nconst normalizeHex = (color: string): string | null => {\n const value = color.trim().replace(/^#/u, \"\");\n if (/^[\\da-f]{3}$/iu.test(value)) {\n return `${value[0]}${value[0]}${value[1]}${value[1]}${value[2]}${value[2]}`;\n }\n if (/^[\\da-f]{6}$/iu.test(value)) {\n return value;\n }\n return null;\n};\n\nconst withAlpha = (color: string, alpha: number): string => {\n const hex = normalizeHex(color);\n if (hex !== null) {\n const suffix = Math.round(clamp(alpha, 0, 255))\n .toString(16)\n .padStart(2, \"0\");\n return `#${hex}${suffix}`;\n }\n const percent = Math.round((clamp(alpha, 0, 255) / 255) * 100);\n return `color-mix(in srgb, ${color} ${percent}%, transparent)`;\n};\n\nexport const getSwatchAtmosphereBackground = (\n colors: SwatchColorStop[] | undefined,\n options: SwatchAtmosphereOptions = {},\n): string | undefined => {\n if (colors === undefined || colors.length === 0) {\n return undefined;\n }\n\n const density = clamp(options.density ?? 0.5, 0, 1);\n const gravity = clamp(options.gravity ?? 0, -1, 1);\n const gy = Math.round(gravity * 8);\n const reach = Math.round(50 + (1 - density) * 15);\n\n const layers = colors.map((stop, index) => {\n const color = typeof stop === \"string\" ? stop : stop.color;\n const pool = POOLS[index % POOLS.length];\n if (pool === undefined) {\n throw new Error(\"Expected atmosphere pool to exist.\");\n }\n const [x, y, baseAlpha, radiusDelta, gravitySign] = pool;\n // Each wrap past the palette length fades the extra pools further back.\n const cycle = Math.floor(index / POOLS.length);\n const alpha = Math.max(0x22, baseAlpha - cycle * 0x22);\n const focalY = clamp(y + gravitySign * gy, 0, 100);\n const radius = Math.max(8, reach + radiusDelta);\n return `radial-gradient(ellipse at ${x}% ${focalY}%, ${withAlpha(\n color,\n alpha,\n )} 0%, transparent ${radius}%)`;\n });\n\n return layers.join(\", \");\n};\n","import type { SwatchColorStop } from \"./swatch-types\";\n\nconst normalizeHex = (hex: string): string | null => {\n const value = hex.trim().replace(/^#/u, \"\");\n if (/^[\\da-f]{3}$/iu.test(value)) {\n return `${value[0]}${value[0]}${value[1]}${value[1]}${value[2]}${value[2]}`;\n }\n if (/^[\\da-f]{6}$/iu.test(value)) {\n return value;\n }\n return null;\n};\n\nconst toColorStop = (stop: SwatchColorStop): { color: string; ratio?: number } =>\n typeof stop === \"string\" ? { color: stop } : stop;\n\nconst getRatioWeight = (ratio: number | undefined): number => {\n if (ratio === undefined) {\n return 1;\n }\n\n return Number.isFinite(ratio) ? Math.max(0, ratio) : 0;\n};\n\nconst formatPercent = (value: number): string =>\n `${Number.isInteger(value) ? value : Number(value.toFixed(2))}%`;\n\nexport const isLightColor = (color: string): boolean => {\n const normalized = normalizeHex(color);\n if (normalized === null) {\n return false;\n }\n\n const red = Number.parseInt(normalized.slice(0, 2), 16);\n const green = Number.parseInt(normalized.slice(2, 4), 16);\n const blue = Number.parseInt(normalized.slice(4, 6), 16);\n const luminance = (0.299 * red + 0.587 * green + 0.114 * blue) / 255;\n return luminance > 0.62;\n};\n\nexport const getSwatchColorsBackground = (\n colors: SwatchColorStop[] | undefined,\n blend: \"smooth\" | \"step\" = \"step\",\n): string | undefined => {\n if (colors === undefined || colors.length === 0) {\n return undefined;\n }\n\n const [singleColor] = colors;\n if (colors.length === 1 && singleColor !== undefined) {\n return toColorStop(singleColor).color;\n }\n\n const stops = colors.map(toColorStop);\n\n /* Smooth blend: one position per stop, interpolated in OKLab so ramps\n read as a continuous region of color rather than discrete bands. */\n if (blend === \"smooth\") {\n const parts = stops.map((stop, index) => {\n const position = stops.length === 1 ? 0 : (index / (stops.length - 1)) * 100;\n return `${stop.color} ${formatPercent(position)}`;\n });\n return `linear-gradient(in oklab 90deg, ${parts.join(\", \")})`;\n }\n\n const weights = stops.map((stop) => getRatioWeight(stop.ratio));\n const rawTotal = weights.reduce((sum, ratio) => sum + ratio, 0);\n const useEqualWeights = rawTotal <= 0;\n const total = useEqualWeights ? stops.length : rawTotal;\n let cursor = 0;\n const parts = stops.map((stop, index) => {\n const ratio = useEqualWeights ? 1 : (weights[index] ?? 0);\n const start = cursor;\n const end = index === stops.length - 1 ? 100 : cursor + (ratio / total) * 100;\n cursor = end;\n return `${stop.color} ${formatPercent(start)} ${formatPercent(end)}`;\n });\n\n return `linear-gradient(90deg, ${parts.join(\", \")})`;\n};\n","import { PATTERNMODE_SIZE_VALUES, PATTERNMODE_SIZES } from \"@patternmode/system\";\nimport type { ObjectFit } from \"@patternmode/system\";\nimport type { ComponentType, HTMLAttributes, ReactElement, ReactNode, SVGProps } from \"react\";\n\nexport const SWATCH_SIZES = [...PATTERNMODE_SIZES, \"4xl\", \"5xl\", \"6xl\", \"7xl\"] as const;\n\nexport const SWATCH_SIZE_VALUES = {\n ...PATTERNMODE_SIZE_VALUES,\n \"4xl\": \"4.5rem\",\n \"5xl\": \"5rem\",\n \"6xl\": \"5.5rem\",\n \"7xl\": \"6rem\",\n} as const satisfies Record<SwatchSize, string>;\n\nexport const SWATCH_SHAPES = [\"circle\", \"pill\", \"square\", \"block\"] as const;\n\nexport const SWATCH_TEXTURES = [\"atmosphere\"] as const;\n\nexport type SwatchSize = (typeof SWATCH_SIZES)[number];\nexport type SwatchShape = (typeof SWATCH_SHAPES)[number];\nexport type SwatchTexture = (typeof SWATCH_TEXTURES)[number];\nexport type SwatchColorStop = string | { color: string; ratio?: number };\ntype SwatchIcon = ComponentType<SVGProps<SVGSVGElement>>;\n\nexport const getSwatchSizeVariableStyle = (\n size: SwatchSize,\n variableName = \"--patternmode-swatch-size\",\n): Record<string, string> => ({\n [variableName]: SWATCH_SIZE_VALUES[size],\n});\n\n/**\n * Visual and behavioural props shared by every Swatch rendering mode. These\n * map deterministically to the fill, scrim, shape, and size treatment\n * regardless of whether the swatch renders its own wrapper or an `asChild`\n * element.\n */\nexport interface SwatchSharedProps extends HTMLAttributes<HTMLElement> {\n background?: string;\n color?: string;\n /**\n * How multiple `colors` blend: `\"step\"` renders hard bands, `\"smooth\"`\n * renders a continuous OKLab-interpolated ramp. Ignored by\n * `texture=\"atmosphere\"`.\n *\n * Default `\"step\"`.\n */\n blend?: \"smooth\" | \"step\";\n colors?: SwatchColorStop[];\n /**\n * Atmosphere density (0 = diffuse wash, 1 = dense pools). Only applies when\n * `texture=\"atmosphere\"`.\n *\n * Default `0.5`.\n */\n density?: number;\n /**\n * Render a precise, flat color block: no top-to-bottom scrim gradient and\n * no drop shadow. Use for data visualisation where the fill must read as\n * the exact color value.\n *\n * Default `false`.\n */\n flat?: boolean;\n /**\n * Atmosphere gravity (-1 = pools sink, 1 = pools rise). Only applies when\n * `texture=\"atmosphere\"`.\n *\n * Default `0`.\n */\n gravity?: number;\n icon?: SwatchIcon;\n isLight?: boolean;\n /**\n * Object-fit mode applied to media children through CSS variables.\n *\n * Default `\"cover\"`.\n */\n objectFit?: ObjectFit;\n /**\n * Object-position value applied to media children through CSS variables.\n *\n * Default `\"center\"`.\n */\n objectPosition?: string;\n raised?: boolean;\n /**\n * Shows selected state and optional icon overlay.\n *\n * Default `false`.\n */\n selected?: boolean;\n /**\n * Rendered swatch shape.\n *\n * Default `\"circle\"`.\n */\n shape?: SwatchShape;\n /**\n * Whether selected swatches render their ring treatment.\n *\n * Default `true`.\n */\n showRing?: boolean;\n /**\n * Size token used for the swatch dimensions.\n *\n * Default `\"base\"`.\n */\n size?: SwatchSize;\n /**\n * Render supplied colors as a soft, layered radial atmosphere — overlapping\n * color pools — instead of a ratio-encoded weighted palette. Pair with\n * `density` and `gravity` to shape the pools.\n */\n texture?: SwatchTexture;\n /**\n * Marks the swatch as unavailable.\n *\n * Default `false`.\n */\n unavailable?: boolean;\n}\n\n/**\n * Default Swatch props: the swatch renders its own wrapper element\n * (`<figure>`, or `<fieldset>` when `onRemove` is set).\n */\nexport interface SwatchDefaultProps extends SwatchSharedProps {\n /**\n * Render the swatch styling onto a provided child element instead of an\n * own wrapper. See {@link SwatchAsChildProps}.\n *\n * Default `false`.\n */\n asChild?: false;\n /**\n * Optional media rendered inside the swatch frame.\n *\n * Swatch does not optimize image elements itself. Next.js consumers can pass\n * their own `next/image` `Image` component here and use `objectFit` /\n * `objectPosition` to align it with the swatch shape.\n */\n children?: ReactNode;\n /** Renders a remove affordance and calls this after stopping propagation. */\n onRemove?: () => void;\n /** Accessible label for the remove affordance. Defaults to the swatch label. */\n removeLabel?: string;\n}\n\n/**\n * `asChild` Swatch props: the swatch merges its className, style (size/fill\n * CSS variables), data attributes, and other props onto the single React\n * element passed as `children`, rendering through it (Radix Slot pattern)\n * instead of emitting its own wrapper. Use this when the swatch must *be* an\n * interactive element, such as a `<button>` cell in a color matrix.\n *\n * `onRemove` is unsupported in this mode — its remove affordance cannot be\n * composed into an arbitrary slotted element. Wrap a default Swatch instead\n * when a remove control is required.\n */\nexport interface SwatchAsChildProps extends SwatchSharedProps {\n asChild: true;\n /** The single element the swatch styling is merged onto and rendered through. */\n children: ReactElement;\n onRemove?: never;\n removeLabel?: never;\n}\n\nexport type SwatchProps = SwatchDefaultProps | SwatchAsChildProps;\n","import { getObjectSizingStyle, joinClassNames } from \"@patternmode/system\";\nimport { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport type { CSSProperties, HTMLAttributes, MouseEvent, ReactNode } from \"react\";\n\nimport { getSwatchAtmosphereBackground } from \"./swatch-atmosphere\";\nimport { getSwatchColorsBackground, isLightColor } from \"./swatch-colors\";\nimport { getSwatchSizeVariableStyle } from \"./swatch-types\";\nimport type { SwatchProps } from \"./swatch-types\";\n\ntype SwatchRootStyle = CSSProperties & Record<\"--patternmode-swatch-fill\", string | undefined>;\n\ninterface SwatchContentProps {\n children: SwatchProps[\"children\"];\n flat: boolean;\n Icon: SwatchProps[\"icon\"];\n mediaStyle: CSSProperties;\n selected: boolean;\n unavailable: boolean;\n}\n\ninterface RemovableSwatchProps {\n ariaLabel: string | undefined;\n children: ReactNode;\n className: string | undefined;\n dataProps: ReturnType<typeof getSwatchDataProps>;\n onRemove: () => void;\n removeLabel: string;\n rootStyle: SwatchRootStyle;\n props: HTMLAttributes<HTMLElement>;\n}\n\nconst SwatchContent = ({\n children,\n flat,\n Icon,\n mediaStyle,\n selected,\n unavailable,\n}: SwatchContentProps) => (\n <>\n <span aria-hidden=\"true\" className=\"patternmode-swatch__fill\" />\n {children !== undefined && children !== null ? (\n <span className=\"patternmode-swatch__media\" style={mediaStyle}>\n {children}\n </span>\n ) : null}\n {flat ? null : <span aria-hidden=\"true\" className=\"patternmode-swatch__scrim\" />}\n {selected && Icon ? (\n <span className=\"patternmode-swatch__icon\">\n <Icon aria-hidden=\"true\" focusable=\"false\" />\n </span>\n ) : null}\n {unavailable ? <span aria-hidden=\"true\" className=\"patternmode-swatch__slash\" /> : null}\n </>\n);\n\nconst getSwatchFill = ({\n background,\n blend,\n color,\n colors,\n density,\n gravity,\n texture,\n}: Pick<SwatchProps, \"background\" | \"blend\" | \"color\" | \"colors\" | \"density\" | \"gravity\" | \"texture\">) => {\n const colorsBackground = getSwatchColorsBackground(colors, blend);\n const atmosphereBackground =\n texture === \"atmosphere\"\n ? getSwatchAtmosphereBackground(colors, { density, gravity })\n : undefined;\n\n return {\n colorsBackground,\n fill: background ?? atmosphereBackground ?? colorsBackground ?? color,\n };\n};\n\nconst getSwatchTone = ({\n background,\n color,\n colorsBackground,\n isLight,\n}: {\n background: SwatchProps[\"background\"];\n color: SwatchProps[\"color\"];\n colorsBackground: string | undefined;\n isLight: SwatchProps[\"isLight\"];\n}) => {\n if (isLight !== undefined) {\n return isLight ? \"light\" : \"dark\";\n }\n\n const hasColor = color !== undefined && color !== \"\";\n const hasBackground = background !== undefined && background !== \"\";\n const hasColorsBackground = colorsBackground !== undefined && colorsBackground !== \"\";\n\n if (hasColor && !hasBackground && !hasColorsBackground && isLightColor(color)) {\n return \"light\";\n }\n\n return \"dark\";\n};\n\nconst getSwatchDataProps = ({\n flat,\n lightTone,\n raised,\n selected,\n shape,\n showRing,\n size,\n unavailable,\n}: {\n flat: boolean;\n lightTone: \"dark\" | \"light\";\n raised: boolean;\n selected: boolean;\n shape: SwatchProps[\"shape\"];\n showRing: boolean;\n size: SwatchProps[\"size\"];\n unavailable: boolean;\n}) => ({\n \"data-flat\": flat ? \"true\" : undefined,\n \"data-raised\": raised ? \"true\" : undefined,\n \"data-selected\": selected ? \"true\" : undefined,\n \"data-shape\": shape,\n \"data-show-ring\": showRing ? \"true\" : \"false\",\n \"data-size\": size,\n \"data-slot\": \"swatch\",\n \"data-tone\": lightTone,\n \"data-unavailable\": unavailable ? \"true\" : undefined,\n});\n\nconst RemovableSwatch = ({\n ariaLabel,\n children,\n className,\n dataProps,\n onRemove,\n removeLabel,\n rootStyle,\n props,\n}: RemovableSwatchProps) => {\n const handleRemove = (event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n onRemove();\n };\n\n return (\n <fieldset\n {...props}\n {...dataProps}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\n style={rootStyle}\n >\n {children}\n <button\n aria-label={removeLabel}\n className=\"patternmode-swatch__remove\"\n onClick={handleRemove}\n type=\"button\"\n >\n <svg aria-hidden=\"true\" fill=\"none\" viewBox=\"0 0 20 20\">\n <path d=\"M5.5 5.5l9 9M14.5 5.5l-9 9\" />\n </svg>\n </button>\n </fieldset>\n );\n};\n\nexport const Swatch = ({\n \"aria-label\": ariaLabel,\n asChild = false,\n background,\n blend = \"step\",\n children,\n className,\n color,\n colors,\n density,\n flat = false,\n gravity,\n icon: Icon,\n isLight,\n objectFit,\n objectPosition,\n onRemove,\n raised = false,\n removeLabel,\n role: _role,\n selected = false,\n shape = \"circle\",\n showRing = true,\n size = \"base\",\n style,\n texture,\n unavailable = false,\n ...props\n}: SwatchProps) => {\n const { colorsBackground, fill } = getSwatchFill({\n background,\n blend,\n color,\n colors,\n density,\n gravity,\n texture,\n });\n const lightTone = getSwatchTone({\n background,\n color,\n colorsBackground,\n isLight,\n });\n const resolvedRemoveLabel =\n removeLabel ?? (ariaLabel !== undefined && ariaLabel !== \"\" ? `Remove ${ariaLabel}` : \"Remove\");\n\n const rootStyle: SwatchRootStyle = {\n ...getSwatchSizeVariableStyle(size),\n \"--patternmode-swatch-fill\": fill,\n ...style,\n };\n const mediaStyle: CSSProperties = getObjectSizingStyle({\n fit: objectFit,\n position: objectPosition,\n });\n const dataProps = getSwatchDataProps({\n flat,\n lightTone,\n raised,\n selected,\n shape,\n showRing,\n size,\n unavailable,\n });\n\n const swatchContent = (\n <SwatchContent\n flat={flat}\n Icon={Icon}\n mediaStyle={mediaStyle}\n selected={selected}\n unavailable={unavailable}\n >\n {asChild ? undefined : children}\n </SwatchContent>\n );\n\n if (asChild) {\n return (\n <Slot\n {...props}\n {...dataProps}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\n style={rootStyle}\n >\n {swatchContent}\n <Slottable>{children}</Slottable>\n </Slot>\n );\n }\n\n if (onRemove !== undefined) {\n return (\n <RemovableSwatch\n ariaLabel={ariaLabel}\n className={className}\n dataProps={dataProps}\n onRemove={onRemove}\n props={props}\n removeLabel={resolvedRemoveLabel}\n rootStyle={rootStyle}\n >\n {swatchContent}\n </RemovableSwatch>\n );\n }\n\n return (\n <figure\n {...props}\n {...dataProps}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\n style={rootStyle}\n >\n {swatchContent}\n </figure>\n );\n};\n"],"mappings":";;;;;;AAcA,MAAM,iBAAiB,UAA2B,OAAO,SAAS,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI;AAEhG,MAAMA,WAAS,OAAe,KAAa,QACzC,KAAK,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG,GAAG;AAEpC,MAAM,cAAc,UAA0B,OAAO,MAAM,QAAQ,CAAC,CAAC;;AAGrE,MAAa,wBAAwB,aACnC,SAAS,QAAQ,KAAK,YAAY,MAAM,cAAc,QAAQ,KAAK,GAAG,CAAC;;AAGzE,MAAa,kCACX,UACA,kBACW;CACX,MAAM,QAAQ,qBAAqB,QAAQ;CAC3C,IAAI,SAAS,GACX,OAAO;CAMT,OAAO,WAHe,SACnB,MAAM,GAAG,gBAAgB,CAAC,EAC1B,QAAQ,KAAK,YAAY,MAAM,cAAc,QAAQ,KAAK,GAAG,CACjC,IAAI,QAAS,GAAG;AACjD;;;;;;;;AASA,MAAa,4BACX,UACA,eACA,YACA,aAC6B;CAC7B,MAAM,OAAO,SAAS;CACtB,MAAM,QAAQ,SAAS,gBAAgB;CACvC,IAAI,EAAE,QAAQ,QACZ,OAAO;CAGT,MAAM,YAAY,cAAc,KAAK,KAAK,IAAI,cAAc,MAAM,KAAK;CACvE,MAAM,aAAa,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,YAAY,CAAC,CAAC;CAChE,MAAM,WAAWA,QACf,cAAc,KAAK,KAAK,IAAI,YAC5B,YACA,YAAY,UACd;CACA,MAAM,YAAY,YAAY;CAE9B,OAAO,SAAS,KAAK,SAAS,UAAU;EACtC,IAAI,UAAU,eACZ,OAAO;GAAE,GAAG;GAAS,OAAO,WAAW,QAAQ;EAAE;EAEnD,IAAI,UAAU,gBAAgB,GAC5B,OAAO;GAAE,GAAG;GAAS,OAAO,WAAW,SAAS;EAAE;EAEpD,OAAO;CACT,CAAC;AACH;;AAGA,MAAa,6BACX,UACA,cAC6B;CAC7B,IAAI,SAAS,UAAU,GACrB,OAAO;CAGT,MAAM,UAAU,SAAS,MAAM,YAAY,QAAQ,OAAO,SAAS;CACnE,IAAI,CAAC,SACH,OAAO;CAGT,MAAM,YAAY,SAAS,QAAQ,YAAY,QAAQ,OAAO,SAAS;CACvE,MAAM,eAAe,cAAc,QAAQ,KAAK;CAChD,MAAM,iBAAiB,qBAAqB,SAAS;CACrD,IAAI,kBAAkB,GAAG;EACvB,MAAM,aAAa,eAAe,UAAU;EAC5C,OAAO,UAAU,KAAK,aAAa;GACjC,GAAG;GACH,OAAO,WAAW,UAAU;EAC9B,EAAE;CACJ;CAEA,IAAI,gBAAgB;CACpB,MAAM,gBAAgB,qBAAqB,QAAQ;CACnD,OAAO,UAAU,KAAK,SAAS,UAAU;EACvC,IAAI,UAAU,UAAU,SAAS,GAC/B,OAAO;GAAE,GAAG;GAAS,OAAO,WAAW,gBAAgB,aAAa;EAAE;EAGxE,MAAM,YAAY,WAChB,cAAc,QAAQ,KAAK,IAAK,eAAe,cAAc,QAAQ,KAAK,IAAK,cACjF;EACA,iBAAiB;EACjB,OAAO;GAAE,GAAG;GAAS,OAAO;EAAU;CACxC,CAAC;AACH;;AAGA,MAAa,6BACX,UACA,WACA,WAEA,SAAS,KAAK,YAAa,QAAQ,OAAO,YAAY;CAAE,GAAG;CAAS,GAAG;AAAO,IAAI,OAAQ;;;ACrB5F,MAAM,kCAAkC,UACtC,OAAO,SAAS,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI;AAEhD,MAAM,oCAAoC,OAAe,UAA0B;CACjF,IAAI,EAAE,QAAQ,KAAK,OAAO,SAAS,KAAK,IACtC,OAAO;CAGT,OAAO,KAAK,MAAO,KAAK,IAAI,GAAG,KAAK,IAAI,QAAS,GAAG;AACtD;AAEA,MAAM,+BACJ,UACA,eACW,qBAAqB,QAAQ,IAAI,+BAA+B,UAAU;AAEvF,MAAM,yCACJ,UACA,YACA,YACA,UACW;CACX,MAAM,gBAAgB,SAAS,KAC5B,YACC,GAAG,QAAQ,SAAS,QAAQ,GAAG,GAAG,iCAAiC,QAAQ,OAAO,KAAK,EAAE,EAC7F;CACA,IAAI,aAAa,GACf,cAAc,KAAK,GAAG,WAAW,GAAG,iCAAiC,YAAY,KAAK,EAAE,EAAE;CAG5F,OAAO,cAAc,KAAK,IAAI;AAChC;AAEA,MAAM,wBAAwB,EAC5B,aAAa,GACb,iBACA,UACA,mBACA,YAEA,qBAAC,OAAD;CAAK,WAAU;WAAf,CACG,SAAS,KAAK,YAAY;EACzB,MAAM,eAAe;GACnB,4CAA4C,QAAQ;GACpD,OACE,QAAQ,IAAI,GAAI,+BAA+B,QAAQ,KAAK,IAAI,QAAS,IAAI,KAAK;EACtF;EACA,MAAM,aAAa,sBAAsB,QAAQ;EAEjD,IAAI,iBACF,OACE,oBAAC,UAAD;GACE,cAAY,GAAG,QAAQ,SAAS,QAAQ,GAAG,GAAG,iCAAiC,QAAQ,OAAO,KAAK,EAAE;GACrG,gBAAc;GACd,WAAU;GACV,iBAAe,aAAa,SAAS,KAAA;GAErC,eAAe;IACb,gBAAgB,OAAO;GACzB;GACA,OAAO;GACP,MAAK;EACN,GANM,QAAQ,EAMd;EAIL,OACE,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,iBAAe,aAAa,SAAS,KAAA;GAErC,OAAO;EACR,GAFM,QAAQ,EAEd;CAEL,CAAC,GACA,aAAa,IACZ,oBAAC,OAAD;EACE,eAAY;EACZ,WAAU;EACV,OAAO,EACL,OACE,QAAQ,IAAI,GAAI,+BAA+B,UAAU,IAAI,QAAS,IAAI,KAAK,KACnF;CACD,CAAA,IACC,IACD;;AAGP,MAAM,6BAA6B,EACjC,YACA,aAAa,GACb,UACA,YAEA,qBAAC,OAAD;CAAK,WAAU;WAAf,CACG,SAAS,KAAK,YAAY;EAMzB,OACE,qBAAC,QAAD,EAAA,UAAA;GACE,oBAAC,QAAD;IACE,eAAY;IACZ,WAAU;IACV,OAAO;KATX,4CAA4C,QAAQ;KACpD,iBAAiB,KAAA;IAQK;GACnB,CAAA;GACA,QAAQ,SAAS,QAAQ;GAAG;GAAE,iCAAiC,QAAQ,OAAO,KAAK;GAAE;EAClF,EAAA,GAPK,QAAQ,EAOb;CAEV,CAAC,GACA,aAAa,KAAK,eAAe,KAAA,KAAa,eAAe,KAC5D,qBAAC,QAAD,EAAA,UAAA;EACE,oBAAC,QAAD;GACE,eAAY;GACZ,WAAU;EACX,CAAA;EACA;EAAW;EAAE,iCAAiC,YAAY,KAAK;EAAE;CAC9D,EAAA,CAAA,IACJ,IACD;;AAGP,MAAM,6BAA6B,EACjC,eACA,YACA,YACA,YACoC;CACpC,MAAM,kBAAkB,iCAAiC,YAAY,KAAK;CAE1E,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,QAAD,EAAA,UAAA;GACG,KAAK,IAAI,GAAG,MAAM,eAAe;GAAE;GAAG;EACnC,EAAA,CAAA,GACL,aAAa,IACZ,qBAAC,QAAD,EAAA,UAAA;GACG;GAAgB;GAAG;EAChB,EAAA,CAAA,IACJ,IACD;;AAET;AAEA,MAAM,yBAAyB,EAC7B,cAAc,WACd,iBACA,QACA,WACA,aACA,gBAEA,oBAAC,YAAD;CAAY,UAAU;WACpB,oBAAC,EAAE,QAAH;EACE,cAAY;EACZ,WAAU;EACV,MAAK;EACL,aAAa;EACb,cAAc;EACd,kBAAA;EACA,SAAS,QAAQ,SAAS;GACxB,OAAO,IAAI;EACb;EACA,YAAY,QAAQ,SAAS;GAC3B,UAAU,IAAI;EAChB;EACa;EACF;EACX,OAAO,EAAE,MAAM,QAAQ,gBAAgB,eAAe;EACtD,yBAAyB;EACzB,MAAK;CACN,CAAA;AACS,CAAA;AAGd,MAAa,uBAAuB,EAClC,cAAc,WACd,gBAAgB,YAChB,WACA,aAAa,cACb,aAAa,GACb,SAAS,YACT,iBACA,UACA,mBACA,GAAG,YAC2B;CAC9B,MAAM,QAAQ,4BAA4B,UAAU,UAAU;CAC9D,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,kBACJ,aAAa,sCAAsC,UAAU,YAAY,YAAY,KAAK;CAE5F,MAAM,UACJ,qBAAA,UAAA,EAAA,UAAA;EACE,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,sBAAD;IACc;IACK;IACP;IACS;IACZ;GACR,CAAA;EACE,CAAA;EACJ,WAAW,aACV,oBAAC,2BAAD;GACc;GACA;GACF;GACH;EACR,CAAA,IACC;EACH,WAAW,YACV,oBAAC,2BAAD;GACiB;GACH;GACA;GACL;EACR,CAAA,IACC;CACJ,EAAA,CAAA;CAEJ,MAAM,kBAAkB,eAAe,oCAAoC,SAAS;CAEpF,OAAO,cACL,oBAAC,YAAD;EACE,GAAI;EACJ,cAAY;EACZ,WAAW;EACX,aAAU;YAET;CACO,CAAA,IAEV,oBAAC,UAAD;EACE,GAAI;EACJ,cAAY;EACZ,WAAW;EACX,aAAU;YAET;CACK,CAAA;AAEZ;AAEA,MAAa,mBAAmB,EAC9B,cAAc,WACd,WACA,SAAS,YACT,WAAW,GACX,UACA,UACA,OAAO,GACP,GAAG,YACuB;CAC1B,MAAM,WAAW,OAAuB,IAAI;CAC5C,MAAM,uBAAuB,OAAwC,IAAI;CACzE,MAAM,QAAQ,qBAAqB,QAAQ;CAE3C,MAAM,gBAAgB,eAAuB,YAAoB,iBAAiB,aAAa;EAC7F,WAAW,yBAAyB,gBAAgB,eAAe,YAAY,QAAQ,CAAC;CAC1F;CAEA,MAAM,wBAAwB;EAC5B,qBAAqB,UAAU;CACjC;CAEA,MAAM,cAAc,eAAuB,SAAkB;EAC3D,MAAM,iBAAiB,qBAAqB,WAAW;EACvD,MAAM,cAAc,qBAAqB,cAAc;EACvD,MAAM,aAAa,SAAS,SAAS,sBAAsB,EAAE,SAAS;EACtE,IAAI,EAAE,aAAa,KAAK,cAAc,IACpC;EAGF,aAAa,eAAgB,KAAK,OAAO,IAAI,aAAc,aAAa,cAAc;CACxF;CAEA,MAAM,iBAAiB,eAAuB,SAAkB;EAC9D,WAAW,eAAe,IAAI;EAC9B,qBAAqB,UAAU;CACjC;CAEA,MAAM,iBAAiB,OAAyC,kBAA0B;EACxF,IAAI,MAAM,QAAQ,aAAa;GAC7B,MAAM,eAAe;GACrB,aAAa,eAAe,CAAC,IAAI;EACnC;EACA,IAAI,MAAM,QAAQ,cAAc;GAC9B,MAAM,eAAe;GACrB,aAAa,eAAe,IAAI;EAClC;CACF;CAEA,OACE,qBAAC,YAAD;EACE,GAAI;EACJ,cAAY;EACZ,WAAW,eAAe,gCAAgC,SAAS;EACnE,aAAU;YAJZ,CAME,qBAAC,OAAD;GAAK,WAAU;GAAsC,KAAK;aAA1D,CACE,oBAAC,sBAAD;IAAgC;IAAiB;GAAQ,CAAA,GACxD,SAAS,MAAM,GAAG,EAAE,EAAE,KAAK,SAAS,kBAAkB;IACrD,MAAM,cAAc,SAAS,gBAAgB;IAC7C,MAAM,kBAAkB,+BAA+B,UAAU,aAAa;IAI9E,OACE,oBAAC,uBAAD;KACE,cAAY,UALQ,QAAQ,SAAS,QAAQ,GAAG,OAClD,aAAa,SAAS,aAAa,GACpC;KAIoB;KAEjB,SAAS,SAAS;MAChB,WAAW,eAAe,IAAI;KAChC;KACA,YAAY,SAAS;MACnB,cAAc,eAAe,IAAI;KACnC;KACA,aAAa;KACb,YAAY,UAAU;MACpB,cAAc,OAAO,aAAa;KACpC;IACD,GAXM,GAAG,QAAQ,GAAG,GAAG,aAAa,MAAM,OAW1C;GAEL,CAAC,CACE;MACJ,WAAW,aACV,oBAAC,2BAAD;GAAqC;GAAiB;EAAQ,CAAA,IAC5D,IACI;;AAEd;;;;;;;;;;;ACvaA,MAAM,QAAwE;CAC5E;EAAC;EAAI;EAAI;EAAM;EAAG;CAAE;CACpB;EAAC;EAAI;EAAI;EAAM;EAAI;CAAC;CACpB;EAAC;EAAI;EAAI;EAAM;EAAG;CAAE;CACpB;EAAC;EAAI;EAAI;EAAM;EAAG;CAAC;CACnB;EAAC;EAAI;EAAI;EAAM;EAAI;CAAE;CACrB;EAAC;EAAI;EAAI;EAAM;EAAG;CAAC;AACrB;;;;;;;AASA,MAAM,SAAS,OAAe,KAAa,QACzC,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAEpC,MAAMC,kBAAgB,UAAiC;CACrD,MAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,OAAO,EAAE;CAC5C,IAAI,iBAAiB,KAAK,KAAK,GAC7B,OAAO,GAAG,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM;CAEzE,IAAI,iBAAiB,KAAK,KAAK,GAC7B,OAAO;CAET,OAAO;AACT;AAEA,MAAM,aAAa,OAAe,UAA0B;CAC1D,MAAM,MAAMA,eAAa,KAAK;CAC9B,IAAI,QAAQ,MAIV,OAAO,IAAI,MAHI,KAAK,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,EAC3C,SAAS,EAAE,EACX,SAAS,GAAG,GACO;CAGxB,OAAO,sBAAsB,MAAM,GADnB,KAAK,MAAO,MAAM,OAAO,GAAG,GAAG,IAAI,MAAO,GACd,EAAE;AAChD;AAEA,MAAa,iCACX,QACA,UAAmC,CAAC,MACb;CACvB,IAAI,WAAW,KAAA,KAAa,OAAO,WAAW,GAC5C;CAGF,MAAM,UAAU,MAAM,QAAQ,WAAW,IAAK,GAAG,CAAC;CAClD,MAAM,UAAU,MAAM,QAAQ,WAAW,GAAG,IAAI,CAAC;CACjD,MAAM,KAAK,KAAK,MAAM,UAAU,CAAC;CACjC,MAAM,QAAQ,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE;CAoBhD,OAlBe,OAAO,KAAK,MAAM,UAAU;EACzC,MAAM,QAAQ,OAAO,SAAS,WAAW,OAAO,KAAK;EACrD,MAAM,OAAO,MAAM,QAAQ,MAAM;EACjC,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,MAAM,oCAAoC;EAEtD,MAAM,CAAC,GAAG,GAAG,WAAW,aAAa,eAAe;EAEpD,MAAM,QAAQ,KAAK,MAAM,QAAQ,MAAM,MAAM;EAC7C,MAAM,QAAQ,KAAK,IAAI,IAAM,YAAY,QAAQ,EAAI;EACrD,MAAM,SAAS,MAAM,IAAI,cAAc,IAAI,GAAG,GAAG;EACjD,MAAM,SAAS,KAAK,IAAI,GAAG,QAAQ,WAAW;EAC9C,OAAO,8BAA8B,EAAE,IAAI,OAAO,KAAK,UACrD,OACA,KACF,EAAE,mBAAmB,OAAO;CAC9B,CAEY,EAAE,KAAK,IAAI;AACzB;;;ACzFA,MAAM,gBAAgB,QAA+B;CACnD,MAAM,QAAQ,IAAI,KAAK,EAAE,QAAQ,OAAO,EAAE;CAC1C,IAAI,iBAAiB,KAAK,KAAK,GAC7B,OAAO,GAAG,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM;CAEzE,IAAI,iBAAiB,KAAK,KAAK,GAC7B,OAAO;CAET,OAAO;AACT;AAEA,MAAM,eAAe,SACnB,OAAO,SAAS,WAAW,EAAE,OAAO,KAAK,IAAI;AAE/C,MAAM,kBAAkB,UAAsC;CAC5D,IAAI,UAAU,KAAA,GACZ,OAAO;CAGT,OAAO,OAAO,SAAS,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI;AACvD;AAEA,MAAM,iBAAiB,UACrB,GAAG,OAAO,UAAU,KAAK,IAAI,QAAQ,OAAO,MAAM,QAAQ,CAAC,CAAC,EAAE;AAEhE,MAAa,gBAAgB,UAA2B;CACtD,MAAM,aAAa,aAAa,KAAK;CACrC,IAAI,eAAe,MACjB,OAAO;CAGT,MAAM,MAAM,OAAO,SAAS,WAAW,MAAM,GAAG,CAAC,GAAG,EAAE;CACtD,MAAM,QAAQ,OAAO,SAAS,WAAW,MAAM,GAAG,CAAC,GAAG,EAAE;CACxD,MAAM,OAAO,OAAO,SAAS,WAAW,MAAM,GAAG,CAAC,GAAG,EAAE;CAEvD,QADmB,OAAQ,MAAM,OAAQ,QAAQ,OAAQ,QAAQ,MAC9C;AACrB;AAEA,MAAa,6BACX,QACA,QAA2B,WACJ;CACvB,IAAI,WAAW,KAAA,KAAa,OAAO,WAAW,GAC5C;CAGF,MAAM,CAAC,eAAe;CACtB,IAAI,OAAO,WAAW,KAAK,gBAAgB,KAAA,GACzC,OAAO,YAAY,WAAW,EAAE;CAGlC,MAAM,QAAQ,OAAO,IAAI,WAAW;CAIpC,IAAI,UAAU,UAKZ,OAAO,mCAJO,MAAM,KAAK,MAAM,UAAU;EACvC,MAAM,WAAW,MAAM,WAAW,IAAI,IAAK,SAAS,MAAM,SAAS,KAAM;EACzE,OAAO,GAAG,KAAK,MAAM,GAAG,cAAc,QAAQ;CAChD,CAC8C,EAAE,KAAK,IAAI,EAAE;CAG7D,MAAM,UAAU,MAAM,KAAK,SAAS,eAAe,KAAK,KAAK,CAAC;CAC9D,MAAM,WAAW,QAAQ,QAAQ,KAAK,UAAU,MAAM,OAAO,CAAC;CAC9D,MAAM,kBAAkB,YAAY;CACpC,MAAM,QAAQ,kBAAkB,MAAM,SAAS;CAC/C,IAAI,SAAS;CASb,OAAO,0BARO,MAAM,KAAK,MAAM,UAAU;EACvC,MAAM,QAAQ,kBAAkB,IAAK,QAAQ,UAAU;EACvD,MAAM,QAAQ;EACd,MAAM,MAAM,UAAU,MAAM,SAAS,IAAI,MAAM,SAAU,QAAQ,QAAS;EAC1E,SAAS;EACT,OAAO,GAAG,KAAK,MAAM,GAAG,cAAc,KAAK,EAAE,GAAG,cAAc,GAAG;CACnE,CAEqC,EAAE,KAAK,IAAI,EAAE;AACpD;;;AC3EA,MAAa,eAAe;CAAC,GAAG;CAAmB;CAAO;CAAO;CAAO;AAAK;AAE7E,MAAa,qBAAqB;CAChC,GAAG;CACH,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;AACT;AAEA,MAAa,gBAAgB;CAAC;CAAU;CAAQ;CAAU;AAAO;AAEjE,MAAa,kBAAkB,CAAC,YAAY;AAQ5C,MAAa,8BACX,MACA,eAAe,iCACa,GAC3B,eAAe,mBAAmB,MACrC;;;ACEA,MAAM,iBAAiB,EACrB,UACA,MACA,MACA,YACA,UACA,kBAEA,qBAAA,UAAA,EAAA,UAAA;CACE,oBAAC,QAAD;EAAM,eAAY;EAAO,WAAU;CAA4B,CAAA;CAC9D,aAAa,KAAA,KAAa,aAAa,OACtC,oBAAC,QAAD;EAAM,WAAU;EAA4B,OAAO;EAChD;CACG,CAAA,IACJ;CACH,OAAO,OAAO,oBAAC,QAAD;EAAM,eAAY;EAAO,WAAU;CAA6B,CAAA;CAC9E,YAAY,OACX,oBAAC,QAAD;EAAM,WAAU;YACd,oBAAC,MAAD;GAAM,eAAY;GAAO,WAAU;EAAS,CAAA;CACxC,CAAA,IACJ;CACH,cAAc,oBAAC,QAAD;EAAM,eAAY;EAAO,WAAU;CAA6B,CAAA,IAAI;AACnF,EAAA,CAAA;AAGJ,MAAM,iBAAiB,EACrB,YACA,OACA,OACA,QACA,SACA,SACA,cACwG;CACxG,MAAM,mBAAmB,0BAA0B,QAAQ,KAAK;CAChE,MAAM,uBACJ,YAAY,eACR,8BAA8B,QAAQ;EAAE;EAAS;CAAQ,CAAC,IAC1D,KAAA;CAEN,OAAO;EACL;EACA,MAAM,cAAc,wBAAwB,oBAAoB;CAClE;AACF;AAEA,MAAM,iBAAiB,EACrB,YACA,OACA,kBACA,cAMI;CACJ,IAAI,YAAY,KAAA,GACd,OAAO,UAAU,UAAU;CAO7B,IAJiB,UAAU,KAAA,KAAa,UAAU,MAIlC,EAHM,eAAe,KAAA,KAAa,eAAe,OAG/B,EAFN,qBAAqB,KAAA,KAAa,qBAAqB,OAEzB,aAAa,KAAK,GAC1E,OAAO;CAGT,OAAO;AACT;AAEA,MAAM,sBAAsB,EAC1B,MACA,WACA,QACA,UACA,OACA,UACA,MACA,mBAUK;CACL,aAAa,OAAO,SAAS,KAAA;CAC7B,eAAe,SAAS,SAAS,KAAA;CACjC,iBAAiB,WAAW,SAAS,KAAA;CACrC,cAAc;CACd,kBAAkB,WAAW,SAAS;CACtC,aAAa;CACb,aAAa;CACb,aAAa;CACb,oBAAoB,cAAc,SAAS,KAAA;AAC7C;AAEA,MAAM,mBAAmB,EACvB,WACA,UACA,WACA,WACA,UACA,aACA,WACA,YAC0B;CAC1B,MAAM,gBAAgB,UAAyC;EAC7D,MAAM,gBAAgB;EACtB,SAAS;CACX;CAEA,OACE,qBAAC,YAAD;EACE,GAAI;EACJ,GAAI;EACJ,cAAY;EACZ,WAAW,eAAe,sBAAsB,SAAS;EACzD,OAAO;YALT,CAOG,UACD,oBAAC,UAAD;GACE,cAAY;GACZ,WAAU;GACV,SAAS;GACT,MAAK;aAEL,oBAAC,OAAD;IAAK,eAAY;IAAO,MAAK;IAAO,SAAQ;cAC1C,oBAAC,QAAD,EAAM,GAAE,6BAA8B,CAAA;GACnC,CAAA;EACC,CAAA,CACA;;AAEd;AAEA,MAAa,UAAU,EACrB,cAAc,WACd,UAAU,OACV,YACA,QAAQ,QACR,UACA,WACA,OACA,QACA,SACA,OAAO,OACP,SACA,MAAM,MACN,SACA,WACA,gBACA,UACA,SAAS,OACT,aACA,MAAM,OACN,WAAW,OACX,QAAQ,UACR,WAAW,MACX,OAAO,QACP,OACA,SACA,cAAc,OACd,GAAG,YACc;CACjB,MAAM,EAAE,kBAAkB,SAAS,cAAc;EAC/C;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,YAAY,cAAc;EAC9B;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,sBACJ,gBAAgB,cAAc,KAAA,KAAa,cAAc,KAAK,UAAU,cAAc;CAExF,MAAM,YAA6B;EACjC,GAAG,2BAA2B,IAAI;EAClC,6BAA6B;EAC7B,GAAG;CACL;CACA,MAAM,aAA4B,qBAAqB;EACrD,KAAK;EACL,UAAU;CACZ,CAAC;CACD,MAAM,YAAY,mBAAmB;EACnC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,gBACJ,oBAAC,eAAD;EACQ;EACA;EACM;EACF;EACG;YAEZ,UAAU,KAAA,IAAY;CACV,CAAA;CAGjB,IAAI,SACF,OACE,qBAAC,MAAD;EACE,GAAI;EACJ,GAAI;EACJ,cAAY;EACZ,WAAW,eAAe,sBAAsB,SAAS;EACzD,OAAO;YALT,CAOG,eACD,oBAAC,WAAD,EAAY,SAAoB,CAAA,CAC5B;;CAIV,IAAI,aAAa,KAAA,GACf,OACE,oBAAC,iBAAD;EACa;EACA;EACA;EACD;EACH;EACP,aAAa;EACF;YAEV;CACc,CAAA;CAIrB,OACE,oBAAC,UAAD;EACE,GAAI;EACJ,GAAI;EACJ,cAAY;EACZ,WAAW,eAAe,sBAAsB,SAAS;EACzD,OAAO;YAEN;CACK,CAAA;AAEZ"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["clamp"],"sources":["../src/DistributionBar/distribution-bar-math.ts","../src/DistributionBar/distribution-bar-root.tsx","../src/Swatch/swatch-atmosphere.ts","../src/Swatch/swatch-colors.ts","../src/Swatch/swatch-types.ts","../src/Swatch/swatch-root.tsx"],"sourcesContent":["import { sanitizeWeight } from \"@patternmode/system\";\nimport type { WeightedColorSegment } from \"@patternmode/system\";\n\n/**\n * Weighted segment used by DistributionBar and DistributionDisplay. Extends the\n * shared {@link WeightedColorSegment} with a required stable `id` for editing.\n */\nexport interface DistributionBarSegment extends WeightedColorSegment {\n id: string;\n}\n\n/** Segment metadata update; weight changes happen through boundary movement. */\nexport type DistributionBarSegmentUpdate = Partial<Omit<DistributionBarSegment, \"value\">> & {\n value?: never;\n};\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(Math.max(value, min), max);\n\nconst roundValue = (value: number): number => Number(value.toFixed(1));\n\n/** Sums sanitized segment weights, treating invalid or negative values as 0. */\nexport const getDistributionTotal = (segments: DistributionBarSegment[]): number =>\n segments.reduce((sum, segment) => sum + sanitizeWeight(segment.value), 0);\n\n/** Returns the percentage position of the boundary after `boundaryIndex`. */\nexport const getDistributionBoundaryPercent = (\n segments: DistributionBarSegment[],\n boundaryIndex: number,\n): number => {\n const total = getDistributionTotal(segments);\n if (total <= 0) {\n return 0;\n }\n\n const boundaryValue = segments\n .slice(0, boundaryIndex + 1)\n .reduce((sum, segment) => sum + sanitizeWeight(segment.value), 0);\n return roundValue((boundaryValue / total) * 100);\n};\n\n/**\n * Moves the boundary between two adjacent segments while preserving their sum.\n *\n * `deltaValue` is applied to the left segment and subtracted from the right\n * segment. `minValue` prevents either side of the pair from collapsing below a\n * caller-defined minimum.\n */\nexport const moveDistributionBoundary = (\n segments: DistributionBarSegment[],\n boundaryIndex: number,\n deltaValue: number,\n minValue: number,\n): DistributionBarSegment[] => {\n const left = segments[boundaryIndex];\n const right = segments[boundaryIndex + 1];\n if (!(left && right)) {\n return segments;\n }\n\n const pairTotal = sanitizeWeight(left.value) + sanitizeWeight(right.value);\n const clampedMin = Math.max(0, Math.min(minValue, pairTotal / 2));\n const nextLeft = clamp(\n sanitizeWeight(left.value) + deltaValue,\n clampedMin,\n pairTotal - clampedMin,\n );\n const nextRight = pairTotal - nextLeft;\n\n return segments.map((segment, index) => {\n if (index === boundaryIndex) {\n return { ...segment, value: roundValue(nextLeft) };\n }\n if (index === boundaryIndex + 1) {\n return { ...segment, value: roundValue(nextRight) };\n }\n return segment;\n });\n};\n\n/** Removes a segment and redistributes its weight proportionally to the rest. */\nexport const removeDistributionSegment = (\n segments: DistributionBarSegment[],\n segmentId: string,\n): DistributionBarSegment[] => {\n if (segments.length <= 1) {\n return segments;\n }\n\n const removed = segments.find((segment) => segment.id === segmentId);\n if (!removed) {\n return segments;\n }\n\n const remaining = segments.filter((segment) => segment.id !== segmentId);\n const removedValue = sanitizeWeight(removed.value);\n const remainingTotal = getDistributionTotal(remaining);\n if (remainingTotal <= 0) {\n const equalValue = removedValue / remaining.length;\n return remaining.map((segment) => ({\n ...segment,\n value: roundValue(equalValue),\n }));\n }\n\n let assignedValue = 0;\n const originalTotal = getDistributionTotal(segments);\n return remaining.map((segment, index) => {\n if (index === remaining.length - 1) {\n return { ...segment, value: roundValue(originalTotal - assignedValue) };\n }\n\n const nextValue = roundValue(\n sanitizeWeight(segment.value) +\n (removedValue * sanitizeWeight(segment.value)) / remainingTotal,\n );\n assignedValue += nextValue;\n return { ...segment, value: nextValue };\n });\n};\n\n/** Updates non-weight segment metadata such as label or color. */\nexport const updateDistributionSegment = (\n segments: DistributionBarSegment[],\n segmentId: string,\n update: DistributionBarSegmentUpdate,\n): DistributionBarSegment[] =>\n segments.map((segment) => (segment.id === segmentId ? { ...segment, ...update } : segment));\n","import { joinClassNames, sanitizeWeight } from \"@patternmode/system\";\nimport { domMax, LazyMotion, m } from \"motion/react\";\nimport type { PanInfo } from \"motion/react\";\nimport type { CSSProperties, HTMLAttributes, KeyboardEvent } from \"react\";\nimport { useRef, useState } from \"react\";\nimport {\n getDistributionBoundaryPercent,\n getDistributionTotal,\n moveDistributionBoundary,\n} from \"./distribution-bar-math\";\nimport type { DistributionBarSegment } from \"./distribution-bar-math\";\n\nexport interface DistributionDisplayProps extends Omit<\n HTMLAttributes<HTMLElement>,\n \"role\" | \"onSelect\"\n> {\n /** Label used in summary legends for assigned segment weight. */\n assignedLabel?: string;\n /** Label used when `emptyValue` contributes unassigned weight. */\n emptyLabel?: string;\n /**\n * Extra unassigned weight included in derived percentage calculations.\n *\n * Default `0`.\n */\n emptyValue?: number;\n /**\n * Legend style for the read-only display.\n *\n * Default `\"segments\"`.\n */\n legend?: \"segments\" | \"summary\" | false;\n /**\n * When provided, each segment renders as a button and selecting one\n * invokes this callback. Pair with `selectedSegmentId` to mark a segment\n * as selected (renders a ring). Read-only by default.\n */\n onSegmentSelect?: (segment: DistributionBarSegment) => void;\n segments: DistributionBarSegment[];\n /** Id of the selected segment — renders a ring on that segment. */\n selectedSegmentId?: string;\n}\n\nexport interface DistributionBarProps extends Omit<\n HTMLAttributes<HTMLFieldSetElement>,\n \"onChange\"\n> {\n /**\n * Show the per-segment legend below the bar, or hide it.\n *\n * Default `\"segments\"`.\n */\n legend?: \"segments\" | false;\n /**\n * Minimum weight each side of a dragged boundary must retain.\n *\n * Default `4`.\n */\n minValue?: number;\n /** Receives the full next segment list after drag or keyboard boundary moves. */\n onChange?: (segments: DistributionBarSegment[]) => void;\n /** Weighted segments; displayed percentages are derived from their total. */\n segments: DistributionBarSegment[];\n /**\n * Keyboard adjustment amount for boundary handles.\n *\n * Default `1`.\n */\n step?: number;\n}\n\ninterface DistributionSegmentsProps {\n emptyValue?: number;\n onSegmentSelect?: (segment: DistributionBarSegment) => void;\n segments: DistributionBarSegment[];\n selectedSegmentId?: string;\n total: number;\n}\n\ninterface DistributionSegmentLegendProps {\n emptyLabel?: string;\n emptyValue?: number;\n segments: DistributionBarSegment[];\n total: number;\n}\n\ninterface DistributionSummaryLegendProps {\n assignedLabel: string;\n emptyLabel: string;\n emptyValue: number;\n total: number;\n}\n\ninterface DistributionBarHandleProps {\n \"aria-label\": string;\n \"aria-valuenow\": number;\n \"aria-valuetext\": string;\n boundaryPercent: number;\n onDrag: (info: PanInfo) => void;\n onDragEnd: (info: PanInfo) => void;\n onDragStart: () => void;\n onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => void;\n}\n\ntype DistributionSegmentStyle = CSSProperties &\n Partial<Record<`--${string}`, number | string | undefined>>;\n\nconst getDerivedDistributionPercentage = (value: number, total: number): number =>\n total > 0 ? Math.round((sanitizeWeight(value) / total) * 100) : 0;\n\nconst getDistributionDisplayTotal = (\n segments: DistributionBarSegment[],\n emptyValue: number,\n): number => getDistributionTotal(segments) + sanitizeWeight(emptyValue);\n\nconst getDistributionDisplayAccessibleLabel = (\n segments: DistributionBarSegment[],\n emptyValue: number,\n emptyLabel: string,\n total: number,\n): string => {\n const segmentLabels = segments.map(\n (segment) =>\n `${segment.label ?? segment.id} ${getDerivedDistributionPercentage(segment.value, total)}%`,\n );\n if (emptyValue > 0) {\n segmentLabels.push(`${emptyLabel} ${getDerivedDistributionPercentage(emptyValue, total)}%`);\n }\n\n return segmentLabels.join(\", \");\n};\n\nconst DistributionSegments = ({\n emptyValue = 0,\n onSegmentSelect,\n segments,\n selectedSegmentId,\n total,\n}: DistributionSegmentsProps) => (\n <div className=\"patternmode-distribution-bar__segments\">\n {segments.map((segment) => {\n const segmentStyle = {\n \"--patternmode-distribution-segment-color\": segment.color,\n width: total > 0 ? `${(sanitizeWeight(segment.value) / total) * 100}%` : \"0%\",\n } satisfies DistributionSegmentStyle;\n const isSelected = selectedSegmentId === segment.id;\n\n if (onSegmentSelect) {\n return (\n <button\n aria-label={`${segment.label ?? segment.id} ${getDerivedDistributionPercentage(segment.value, total)}%`}\n aria-pressed={isSelected}\n className=\"patternmode-distribution-bar__segment\"\n data-selected={isSelected ? \"true\" : undefined}\n key={segment.id}\n onClick={() => {\n onSegmentSelect(segment);\n }}\n style={segmentStyle}\n type=\"button\"\n />\n );\n }\n\n return (\n <div\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__segment\"\n data-selected={isSelected ? \"true\" : undefined}\n key={segment.id}\n style={segmentStyle}\n />\n );\n })}\n {emptyValue > 0 ? (\n <div\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__segment patternmode-distribution-bar__segment--empty\"\n style={{\n width: total > 0 ? `${(sanitizeWeight(emptyValue) / total) * 100}%` : \"0%\",\n }}\n />\n ) : null}\n </div>\n);\n\nconst DistributionSegmentLegend = ({\n emptyLabel,\n emptyValue = 0,\n segments,\n total,\n}: DistributionSegmentLegendProps) => (\n <div className=\"patternmode-distribution-bar__legend\">\n {segments.map((segment) => {\n const segmentStyle = {\n \"--patternmode-distribution-segment-color\": segment.color,\n backgroundColor: undefined,\n } satisfies DistributionSegmentStyle;\n\n return (\n <span key={segment.id}>\n <span\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__swatch\"\n style={segmentStyle}\n />\n {segment.label ?? segment.id} {getDerivedDistributionPercentage(segment.value, total)}%\n </span>\n );\n })}\n {emptyValue > 0 && emptyLabel !== undefined && emptyLabel !== \"\" ? (\n <span>\n <span\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__swatch patternmode-distribution-bar__swatch--empty\"\n />\n {emptyLabel} {getDerivedDistributionPercentage(emptyValue, total)}%\n </span>\n ) : null}\n </div>\n);\n\nconst DistributionSummaryLegend = ({\n assignedLabel,\n emptyLabel,\n emptyValue,\n total,\n}: DistributionSummaryLegendProps) => {\n const emptyPercentage = getDerivedDistributionPercentage(emptyValue, total);\n\n return (\n <div className=\"patternmode-distribution-bar__legend\">\n <span>\n {Math.max(0, 100 - emptyPercentage)}% {assignedLabel}\n </span>\n {emptyValue > 0 ? (\n <span>\n {emptyPercentage}% {emptyLabel}\n </span>\n ) : null}\n </div>\n );\n};\n\nconst DistributionBarHandle = ({\n \"aria-label\": ariaLabel,\n \"aria-valuenow\": ariaValueNow,\n \"aria-valuetext\": ariaValueText,\n boundaryPercent,\n onDrag,\n onDragEnd,\n onDragStart,\n onKeyDown,\n}: DistributionBarHandleProps) => (\n <LazyMotion features={domMax}>\n <m.button\n aria-label={ariaLabel}\n aria-orientation=\"horizontal\"\n aria-valuemax={100}\n aria-valuemin={0}\n aria-valuenow={ariaValueNow}\n aria-valuetext={ariaValueText}\n className=\"patternmode-distribution-bar__handle\"\n drag=\"x\"\n dragElastic={0}\n dragMomentum={false}\n dragSnapToOrigin\n onDrag={(_event, info) => {\n onDrag(info);\n }}\n onDragEnd={(_event, info) => {\n onDragEnd(info);\n }}\n onDragStart={onDragStart}\n onKeyDown={onKeyDown}\n role=\"slider\"\n style={{ left: `calc(${boundaryPercent}% - 1.375rem)` }}\n tabIndex={0}\n transformTemplate={() => \"none\"}\n type=\"button\"\n />\n </LazyMotion>\n);\n\nexport const DistributionDisplay = ({\n \"aria-label\": ariaLabel,\n assignedLabel = \"assigned\",\n className,\n emptyLabel = \"unassigned\",\n emptyValue = 0,\n legend = \"segments\",\n onSegmentSelect,\n segments,\n selectedSegmentId,\n ...props\n}: DistributionDisplayProps) => {\n const total = getDistributionDisplayTotal(segments, emptyValue);\n const interactive = Boolean(onSegmentSelect);\n const accessibleLabel =\n ariaLabel ?? getDistributionDisplayAccessibleLabel(segments, emptyValue, emptyLabel, total);\n\n const content = (\n <>\n <div className=\"patternmode-distribution-bar__track\">\n <DistributionSegments\n emptyValue={emptyValue}\n onSegmentSelect={onSegmentSelect}\n segments={segments}\n selectedSegmentId={selectedSegmentId}\n total={total}\n />\n </div>\n {legend === \"segments\" ? (\n <DistributionSegmentLegend\n emptyLabel={emptyLabel}\n emptyValue={emptyValue}\n segments={segments}\n total={total}\n />\n ) : null}\n {legend === \"summary\" ? (\n <DistributionSummaryLegend\n assignedLabel={assignedLabel}\n emptyLabel={emptyLabel}\n emptyValue={emptyValue}\n total={total}\n />\n ) : null}\n </>\n );\n const sharedClassName = joinClassNames(\"patternmode-distribution-display\", className);\n\n return interactive ? (\n <fieldset\n {...props}\n aria-label={accessibleLabel}\n className={sharedClassName}\n data-slot=\"distribution-display\"\n >\n {content}\n </fieldset>\n ) : (\n <figure\n {...props}\n aria-label={accessibleLabel}\n className={sharedClassName}\n data-slot=\"distribution-display\"\n >\n {content}\n </figure>\n );\n};\n\nexport const DistributionBar = ({\n \"aria-label\": ariaLabel,\n className,\n legend = \"segments\",\n minValue = 4,\n onChange,\n segments,\n step = 1,\n ...props\n}: DistributionBarProps) => {\n const trackRef = useRef<HTMLDivElement>(null);\n const dragStartSegmentsRef = useRef<DistributionBarSegment[] | null>(null);\n const [dragging, setDragging] = useState(false);\n const total = getDistributionTotal(segments);\n\n const moveBoundary = (boundaryIndex: number, deltaValue: number, sourceSegments = segments) => {\n onChange?.(moveDistributionBoundary(sourceSegments, boundaryIndex, deltaValue, minValue));\n };\n\n const handleDragStart = () => {\n dragStartSegmentsRef.current = segments;\n setDragging(true);\n };\n\n const handleDrag = (boundaryIndex: number, info: PanInfo) => {\n const sourceSegments = dragStartSegmentsRef.current ?? segments;\n const sourceTotal = getDistributionTotal(sourceSegments);\n const trackWidth = trackRef.current?.getBoundingClientRect().width ?? 0;\n if (!(trackWidth > 0 && sourceTotal > 0)) {\n return;\n }\n\n moveBoundary(boundaryIndex, (info.offset.x / trackWidth) * sourceTotal, sourceSegments);\n };\n\n const handleDragEnd = (boundaryIndex: number, info: PanInfo) => {\n handleDrag(boundaryIndex, info);\n dragStartSegmentsRef.current = null;\n setDragging(false);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>, boundaryIndex: number) => {\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n moveBoundary(boundaryIndex, -step);\n }\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n moveBoundary(boundaryIndex, step);\n }\n };\n\n return (\n <fieldset\n {...props}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-distribution-bar\", className)}\n data-dragging={dragging ? \"true\" : undefined}\n data-slot=\"distribution-bar\"\n >\n <div className=\"patternmode-distribution-bar__track\" ref={trackRef}>\n <DistributionSegments segments={segments} total={total} />\n {segments.slice(0, -1).map((segment, boundaryIndex) => {\n const nextSegment = segments[boundaryIndex + 1];\n const boundaryPercent = getDistributionBoundaryPercent(segments, boundaryIndex);\n const label = `Adjust ${segment.label ?? segment.id} and ${\n nextSegment?.label ?? nextSegment?.id\n } distribution`;\n const leftValue = sanitizeWeight(segment.value);\n const rightValue = sanitizeWeight(nextSegment?.value ?? 0);\n const pairTotal = leftValue + rightValue;\n /* Slider value: the left segment's share of the adjacent pair, so\n arrow keys and drags read as moving weight between neighbours. */\n const leftShare = pairTotal > 0 ? Math.round((leftValue / pairTotal) * 100) : 0;\n const valueText = `${segment.label ?? segment.id} ${leftShare}%, ${\n nextSegment?.label ?? nextSegment?.id\n } ${100 - leftShare}%`;\n return (\n <DistributionBarHandle\n aria-label={label}\n aria-valuenow={leftShare}\n aria-valuetext={valueText}\n boundaryPercent={boundaryPercent}\n key={`${segment.id}-${nextSegment?.id ?? \"end\"}`}\n onDrag={(info) => {\n handleDrag(boundaryIndex, info);\n }}\n onDragEnd={(info) => {\n handleDragEnd(boundaryIndex, info);\n }}\n onDragStart={handleDragStart}\n onKeyDown={(event) => {\n handleKeyDown(event, boundaryIndex);\n }}\n />\n );\n })}\n </div>\n {legend === \"segments\" ? (\n <DistributionSegmentLegend segments={segments} total={total} />\n ) : null}\n </fieldset>\n );\n};\n","import { hexToRgb, rgbToHex } from \"@instruments/colorscope/convert\";\n\nimport type { SwatchColorStop } from \"./swatch-types\";\n\nexport interface SwatchAtmosphereOptions {\n /** 0 = diffuse, wide wash · 1 = dense, tight pools. Default 0.5. */\n density?: number;\n /** -1 = grounds (pools sink) · 1 = lifts (pools rise). Default 0. */\n gravity?: number;\n}\n\n/**\n * Per-pool layout for the atmosphere fill:\n * `[focal x%, focal y%, base alpha (0-255), radius delta %, gravity sign]`.\n *\n * The first three entries reproduce the original three-pool blend identity\n * gradient exactly; further entries extend the pattern for palettes with\n * more than three colors.\n */\nconst POOLS: readonly (readonly [number, number, number, number, number])[] = [\n [30, 42, 0xcc, 0, -1],\n [72, 58, 0x99, -5, 1],\n [45, 65, 0x77, 8, -1],\n [62, 32, 0x66, 3, 1],\n [24, 72, 0x55, -3, -1],\n [80, 40, 0x44, 6, 1],\n];\n\n/**\n * Build a soft, layered radial \"atmosphere\" background from color stops — a\n * stack of overlapping elliptical pools rather than a flat or linear fill.\n * Density controls how far each pool reaches; gravity shifts the pools\n * vertically. Returns `undefined` when there are no colors.\n */\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(max, Math.max(min, value));\n\nconst withAlpha = (color: string, alpha: number): string => {\n const rgb = hexToRgb(color);\n if (rgb !== null) {\n const suffix = Math.round(clamp(alpha, 0, 255))\n .toString(16)\n .padStart(2, \"0\");\n return `${rgbToHex(rgb.r, rgb.g, rgb.b)}${suffix}`;\n }\n const percent = Math.round((clamp(alpha, 0, 255) / 255) * 100);\n return `color-mix(in srgb, ${color} ${percent}%, transparent)`;\n};\n\nexport const getSwatchAtmosphereBackground = (\n colors: SwatchColorStop[] | undefined,\n options: SwatchAtmosphereOptions = {},\n): string | undefined => {\n if (colors === undefined || colors.length === 0) {\n return undefined;\n }\n\n const density = clamp(options.density ?? 0.5, 0, 1);\n const gravity = clamp(options.gravity ?? 0, -1, 1);\n const gy = Math.round(gravity * 8);\n const reach = Math.round(50 + (1 - density) * 15);\n\n const layers = colors.map((stop, index) => {\n const color = typeof stop === \"string\" ? stop : stop.color;\n const pool = POOLS[index % POOLS.length];\n if (pool === undefined) {\n throw new Error(\"Expected atmosphere pool to exist.\");\n }\n const [x, y, baseAlpha, radiusDelta, gravitySign] = pool;\n // Each wrap past the palette length fades the extra pools further back.\n const cycle = Math.floor(index / POOLS.length);\n const alpha = Math.max(0x22, baseAlpha - cycle * 0x22);\n const focalY = clamp(y + gravitySign * gy, 0, 100);\n const radius = Math.max(8, reach + radiusDelta);\n return `radial-gradient(ellipse at ${x}% ${focalY}%, ${withAlpha(\n color,\n alpha,\n )} 0%, transparent ${radius}%)`;\n });\n\n return layers.join(\", \");\n};\n","import { sanitizeWeight } from \"@patternmode/system\";\n\nimport type { SwatchColorStop } from \"./swatch-types\";\n\nconst toColorStop = (stop: SwatchColorStop): { color: string; ratio?: number } =>\n typeof stop === \"string\" ? { color: stop } : stop;\n\n/** Missing ratios default to equal weight; finite/negative handling is shared. */\nconst getRatioWeight = (ratio: number | undefined): number =>\n ratio === undefined ? 1 : sanitizeWeight(ratio);\n\nconst formatPercent = (value: number): string =>\n `${Number.isInteger(value) ? value : Number(value.toFixed(2))}%`;\n\nexport const getSwatchColorsBackground = (\n colors: SwatchColorStop[] | undefined,\n blend: \"smooth\" | \"step\" = \"step\",\n): string | undefined => {\n if (colors === undefined || colors.length === 0) {\n return undefined;\n }\n\n const [singleColor] = colors;\n if (colors.length === 1 && singleColor !== undefined) {\n return toColorStop(singleColor).color;\n }\n\n const stops = colors.map(toColorStop);\n\n /* Smooth blend: one position per stop, interpolated in OKLab so ramps\n read as a continuous region of color rather than discrete bands. Each\n stop sits at the cumulative midpoint of its ratio share (a 90/10 palette\n centers at 45% and 95%), so weighted palettes still read proportionally.\n Equal, missing, or all-zero ratios fall back to even spacing. */\n if (blend === \"smooth\") {\n const weights = stops.map((stop) => getRatioWeight(stop.ratio));\n const weightTotal = weights.reduce((sum, weight) => sum + weight, 0);\n const useEvenSpacing = weightTotal <= 0 || weights.every((weight) => weight === weights[0]);\n let cursor = 0;\n const parts = stops.map((stop, index) => {\n let position: number;\n if (useEvenSpacing) {\n position = stops.length === 1 ? 0 : (index / (stops.length - 1)) * 100;\n } else {\n const share = ((weights[index] ?? 0) / weightTotal) * 100;\n position = cursor + share / 2;\n cursor += share;\n }\n return `${stop.color} ${formatPercent(position)}`;\n });\n return `linear-gradient(in oklab 90deg, ${parts.join(\", \")})`;\n }\n\n const weights = stops.map((stop) => getRatioWeight(stop.ratio));\n const rawTotal = weights.reduce((sum, ratio) => sum + ratio, 0);\n const useEqualWeights = rawTotal <= 0;\n const total = useEqualWeights ? stops.length : rawTotal;\n let cursor = 0;\n const parts = stops.map((stop, index) => {\n const ratio = useEqualWeights ? 1 : (weights[index] ?? 0);\n const start = cursor;\n const end = index === stops.length - 1 ? 100 : cursor + (ratio / total) * 100;\n cursor = end;\n return `${stop.color} ${formatPercent(start)} ${formatPercent(end)}`;\n });\n\n return `linear-gradient(90deg, ${parts.join(\", \")})`;\n};\n","import { PATTERNMODE_SIZE_VALUES, PATTERNMODE_SIZES } from \"@patternmode/system\";\nimport type { ObjectFit } from \"@patternmode/system\";\nimport type { ComponentType, HTMLAttributes, ReactElement, ReactNode, SVGProps } from \"react\";\n\nexport const SWATCH_SIZES = [...PATTERNMODE_SIZES, \"4xl\", \"5xl\", \"6xl\", \"7xl\"] as const;\n\nexport const SWATCH_SIZE_VALUES = {\n ...PATTERNMODE_SIZE_VALUES,\n \"4xl\": \"4.5rem\",\n \"5xl\": \"5rem\",\n \"6xl\": \"5.5rem\",\n \"7xl\": \"6rem\",\n} as const satisfies Record<SwatchSize, string>;\n\nexport const SWATCH_SHAPES = [\"circle\", \"pill\", \"square\", \"block\"] as const;\n\nexport const SWATCH_TEXTURES = [\"atmosphere\"] as const;\n\nexport type SwatchSize = (typeof SWATCH_SIZES)[number];\nexport type SwatchShape = (typeof SWATCH_SHAPES)[number];\nexport type SwatchTexture = (typeof SWATCH_TEXTURES)[number];\nexport type SwatchColorStop = string | { color: string; ratio?: number };\ntype SwatchIcon = ComponentType<SVGProps<SVGSVGElement>>;\n\nexport const getSwatchSizeVariableStyle = (\n size: SwatchSize,\n variableName = \"--patternmode-swatch-size\",\n): Record<string, string> => ({\n [variableName]: SWATCH_SIZE_VALUES[size],\n});\n\n/**\n * Visual and behavioural props shared by every Swatch rendering mode. These\n * map deterministically to the fill, scrim, shape, and size treatment\n * regardless of whether the swatch renders its own wrapper or an `asChild`\n * element.\n */\nexport interface SwatchSharedProps extends HTMLAttributes<HTMLElement> {\n background?: string;\n color?: string;\n /**\n * How multiple `colors` blend: `\"step\"` renders hard bands, `\"smooth\"`\n * renders a continuous OKLab-interpolated ramp. Ignored by\n * `texture=\"atmosphere\"`.\n *\n * Default `\"step\"`.\n */\n blend?: \"smooth\" | \"step\";\n colors?: SwatchColorStop[];\n /**\n * Atmosphere density (0 = diffuse wash, 1 = dense pools). Only applies when\n * `texture=\"atmosphere\"`.\n *\n * Default `0.5`.\n */\n density?: number;\n /**\n * Render a precise, flat color block: no top-to-bottom scrim gradient and\n * no drop shadow. Use for data visualisation where the fill must read as\n * the exact color value.\n *\n * Default `false`.\n */\n flat?: boolean;\n /**\n * Atmosphere gravity (-1 = pools sink, 1 = pools rise). Only applies when\n * `texture=\"atmosphere\"`.\n *\n * Default `0`.\n */\n gravity?: number;\n icon?: SwatchIcon;\n isLight?: boolean;\n /**\n * Object-fit mode applied to media children through CSS variables.\n *\n * Default `\"cover\"`.\n */\n objectFit?: ObjectFit;\n /**\n * Object-position value applied to media children through CSS variables.\n *\n * Default `\"center\"`.\n */\n objectPosition?: string;\n raised?: boolean;\n /**\n * Shows selected state and optional icon overlay.\n *\n * Default `false`.\n */\n selected?: boolean;\n /**\n * Rendered swatch shape.\n *\n * Default `\"circle\"`.\n */\n shape?: SwatchShape;\n /**\n * Whether selected swatches render their ring treatment.\n *\n * Default `true`.\n */\n showRing?: boolean;\n /**\n * Size token used for the swatch dimensions.\n *\n * Default `\"base\"`.\n */\n size?: SwatchSize;\n /**\n * Render supplied colors as a soft, layered radial atmosphere — overlapping\n * color pools — instead of a ratio-encoded weighted palette. Pair with\n * `density` and `gravity` to shape the pools.\n */\n texture?: SwatchTexture;\n /**\n * Marks the swatch as unavailable.\n *\n * Default `false`.\n */\n unavailable?: boolean;\n}\n\n/**\n * Default Swatch props: the swatch renders its own wrapper element\n * (`<figure>`, or `<fieldset>` when `onRemove` is set).\n */\nexport interface SwatchDefaultProps extends SwatchSharedProps {\n /**\n * Render the swatch styling onto a provided child element instead of an\n * own wrapper. See {@link SwatchAsChildProps}.\n *\n * Default `false`.\n */\n asChild?: false;\n /**\n * Optional media rendered inside the swatch frame.\n *\n * Swatch does not optimize image elements itself. Next.js consumers can pass\n * their own `next/image` `Image` component here and use `objectFit` /\n * `objectPosition` to align it with the swatch shape.\n */\n children?: ReactNode;\n /** Renders a remove affordance and calls this after stopping propagation. */\n onRemove?: () => void;\n /** Accessible label for the remove affordance. Defaults to the swatch label. */\n removeLabel?: string;\n}\n\n/**\n * `asChild` Swatch props: the swatch merges its className, style (size/fill\n * CSS variables), data attributes, and other props onto the single React\n * element passed as `children`, rendering through it (Radix Slot pattern)\n * instead of emitting its own wrapper. Use this when the swatch must *be* an\n * interactive element, such as a `<button>` cell in a color matrix.\n *\n * `onRemove` is unsupported in this mode — its remove affordance cannot be\n * composed into an arbitrary slotted element. Wrap a default Swatch instead\n * when a remove control is required.\n */\nexport interface SwatchAsChildProps extends SwatchSharedProps {\n asChild: true;\n /** The single element the swatch styling is merged onto and rendered through. */\n children: ReactElement;\n onRemove?: never;\n removeLabel?: never;\n}\n\nexport type SwatchProps = SwatchDefaultProps | SwatchAsChildProps;\n","import { getObjectSizingStyle, isLightColor, joinClassNames } from \"@patternmode/system\";\nimport { Slot, Slottable } from \"@radix-ui/react-slot\";\nimport type { CSSProperties, HTMLAttributes, MouseEvent, ReactNode } from \"react\";\n\nimport { getSwatchAtmosphereBackground } from \"./swatch-atmosphere\";\nimport { getSwatchColorsBackground } from \"./swatch-colors\";\nimport { getSwatchSizeVariableStyle } from \"./swatch-types\";\nimport type { SwatchProps } from \"./swatch-types\";\n\ntype SwatchRootStyle = CSSProperties & Record<\"--patternmode-swatch-fill\", string | undefined>;\n\ninterface SwatchContentProps {\n children: SwatchProps[\"children\"];\n flat: boolean;\n Icon: SwatchProps[\"icon\"];\n mediaStyle: CSSProperties;\n selected: boolean;\n unavailable: boolean;\n}\n\ninterface RemovableSwatchProps {\n ariaLabel: string | undefined;\n children: ReactNode;\n className: string | undefined;\n dataProps: ReturnType<typeof getSwatchDataProps>;\n onRemove: () => void;\n removeLabel: string;\n rootStyle: SwatchRootStyle;\n props: HTMLAttributes<HTMLElement>;\n}\n\nconst SwatchContent = ({\n children,\n flat,\n Icon,\n mediaStyle,\n selected,\n unavailable,\n}: SwatchContentProps) => (\n <>\n <span aria-hidden=\"true\" className=\"patternmode-swatch__fill\" />\n {children !== undefined && children !== null ? (\n <span className=\"patternmode-swatch__media\" style={mediaStyle}>\n {children}\n </span>\n ) : null}\n {flat ? null : <span aria-hidden=\"true\" className=\"patternmode-swatch__scrim\" />}\n {selected && Icon ? (\n <span className=\"patternmode-swatch__icon\">\n <Icon aria-hidden=\"true\" focusable=\"false\" />\n </span>\n ) : null}\n {unavailable ? <span aria-hidden=\"true\" className=\"patternmode-swatch__slash\" /> : null}\n </>\n);\n\nconst getSwatchFill = ({\n background,\n blend,\n color,\n colors,\n density,\n gravity,\n texture,\n}: Pick<\n SwatchProps,\n \"background\" | \"blend\" | \"color\" | \"colors\" | \"density\" | \"gravity\" | \"texture\"\n>) => {\n const colorsBackground = getSwatchColorsBackground(colors, blend);\n const atmosphereBackground =\n texture === \"atmosphere\"\n ? getSwatchAtmosphereBackground(colors, { density, gravity })\n : undefined;\n\n return {\n colorsBackground,\n fill: background ?? atmosphereBackground ?? colorsBackground ?? color,\n };\n};\n\nconst getSwatchTone = ({\n background,\n color,\n colorsBackground,\n isLight,\n}: {\n background: SwatchProps[\"background\"];\n color: SwatchProps[\"color\"];\n colorsBackground: string | undefined;\n isLight: SwatchProps[\"isLight\"];\n}) => {\n if (isLight !== undefined) {\n return isLight ? \"light\" : \"dark\";\n }\n\n const hasColor = color !== undefined && color !== \"\";\n const hasBackground = background !== undefined && background !== \"\";\n const hasColorsBackground = colorsBackground !== undefined && colorsBackground !== \"\";\n\n if (hasColor && !hasBackground && !hasColorsBackground && isLightColor(color)) {\n return \"light\";\n }\n\n return \"dark\";\n};\n\nconst getSwatchDataProps = ({\n flat,\n lightTone,\n raised,\n selected,\n shape,\n showRing,\n size,\n unavailable,\n}: {\n flat: boolean;\n lightTone: \"dark\" | \"light\";\n raised: boolean;\n selected: boolean;\n shape: SwatchProps[\"shape\"];\n showRing: boolean;\n size: SwatchProps[\"size\"];\n unavailable: boolean;\n}) => ({\n \"data-flat\": flat ? \"true\" : undefined,\n \"data-raised\": raised ? \"true\" : undefined,\n \"data-selected\": selected ? \"true\" : undefined,\n \"data-shape\": shape,\n \"data-show-ring\": showRing ? \"true\" : \"false\",\n \"data-size\": size,\n \"data-slot\": \"swatch\",\n \"data-tone\": lightTone,\n \"data-unavailable\": unavailable ? \"true\" : undefined,\n});\n\nconst RemovableSwatch = ({\n ariaLabel,\n children,\n className,\n dataProps,\n onRemove,\n removeLabel,\n rootStyle,\n props,\n}: RemovableSwatchProps) => {\n const handleRemove = (event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n onRemove();\n };\n\n return (\n <fieldset\n {...props}\n {...dataProps}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\n style={rootStyle}\n >\n {children}\n <button\n aria-label={removeLabel}\n className=\"patternmode-swatch__remove\"\n onClick={handleRemove}\n type=\"button\"\n >\n <svg aria-hidden=\"true\" fill=\"none\" viewBox=\"0 0 20 20\">\n <path d=\"M5.5 5.5l9 9M14.5 5.5l-9 9\" />\n </svg>\n </button>\n </fieldset>\n );\n};\n\nexport const Swatch = ({\n \"aria-label\": ariaLabel,\n asChild = false,\n background,\n blend = \"step\",\n children,\n className,\n color,\n colors,\n density,\n flat = false,\n gravity,\n icon: Icon,\n isLight,\n objectFit,\n objectPosition,\n onRemove,\n raised = false,\n removeLabel,\n selected = false,\n shape = \"circle\",\n showRing = true,\n size = \"base\",\n style,\n texture,\n unavailable = false,\n ...props\n}: SwatchProps) => {\n const { colorsBackground, fill } = getSwatchFill({\n background,\n blend,\n color,\n colors,\n density,\n gravity,\n texture,\n });\n const lightTone = getSwatchTone({\n background,\n color,\n colorsBackground,\n isLight,\n });\n const resolvedRemoveLabel =\n removeLabel ?? (ariaLabel !== undefined && ariaLabel !== \"\" ? `Remove ${ariaLabel}` : \"Remove\");\n\n const rootStyle: SwatchRootStyle = {\n ...getSwatchSizeVariableStyle(size),\n \"--patternmode-swatch-fill\": fill,\n ...style,\n };\n const mediaStyle: CSSProperties = getObjectSizingStyle({\n fit: objectFit,\n position: objectPosition,\n });\n const dataProps = getSwatchDataProps({\n flat,\n lightTone,\n raised,\n selected,\n shape,\n showRing,\n size,\n unavailable,\n });\n\n const swatchContent = (\n <SwatchContent\n flat={flat}\n Icon={Icon}\n mediaStyle={mediaStyle}\n selected={selected}\n unavailable={unavailable}\n >\n {asChild ? undefined : children}\n </SwatchContent>\n );\n\n if (asChild) {\n return (\n <Slot\n {...props}\n {...dataProps}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\n style={rootStyle}\n >\n {swatchContent}\n <Slottable>{children}</Slottable>\n </Slot>\n );\n }\n\n if (onRemove !== undefined) {\n return (\n <RemovableSwatch\n ariaLabel={ariaLabel}\n className={className}\n dataProps={dataProps}\n onRemove={onRemove}\n props={props}\n removeLabel={resolvedRemoveLabel}\n rootStyle={rootStyle}\n >\n {swatchContent}\n </RemovableSwatch>\n );\n }\n\n return (\n <figure\n {...props}\n {...dataProps}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\n style={rootStyle}\n >\n {swatchContent}\n </figure>\n );\n};\n"],"mappings":"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"}
|
package/dist/styles.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer components{.patternmode-swatch{--patternmode-swatch-size:2rem;--patternmode-swatch-fill:#e3e1dc;--patternmode-swatch-radius:999px;aspect-ratio:1;border-radius:var(--patternmode-swatch-radius);color:#fff;height:var(--patternmode-swatch-size);vertical-align:middle;min-inline-size:0;width:var(--patternmode-swatch-size);border:0;justify-content:center;align-items:center;margin:0;padding:0;transition:box-shadow .14s,opacity .14s,transform .14s;display:inline-flex;position:relative;box-shadow:0 1px 2px #1118271a}.patternmode-swatch[data-tone=light]{color:#1d1d1b}.patternmode-swatch[data-shape=pill]{--patternmode-swatch-radius:999px;aspect-ratio:auto;width:calc(var(--patternmode-swatch-size) * 3)}.patternmode-swatch[data-shape=square]{--patternmode-swatch-radius:7px}.patternmode-swatch[data-shape=block]{--patternmode-swatch-radius:.25rem;aspect-ratio:auto;width:100%;height:100%;display:block}.patternmode-swatch[data-raised=true]{box-shadow:0 1px 2px #1118271a, 0 0 0 2px var(--surface,#fff)}.patternmode-swatch[data-selected=true][data-show-ring=true]{box-shadow:0 1px 2px #1118271a, 0 0 0 2px var(--surface,#fff), 0 0 0 4px var(--accent,#315c4b)}.patternmode-swatch[data-unavailable=true]{opacity:.5}.patternmode-swatch[data-flat=true]{box-shadow:none}.patternmode-swatch__fill,.patternmode-swatch__media,.patternmode-swatch__scrim{border-radius:inherit;position:absolute;inset:0;overflow:hidden}.patternmode-swatch__fill{background:var(--patternmode-swatch-fill)}.patternmode-swatch__media>*{object-fit:inherit;object-position:inherit;width:100%;height:100%;display:block}.patternmode-swatch__scrim{pointer-events:none;background:linear-gradient(#0000 0%,#0003 100%)}.patternmode-swatch__icon{justify-content:center;align-items:center;display:inline-flex;position:absolute;inset:0}.patternmode-swatch__icon svg{stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.4px;width:48%;height:48%;display:block}.patternmode-swatch__slash{background:currentColor;border-radius:999px;width:112%;height:2px;position:absolute;transform:rotate(-45deg)}.patternmode-swatch__remove{color:var(--surface,#fff);cursor:pointer;opacity:0;background:0 0;border:0;border-radius:999px;justify-content:center;align-items:center;width:2.75rem;height:2.75rem;padding:0;transition:opacity .14s;display:inline-flex;position:absolute;top:-1.1rem;right:-1.1rem}.patternmode-swatch__remove:before{background:var(--ink,#1d1d1b);border-radius:inherit;content:"";width:1.25rem;height:1.25rem;transition:background .14s;position:absolute}.patternmode-swatch__remove:focus-visible{opacity:1}@media (hover:hover){.patternmode-swatch:hover .patternmode-swatch__remove{opacity:1}.patternmode-swatch__remove:hover:before{background:var(--accent,#315c4b)}}.patternmode-swatch__remove:focus-visible{outline:2px solid var(--accent,#315c4b);outline-offset:2px}.patternmode-swatch__remove svg{stroke:currentColor;stroke-linecap:round;stroke-width:2px;z-index:1;width:.8rem;height:.8rem}@media (prefers-reduced-motion:reduce){.patternmode-swatch,.patternmode-swatch__remove,.patternmode-swatch__remove:before{transition:none}}.patternmode-distribution-bar,.patternmode-distribution-display{min-inline-size:0;border:0;gap:10px;width:100%;margin:0;padding:0;display:grid}.patternmode-distribution-bar__track{height:var(--patternmode-distribution-height,40px);width:100%;position:relative}.patternmode-distribution-bar .patternmode-distribution-bar__track{touch-action:none}.patternmode-distribution-bar__segments{border:1px solid var(--border-soft,#1118271f);border-radius:var(--patternmode-distribution-radius,999px);width:100%;height:100%;display:flex;overflow:hidden}.patternmode-distribution-bar__segment{background:var(--patternmode-distribution-segment-color);border:0;min-width:0;height:100%;margin:0;padding:0;transition:width .48s cubic-bezier(.2,0,0,1)}button.patternmode-distribution-bar__segment{cursor:pointer}button.patternmode-distribution-bar__segment:focus-visible{outline:2px solid var(--accent,#315c4b);outline-offset:-2px;z-index:2}.patternmode-distribution-bar__segment+.patternmode-distribution-bar__segment{box-shadow:inset 1px 0 #fff9}.patternmode-distribution-bar__segment[data-selected=true]{z-index:2;position:relative}.patternmode-distribution-bar__segment[data-selected=true]:after{border:2px solid var(--surface,#fff);content:"";border-radius:999px;width:.62rem;height:.62rem;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 1px 4px #11182747,inset 0 0 0 1px #1118271f}@media (prefers-reduced-motion:reduce){.patternmode-distribution-bar__segment{transition:none}}.patternmode-distribution-bar__segment--empty{background-color:var(--surface-soft,#f7f5f0);background-image:repeating-linear-gradient(45deg, transparent, transparent 3px, var(--border-soft,#1118271f) 3px, var(--border-soft,#1118271f) 4px)}.patternmode-distribution-bar__handle{cursor:ew-resize;z-index:1;background:0 0;border:0;border-radius:999px;justify-content:center;align-items:center;width:2.75rem;height:2.75rem;padding:0;display:inline-flex;position:absolute;top:calc(50% - 1.375rem)}.patternmode-distribution-bar__handle:before{background:var(--surface,#fff);content:"";border-radius:999px;width:.62rem;height:.62rem;transition:box-shadow .12s,transform .12s;box-shadow:0 1px 4px #1118272e,0 0 0 1px #11182733}.patternmode-distribution-bar__handle:focus-visible{outline:2px solid var(--accent,#315c4b);outline-offset:-4px}@media (hover:hover){.patternmode-distribution-bar__handle:hover:before{transform:scale(1.15);box-shadow:0 5px 14px #1118274d,0 0 0 1px #11182738}}.patternmode-distribution-bar__legend{flex-wrap:wrap;gap:8px 14px;display:flex}.patternmode-distribution-bar__legend>span{color:var(--muted,#595853);align-items:center;gap:6px;font-size:.68rem;font-weight:500;display:inline-flex}.patternmode-distribution-bar__swatch{background:var(--patternmode-distribution-segment-color);border-radius:999px;width:.55rem;height:.55rem;display:inline-flex}.patternmode-distribution-bar__swatch--empty{background-color:var(--surface-soft,#f7f5f0);background-image:repeating-linear-gradient(45deg, transparent, transparent 2px, var(--border-soft,#1118271f) 2px, var(--border-soft,#1118271f) 3px);box-shadow:inset 0 0 0 1px var(--border-soft,#1118271f)}@media (prefers-reduced-motion:reduce){.patternmode-distribution-bar__handle:before{transition:none}}}
|
|
1
|
+
@layer components{.patternmode-swatch{--patternmode-swatch-size:2rem;--patternmode-swatch-fill:#e3e1dc;--patternmode-swatch-radius:999px;aspect-ratio:1;border-radius:var(--patternmode-swatch-radius);color:#fff;height:var(--patternmode-swatch-size);vertical-align:middle;min-inline-size:0;width:var(--patternmode-swatch-size);border:0;justify-content:center;align-items:center;margin:0;padding:0;transition:box-shadow .14s,opacity .14s,transform .14s;display:inline-flex;position:relative;box-shadow:0 1px 2px #1118271a}.patternmode-swatch[data-tone=light]{color:#1d1d1b}.patternmode-swatch[data-shape=pill]{--patternmode-swatch-radius:999px;aspect-ratio:auto;width:calc(var(--patternmode-swatch-size) * 3)}.patternmode-swatch[data-shape=square]{--patternmode-swatch-radius:7px}.patternmode-swatch[data-shape=block]{--patternmode-swatch-radius:.25rem;aspect-ratio:auto;width:100%;height:100%;display:block}.patternmode-swatch[data-raised=true]{box-shadow:0 1px 2px #1118271a, 0 0 0 2px var(--surface,#fff)}.patternmode-swatch[data-selected=true][data-show-ring=true]{box-shadow:0 1px 2px #1118271a, 0 0 0 2px var(--surface,#fff), 0 0 0 4px var(--accent,#315c4b)}.patternmode-swatch[data-unavailable=true]{opacity:.5}.patternmode-swatch[data-flat=true]{box-shadow:none}.patternmode-swatch__fill,.patternmode-swatch__media,.patternmode-swatch__scrim{border-radius:inherit;position:absolute;inset:0;overflow:hidden}.patternmode-swatch__fill{background:var(--patternmode-swatch-fill)}.patternmode-swatch__media>*{object-fit:inherit;object-position:inherit;width:100%;height:100%;display:block}.patternmode-swatch__scrim{pointer-events:none;background:linear-gradient(#0000 0%,#0003 100%)}.patternmode-swatch__icon{justify-content:center;align-items:center;display:inline-flex;position:absolute;inset:0}.patternmode-swatch__icon svg{stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:2.4px;width:48%;height:48%;display:block}.patternmode-swatch__slash{background:currentColor;border-radius:999px;width:112%;height:2px;position:absolute;transform:rotate(-45deg)}.patternmode-swatch__remove{color:var(--surface,#fff);cursor:pointer;opacity:0;background:0 0;border:0;border-radius:999px;justify-content:center;align-items:center;width:2.75rem;height:2.75rem;padding:0;transition:opacity .14s;display:inline-flex;position:absolute;top:-1.1rem;right:-1.1rem}.patternmode-swatch__remove:before{background:var(--ink,#1d1d1b);border-radius:inherit;content:"";width:1.25rem;height:1.25rem;transition:background .14s;position:absolute}.patternmode-swatch__remove:focus-visible{opacity:1}@media (hover:hover){.patternmode-swatch:hover .patternmode-swatch__remove{opacity:1}.patternmode-swatch__remove:hover:before{background:var(--accent,#315c4b)}}@media (hover:none){.patternmode-swatch__remove{opacity:1}}.patternmode-swatch__remove:focus-visible{outline:2px solid var(--accent,#315c4b);outline-offset:2px}.patternmode-swatch__remove svg{stroke:currentColor;stroke-linecap:round;stroke-width:2px;z-index:1;width:.8rem;height:.8rem}@media (prefers-reduced-motion:reduce){.patternmode-swatch,.patternmode-swatch__remove,.patternmode-swatch__remove:before{transition:none}}.patternmode-distribution-bar,.patternmode-distribution-display{min-inline-size:0;border:0;gap:10px;width:100%;margin:0;padding:0;display:grid}.patternmode-distribution-bar__track{height:var(--patternmode-distribution-height,40px);width:100%;position:relative}.patternmode-distribution-bar .patternmode-distribution-bar__track{touch-action:none}.patternmode-distribution-bar__segments{border:1px solid var(--border-soft,#1118271f);border-radius:var(--patternmode-distribution-radius,999px);width:100%;height:100%;display:flex;overflow:hidden}.patternmode-distribution-bar__segment{background:var(--patternmode-distribution-segment-color);border:0;min-width:0;height:100%;margin:0;padding:0;transition:width .48s cubic-bezier(.2,0,0,1)}.patternmode-distribution-bar[data-dragging=true] .patternmode-distribution-bar__segment{transition:none}button.patternmode-distribution-bar__segment{cursor:pointer}button.patternmode-distribution-bar__segment:focus-visible{outline:2px solid var(--accent,#315c4b);outline-offset:-2px;z-index:2}.patternmode-distribution-bar__segment+.patternmode-distribution-bar__segment{box-shadow:inset 1px 0 #fff9}.patternmode-distribution-bar__segment[data-selected=true]{z-index:2;position:relative}.patternmode-distribution-bar__segment[data-selected=true]:after{border:2px solid var(--surface,#fff);content:"";border-radius:999px;width:.62rem;height:.62rem;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 1px 4px #11182747,inset 0 0 0 1px #1118271f}@media (prefers-reduced-motion:reduce){.patternmode-distribution-bar__segment{transition:none}}.patternmode-distribution-bar__segment--empty{background-color:var(--surface-soft,#f7f5f0);background-image:repeating-linear-gradient(45deg, transparent, transparent 3px, var(--border-soft,#1118271f) 3px, var(--border-soft,#1118271f) 4px)}.patternmode-distribution-bar__handle{cursor:ew-resize;z-index:1;background:0 0;border:0;border-radius:999px;justify-content:center;align-items:center;width:2.75rem;height:2.75rem;padding:0;display:inline-flex;position:absolute;top:calc(50% - 1.375rem)}.patternmode-distribution-bar__handle:before{background:var(--surface,#fff);content:"";border-radius:999px;width:.62rem;height:.62rem;transition:box-shadow .12s,transform .12s;box-shadow:0 1px 4px #1118272e,0 0 0 1px #11182733}.patternmode-distribution-bar__handle:focus-visible{outline:2px solid var(--accent,#315c4b);outline-offset:-4px}@media (hover:hover){.patternmode-distribution-bar__handle:hover:before{transform:scale(1.15);box-shadow:0 5px 14px #1118274d,0 0 0 1px #11182738}}.patternmode-distribution-bar__legend{flex-wrap:wrap;gap:8px 14px;display:flex}.patternmode-distribution-bar__legend>span{color:var(--muted,#595853);align-items:center;gap:6px;font-size:.68rem;font-weight:500;display:inline-flex}.patternmode-distribution-bar__swatch{background:var(--patternmode-distribution-segment-color);border-radius:999px;width:.55rem;height:.55rem;display:inline-flex}.patternmode-distribution-bar__swatch--empty{background-color:var(--surface-soft,#f7f5f0);background-image:repeating-linear-gradient(45deg, transparent, transparent 2px, var(--border-soft,#1118271f) 2px, var(--border-soft,#1118271f) 3px);box-shadow:inset 0 0 0 1px var(--border-soft,#1118271f)}@media (prefers-reduced-motion:reduce){.patternmode-distribution-bar__handle:before{transition:none}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternmode/swatch",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Color, gradient, image, and palette swatch primitives for Patternmode interfaces.",
|
|
6
6
|
"keywords": [
|
|
@@ -41,9 +41,10 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
+
"@instruments/colorscope": "^3.5.0",
|
|
44
45
|
"@radix-ui/react-slot": "^1.2.5",
|
|
45
46
|
"motion": "^12.40.0",
|
|
46
|
-
"@patternmode/system": "0.
|
|
47
|
+
"@patternmode/system": "0.4.0"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@howells/lint": "^0.5.0",
|