{"version":3,"file":"react-dachswitch.umd.cjs","sources":["../components/DACHSwitch.tsx"],"sourcesContent":["\nimport React, { useState, useEffect, useMemo } from 'react';\n\nexport interface DACHSwitchProps {\n  /**\n   * The full HTML Attribute name to check on target elements.\n   * Examples: \"data-country\", \"lang\", \"data-market\".\n   * Default: \"data-country\"\n   */\n  countryCodeAttribute?: string;\n\n  /**\n   * The CSS Selector identifying the elements to be filtered.\n   * If omitted, it defaults to selecting all elements that have the `countryCodeAttribute`.\n   * (e.g., default becomes \"[data-country]\").\n   */\n  targetSelector?: string;\n\n  /**\n   * An object mapping UI labels to country codes.\n   * Default: {\"D\": \"DE\", \"A\": \"AT\", \"CH\": \"CH\"}\n   */\n  codes?: Record<string, string>;\n\n  /**\n   * The initial active UI label(s) OR value(s).\n   * Can be a single key/value (e.g., \"D\" or \"DE\") or an array (e.g., [\"D\", \"AT\"]).\n   * Ignored if defaultAllActive is true.\n   */\n  defaultActive?: string | string[];\n\n  /**\n   * Whether to show the master \"DACH\" toggle button.\n   * Default: true\n   */\n  showAllToggle?: boolean;\n\n  /**\n   * Whether all countries should be active by default on mount.\n   * Overrides defaultActive if true.\n   * Default: true\n   */\n  defaultAllActive?: boolean;\n\n  /**\n   * If true, clicking a flag deselects all others (Radio button behavior).\n   * If false, multiple flags can be active simultaneously.\n   * Default: false\n   */\n  singleSelect?: boolean;\n\n  /**\n   * If true, the selection state will be saved to localStorage and restored on reload.\n   * Default: true\n   */\n  persist?: boolean;\n\n  /**\n   * The key used for localStorage when persist is true.\n   * Change this if you have multiple switches on the same site.\n   * Default: \"dach-switch-selection\"\n   */\n  storageKey?: string;\n}\n\nconst FLAGS: Record<string, string> = {\n  \"D\": \"🇩🇪\",\n  \"A\": \"🇦🇹\",\n  \"CH\": \"🇨🇭\"\n};\n\nexport const DACHSwitch: React.FC<DACHSwitchProps> = ({\n  countryCodeAttribute = \"data-country\",\n  targetSelector, // Now optional\n  codes = { \"D\": \"DE\", \"A\": \"AT\", \"CH\": \"CH\" },\n  defaultActive = \"D\",\n  showAllToggle = true,\n  defaultAllActive = true,\n  singleSelect = false,\n  persist = true,\n  storageKey = \"dach-switch-selection\"\n}) => {\n  // Helper to get all available labels\n  const allLabels = useMemo(() => Object.keys(codes), [codes]);\n\n  // Initialize state with Lazy Initializer for Persistence and Normalization\n  const [activeLabels, setActiveLabels] = useState<string[]>(() => {\n    // 1. Try to load from LocalStorage if enabled\n    if (persist && typeof window !== 'undefined') {\n      try {\n        const saved = window.localStorage.getItem(storageKey);\n        if (saved) {\n          const parsed = JSON.parse(saved);\n          if (Array.isArray(parsed)) {\n            // Sanity check: filter out any keys that no longer exist in 'codes'\n            const validKeys = parsed.filter(k => Object.prototype.hasOwnProperty.call(codes, k));\n            if (validKeys.length > 0) {\n              return validKeys;\n            }\n          }\n        }\n      } catch (error) {\n        console.warn(\"DACHSwitch: Failed to parse localStorage item\", error);\n      }\n    }\n\n    // 2. Fallback: Handle defaultAllActive\n    if (defaultAllActive) return [...allLabels];\n\n    // 3. Fallback: Normalize defaultActive\n    // This allows users to pass \"DE\" (value) instead of \"D\" (key) and still work.\n    const inputs = Array.isArray(defaultActive) ? defaultActive : [defaultActive];\n    const normalizedDefaults: string[] = [];\n\n    inputs.forEach(input => {\n      // Check if input is a Key (e.g., \"D\")\n      if (Object.prototype.hasOwnProperty.call(codes, input)) {\n        normalizedDefaults.push(input);\n        return;\n      }\n      // Check if input is a Value (e.g., \"DE\") -> find its Key\n      const foundKey = Object.keys(codes).find(key => codes[key] === input);\n      if (foundKey) {\n        normalizedDefaults.push(foundKey);\n      }\n    });\n\n    // If normalization resulted in empty array but we had inputs, fallback to empty (nothing selected)\n    // or if inputs were empty, defaults to empty.\n    return normalizedDefaults;\n  });\n\n  // Computed property: Are all options currently selected?\n  const isAllSelected = allLabels.length > 0 && allLabels.every(label => activeLabels.includes(label));\n\n  // Effect: Save to LocalStorage whenever selection changes\n  useEffect(() => {\n    if (persist && typeof window !== 'undefined') {\n      window.localStorage.setItem(storageKey, JSON.stringify(activeLabels));\n    }\n  }, [activeLabels, persist, storageKey]);\n\n  const filterContent = () => {\n    // If no selector provided, target anything with the specific attribute\n    const effectiveSelector = targetSelector || `[${countryCodeAttribute}]`;\n    const targets = document.querySelectorAll(effectiveSelector);\n    \n    // Map active labels to their actual data codes\n    const activeCodes = new Set(activeLabels.map(label => codes[label]));\n\n    targets.forEach((node) => {\n      const element = node as HTMLElement;\n      \n      // Elements without the attribute are always visible (if caught by a broad selector)\n      // OR if they are layout elements wrapping the content.\n      if (!element.hasAttribute(countryCodeAttribute)) {\n        element.style.display = '';\n        return;\n      }\n\n      const elementCode = element.getAttribute(countryCodeAttribute);\n      \n      // Show if the element's code is in our active set\n      if (elementCode && activeCodes.has(elementCode)) {\n        element.style.display = '';\n      } else {\n        element.style.display = 'none';\n      }\n    });\n  };\n\n  // Run filter on mount and when selection changes\n  useEffect(() => {\n    filterContent();\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [activeLabels, targetSelector, countryCodeAttribute, codes]);\n\n  // Handler for clicking the \"DACH\" (All) toggle\n  const handleAllToggle = () => {\n    if (isAllSelected) {\n      // If all are selected, deselect all\n      setActiveLabels([]);\n    } else {\n      // Select all\n      setActiveLabels([...allLabels]);\n    }\n  };\n\n  // Handler for clicking a specific country flag\n  const handleFlagClick = (label: string) => {\n    if (singleSelect) {\n      // Radio behavior: Select only this one\n      setActiveLabels([label]);\n    } else {\n      // Checkbox behavior\n      if (activeLabels.includes(label)) {\n        setActiveLabels(prev => prev.filter(l => l !== label));\n      } else {\n        setActiveLabels(prev => [...prev, label]);\n      }\n    }\n  };\n\n  return (\n    <div className=\"inline-flex items-center justify-center p-1.5 bg-slate-100/90 backdrop-blur-sm rounded-xl shadow-inner border border-slate-200 gap-3\">\n      \n      {/* Master DACH Toggle */}\n      {showAllToggle && (\n        <>\n          <button\n            onClick={handleAllToggle}\n            className={`\n              group relative flex items-center justify-center px-3 py-2 rounded-lg text-sm font-bold transition-all duration-200 ease-in-out focus:outline-none\n              ${\n                isAllSelected\n                  ? 'bg-white text-slate-900 shadow-sm ring-1 ring-slate-200'\n                  : 'text-slate-500 hover:text-slate-700 hover:bg-slate-200/50'\n              }\n            `}\n            type=\"button\"\n            title=\"Toggle All Countries\"\n            aria-pressed={isAllSelected}\n          >\n            {/* Toggle Switch Icon */}\n            <div className={`mr-2 w-8 h-4 rounded-full relative transition-colors duration-300 ${isAllSelected ? 'bg-emerald-500' : 'bg-slate-300 group-hover:bg-slate-400'}`}>\n               <div className={`absolute top-0.5 left-0.5 w-3 h-3 rounded-full bg-white shadow-sm transition-transform duration-300 ${isAllSelected ? 'translate-x-4' : 'translate-x-0'}`} />\n            </div>\n            <span className=\"tracking-tight\">DACH</span>\n          </button>\n\n          {/* Vertical Divider */}\n          <div className=\"w-px h-8 bg-slate-300/60\" />\n        </>\n      )}\n\n      {/* Country Flags */}\n      <div className=\"flex items-center gap-1\">\n        {allLabels.map((label) => {\n          const isActive = activeLabels.includes(label);\n          \n          // Visual Logic:\n          // If \"All\" is active (via toggle), show flags as colorful but flat (no border/scale).\n          // If specific flags are active (subset), show them colorful AND highlighted (border + bg + scale).\n          \n          const isGlobalActive = showAllToggle && isAllSelected;\n          \n          const containerClasses = isActive && !isGlobalActive\n            ? 'bg-white shadow-sm ring-1 ring-slate-200 scale-105 z-10'\n            : 'hover:bg-slate-200/50'; // Flat state for \"All active\" or \"Inactive\"\n\n          // If active (either globally or individually), show full color. Otherwise grayscale.\n          const flagClasses = isActive\n            ? 'grayscale-0 opacity-100'\n            : 'grayscale opacity-40 hover:opacity-60 hover:grayscale-[50%]';\n\n          return (\n            <button\n              key={label}\n              onClick={() => handleFlagClick(label)}\n              className={`\n                relative flex items-center justify-center p-2 rounded-lg transition-all duration-200 ease-in-out focus:outline-none\n                ${containerClasses}\n              `}\n              aria-pressed={isActive}\n              type=\"button\"\n              title={`Filter by ${label}`}\n              data-testid={`flag-${label}`}\n            >\n              <span \n                className={`text-2xl leading-none filter transition-all duration-300 ${flagClasses}`}\n              >\n                {FLAGS[label] || '🏳️'}\n              </span>\n            </button>\n          );\n        })}\n      </div>\n    </div>\n  );\n};\n"],"names":["FLAGS","DACHSwitch","countryCodeAttribute","targetSelector","codes","defaultActive","showAllToggle","defaultAllActive","singleSelect","persist","storageKey","allLabels","useMemo","activeLabels","setActiveLabels","useState","saved","parsed","validKeys","k","error","inputs","normalizedDefaults","input","foundKey","key","isAllSelected","label","useEffect","filterContent","effectiveSelector","targets","activeCodes","node","element","elementCode","handleAllToggle","handleFlagClick","prev","l","jsxs","Fragment","jsx","isActive","containerClasses","flagClasses"],"mappings":"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"}