@nswds/app 1.97.15 → 1.98.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/globals.css +232 -0
- package/dist/index.cjs +734 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +732 -146
- package/dist/index.js.map +1 -1
- package/dist/styles.css +226 -0
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,8 @@ var LabelPrimitive = require('@radix-ui/react-label');
|
|
|
40
40
|
var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
|
|
41
41
|
var TabsPrimitives = require('@radix-ui/react-tabs');
|
|
42
42
|
var CollapsiblePrimitive = require('@radix-ui/react-collapsible');
|
|
43
|
+
var ToggleGroupPrimitive = require('@radix-ui/react-toggle-group');
|
|
44
|
+
var TogglePrimitive = require('@radix-ui/react-toggle');
|
|
43
45
|
var cmdk = require('cmdk');
|
|
44
46
|
var DialogPrimitive = require('@radix-ui/react-dialog');
|
|
45
47
|
var ContextMenuPrimitive = require('@radix-ui/react-context-menu');
|
|
@@ -47,8 +49,6 @@ var reactTable = require('@tanstack/react-table');
|
|
|
47
49
|
var SeparatorPrimitive = require('@radix-ui/react-separator');
|
|
48
50
|
var vaul = require('vaul');
|
|
49
51
|
var reactHookForm = require('react-hook-form');
|
|
50
|
-
var ToggleGroupPrimitive = require('@radix-ui/react-toggle-group');
|
|
51
|
-
var TogglePrimitive = require('@radix-ui/react-toggle');
|
|
52
52
|
var Image2 = require('next/image');
|
|
53
53
|
var HoverCardPrimitive = require('@radix-ui/react-hover-card');
|
|
54
54
|
var inputOtp = require('input-otp');
|
|
@@ -110,11 +110,11 @@ var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
|
|
|
110
110
|
var RadioGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(RadioGroupPrimitive);
|
|
111
111
|
var TabsPrimitives__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitives);
|
|
112
112
|
var CollapsiblePrimitive__namespace = /*#__PURE__*/_interopNamespace(CollapsiblePrimitive);
|
|
113
|
+
var ToggleGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(ToggleGroupPrimitive);
|
|
114
|
+
var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespace(TogglePrimitive);
|
|
113
115
|
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
|
|
114
116
|
var ContextMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(ContextMenuPrimitive);
|
|
115
117
|
var SeparatorPrimitive__namespace = /*#__PURE__*/_interopNamespace(SeparatorPrimitive);
|
|
116
|
-
var ToggleGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(ToggleGroupPrimitive);
|
|
117
|
-
var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespace(TogglePrimitive);
|
|
118
118
|
var Image2__default = /*#__PURE__*/_interopDefault(Image2);
|
|
119
119
|
var HoverCardPrimitive__namespace = /*#__PURE__*/_interopNamespace(HoverCardPrimitive);
|
|
120
120
|
var MenubarPrimitive__namespace = /*#__PURE__*/_interopNamespace(MenubarPrimitive);
|
|
@@ -14972,6 +14972,734 @@ function ColorCard({ name, token, hex: hex2, rgb: rgb2, hsl, oklch: oklch2, form
|
|
|
14972
14972
|
] })
|
|
14973
14973
|
] }) });
|
|
14974
14974
|
}
|
|
14975
|
+
var recommendedBackgroundTones = [100, 200, 400, 500, 600, 700, 800];
|
|
14976
|
+
var AAA_NORMAL_TEXT_RATIO = 7;
|
|
14977
|
+
function extractTone(token) {
|
|
14978
|
+
const match = token.match(/-(\d+)$/);
|
|
14979
|
+
return match ? Number.parseInt(match[1], 10) : 0;
|
|
14980
|
+
}
|
|
14981
|
+
function formatFamilyLabel(name, key) {
|
|
14982
|
+
if (key === "grey") return "Grey";
|
|
14983
|
+
return name.replace(/^NSW Aboriginal\s+/i, "").replace(/^NSW\s+/i, "").trim();
|
|
14984
|
+
}
|
|
14985
|
+
function toPairingColor(color2) {
|
|
14986
|
+
return {
|
|
14987
|
+
...color2,
|
|
14988
|
+
tone: extractTone(color2.token)
|
|
14989
|
+
};
|
|
14990
|
+
}
|
|
14991
|
+
function getPreferredForegroundTone(backgroundTone) {
|
|
14992
|
+
if (backgroundTone <= 200) return 800;
|
|
14993
|
+
if (backgroundTone <= 500) return 700;
|
|
14994
|
+
if (backgroundTone <= 650) return 250;
|
|
14995
|
+
return 200;
|
|
14996
|
+
}
|
|
14997
|
+
function getPairRating(contrastRatio) {
|
|
14998
|
+
if (contrastRatio >= 7) return "AAA";
|
|
14999
|
+
if (contrastRatio >= 4.5) return "AA";
|
|
15000
|
+
return "AA Large";
|
|
15001
|
+
}
|
|
15002
|
+
function isPreferredDirection(backgroundTone, foregroundTone, preferredForegroundTone) {
|
|
15003
|
+
if (preferredForegroundTone < backgroundTone) {
|
|
15004
|
+
return foregroundTone < backgroundTone;
|
|
15005
|
+
}
|
|
15006
|
+
return foregroundTone > backgroundTone;
|
|
15007
|
+
}
|
|
15008
|
+
function buildPair(background, foreground) {
|
|
15009
|
+
const contrastRatio = culori__namespace.wcagContrast(background.hex, foreground.hex);
|
|
15010
|
+
return {
|
|
15011
|
+
id: `${background.token}:${foreground.token}`,
|
|
15012
|
+
background,
|
|
15013
|
+
foreground,
|
|
15014
|
+
contrastRatio,
|
|
15015
|
+
passes: {
|
|
15016
|
+
aaLarge: contrastRatio >= 3,
|
|
15017
|
+
aaText: contrastRatio >= 4.5,
|
|
15018
|
+
aaaLarge: contrastRatio >= 4.5,
|
|
15019
|
+
aaaText: contrastRatio >= 7
|
|
15020
|
+
},
|
|
15021
|
+
rating: getPairRating(contrastRatio)
|
|
15022
|
+
};
|
|
15023
|
+
}
|
|
15024
|
+
function pickForeground(colorsToPair, background, minimumRatio) {
|
|
15025
|
+
const preferredForegroundTone = getPreferredForegroundTone(background.tone);
|
|
15026
|
+
const passingCandidates = colorsToPair.filter((color2) => color2.token !== background.token).map((color2) => buildPair(background, color2)).filter((pair) => pair.contrastRatio >= minimumRatio);
|
|
15027
|
+
if (passingCandidates.length === 0) return null;
|
|
15028
|
+
const preferredCandidates = passingCandidates.filter(
|
|
15029
|
+
(pair) => isPreferredDirection(background.tone, pair.foreground.tone, preferredForegroundTone)
|
|
15030
|
+
);
|
|
15031
|
+
const candidates = preferredCandidates.length > 0 ? preferredCandidates : passingCandidates;
|
|
15032
|
+
return candidates.sort((left, right) => {
|
|
15033
|
+
const leftTargetDelta = Math.abs(left.foreground.tone - preferredForegroundTone);
|
|
15034
|
+
const rightTargetDelta = Math.abs(right.foreground.tone - preferredForegroundTone);
|
|
15035
|
+
if (leftTargetDelta !== rightTargetDelta) {
|
|
15036
|
+
return leftTargetDelta - rightTargetDelta;
|
|
15037
|
+
}
|
|
15038
|
+
const leftToneGap = Math.abs(left.foreground.tone - background.tone);
|
|
15039
|
+
const rightToneGap = Math.abs(right.foreground.tone - background.tone);
|
|
15040
|
+
if (leftToneGap !== rightToneGap) {
|
|
15041
|
+
return rightToneGap - leftToneGap;
|
|
15042
|
+
}
|
|
15043
|
+
return right.contrastRatio - left.contrastRatio;
|
|
15044
|
+
})[0];
|
|
15045
|
+
}
|
|
15046
|
+
function buildRecommendedPairs(colorsToPair, minimumRatio) {
|
|
15047
|
+
const backgrounds = recommendedBackgroundTones.map((tone) => colorsToPair.find((color2) => color2.tone === tone)).filter((color2) => Boolean(color2));
|
|
15048
|
+
const recommendedPairs = [];
|
|
15049
|
+
for (const background of backgrounds) {
|
|
15050
|
+
const pair = pickForeground(colorsToPair, background, minimumRatio);
|
|
15051
|
+
if (!pair || recommendedPairs.some((item) => item.id === pair.id)) {
|
|
15052
|
+
continue;
|
|
15053
|
+
}
|
|
15054
|
+
recommendedPairs.push(pair);
|
|
15055
|
+
}
|
|
15056
|
+
return recommendedPairs;
|
|
15057
|
+
}
|
|
15058
|
+
function buildRecommendedCollections(minimumRatio) {
|
|
15059
|
+
return {
|
|
15060
|
+
brand: Object.entries(colors.brand).map(([key, palette]) => {
|
|
15061
|
+
const scale2 = palette.colors.map(toPairingColor);
|
|
15062
|
+
return {
|
|
15063
|
+
key,
|
|
15064
|
+
label: formatFamilyLabel(palette.name, key),
|
|
15065
|
+
paletteName: palette.name,
|
|
15066
|
+
colors: scale2,
|
|
15067
|
+
recommendedPairs: buildRecommendedPairs(scale2, minimumRatio)
|
|
15068
|
+
};
|
|
15069
|
+
}),
|
|
15070
|
+
aboriginal: Object.entries(colors.aboriginal).map(([key, palette]) => {
|
|
15071
|
+
const scale2 = palette.colors.map(toPairingColor);
|
|
15072
|
+
return {
|
|
15073
|
+
key,
|
|
15074
|
+
label: formatFamilyLabel(palette.name, key),
|
|
15075
|
+
paletteName: palette.name,
|
|
15076
|
+
colors: scale2,
|
|
15077
|
+
recommendedPairs: buildRecommendedPairs(scale2, minimumRatio)
|
|
15078
|
+
};
|
|
15079
|
+
})
|
|
15080
|
+
};
|
|
15081
|
+
}
|
|
15082
|
+
var recommendedAaaPairingCollections = buildRecommendedCollections(AAA_NORMAL_TEXT_RATIO);
|
|
15083
|
+
function getPairingColorValue(color2, format) {
|
|
15084
|
+
return getColorValue(color2, format);
|
|
15085
|
+
}
|
|
15086
|
+
var styles3 = {
|
|
15087
|
+
base: [
|
|
15088
|
+
// Base
|
|
15089
|
+
"inline-flex items-center justify-center gap-2 rounded-sm text-sm font-medium bg-transparent transition-all whitespace-nowrap cursor-pointer border-(--toggle-border) [--toggle-border:var(--color-grey-200)] text-grey-800",
|
|
15090
|
+
// States
|
|
15091
|
+
"data-[state=on]:bg-grey-100 data-[state=on]:text-grey-850",
|
|
15092
|
+
// Hover
|
|
15093
|
+
"hover:bg-grey-100 hover:text-grey-850",
|
|
15094
|
+
// Focus
|
|
15095
|
+
"focus:outline focus:outline-2 focus:outline-offset-0 focus:outline-(--toggle-border)",
|
|
15096
|
+
// Dark mode
|
|
15097
|
+
"dark:text-white",
|
|
15098
|
+
// Dark mode states
|
|
15099
|
+
"dark:data-[state=on]:bg-white/10 dark:data-[state=on]:text-white",
|
|
15100
|
+
// Dark mode hover
|
|
15101
|
+
"dark:hover:bg-white/10 dark:hover:text-white",
|
|
15102
|
+
// Disabled
|
|
15103
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
15104
|
+
// Icon
|
|
15105
|
+
'[&_svg]:pointer-events-none [&_svg:not([class*="size-"])]:size-4 [&_svg]:shrink-0',
|
|
15106
|
+
// Aria invalid
|
|
15107
|
+
"aria-invalid:ring-destructive/20 aria-invalid:border-destructive",
|
|
15108
|
+
// Aria invalid dark mode
|
|
15109
|
+
"dark:aria-invalid:ring-destructive/40"
|
|
15110
|
+
],
|
|
15111
|
+
outline: [
|
|
15112
|
+
// Base
|
|
15113
|
+
"text-grey-800 border [--toggle-border:var(--color-grey-300)]",
|
|
15114
|
+
// States
|
|
15115
|
+
"hover:[--toggle-border:var(--color-grey-400)]",
|
|
15116
|
+
// Dark mode
|
|
15117
|
+
"dark:[--toggle-border:white]/40",
|
|
15118
|
+
// Dark mode states
|
|
15119
|
+
"dark:hover:[--toggle-border:white]/50",
|
|
15120
|
+
// Data on
|
|
15121
|
+
"data-[state=on]:bg-primary-800/10"
|
|
15122
|
+
]
|
|
15123
|
+
};
|
|
15124
|
+
var toggleVariants = classVarianceAuthority.cva(styles3.base, {
|
|
15125
|
+
variants: {
|
|
15126
|
+
variant: {
|
|
15127
|
+
ghost: "",
|
|
15128
|
+
outline: clsx12__default.default(styles3.outline)
|
|
15129
|
+
},
|
|
15130
|
+
size: {
|
|
15131
|
+
default: "h-9 px-2 min-w-9",
|
|
15132
|
+
sm: "h-8 px-1.5 min-w-8",
|
|
15133
|
+
lg: "h-10 px-2.5 min-w-10"
|
|
15134
|
+
}
|
|
15135
|
+
},
|
|
15136
|
+
defaultVariants: {
|
|
15137
|
+
variant: "ghost",
|
|
15138
|
+
size: "default"
|
|
15139
|
+
}
|
|
15140
|
+
});
|
|
15141
|
+
function Toggle({
|
|
15142
|
+
className,
|
|
15143
|
+
variant,
|
|
15144
|
+
size,
|
|
15145
|
+
...props
|
|
15146
|
+
}) {
|
|
15147
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15148
|
+
TogglePrimitive__namespace.Root,
|
|
15149
|
+
{
|
|
15150
|
+
"data-slot": "toggle",
|
|
15151
|
+
className: cn(toggleVariants({ variant, size, className })),
|
|
15152
|
+
...props
|
|
15153
|
+
}
|
|
15154
|
+
);
|
|
15155
|
+
}
|
|
15156
|
+
var ToggleGroupContext = React5__namespace.createContext({
|
|
15157
|
+
size: "default",
|
|
15158
|
+
variant: "ghost"
|
|
15159
|
+
});
|
|
15160
|
+
function ToggleGroup({
|
|
15161
|
+
className,
|
|
15162
|
+
variant,
|
|
15163
|
+
size,
|
|
15164
|
+
children,
|
|
15165
|
+
...props
|
|
15166
|
+
}) {
|
|
15167
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15168
|
+
ToggleGroupPrimitive__namespace.Root,
|
|
15169
|
+
{
|
|
15170
|
+
"data-slot": "toggle-group",
|
|
15171
|
+
"data-variant": variant,
|
|
15172
|
+
"data-size": size,
|
|
15173
|
+
className: cn(
|
|
15174
|
+
"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs",
|
|
15175
|
+
className
|
|
15176
|
+
),
|
|
15177
|
+
...props,
|
|
15178
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ToggleGroupContext.Provider, { value: { variant, size }, children })
|
|
15179
|
+
}
|
|
15180
|
+
);
|
|
15181
|
+
}
|
|
15182
|
+
function ToggleGroupItem({
|
|
15183
|
+
className,
|
|
15184
|
+
children,
|
|
15185
|
+
variant,
|
|
15186
|
+
size,
|
|
15187
|
+
...props
|
|
15188
|
+
}) {
|
|
15189
|
+
const context = React5__namespace.useContext(ToggleGroupContext);
|
|
15190
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
15191
|
+
ToggleGroupPrimitive__namespace.Item,
|
|
15192
|
+
{
|
|
15193
|
+
"data-slot": "toggle-group-item",
|
|
15194
|
+
"data-variant": context.variant || variant,
|
|
15195
|
+
"data-size": context.size || size,
|
|
15196
|
+
className: cn(
|
|
15197
|
+
toggleVariants({
|
|
15198
|
+
variant: context.variant || variant,
|
|
15199
|
+
size: context.size || size
|
|
15200
|
+
}),
|
|
15201
|
+
"min-w-0 shrink-0 rounded-none shadow-none first:rounded-l-sm last:rounded-r-sm focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l",
|
|
15202
|
+
className
|
|
15203
|
+
),
|
|
15204
|
+
...props,
|
|
15205
|
+
children
|
|
15206
|
+
}
|
|
15207
|
+
);
|
|
15208
|
+
}
|
|
15209
|
+
function FormatToggle({ format, setFormat }) {
|
|
15210
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
15211
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Format:" }),
|
|
15212
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
15213
|
+
ToggleGroup,
|
|
15214
|
+
{
|
|
15215
|
+
type: "single",
|
|
15216
|
+
value: format,
|
|
15217
|
+
onValueChange: (value) => value && setFormat(value),
|
|
15218
|
+
children: [
|
|
15219
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleGroupItem, { value: "hex", "aria-label": "HEX format", children: "HEX" }),
|
|
15220
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleGroupItem, { value: "rgb", "aria-label": "RGB format", children: "RGB" }),
|
|
15221
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleGroupItem, { value: "hsl", "aria-label": "HSL format", children: "HSL" }),
|
|
15222
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleGroupItem, { value: "oklch", "aria-label": "OKLCH format", children: "OKLCH" })
|
|
15223
|
+
]
|
|
15224
|
+
}
|
|
15225
|
+
)
|
|
15226
|
+
] });
|
|
15227
|
+
}
|
|
15228
|
+
function getPreferredFamilyKey(families) {
|
|
15229
|
+
return families.find((family) => family.key === "green")?.key ?? families[0]?.key ?? "";
|
|
15230
|
+
}
|
|
15231
|
+
function getDefaultPair(family) {
|
|
15232
|
+
if (!family || family.recommendedPairs.length === 0) return null;
|
|
15233
|
+
return family.recommendedPairs.reduce((bestPair, pair) => {
|
|
15234
|
+
const bestDelta = Math.abs(bestPair.background.tone - 600);
|
|
15235
|
+
const currentDelta = Math.abs(pair.background.tone - 600);
|
|
15236
|
+
return currentDelta < bestDelta ? pair : bestPair;
|
|
15237
|
+
}, family.recommendedPairs[0]);
|
|
15238
|
+
}
|
|
15239
|
+
function getFamilySwatchColor(family) {
|
|
15240
|
+
return family.colors.find((color2) => color2.tone === 500)?.hex ?? family.colors.find((color2) => color2.tone === 400)?.hex ?? family.colors[Math.min(3, family.colors.length - 1)]?.hex ?? "transparent";
|
|
15241
|
+
}
|
|
15242
|
+
function ColorPairingToolLoading() {
|
|
15243
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse space-y-6", children: [
|
|
15244
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-40 rounded-md border border-grey-200 bg-grey-50 dark:border-grey-700 dark:bg-grey-900" }),
|
|
15245
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-6 xl:grid-cols-[minmax(0,1.3fr)_minmax(20rem,0.9fr)]", children: [
|
|
15246
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-96 rounded-md border border-grey-200 bg-grey-50 dark:border-grey-700 dark:bg-grey-900" }),
|
|
15247
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-96 rounded-md border border-grey-200 bg-grey-50 dark:border-grey-700 dark:bg-grey-900" })
|
|
15248
|
+
] })
|
|
15249
|
+
] });
|
|
15250
|
+
}
|
|
15251
|
+
function getInitialPairingState(searchParams) {
|
|
15252
|
+
const paletteParam = searchParams.get("palette");
|
|
15253
|
+
const familyParam = searchParams.get("family");
|
|
15254
|
+
const pairParam = searchParams.get("pair");
|
|
15255
|
+
const themeCategory = paletteParam === "brand" || paletteParam === "aboriginal" ? paletteParam : "brand";
|
|
15256
|
+
const families = recommendedAaaPairingCollections[themeCategory];
|
|
15257
|
+
const familyKey = families.some((family) => family.key === familyParam) ? familyParam : getPreferredFamilyKey(families);
|
|
15258
|
+
const activeFamily = families.find((family) => family.key === familyKey) ?? families[0];
|
|
15259
|
+
const defaultPair = getDefaultPair(activeFamily);
|
|
15260
|
+
const selectedPairId = activeFamily?.recommendedPairs.some((pair) => pair.id === pairParam) ? pairParam : defaultPair?.id ?? "";
|
|
15261
|
+
return { familyKey, selectedPairId, themeCategory };
|
|
15262
|
+
}
|
|
15263
|
+
function PairPreview({ family, pair }) {
|
|
15264
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "gap-0 overflow-hidden py-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
15265
|
+
"div",
|
|
15266
|
+
{
|
|
15267
|
+
className: "p-6 sm:min-h-[26rem] sm:p-8",
|
|
15268
|
+
style: {
|
|
15269
|
+
backgroundColor: pair.background.hex,
|
|
15270
|
+
color: pair.foreground.hex
|
|
15271
|
+
},
|
|
15272
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-[22rem] flex-col justify-between gap-8", children: [
|
|
15273
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
15274
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
15275
|
+
"span",
|
|
15276
|
+
{
|
|
15277
|
+
className: "inline-flex items-center gap-2 rounded-full border px-3 py-1 text-[0.72rem] font-semibold tracking-[0.16em] uppercase",
|
|
15278
|
+
style: {
|
|
15279
|
+
borderColor: pair.foreground.hex,
|
|
15280
|
+
backgroundColor: pair.foreground.hex,
|
|
15281
|
+
color: pair.background.hex
|
|
15282
|
+
},
|
|
15283
|
+
children: [
|
|
15284
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.palette, { "data-slot": "icon", className: "size-4" }),
|
|
15285
|
+
family.label
|
|
15286
|
+
]
|
|
15287
|
+
}
|
|
15288
|
+
),
|
|
15289
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
15290
|
+
"span",
|
|
15291
|
+
{
|
|
15292
|
+
className: "inline-flex rounded-full border px-3 py-1 text-[0.72rem] font-semibold tracking-[0.16em] uppercase",
|
|
15293
|
+
style: {
|
|
15294
|
+
borderColor: pair.foreground.hex
|
|
15295
|
+
},
|
|
15296
|
+
children: [
|
|
15297
|
+
pair.rating,
|
|
15298
|
+
" ",
|
|
15299
|
+
pair.contrastRatio.toFixed(2),
|
|
15300
|
+
":1"
|
|
15301
|
+
]
|
|
15302
|
+
}
|
|
15303
|
+
)
|
|
15304
|
+
] }),
|
|
15305
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-xl space-y-4 pb-12 sm:pb-16", children: [
|
|
15306
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold tracking-[0.22em] uppercase", children: "Tone on tone" }),
|
|
15307
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
15308
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "max-w-lg text-4xl leading-none font-bold text-current sm:text-5xl", children: "Pair colour with confidence." }),
|
|
15309
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-md text-sm/6 sm:text-base/7", children: "Use only AAA-approved tone-on-tone combinations for headings, body copy, and calls to action on colour." })
|
|
15310
|
+
] })
|
|
15311
|
+
] }),
|
|
15312
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
15313
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
15314
|
+
"span",
|
|
15315
|
+
{
|
|
15316
|
+
className: "inline-flex items-center gap-2 rounded-full px-4 py-2 text-sm font-semibold",
|
|
15317
|
+
style: {
|
|
15318
|
+
backgroundColor: pair.foreground.hex,
|
|
15319
|
+
color: pair.background.hex
|
|
15320
|
+
},
|
|
15321
|
+
children: [
|
|
15322
|
+
"Pass",
|
|
15323
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-4" })
|
|
15324
|
+
]
|
|
15325
|
+
}
|
|
15326
|
+
),
|
|
15327
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
15328
|
+
"span",
|
|
15329
|
+
{
|
|
15330
|
+
className: "inline-flex rounded-full border px-4 py-2 text-sm",
|
|
15331
|
+
style: {
|
|
15332
|
+
borderColor: pair.foreground.hex
|
|
15333
|
+
},
|
|
15334
|
+
children: [
|
|
15335
|
+
pair.background.token,
|
|
15336
|
+
" / ",
|
|
15337
|
+
pair.foreground.token
|
|
15338
|
+
]
|
|
15339
|
+
}
|
|
15340
|
+
)
|
|
15341
|
+
] })
|
|
15342
|
+
] })
|
|
15343
|
+
}
|
|
15344
|
+
) });
|
|
15345
|
+
}
|
|
15346
|
+
function PairDetailCard({
|
|
15347
|
+
color: color2,
|
|
15348
|
+
format,
|
|
15349
|
+
role
|
|
15350
|
+
}) {
|
|
15351
|
+
const [, copyToClipboardRaw] = usehooks.useCopyToClipboard();
|
|
15352
|
+
const [copiedField, setCopiedField] = React5.useState(null);
|
|
15353
|
+
const valueLabel = format.toUpperCase();
|
|
15354
|
+
const formattedValue = getPairingColorValue(color2, format);
|
|
15355
|
+
const copyField = (field) => {
|
|
15356
|
+
const fieldValue = field === "token" ? color2.token : field === "tone" ? String(color2.tone) : formattedValue;
|
|
15357
|
+
copyToClipboardRaw(fieldValue);
|
|
15358
|
+
setCopiedField(field);
|
|
15359
|
+
const toastLabel = field === "token" ? "Token" : field === "tone" ? "Tone" : `${valueLabel} value`;
|
|
15360
|
+
sonner.toast(`${toastLabel} copied to clipboard`, {
|
|
15361
|
+
duration: 2e3
|
|
15362
|
+
});
|
|
15363
|
+
setTimeout(() => setCopiedField(null), 2e3);
|
|
15364
|
+
};
|
|
15365
|
+
const renderCopyButton = (field, srLabel, className) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15366
|
+
Button2,
|
|
15367
|
+
{
|
|
15368
|
+
variant: "ghost",
|
|
15369
|
+
size: "icon",
|
|
15370
|
+
className: cn("shrink-0", className),
|
|
15371
|
+
onClick: () => copyField(field),
|
|
15372
|
+
children: [
|
|
15373
|
+
copiedField === field ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-5" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
|
|
15374
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: srLabel })
|
|
15375
|
+
]
|
|
15376
|
+
}
|
|
15377
|
+
);
|
|
15378
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "gap-4", children: [
|
|
15379
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "gap-3 border-b", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
|
|
15380
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
15381
|
+
"div",
|
|
15382
|
+
{
|
|
15383
|
+
className: "size-14 rounded-2xl border border-grey-200 shadow-sm dark:border-grey-700",
|
|
15384
|
+
style: { backgroundColor: color2.hex }
|
|
15385
|
+
}
|
|
15386
|
+
),
|
|
15387
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
15388
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { children: role }),
|
|
15389
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: color2.name ?? color2.token })
|
|
15390
|
+
] })
|
|
15391
|
+
] }) }),
|
|
15392
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "grid gap-4", children: [
|
|
15393
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
15394
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
15395
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold tracking-[0.16em] text-muted-foreground uppercase", children: "Token" }),
|
|
15396
|
+
renderCopyButton("token", `Copy ${role.toLowerCase()} token`)
|
|
15397
|
+
] }),
|
|
15398
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-base break-all", children: color2.token })
|
|
15399
|
+
] }),
|
|
15400
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
15401
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
15402
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold tracking-[0.16em] text-muted-foreground uppercase", children: "Tone" }),
|
|
15403
|
+
renderCopyButton("tone", `Copy ${role.toLowerCase()} tone`)
|
|
15404
|
+
] }),
|
|
15405
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: color2.tone })
|
|
15406
|
+
] }),
|
|
15407
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
15408
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
15409
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold tracking-[0.16em] text-muted-foreground uppercase", children: valueLabel }),
|
|
15410
|
+
renderCopyButton("value", `Copy ${role.toLowerCase()} ${valueLabel} value`)
|
|
15411
|
+
] }),
|
|
15412
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-sm break-all", children: formattedValue })
|
|
15413
|
+
] })
|
|
15414
|
+
] })
|
|
15415
|
+
] });
|
|
15416
|
+
}
|
|
15417
|
+
function ComplianceRow({
|
|
15418
|
+
label,
|
|
15419
|
+
passes,
|
|
15420
|
+
threshold
|
|
15421
|
+
}) {
|
|
15422
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4 rounded-xl border border-grey-200 px-4 py-3 dark:border-grey-700", children: [
|
|
15423
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
15424
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: label }),
|
|
15425
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: threshold })
|
|
15426
|
+
] }),
|
|
15427
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
15428
|
+
"span",
|
|
15429
|
+
{
|
|
15430
|
+
className: cn(
|
|
15431
|
+
"inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-semibold",
|
|
15432
|
+
passes ? "bg-success-50 text-success-800 dark:bg-success-950/30 dark:text-success-200" : "bg-danger-50 text-danger-800 dark:bg-danger-950/30 dark:text-danger-200"
|
|
15433
|
+
),
|
|
15434
|
+
children: [
|
|
15435
|
+
passes ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.close, { "data-slot": "icon", className: "size-4" }),
|
|
15436
|
+
passes ? "Pass" : "Fail"
|
|
15437
|
+
]
|
|
15438
|
+
}
|
|
15439
|
+
)
|
|
15440
|
+
] });
|
|
15441
|
+
}
|
|
15442
|
+
function PairComplianceCard({ pair }) {
|
|
15443
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { children: [
|
|
15444
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "gap-2 border-b", children: [
|
|
15445
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-base", children: "AAA compliance" }),
|
|
15446
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "Only pairs that pass AAA normal-text contrast are suggested here. Evaluation uses the raw contrast ratio, not the rounded display value." })
|
|
15447
|
+
] }),
|
|
15448
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-3", children: [
|
|
15449
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-grey-200 bg-grey-50 px-4 py-3 dark:border-grey-700 dark:bg-grey-900/60", children: [
|
|
15450
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold tracking-[0.16em] text-muted-foreground uppercase", children: "Contrast ratio" }),
|
|
15451
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-2xl font-semibold", children: [
|
|
15452
|
+
pair.contrastRatio.toFixed(2),
|
|
15453
|
+
":1"
|
|
15454
|
+
] })
|
|
15455
|
+
] }),
|
|
15456
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
15457
|
+
ComplianceRow,
|
|
15458
|
+
{
|
|
15459
|
+
label: "AAA normal text",
|
|
15460
|
+
passes: pair.passes.aaaText,
|
|
15461
|
+
threshold: "7.0:1 or higher"
|
|
15462
|
+
}
|
|
15463
|
+
),
|
|
15464
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
15465
|
+
ComplianceRow,
|
|
15466
|
+
{
|
|
15467
|
+
label: "AAA large text",
|
|
15468
|
+
passes: pair.passes.aaaLarge,
|
|
15469
|
+
threshold: "4.5:1 or higher"
|
|
15470
|
+
}
|
|
15471
|
+
)
|
|
15472
|
+
] })
|
|
15473
|
+
] });
|
|
15474
|
+
}
|
|
15475
|
+
function ColorPairingToolContent() {
|
|
15476
|
+
const searchParams = navigation.useSearchParams();
|
|
15477
|
+
const {
|
|
15478
|
+
familyKey: initialFamilyKey,
|
|
15479
|
+
selectedPairId: initialSelectedPairId,
|
|
15480
|
+
themeCategory: initialThemeCategory
|
|
15481
|
+
} = getInitialPairingState(searchParams);
|
|
15482
|
+
const [themeCategory, setThemeCategory] = React5.useState(initialThemeCategory);
|
|
15483
|
+
const [format, setFormat] = React5.useState("hex");
|
|
15484
|
+
const [activeFamilyKey, setActiveFamilyKey] = React5.useState(initialFamilyKey);
|
|
15485
|
+
const [selectedPairId, setSelectedPairId] = React5.useState(initialSelectedPairId);
|
|
15486
|
+
const families = recommendedAaaPairingCollections[themeCategory];
|
|
15487
|
+
const resolvedActiveFamilyKey = families.some((family) => family.key === activeFamilyKey) ? activeFamilyKey : getPreferredFamilyKey(families);
|
|
15488
|
+
const activeFamily = families.find((family) => family.key === resolvedActiveFamilyKey) ?? families[0];
|
|
15489
|
+
const selectedPair = activeFamily?.recommendedPairs.find((pair) => pair.id === selectedPairId) ?? getDefaultPair(activeFamily);
|
|
15490
|
+
const updateUrlParams = (nextThemeCategory, nextFamilyKey, nextSelectedPairId) => {
|
|
15491
|
+
const params = new URLSearchParams(window.location.search);
|
|
15492
|
+
params.set("palette", nextThemeCategory);
|
|
15493
|
+
params.set("family", nextFamilyKey);
|
|
15494
|
+
if (nextSelectedPairId) {
|
|
15495
|
+
params.set("pair", nextSelectedPairId);
|
|
15496
|
+
} else {
|
|
15497
|
+
params.delete("pair");
|
|
15498
|
+
}
|
|
15499
|
+
window.history.replaceState(
|
|
15500
|
+
null,
|
|
15501
|
+
"",
|
|
15502
|
+
`${window.location.pathname}?${params.toString()}${window.location.hash}`
|
|
15503
|
+
);
|
|
15504
|
+
};
|
|
15505
|
+
const handleThemeCategoryChange = (nextThemeCategory) => {
|
|
15506
|
+
const nextFamilies = recommendedAaaPairingCollections[nextThemeCategory];
|
|
15507
|
+
const nextFamilyKey = nextFamilies.some((family) => family.key === activeFamilyKey) ? activeFamilyKey : getPreferredFamilyKey(nextFamilies);
|
|
15508
|
+
const nextActiveFamily = nextFamilies.find((family) => family.key === nextFamilyKey) ?? nextFamilies[0];
|
|
15509
|
+
const nextSelectedPair = nextActiveFamily?.recommendedPairs.find((pair) => pair.id === selectedPairId) ?? getDefaultPair(nextActiveFamily);
|
|
15510
|
+
setThemeCategory(nextThemeCategory);
|
|
15511
|
+
setActiveFamilyKey(nextFamilyKey);
|
|
15512
|
+
setSelectedPairId(nextSelectedPair?.id ?? "");
|
|
15513
|
+
updateUrlParams(nextThemeCategory, nextFamilyKey, nextSelectedPair?.id ?? "");
|
|
15514
|
+
};
|
|
15515
|
+
const handleFamilyChange = (nextFamilyKey) => {
|
|
15516
|
+
const nextActiveFamily = families.find((family) => family.key === nextFamilyKey);
|
|
15517
|
+
const nextSelectedPair = nextActiveFamily?.recommendedPairs.find((pair) => pair.id === selectedPairId) ?? getDefaultPair(nextActiveFamily);
|
|
15518
|
+
setActiveFamilyKey(nextFamilyKey);
|
|
15519
|
+
setSelectedPairId(nextSelectedPair?.id ?? "");
|
|
15520
|
+
updateUrlParams(themeCategory, nextFamilyKey, nextSelectedPair?.id ?? "");
|
|
15521
|
+
};
|
|
15522
|
+
const handlePairChange = (nextSelectedPairId) => {
|
|
15523
|
+
setSelectedPairId(nextSelectedPairId);
|
|
15524
|
+
updateUrlParams(themeCategory, resolvedActiveFamilyKey, nextSelectedPairId);
|
|
15525
|
+
};
|
|
15526
|
+
if (!activeFamily || !selectedPair) {
|
|
15527
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { children: /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { children: [
|
|
15528
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { children: "No recommended AAA pairs available" }),
|
|
15529
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "No recommended pairs are available for the current palette." })
|
|
15530
|
+
] }) });
|
|
15531
|
+
}
|
|
15532
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
15533
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
15534
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
15535
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Palette:" }),
|
|
15536
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
15537
|
+
SegmentedControl,
|
|
15538
|
+
{
|
|
15539
|
+
value: themeCategory,
|
|
15540
|
+
onValueChange: (value) => handleThemeCategoryChange(value),
|
|
15541
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(SegmentedControlList, { className: "w-full sm:w-fit", children: [
|
|
15542
|
+
/* @__PURE__ */ jsxRuntime.jsx(SegmentedControlTrigger, { value: "brand", children: "Brand palette" }),
|
|
15543
|
+
/* @__PURE__ */ jsxRuntime.jsx(SegmentedControlTrigger, { value: "aboriginal", children: "Aboriginal palette" })
|
|
15544
|
+
] })
|
|
15545
|
+
}
|
|
15546
|
+
)
|
|
15547
|
+
] }),
|
|
15548
|
+
/* @__PURE__ */ jsxRuntime.jsx(FormatToggle, { format, setFormat })
|
|
15549
|
+
] }),
|
|
15550
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2 lg:grid-cols-4 xl:grid-cols-5", children: families.map((family) => {
|
|
15551
|
+
const isActive = family.key === resolvedActiveFamilyKey;
|
|
15552
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15553
|
+
"button",
|
|
15554
|
+
{
|
|
15555
|
+
type: "button",
|
|
15556
|
+
onClick: () => handleFamilyChange(family.key),
|
|
15557
|
+
className: cn(
|
|
15558
|
+
"group relative flex w-full items-center gap-3 rounded-sm border px-3 py-2 text-left transition-colors",
|
|
15559
|
+
"border-grey-200 bg-background hover:bg-primary-800/10 hover:text-foreground dark:hover:bg-white/10",
|
|
15560
|
+
isActive && "border-grey-800 dark:border-grey-400"
|
|
15561
|
+
),
|
|
15562
|
+
children: [
|
|
15563
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
15564
|
+
"span",
|
|
15565
|
+
{
|
|
15566
|
+
className: "size-4 shrink-0 rounded-full",
|
|
15567
|
+
style: { backgroundColor: getFamilySwatchColor(family) }
|
|
15568
|
+
}
|
|
15569
|
+
),
|
|
15570
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: family.label })
|
|
15571
|
+
]
|
|
15572
|
+
},
|
|
15573
|
+
family.key
|
|
15574
|
+
);
|
|
15575
|
+
}) }) }),
|
|
15576
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
15577
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid items-start gap-6 xl:grid-cols-[minmax(0,1.5fr)_minmax(17rem,0.68fr)]", children: [
|
|
15578
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
15579
|
+
/* @__PURE__ */ jsxRuntime.jsx(PairPreview, { family: activeFamily, pair: selectedPair }),
|
|
15580
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Card, { children: [
|
|
15581
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "gap-2 border-b", children: [
|
|
15582
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-base", children: "Background tone strip" }),
|
|
15583
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "Filled chips have a recommended AAA foreground pair. Select one to update the preview." })
|
|
15584
|
+
] }),
|
|
15585
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-4", children: [
|
|
15586
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-5 gap-2 sm:grid-cols-7 lg:grid-cols-10 xl:grid-cols-[repeat(19,minmax(0,1fr))]", children: activeFamily.colors.map((color2) => {
|
|
15587
|
+
const pair = activeFamily.recommendedPairs.find(
|
|
15588
|
+
(item) => item.background.token === color2.token
|
|
15589
|
+
);
|
|
15590
|
+
const isSelected = selectedPair.background.token === color2.token;
|
|
15591
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15592
|
+
"button",
|
|
15593
|
+
{
|
|
15594
|
+
type: "button",
|
|
15595
|
+
disabled: !pair,
|
|
15596
|
+
onClick: () => pair && handlePairChange(pair.id),
|
|
15597
|
+
className: cn(
|
|
15598
|
+
"group relative h-12 rounded-xl border transition-transform",
|
|
15599
|
+
pair ? "cursor-pointer border-grey-200 hover:scale-[1.03] dark:border-grey-700" : "cursor-not-allowed border-grey-100 dark:border-grey-800",
|
|
15600
|
+
isSelected && "ring-2 ring-primary-500 ring-offset-2 ring-offset-background"
|
|
15601
|
+
),
|
|
15602
|
+
style: { backgroundColor: color2.hex },
|
|
15603
|
+
children: [
|
|
15604
|
+
pair && /* @__PURE__ */ jsxRuntime.jsx(
|
|
15605
|
+
"span",
|
|
15606
|
+
{
|
|
15607
|
+
className: "absolute top-1/2 left-1/2 size-3 -translate-x-1/2 -translate-y-1/2 rounded-full border border-white/30 shadow-sm",
|
|
15608
|
+
style: { backgroundColor: pair.foreground.hex }
|
|
15609
|
+
}
|
|
15610
|
+
),
|
|
15611
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
|
|
15612
|
+
color2.token,
|
|
15613
|
+
pair ? ` paired with ${pair.foreground.token}` : " has no recommended pair in this tool"
|
|
15614
|
+
] })
|
|
15615
|
+
]
|
|
15616
|
+
},
|
|
15617
|
+
color2.token
|
|
15618
|
+
);
|
|
15619
|
+
}) }),
|
|
15620
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-4 text-sm text-muted-foreground", children: [
|
|
15621
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
15622
|
+
"Selected background:",
|
|
15623
|
+
" ",
|
|
15624
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { className: "text-foreground", children: selectedPair.background.token })
|
|
15625
|
+
] }),
|
|
15626
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
15627
|
+
"Recommended foreground:",
|
|
15628
|
+
" ",
|
|
15629
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { className: "text-foreground", children: selectedPair.foreground.token })
|
|
15630
|
+
] })
|
|
15631
|
+
] })
|
|
15632
|
+
] })
|
|
15633
|
+
] }),
|
|
15634
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [
|
|
15635
|
+
/* @__PURE__ */ jsxRuntime.jsx(PairDetailCard, { color: selectedPair.background, format, role: "Background" }),
|
|
15636
|
+
/* @__PURE__ */ jsxRuntime.jsx(PairDetailCard, { color: selectedPair.foreground, format, role: "Foreground" })
|
|
15637
|
+
] })
|
|
15638
|
+
] }),
|
|
15639
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "h-fit", children: [
|
|
15640
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "gap-2 border-b", children: [
|
|
15641
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-base", children: "Recommended pairs" }),
|
|
15642
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "Recommended same-family combinations that meet AAA normal-text contrast." })
|
|
15643
|
+
] }),
|
|
15644
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "grid gap-3", children: activeFamily.recommendedPairs.map((pair) => {
|
|
15645
|
+
const isActive = selectedPair.id === pair.id;
|
|
15646
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15647
|
+
"button",
|
|
15648
|
+
{
|
|
15649
|
+
type: "button",
|
|
15650
|
+
onClick: () => handlePairChange(pair.id),
|
|
15651
|
+
className: cn(
|
|
15652
|
+
"rounded-2xl border p-4 text-left transition-colors",
|
|
15653
|
+
isActive ? "border-primary-500 bg-primary-50/70 dark:bg-primary-950/30" : "border-grey-200 hover:border-grey-400 hover:bg-grey-50 dark:border-grey-700 dark:hover:border-grey-500 dark:hover:bg-grey-900/70"
|
|
15654
|
+
),
|
|
15655
|
+
children: [
|
|
15656
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
|
|
15657
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
15658
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
15659
|
+
"div",
|
|
15660
|
+
{
|
|
15661
|
+
className: "size-11 rounded-2xl border border-grey-200 shadow-sm dark:border-grey-700",
|
|
15662
|
+
style: { backgroundColor: pair.background.hex }
|
|
15663
|
+
}
|
|
15664
|
+
),
|
|
15665
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
15666
|
+
"div",
|
|
15667
|
+
{
|
|
15668
|
+
className: "size-11 rounded-2xl border border-grey-200 shadow-sm dark:border-grey-700",
|
|
15669
|
+
style: { backgroundColor: pair.foreground.hex }
|
|
15670
|
+
}
|
|
15671
|
+
)
|
|
15672
|
+
] }),
|
|
15673
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-full border border-grey-200 px-2.5 py-1 text-xs font-semibold text-muted-foreground dark:border-grey-700", children: [
|
|
15674
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.contrast, { "data-slot": "icon", className: "size-4" }),
|
|
15675
|
+
pair.rating
|
|
15676
|
+
] })
|
|
15677
|
+
] }),
|
|
15678
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-1", children: [
|
|
15679
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "font-medium text-foreground", children: [
|
|
15680
|
+
pair.background.token,
|
|
15681
|
+
" / ",
|
|
15682
|
+
pair.foreground.token
|
|
15683
|
+
] }),
|
|
15684
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
|
|
15685
|
+
pair.contrastRatio.toFixed(2),
|
|
15686
|
+
":1 contrast ratio"
|
|
15687
|
+
] })
|
|
15688
|
+
] })
|
|
15689
|
+
]
|
|
15690
|
+
},
|
|
15691
|
+
pair.id
|
|
15692
|
+
);
|
|
15693
|
+
}) })
|
|
15694
|
+
] }) })
|
|
15695
|
+
] }),
|
|
15696
|
+
/* @__PURE__ */ jsxRuntime.jsx(PairComplianceCard, { pair: selectedPair })
|
|
15697
|
+
] })
|
|
15698
|
+
] });
|
|
15699
|
+
}
|
|
15700
|
+
function ColorPairingTool() {
|
|
15701
|
+
return /* @__PURE__ */ jsxRuntime.jsx(React5.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(ColorPairingToolLoading, {}), children: /* @__PURE__ */ jsxRuntime.jsx(ColorPairingToolContent, {}) });
|
|
15702
|
+
}
|
|
14975
15703
|
function ColorSwatches({ theme: theme2, format, viewMode }) {
|
|
14976
15704
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14977
15705
|
"div",
|
|
@@ -17451,152 +18179,10 @@ function FormMessage({ className, ...props }) {
|
|
|
17451
18179
|
}
|
|
17452
18180
|
);
|
|
17453
18181
|
}
|
|
17454
|
-
var styles3 = {
|
|
17455
|
-
base: [
|
|
17456
|
-
// Base
|
|
17457
|
-
"inline-flex items-center justify-center gap-2 rounded-sm text-sm font-medium bg-transparent transition-all whitespace-nowrap cursor-pointer border-(--toggle-border) [--toggle-border:var(--color-grey-200)] text-grey-800",
|
|
17458
|
-
// States
|
|
17459
|
-
"data-[state=on]:bg-grey-100 data-[state=on]:text-grey-850",
|
|
17460
|
-
// Hover
|
|
17461
|
-
"hover:bg-grey-100 hover:text-grey-850",
|
|
17462
|
-
// Focus
|
|
17463
|
-
"focus:outline focus:outline-2 focus:outline-offset-0 focus:outline-(--toggle-border)",
|
|
17464
|
-
// Dark mode
|
|
17465
|
-
"dark:text-white",
|
|
17466
|
-
// Dark mode states
|
|
17467
|
-
"dark:data-[state=on]:bg-white/10 dark:data-[state=on]:text-white",
|
|
17468
|
-
// Dark mode hover
|
|
17469
|
-
"dark:hover:bg-white/10 dark:hover:text-white",
|
|
17470
|
-
// Disabled
|
|
17471
|
-
"disabled:pointer-events-none disabled:opacity-50",
|
|
17472
|
-
// Icon
|
|
17473
|
-
'[&_svg]:pointer-events-none [&_svg:not([class*="size-"])]:size-4 [&_svg]:shrink-0',
|
|
17474
|
-
// Aria invalid
|
|
17475
|
-
"aria-invalid:ring-destructive/20 aria-invalid:border-destructive",
|
|
17476
|
-
// Aria invalid dark mode
|
|
17477
|
-
"dark:aria-invalid:ring-destructive/40"
|
|
17478
|
-
],
|
|
17479
|
-
outline: [
|
|
17480
|
-
// Base
|
|
17481
|
-
"text-grey-800 border [--toggle-border:var(--color-grey-300)]",
|
|
17482
|
-
// States
|
|
17483
|
-
"hover:[--toggle-border:var(--color-grey-400)]",
|
|
17484
|
-
// Dark mode
|
|
17485
|
-
"dark:[--toggle-border:white]/40",
|
|
17486
|
-
// Dark mode states
|
|
17487
|
-
"dark:hover:[--toggle-border:white]/50",
|
|
17488
|
-
// Data on
|
|
17489
|
-
"data-[state=on]:bg-primary-800/10"
|
|
17490
|
-
]
|
|
17491
|
-
};
|
|
17492
|
-
var toggleVariants = classVarianceAuthority.cva(styles3.base, {
|
|
17493
|
-
variants: {
|
|
17494
|
-
variant: {
|
|
17495
|
-
ghost: "",
|
|
17496
|
-
outline: clsx12__default.default(styles3.outline)
|
|
17497
|
-
},
|
|
17498
|
-
size: {
|
|
17499
|
-
default: "h-9 px-2 min-w-9",
|
|
17500
|
-
sm: "h-8 px-1.5 min-w-8",
|
|
17501
|
-
lg: "h-10 px-2.5 min-w-10"
|
|
17502
|
-
}
|
|
17503
|
-
},
|
|
17504
|
-
defaultVariants: {
|
|
17505
|
-
variant: "ghost",
|
|
17506
|
-
size: "default"
|
|
17507
|
-
}
|
|
17508
|
-
});
|
|
17509
|
-
function Toggle({
|
|
17510
|
-
className,
|
|
17511
|
-
variant,
|
|
17512
|
-
size,
|
|
17513
|
-
...props
|
|
17514
|
-
}) {
|
|
17515
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17516
|
-
TogglePrimitive__namespace.Root,
|
|
17517
|
-
{
|
|
17518
|
-
"data-slot": "toggle",
|
|
17519
|
-
className: cn(toggleVariants({ variant, size, className })),
|
|
17520
|
-
...props
|
|
17521
|
-
}
|
|
17522
|
-
);
|
|
17523
|
-
}
|
|
17524
|
-
var ToggleGroupContext = React5__namespace.createContext({
|
|
17525
|
-
size: "default",
|
|
17526
|
-
variant: "ghost"
|
|
17527
|
-
});
|
|
17528
|
-
function ToggleGroup({
|
|
17529
|
-
className,
|
|
17530
|
-
variant,
|
|
17531
|
-
size,
|
|
17532
|
-
children,
|
|
17533
|
-
...props
|
|
17534
|
-
}) {
|
|
17535
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17536
|
-
ToggleGroupPrimitive__namespace.Root,
|
|
17537
|
-
{
|
|
17538
|
-
"data-slot": "toggle-group",
|
|
17539
|
-
"data-variant": variant,
|
|
17540
|
-
"data-size": size,
|
|
17541
|
-
className: cn(
|
|
17542
|
-
"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs",
|
|
17543
|
-
className
|
|
17544
|
-
),
|
|
17545
|
-
...props,
|
|
17546
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ToggleGroupContext.Provider, { value: { variant, size }, children })
|
|
17547
|
-
}
|
|
17548
|
-
);
|
|
17549
|
-
}
|
|
17550
|
-
function ToggleGroupItem({
|
|
17551
|
-
className,
|
|
17552
|
-
children,
|
|
17553
|
-
variant,
|
|
17554
|
-
size,
|
|
17555
|
-
...props
|
|
17556
|
-
}) {
|
|
17557
|
-
const context = React5__namespace.useContext(ToggleGroupContext);
|
|
17558
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17559
|
-
ToggleGroupPrimitive__namespace.Item,
|
|
17560
|
-
{
|
|
17561
|
-
"data-slot": "toggle-group-item",
|
|
17562
|
-
"data-variant": context.variant || variant,
|
|
17563
|
-
"data-size": context.size || size,
|
|
17564
|
-
className: cn(
|
|
17565
|
-
toggleVariants({
|
|
17566
|
-
variant: context.variant || variant,
|
|
17567
|
-
size: context.size || size
|
|
17568
|
-
}),
|
|
17569
|
-
"min-w-0 shrink-0 rounded-none shadow-none first:rounded-l-sm last:rounded-r-sm focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l",
|
|
17570
|
-
className
|
|
17571
|
-
),
|
|
17572
|
-
...props,
|
|
17573
|
-
children
|
|
17574
|
-
}
|
|
17575
|
-
);
|
|
17576
|
-
}
|
|
17577
|
-
function FormatToggle({ format, setFormat }) {
|
|
17578
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
17579
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Format:" }),
|
|
17580
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
17581
|
-
ToggleGroup,
|
|
17582
|
-
{
|
|
17583
|
-
type: "single",
|
|
17584
|
-
value: format,
|
|
17585
|
-
onValueChange: (value) => value && setFormat(value),
|
|
17586
|
-
children: [
|
|
17587
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleGroupItem, { value: "hex", "aria-label": "HEX format", children: "HEX" }),
|
|
17588
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleGroupItem, { value: "rgb", "aria-label": "RGB format", children: "RGB" }),
|
|
17589
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleGroupItem, { value: "hsl", "aria-label": "HSL format", children: "HSL" }),
|
|
17590
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleGroupItem, { value: "oklch", "aria-label": "OKLCH format", children: "OKLCH" })
|
|
17591
|
-
]
|
|
17592
|
-
}
|
|
17593
|
-
)
|
|
17594
|
-
] });
|
|
17595
|
-
}
|
|
17596
18182
|
|
|
17597
18183
|
// package.json
|
|
17598
18184
|
var package_default = {
|
|
17599
|
-
version: "1.
|
|
18185
|
+
version: "1.97.13"};
|
|
17600
18186
|
var SluggerContext = React5__namespace.default.createContext(null);
|
|
17601
18187
|
function flattenText(nodes) {
|
|
17602
18188
|
if (nodes == null || typeof nodes === "boolean") return "";
|
|
@@ -33838,6 +34424,7 @@ exports.Collapsible = Collapsible;
|
|
|
33838
34424
|
exports.CollapsibleContent = CollapsibleContent2;
|
|
33839
34425
|
exports.CollapsibleTrigger = CollapsibleTrigger2;
|
|
33840
34426
|
exports.ColorCard = ColorCard;
|
|
34427
|
+
exports.ColorPairingTool = ColorPairingTool;
|
|
33841
34428
|
exports.ColorSwatches = ColorSwatches;
|
|
33842
34429
|
exports.ColourScale = ColourScale;
|
|
33843
34430
|
exports.ComboChart = ComboChart;
|