@patternmode/swatch 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,27 +7,27 @@ import { DistributionBar, Swatch } from "@patternmode/swatch";
7
7
  import "@patternmode/swatch/styles.css";
8
8
 
9
9
  export function Example() {
10
- return (
11
- <>
12
- <Swatch
13
- aria-label="Palette"
14
- colors={[
15
- { color: "#315c4b", ratio: 60 },
16
- { color: "#e1ebe5", ratio: 40 },
17
- ]}
18
- shape="pill"
19
- size="2xl"
20
- />
21
- <DistributionBar
22
- aria-label="Finish distribution"
23
- segments={[
24
- { id: "evergreen", color: "#315c4b", label: "Evergreen", value: 48 },
25
- { id: "saffron", color: "#d9a441", label: "Saffron", value: 30 },
26
- { id: "oxblood", color: "#9b3d32", label: "Oxblood", value: 22 },
27
- ]}
28
- />
29
- </>
30
- );
10
+ return (
11
+ <>
12
+ <Swatch
13
+ aria-label="Palette"
14
+ colors={[
15
+ { color: "#315c4b", ratio: 60 },
16
+ { color: "#e1ebe5", ratio: 40 },
17
+ ]}
18
+ shape="pill"
19
+ size="2xl"
20
+ />
21
+ <DistributionBar
22
+ aria-label="Finish distribution"
23
+ segments={[
24
+ { id: "evergreen", color: "#315c4b", label: "Evergreen", value: 48 },
25
+ { id: "saffron", color: "#d9a441", label: "Saffron", value: 30 },
26
+ { id: "oxblood", color: "#9b3d32", label: "Oxblood", value: 22 },
27
+ ]}
28
+ />
29
+ </>
30
+ );
31
31
  }
32
32
  ```
33
33
 
@@ -1 +1 @@
1
- {"version":3,"file":"DistributionBarRoot.d.ts","sourceRoot":"","sources":["../../src/DistributionBar/DistributionBarRoot.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,cAAc,EAAiB,MAAM,OAAO,CAAC;AAG1E,OAAO,EACL,KAAK,sBAAsB,EAI5B,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,wBACf,SAAQ,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,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,oBACf,SAAQ,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,EAAE,UAAU,CAAC;IAC7D,iFAAiF;IACjF,MAAM,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,sBAAsB,EAAE,KAAK,IAAI,CAAC;IACxD,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,mBAAmB,CAAC,EAClC,YAAY,EAAE,SAAS,EACvB,aAA0B,EAC1B,SAAS,EACT,UAAyB,EACzB,UAAc,EACd,MAAmB,EACnB,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,GAAG,KAAK,EACT,EAAE,wBAAwB,2CAmE1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,MAAmB,EACnB,QAAY,EACZ,QAAQ,EACR,QAAQ,EACR,IAAQ,EACR,GAAG,KAAK,EACT,EAAE,oBAAoB,2CA8FtB"}
1
+ {"version":3,"file":"DistributionBarRoot.d.ts","sourceRoot":"","sources":["../../src/DistributionBar/DistributionBarRoot.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,cAAc,EAAiB,MAAM,OAAO,CAAC;AAG1E,OAAO,EACL,KAAK,sBAAsB,EAI5B,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,cAAc,CAAC,cAAc,CAAC,EAC9B,MAAM,GAAG,UAAU,CACpB;IACC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,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,iFAAiF;IACjF,MAAM,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,sBAAsB,EAAE,KAAK,IAAI,CAAC;IACxD,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,mBAAmB,CAAC,EAClC,YAAY,EAAE,SAAS,EACvB,aAA0B,EAC1B,SAAS,EACT,UAAyB,EACzB,UAAc,EACd,MAAmB,EACnB,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,GAAG,KAAK,EACT,EAAE,wBAAwB,2CAmE1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,MAAmB,EACnB,QAAY,EACZ,QAAQ,EACR,QAAQ,EACR,IAAQ,EACR,GAAG,KAAK,EACT,EAAE,oBAAoB,2CA8FtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"SwatchAtmosphere.d.ts","sourceRoot":"","sources":["../../src/Swatch/SwatchAtmosphere.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,eAAe,EAAE,GAAG,SAAS,EACrC,OAAO,GAAE,uBAA4B,GACpC,MAAM,GAAG,SAAS,CA0BpB"}
1
+ {"version":3,"file":"SwatchAtmosphere.d.ts","sourceRoot":"","sources":["../../src/Swatch/SwatchAtmosphere.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmBD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,eAAe,EAAE,GAAG,SAAS,EACrC,OAAO,GAAE,uBAA4B,GACpC,MAAM,GAAG,SAAS,CA0BpB"}
package/dist/index.mjs CHANGED
@@ -369,7 +369,7 @@ function withAlpha(color, alpha) {
369
369
  }
370
370
  function normalizeHex$1(color) {
371
371
  const value = color.trim().replace(/^#/, "");
372
- if (/^[\da-f]{3}$/i.test(value)) return value.split("").map((part) => part + part).join("");
372
+ if (/^[\da-f]{3}$/i.test(value)) return [...value].map((part) => part + part).join("");
373
373
  if (/^[\da-f]{6}$/i.test(value)) return value;
374
374
  return null;
375
375
  }
@@ -405,7 +405,7 @@ function getSwatchColorsBackground(colors) {
405
405
  }
406
406
  function normalizeHex(hex) {
407
407
  const value = hex.trim().replace(/^#/, "");
408
- if (/^[\da-f]{3}$/i.test(value)) return value.split("").map((part) => part + part).join("");
408
+ if (/^[\da-f]{3}$/i.test(value)) return [...value].map((part) => part + part).join("");
409
409
  if (/^[\da-f]{6}$/i.test(value)) return value;
410
410
  return null;
411
411
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["clamp","normalizeHex"],"sources":["../src/DistributionBar/DistributionBarMath.ts","../src/DistributionBar/DistributionBarRoot.tsx","../src/Swatch/SwatchAtmosphere.ts","../src/Swatch/SwatchColors.ts","../src/Swatch/SwatchTypes.ts","../src/Swatch/SwatchRoot.tsx"],"sourcesContent":["export interface DistributionBarSegment {\n color: string;\n id: string;\n label?: string;\n value: number;\n}\n\nexport type DistributionBarSegmentUpdate = Partial<\n Omit<DistributionBarSegment, \"value\">\n> & {\n value?: never;\n};\n\nexport function getDistributionTotal(\n segments: DistributionBarSegment[],\n): number {\n return segments.reduce(\n (sum, segment) => sum + sanitizeValue(segment.value),\n 0,\n );\n}\n\nexport function 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\nexport function 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\nexport function 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) +\n (removedValue * sanitizeValue(segment.value)) / remainingTotal,\n );\n assignedValue += nextValue;\n return { ...segment, value: nextValue };\n });\n}\n\nexport function updateDistributionSegment(\n segments: DistributionBarSegment[],\n segmentId: string,\n update: DistributionBarSegmentUpdate,\n): DistributionBarSegment[] {\n return segments.map((segment) =>\n segment.id === segmentId ? { ...segment, ...update } : segment,\n );\n}\n\nfunction sanitizeValue(value: number): number {\n return Number.isFinite(value) ? Math.max(0, value) : 0;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction roundValue(value: number): number {\n return Number(value.toFixed(1));\n}\n","import { joinClassNames } from \"@patternmode/system\";\nimport { domMax, LazyMotion, m, type PanInfo } from \"motion/react\";\nimport type { CSSProperties, HTMLAttributes, KeyboardEvent } from \"react\";\nimport { useRef } from \"react\";\n\nimport {\n type DistributionBarSegment,\n getDistributionBoundaryPercent,\n getDistributionTotal,\n moveDistributionBoundary,\n} from \"./DistributionBarMath\";\n\nexport interface DistributionDisplayProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"role\" | \"onSelect\"> {\n assignedLabel?: string;\n emptyLabel?: string;\n emptyValue?: number;\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\n extends Omit<HTMLAttributes<HTMLFieldSetElement>, \"onChange\"> {\n /** Show the per-segment legend below the bar, or hide it. Default \"segments\". */\n legend?: \"segments\" | false;\n minValue?: number;\n onChange?: (segments: DistributionBarSegment[]) => void;\n segments: DistributionBarSegment[];\n step?: number;\n}\n\nexport function 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 ??\n getDistributionDisplayAccessibleLabel(\n segments,\n emptyValue,\n emptyLabel,\n total,\n );\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(\n \"patternmode-distribution-display\",\n className,\n );\n\n // A selectable distribution is a group of buttons (fieldset → implicit\n // group role); a read-only one keeps the label on the display wrapper.\n return interactive ? (\n <fieldset\n {...(props as HTMLAttributes<HTMLFieldSetElement>)}\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 function 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 function moveBoundary(\n boundaryIndex: number,\n deltaValue: number,\n sourceSegments = segments,\n ) {\n onChange?.(\n moveDistributionBoundary(\n sourceSegments,\n boundaryIndex,\n deltaValue,\n minValue,\n ),\n );\n }\n\n function handleDragStart() {\n dragStartSegmentsRef.current = segments;\n }\n\n function 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(\n boundaryIndex,\n (info.offset.x / trackWidth) * sourceTotal,\n sourceSegments,\n );\n }\n\n function handleDragEnd(boundaryIndex: number, info: PanInfo) {\n handleDrag(boundaryIndex, info);\n dragStartSegmentsRef.current = null;\n }\n\n function handleKeyDown(\n event: KeyboardEvent<HTMLButtonElement>,\n boundaryIndex: number,\n ) {\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(\n segments,\n boundaryIndex,\n );\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) => handleDrag(boundaryIndex, info)}\n onDragEnd={(info) => handleDragEnd(boundaryIndex, info)}\n onDragStart={handleDragStart}\n onKeyDown={(event) => handleKeyDown(event, boundaryIndex)}\n />\n );\n })}\n </div>\n {legend === \"segments\" ? (\n <DistributionSegmentLegend segments={segments} total={total} />\n ) : null}\n </fieldset>\n );\n}\n\ninterface DistributionSegmentsProps {\n emptyValue?: number;\n onSegmentSelect?: (segment: DistributionBarSegment) => void;\n segments: DistributionBarSegment[];\n selectedSegmentId?: string;\n total: number;\n}\n\nfunction DistributionSegments({\n emptyValue = 0,\n onSegmentSelect,\n segments,\n selectedSegmentId,\n total,\n}: DistributionSegmentsProps) {\n return (\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\n ? `${(getRenderableDistributionValue(segment.value) / total) * 100}%`\n : \"0%\",\n } as CSSProperties;\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={() => onSegmentSelect(segment)}\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\n ? `${(getRenderableDistributionValue(emptyValue) / total) * 100}%`\n : \"0%\",\n }}\n />\n ) : null}\n </div>\n );\n}\n\ninterface DistributionSegmentLegendProps {\n emptyLabel?: string;\n emptyValue?: number;\n segments: DistributionBarSegment[];\n total: number;\n}\n\nfunction DistributionSegmentLegend({\n emptyLabel,\n emptyValue = 0,\n segments,\n total,\n}: DistributionSegmentLegendProps) {\n return (\n <div className=\"patternmode-distribution-bar__legend\">\n {segments.map((segment) => (\n <span key={segment.id}>\n <span\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__swatch\"\n style={\n {\n \"--patternmode-distribution-segment-color\": segment.color,\n } as CSSProperties\n }\n />\n {segment.label ?? segment.id}{\" \"}\n {getDerivedDistributionPercentage(segment.value, total)}%\n </span>\n ))}\n {emptyValue > 0 && 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}\n\ninterface DistributionSummaryLegendProps {\n assignedLabel: string;\n emptyLabel: string;\n emptyValue: number;\n total: number;\n}\n\nfunction 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\nfunction getDistributionDisplayTotal(\n segments: DistributionBarSegment[],\n emptyValue: number,\n): number {\n return (\n getDistributionTotal(segments) + getRenderableDistributionValue(emptyValue)\n );\n}\n\nfunction 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(\n segment.value,\n total,\n )}%`,\n );\n if (emptyValue > 0) {\n segmentLabels.push(\n `${emptyLabel} ${getDerivedDistributionPercentage(emptyValue, total)}%`,\n );\n }\n\n return segmentLabels.join(\", \");\n}\n\nfunction getDerivedDistributionPercentage(\n value: number,\n total: number,\n): 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\nfunction getRenderableDistributionValue(value: number): number {\n return Number.isFinite(value) ? Math.max(0, value) : 0;\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\nfunction DistributionBarHandle({\n \"aria-label\": ariaLabel,\n boundaryPercent,\n onDrag,\n onDragEnd,\n onDragStart,\n onKeyDown,\n}: DistributionBarHandleProps) {\n return (\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) => onDrag(info)}\n onDragEnd={(_event, info) => onDragEnd(info)}\n onDragStart={onDragStart}\n onKeyDown={onKeyDown}\n style={{ left: `calc(${boundaryPercent}% - 1.375rem)` }}\n transformTemplate={() => \"none\"}\n type=\"button\"\n />\n </LazyMotion>\n );\n}\n","import type { SwatchColorStop } from \"./SwatchTypes\";\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: ReadonlyArray<readonly [number, number, number, number, number]> =\n [\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 */\nexport function getSwatchAtmosphereBackground(\n colors: SwatchColorStop[] | undefined,\n options: SwatchAtmosphereOptions = {},\n): string | undefined {\n if (!colors || 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] as (typeof POOLS)[number];\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\nfunction withAlpha(color: string, alpha: number): string {\n const hex = normalizeHex(color);\n if (hex) {\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\nfunction normalizeHex(color: string): string | null {\n const value = color.trim().replace(/^#/, \"\");\n if (/^[\\da-f]{3}$/i.test(value)) {\n return value\n .split(\"\")\n .map((part) => part + part)\n .join(\"\");\n }\n if (/^[\\da-f]{6}$/i.test(value)) {\n return value;\n }\n return null;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n","import type { SwatchColorStop } from \"./SwatchTypes\";\n\nexport function isLightColor(color: string): boolean {\n const normalized = normalizeHex(color);\n if (!normalized) {\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 function getSwatchColorsBackground(\n colors: SwatchColorStop[] | undefined,\n): string | undefined {\n if (!colors || colors.length === 0) {\n return undefined;\n }\n\n if (colors.length === 1) {\n return toColorStop(colors[0] as SwatchColorStop).color;\n }\n\n const stops = colors.map(toColorStop);\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 =\n 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\nfunction normalizeHex(hex: string): string | null {\n const value = hex.trim().replace(/^#/, \"\");\n if (/^[\\da-f]{3}$/i.test(value)) {\n return value\n .split(\"\")\n .map((part) => part + part)\n .join(\"\");\n }\n if (/^[\\da-f]{6}$/i.test(value)) {\n return value;\n }\n return null;\n}\n\nfunction toColorStop(stop: SwatchColorStop): { color: string; ratio?: number } {\n return typeof stop === \"string\" ? { color: stop } : stop;\n}\n\nfunction 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\nfunction formatPercent(value: number): string {\n return `${Number.isInteger(value) ? value : Number(value.toFixed(2))}%`;\n}\n","import {\n type ObjectFit,\n PATTERNMODE_SIZE_VALUES,\n PATTERNMODE_SIZES,\n} from \"@patternmode/system\";\nimport type { ComponentType, HTMLAttributes, SVGProps } from \"react\";\n\nexport const SWATCH_SIZES = [\n ...PATTERNMODE_SIZES,\n \"4xl\",\n \"5xl\",\n \"6xl\",\n \"7xl\",\n] 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 function getSwatchSizeVariableStyle(\n size: SwatchSize,\n variableName = \"--patternmode-swatch-size\",\n): Record<string, string> {\n return {\n [variableName]: SWATCH_SIZE_VALUES[size],\n };\n}\n\nexport interface SwatchProps extends HTMLAttributes<HTMLElement> {\n background?: string;\n color?: string;\n colors?: SwatchColorStop[];\n /**\n * Atmosphere density (0 = diffuse wash, 1 = dense pools). Only applies when\n * `texture=\"atmosphere\"`. 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 flat?: boolean;\n /**\n * Atmosphere gravity (-1 = pools sink, 1 = pools rise). Only applies when\n * `texture=\"atmosphere\"`. Default 0.\n */\n gravity?: number;\n icon?: SwatchIcon;\n isLight?: boolean;\n objectFit?: ObjectFit;\n objectPosition?: string;\n onRemove?: () => void;\n raised?: boolean;\n removeLabel?: string;\n selected?: boolean;\n shape?: SwatchShape;\n showRing?: boolean;\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 unavailable?: boolean;\n}\n","import { getObjectSizingStyle, joinClassNames } from \"@patternmode/system\";\nimport type { CSSProperties, MouseEvent } from \"react\";\n\nimport { getSwatchAtmosphereBackground } from \"./SwatchAtmosphere\";\nimport { getSwatchColorsBackground, isLightColor } from \"./SwatchColors\";\nimport { getSwatchSizeVariableStyle, type SwatchProps } from \"./SwatchTypes\";\n\nexport function Swatch({\n \"aria-label\": ariaLabel,\n background,\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 = getSwatchColorsBackground(colors);\n const atmosphereBackground =\n texture === \"atmosphere\"\n ? getSwatchAtmosphereBackground(colors, { density, gravity })\n : undefined;\n const fill = background ?? atmosphereBackground ?? colorsBackground ?? color;\n const light =\n isLight ??\n (color && !background && !colorsBackground\n ? isLightColor(color as string)\n : false);\n const resolvedRemoveLabel =\n removeLabel ?? (ariaLabel ? `Remove ${ariaLabel}` : \"Remove\");\n\n const rootStyle = {\n ...getSwatchSizeVariableStyle(size),\n \"--patternmode-swatch-fill\": fill,\n ...style,\n } as CSSProperties;\n const mediaStyle = getObjectSizingStyle({\n fit: objectFit,\n position: objectPosition,\n }) as CSSProperties;\n\n function handleRemove(event: MouseEvent<HTMLButtonElement>) {\n event.stopPropagation();\n onRemove?.();\n }\n\n const swatchContent = (\n <>\n <span aria-hidden=\"true\" className=\"patternmode-swatch__fill\" />\n {children ? (\n <span className=\"patternmode-swatch__media\" style={mediaStyle}>\n {children}\n </span>\n ) : null}\n {flat ? null : (\n <span aria-hidden=\"true\" className=\"patternmode-swatch__scrim\" />\n )}\n {selected && Icon ? (\n <span className=\"patternmode-swatch__icon\">\n <Icon aria-hidden=\"true\" focusable=\"false\" />\n </span>\n ) : null}\n {unavailable ? (\n <span aria-hidden=\"true\" className=\"patternmode-swatch__slash\" />\n ) : null}\n </>\n );\n\n if (onRemove) {\n return (\n <fieldset\n {...props}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\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={light ? \"light\" : \"dark\"}\n data-unavailable={unavailable ? \"true\" : undefined}\n style={rootStyle}\n >\n {swatchContent}\n <button\n aria-label={resolvedRemoveLabel}\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\n return (\n <figure\n {...props}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\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={light ? \"light\" : \"dark\"}\n data-unavailable={unavailable ? \"true\" : undefined}\n style={rootStyle}\n >\n {swatchContent}\n </figure>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["clamp","normalizeHex"],"sources":["../src/DistributionBar/DistributionBarMath.ts","../src/DistributionBar/DistributionBarRoot.tsx","../src/Swatch/SwatchAtmosphere.ts","../src/Swatch/SwatchColors.ts","../src/Swatch/SwatchTypes.ts","../src/Swatch/SwatchRoot.tsx"],"sourcesContent":["export interface DistributionBarSegment {\n color: string;\n id: string;\n label?: string;\n value: number;\n}\n\nexport type DistributionBarSegmentUpdate = Partial<\n Omit<DistributionBarSegment, \"value\">\n> & {\n value?: never;\n};\n\nexport function getDistributionTotal(\n segments: DistributionBarSegment[]\n): number {\n return segments.reduce(\n (sum, segment) => sum + sanitizeValue(segment.value),\n 0\n );\n}\n\nexport function 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\nexport function 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\nexport function 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) +\n (removedValue * sanitizeValue(segment.value)) / remainingTotal\n );\n assignedValue += nextValue;\n return { ...segment, value: nextValue };\n });\n}\n\nexport function updateDistributionSegment(\n segments: DistributionBarSegment[],\n segmentId: string,\n update: DistributionBarSegmentUpdate\n): DistributionBarSegment[] {\n return segments.map((segment) =>\n segment.id === segmentId ? { ...segment, ...update } : segment\n );\n}\n\nfunction sanitizeValue(value: number): number {\n return Number.isFinite(value) ? Math.max(0, value) : 0;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction roundValue(value: number): number {\n return Number(value.toFixed(1));\n}\n","import { joinClassNames } from \"@patternmode/system\";\nimport { domMax, LazyMotion, m, type PanInfo } from \"motion/react\";\nimport type { CSSProperties, HTMLAttributes, KeyboardEvent } from \"react\";\nimport { useRef } from \"react\";\n\nimport {\n type DistributionBarSegment,\n getDistributionBoundaryPercent,\n getDistributionTotal,\n moveDistributionBoundary,\n} from \"./DistributionBarMath\";\n\nexport interface DistributionDisplayProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"role\" | \"onSelect\"\n> {\n assignedLabel?: string;\n emptyLabel?: string;\n emptyValue?: number;\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 /** Show the per-segment legend below the bar, or hide it. Default \"segments\". */\n legend?: \"segments\" | false;\n minValue?: number;\n onChange?: (segments: DistributionBarSegment[]) => void;\n segments: DistributionBarSegment[];\n step?: number;\n}\n\nexport function 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 ??\n getDistributionDisplayAccessibleLabel(\n segments,\n emptyValue,\n emptyLabel,\n total\n );\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(\n \"patternmode-distribution-display\",\n className\n );\n\n // A selectable distribution is a group of buttons (fieldset → implicit\n // group role); a read-only one keeps the label on the display wrapper.\n return interactive ? (\n <fieldset\n {...(props as HTMLAttributes<HTMLFieldSetElement>)}\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 function 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 function moveBoundary(\n boundaryIndex: number,\n deltaValue: number,\n sourceSegments = segments\n ) {\n onChange?.(\n moveDistributionBoundary(\n sourceSegments,\n boundaryIndex,\n deltaValue,\n minValue\n )\n );\n }\n\n function handleDragStart() {\n dragStartSegmentsRef.current = segments;\n }\n\n function 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(\n boundaryIndex,\n (info.offset.x / trackWidth) * sourceTotal,\n sourceSegments\n );\n }\n\n function handleDragEnd(boundaryIndex: number, info: PanInfo) {\n handleDrag(boundaryIndex, info);\n dragStartSegmentsRef.current = null;\n }\n\n function handleKeyDown(\n event: KeyboardEvent<HTMLButtonElement>,\n boundaryIndex: number\n ) {\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(\n segments,\n boundaryIndex\n );\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) => handleDrag(boundaryIndex, info)}\n onDragEnd={(info) => handleDragEnd(boundaryIndex, info)}\n onDragStart={handleDragStart}\n onKeyDown={(event) => handleKeyDown(event, boundaryIndex)}\n />\n );\n })}\n </div>\n {legend === \"segments\" ? (\n <DistributionSegmentLegend segments={segments} total={total} />\n ) : null}\n </fieldset>\n );\n}\n\ninterface DistributionSegmentsProps {\n emptyValue?: number;\n onSegmentSelect?: (segment: DistributionBarSegment) => void;\n segments: DistributionBarSegment[];\n selectedSegmentId?: string;\n total: number;\n}\n\nfunction DistributionSegments({\n emptyValue = 0,\n onSegmentSelect,\n segments,\n selectedSegmentId,\n total,\n}: DistributionSegmentsProps) {\n return (\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\n ? `${(getRenderableDistributionValue(segment.value) / total) * 100}%`\n : \"0%\",\n } as CSSProperties;\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={() => onSegmentSelect(segment)}\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\n ? `${(getRenderableDistributionValue(emptyValue) / total) * 100}%`\n : \"0%\",\n }}\n />\n ) : null}\n </div>\n );\n}\n\ninterface DistributionSegmentLegendProps {\n emptyLabel?: string;\n emptyValue?: number;\n segments: DistributionBarSegment[];\n total: number;\n}\n\nfunction DistributionSegmentLegend({\n emptyLabel,\n emptyValue = 0,\n segments,\n total,\n}: DistributionSegmentLegendProps) {\n return (\n <div className=\"patternmode-distribution-bar__legend\">\n {segments.map((segment) => (\n <span key={segment.id}>\n <span\n aria-hidden=\"true\"\n className=\"patternmode-distribution-bar__swatch\"\n style={\n {\n \"--patternmode-distribution-segment-color\": segment.color,\n } as CSSProperties\n }\n />\n {segment.label ?? segment.id}{\" \"}\n {getDerivedDistributionPercentage(segment.value, total)}%\n </span>\n ))}\n {emptyValue > 0 && 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}\n\ninterface DistributionSummaryLegendProps {\n assignedLabel: string;\n emptyLabel: string;\n emptyValue: number;\n total: number;\n}\n\nfunction 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\nfunction getDistributionDisplayTotal(\n segments: DistributionBarSegment[],\n emptyValue: number\n): number {\n return (\n getDistributionTotal(segments) + getRenderableDistributionValue(emptyValue)\n );\n}\n\nfunction 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(\n segment.value,\n total\n )}%`\n );\n if (emptyValue > 0) {\n segmentLabels.push(\n `${emptyLabel} ${getDerivedDistributionPercentage(emptyValue, total)}%`\n );\n }\n\n return segmentLabels.join(\", \");\n}\n\nfunction getDerivedDistributionPercentage(\n value: number,\n total: number\n): 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\nfunction getRenderableDistributionValue(value: number): number {\n return Number.isFinite(value) ? Math.max(0, value) : 0;\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\nfunction DistributionBarHandle({\n \"aria-label\": ariaLabel,\n boundaryPercent,\n onDrag,\n onDragEnd,\n onDragStart,\n onKeyDown,\n}: DistributionBarHandleProps) {\n return (\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) => onDrag(info)}\n onDragEnd={(_event, info) => onDragEnd(info)}\n onDragStart={onDragStart}\n onKeyDown={onKeyDown}\n style={{ left: `calc(${boundaryPercent}% - 1.375rem)` }}\n transformTemplate={() => \"none\"}\n type=\"button\"\n />\n </LazyMotion>\n );\n}\n","import type { SwatchColorStop } from \"./SwatchTypes\";\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 */\nexport function getSwatchAtmosphereBackground(\n colors: SwatchColorStop[] | undefined,\n options: SwatchAtmosphereOptions = {}\n): string | undefined {\n if (!colors || 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] as (typeof POOLS)[number];\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\nfunction withAlpha(color: string, alpha: number): string {\n const hex = normalizeHex(color);\n if (hex) {\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\nfunction normalizeHex(color: string): string | null {\n const value = color.trim().replace(/^#/, \"\");\n if (/^[\\da-f]{3}$/i.test(value)) {\n return [...value].map((part) => part + part).join(\"\");\n }\n if (/^[\\da-f]{6}$/i.test(value)) {\n return value;\n }\n return null;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n","import type { SwatchColorStop } from \"./SwatchTypes\";\n\nexport function isLightColor(color: string): boolean {\n const normalized = normalizeHex(color);\n if (!normalized) {\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 function getSwatchColorsBackground(\n colors: SwatchColorStop[] | undefined\n): string | undefined {\n if (!colors || colors.length === 0) {\n return undefined;\n }\n\n if (colors.length === 1) {\n return toColorStop(colors[0] as SwatchColorStop).color;\n }\n\n const stops = colors.map(toColorStop);\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 =\n 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\nfunction normalizeHex(hex: string): string | null {\n const value = hex.trim().replace(/^#/, \"\");\n if (/^[\\da-f]{3}$/i.test(value)) {\n return [...value].map((part) => part + part).join(\"\");\n }\n if (/^[\\da-f]{6}$/i.test(value)) {\n return value;\n }\n return null;\n}\n\nfunction toColorStop(stop: SwatchColorStop): { color: string; ratio?: number } {\n return typeof stop === \"string\" ? { color: stop } : stop;\n}\n\nfunction 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\nfunction formatPercent(value: number): string {\n return `${Number.isInteger(value) ? value : Number(value.toFixed(2))}%`;\n}\n","import {\n type ObjectFit,\n PATTERNMODE_SIZE_VALUES,\n PATTERNMODE_SIZES,\n} from \"@patternmode/system\";\nimport type { ComponentType, HTMLAttributes, SVGProps } from \"react\";\n\nexport const SWATCH_SIZES = [\n ...PATTERNMODE_SIZES,\n \"4xl\",\n \"5xl\",\n \"6xl\",\n \"7xl\",\n] 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 function getSwatchSizeVariableStyle(\n size: SwatchSize,\n variableName = \"--patternmode-swatch-size\"\n): Record<string, string> {\n return {\n [variableName]: SWATCH_SIZE_VALUES[size],\n };\n}\n\nexport interface SwatchProps extends HTMLAttributes<HTMLElement> {\n background?: string;\n color?: string;\n colors?: SwatchColorStop[];\n /**\n * Atmosphere density (0 = diffuse wash, 1 = dense pools). Only applies when\n * `texture=\"atmosphere\"`. 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 flat?: boolean;\n /**\n * Atmosphere gravity (-1 = pools sink, 1 = pools rise). Only applies when\n * `texture=\"atmosphere\"`. Default 0.\n */\n gravity?: number;\n icon?: SwatchIcon;\n isLight?: boolean;\n objectFit?: ObjectFit;\n objectPosition?: string;\n onRemove?: () => void;\n raised?: boolean;\n removeLabel?: string;\n selected?: boolean;\n shape?: SwatchShape;\n showRing?: boolean;\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 unavailable?: boolean;\n}\n","import { getObjectSizingStyle, joinClassNames } from \"@patternmode/system\";\nimport type { CSSProperties, MouseEvent } from \"react\";\n\nimport { getSwatchAtmosphereBackground } from \"./SwatchAtmosphere\";\nimport { getSwatchColorsBackground, isLightColor } from \"./SwatchColors\";\nimport { getSwatchSizeVariableStyle, type SwatchProps } from \"./SwatchTypes\";\n\nexport function Swatch({\n \"aria-label\": ariaLabel,\n background,\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 = getSwatchColorsBackground(colors);\n const atmosphereBackground =\n texture === \"atmosphere\"\n ? getSwatchAtmosphereBackground(colors, { density, gravity })\n : undefined;\n const fill = background ?? atmosphereBackground ?? colorsBackground ?? color;\n const light =\n isLight ??\n (color && !background && !colorsBackground\n ? isLightColor(color as string)\n : false);\n const resolvedRemoveLabel =\n removeLabel ?? (ariaLabel ? `Remove ${ariaLabel}` : \"Remove\");\n\n const rootStyle = {\n ...getSwatchSizeVariableStyle(size),\n \"--patternmode-swatch-fill\": fill,\n ...style,\n } as CSSProperties;\n const mediaStyle = getObjectSizingStyle({\n fit: objectFit,\n position: objectPosition,\n }) as CSSProperties;\n\n function handleRemove(event: MouseEvent<HTMLButtonElement>) {\n event.stopPropagation();\n onRemove?.();\n }\n\n const swatchContent = (\n <>\n <span aria-hidden=\"true\" className=\"patternmode-swatch__fill\" />\n {children ? (\n <span className=\"patternmode-swatch__media\" style={mediaStyle}>\n {children}\n </span>\n ) : null}\n {flat ? null : (\n <span aria-hidden=\"true\" className=\"patternmode-swatch__scrim\" />\n )}\n {selected && Icon ? (\n <span className=\"patternmode-swatch__icon\">\n <Icon aria-hidden=\"true\" focusable=\"false\" />\n </span>\n ) : null}\n {unavailable ? (\n <span aria-hidden=\"true\" className=\"patternmode-swatch__slash\" />\n ) : null}\n </>\n );\n\n if (onRemove) {\n return (\n <fieldset\n {...props}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\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={light ? \"light\" : \"dark\"}\n data-unavailable={unavailable ? \"true\" : undefined}\n style={rootStyle}\n >\n {swatchContent}\n <button\n aria-label={resolvedRemoveLabel}\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\n return (\n <figure\n {...props}\n aria-label={ariaLabel}\n className={joinClassNames(\"patternmode-swatch\", className)}\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={light ? \"light\" : \"dark\"}\n data-unavailable={unavailable ? \"true\" : undefined}\n style={rootStyle}\n >\n {swatchContent}\n </figure>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "@patternmode/swatch",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "private": false,
5
5
  "description": "Color, gradient, image, and palette swatch primitives for Patternmode interfaces.",
6
- "type": "module",
7
- "sideEffects": [
8
- "**/*.css"
6
+ "keywords": [
7
+ "color",
8
+ "component",
9
+ "palette",
10
+ "patternmode",
11
+ "react",
12
+ "swatch"
9
13
  ],
14
+ "homepage": "https://github.com/howells/patternmode/tree/main/packages/swatch#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/howells/patternmode/issues"
17
+ },
10
18
  "license": "MIT",
11
19
  "author": "Daniel Howells",
12
20
  "repository": {
@@ -14,13 +22,13 @@
14
22
  "url": "git+ssh://git@github.com/howells/patternmode.git",
15
23
  "directory": "packages/swatch"
16
24
  },
17
- "bugs": {
18
- "url": "https://github.com/howells/patternmode/issues"
19
- },
20
- "homepage": "https://github.com/howells/patternmode/tree/main/packages/swatch#readme",
21
25
  "files": [
22
26
  "dist"
23
27
  ],
28
+ "type": "module",
29
+ "sideEffects": [
30
+ "**/*.css"
31
+ ],
24
32
  "exports": {
25
33
  ".": {
26
34
  "types": "./dist/index.d.ts",
@@ -32,27 +40,12 @@
32
40
  "publishConfig": {
33
41
  "access": "public"
34
42
  },
35
- "engines": {
36
- "node": ">=20"
37
- },
38
- "keywords": [
39
- "swatch",
40
- "palette",
41
- "color",
42
- "react",
43
- "component",
44
- "patternmode"
45
- ],
46
43
  "dependencies": {
47
44
  "motion": "^12.38.0",
48
- "@patternmode/system": "0.2.1"
49
- },
50
- "peerDependencies": {
51
- "react": "^18.0.0 || ^19.0.0",
52
- "react-dom": "^18.0.0 || ^19.0.0"
45
+ "@patternmode/system": "0.2.2"
53
46
  },
54
47
  "devDependencies": {
55
- "@howells/lint": "^0.1.8",
48
+ "@howells/lint": "^0.2.0",
56
49
  "@howells/typescript-config": "^0.1.2",
57
50
  "@tailwindcss/cli": "^4.3.0",
58
51
  "@testing-library/jest-dom": "^6.9.1",
@@ -69,6 +62,13 @@
69
62
  "typescript": "^6.0.3",
70
63
  "vitest": "^4.1.6"
71
64
  },
65
+ "peerDependencies": {
66
+ "react": "^18.0.0 || ^19.0.0",
67
+ "react-dom": "^18.0.0 || ^19.0.0"
68
+ },
69
+ "engines": {
70
+ "node": ">=20"
71
+ },
72
72
  "scripts": {
73
73
  "build": "tsdown && tsc --emitDeclarationOnly --declaration --declarationMap --outDir dist --noEmit false && pnpm build:styles",
74
74
  "build:styles": "tailwindcss -i ./src/styles.css -o ./dist/styles.css --minify",
@@ -77,9 +77,8 @@
77
77
  "dev:js": "tsdown --watch",
78
78
  "dev:styles": "tailwindcss -i ./src/styles.css -o ./dist/styles.css --watch",
79
79
  "dev:types": "tsc --emitDeclarationOnly --declaration --declarationMap --outDir dist --noEmit false --watch --preserveWatchOutput",
80
- "lint": "howells-lint .",
81
- "lint:fix": "howells-format .",
82
- "lint:strict": "howells-lint-strict .",
80
+ "lint": "howells-ox-check .",
81
+ "lint:fix": "howells-ox-fix .",
83
82
  "test": "vitest run",
84
83
  "typecheck": "tsc --noEmit"
85
84
  }