@nswds/app 1.106.0 → 1.107.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 +127 -0
- package/dist/index.cjs +1618 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +1618 -1
- package/dist/index.js.map +1 -1
- package/dist/styles.css +127 -0
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20527,6 +20527,1623 @@ function ColorPairingToolV4({
|
|
|
20527
20527
|
}
|
|
20528
20528
|
) });
|
|
20529
20529
|
}
|
|
20530
|
+
var PREFERRED_BACKGROUND_TONES5 = [400, 600, 200, 800, 100, 50];
|
|
20531
|
+
var DEFAULT_VISIBLE_FORMATS5 = ["hex", "rgb", "hsl", "oklch"];
|
|
20532
|
+
var DEFAULT_INITIAL_BACKGROUND_TOKEN5 = "nsw-blue-800";
|
|
20533
|
+
var DEFAULT_INITIAL_PAIR_ID5 = "nsw-blue-800:nsw-blue-200";
|
|
20534
|
+
var COLOR_PAIRING_TOOL_V5_PATH = "/core/colour/colour-pairing-tool-5";
|
|
20535
|
+
var MOBILE_RESULT_SCROLL_QUERY3 = "(max-width: 1023px)";
|
|
20536
|
+
var PERSISTENT_DRAWER_MIN_WIDTH_QUERY3 = "(min-width: 1280px)";
|
|
20537
|
+
var INITIAL_VISIBLE_ALTERNATIVES2 = 6;
|
|
20538
|
+
var COLOR_PAIRING_TOOL_DRAWER_STEPS3 = [
|
|
20539
|
+
{
|
|
20540
|
+
id: "colours",
|
|
20541
|
+
title: "Choose colours",
|
|
20542
|
+
eyebrow: "Step 1 of 3",
|
|
20543
|
+
description: "Select the palette, primary family, and accent family."
|
|
20544
|
+
},
|
|
20545
|
+
{
|
|
20546
|
+
id: "backgrounds",
|
|
20547
|
+
title: "Choose background",
|
|
20548
|
+
eyebrow: "Step 2 of 3",
|
|
20549
|
+
description: "Pick the background tone that you want to pair."
|
|
20550
|
+
},
|
|
20551
|
+
{
|
|
20552
|
+
id: "refine",
|
|
20553
|
+
title: "Refine or override recommendation",
|
|
20554
|
+
eyebrow: "Step 3 of 3",
|
|
20555
|
+
description: "Use the result panel to review the NSW default pairing and override it only when a different approved option is needed."
|
|
20556
|
+
}
|
|
20557
|
+
];
|
|
20558
|
+
var COLOR_PAIRING_TOOL_V5_ANALYTICS_EVENT = "nsw-colour-pairing-tool-v5";
|
|
20559
|
+
function getToneFromToken5(token) {
|
|
20560
|
+
if (!token) return null;
|
|
20561
|
+
const match = token.match(/-(\d+)$/);
|
|
20562
|
+
return match ? Number.parseInt(match[1], 10) : null;
|
|
20563
|
+
}
|
|
20564
|
+
function getFamilySwatchColor5(family, preferredTone = 600) {
|
|
20565
|
+
const exactMatch = family.colors.find((color2) => color2.tone === preferredTone);
|
|
20566
|
+
if (exactMatch) {
|
|
20567
|
+
return exactMatch.hex;
|
|
20568
|
+
}
|
|
20569
|
+
const closestMatch = [...family.colors].sort(
|
|
20570
|
+
(left, right) => Math.abs(left.tone - preferredTone) - Math.abs(right.tone - preferredTone)
|
|
20571
|
+
)[0];
|
|
20572
|
+
return closestMatch?.hex ?? "transparent";
|
|
20573
|
+
}
|
|
20574
|
+
function getFamilySelectorLabel5(family, themeCategory, selectionRole) {
|
|
20575
|
+
if (themeCategory !== "aboriginal") {
|
|
20576
|
+
return family.label;
|
|
20577
|
+
}
|
|
20578
|
+
const preferredTone = selectionRole === "primary colour" ? 800 : 600;
|
|
20579
|
+
return family.colors.find((color2) => color2.tone === preferredTone)?.name ?? family.label;
|
|
20580
|
+
}
|
|
20581
|
+
function getPairingColorDisplayName5(color2) {
|
|
20582
|
+
return color2.name ?? `${color2.familyLabel} ${color2.tone}`;
|
|
20583
|
+
}
|
|
20584
|
+
function isWhiteForegroundPair5(pair) {
|
|
20585
|
+
return pair.foreground.token === "white";
|
|
20586
|
+
}
|
|
20587
|
+
function isLargeTextOnlyPair3(pair) {
|
|
20588
|
+
return pair.passes.aaaLarge && !pair.passes.aaaText;
|
|
20589
|
+
}
|
|
20590
|
+
function getWhiteForegroundGuidance5(pair) {
|
|
20591
|
+
if (pair.passes.aaaText) {
|
|
20592
|
+
return "White is approved for headings, body copy, and calls to action on this background.";
|
|
20593
|
+
}
|
|
20594
|
+
if (pair.passes.aaaLarge) {
|
|
20595
|
+
return "Use white only for WCAG large text on this background, such as headings at 24px+ or bold text at 18.5px+. Keep sentence-case body copy at 16px+ and use a darker recommended foreground instead.";
|
|
20596
|
+
}
|
|
20597
|
+
return "Do not use white on this background. Choose one of the recommended foregrounds below instead.";
|
|
20598
|
+
}
|
|
20599
|
+
function getPreviewGuidance5(pair, isRecommended) {
|
|
20600
|
+
if (!isWhiteForegroundPair5(pair)) {
|
|
20601
|
+
return isRecommended ? "Use this pairing for headings, body copy, and actions on the selected background." : "Use this approved alternative when you need a different tone or stronger emphasis.";
|
|
20602
|
+
}
|
|
20603
|
+
if (isRecommended) {
|
|
20604
|
+
return "Use white text on this background for headings, body copy, and actions only while it maintains AAA contrast.";
|
|
20605
|
+
}
|
|
20606
|
+
return getWhiteForegroundGuidance5(pair);
|
|
20607
|
+
}
|
|
20608
|
+
function getPreferredPairForBackground5(pairs, preferredPairId) {
|
|
20609
|
+
if (preferredPairId) {
|
|
20610
|
+
const preferredPair = pairs.find((pair) => pair.id === preferredPairId);
|
|
20611
|
+
if (preferredPair) {
|
|
20612
|
+
return preferredPair;
|
|
20613
|
+
}
|
|
20614
|
+
}
|
|
20615
|
+
return pairs.find((pair) => !isWhiteForegroundPair5(pair)) ?? pairs[0] ?? null;
|
|
20616
|
+
}
|
|
20617
|
+
function getDefaultBackgroundToken5(context) {
|
|
20618
|
+
for (const tone of PREFERRED_BACKGROUND_TONES5) {
|
|
20619
|
+
for (const group of context.backgroundGroups) {
|
|
20620
|
+
const match = group.backgrounds.find(
|
|
20621
|
+
(background) => background.tone === tone && (context.pairsByBackground[background.token]?.length ?? 0) > 0
|
|
20622
|
+
);
|
|
20623
|
+
if (match) {
|
|
20624
|
+
return match.token;
|
|
20625
|
+
}
|
|
20626
|
+
}
|
|
20627
|
+
}
|
|
20628
|
+
for (const tone of PREFERRED_BACKGROUND_TONES5) {
|
|
20629
|
+
for (const group of context.backgroundGroups) {
|
|
20630
|
+
const match = group.backgrounds.find((background) => background.tone === tone);
|
|
20631
|
+
if (match) {
|
|
20632
|
+
return match.token;
|
|
20633
|
+
}
|
|
20634
|
+
}
|
|
20635
|
+
}
|
|
20636
|
+
return context.backgrounds[0]?.token ?? "";
|
|
20637
|
+
}
|
|
20638
|
+
function resolveBackgroundToken5(context, preferredToken, preferredTone) {
|
|
20639
|
+
if (preferredToken && context.backgrounds.some((background) => background.token === preferredToken)) {
|
|
20640
|
+
return preferredToken;
|
|
20641
|
+
}
|
|
20642
|
+
if (preferredTone !== null && preferredTone !== void 0) {
|
|
20643
|
+
for (const group of context.backgroundGroups) {
|
|
20644
|
+
const match = group.backgrounds.find((background) => background.tone === preferredTone);
|
|
20645
|
+
if (match) {
|
|
20646
|
+
return match.token;
|
|
20647
|
+
}
|
|
20648
|
+
}
|
|
20649
|
+
}
|
|
20650
|
+
return getDefaultBackgroundToken5(context);
|
|
20651
|
+
}
|
|
20652
|
+
function getInitialPairingState5(searchParams) {
|
|
20653
|
+
const paletteParam = searchParams.get("palette");
|
|
20654
|
+
const primaryParam = searchParams.get("primary");
|
|
20655
|
+
const accentParam = searchParams.get("accent");
|
|
20656
|
+
const pairParam = searchParams.get("pair");
|
|
20657
|
+
const backgroundParam = searchParams.get("background");
|
|
20658
|
+
const themeCategory = paletteParam === "brand" || paletteParam === "aboriginal" ? paletteParam : "brand";
|
|
20659
|
+
const context = getPairingContext(themeCategory, primaryParam, accentParam);
|
|
20660
|
+
const shouldUseDefaultBrandExample = !backgroundParam && !pairParam && themeCategory === "brand" && context.primary.key === "blue" && context.accent.key === "red";
|
|
20661
|
+
const defaultBackgroundToken = shouldUseDefaultBrandExample ? context.backgrounds.some(
|
|
20662
|
+
(background) => background.token === DEFAULT_INITIAL_BACKGROUND_TOKEN5
|
|
20663
|
+
) ? DEFAULT_INITIAL_BACKGROUND_TOKEN5 : null : null;
|
|
20664
|
+
const defaultPairId = shouldUseDefaultBrandExample && defaultBackgroundToken && context.pairsByBackground[defaultBackgroundToken]?.some(
|
|
20665
|
+
(pair) => pair.id === DEFAULT_INITIAL_PAIR_ID5
|
|
20666
|
+
) ? DEFAULT_INITIAL_PAIR_ID5 : null;
|
|
20667
|
+
const pairBackgroundToken = context.recommendedPairs.find((pair) => pair.id === pairParam)?.background.token ?? null;
|
|
20668
|
+
const selectedBackgroundToken = resolveBackgroundToken5(
|
|
20669
|
+
context,
|
|
20670
|
+
backgroundParam ?? pairBackgroundToken ?? defaultBackgroundToken,
|
|
20671
|
+
getToneFromToken5(backgroundParam ?? pairBackgroundToken ?? defaultBackgroundToken)
|
|
20672
|
+
);
|
|
20673
|
+
const selectedPairId = getPreferredPairForBackground5(
|
|
20674
|
+
context.pairsByBackground[selectedBackgroundToken] ?? [],
|
|
20675
|
+
pairParam ?? defaultPairId
|
|
20676
|
+
)?.id ?? "";
|
|
20677
|
+
return {
|
|
20678
|
+
accentKey: context.accent.key,
|
|
20679
|
+
primaryKey: context.primary.key,
|
|
20680
|
+
selectedBackgroundToken,
|
|
20681
|
+
selectedPairId,
|
|
20682
|
+
themeCategory
|
|
20683
|
+
};
|
|
20684
|
+
}
|
|
20685
|
+
function getReadableTextColor4(tone) {
|
|
20686
|
+
return tone >= 600 ? "#ffffff" : "#002664";
|
|
20687
|
+
}
|
|
20688
|
+
function getBackgroundOptionName3(background) {
|
|
20689
|
+
return background.name ?? `${background.familyLabel} ${background.tone}`;
|
|
20690
|
+
}
|
|
20691
|
+
function getMainPairingLabel2(pair, bestPair) {
|
|
20692
|
+
if (!pair) {
|
|
20693
|
+
return "No AAA pairing available";
|
|
20694
|
+
}
|
|
20695
|
+
if (pair.id === bestPair?.id) {
|
|
20696
|
+
return "NSW recommended pairing";
|
|
20697
|
+
}
|
|
20698
|
+
if (isWhiteForegroundPair5(pair) && isLargeTextOnlyPair3(pair)) {
|
|
20699
|
+
return "Large-text example only";
|
|
20700
|
+
}
|
|
20701
|
+
if (isWhiteForegroundPair5(pair) && !pair.passes.aaaLarge) {
|
|
20702
|
+
return "Example only";
|
|
20703
|
+
}
|
|
20704
|
+
return "Approved alternative";
|
|
20705
|
+
}
|
|
20706
|
+
function getMainPairingSupportCopy2(pair, bestPair, context) {
|
|
20707
|
+
if (!pair) {
|
|
20708
|
+
return "No AAA-compliant foreground available for this background.";
|
|
20709
|
+
}
|
|
20710
|
+
if (pair.id === bestPair?.id) {
|
|
20711
|
+
return getBestRecommendationReason3(pair, context);
|
|
20712
|
+
}
|
|
20713
|
+
if (isWhiteForegroundPair5(pair) && isLargeTextOnlyPair3(pair)) {
|
|
20714
|
+
return "White works here for large text only. Use the NSW default for standard body copy and smaller interface text.";
|
|
20715
|
+
}
|
|
20716
|
+
if (isWhiteForegroundPair5(pair) && !pair.passes.aaaLarge) {
|
|
20717
|
+
return "White does not meet AAA on this background. Choose a different approved background or foreground.";
|
|
20718
|
+
}
|
|
20719
|
+
return "Approved AAA alternative when a different tone or emphasis is needed.";
|
|
20720
|
+
}
|
|
20721
|
+
function getBestRecommendationReason3(pair, context) {
|
|
20722
|
+
if (isWhiteForegroundPair5(pair)) {
|
|
20723
|
+
return "Recommended because this background is dark enough to support white text at AAA contrast.";
|
|
20724
|
+
}
|
|
20725
|
+
if (pair.foreground.familyKey === pair.background.familyKey) {
|
|
20726
|
+
return "Recommended because it stays within the same colour family while keeping clear AAA contrast.";
|
|
20727
|
+
}
|
|
20728
|
+
if (pair.foreground.familyKey === context.grey.key) {
|
|
20729
|
+
return "Recommended because grey provides a strong neutral contrast without competing with the background.";
|
|
20730
|
+
}
|
|
20731
|
+
if (pair.foreground.familyKey === context.accent.key) {
|
|
20732
|
+
return "Recommended because the selected accent family adds emphasis while preserving AAA contrast.";
|
|
20733
|
+
}
|
|
20734
|
+
if (pair.foreground.familyKey === context.primary.key) {
|
|
20735
|
+
return "Recommended because the selected primary family gives the clearest AAA-compliant contrast for this background.";
|
|
20736
|
+
}
|
|
20737
|
+
return "Recommended because it is the clearest NSW-approved AAA pairing for this background.";
|
|
20738
|
+
}
|
|
20739
|
+
function getRecommendationCategory3(pair, bestPair, context) {
|
|
20740
|
+
if (pair.id === bestPair?.id) return "best";
|
|
20741
|
+
if (isWhiteForegroundPair5(pair)) return "white";
|
|
20742
|
+
if (pair.foreground.familyKey === pair.background.familyKey) return "same-family";
|
|
20743
|
+
if (pair.foreground.familyKey === context.accent.key) return "accent-family";
|
|
20744
|
+
if (pair.foreground.familyKey === context.grey.key) return "grey-option";
|
|
20745
|
+
if (pair.foreground.familyKey === context.primary.key) return "primary-family";
|
|
20746
|
+
return "approved";
|
|
20747
|
+
}
|
|
20748
|
+
function getRecommendationSortRank3(category) {
|
|
20749
|
+
switch (category) {
|
|
20750
|
+
case "best":
|
|
20751
|
+
return 0;
|
|
20752
|
+
case "same-family":
|
|
20753
|
+
return 1;
|
|
20754
|
+
case "primary-family":
|
|
20755
|
+
return 2;
|
|
20756
|
+
case "accent-family":
|
|
20757
|
+
return 3;
|
|
20758
|
+
case "grey-option":
|
|
20759
|
+
return 4;
|
|
20760
|
+
case "white":
|
|
20761
|
+
return 5;
|
|
20762
|
+
default:
|
|
20763
|
+
return 6;
|
|
20764
|
+
}
|
|
20765
|
+
}
|
|
20766
|
+
function getRecommendationGroupId2(category) {
|
|
20767
|
+
switch (category) {
|
|
20768
|
+
case "best":
|
|
20769
|
+
case "same-family":
|
|
20770
|
+
case "primary-family":
|
|
20771
|
+
return "closest";
|
|
20772
|
+
case "accent-family":
|
|
20773
|
+
case "white":
|
|
20774
|
+
case "approved":
|
|
20775
|
+
return "expressive";
|
|
20776
|
+
case "grey-option":
|
|
20777
|
+
return "neutral";
|
|
20778
|
+
default:
|
|
20779
|
+
return null;
|
|
20780
|
+
}
|
|
20781
|
+
}
|
|
20782
|
+
function buildRecommendationGroups2(items) {
|
|
20783
|
+
const groupedItems = items.reduce(
|
|
20784
|
+
(accumulator, item) => {
|
|
20785
|
+
const groupId = getRecommendationGroupId2(item.category);
|
|
20786
|
+
if (!groupId) {
|
|
20787
|
+
return accumulator;
|
|
20788
|
+
}
|
|
20789
|
+
accumulator[groupId].push(item);
|
|
20790
|
+
return accumulator;
|
|
20791
|
+
},
|
|
20792
|
+
{
|
|
20793
|
+
closest: [],
|
|
20794
|
+
expressive: [],
|
|
20795
|
+
neutral: []
|
|
20796
|
+
}
|
|
20797
|
+
);
|
|
20798
|
+
const groups = [
|
|
20799
|
+
{
|
|
20800
|
+
id: "closest",
|
|
20801
|
+
title: "Closest to default",
|
|
20802
|
+
description: "Stays closest to the NSW default in tone and overall treatment.",
|
|
20803
|
+
items: groupedItems.closest
|
|
20804
|
+
},
|
|
20805
|
+
{
|
|
20806
|
+
id: "expressive",
|
|
20807
|
+
title: "More expressive (accent)",
|
|
20808
|
+
description: "Brings more accent or emphasis into the foreground treatment.",
|
|
20809
|
+
items: groupedItems.expressive
|
|
20810
|
+
},
|
|
20811
|
+
{
|
|
20812
|
+
id: "neutral",
|
|
20813
|
+
title: "Neutral/system",
|
|
20814
|
+
description: "Uses quieter neutral contrast for system or utility treatments.",
|
|
20815
|
+
items: groupedItems.neutral
|
|
20816
|
+
}
|
|
20817
|
+
];
|
|
20818
|
+
return groups.filter((group) => group.items.length > 0);
|
|
20819
|
+
}
|
|
20820
|
+
function getAvailabilityMeta3(isSelected, hasPairs) {
|
|
20821
|
+
if (isSelected && hasPairs) {
|
|
20822
|
+
return {
|
|
20823
|
+
description: "Selected background with AAA foreground options.",
|
|
20824
|
+
icon: Icons.check_circle,
|
|
20825
|
+
label: "Selected",
|
|
20826
|
+
tone: "selected"
|
|
20827
|
+
};
|
|
20828
|
+
}
|
|
20829
|
+
if (isSelected) {
|
|
20830
|
+
return {
|
|
20831
|
+
description: "Selected background with no AAA-compliant foreground available.",
|
|
20832
|
+
icon: Icons.warning,
|
|
20833
|
+
label: "Selected, no AAA",
|
|
20834
|
+
tone: "unavailable"
|
|
20835
|
+
};
|
|
20836
|
+
}
|
|
20837
|
+
if (hasPairs) {
|
|
20838
|
+
return {
|
|
20839
|
+
description: "AAA foreground options available.",
|
|
20840
|
+
icon: Icons.radio_button_checked,
|
|
20841
|
+
label: "Available",
|
|
20842
|
+
tone: "available"
|
|
20843
|
+
};
|
|
20844
|
+
}
|
|
20845
|
+
return {
|
|
20846
|
+
description: "No AAA-compliant foreground available for this background.",
|
|
20847
|
+
icon: Icons.close,
|
|
20848
|
+
label: "No AAA",
|
|
20849
|
+
tone: "unavailable"
|
|
20850
|
+
};
|
|
20851
|
+
}
|
|
20852
|
+
function getPairingCopyText3(pair) {
|
|
20853
|
+
const accessibilityLine = pair.passes.aaaText ? "Accessibility: Meets AAA for normal and large text" : pair.passes.aaaLarge ? "Accessibility: Meets AAA for large text only" : "Accessibility: Fails AAA for normal and large text";
|
|
20854
|
+
return [
|
|
20855
|
+
`Background: ${pair.background.token} (${pair.background.hex})`,
|
|
20856
|
+
`Foreground: ${pair.foreground.token} (${pair.foreground.hex})`,
|
|
20857
|
+
`Contrast ratio: ${pair.contrastRatio.toFixed(2)}:1`,
|
|
20858
|
+
accessibilityLine
|
|
20859
|
+
].join("\n");
|
|
20860
|
+
}
|
|
20861
|
+
function getAccessibilitySummaryLine2(pair) {
|
|
20862
|
+
if (!pair) {
|
|
20863
|
+
return "Contrast unavailable";
|
|
20864
|
+
}
|
|
20865
|
+
if (pair.passes.aaaText) {
|
|
20866
|
+
return `${pair.contrastRatio.toFixed(2)}:1 \u2014 AAA compliant (normal + large text)`;
|
|
20867
|
+
}
|
|
20868
|
+
if (pair.passes.aaaLarge) {
|
|
20869
|
+
return `${pair.contrastRatio.toFixed(2)}:1 \u2014 AAA compliant (large text only)`;
|
|
20870
|
+
}
|
|
20871
|
+
return `${pair.contrastRatio.toFixed(2)}:1 \u2014 Not AAA compliant`;
|
|
20872
|
+
}
|
|
20873
|
+
function getLiveAnnouncement3(pair, background) {
|
|
20874
|
+
if (!background) {
|
|
20875
|
+
return "No approved background tones available.";
|
|
20876
|
+
}
|
|
20877
|
+
if (!pair) {
|
|
20878
|
+
return `${background.token} selected. No AAA-compliant foreground options available for this selection.`;
|
|
20879
|
+
}
|
|
20880
|
+
if (isWhiteForegroundPair5(pair) && isLargeTextOnlyPair3(pair)) {
|
|
20881
|
+
return `${background.token} with white. Contrast ratio ${pair.contrastRatio.toFixed(2)} to 1. Meets AAA for large text only.`;
|
|
20882
|
+
}
|
|
20883
|
+
if (isWhiteForegroundPair5(pair) && !pair.passes.aaaLarge) {
|
|
20884
|
+
return `${background.token} with white. Contrast ratio ${pair.contrastRatio.toFixed(2)} to 1. Fails AAA for normal and large text.`;
|
|
20885
|
+
}
|
|
20886
|
+
return `${background.token} with ${pair.foreground.token}. Contrast ratio ${pair.contrastRatio.toFixed(2)} to 1. Meets AAA for normal and large text.`;
|
|
20887
|
+
}
|
|
20888
|
+
function formatValueRows3(color2, visibleFormats) {
|
|
20889
|
+
const hasDisplayTone = color2.token !== "white";
|
|
20890
|
+
return [
|
|
20891
|
+
{ key: "token", label: "Token", value: color2.token, copyable: true },
|
|
20892
|
+
{
|
|
20893
|
+
key: "tone",
|
|
20894
|
+
label: "Tone",
|
|
20895
|
+
value: hasDisplayTone ? String(color2.tone) : "Not applicable",
|
|
20896
|
+
copyable: hasDisplayTone
|
|
20897
|
+
},
|
|
20898
|
+
...visibleFormats.map((format) => ({
|
|
20899
|
+
key: format,
|
|
20900
|
+
label: format.toUpperCase(),
|
|
20901
|
+
value: color2[format],
|
|
20902
|
+
copyable: true
|
|
20903
|
+
}))
|
|
20904
|
+
];
|
|
20905
|
+
}
|
|
20906
|
+
function SelectorButton3({
|
|
20907
|
+
description,
|
|
20908
|
+
isSelected,
|
|
20909
|
+
label,
|
|
20910
|
+
onClick,
|
|
20911
|
+
swatch
|
|
20912
|
+
}) {
|
|
20913
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20914
|
+
"button",
|
|
20915
|
+
{
|
|
20916
|
+
type: "button",
|
|
20917
|
+
"aria-pressed": isSelected,
|
|
20918
|
+
onClick,
|
|
20919
|
+
className: cn(
|
|
20920
|
+
"w-full rounded-sm border px-3 py-3 text-left transition-colors focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
|
|
20921
|
+
isSelected ? "border-primary-800 bg-primary-50" : "border-grey-300 bg-white hover:border-primary-500 hover:bg-grey-50"
|
|
20922
|
+
),
|
|
20923
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
|
|
20924
|
+
swatch ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
20925
|
+
"span",
|
|
20926
|
+
{
|
|
20927
|
+
"aria-hidden": "true",
|
|
20928
|
+
className: "mt-0.5 size-4 shrink-0 rounded-full border border-black/10",
|
|
20929
|
+
style: { backgroundColor: swatch }
|
|
20930
|
+
}
|
|
20931
|
+
) : null,
|
|
20932
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-1", children: [
|
|
20933
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: label }),
|
|
20934
|
+
description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs/5 text-muted-foreground", children: description }) : null
|
|
20935
|
+
] })
|
|
20936
|
+
] })
|
|
20937
|
+
}
|
|
20938
|
+
);
|
|
20939
|
+
}
|
|
20940
|
+
function BackgroundSwatchButton3({
|
|
20941
|
+
background,
|
|
20942
|
+
hasPairs,
|
|
20943
|
+
isSelected,
|
|
20944
|
+
onClick
|
|
20945
|
+
}) {
|
|
20946
|
+
const status = getAvailabilityMeta3(isSelected, hasPairs);
|
|
20947
|
+
const StatusIcon = status.icon;
|
|
20948
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
20949
|
+
"button",
|
|
20950
|
+
{
|
|
20951
|
+
type: "button",
|
|
20952
|
+
"aria-pressed": isSelected,
|
|
20953
|
+
"aria-label": `Select ${background.token} background. ${status.description}`,
|
|
20954
|
+
onClick,
|
|
20955
|
+
className: cn(
|
|
20956
|
+
"w-full rounded-sm border bg-white p-3 text-left transition-colors focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
|
|
20957
|
+
isSelected ? "border-primary-800 bg-primary-50" : hasPairs ? "border-grey-300 hover:border-primary-500 hover:bg-grey-50" : "border-grey-300 hover:border-grey-500"
|
|
20958
|
+
),
|
|
20959
|
+
children: [
|
|
20960
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
20961
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
20962
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: getBackgroundOptionName3(background) }),
|
|
20963
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 font-mono text-[0.72rem] break-all text-muted-foreground", children: background.token })
|
|
20964
|
+
] }),
|
|
20965
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
20966
|
+
"span",
|
|
20967
|
+
{
|
|
20968
|
+
className: cn(
|
|
20969
|
+
"inline-flex items-center gap-1 rounded-sm border px-2 py-1 text-[0.68rem] font-semibold uppercase",
|
|
20970
|
+
status.tone === "selected" && "border-primary-800 bg-primary-800 text-white dark:border-primary-500 dark:bg-primary-500",
|
|
20971
|
+
status.tone === "available" && "border-grey-300 bg-grey-50 text-foreground",
|
|
20972
|
+
status.tone === "unavailable" && "border-danger-300 bg-danger-50 text-danger-900 dark:border-danger-800 dark:bg-danger-950/20 dark:text-danger-200"
|
|
20973
|
+
),
|
|
20974
|
+
children: [
|
|
20975
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { "data-slot": "icon", className: "size-4" }),
|
|
20976
|
+
status.label
|
|
20977
|
+
]
|
|
20978
|
+
}
|
|
20979
|
+
)
|
|
20980
|
+
] }),
|
|
20981
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 overflow-hidden rounded-[2px] border border-black/10", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-14 w-full", style: { backgroundColor: background.hex } }) }),
|
|
20982
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-xs/5 text-muted-foreground", children: status.description })
|
|
20983
|
+
]
|
|
20984
|
+
}
|
|
20985
|
+
);
|
|
20986
|
+
}
|
|
20987
|
+
function CurrentResultCard3({
|
|
20988
|
+
bestPair,
|
|
20989
|
+
copiedKey,
|
|
20990
|
+
familySummary,
|
|
20991
|
+
onCopyPairing,
|
|
20992
|
+
pair,
|
|
20993
|
+
supportText,
|
|
20994
|
+
selectedBackground
|
|
20995
|
+
}) {
|
|
20996
|
+
const previewForeground = pair?.foreground.hex ?? getReadableTextColor4(selectedBackground.tone);
|
|
20997
|
+
const isRecommended = pair ? pair.id === bestPair?.id : false;
|
|
20998
|
+
const pairingLabel = getMainPairingLabel2(pair, bestPair);
|
|
20999
|
+
const accessibilitySummary = getAccessibilitySummaryLine2(pair);
|
|
21000
|
+
const whiteForeground = pair ? isWhiteForegroundPair5(pair) : false;
|
|
21001
|
+
const fauxButtonStyle = pair ? {
|
|
21002
|
+
"--btn-bg": pair.foreground.hex,
|
|
21003
|
+
"--btn-border": pair.foreground.hex,
|
|
21004
|
+
"--btn-text": pair.background.hex,
|
|
21005
|
+
"--btn-icon": pair.background.hex,
|
|
21006
|
+
"--btn-hover-overlay": pair.background.hex
|
|
21007
|
+
} : null;
|
|
21008
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
21009
|
+
Card,
|
|
21010
|
+
{
|
|
21011
|
+
className: cn(
|
|
21012
|
+
"gap-0 overflow-hidden border-grey-200 bg-white py-0",
|
|
21013
|
+
isRecommended && "border-primary-100"
|
|
21014
|
+
),
|
|
21015
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
21016
|
+
"div",
|
|
21017
|
+
{
|
|
21018
|
+
className: "p-3 sm:min-h-[21rem] sm:p-5",
|
|
21019
|
+
style: {
|
|
21020
|
+
backgroundColor: selectedBackground.hex,
|
|
21021
|
+
color: previewForeground
|
|
21022
|
+
},
|
|
21023
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-[16rem] flex-col gap-5 sm:min-h-[17.5rem] sm:gap-6", children: [
|
|
21024
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-[42rem] rounded-sm bg-white/92 px-4 py-3.5 text-foreground sm:px-5 sm:py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between", children: [
|
|
21025
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-3", children: [
|
|
21026
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
21027
|
+
"span",
|
|
21028
|
+
{
|
|
21029
|
+
className: cn(
|
|
21030
|
+
"inline-flex items-center gap-2 rounded-sm border px-2.5 py-1 text-[0.68rem] font-semibold tracking-[0.1em] uppercase",
|
|
21031
|
+
isRecommended ? "border-primary-200 bg-primary-50 text-primary-900" : "border-grey-300 bg-white text-foreground"
|
|
21032
|
+
),
|
|
21033
|
+
children: [
|
|
21034
|
+
isRecommended ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check_circle, { "data-slot": "icon", className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.info, { "data-slot": "icon", className: "size-4" }),
|
|
21035
|
+
pairingLabel
|
|
21036
|
+
]
|
|
21037
|
+
}
|
|
21038
|
+
),
|
|
21039
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
21040
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 4, className: "text-foreground", trim: "normal", children: pair ? `${getPairingColorDisplayName5(pair.foreground)} on ${getPairingColorDisplayName5(pair.background)}` : `${getPairingColorDisplayName5(selectedBackground)} selected` }),
|
|
21041
|
+
pair ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "font-mono text-[0.74rem] break-all text-muted-foreground", children: [
|
|
21042
|
+
pair.foreground.token,
|
|
21043
|
+
" on ",
|
|
21044
|
+
pair.background.token
|
|
21045
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-[0.74rem] break-all text-muted-foreground", children: selectedBackground.token }),
|
|
21046
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.95rem] font-semibold text-foreground", children: accessibilitySummary }),
|
|
21047
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "max-w-3xl text-grey-700", children: supportText })
|
|
21048
|
+
] })
|
|
21049
|
+
] }),
|
|
21050
|
+
pair ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
21051
|
+
Button2,
|
|
21052
|
+
{
|
|
21053
|
+
variant: "outline",
|
|
21054
|
+
color: "grey",
|
|
21055
|
+
size: "sm",
|
|
21056
|
+
className: "w-full justify-center bg-white/90 lg:w-auto lg:min-w-40",
|
|
21057
|
+
onClick: onCopyPairing,
|
|
21058
|
+
children: copiedKey === "current-pairing" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
21059
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-5" }),
|
|
21060
|
+
"Pairing copied"
|
|
21061
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
21062
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
|
|
21063
|
+
"Copy pairing"
|
|
21064
|
+
] })
|
|
21065
|
+
}
|
|
21066
|
+
) : null
|
|
21067
|
+
] }) }),
|
|
21068
|
+
pair ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-[12rem] flex-col justify-between gap-5", children: [
|
|
21069
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
21070
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
21071
|
+
"span",
|
|
21072
|
+
{
|
|
21073
|
+
className: "inline-flex items-center gap-2 rounded-full border px-3 py-1 text-[0.72rem] font-semibold tracking-[0.16em] uppercase",
|
|
21074
|
+
style: {
|
|
21075
|
+
borderColor: pair.foreground.hex,
|
|
21076
|
+
backgroundColor: pair.foreground.hex,
|
|
21077
|
+
color: pair.background.hex
|
|
21078
|
+
},
|
|
21079
|
+
children: [
|
|
21080
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.palette, { "data-slot": "icon", className: "size-4" }),
|
|
21081
|
+
familySummary
|
|
21082
|
+
]
|
|
21083
|
+
}
|
|
21084
|
+
),
|
|
21085
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
21086
|
+
"span",
|
|
21087
|
+
{
|
|
21088
|
+
className: "inline-flex rounded-full border px-3 py-1 text-[0.72rem] font-semibold tracking-[0.16em] uppercase",
|
|
21089
|
+
style: {
|
|
21090
|
+
borderColor: pair.foreground.hex
|
|
21091
|
+
},
|
|
21092
|
+
children: [
|
|
21093
|
+
pair.rating,
|
|
21094
|
+
" ",
|
|
21095
|
+
pair.contrastRatio.toFixed(2),
|
|
21096
|
+
":1"
|
|
21097
|
+
]
|
|
21098
|
+
}
|
|
21099
|
+
)
|
|
21100
|
+
] }),
|
|
21101
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-xl space-y-4 pb-8 sm:pb-10", children: [
|
|
21102
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold tracking-[0.22em] uppercase", children: whiteForeground && !isRecommended ? "White on colour example" : whiteForeground ? "White on colour" : "Colour on colour" }),
|
|
21103
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
21104
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "max-w-lg text-[2.8rem] leading-none font-bold text-current sm:text-[4rem]", children: "Pair colour with confidence." }),
|
|
21105
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-md text-[0.96rem]/7 sm:text-base/7", children: getPreviewGuidance5(pair, isRecommended) }),
|
|
21106
|
+
fauxButtonStyle ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
21107
|
+
"span",
|
|
21108
|
+
{
|
|
21109
|
+
"aria-hidden": "true",
|
|
21110
|
+
"data-variant": "solid",
|
|
21111
|
+
className: cn(
|
|
21112
|
+
buttonVariants({ variant: "solid", size: "default" }),
|
|
21113
|
+
"pointer-events-none cursor-default px-5 text-[15px] font-[700] select-none sm:px-6 sm:text-[16px] sm:font-[700]"
|
|
21114
|
+
),
|
|
21115
|
+
style: fauxButtonStyle,
|
|
21116
|
+
children: "Get started"
|
|
21117
|
+
}
|
|
21118
|
+
) : null
|
|
21119
|
+
] })
|
|
21120
|
+
] }),
|
|
21121
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
21122
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
21123
|
+
"span",
|
|
21124
|
+
{
|
|
21125
|
+
className: "inline-flex items-center gap-2 rounded-full px-4 py-2 text-sm font-semibold",
|
|
21126
|
+
style: {
|
|
21127
|
+
backgroundColor: pair.foreground.hex,
|
|
21128
|
+
color: pair.background.hex
|
|
21129
|
+
},
|
|
21130
|
+
children: [
|
|
21131
|
+
"Pass",
|
|
21132
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-4" })
|
|
21133
|
+
]
|
|
21134
|
+
}
|
|
21135
|
+
),
|
|
21136
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
21137
|
+
"span",
|
|
21138
|
+
{
|
|
21139
|
+
className: "inline-flex rounded-full border px-4 py-2 text-sm",
|
|
21140
|
+
style: {
|
|
21141
|
+
borderColor: pair.foreground.hex
|
|
21142
|
+
},
|
|
21143
|
+
children: [
|
|
21144
|
+
pair.background.token,
|
|
21145
|
+
" / ",
|
|
21146
|
+
pair.foreground.token
|
|
21147
|
+
]
|
|
21148
|
+
}
|
|
21149
|
+
)
|
|
21150
|
+
] })
|
|
21151
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-lg space-y-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
21152
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "max-w-lg text-[1.9rem] leading-tight font-bold text-current sm:text-[2.25rem]", children: "No AAA combination available." }),
|
|
21153
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-md text-[0.96rem]/7 sm:text-base/7", children: "This approved background does not currently have an AAA foreground in this tool. Choose another approved background to continue." })
|
|
21154
|
+
] }) })
|
|
21155
|
+
] })
|
|
21156
|
+
}
|
|
21157
|
+
)
|
|
21158
|
+
}
|
|
21159
|
+
);
|
|
21160
|
+
}
|
|
21161
|
+
function RecommendationCard3({
|
|
21162
|
+
copiedKey,
|
|
21163
|
+
isSelected,
|
|
21164
|
+
item,
|
|
21165
|
+
onCopyPairing,
|
|
21166
|
+
onSelect
|
|
21167
|
+
}) {
|
|
21168
|
+
const { pair } = item;
|
|
21169
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
21170
|
+
"div",
|
|
21171
|
+
{
|
|
21172
|
+
className: cn(
|
|
21173
|
+
"relative rounded-sm border bg-white/95 px-3 py-2 text-left transition-colors focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
|
|
21174
|
+
isSelected ? "border-primary-700 bg-primary-50/30" : "border-grey-200 hover:border-grey-300"
|
|
21175
|
+
),
|
|
21176
|
+
children: [
|
|
21177
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
21178
|
+
"button",
|
|
21179
|
+
{
|
|
21180
|
+
type: "button",
|
|
21181
|
+
"aria-pressed": isSelected,
|
|
21182
|
+
"aria-label": `Use ${pair.foreground.token} on ${pair.background.token}`,
|
|
21183
|
+
onClick: onSelect,
|
|
21184
|
+
className: "absolute inset-0 rounded-sm focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden"
|
|
21185
|
+
}
|
|
21186
|
+
),
|
|
21187
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none relative z-10 flex items-start gap-2.5", children: [
|
|
21188
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-0.5 w-10 shrink-0 overflow-hidden rounded-[2px] border border-black/10", children: [
|
|
21189
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 w-full", style: { backgroundColor: pair.background.hex } }),
|
|
21190
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-full", style: { backgroundColor: pair.foreground.hex } })
|
|
21191
|
+
] }),
|
|
21192
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-0.5", children: [
|
|
21193
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
21194
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-[0.94rem] leading-6 font-semibold text-foreground", children: [
|
|
21195
|
+
getPairingColorDisplayName5(pair.foreground),
|
|
21196
|
+
" on",
|
|
21197
|
+
" ",
|
|
21198
|
+
getPairingColorDisplayName5(pair.background)
|
|
21199
|
+
] }),
|
|
21200
|
+
item.category === "best" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex rounded-sm border border-primary-200 bg-primary-50 px-1.5 py-0.5 text-[0.64rem] font-semibold tracking-[0.1em] text-primary-900 uppercase", children: "Default" }) : null,
|
|
21201
|
+
isSelected ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex rounded-sm border border-primary-700 px-1.5 py-0.5 text-[0.64rem] font-semibold tracking-[0.1em] text-primary-800 uppercase", children: "Current" }) : null
|
|
21202
|
+
] }),
|
|
21203
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "font-mono text-[0.72rem] break-all text-muted-foreground", children: [
|
|
21204
|
+
pair.foreground.token,
|
|
21205
|
+
" on ",
|
|
21206
|
+
pair.background.token
|
|
21207
|
+
] }),
|
|
21208
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-[0.82rem] text-muted-foreground", children: [
|
|
21209
|
+
pair.contrastRatio.toFixed(2),
|
|
21210
|
+
":1 contrast"
|
|
21211
|
+
] })
|
|
21212
|
+
] }),
|
|
21213
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto shrink-0 self-start", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
21214
|
+
Button2,
|
|
21215
|
+
{
|
|
21216
|
+
variant: "ghost",
|
|
21217
|
+
color: "grey",
|
|
21218
|
+
size: "icon",
|
|
21219
|
+
className: "size-7 text-muted-foreground hover:text-foreground",
|
|
21220
|
+
onClick: onCopyPairing,
|
|
21221
|
+
"aria-label": `Copy pairing ${pair.background.token} and ${pair.foreground.token}`,
|
|
21222
|
+
title: copiedKey === `pair:${pair.id}` ? "Copied" : "Copy pairing",
|
|
21223
|
+
children: copiedKey === `pair:${pair.id}` ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-4" })
|
|
21224
|
+
}
|
|
21225
|
+
) })
|
|
21226
|
+
] })
|
|
21227
|
+
]
|
|
21228
|
+
}
|
|
21229
|
+
);
|
|
21230
|
+
}
|
|
21231
|
+
function RecommendationGroupSection2({
|
|
21232
|
+
children,
|
|
21233
|
+
description,
|
|
21234
|
+
title
|
|
21235
|
+
}) {
|
|
21236
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-1.5", children: [
|
|
21237
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
|
|
21238
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "text-foreground", trim: "normal", children: title }),
|
|
21239
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "text-grey-600", children: description })
|
|
21240
|
+
] }),
|
|
21241
|
+
children
|
|
21242
|
+
] });
|
|
21243
|
+
}
|
|
21244
|
+
function TechnicalDetailsPanel3({
|
|
21245
|
+
color: color2,
|
|
21246
|
+
copiedKey,
|
|
21247
|
+
onCopyValue,
|
|
21248
|
+
title,
|
|
21249
|
+
visibleFormats
|
|
21250
|
+
}) {
|
|
21251
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm border border-grey-200 bg-white", children: [
|
|
21252
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-grey-200 px-4 py-3.5 sm:px-5", children: [
|
|
21253
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "text-foreground", trim: "normal", children: title }),
|
|
21254
|
+
color2 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
21255
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: getPairingColorDisplayName5(color2) }),
|
|
21256
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3.5 overflow-hidden rounded-sm border border-black/10 bg-white", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-16 w-full sm:h-20", style: { backgroundColor: color2.hex } }) })
|
|
21257
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "No AAA foreground available." })
|
|
21258
|
+
] }),
|
|
21259
|
+
color2 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-grey-200", children: formatValueRows3(color2, visibleFormats).map((row) => {
|
|
21260
|
+
const copyKey = `${title}-${row.key}`;
|
|
21261
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
21262
|
+
"div",
|
|
21263
|
+
{
|
|
21264
|
+
className: "flex flex-col items-start gap-3 px-4 py-3.5 sm:flex-row sm:items-start sm:justify-between sm:gap-4 sm:px-5",
|
|
21265
|
+
children: [
|
|
21266
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
21267
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.72rem] font-semibold tracking-[0.12em] text-muted-foreground uppercase", children: row.label }),
|
|
21268
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
21269
|
+
"p",
|
|
21270
|
+
{
|
|
21271
|
+
className: cn(
|
|
21272
|
+
"mt-2 text-sm text-foreground",
|
|
21273
|
+
row.key !== "tone" && "font-mono break-all"
|
|
21274
|
+
),
|
|
21275
|
+
children: row.value
|
|
21276
|
+
}
|
|
21277
|
+
)
|
|
21278
|
+
] }),
|
|
21279
|
+
row.copyable ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
21280
|
+
Button2,
|
|
21281
|
+
{
|
|
21282
|
+
variant: "ghost",
|
|
21283
|
+
color: "grey",
|
|
21284
|
+
size: "sm",
|
|
21285
|
+
className: "self-start",
|
|
21286
|
+
onClick: () => onCopyValue(copyKey, row.value, `${row.label} copied`),
|
|
21287
|
+
"aria-label": `Copy ${title.toLowerCase()} ${row.label.toLowerCase()}`,
|
|
21288
|
+
children: copiedKey === copyKey ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
21289
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.check_circle, { "data-slot": "icon", className: "size-5" }),
|
|
21290
|
+
"Copied"
|
|
21291
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
21292
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
|
|
21293
|
+
"Copy"
|
|
21294
|
+
] })
|
|
21295
|
+
}
|
|
21296
|
+
) : null
|
|
21297
|
+
]
|
|
21298
|
+
},
|
|
21299
|
+
row.key
|
|
21300
|
+
);
|
|
21301
|
+
}) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "No technical values are shown because there is no AAA-compliant foreground for this background." }) })
|
|
21302
|
+
] });
|
|
21303
|
+
}
|
|
21304
|
+
function resolveSelectionState3(nextThemeCategory, nextPrimaryKey, nextAccentKey, preferredBackgroundToken, preferredPairId) {
|
|
21305
|
+
const context = getPairingContext(nextThemeCategory, nextPrimaryKey, nextAccentKey);
|
|
21306
|
+
const selectedBackgroundToken = resolveBackgroundToken5(
|
|
21307
|
+
context,
|
|
21308
|
+
preferredBackgroundToken,
|
|
21309
|
+
getToneFromToken5(preferredBackgroundToken)
|
|
21310
|
+
);
|
|
21311
|
+
const selectedPairId = getPreferredPairForBackground5(
|
|
21312
|
+
context.pairsByBackground[selectedBackgroundToken] ?? [],
|
|
21313
|
+
preferredPairId
|
|
21314
|
+
)?.id ?? "";
|
|
21315
|
+
return {
|
|
21316
|
+
accentKey: context.accent.key,
|
|
21317
|
+
context,
|
|
21318
|
+
primaryKey: context.primary.key,
|
|
21319
|
+
selectedBackgroundToken,
|
|
21320
|
+
selectedPairId,
|
|
21321
|
+
themeCategory: nextThemeCategory
|
|
21322
|
+
};
|
|
21323
|
+
}
|
|
21324
|
+
function ColorPairingToolV5Loading() {
|
|
21325
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 xl:grid-cols-[minmax(18rem,24rem)_minmax(0,1fr)]", children: [
|
|
21326
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
21327
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-52 rounded-sm border border-grey-200 bg-grey-50" }),
|
|
21328
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[32rem] rounded-sm border border-grey-200 bg-grey-50" })
|
|
21329
|
+
] }),
|
|
21330
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
21331
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-96 rounded-sm border border-grey-200 bg-grey-50" }),
|
|
21332
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-64 rounded-sm border border-grey-200 bg-grey-50" }),
|
|
21333
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-72 rounded-sm border border-grey-200 bg-grey-50" })
|
|
21334
|
+
] })
|
|
21335
|
+
] });
|
|
21336
|
+
}
|
|
21337
|
+
function ColorPairingToolV5Content({
|
|
21338
|
+
onAnalyticsEvent,
|
|
21339
|
+
visibleFormats
|
|
21340
|
+
}) {
|
|
21341
|
+
const searchParams = navigation.useSearchParams();
|
|
21342
|
+
const stickyOffset = useStickyOffset(24);
|
|
21343
|
+
const [initialState] = React5.useState(() => getInitialPairingState5(searchParams));
|
|
21344
|
+
const [themeCategory, setThemeCategory] = React5.useState(initialState.themeCategory);
|
|
21345
|
+
const [primaryFamilyKey, setPrimaryFamilyKey] = React5.useState(initialState.primaryKey);
|
|
21346
|
+
const [accentFamilyKey, setAccentFamilyKey] = React5.useState(initialState.accentKey);
|
|
21347
|
+
const [selectedBackgroundToken, setSelectedBackgroundToken] = React5.useState(
|
|
21348
|
+
initialState.selectedBackgroundToken
|
|
21349
|
+
);
|
|
21350
|
+
const [selectedPairId, setSelectedPairId] = React5.useState(initialState.selectedPairId);
|
|
21351
|
+
const [drawerStepIndex, setDrawerStepIndex] = React5.useState(0);
|
|
21352
|
+
const [isCompactControlsOpen, setIsCompactControlsOpen] = React5.useState(false);
|
|
21353
|
+
const [isShowingAllAlternatives, setIsShowingAllAlternatives] = React5.useState(false);
|
|
21354
|
+
const [isTechnicalDetailsOpen, setIsTechnicalDetailsOpen] = React5.useState(false);
|
|
21355
|
+
const [, copyToClipboardRaw] = usehooks.useCopyToClipboard();
|
|
21356
|
+
const [copiedKey, setCopiedKey] = React5.useState(null);
|
|
21357
|
+
const copiedKeyTimeoutRef = React5.useRef(null);
|
|
21358
|
+
const resultSectionRef = React5.useRef(null);
|
|
21359
|
+
const noValidStateRef = React5.useRef(/* @__PURE__ */ new Set());
|
|
21360
|
+
const technicalDetailsViewedRef = React5.useRef(false);
|
|
21361
|
+
const emitAnalyticsEvent = React5.useCallback(
|
|
21362
|
+
(event) => {
|
|
21363
|
+
onAnalyticsEvent(event);
|
|
21364
|
+
if (typeof window !== "undefined") {
|
|
21365
|
+
window.dispatchEvent(
|
|
21366
|
+
new CustomEvent(COLOR_PAIRING_TOOL_V5_ANALYTICS_EVENT, {
|
|
21367
|
+
detail: event
|
|
21368
|
+
})
|
|
21369
|
+
);
|
|
21370
|
+
}
|
|
21371
|
+
},
|
|
21372
|
+
[onAnalyticsEvent]
|
|
21373
|
+
);
|
|
21374
|
+
React5.useEffect(() => {
|
|
21375
|
+
return () => {
|
|
21376
|
+
if (copiedKeyTimeoutRef.current) {
|
|
21377
|
+
clearTimeout(copiedKeyTimeoutRef.current);
|
|
21378
|
+
}
|
|
21379
|
+
};
|
|
21380
|
+
}, []);
|
|
21381
|
+
React5.useEffect(() => {
|
|
21382
|
+
if (typeof window === "undefined") {
|
|
21383
|
+
return;
|
|
21384
|
+
}
|
|
21385
|
+
const mediaQuery = window.matchMedia(PERSISTENT_DRAWER_MIN_WIDTH_QUERY3);
|
|
21386
|
+
const handleChange = (event) => {
|
|
21387
|
+
if (event?.matches ?? mediaQuery.matches) {
|
|
21388
|
+
setIsCompactControlsOpen(false);
|
|
21389
|
+
}
|
|
21390
|
+
};
|
|
21391
|
+
handleChange();
|
|
21392
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
21393
|
+
return () => {
|
|
21394
|
+
mediaQuery.removeEventListener("change", handleChange);
|
|
21395
|
+
};
|
|
21396
|
+
}, []);
|
|
21397
|
+
const themeFamilies = React5.useMemo(() => getPairingFamilies(themeCategory), [themeCategory]);
|
|
21398
|
+
const context = React5.useMemo(
|
|
21399
|
+
() => getPairingContext(themeCategory, primaryFamilyKey, accentFamilyKey),
|
|
21400
|
+
[themeCategory, primaryFamilyKey, accentFamilyKey]
|
|
21401
|
+
);
|
|
21402
|
+
const selectableFamilies = React5.useMemo(
|
|
21403
|
+
() => themeFamilies.filter((family) => family.key !== context.grey.key),
|
|
21404
|
+
[themeFamilies, context.grey.key]
|
|
21405
|
+
);
|
|
21406
|
+
const selectableAccentFamilies = React5.useMemo(
|
|
21407
|
+
() => selectableFamilies.filter((family) => family.key !== context.primary.key),
|
|
21408
|
+
[selectableFamilies, context.primary.key]
|
|
21409
|
+
);
|
|
21410
|
+
const selectedBackground = React5.useMemo(
|
|
21411
|
+
() => context.backgrounds.find((background) => background.token === selectedBackgroundToken) ?? context.backgrounds[0] ?? null,
|
|
21412
|
+
[context.backgrounds, selectedBackgroundToken]
|
|
21413
|
+
);
|
|
21414
|
+
const selectedBackgroundPairs = React5.useMemo(
|
|
21415
|
+
() => selectedBackground ? context.pairsByBackground[selectedBackground.token] ?? [] : [],
|
|
21416
|
+
[context.pairsByBackground, selectedBackground]
|
|
21417
|
+
);
|
|
21418
|
+
const bestRecommendedPair = React5.useMemo(
|
|
21419
|
+
() => getPreferredPairForBackground5(selectedBackgroundPairs),
|
|
21420
|
+
[selectedBackgroundPairs]
|
|
21421
|
+
);
|
|
21422
|
+
const selectedPair = React5.useMemo(
|
|
21423
|
+
() => getPreferredPairForBackground5(selectedBackgroundPairs, selectedPairId),
|
|
21424
|
+
[selectedBackgroundPairs, selectedPairId]
|
|
21425
|
+
);
|
|
21426
|
+
const whiteForegroundExample = React5.useMemo(
|
|
21427
|
+
() => selectedBackground && supportsWhiteForegroundPreview(selectedBackground) ? getWhiteForegroundPair(selectedBackground) : null,
|
|
21428
|
+
[selectedBackground]
|
|
21429
|
+
);
|
|
21430
|
+
const previewPair = selectedPair ?? whiteForegroundExample ?? null;
|
|
21431
|
+
const detailForeground = selectedPair?.foreground ?? whiteForegroundExample?.foreground ?? null;
|
|
21432
|
+
const currentPairSupportText = React5.useMemo(
|
|
21433
|
+
() => getMainPairingSupportCopy2(previewPair, bestRecommendedPair, context),
|
|
21434
|
+
[bestRecommendedPair, context, previewPair]
|
|
21435
|
+
);
|
|
21436
|
+
const recommendationItems = React5.useMemo(() => {
|
|
21437
|
+
return selectedBackgroundPairs.map((pair) => {
|
|
21438
|
+
const category = getRecommendationCategory3(pair, bestRecommendedPair, context);
|
|
21439
|
+
return {
|
|
21440
|
+
category,
|
|
21441
|
+
pair
|
|
21442
|
+
};
|
|
21443
|
+
}).sort(
|
|
21444
|
+
(left, right) => getRecommendationSortRank3(left.category) - getRecommendationSortRank3(right.category)
|
|
21445
|
+
);
|
|
21446
|
+
}, [bestRecommendedPair, context, selectedBackgroundPairs]);
|
|
21447
|
+
const alternativeRecommendationGroups = React5.useMemo(
|
|
21448
|
+
() => buildRecommendationGroups2(
|
|
21449
|
+
recommendationItems.filter((item) => item.pair.id !== selectedPair?.id)
|
|
21450
|
+
),
|
|
21451
|
+
[recommendationItems, selectedPair?.id]
|
|
21452
|
+
);
|
|
21453
|
+
const visibleAlternativeRecommendationGroups = React5.useMemo(() => {
|
|
21454
|
+
if (isShowingAllAlternatives) {
|
|
21455
|
+
return alternativeRecommendationGroups;
|
|
21456
|
+
}
|
|
21457
|
+
let remaining = INITIAL_VISIBLE_ALTERNATIVES2;
|
|
21458
|
+
return alternativeRecommendationGroups.reduce((groups, group) => {
|
|
21459
|
+
if (remaining <= 0) {
|
|
21460
|
+
return groups;
|
|
21461
|
+
}
|
|
21462
|
+
const items = group.items.slice(0, remaining);
|
|
21463
|
+
if (items.length > 0) {
|
|
21464
|
+
groups.push({
|
|
21465
|
+
...group,
|
|
21466
|
+
items
|
|
21467
|
+
});
|
|
21468
|
+
remaining -= items.length;
|
|
21469
|
+
}
|
|
21470
|
+
return groups;
|
|
21471
|
+
}, []);
|
|
21472
|
+
}, [alternativeRecommendationGroups, isShowingAllAlternatives]);
|
|
21473
|
+
const hiddenAlternativeCount = React5.useMemo(() => {
|
|
21474
|
+
const totalAlternatives = alternativeRecommendationGroups.reduce(
|
|
21475
|
+
(count, group) => count + group.items.length,
|
|
21476
|
+
0
|
|
21477
|
+
);
|
|
21478
|
+
const visibleAlternatives = visibleAlternativeRecommendationGroups.reduce(
|
|
21479
|
+
(count, group) => count + group.items.length,
|
|
21480
|
+
0
|
|
21481
|
+
);
|
|
21482
|
+
return Math.max(0, totalAlternatives - visibleAlternatives);
|
|
21483
|
+
}, [alternativeRecommendationGroups, visibleAlternativeRecommendationGroups]);
|
|
21484
|
+
const liveAnnouncement = React5.useMemo(
|
|
21485
|
+
() => getLiveAnnouncement3(previewPair, selectedBackground),
|
|
21486
|
+
[previewPair, selectedBackground]
|
|
21487
|
+
);
|
|
21488
|
+
const familySummary = React5.useMemo(
|
|
21489
|
+
() => [context.primary.label, context.accent.label, context.grey.label].join(" + "),
|
|
21490
|
+
[context.accent.label, context.grey.label, context.primary.label]
|
|
21491
|
+
);
|
|
21492
|
+
const shareBackgroundToken = selectedBackground?.token ?? selectedBackgroundToken;
|
|
21493
|
+
const shareUrl = React5.useMemo(() => {
|
|
21494
|
+
const params = new URLSearchParams();
|
|
21495
|
+
params.set("palette", themeCategory);
|
|
21496
|
+
params.set("primary", context.primary.key);
|
|
21497
|
+
params.set("accent", context.accent.key);
|
|
21498
|
+
if (shareBackgroundToken) {
|
|
21499
|
+
params.set("background", shareBackgroundToken);
|
|
21500
|
+
}
|
|
21501
|
+
if (selectedPairId) {
|
|
21502
|
+
params.set("pair", selectedPairId);
|
|
21503
|
+
}
|
|
21504
|
+
const query = params.toString();
|
|
21505
|
+
return `${COLOR_PAIRING_TOOL_V5_PATH}${query ? `?${query}` : ""}`;
|
|
21506
|
+
}, [context.accent.key, context.primary.key, shareBackgroundToken, selectedPairId, themeCategory]);
|
|
21507
|
+
const activeDrawerStep = COLOR_PAIRING_TOOL_DRAWER_STEPS3[drawerStepIndex];
|
|
21508
|
+
const isFirstDrawerStep = drawerStepIndex === 0;
|
|
21509
|
+
const isLastDrawerStep = drawerStepIndex === COLOR_PAIRING_TOOL_DRAWER_STEPS3.length - 1;
|
|
21510
|
+
const desktopSidebarStyle = React5.useMemo(
|
|
21511
|
+
() => ({
|
|
21512
|
+
"--tool-sidebar-max-height": `calc(100vh - ${stickyOffset}px)`,
|
|
21513
|
+
"--tool-sidebar-top": `${stickyOffset}px`
|
|
21514
|
+
}),
|
|
21515
|
+
[stickyOffset]
|
|
21516
|
+
);
|
|
21517
|
+
const goToDrawerStep = React5.useCallback((stepIndex) => {
|
|
21518
|
+
setDrawerStepIndex(Math.max(0, Math.min(stepIndex, COLOR_PAIRING_TOOL_DRAWER_STEPS3.length - 1)));
|
|
21519
|
+
}, []);
|
|
21520
|
+
const goToNextDrawerStep = React5.useCallback(() => {
|
|
21521
|
+
setDrawerStepIndex(
|
|
21522
|
+
(currentStep) => Math.min(currentStep + 1, COLOR_PAIRING_TOOL_DRAWER_STEPS3.length - 1)
|
|
21523
|
+
);
|
|
21524
|
+
}, []);
|
|
21525
|
+
const goToPreviousDrawerStep = React5.useCallback(() => {
|
|
21526
|
+
setDrawerStepIndex((currentStep) => Math.max(currentStep - 1, 0));
|
|
21527
|
+
}, []);
|
|
21528
|
+
const updateUrlParams = React5.useCallback((nextState) => {
|
|
21529
|
+
const params = new URLSearchParams(window.location.search);
|
|
21530
|
+
params.delete("family");
|
|
21531
|
+
params.set("palette", nextState.themeCategory);
|
|
21532
|
+
params.set("primary", nextState.primaryKey);
|
|
21533
|
+
params.set("accent", nextState.accentKey);
|
|
21534
|
+
params.set("background", nextState.selectedBackgroundToken);
|
|
21535
|
+
if (nextState.selectedPairId) {
|
|
21536
|
+
params.set("pair", nextState.selectedPairId);
|
|
21537
|
+
} else {
|
|
21538
|
+
params.delete("pair");
|
|
21539
|
+
}
|
|
21540
|
+
window.history.replaceState(
|
|
21541
|
+
null,
|
|
21542
|
+
"",
|
|
21543
|
+
`${window.location.pathname}?${params.toString()}${window.location.hash}`
|
|
21544
|
+
);
|
|
21545
|
+
}, []);
|
|
21546
|
+
const applyResolvedSelection = React5.useCallback(
|
|
21547
|
+
(nextState) => {
|
|
21548
|
+
setThemeCategory(nextState.themeCategory);
|
|
21549
|
+
setPrimaryFamilyKey(nextState.primaryKey);
|
|
21550
|
+
setAccentFamilyKey(nextState.accentKey);
|
|
21551
|
+
setSelectedBackgroundToken(nextState.selectedBackgroundToken);
|
|
21552
|
+
setSelectedPairId(nextState.selectedPairId);
|
|
21553
|
+
updateUrlParams(nextState);
|
|
21554
|
+
},
|
|
21555
|
+
[updateUrlParams]
|
|
21556
|
+
);
|
|
21557
|
+
const buildAnalyticsContext = React5.useCallback(
|
|
21558
|
+
(overrides) => ({
|
|
21559
|
+
accentKey: context.accent.key,
|
|
21560
|
+
backgroundToken: selectedBackground?.token,
|
|
21561
|
+
foregroundToken: selectedPair?.foreground.token,
|
|
21562
|
+
pairId: selectedPair?.id,
|
|
21563
|
+
palette: themeCategory,
|
|
21564
|
+
primaryKey: context.primary.key,
|
|
21565
|
+
...overrides
|
|
21566
|
+
}),
|
|
21567
|
+
[context.accent.key, context.primary.key, selectedBackground, selectedPair, themeCategory]
|
|
21568
|
+
);
|
|
21569
|
+
const copyValue = React5.useCallback(
|
|
21570
|
+
(copyKey, value, toastLabel, analyticsEvent) => {
|
|
21571
|
+
copyToClipboardRaw(value);
|
|
21572
|
+
setCopiedKey(copyKey);
|
|
21573
|
+
sonner.toast(toastLabel, { duration: 2e3 });
|
|
21574
|
+
if (analyticsEvent) {
|
|
21575
|
+
emitAnalyticsEvent(analyticsEvent);
|
|
21576
|
+
}
|
|
21577
|
+
if (copiedKeyTimeoutRef.current) {
|
|
21578
|
+
clearTimeout(copiedKeyTimeoutRef.current);
|
|
21579
|
+
}
|
|
21580
|
+
copiedKeyTimeoutRef.current = setTimeout(() => {
|
|
21581
|
+
setCopiedKey(null);
|
|
21582
|
+
copiedKeyTimeoutRef.current = null;
|
|
21583
|
+
}, 2e3);
|
|
21584
|
+
},
|
|
21585
|
+
[copyToClipboardRaw, emitAnalyticsEvent]
|
|
21586
|
+
);
|
|
21587
|
+
const handleThemeCategoryChange = (nextThemeCategory) => {
|
|
21588
|
+
const nextState = resolveSelectionState3(
|
|
21589
|
+
nextThemeCategory,
|
|
21590
|
+
primaryFamilyKey,
|
|
21591
|
+
accentFamilyKey,
|
|
21592
|
+
selectedBackgroundToken,
|
|
21593
|
+
null
|
|
21594
|
+
);
|
|
21595
|
+
setIsShowingAllAlternatives(false);
|
|
21596
|
+
applyResolvedSelection(nextState);
|
|
21597
|
+
emitAnalyticsEvent({
|
|
21598
|
+
name: "palette_change",
|
|
21599
|
+
accentKey: nextState.accentKey,
|
|
21600
|
+
backgroundToken: nextState.selectedBackgroundToken,
|
|
21601
|
+
pairId: nextState.selectedPairId,
|
|
21602
|
+
palette: nextState.themeCategory,
|
|
21603
|
+
primaryKey: nextState.primaryKey
|
|
21604
|
+
});
|
|
21605
|
+
};
|
|
21606
|
+
const handlePrimaryColorChange = (nextPrimaryKey) => {
|
|
21607
|
+
const nextAccentKey = nextPrimaryKey === accentFamilyKey ? getDefaultAccentFamilyKey(themeCategory, nextPrimaryKey) : accentFamilyKey;
|
|
21608
|
+
const nextState = resolveSelectionState3(
|
|
21609
|
+
themeCategory,
|
|
21610
|
+
nextPrimaryKey,
|
|
21611
|
+
nextAccentKey,
|
|
21612
|
+
selectedBackgroundToken,
|
|
21613
|
+
null
|
|
21614
|
+
);
|
|
21615
|
+
setIsShowingAllAlternatives(false);
|
|
21616
|
+
applyResolvedSelection(nextState);
|
|
21617
|
+
emitAnalyticsEvent({
|
|
21618
|
+
name: "primary_change",
|
|
21619
|
+
accentKey: nextState.accentKey,
|
|
21620
|
+
backgroundToken: nextState.selectedBackgroundToken,
|
|
21621
|
+
pairId: nextState.selectedPairId,
|
|
21622
|
+
palette: nextState.themeCategory,
|
|
21623
|
+
primaryKey: nextState.primaryKey
|
|
21624
|
+
});
|
|
21625
|
+
};
|
|
21626
|
+
const handleAccentColorChange = (nextAccentKey) => {
|
|
21627
|
+
if (nextAccentKey === primaryFamilyKey) return;
|
|
21628
|
+
const nextState = resolveSelectionState3(
|
|
21629
|
+
themeCategory,
|
|
21630
|
+
primaryFamilyKey,
|
|
21631
|
+
nextAccentKey,
|
|
21632
|
+
selectedBackgroundToken,
|
|
21633
|
+
null
|
|
21634
|
+
);
|
|
21635
|
+
setIsShowingAllAlternatives(false);
|
|
21636
|
+
applyResolvedSelection(nextState);
|
|
21637
|
+
emitAnalyticsEvent({
|
|
21638
|
+
name: "accent_change",
|
|
21639
|
+
accentKey: nextState.accentKey,
|
|
21640
|
+
backgroundToken: nextState.selectedBackgroundToken,
|
|
21641
|
+
pairId: nextState.selectedPairId,
|
|
21642
|
+
palette: nextState.themeCategory,
|
|
21643
|
+
primaryKey: nextState.primaryKey
|
|
21644
|
+
});
|
|
21645
|
+
};
|
|
21646
|
+
const handleBackgroundChange = (nextSelectedBackgroundToken) => {
|
|
21647
|
+
const nextSelectedPairId = getPreferredPairForBackground5(context.pairsByBackground[nextSelectedBackgroundToken] ?? [])?.id ?? "";
|
|
21648
|
+
const nextState = {
|
|
21649
|
+
accentKey: context.accent.key,
|
|
21650
|
+
context,
|
|
21651
|
+
primaryKey: context.primary.key,
|
|
21652
|
+
selectedBackgroundToken: nextSelectedBackgroundToken,
|
|
21653
|
+
selectedPairId: nextSelectedPairId,
|
|
21654
|
+
themeCategory
|
|
21655
|
+
};
|
|
21656
|
+
setIsShowingAllAlternatives(false);
|
|
21657
|
+
applyResolvedSelection(nextState);
|
|
21658
|
+
emitAnalyticsEvent({
|
|
21659
|
+
name: "background_selection",
|
|
21660
|
+
...buildAnalyticsContext({
|
|
21661
|
+
backgroundToken: nextSelectedBackgroundToken,
|
|
21662
|
+
foregroundToken: context.pairsByBackground[nextSelectedBackgroundToken]?.find(
|
|
21663
|
+
(pair) => pair.id === nextSelectedPairId
|
|
21664
|
+
)?.foreground.token,
|
|
21665
|
+
pairId: nextSelectedPairId
|
|
21666
|
+
})
|
|
21667
|
+
});
|
|
21668
|
+
if (typeof window !== "undefined" && window.matchMedia(MOBILE_RESULT_SCROLL_QUERY3).matches) {
|
|
21669
|
+
requestAnimationFrame(() => {
|
|
21670
|
+
resultSectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
21671
|
+
});
|
|
21672
|
+
}
|
|
21673
|
+
};
|
|
21674
|
+
const handlePairChange = (nextSelectedPairId, source) => {
|
|
21675
|
+
if (!selectedBackground) return;
|
|
21676
|
+
const nextPair = selectedBackgroundPairs.find((pair) => pair.id === nextSelectedPairId) ?? null;
|
|
21677
|
+
setSelectedPairId(nextSelectedPairId);
|
|
21678
|
+
updateUrlParams({
|
|
21679
|
+
accentKey: context.accent.key,
|
|
21680
|
+
context,
|
|
21681
|
+
primaryKey: context.primary.key,
|
|
21682
|
+
selectedBackgroundToken: selectedBackground.token,
|
|
21683
|
+
selectedPairId: nextSelectedPairId,
|
|
21684
|
+
themeCategory
|
|
21685
|
+
});
|
|
21686
|
+
emitAnalyticsEvent({
|
|
21687
|
+
name: "foreground_selection",
|
|
21688
|
+
...buildAnalyticsContext({
|
|
21689
|
+
foregroundToken: nextPair?.foreground.token,
|
|
21690
|
+
pairId: nextSelectedPairId,
|
|
21691
|
+
source
|
|
21692
|
+
})
|
|
21693
|
+
});
|
|
21694
|
+
if (bestRecommendedPair && nextSelectedPairId !== bestRecommendedPair.id) {
|
|
21695
|
+
emitAnalyticsEvent({
|
|
21696
|
+
name: "alternative_combination_selected",
|
|
21697
|
+
...buildAnalyticsContext({
|
|
21698
|
+
foregroundToken: nextPair?.foreground.token,
|
|
21699
|
+
pairId: nextSelectedPairId,
|
|
21700
|
+
source
|
|
21701
|
+
})
|
|
21702
|
+
});
|
|
21703
|
+
}
|
|
21704
|
+
};
|
|
21705
|
+
React5.useEffect(() => {
|
|
21706
|
+
if (!selectedBackground || selectedBackgroundPairs.length > 0) {
|
|
21707
|
+
return;
|
|
21708
|
+
}
|
|
21709
|
+
const key = `${themeCategory}:${context.primary.key}:${context.accent.key}:${selectedBackground.token}`;
|
|
21710
|
+
if (noValidStateRef.current.has(key)) {
|
|
21711
|
+
return;
|
|
21712
|
+
}
|
|
21713
|
+
noValidStateRef.current.add(key);
|
|
21714
|
+
emitAnalyticsEvent({
|
|
21715
|
+
name: "no_valid_combination_state",
|
|
21716
|
+
...buildAnalyticsContext({
|
|
21717
|
+
backgroundToken: selectedBackground.token
|
|
21718
|
+
})
|
|
21719
|
+
});
|
|
21720
|
+
}, [
|
|
21721
|
+
buildAnalyticsContext,
|
|
21722
|
+
context.accent.key,
|
|
21723
|
+
context.primary.key,
|
|
21724
|
+
emitAnalyticsEvent,
|
|
21725
|
+
selectedBackground,
|
|
21726
|
+
selectedBackgroundPairs.length,
|
|
21727
|
+
themeCategory
|
|
21728
|
+
]);
|
|
21729
|
+
React5.useEffect(() => {
|
|
21730
|
+
if (!isTechnicalDetailsOpen || technicalDetailsViewedRef.current) {
|
|
21731
|
+
return;
|
|
21732
|
+
}
|
|
21733
|
+
technicalDetailsViewedRef.current = true;
|
|
21734
|
+
emitAnalyticsEvent({
|
|
21735
|
+
name: "technical_details_viewed",
|
|
21736
|
+
...buildAnalyticsContext({
|
|
21737
|
+
source: "details"
|
|
21738
|
+
})
|
|
21739
|
+
});
|
|
21740
|
+
}, [buildAnalyticsContext, emitAnalyticsEvent, isTechnicalDetailsOpen]);
|
|
21741
|
+
if (!selectedBackground) {
|
|
21742
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "px-6 py-6", children: [
|
|
21743
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "No approved background tones available" }),
|
|
21744
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "mt-3", children: "No approved tones are available for the current palette and colour selection." })
|
|
21745
|
+
] });
|
|
21746
|
+
}
|
|
21747
|
+
const compactControlsSummary = `${themeCategory === "brand" ? "Brand" : "Aboriginal"} palette, ${context.primary.label} primary, ${context.accent.label} accent, ${getPairingColorDisplayName5(
|
|
21748
|
+
selectedBackground
|
|
21749
|
+
)} background.`;
|
|
21750
|
+
const renderControlsPanel = (isOverlay = false) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
21751
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-grey-200 px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
|
|
21752
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Configuration" }),
|
|
21753
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
21754
|
+
!isFirstDrawerStep ? /* @__PURE__ */ jsxRuntime.jsxs(Button2, { variant: "ghost", color: "grey", size: "sm", onClick: goToPreviousDrawerStep, children: [
|
|
21755
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.west, { "data-slot": "icon", className: "size-5" }),
|
|
21756
|
+
"Back"
|
|
21757
|
+
] }) : null,
|
|
21758
|
+
isOverlay ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
21759
|
+
Button2,
|
|
21760
|
+
{
|
|
21761
|
+
variant: "ghost",
|
|
21762
|
+
color: "grey",
|
|
21763
|
+
size: "icon",
|
|
21764
|
+
onClick: () => setIsCompactControlsOpen(false),
|
|
21765
|
+
"aria-label": "Close configuration",
|
|
21766
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icons.close, { "data-slot": "icon", className: "size-5" })
|
|
21767
|
+
}
|
|
21768
|
+
) : null
|
|
21769
|
+
] })
|
|
21770
|
+
] }) }),
|
|
21771
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-grey-200 px-5 py-4", children: [
|
|
21772
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
21773
|
+
COLOR_PAIRING_TOOL_DRAWER_STEPS3.map((step, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
21774
|
+
"button",
|
|
21775
|
+
{
|
|
21776
|
+
type: "button",
|
|
21777
|
+
"aria-current": index === drawerStepIndex ? "step" : void 0,
|
|
21778
|
+
"aria-label": `${step.eyebrow}: ${step.title}`,
|
|
21779
|
+
onClick: () => goToDrawerStep(index),
|
|
21780
|
+
className: "flex-1 rounded-sm focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
|
|
21781
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
21782
|
+
"span",
|
|
21783
|
+
{
|
|
21784
|
+
className: cn(
|
|
21785
|
+
"block h-1.5 rounded-full transition-colors",
|
|
21786
|
+
index <= drawerStepIndex ? "bg-primary-800" : "bg-grey-200"
|
|
21787
|
+
)
|
|
21788
|
+
}
|
|
21789
|
+
)
|
|
21790
|
+
},
|
|
21791
|
+
step.id
|
|
21792
|
+
)),
|
|
21793
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-2 basis-full text-[0.68rem] font-semibold tracking-[0.12em] text-primary-800 uppercase sm:mt-0 sm:ml-2 sm:basis-auto sm:text-[0.72rem]", children: activeDrawerStep.eyebrow })
|
|
21794
|
+
] }),
|
|
21795
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-2", children: [
|
|
21796
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: activeDrawerStep.title }),
|
|
21797
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: activeDrawerStep.description })
|
|
21798
|
+
] })
|
|
21799
|
+
] }),
|
|
21800
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
21801
|
+
"div",
|
|
21802
|
+
{
|
|
21803
|
+
className: "flex h-full transition-transform duration-300 ease-out",
|
|
21804
|
+
style: { transform: `translateX(-${drawerStepIndex * 100}%)` },
|
|
21805
|
+
children: [
|
|
21806
|
+
/* @__PURE__ */ jsxRuntime.jsx("section", { className: "h-full w-full shrink-0 overflow-y-auto px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 pr-1", children: [
|
|
21807
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
|
|
21808
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Palette" }),
|
|
21809
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: ["brand", "aboriginal"].map((palette) => {
|
|
21810
|
+
const isSelected = themeCategory === palette;
|
|
21811
|
+
const label = palette === "brand" ? "Brand palette" : "Aboriginal palette";
|
|
21812
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
21813
|
+
SelectorButton3,
|
|
21814
|
+
{
|
|
21815
|
+
label,
|
|
21816
|
+
isSelected,
|
|
21817
|
+
onClick: () => handleThemeCategoryChange(palette)
|
|
21818
|
+
},
|
|
21819
|
+
palette
|
|
21820
|
+
);
|
|
21821
|
+
}) })
|
|
21822
|
+
] }),
|
|
21823
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
|
|
21824
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Primary colour family" }),
|
|
21825
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: selectableFamilies.map((family) => {
|
|
21826
|
+
const label = getFamilySelectorLabel5(family, themeCategory, "primary colour");
|
|
21827
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
21828
|
+
SelectorButton3,
|
|
21829
|
+
{
|
|
21830
|
+
label,
|
|
21831
|
+
isSelected: family.key === context.primary.key,
|
|
21832
|
+
onClick: () => handlePrimaryColorChange(family.key),
|
|
21833
|
+
swatch: getFamilySwatchColor5(family, 800)
|
|
21834
|
+
},
|
|
21835
|
+
family.key
|
|
21836
|
+
);
|
|
21837
|
+
}) })
|
|
21838
|
+
] }),
|
|
21839
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
|
|
21840
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Accent colour family" }),
|
|
21841
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: selectableAccentFamilies.map((family) => {
|
|
21842
|
+
const label = getFamilySelectorLabel5(family, themeCategory, "accent colour");
|
|
21843
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
21844
|
+
SelectorButton3,
|
|
21845
|
+
{
|
|
21846
|
+
label,
|
|
21847
|
+
isSelected: family.key === context.accent.key,
|
|
21848
|
+
onClick: () => handleAccentColorChange(family.key),
|
|
21849
|
+
swatch: getFamilySwatchColor5(family, 600)
|
|
21850
|
+
},
|
|
21851
|
+
family.key
|
|
21852
|
+
);
|
|
21853
|
+
}) })
|
|
21854
|
+
] }),
|
|
21855
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-grey-200 pt-4", children: [
|
|
21856
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: "Grey is always included" }),
|
|
21857
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Neutral grey options are automatically added so every selection includes a practical fallback family." })
|
|
21858
|
+
] })
|
|
21859
|
+
] }) }),
|
|
21860
|
+
/* @__PURE__ */ jsxRuntime.jsx("section", { className: "h-full w-full shrink-0 overflow-y-auto px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6 pr-1", children: context.backgroundGroups.map((group, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
21861
|
+
"section",
|
|
21862
|
+
{
|
|
21863
|
+
className: cn("space-y-3", index > 0 && "border-t border-grey-200 pt-6"),
|
|
21864
|
+
children: [
|
|
21865
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
21866
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Heading, { level: 4, size: 6, className: "text-foreground", trim: "normal", children: [
|
|
21867
|
+
group.family.label,
|
|
21868
|
+
" backgrounds"
|
|
21869
|
+
] }),
|
|
21870
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: group.label })
|
|
21871
|
+
] }),
|
|
21872
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-3", children: group.backgrounds.map((background) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
21873
|
+
BackgroundSwatchButton3,
|
|
21874
|
+
{
|
|
21875
|
+
background,
|
|
21876
|
+
hasPairs: (context.pairsByBackground[background.token]?.length ?? 0) > 0,
|
|
21877
|
+
isSelected: selectedBackground.token === background.token,
|
|
21878
|
+
onClick: () => handleBackgroundChange(background.token)
|
|
21879
|
+
},
|
|
21880
|
+
background.token
|
|
21881
|
+
)) })
|
|
21882
|
+
]
|
|
21883
|
+
},
|
|
21884
|
+
group.key
|
|
21885
|
+
)) }) }),
|
|
21886
|
+
/* @__PURE__ */ jsxRuntime.jsx("section", { className: "h-full w-full shrink-0 overflow-y-auto px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 pr-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-sm border border-grey-200 bg-grey-50 px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
21887
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "text-foreground", trim: "normal", children: "Review the result on the right" }),
|
|
21888
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "The right panel shows one recommended pairing first. Use approved alternatives there only when you need a different tone or emphasis." })
|
|
21889
|
+
] }) }) }) })
|
|
21890
|
+
]
|
|
21891
|
+
}
|
|
21892
|
+
) }),
|
|
21893
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-grey-200 px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
21894
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-10 flex-1", children: isLastDrawerStep ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Review the NSW recommendation in the result panel. Use alternatives there only if you need a different approved treatment." }) : null }),
|
|
21895
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2 sm:w-auto sm:flex-none", children: [
|
|
21896
|
+
isOverlay && isLastDrawerStep ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
21897
|
+
Button2,
|
|
21898
|
+
{
|
|
21899
|
+
color: "primary",
|
|
21900
|
+
className: "w-full sm:w-auto sm:min-w-40",
|
|
21901
|
+
onClick: () => setIsCompactControlsOpen(false),
|
|
21902
|
+
children: "Review result"
|
|
21903
|
+
}
|
|
21904
|
+
) : null,
|
|
21905
|
+
!isLastDrawerStep ? /* @__PURE__ */ jsxRuntime.jsxs(Button2, { color: "primary", className: "w-full sm:w-auto", onClick: goToNextDrawerStep, children: [
|
|
21906
|
+
"Continue",
|
|
21907
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.east, { "data-slot": "icon", className: "size-5" })
|
|
21908
|
+
] }) : null
|
|
21909
|
+
] })
|
|
21910
|
+
] }) })
|
|
21911
|
+
] });
|
|
21912
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 xl:grid-cols-[minmax(18rem,24rem)_minmax(0,1fr)]", children: [
|
|
21913
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
21914
|
+
"div",
|
|
21915
|
+
{
|
|
21916
|
+
"data-slot": "tool-sidebar",
|
|
21917
|
+
className: "hidden xl:sticky xl:top-[var(--tool-sidebar-top)] xl:block xl:self-start",
|
|
21918
|
+
style: desktopSidebarStyle,
|
|
21919
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "h-[40rem] max-h-[40rem] gap-0 overflow-hidden border-grey-200 bg-grey-50/60 py-0 sm:h-[44rem] sm:max-h-[44rem] xl:h-[var(--tool-sidebar-max-height)] xl:max-h-[var(--tool-sidebar-max-height)]", children: renderControlsPanel() })
|
|
21920
|
+
}
|
|
21921
|
+
),
|
|
21922
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "tool-results", className: "space-y-5", children: [
|
|
21923
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4 xl:hidden", children: [
|
|
21924
|
+
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "gap-4 px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between", children: [
|
|
21925
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
21926
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Configuration" }),
|
|
21927
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "Open the drawer to set palette, colour families, and background. The result panel shows the NSW recommendation first." }),
|
|
21928
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: compactControlsSummary })
|
|
21929
|
+
] }),
|
|
21930
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
21931
|
+
Button2,
|
|
21932
|
+
{
|
|
21933
|
+
color: "primary",
|
|
21934
|
+
className: "w-full sm:w-auto",
|
|
21935
|
+
onClick: () => setIsCompactControlsOpen(true),
|
|
21936
|
+
children: [
|
|
21937
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.edit_square, { "data-slot": "icon", className: "size-5" }),
|
|
21938
|
+
"Open configuration"
|
|
21939
|
+
]
|
|
21940
|
+
}
|
|
21941
|
+
)
|
|
21942
|
+
] }) }),
|
|
21943
|
+
/* @__PURE__ */ jsxRuntime.jsx(Sheet, { open: isCompactControlsOpen, onOpenChange: setIsCompactControlsOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
21944
|
+
SheetContent,
|
|
21945
|
+
{
|
|
21946
|
+
side: "left",
|
|
21947
|
+
showClose: false,
|
|
21948
|
+
className: "w-[30rem] max-w-[90vw] overflow-hidden p-0",
|
|
21949
|
+
children: [
|
|
21950
|
+
/* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Colour pairing configuration" }),
|
|
21951
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full flex-col bg-background", children: renderControlsPanel(true) })
|
|
21952
|
+
]
|
|
21953
|
+
}
|
|
21954
|
+
) })
|
|
21955
|
+
] }),
|
|
21956
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { ref: resultSectionRef, className: "space-y-5", "aria-label": "Current result", children: [
|
|
21957
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sr-only", "aria-live": "polite", children: liveAnnouncement }),
|
|
21958
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
21959
|
+
CurrentResultCard3,
|
|
21960
|
+
{
|
|
21961
|
+
bestPair: bestRecommendedPair,
|
|
21962
|
+
copiedKey,
|
|
21963
|
+
familySummary,
|
|
21964
|
+
onCopyPairing: () => previewPair ? copyValue(
|
|
21965
|
+
"current-pairing",
|
|
21966
|
+
getPairingCopyText3(previewPair),
|
|
21967
|
+
"Pairing copied",
|
|
21968
|
+
previewPair.id === bestRecommendedPair?.id ? {
|
|
21969
|
+
name: "best_recommendation_copied",
|
|
21970
|
+
...buildAnalyticsContext({
|
|
21971
|
+
foregroundToken: previewPair.foreground.token,
|
|
21972
|
+
pairId: previewPair.id,
|
|
21973
|
+
source: "current-result"
|
|
21974
|
+
})
|
|
21975
|
+
} : void 0
|
|
21976
|
+
) : void 0,
|
|
21977
|
+
pair: previewPair,
|
|
21978
|
+
supportText: currentPairSupportText,
|
|
21979
|
+
selectedBackground
|
|
21980
|
+
}
|
|
21981
|
+
)
|
|
21982
|
+
] }),
|
|
21983
|
+
bestRecommendedPair || alternativeRecommendationGroups.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
|
|
21984
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
21985
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 6, className: "text-foreground", trim: "normal", children: "Approved alternatives" }),
|
|
21986
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "text-grey-600", children: "These are approved alternatives for different tone or emphasis." })
|
|
21987
|
+
] }),
|
|
21988
|
+
alternativeRecommendationGroups.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
21989
|
+
visibleAlternativeRecommendationGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
21990
|
+
RecommendationGroupSection2,
|
|
21991
|
+
{
|
|
21992
|
+
title: group.title,
|
|
21993
|
+
description: group.description,
|
|
21994
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: group.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
21995
|
+
RecommendationCard3,
|
|
21996
|
+
{
|
|
21997
|
+
copiedKey,
|
|
21998
|
+
item,
|
|
21999
|
+
isSelected: item.pair.id === selectedPair?.id,
|
|
22000
|
+
onCopyPairing: () => copyValue(
|
|
22001
|
+
`pair:${item.pair.id}`,
|
|
22002
|
+
getPairingCopyText3(item.pair),
|
|
22003
|
+
"Pairing copied",
|
|
22004
|
+
item.pair.id === bestRecommendedPair?.id ? {
|
|
22005
|
+
name: "best_recommendation_copied",
|
|
22006
|
+
...buildAnalyticsContext({
|
|
22007
|
+
foregroundToken: item.pair.foreground.token,
|
|
22008
|
+
pairId: item.pair.id,
|
|
22009
|
+
source: "recommendations-list"
|
|
22010
|
+
})
|
|
22011
|
+
} : void 0
|
|
22012
|
+
),
|
|
22013
|
+
onSelect: () => handlePairChange(item.pair.id, "recommendations-list")
|
|
22014
|
+
},
|
|
22015
|
+
item.pair.id
|
|
22016
|
+
)) })
|
|
22017
|
+
},
|
|
22018
|
+
group.id
|
|
22019
|
+
)),
|
|
22020
|
+
hiddenAlternativeCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
22021
|
+
Button2,
|
|
22022
|
+
{
|
|
22023
|
+
variant: "ghost",
|
|
22024
|
+
color: "grey",
|
|
22025
|
+
className: "w-full justify-center border border-grey-200 bg-white sm:w-auto",
|
|
22026
|
+
onClick: () => setIsShowingAllAlternatives(true),
|
|
22027
|
+
children: [
|
|
22028
|
+
"Show ",
|
|
22029
|
+
hiddenAlternativeCount,
|
|
22030
|
+
" more"
|
|
22031
|
+
]
|
|
22032
|
+
}
|
|
22033
|
+
) : null
|
|
22034
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "px-6 py-6", children: [
|
|
22035
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "text-foreground", trim: "normal", children: "No other AAA alternatives" }),
|
|
22036
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "mt-3", children: "The NSW recommended pairing is the only AAA-compliant foreground option for this background." })
|
|
22037
|
+
] })
|
|
22038
|
+
] }) : null,
|
|
22039
|
+
/* @__PURE__ */ jsxRuntime.jsx("section", { className: "space-y-2", children: /* @__PURE__ */ jsxRuntime.jsxs(Collapsible, { open: isTechnicalDetailsOpen, onOpenChange: setIsTechnicalDetailsOpen, children: [
|
|
22040
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
22041
|
+
"button",
|
|
22042
|
+
{
|
|
22043
|
+
type: "button",
|
|
22044
|
+
className: "flex w-full items-center justify-between gap-4 rounded-sm border border-grey-200 bg-white px-4 py-3.5 text-left transition-colors hover:bg-grey-50 focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden sm:px-5",
|
|
22045
|
+
children: [
|
|
22046
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
|
|
22047
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 6, className: "text-foreground", trim: "normal", children: "Technical colour values" }),
|
|
22048
|
+
/* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "text-muted-foreground", children: "Token, tone, HEX, RGB, HSL, and OKLCH values for advanced use." })
|
|
22049
|
+
] }),
|
|
22050
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
22051
|
+
"span",
|
|
22052
|
+
{
|
|
22053
|
+
className: cn(
|
|
22054
|
+
"inline-flex items-center gap-2 text-sm font-semibold text-primary-800",
|
|
22055
|
+
isTechnicalDetailsOpen && "text-foreground"
|
|
22056
|
+
),
|
|
22057
|
+
children: [
|
|
22058
|
+
isTechnicalDetailsOpen ? "Hide" : "Show",
|
|
22059
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
22060
|
+
Icons.keyboard_arrow_down,
|
|
22061
|
+
{
|
|
22062
|
+
"data-slot": "icon",
|
|
22063
|
+
className: cn(
|
|
22064
|
+
"size-5 transition-transform",
|
|
22065
|
+
isTechnicalDetailsOpen && "rotate-180"
|
|
22066
|
+
)
|
|
22067
|
+
}
|
|
22068
|
+
)
|
|
22069
|
+
]
|
|
22070
|
+
}
|
|
22071
|
+
)
|
|
22072
|
+
]
|
|
22073
|
+
}
|
|
22074
|
+
) }),
|
|
22075
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent2, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [
|
|
22076
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
22077
|
+
TechnicalDetailsPanel3,
|
|
22078
|
+
{
|
|
22079
|
+
title: "Background values",
|
|
22080
|
+
color: selectedBackground,
|
|
22081
|
+
visibleFormats,
|
|
22082
|
+
copiedKey,
|
|
22083
|
+
onCopyValue: (copyKey, value, toastLabel) => copyValue(copyKey, value, toastLabel)
|
|
22084
|
+
}
|
|
22085
|
+
),
|
|
22086
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
22087
|
+
TechnicalDetailsPanel3,
|
|
22088
|
+
{
|
|
22089
|
+
title: "Foreground values",
|
|
22090
|
+
color: detailForeground,
|
|
22091
|
+
visibleFormats,
|
|
22092
|
+
copiedKey,
|
|
22093
|
+
onCopyValue: (copyKey, value, toastLabel) => copyValue(copyKey, value, toastLabel)
|
|
22094
|
+
}
|
|
22095
|
+
)
|
|
22096
|
+
] }) }) })
|
|
22097
|
+
] }) }),
|
|
22098
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-1.5", children: [
|
|
22099
|
+
/* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "text-foreground", trim: "normal", children: "Share colour pairing" }),
|
|
22100
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm border border-grey-200 bg-white px-4 py-3.5", children: [
|
|
22101
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
22102
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Copy a link to this current result." }),
|
|
22103
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
22104
|
+
Button2,
|
|
22105
|
+
{
|
|
22106
|
+
variant: "ghost",
|
|
22107
|
+
color: "grey",
|
|
22108
|
+
size: "sm",
|
|
22109
|
+
className: "shrink-0 self-start sm:self-center",
|
|
22110
|
+
onClick: () => copyValue(
|
|
22111
|
+
"share-url",
|
|
22112
|
+
typeof window === "undefined" ? shareUrl : new URL(shareUrl, window.location.origin).toString(),
|
|
22113
|
+
"Colour pairing link copied"
|
|
22114
|
+
),
|
|
22115
|
+
"aria-label": copiedKey === "share-url" ? "Colour pairing URL copied to clipboard" : "Copy colour pairing URL to clipboard",
|
|
22116
|
+
title: copiedKey === "share-url" ? "Copied" : "Copy URL",
|
|
22117
|
+
children: copiedKey === "share-url" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
22118
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-5" }),
|
|
22119
|
+
"Copied"
|
|
22120
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
22121
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
|
|
22122
|
+
"Copy URL"
|
|
22123
|
+
] })
|
|
22124
|
+
}
|
|
22125
|
+
)
|
|
22126
|
+
] }),
|
|
22127
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { className: "mt-2.5 block w-full rounded-sm border border-grey-200 bg-background px-3 py-2 font-mono text-[11px] break-all text-foreground sm:text-xs", children: shareUrl })
|
|
22128
|
+
] })
|
|
22129
|
+
] })
|
|
22130
|
+
] })
|
|
22131
|
+
] });
|
|
22132
|
+
}
|
|
22133
|
+
function ColorPairingToolV5({
|
|
22134
|
+
onAnalyticsEvent = () => {
|
|
22135
|
+
},
|
|
22136
|
+
visibleFormats = DEFAULT_VISIBLE_FORMATS5
|
|
22137
|
+
} = {}) {
|
|
22138
|
+
const normalizedVisibleFormats = [...new Set(visibleFormats)];
|
|
22139
|
+
return /* @__PURE__ */ jsxRuntime.jsx(React5.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(ColorPairingToolV5Loading, {}), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
22140
|
+
ColorPairingToolV5Content,
|
|
22141
|
+
{
|
|
22142
|
+
onAnalyticsEvent,
|
|
22143
|
+
visibleFormats: normalizedVisibleFormats
|
|
22144
|
+
}
|
|
22145
|
+
) });
|
|
22146
|
+
}
|
|
20530
22147
|
function ColorSwatches({ theme: theme2, format, viewMode }) {
|
|
20531
22148
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20532
22149
|
"div",
|
|
@@ -39135,6 +40752,7 @@ exports.ColorPairingTool = ColorPairingTool;
|
|
|
39135
40752
|
exports.ColorPairingToolV2 = ColorPairingToolV2;
|
|
39136
40753
|
exports.ColorPairingToolV3 = ColorPairingToolV3;
|
|
39137
40754
|
exports.ColorPairingToolV4 = ColorPairingToolV4;
|
|
40755
|
+
exports.ColorPairingToolV5 = ColorPairingToolV5;
|
|
39138
40756
|
exports.ColorSwatches = ColorSwatches;
|
|
39139
40757
|
exports.ColourScale = ColourScale;
|
|
39140
40758
|
exports.ComboChart = ComboChart;
|