hazo_ui 6.16.0 → 6.19.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/dropdown-menu.tsx","../src/components/ui/button.tsx","../src/locales/en.json","../src/contexts/hazo_ui_i18n.tsx","../src/components/locale_picker/index.tsx"],"names":["React2","jsx","jsxs","React3","DropdownMenuPrimitive2","Circle"],"mappings":"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","file":"index.locale-picker.js","sourcesContent":["// Utility functions for hazo_ui component library\n// Provides className merging utility (cn function)\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merges class names using clsx and tailwind-merge\n * @param inputs - Class values to merge\n * @returns Merged class string\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Sanitizes a user/admin-supplied href against a scheme allowlist to prevent\n * `javascript:`/`data:`/`vbscript:` URI XSS when the value is rendered into an\n * `<a href>`. Allows http(s), mailto, and same-origin absolute paths (`/…` but\n * not protocol-relative `//…`). Returns `undefined` for anything else, so the\n * anchor renders with no href rather than an active malicious one.\n * @param url - Candidate href (may be undefined)\n * @returns The original url if allowed, otherwise undefined\n */\nexport function safeHref(url?: string): string | undefined {\n if (!url) return undefined;\n const trimmed = url.trim();\n const lower = trimmed.toLowerCase();\n if (\n lower.startsWith(\"http://\") ||\n lower.startsWith(\"https://\") ||\n lower.startsWith(\"mailto:\")\n ) {\n return trimmed;\n }\n // Same-origin absolute path, but not protocol-relative \"//host\".\n if (trimmed.startsWith(\"/\") && !trimmed.startsWith(\"//\")) {\n return trimmed;\n }\n return undefined;\n}\n\n","// DropdownMenu component for hazo_ui library\n// Based on shadcn/ui dropdown-menu component\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport { cn } from \"../../lib/utils\";\n\nconst DropdownMenu = DropdownMenuPrimitive.Root;\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto h-4 w-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;\n\nconst DropdownMenuSubContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;\n\nconst DropdownMenuContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nconst DropdownMenuItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;\n\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;\n\nconst DropdownMenuLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-2 py-1.5 text-sm font-semibold\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;\n\nconst DropdownMenuSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;\n\nconst DropdownMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn(\"ml-auto text-xs tracking-widest opacity-60\", className)}\n {...props}\n />\n );\n};\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\";\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuGroup,\n DropdownMenuPortal,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuRadioGroup,\n};\n","// Button component for hazo_ui library\n// Based on shadcn/ui button component\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../../lib/utils\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive: \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, style, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n style={style}\n ref={ref}\n {...props}\n />\n );\n }\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n\n","{\n \"table.showing\": \"Showing {{start}}–{{end}} of {{total}}\",\n \"table.prev\": \"‹ Prev\",\n \"table.prev_aria\": \"Previous page\",\n \"table.next\": \"Next ›\",\n \"table.next_aria\": \"Next page\",\n \"table.search_placeholder\": \"Search...\",\n \"table.sort_tooltip\": \"Click to sort; shift-click to append a secondary sort\",\n \"table.empty\": \"No items\",\n \"table.no_results\": \"No matches — adjust your filters\",\n \"table.error_title\": \"Couldn't load data\",\n \"table.error_description\": \"The data source rejected the request.\",\n\n \"rte.undo\": \"Undo\",\n \"rte.redo\": \"Redo\",\n \"rte.decrease_font_size\": \"Decrease font size\",\n \"rte.increase_font_size\": \"Increase font size\",\n \"rte.bold\": \"Bold\",\n \"rte.italic\": \"Italic\",\n \"rte.underline\": \"Underline\",\n \"rte.strikethrough\": \"Strikethrough\",\n \"rte.subscript\": \"Subscript\",\n \"rte.superscript\": \"Superscript\",\n \"rte.link\": \"Link\",\n \"rte.clear_formatting\": \"Clear formatting\",\n \"rte.text_color\": \"Text color\",\n \"rte.highlight_color\": \"Highlight color\",\n \"rte.align_left\": \"Align left\",\n \"rte.align_center\": \"Align center\",\n \"rte.align_right\": \"Align right\",\n \"rte.justify\": \"Justify\",\n \"rte.bullet_list\": \"Bullet list\",\n \"rte.ordered_list\": \"Numbered list\",\n \"rte.checklist\": \"Checklist\",\n \"rte.decrease_indent\": \"Decrease indent\",\n \"rte.increase_indent\": \"Increase indent\",\n \"rte.horizontal_rule\": \"Horizontal rule\",\n \"rte.insert_image\": \"Insert image\",\n \"rte.table\": \"Table\",\n \"rte.tab_html\": \"HTML\",\n \"rte.tab_plain_text\": \"Plain Text\",\n \"rte.tab_raw_html\": \"Raw HTML\",\n \"rte.empty_content\": \"(empty)\",\n \"rte.link_placeholder\": \"https://example.com\",\n \"rte.insert_variable\": \"Insert variable\",\n \"rte.attach_file\": \"Attach file\",\n\n \"rte.block_type.paragraph\": \"Paragraph\",\n \"rte.block_type.heading_1\": \"Heading 1\",\n \"rte.block_type.heading_2\": \"Heading 2\",\n \"rte.block_type.heading_3\": \"Heading 3\",\n \"rte.block_type.ordered_list\": \"Numbered List\",\n \"rte.block_type.bullet_list\": \"Bulleted List\",\n \"rte.block_type.task_list\": \"Check List\",\n \"rte.block_type.code_block\": \"Code Block\",\n \"rte.block_type.blockquote\": \"Quote\",\n\n \"filter.title\": \"Filter\",\n \"filter.description\": \"Add fields to filter by. Select a field and set its value.\",\n \"filter.text_placeholder\": \"Enter text...\",\n \"filter.number_placeholder\": \"Value\",\n \"filter.select_option_placeholder\": \"Select option...\",\n \"filter.select_placeholder\": \"Select...\",\n \"filter.pick_date\": \"Pick a date\",\n \"filter.on\": \"On\",\n \"filter.off\": \"Off\",\n \"filter.remove_field_aria\": \"Remove {{field}} filter\",\n \"filter.active_filters\": \"Active filters\",\n \"filter.no_active_filters\": \"No active filters\",\n \"filter.open_dialog_aria\": \"Open filter dialog\",\n \"filter.button_label\": \"Filter\",\n \"filter.empty_fields\": \"No filters yet. Add one below to narrow down the results.\",\n \"filter.all_fields_added\": \"All fields added\",\n \"filter.add_filter_field\": \"Add filter field\",\n \"filter.search_fields_placeholder\": \"Search fields...\",\n \"filter.no_fields_available\": \"No fields available.\",\n \"filter.clear_all\": \"Clear all\",\n \"filter.cancel\": \"Cancel\",\n \"filter.apply\": \"Apply\",\n\n \"sort.title\": \"Sort\",\n \"sort.description\": \"Add fields to sort by, drag to reorder, toggle ascending or descending.\",\n \"sort.search_fields\": \"Search fields...\",\n \"sort.open_dialog_aria\": \"Open sort dialog\",\n \"sort.clear_all\": \"Clear all\",\n \"sort.cancel\": \"Cancel\",\n \"sort.apply\": \"Apply\",\n\n \"canvas_toolbar.bold\": \"Bold\",\n \"canvas_toolbar.italic\": \"Italic\",\n \"canvas_toolbar.underline\": \"Underline\",\n \"canvas_toolbar.align_left\": \"Align left\",\n \"canvas_toolbar.align_center\": \"Align center\",\n \"canvas_toolbar.align_right\": \"Align right\",\n \"canvas_toolbar.text_color\": \"Text color\",\n \"canvas_toolbar.font_family\": \"Font family\",\n \"canvas_toolbar.font_sans\": \"Sans\",\n \"canvas_toolbar.font_serif\": \"Serif\",\n \"canvas_toolbar.font_mono\": \"Mono\",\n \"canvas_toolbar.align_top\": \"Align top\",\n \"canvas_toolbar.align_middle\": \"Align middle\",\n \"canvas_toolbar.align_bottom\": \"Align bottom\",\n \"canvas_toolbar.bullet_list\": \"Bullet list\",\n\n \"toast.permission_required\": \"Permission required\",\n \"toast.permission_denied_message\": \"You do not have permission to perform this action.\",\n\n \"error.something_went_wrong\": \"Something went wrong\",\n \"error.dismiss\": \"Dismiss\",\n\n \"loading.taking_longer\": \"This is taking longer than expected\",\n\n \"notification.loading\": \"Loading notifications\",\n \"notification.mark_all_read\": \"Mark all as read\",\n \"notification.unread\": \"Unread\",\n \"notification.unread_count\": \"{{count}} unread\",\n \"browser_tab.close_aria\": \"Close {{label}}\",\n\n \"confirm.cancel\": \"Cancel\",\n\n \"icon_picker.search_placeholder\": \"Search icons...\",\n\n \"common.loading\": \"Loading...\",\n \"common.cancel\": \"Cancel\",\n \"common.search\": \"Search...\",\n \"dialog.default_title\": \"Action required\",\n \"dialog.cancel\": \"Cancel\",\n \"dialog.ok\": \"OK\",\n \"dialog.confirm\": \"Confirm\",\n \"dialog.close\": \"Close\",\n \"kanban.status_label\": \"Status\",\n \"kanban.edit_fallback\": \"Edit {{id}}\",\n \"kanban.update_description\": \"Update card details below.\",\n \"kanban.saving\": \"Saving…\",\n \"kanban.save\": \"Save\",\n \"kanban.cancel\": \"Cancel\",\n \"kanban.select_placeholder\": \"Select {{label}}…\",\n \"kanban.select_priority\": \"Select priority…\",\n \"kanban.select_status\": \"Select status…\",\n \"kanban.clear\": \"Clear\",\n \"markdown.placeholder\": \"Write in Markdown…\",\n \"markdown.upload_failed\": \"Upload failed.\",\n \"markdown.loading_editor\": \"Loading editor…\",\n \"markdown.uploading_image\": \"Uploading image…\",\n \"markdown.upload_placeholder\": \"uploading…\",\n \"cropper.title\": \"Crop photo\",\n \"cropper.save\": \"Save\",\n \"cropper.cancel\": \"Cancel\",\n \"cropper.zoom\": \"Zoom\",\n \"memory.search_placeholder\": \"Search history…\",\n \"memory.no_history\": \"No history yet\",\n \"memory.remove_aria\": \"Remove {{label}} from history\",\n \"celebration.close\": \"Close celebration\",\n \"celebration.download_png\": \"Download PNG\",\n \"celebration.share\": \"Share\",\n \"celebration.copy_image\": \"Copy image\",\n \"celebration.dismiss\": \"Dismiss\",\n \"charts.date_range\": \"Date range\",\n\n \"flex_input.must_be_valid_number\": \"Must be a valid number\",\n \"flex_input.max_decimals\": \"Maximum {{count}} decimal places allowed\",\n \"flex_input.min_value\": \"Must be at least {{min}}\",\n \"flex_input.max_value\": \"Must be at most {{max}}\",\n \"flex_input.alpha_only\": \"Only letters, numbers, and spaces are allowed\",\n \"flex_input.must_be_valid_email\": \"Must be a valid email address\",\n \"flex_input.min_characters\": \"Must be at least {{min}} characters\",\n \"flex_input.max_characters\": \"Must be at most {{max}} characters\",\n \"flex_input.invalid_format\": \"Invalid format\",\n \"flex_input.invalid_input\": \"Invalid input\",\n\n \"textbox.placeholder\": \"Type here...\",\n \"textarea.placeholder\": \"Type here...\",\n \"common.remove\": \"Remove\",\n\n \"locale_picker.change_language\": \"Change language\",\n\n \"app_logo.alt_fallback\": \"Logo\",\n \"app_header.aria_label\": \"Application header\",\n \"app_header.menu_label\": \"Menu\",\n \"app_header.nav_title\": \"Navigation\",\n\n \"skeleton.loading_content\": \"Loading content\",\n \"spinner.loading\": \"Loading\",\n \"spinner.loading_text\": \"Loading...\",\n\n \"rte.update_link\": \"Update Link\",\n \"rte.add_link\": \"Add Link\",\n \"rte.remove_link\": \"Remove\",\n \"rte.select_size\": \"Select size\",\n \"rte.custom_size\": \"Custom size\",\n \"rte.insert_table\": \"Insert\",\n \"rte.search_variables\": \"Search variables...\",\n \"rte.no_variables\": \"No variables found.\",\n \"rte.table_operations\": \"Table Operations\",\n \"rte.add_row_above\": \"Add row above\",\n \"rte.add_row_below\": \"Add row below\",\n \"rte.add_col_left\": \"Add col left\",\n \"rte.add_col_right\": \"Add col right\",\n \"rte.delete_row\": \"Delete row\",\n \"rte.delete_col\": \"Delete col\",\n \"rte.delete_table\": \"Delete table\",\n \"rte.insert_table_heading\": \"Insert Table\",\n\n \"rte.placeholder\": \"Start typing...\",\n\n \"sort.asc\": \"Asc\",\n \"sort.desc\": \"Desc\",\n \"sort.reorder_aria\": \"Reorder {{field}}\",\n \"sort.priority_aria\": \"Sort priority {{n}}\",\n \"sort.direction_aria\": \"Sort direction for {{field}}\",\n \"sort.remove_aria\": \"Remove {{field}} from sort\",\n \"sort.active_sorts\": \"Active sorts\",\n \"sort.no_active_sorts\": \"No active sorts\",\n \"sort.button_label\": \"Sort\",\n \"sort.empty_message\": \"No sort fields yet. Add one below to start ordering rows.\",\n \"sort.all_fields_added\": \"All fields added\",\n \"sort.add_sort_field\": \"Add sort field\",\n \"sort.no_fields_available\": \"No fields available.\",\n\n \"kanban.dnd_pickup\": \"Picked up {{item}}. Currently in {{column}}. Use arrow keys to choose a different column. Press space to drop, escape to cancel.\",\n \"kanban.dnd_over\": \"{{item}} over {{column}}.\",\n \"kanban.dnd_drop\": \"{{item}} dropped in {{column}}, position {{pos}}.\",\n \"kanban.dnd_reorder\": \"{{item}} reordered to position {{pos}} in {{column}}.\",\n \"kanban.dnd_cancel\": \"Movement cancelled. {{item}} returned to {{column}}.\",\n \"kanban.draggable_card\": \"draggable card\",\n\n \"loading.still_loading\": \"We're still trying to load the {{label}}. The connection may be slow.\",\n \"loading.try_again\": \"Try again\",\n \"loading.gentle_message\": \"Loading {{label}}…\",\n \"loading.default_label\": \"content\",\n \"loading.firm_message\":\"Still working on it — almost there.\",\n\n \"icon_picker.emoji_tab\": \"Emoji\",\n \"icon_picker.tools_group\": \"Tools\",\n \"icon_picker.home_group\": \"Home\",\n \"icon_picker.weather_group\": \"Weather\",\n \"icon_picker.nature_group\": \"Nature\",\n \"icon_picker.symbols_group\": \"Symbols\",\n \"icon_picker.no_results\": \"No icons found\",\n\n \"error.correlation_id\": \"Correlation ID\",\n\n \"charts.total\": \"Total: {{value}}\",\n \"charts.pct_of_first\": \"% of first: {{pct}}%\",\n \"charts.pct_of_prev\": \"% of prev: {{pct}}%\",\n \"charts.dropoff\": \"Drop-off: −{{value}}\",\n\n \"toast.missing_prefix\": \"Missing: {{items}}\"\n}\n","\"use client\";\n\n/**\n * hazo_ui_i18n.tsx\n *\n * Purpose: Lets the consuming app supply a locale-aware translator to every\n * hazo_ui component. Mirrors hazo_auth's `HazoAuthProvider` `t` prop.\n *\n * Why: `createPackageT` (hazo_core/i18n) only reads hazo_ui's bundled English\n * catalog — it is locale-blind by design. Without a provider, every hazo_ui\n * component renders English regardless of the active locale. The app mounts\n * this provider under <HazoI18nProvider> and passes the locale-aware `t`\n * (e.g. `useTranslations(\"hazo_ui\")` from \"hazo_i18n/client\").\n *\n * With no provider mounted, `useHazoUiT()` falls back to the English catalog,\n * so hazo_ui keeps working without hazo_i18n installed.\n */\n\nimport { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport { createPackageT } from \"hazo_core/i18n\";\nimport en from \"../locales/en.json\" with { type: \"json\" };\nimport { get_logger } from \"../utils/logger\";\n\n/** Translator signature components call: `t(\"filter.title\", { field: \"x\" })`. */\nexport type HazoUiTFunction = (\n key: string,\n values?: Record<string, string | number>\n) => string;\n\n// English fallback — used when no HazoUiI18nProvider is mounted.\nconst default_t: HazoUiTFunction = createPackageT(\"hazo_ui\", en);\n\n/**\n * English translator for non-React callers (imperative APIs such as\n * `permissionToast`). Not locale-aware — React components should use `useHazoUiT()`.\n */\nexport const defaultHazoUiT: HazoUiTFunction = default_t;\n\nconst HazoUiI18nContext = createContext<HazoUiTFunction>(default_t);\n\nexport interface HazoUiI18nProviderProps {\n /** Locale-aware translator. Typically `useTranslations(\"hazo_ui\")` from \"hazo_i18n/client\". */\n t: HazoUiTFunction;\n children: ReactNode;\n}\n\n/**\n * Supplies a locale-aware `t` to all hazo_ui components beneath it.\n *\n * @example\n * ```tsx\n * function Providers({ children }) {\n * const t = useTranslations(\"hazo_ui\");\n * return <HazoUiI18nProvider t={t}>{children}</HazoUiI18nProvider>;\n * }\n * ```\n */\nexport function HazoUiI18nProvider({ t, children }: HazoUiI18nProviderProps) {\n // A key missing from the active locale's catalog (e.g. a newly added hazo_ui\n // string not yet translated) would throw in hazo_i18n's dev mode. Fall back\n // to the English string for that key instead of crashing the page.\n const safe_t = useMemo<HazoUiTFunction>(\n () => (key, values) => {\n try {\n return t(key, values);\n } catch {\n get_logger().warn(\"i18n_missing_key_fallback\", { key });\n return default_t(key, values);\n }\n },\n [t]\n );\n return <HazoUiI18nContext.Provider value={safe_t}>{children}</HazoUiI18nContext.Provider>;\n}\n\n/**\n * Returns the active hazo_ui translator (locale-aware under a provider,\n * English otherwise). Call inside a component body.\n */\nexport function useHazoUiT(): HazoUiTFunction {\n return useContext(HazoUiI18nContext);\n}\n","\"use client\";\n\n/**\n * LocalePicker — standard language switcher for hazo_* apps (FR-030).\n *\n * Purely prop-driven: no hazo_i18n dependency, no context, no fetch. A\n * consumer supplies `alternates` (the same locale -> URL map used for\n * `<head>` hreflang) and this renders a picker that can only ever offer\n * URLs that exist. Works identically whether hazo_i18n exists or not —\n * today it doesn't, so this component has zero runtime dependency on it.\n *\n * Built on the same Radix DropdownMenu primitives as\n * `src/components/ui/dropdown-menu.tsx`, but each option is rendered as a\n * real `<a href>` (via Radix's `asChild`) rather than a JS-only click\n * handler, so it stays crawlable and middle-click-openable.\n */\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Circle, ChevronDown, Globe } from \"lucide-react\";\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuRadioGroup,\n} from \"../ui/dropdown-menu\";\nimport { Button } from \"../ui/button\";\nimport { cn, safeHref } from \"../../lib/utils\";\nimport { useHazoUiT } from \"../../contexts/hazo_ui_i18n\";\n\n\nexport type LocalePickerVariant = \"dropdown\" | \"inline\" | \"compact\";\nexport type LocalePickerShow = \"auto\" | \"always\" | \"never\";\nexport type LocalePickerDisplay = \"native\" | \"native+code\" | \"code\";\n\nexport interface LocalePickerProps {\n /** Visual form. `dropdown` (default) and `compact` are Radix dropdown\n * menus; `inline` renders a flat row of links with no popover. */\n variant?: LocalePickerVariant;\n /** `auto` (default) renders nothing when fewer than two locales are\n * offered — single-locale apps need no conditional around this\n * component. `always` / `never` override that. */\n show?: LocalePickerShow;\n /** How each option's label is built. Default `native` — the language's\n * own name in its own script (`Deutsch`, `Svenska`), not an English\n * name and not a flag (PRD-hazo_i18n §11.2). */\n display?: LocalePickerDisplay;\n /** Render an inline SVG flag alongside each option. Default false.\n * Never emoji — Segoe UI Emoji ships no regional-indicator glyphs, so\n * flag emoji render as two letter-boxes on Windows Chrome/Edge. */\n flags?: boolean;\n /** hreflang code -> URL for the current page. The picker can only ever\n * offer locales present here — same map used for `<head>` hreflang. */\n alternates: Record<string, string>;\n /** Currently active locale, used to mark the selected option. */\n activeLocale?: string;\n /** aria-label for the trigger (dropdown/compact) or the `<nav>`\n * (inline). Defaults to the localized `locale_picker.change_language` string. */\n triggerLabel?: string;\n className?: string;\n}\n\ninterface LocalePickerOption {\n code: string;\n href: string;\n label: string;\n}\n\n// ────────────────────────────────────────────────────────────────────────\n// Native language names — Intl.DisplayNames instantiated PER LANGUAGE in\n// that language's own locale, so German renders \"Deutsch\" (not \"German\"),\n// Swedish renders \"Svenska\" (not \"Swedish\"), etc.\n// ────────────────────────────────────────────────────────────────────────\n\nconst native_name_cache = new Map<string, string>();\n\nfunction get_native_name(code: string): string {\n const cached = native_name_cache.get(code);\n if (cached !== undefined) return cached;\n\n let name = code;\n if (typeof Intl !== \"undefined\" && \"DisplayNames\" in Intl) {\n try {\n const display_names = new Intl.DisplayNames([code], {\n type: \"language\",\n languageDisplay: \"standard\",\n });\n name = display_names.of(code) ?? code;\n } catch {\n name = code;\n }\n }\n native_name_cache.set(code, name);\n return name;\n}\n\nfunction build_label(code: string, display: LocalePickerDisplay): string {\n if (display === \"code\") return code.toUpperCase();\n const native = get_native_name(code);\n if (display === \"native+code\") return `${native} (${code.toUpperCase()})`;\n return native;\n}\n\n// ────────────────────────────────────────────────────────────────────────\n// Flags — minimal inline SVGs for a handful of common locales; anything\n// else (including English, deliberately — see PRD-hazo_i18n §11.2 on why\n// English has no single honest flag) falls back to a generic globe icon.\n// Never emoji.\n// ────────────────────────────────────────────────────────────────────────\n\nconst STRIPE_FLAGS: Record<string, { dir: \"h\" | \"v\"; colors: string[] }> = {\n de: { dir: \"h\", colors: [\"#000000\", \"#DD0000\", \"#FFCE00\"] },\n fr: { dir: \"v\", colors: [\"#0055A4\", \"#FFFFFF\", \"#EF4135\"] },\n it: { dir: \"v\", colors: [\"#009246\", \"#FFFFFF\", \"#CE2B37\"] },\n es: { dir: \"h\", colors: [\"#AA151B\", \"#F1BF00\", \"#AA151B\"] },\n pt: { dir: \"v\", colors: [\"#046A38\", \"#FFFFFF\", \"#DA291C\"] },\n nl: { dir: \"h\", colors: [\"#AE1C28\", \"#FFFFFF\", \"#21468B\"] },\n};\n\nconst NORDIC_CROSS_FLAGS: Record<string, { bg: string; cross: string }> = {\n sv: { bg: \"#006AA7\", cross: \"#FECC00\" },\n fi: { bg: \"#FFFFFF\", cross: \"#003580\" },\n};\n\nfunction StripeFlag({\n dir,\n colors,\n}: {\n dir: \"h\" | \"v\";\n colors: string[];\n}): React.ReactElement {\n const band = 12 / colors.length;\n return (\n <svg viewBox=\"0 0 16 12\" width=\"16\" height=\"12\" aria-hidden=\"true\" focusable=\"false\">\n {colors.map((color, i) =>\n dir === \"h\" ? (\n <rect key={i} x={0} y={i * band} width={16} height={band} fill={color} />\n ) : (\n <rect key={i} x={i * (16 / colors.length)} y={0} width={16 / colors.length} height={12} fill={color} />\n )\n )}\n </svg>\n );\n}\n\nfunction NordicCrossFlag({ bg, cross }: { bg: string; cross: string }): React.ReactElement {\n return (\n <svg viewBox=\"0 0 16 12\" width=\"16\" height=\"12\" aria-hidden=\"true\" focusable=\"false\">\n <rect width=\"16\" height=\"12\" fill={bg} />\n <rect x=\"5\" width=\"2\" height=\"12\" fill={cross} />\n <rect y=\"5\" width=\"16\" height=\"2\" fill={cross} />\n </svg>\n );\n}\n\nfunction get_flag_node(code: string): React.ReactNode {\n const lang = code.toLowerCase().split(/[-_]/)[0];\n const cross = NORDIC_CROSS_FLAGS[lang];\n if (cross) return <NordicCrossFlag {...cross} />;\n const stripes = STRIPE_FLAGS[lang];\n if (stripes) return <StripeFlag {...stripes} />;\n return <Globe className=\"h-3 w-3\" aria-hidden=\"true\" />;\n}\n\nfunction FlagIcon({ code }: { code: string }): React.ReactElement {\n return (\n <span className=\"cls_locale_picker_flag inline-flex h-3.5 w-4 shrink-0 items-center justify-center overflow-hidden rounded-[2px]\">\n {get_flag_node(code)}\n </span>\n );\n}\n\n// ────────────────────────────────────────────────────────────────────────\n// Component\n// ────────────────────────────────────────────────────────────────────────\n\nexport function LocalePicker({\n variant = \"dropdown\",\n show = \"auto\",\n display = \"native\",\n flags = false,\n alternates,\n activeLocale,\n triggerLabel,\n className,\n}: LocalePickerProps): React.ReactElement | null {\n const t = useHazoUiT();\n const resolved_trigger_label = triggerLabel ?? t(\"locale_picker.change_language\");\n const options: LocalePickerOption[] = React.useMemo(() => {\n return Object.entries(alternates ?? {})\n .map(([code, url]) => {\n const href = safeHref(url);\n if (!href) return null;\n return { code, href, label: build_label(code, display) };\n })\n .filter((o): o is LocalePickerOption => o !== null);\n }, [alternates, display]);\n\n if (show === \"never\") return null;\n if (options.length === 0) return null;\n if (show === \"auto\" && options.length < 2) return null;\n\n if (variant === \"inline\") {\n return (\n <nav\n aria-label={resolved_trigger_label}\n className={cn(\"cls_locale_picker_inline flex items-center gap-1\", className)}\n >\n {options.map((opt) => (\n <a\n key={opt.code}\n href={opt.href}\n lang={opt.code}\n aria-current={opt.code === activeLocale ? \"true\" : undefined}\n className={cn(\n \"cls_locale_picker_inline_item inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-sm transition-colors hover:bg-accent hover:text-accent-foreground\",\n opt.code === activeLocale && \"bg-accent font-medium text-accent-foreground\"\n )}\n >\n {flags && <FlagIcon code={opt.code} />}\n <span>{opt.label}</span>\n </a>\n ))}\n </nav>\n );\n }\n\n const active_option = options.find((o) => o.code === activeLocale);\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"outline\"\n size=\"sm\"\n lang={activeLocale}\n aria-label={resolved_trigger_label}\n className={cn(\"cls_locale_picker_trigger gap-1.5\", className)}\n >\n {flags && <FlagIcon code={active_option?.code ?? options[0].code} />}\n <span className=\"cls_locale_picker_trigger_label\">\n {variant === \"compact\"\n ? (active_option ?? options[0]).code.toUpperCase()\n : (active_option ?? options[0]).label}\n </span>\n <ChevronDown className=\"h-3.5 w-3.5 opacity-60\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"cls_locale_picker_content\">\n <DropdownMenuRadioGroup value={activeLocale}>\n {options.map((opt) => (\n <DropdownMenuPrimitive.RadioItem key={opt.code} value={opt.code} asChild>\n <a\n href={opt.href}\n lang={opt.code}\n className=\"cls_locale_picker_radio_item relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\"\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {flags && <FlagIcon code={opt.code} />}\n <span>{opt.label}</span>\n </a>\n </DropdownMenuPrimitive.RadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nLocalePicker.displayName = \"LocalePicker\";\n"]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/dropdown-menu.tsx","../src/components/ui/button.tsx","../src/locales/en.json","../src/contexts/hazo_ui_i18n.tsx","../src/components/locale_picker/index.tsx"],"names":["React2","jsx","jsxs","React3","DropdownMenuPrimitive2","Circle"],"mappings":"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","file":"index.locale-picker.js","sourcesContent":["// Utility functions for hazo_ui component library\n// Provides className merging utility (cn function)\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merges class names using clsx and tailwind-merge\n * @param inputs - Class values to merge\n * @returns Merged class string\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Sanitizes a user/admin-supplied href against a scheme allowlist to prevent\n * `javascript:`/`data:`/`vbscript:` URI XSS when the value is rendered into an\n * `<a href>`. Allows http(s), mailto, and same-origin absolute paths (`/…` but\n * not protocol-relative `//…`). Returns `undefined` for anything else, so the\n * anchor renders with no href rather than an active malicious one.\n * @param url - Candidate href (may be undefined)\n * @returns The original url if allowed, otherwise undefined\n */\nexport function safeHref(url?: string): string | undefined {\n if (!url) return undefined;\n const trimmed = url.trim();\n const lower = trimmed.toLowerCase();\n if (\n lower.startsWith(\"http://\") ||\n lower.startsWith(\"https://\") ||\n lower.startsWith(\"mailto:\")\n ) {\n return trimmed;\n }\n // Same-origin absolute path, but not protocol-relative \"//host\".\n if (trimmed.startsWith(\"/\") && !trimmed.startsWith(\"//\")) {\n return trimmed;\n }\n return undefined;\n}\n\n","// DropdownMenu component for hazo_ui library\n// Based on shadcn/ui dropdown-menu component\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport { cn } from \"../../lib/utils\";\n\nconst DropdownMenu = DropdownMenuPrimitive.Root;\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto h-4 w-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;\n\nconst DropdownMenuSubContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;\n\nconst DropdownMenuContent = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nconst DropdownMenuItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;\n\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;\n\nconst DropdownMenuLabel = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-2 py-1.5 text-sm font-semibold\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;\n\nconst DropdownMenuSeparator = React.forwardRef<\n React.ElementRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;\n\nconst DropdownMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn(\"ml-auto text-xs tracking-widest opacity-60\", className)}\n {...props}\n />\n );\n};\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\";\n\nexport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuGroup,\n DropdownMenuPortal,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuRadioGroup,\n};\n","// Button component for hazo_ui library\n// Based on shadcn/ui button component\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../../lib/utils\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive: \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, style, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n className={cn(buttonVariants({ variant, size, className }))}\n style={style}\n ref={ref}\n {...props}\n />\n );\n }\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n\n","{\n \"table.showing\": \"Showing {{start}}–{{end}} of {{total}}\",\n \"table.prev\": \"‹ Prev\",\n \"table.prev_aria\": \"Previous page\",\n \"table.next\": \"Next ›\",\n \"table.next_aria\": \"Next page\",\n \"table.search_placeholder\": \"Search...\",\n \"table.sort_tooltip\": \"Click to sort; shift-click to append a secondary sort\",\n \"table.empty\": \"No items\",\n \"table.no_results\": \"No matches — adjust your filters\",\n \"table.error_title\": \"Couldn't load data\",\n \"table.error_description\": \"The data source rejected the request.\",\n\n \"rte.undo\": \"Undo\",\n \"rte.redo\": \"Redo\",\n \"rte.decrease_font_size\": \"Decrease font size\",\n \"rte.increase_font_size\": \"Increase font size\",\n \"rte.bold\": \"Bold\",\n \"rte.italic\": \"Italic\",\n \"rte.underline\": \"Underline\",\n \"rte.strikethrough\": \"Strikethrough\",\n \"rte.subscript\": \"Subscript\",\n \"rte.superscript\": \"Superscript\",\n \"rte.link\": \"Link\",\n \"rte.clear_formatting\": \"Clear formatting\",\n \"rte.text_color\": \"Text color\",\n \"rte.highlight_color\": \"Highlight color\",\n \"rte.align_left\": \"Align left\",\n \"rte.align_center\": \"Align center\",\n \"rte.align_right\": \"Align right\",\n \"rte.justify\": \"Justify\",\n \"rte.bullet_list\": \"Bullet list\",\n \"rte.ordered_list\": \"Numbered list\",\n \"rte.checklist\": \"Checklist\",\n \"rte.decrease_indent\": \"Decrease indent\",\n \"rte.increase_indent\": \"Increase indent\",\n \"rte.horizontal_rule\": \"Horizontal rule\",\n \"rte.insert_image\": \"Insert image\",\n \"rte.table\": \"Table\",\n \"rte.tab_html\": \"HTML\",\n \"rte.tab_plain_text\": \"Plain Text\",\n \"rte.tab_raw_html\": \"Raw HTML\",\n \"rte.empty_content\": \"(empty)\",\n \"rte.link_placeholder\": \"https://example.com\",\n \"rte.insert_variable\": \"Insert variable\",\n \"rte.attach_file\": \"Attach file\",\n\n \"rte.block_type.paragraph\": \"Paragraph\",\n \"rte.block_type.heading_1\": \"Heading 1\",\n \"rte.block_type.heading_2\": \"Heading 2\",\n \"rte.block_type.heading_3\": \"Heading 3\",\n \"rte.block_type.ordered_list\": \"Numbered List\",\n \"rte.block_type.bullet_list\": \"Bulleted List\",\n \"rte.block_type.task_list\": \"Check List\",\n \"rte.block_type.code_block\": \"Code Block\",\n \"rte.block_type.blockquote\": \"Quote\",\n\n \"filter.title\": \"Filter\",\n \"filter.description\": \"Add fields to filter by. Select a field and set its value.\",\n \"filter.text_placeholder\": \"Enter text...\",\n \"filter.number_placeholder\": \"Value\",\n \"filter.select_option_placeholder\": \"Select option...\",\n \"filter.select_placeholder\": \"Select...\",\n \"filter.pick_date\": \"Pick a date\",\n \"filter.on\": \"On\",\n \"filter.off\": \"Off\",\n \"filter.remove_field_aria\": \"Remove {{field}} filter\",\n \"filter.active_filters\": \"Active filters\",\n \"filter.no_active_filters\": \"No active filters\",\n \"filter.open_dialog_aria\": \"Open filter dialog\",\n \"filter.button_label\": \"Filter\",\n \"filter.empty_fields\": \"No filters yet. Add one below to narrow down the results.\",\n \"filter.all_fields_added\": \"All fields added\",\n \"filter.add_filter_field\": \"Add filter field\",\n \"filter.search_fields_placeholder\": \"Search fields...\",\n \"filter.no_fields_available\": \"No fields available.\",\n \"filter.clear_all\": \"Clear all\",\n \"filter.cancel\": \"Cancel\",\n \"filter.apply\": \"Apply\",\n\n \"sort.title\": \"Sort\",\n \"sort.description\": \"Add fields to sort by, drag to reorder, toggle ascending or descending.\",\n \"sort.search_fields\": \"Search fields...\",\n \"sort.open_dialog_aria\": \"Open sort dialog\",\n \"sort.clear_all\": \"Clear all\",\n \"sort.cancel\": \"Cancel\",\n \"sort.apply\": \"Apply\",\n\n \"canvas_toolbar.bold\": \"Bold\",\n \"canvas_toolbar.italic\": \"Italic\",\n \"canvas_toolbar.underline\": \"Underline\",\n \"canvas_toolbar.align_left\": \"Align left\",\n \"canvas_toolbar.align_center\": \"Align center\",\n \"canvas_toolbar.align_right\": \"Align right\",\n \"canvas_toolbar.text_color\": \"Text color\",\n \"canvas_toolbar.font_family\": \"Font family\",\n \"canvas_toolbar.font_sans\": \"Sans\",\n \"canvas_toolbar.font_serif\": \"Serif\",\n \"canvas_toolbar.font_mono\": \"Mono\",\n \"canvas_toolbar.align_top\": \"Align top\",\n \"canvas_toolbar.align_middle\": \"Align middle\",\n \"canvas_toolbar.align_bottom\": \"Align bottom\",\n \"canvas_toolbar.bullet_list\": \"Bullet list\",\n\n \"toast.permission_required\": \"Permission required\",\n \"toast.permission_denied_message\": \"You do not have permission to perform this action.\",\n\n \"error.something_went_wrong\": \"Something went wrong\",\n \"error.dismiss\": \"Dismiss\",\n\n \"loading.taking_longer\": \"This is taking longer than expected\",\n\n \"notification.loading\": \"Loading notifications\",\n \"notification.mark_all_read\": \"Mark all as read\",\n \"notification.unread\": \"Unread\",\n \"notification.unread_count\": \"{{count}} unread\",\n \"browser_tab.close_aria\": \"Close {{label}}\",\n\n \"confirm.cancel\": \"Cancel\",\n\n \"icon_picker.search_placeholder\": \"Search icons...\",\n\n \"common.loading\": \"Loading...\",\n \"common.cancel\": \"Cancel\",\n \"common.search\": \"Search...\",\n \"dialog.default_title\": \"Action required\",\n \"dialog.cancel\": \"Cancel\",\n \"dialog.ok\": \"OK\",\n \"dialog.confirm\": \"Confirm\",\n \"dialog.close\": \"Close\",\n \"kanban.status_label\": \"Status\",\n \"kanban.edit_fallback\": \"Edit {{id}}\",\n \"kanban.update_description\": \"Update card details below.\",\n \"kanban.saving\": \"Saving…\",\n \"kanban.save\": \"Save\",\n \"kanban.cancel\": \"Cancel\",\n \"kanban.select_placeholder\": \"Select {{label}}…\",\n \"kanban.select_priority\": \"Select priority…\",\n \"kanban.select_status\": \"Select status…\",\n \"kanban.clear\": \"Clear\",\n \"markdown.placeholder\": \"Write in Markdown…\",\n \"markdown.upload_failed\": \"Upload failed.\",\n \"markdown.loading_editor\": \"Loading editor…\",\n \"markdown.uploading_image\": \"Uploading image…\",\n \"markdown.upload_placeholder\": \"uploading…\",\n \"cropper.title\": \"Crop photo\",\n \"cropper.save\": \"Save\",\n \"cropper.cancel\": \"Cancel\",\n \"cropper.zoom\": \"Zoom\",\n \"memory.search_placeholder\": \"Search history…\",\n \"memory.no_history\": \"No history yet\",\n \"memory.remove_aria\": \"Remove {{label}} from history\",\n \"celebration.close\": \"Close celebration\",\n \"celebration.download_png\": \"Download PNG\",\n \"celebration.share\": \"Share\",\n \"celebration.copy_image\": \"Copy image\",\n \"celebration.dismiss\": \"Dismiss\",\n \"charts.date_range\": \"Date range\",\n\n \"flex_input.must_be_valid_number\": \"Must be a valid number\",\n \"flex_input.max_decimals\": \"Maximum {{count}} decimal places allowed\",\n \"flex_input.min_value\": \"Must be at least {{min}}\",\n \"flex_input.max_value\": \"Must be at most {{max}}\",\n \"flex_input.alpha_only\": \"Only letters, numbers, and spaces are allowed\",\n \"flex_input.must_be_valid_email\": \"Must be a valid email address\",\n \"flex_input.min_characters\": \"Must be at least {{min}} characters\",\n \"flex_input.max_characters\": \"Must be at most {{max}} characters\",\n \"flex_input.invalid_format\": \"Invalid format\",\n \"flex_input.invalid_input\": \"Invalid input\",\n\n \"textbox.placeholder\": \"Type here...\",\n \"textarea.placeholder\": \"Type here...\",\n \"common.remove\": \"Remove\",\n\n \"locale_picker.change_language\": \"Change language\",\n\n \"app_logo.alt_fallback\": \"Logo\",\n \"app_header.aria_label\": \"Application header\",\n \"app_header.menu_label\": \"Menu\",\n \"app_header.nav_title\": \"Navigation\",\n\n \"skeleton.loading_content\": \"Loading content\",\n \"spinner.loading\": \"Loading\",\n \"spinner.loading_text\": \"Loading...\",\n\n \"rte.update_link\": \"Update Link\",\n \"rte.add_link\": \"Add Link\",\n \"rte.remove_link\": \"Remove\",\n \"rte.select_size\": \"Select size\",\n \"rte.custom_size\": \"Custom size\",\n \"rte.insert_table\": \"Insert\",\n \"rte.search_variables\": \"Search variables...\",\n \"rte.no_variables\": \"No variables found.\",\n \"rte.table_operations\": \"Table Operations\",\n \"rte.add_row_above\": \"Add row above\",\n \"rte.add_row_below\": \"Add row below\",\n \"rte.add_col_left\": \"Add col left\",\n \"rte.add_col_right\": \"Add col right\",\n \"rte.delete_row\": \"Delete row\",\n \"rte.delete_col\": \"Delete col\",\n \"rte.delete_table\": \"Delete table\",\n \"rte.insert_table_heading\": \"Insert Table\",\n\n \"rte.placeholder\": \"Start typing...\",\n\n \"sort.asc\": \"Asc\",\n \"sort.desc\": \"Desc\",\n \"sort.reorder_aria\": \"Reorder {{field}}\",\n \"sort.priority_aria\": \"Sort priority {{n}}\",\n \"sort.direction_aria\": \"Sort direction for {{field}}\",\n \"sort.remove_aria\": \"Remove {{field}} from sort\",\n \"sort.active_sorts\": \"Active sorts\",\n \"sort.no_active_sorts\": \"No active sorts\",\n \"sort.button_label\": \"Sort\",\n \"sort.empty_message\": \"No sort fields yet. Add one below to start ordering rows.\",\n \"sort.all_fields_added\": \"All fields added\",\n \"sort.add_sort_field\": \"Add sort field\",\n \"sort.no_fields_available\": \"No fields available.\",\n\n \"kanban.dnd_pickup\": \"Picked up {{item}}. Currently in {{column}}. Use arrow keys to choose a different column. Press space to drop, escape to cancel.\",\n \"kanban.dnd_over\": \"{{item}} over {{column}}.\",\n \"kanban.dnd_drop\": \"{{item}} dropped in {{column}}, position {{pos}}.\",\n \"kanban.dnd_reorder\": \"{{item}} reordered to position {{pos}} in {{column}}.\",\n \"kanban.dnd_cancel\": \"Movement cancelled. {{item}} returned to {{column}}.\",\n \"kanban.draggable_card\": \"draggable card\",\n\n \"loading.still_loading\": \"We're still trying to load the {{label}}. The connection may be slow.\",\n \"loading.try_again\": \"Try again\",\n \"loading.gentle_message\": \"Loading {{label}}…\",\n \"loading.default_label\": \"content\",\n \"loading.firm_message\":\"Still working on it — almost there.\",\n\n \"icon_picker.emoji_tab\": \"Emoji\",\n \"icon_picker.tools_group\": \"Tools\",\n \"icon_picker.home_group\": \"Home\",\n \"icon_picker.weather_group\": \"Weather\",\n \"icon_picker.nature_group\": \"Nature\",\n \"icon_picker.symbols_group\": \"Symbols\",\n \"icon_picker.no_results\": \"No icons found\",\n\n \"error.correlation_id\": \"Correlation ID\",\n\n \"charts.total\": \"Total: {{value}}\",\n \"charts.pct_of_first\": \"% of first: {{pct}}%\",\n \"charts.pct_of_prev\": \"% of prev: {{pct}}%\",\n \"charts.dropoff\": \"Drop-off: −{{value}}\",\n\n \"toast.missing_prefix\": \"Missing: {{items}}\",\n\n \"editable_data_table.add\": \"Add\",\n \"editable_data_table.delete\": \"Delete row\",\n \"editable_data_table.empty\": \"No rows yet. Click Add to start.\",\n \"editable_data_table.drag_to_reorder\": \"Drag to reorder\"\n}\n","\"use client\";\n\n/**\n * hazo_ui_i18n.tsx\n *\n * Purpose: Lets the consuming app supply a locale-aware translator to every\n * hazo_ui component. Mirrors hazo_auth's `HazoAuthProvider` `t` prop.\n *\n * Why: `createPackageT` (hazo_core/i18n) only reads hazo_ui's bundled English\n * catalog — it is locale-blind by design. Without a provider, every hazo_ui\n * component renders English regardless of the active locale. The app mounts\n * this provider under <HazoI18nProvider> and passes the locale-aware `t`\n * (e.g. `useTranslations(\"hazo_ui\")` from \"hazo_i18n/client\").\n *\n * With no provider mounted, `useHazoUiT()` falls back to the English catalog,\n * so hazo_ui keeps working without hazo_i18n installed.\n */\n\nimport { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport { createPackageT } from \"hazo_core/i18n\";\nimport en from \"../locales/en.json\" with { type: \"json\" };\nimport { get_logger } from \"../utils/logger\";\n\n/** Translator signature components call: `t(\"filter.title\", { field: \"x\" })`. */\nexport type HazoUiTFunction = (\n key: string,\n values?: Record<string, string | number>\n) => string;\n\n// English fallback — used when no HazoUiI18nProvider is mounted.\nconst default_t: HazoUiTFunction = createPackageT(\"hazo_ui\", en);\n\n/**\n * English translator for non-React callers (imperative APIs such as\n * `permissionToast`). Not locale-aware — React components should use `useHazoUiT()`.\n */\nexport const defaultHazoUiT: HazoUiTFunction = default_t;\n\nconst HazoUiI18nContext = createContext<HazoUiTFunction>(default_t);\n\nexport interface HazoUiI18nProviderProps {\n /** Locale-aware translator. Typically `useTranslations(\"hazo_ui\")` from \"hazo_i18n/client\". */\n t: HazoUiTFunction;\n children: ReactNode;\n}\n\n/**\n * Supplies a locale-aware `t` to all hazo_ui components beneath it.\n *\n * @example\n * ```tsx\n * function Providers({ children }) {\n * const t = useTranslations(\"hazo_ui\");\n * return <HazoUiI18nProvider t={t}>{children}</HazoUiI18nProvider>;\n * }\n * ```\n */\nexport function HazoUiI18nProvider({ t, children }: HazoUiI18nProviderProps) {\n // A key missing from the active locale's catalog (e.g. a newly added hazo_ui\n // string not yet translated) would throw in hazo_i18n's dev mode. Fall back\n // to the English string for that key instead of crashing the page.\n const safe_t = useMemo<HazoUiTFunction>(\n () => (key, values) => {\n try {\n return t(key, values);\n } catch {\n get_logger().warn(\"i18n_missing_key_fallback\", { key });\n return default_t(key, values);\n }\n },\n [t]\n );\n return <HazoUiI18nContext.Provider value={safe_t}>{children}</HazoUiI18nContext.Provider>;\n}\n\n/**\n * Returns the active hazo_ui translator (locale-aware under a provider,\n * English otherwise). Call inside a component body.\n */\nexport function useHazoUiT(): HazoUiTFunction {\n return useContext(HazoUiI18nContext);\n}\n","\"use client\";\n\n/**\n * LocalePicker — standard language switcher for hazo_* apps (FR-030).\n *\n * Purely prop-driven: no hazo_i18n dependency, no context, no fetch. A\n * consumer supplies `alternates` (the same locale -> URL map used for\n * `<head>` hreflang) and this renders a picker that can only ever offer\n * URLs that exist. Works identically whether hazo_i18n exists or not —\n * today it doesn't, so this component has zero runtime dependency on it.\n *\n * Built on the same Radix DropdownMenu primitives as\n * `src/components/ui/dropdown-menu.tsx`, but each option is rendered as a\n * real `<a href>` (via Radix's `asChild`) rather than a JS-only click\n * handler, so it stays crawlable and middle-click-openable.\n */\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Circle, ChevronDown, Globe } from \"lucide-react\";\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuRadioGroup,\n} from \"../ui/dropdown-menu\";\nimport { Button } from \"../ui/button\";\nimport { cn, safeHref } from \"../../lib/utils\";\nimport { useHazoUiT } from \"../../contexts/hazo_ui_i18n\";\n\n\nexport type LocalePickerVariant = \"dropdown\" | \"inline\" | \"compact\";\nexport type LocalePickerShow = \"auto\" | \"always\" | \"never\";\nexport type LocalePickerDisplay = \"native\" | \"native+code\" | \"code\";\n\nexport interface LocalePickerProps {\n /** Visual form. `dropdown` (default) and `compact` are Radix dropdown\n * menus; `inline` renders a flat row of links with no popover. */\n variant?: LocalePickerVariant;\n /** `auto` (default) renders nothing when fewer than two locales are\n * offered — single-locale apps need no conditional around this\n * component. `always` / `never` override that. */\n show?: LocalePickerShow;\n /** How each option's label is built. Default `native` — the language's\n * own name in its own script (`Deutsch`, `Svenska`), not an English\n * name and not a flag (PRD-hazo_i18n §11.2). */\n display?: LocalePickerDisplay;\n /** Render an inline SVG flag alongside each option. Default false.\n * Never emoji — Segoe UI Emoji ships no regional-indicator glyphs, so\n * flag emoji render as two letter-boxes on Windows Chrome/Edge. */\n flags?: boolean;\n /** hreflang code -> URL for the current page. The picker can only ever\n * offer locales present here — same map used for `<head>` hreflang. */\n alternates: Record<string, string>;\n /** Currently active locale, used to mark the selected option. */\n activeLocale?: string;\n /** aria-label for the trigger (dropdown/compact) or the `<nav>`\n * (inline). Defaults to the localized `locale_picker.change_language` string. */\n triggerLabel?: string;\n className?: string;\n}\n\ninterface LocalePickerOption {\n code: string;\n href: string;\n label: string;\n}\n\n// ────────────────────────────────────────────────────────────────────────\n// Native language names — Intl.DisplayNames instantiated PER LANGUAGE in\n// that language's own locale, so German renders \"Deutsch\" (not \"German\"),\n// Swedish renders \"Svenska\" (not \"Swedish\"), etc.\n// ────────────────────────────────────────────────────────────────────────\n\nconst native_name_cache = new Map<string, string>();\n\nfunction get_native_name(code: string): string {\n const cached = native_name_cache.get(code);\n if (cached !== undefined) return cached;\n\n let name = code;\n if (typeof Intl !== \"undefined\" && \"DisplayNames\" in Intl) {\n try {\n const display_names = new Intl.DisplayNames([code], {\n type: \"language\",\n languageDisplay: \"standard\",\n });\n name = display_names.of(code) ?? code;\n } catch {\n name = code;\n }\n }\n native_name_cache.set(code, name);\n return name;\n}\n\nfunction build_label(code: string, display: LocalePickerDisplay): string {\n if (display === \"code\") return code.toUpperCase();\n const native = get_native_name(code);\n if (display === \"native+code\") return `${native} (${code.toUpperCase()})`;\n return native;\n}\n\n// ────────────────────────────────────────────────────────────────────────\n// Flags — minimal inline SVGs for a handful of common locales; anything\n// else (including English, deliberately — see PRD-hazo_i18n §11.2 on why\n// English has no single honest flag) falls back to a generic globe icon.\n// Never emoji.\n// ────────────────────────────────────────────────────────────────────────\n\nconst STRIPE_FLAGS: Record<string, { dir: \"h\" | \"v\"; colors: string[] }> = {\n de: { dir: \"h\", colors: [\"#000000\", \"#DD0000\", \"#FFCE00\"] },\n fr: { dir: \"v\", colors: [\"#0055A4\", \"#FFFFFF\", \"#EF4135\"] },\n it: { dir: \"v\", colors: [\"#009246\", \"#FFFFFF\", \"#CE2B37\"] },\n es: { dir: \"h\", colors: [\"#AA151B\", \"#F1BF00\", \"#AA151B\"] },\n pt: { dir: \"v\", colors: [\"#046A38\", \"#FFFFFF\", \"#DA291C\"] },\n nl: { dir: \"h\", colors: [\"#AE1C28\", \"#FFFFFF\", \"#21468B\"] },\n};\n\nconst NORDIC_CROSS_FLAGS: Record<string, { bg: string; cross: string }> = {\n sv: { bg: \"#006AA7\", cross: \"#FECC00\" },\n fi: { bg: \"#FFFFFF\", cross: \"#003580\" },\n};\n\nfunction StripeFlag({\n dir,\n colors,\n}: {\n dir: \"h\" | \"v\";\n colors: string[];\n}): React.ReactElement {\n const band = 12 / colors.length;\n return (\n <svg viewBox=\"0 0 16 12\" width=\"16\" height=\"12\" aria-hidden=\"true\" focusable=\"false\">\n {colors.map((color, i) =>\n dir === \"h\" ? (\n <rect key={i} x={0} y={i * band} width={16} height={band} fill={color} />\n ) : (\n <rect key={i} x={i * (16 / colors.length)} y={0} width={16 / colors.length} height={12} fill={color} />\n )\n )}\n </svg>\n );\n}\n\nfunction NordicCrossFlag({ bg, cross }: { bg: string; cross: string }): React.ReactElement {\n return (\n <svg viewBox=\"0 0 16 12\" width=\"16\" height=\"12\" aria-hidden=\"true\" focusable=\"false\">\n <rect width=\"16\" height=\"12\" fill={bg} />\n <rect x=\"5\" width=\"2\" height=\"12\" fill={cross} />\n <rect y=\"5\" width=\"16\" height=\"2\" fill={cross} />\n </svg>\n );\n}\n\nfunction get_flag_node(code: string): React.ReactNode {\n const lang = code.toLowerCase().split(/[-_]/)[0];\n const cross = NORDIC_CROSS_FLAGS[lang];\n if (cross) return <NordicCrossFlag {...cross} />;\n const stripes = STRIPE_FLAGS[lang];\n if (stripes) return <StripeFlag {...stripes} />;\n return <Globe className=\"h-3 w-3\" aria-hidden=\"true\" />;\n}\n\nfunction FlagIcon({ code }: { code: string }): React.ReactElement {\n return (\n <span className=\"cls_locale_picker_flag inline-flex h-3.5 w-4 shrink-0 items-center justify-center overflow-hidden rounded-[2px]\">\n {get_flag_node(code)}\n </span>\n );\n}\n\n// ────────────────────────────────────────────────────────────────────────\n// Component\n// ────────────────────────────────────────────────────────────────────────\n\nexport function LocalePicker({\n variant = \"dropdown\",\n show = \"auto\",\n display = \"native\",\n flags = false,\n alternates,\n activeLocale,\n triggerLabel,\n className,\n}: LocalePickerProps): React.ReactElement | null {\n const t = useHazoUiT();\n const resolved_trigger_label = triggerLabel ?? t(\"locale_picker.change_language\");\n const options: LocalePickerOption[] = React.useMemo(() => {\n return Object.entries(alternates ?? {})\n .map(([code, url]) => {\n const href = safeHref(url);\n if (!href) return null;\n return { code, href, label: build_label(code, display) };\n })\n .filter((o): o is LocalePickerOption => o !== null);\n }, [alternates, display]);\n\n if (show === \"never\") return null;\n if (options.length === 0) return null;\n if (show === \"auto\" && options.length < 2) return null;\n\n if (variant === \"inline\") {\n return (\n <nav\n aria-label={resolved_trigger_label}\n className={cn(\"cls_locale_picker_inline flex items-center gap-1\", className)}\n >\n {options.map((opt) => (\n <a\n key={opt.code}\n href={opt.href}\n lang={opt.code}\n aria-current={opt.code === activeLocale ? \"true\" : undefined}\n className={cn(\n \"cls_locale_picker_inline_item inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-sm transition-colors hover:bg-accent hover:text-accent-foreground\",\n opt.code === activeLocale && \"bg-accent font-medium text-accent-foreground\"\n )}\n >\n {flags && <FlagIcon code={opt.code} />}\n <span>{opt.label}</span>\n </a>\n ))}\n </nav>\n );\n }\n\n const active_option = options.find((o) => o.code === activeLocale);\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"outline\"\n size=\"sm\"\n lang={activeLocale}\n aria-label={resolved_trigger_label}\n className={cn(\"cls_locale_picker_trigger gap-1.5\", className)}\n >\n {flags && <FlagIcon code={active_option?.code ?? options[0].code} />}\n <span className=\"cls_locale_picker_trigger_label\">\n {variant === \"compact\"\n ? (active_option ?? options[0]).code.toUpperCase()\n : (active_option ?? options[0]).label}\n </span>\n <ChevronDown className=\"h-3.5 w-3.5 opacity-60\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"cls_locale_picker_content\">\n <DropdownMenuRadioGroup value={activeLocale}>\n {options.map((opt) => (\n <DropdownMenuPrimitive.RadioItem key={opt.code} value={opt.code} asChild>\n <a\n href={opt.href}\n lang={opt.code}\n className=\"cls_locale_picker_radio_item relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\"\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {flags && <FlagIcon code={opt.code} />}\n <span>{opt.label}</span>\n </a>\n </DropdownMenuPrimitive.RadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nLocalePicker.displayName = \"LocalePicker\";\n"]}
@@ -70,11 +70,86 @@ function loadScrollPos(key) {
70
70
  }
71
71
  }
72
72
 
73
+ // src/lib/trend_stats.ts
74
+ var DAY_MS = 864e5;
75
+ var MONTHS = [
76
+ "Jan",
77
+ "Feb",
78
+ "Mar",
79
+ "Apr",
80
+ "May",
81
+ "Jun",
82
+ "Jul",
83
+ "Aug",
84
+ "Sep",
85
+ "Oct",
86
+ "Nov",
87
+ "Dec"
88
+ ];
89
+ function pctOf(count, prev) {
90
+ if (prev === null || prev === 0) return null;
91
+ return Math.round((count - prev) / prev * 100);
92
+ }
93
+ var DEFAULT_WINDOWS = [
94
+ { key: "7d", label: "7 days", days: 7 },
95
+ { key: "30d", label: "30 days", days: 30 },
96
+ { key: "90d", label: "3 months", days: 90 },
97
+ { key: "180d", label: "6 months", days: 180 }
98
+ ];
99
+ function computeTrendStats(items, now = /* @__PURE__ */ new Date(), options) {
100
+ const nowMs = now.getTime();
101
+ const times = [];
102
+ for (const item of items) {
103
+ if (!item || !item.created_at) continue;
104
+ const t = new Date(item.created_at).getTime();
105
+ if (!Number.isNaN(t)) times.push(t);
106
+ }
107
+ const countBetween = (startMs, endMs) => times.reduce((n, t) => t >= startMs && t < endMs ? n + 1 : n, 0);
108
+ const total = times.length;
109
+ const rollingDefs = options?.windows ?? DEFAULT_WINDOWS;
110
+ const windows = [
111
+ { key: "all", label: options?.totalLabel ?? "All time", count: total, prevCount: null, pctChange: null }
112
+ ];
113
+ for (const w of rollingDefs) {
114
+ const span = w.days * DAY_MS;
115
+ const count = countBetween(nowMs - span, nowMs);
116
+ const prevCount = countBetween(nowMs - 2 * span, nowMs - span);
117
+ windows.push({
118
+ key: w.key,
119
+ label: w.label,
120
+ count,
121
+ prevCount,
122
+ pctChange: pctOf(count, prevCount)
123
+ });
124
+ }
125
+ const ytdStart = new Date(now.getFullYear(), 0, 1).getTime();
126
+ const elapsed = nowMs - ytdStart;
127
+ const ytdCount = countBetween(ytdStart, nowMs);
128
+ const prevYtdStart = new Date(now.getFullYear() - 1, 0, 1).getTime();
129
+ const prevYtdCount = countBetween(prevYtdStart, prevYtdStart + elapsed);
130
+ windows.push({
131
+ key: "ytd",
132
+ label: "YTD",
133
+ count: ytdCount,
134
+ prevCount: prevYtdCount,
135
+ pctChange: pctOf(ytdCount, prevYtdCount)
136
+ });
137
+ const ytdMonthly = [];
138
+ const year = now.getFullYear();
139
+ for (let m = 0; m <= now.getMonth(); m++) {
140
+ const monthStart = new Date(year, m, 1).getTime();
141
+ const monthEnd = new Date(year, m + 1, 1).getTime();
142
+ ytdMonthly.push({ label: MONTHS[m], count: countBetween(monthStart, monthEnd) });
143
+ }
144
+ return { total, windows, ytdMonthly };
145
+ }
146
+
73
147
  exports.DEFAULT_ANNOUNCE_EVENT = DEFAULT_ANNOUNCE_EVENT;
74
148
  exports.DEFAULT_SCROLL_RESTORE_PREFIX = DEFAULT_SCROLL_RESTORE_PREFIX;
75
149
  exports.announce = announce;
76
150
  exports.buildScrollRestoreKey = buildScrollRestoreKey;
77
151
  exports.cn = cn;
152
+ exports.computeTrendStats = computeTrendStats;
78
153
  exports.hasUrlParam = hasUrlParam;
79
154
  exports.loadScrollPos = loadScrollPos;
80
155
  exports.readRememberedState = readRememberedState;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/utils.ts","../src/lib/remembered_state.ts","../src/lib/announce.ts","../src/lib/scroll_restore.ts"],"names":["twMerge","clsx"],"mappings":";;;;;AAWO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAOA,qBAAA,CAAQC,SAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;;;ACIO,SAAS,oBAAuB,GAAA,EAAuB;AAC5D,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAC1C,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AAC3C,IAAA,OAAO,GAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,GAAU,IAAA;AAAA,EACxC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAaO,SAAS,oBAAA,CAAwB,KAAa,QAAA,EAAmB;AACtE,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,aAAa,OAAA,CAAQ,GAAA,EAAK,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,EAC3D,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAeO,SAAS,WAAA,CAAY,QAAgB,SAAA,EAA4B;AACtE,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,eAAA,CAAgB,MAAM,CAAA,CAAE,IAAI,SAAS,CAAA;AAAA,EAClD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;;;ACtCO,IAAM,sBAAA,GAAyB;AAuB/B,SAAS,QAAA,CACd,OAAA,EACA,QAAA,GAA6B,QAAA,EAC7B,OAAA,EACM;AACN,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,EAAA,MAAM,OAAA,GAAU,QAAQ,IAAA,EAAK;AAC7B,EAAA,IAAI,CAAC,OAAA,EAAS;AACd,EAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,sBAAA;AACxC,EAAA,MAAA,CAAO,aAAA;AAAA,IACL,IAAI,YAA8B,SAAA,EAAW;AAAA,MAC3C,MAAA,EAAQ,EAAE,OAAA,EAAS,OAAA,EAAS,QAAA;AAAS,KACtC;AAAA,GACH;AACF;;;ACrDO,IAAM,6BAAA,GAAgC;AAStC,SAAS,qBAAA,CAAsB,MAAA,EAAgB,MAAA,EAAgB,QAAA,EAA0B;AAC9F,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAM,IAAI,QAAQ,CAAA,CAAA;AACxC;AAUO,SAAS,aAAA,CAAc,KAAa,OAAA,EAAuB;AAChE,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,YAAA,CAAa,QAAQ,GAAA,EAAK,MAAA,CAAO,KAAK,KAAA,CAAM,OAAO,CAAC,CAAC,CAAA;AAAA,EAC9D,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AASO,SAAS,cAAc,GAAA,EAA4B;AACxD,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,IAAA;AAC1C,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AAC3C,IAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,IAAA,MAAM,CAAA,GAAI,MAAA,CAAO,QAAA,CAAS,GAAA,EAAK,EAAE,CAAA;AACjC,IAAA,OAAO,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,GAAI,CAAA,GAAI,IAAA;AAAA,EAClC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF","file":"index.utils.cjs","sourcesContent":["// Utility functions for hazo_ui component library\n// Provides className merging utility (cn function)\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merges class names using clsx and tailwind-merge\n * @param inputs - Class values to merge\n * @returns Merged class string\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Sanitizes a user/admin-supplied href against a scheme allowlist to prevent\n * `javascript:`/`data:`/`vbscript:` URI XSS when the value is rendered into an\n * `<a href>`. Allows http(s), mailto, and same-origin absolute paths (`/…` but\n * not protocol-relative `//…`). Returns `undefined` for anything else, so the\n * anchor renders with no href rather than an active malicious one.\n * @param url - Candidate href (may be undefined)\n * @returns The original url if allowed, otherwise undefined\n */\nexport function safeHref(url?: string): string | undefined {\n if (!url) return undefined;\n const trimmed = url.trim();\n const lower = trimmed.toLowerCase();\n if (\n lower.startsWith(\"http://\") ||\n lower.startsWith(\"https://\") ||\n lower.startsWith(\"mailto:\")\n ) {\n return trimmed;\n }\n // Same-origin absolute path, but not protocol-relative \"//host\".\n if (trimmed.startsWith(\"/\") && !trimmed.startsWith(\"//\")) {\n return trimmed;\n }\n return undefined;\n}\n\n","// remembered_state.ts — SSR-safe localStorage read/write/URL-param helpers\n// backing `useRememberedState` (src/hooks/use_remembered_state.ts). Pure,\n// framework-free functions (no React) so they're independently testable and\n// usable outside the hook. No \"use client\" directive here — this module is\n// re-exported from both the main client bundle (`hazo_ui`) and the pure\n// server-safe subpath (`hazo_ui/utils`), same dual-export pattern as `cn`.\n\n/**\n * Reads and JSON-parses the remembered value stored under `key`. SSR-safe —\n * returns `null` on the server, when nothing is stored, or when the stored\n * value is corrupt/unparsable.\n *\n * @param key - localStorage key to read.\n *\n * @example\n * const seed = readRememberedState<MySeed>(\"myapp:tool:cgt\");\n */\nexport function readRememberedState<T>(key: string): T | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(key);\n return raw ? (JSON.parse(raw) as T) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * JSON-stringifies and writes `snapshot` under `key`. SSR-safe — no-ops on\n * the server. Quota / private-mode errors are swallowed; losing a memory\n * write is non-fatal.\n *\n * @param key - localStorage key to write.\n * @param snapshot - Serialisable value to remember.\n *\n * @example\n * writeRememberedState(\"myapp:tool:cgt\", { proceeds: 1000 });\n */\nexport function writeRememberedState<T>(key: string, snapshot: T): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(key, JSON.stringify(snapshot));\n } catch {\n /* quota / private-mode — non-fatal */\n }\n}\n\n/**\n * True when `paramName` is present in the given search string (e.g.\n * `window.location.search`). Generic form of the \"an explicit shared-link /\n * saved-record query param always wins over remembered state\" precedence\n * check — callers supply the param name (e.g. `\"restore\"`); this module\n * never hardcodes one.\n *\n * @param search - A URL search string, e.g. `window.location.search`.\n * @param paramName - The query param to look for.\n *\n * @example\n * hasUrlParam(\"?restore=abc123\", \"restore\"); // true\n */\nexport function hasUrlParam(search: string, paramName: string): boolean {\n try {\n return new URLSearchParams(search).has(paramName);\n } catch {\n return false;\n }\n}\n","// announce.ts — SSR-safe screen-reader announcement bus. Dispatches a\n// `window` CustomEvent that `LiveRegion` (../components/live_region/)\n// listens for. Pure, framework-free (no React) so it's independently\n// testable and usable outside a component. No \"use client\" directive here\n// — this module is re-exported from both the main client bundle\n// (`hazo_ui`) and the pure server-safe subpath (`hazo_ui/utils`), same\n// dual-export pattern as `cn` and the `remembered_state` helpers.\n//\n// Ported from Kinstripe's `src/lib/a11y/announce.ts`, which hardcoded the\n// event name to `\"kinstripe:announce\"`. Here the event name is caller-\n// configurable (`options.eventName`) so multiple apps — or multiple\n// `LiveRegion` instances on the same page — don't collide on a single\n// hardcoded channel; it defaults to `DEFAULT_ANNOUNCE_EVENT` for\n// single-app usage.\n\nexport type AnnouncePriority = \"polite\" | \"assertive\";\n\nexport interface LiveAnnouncement {\n message: string;\n priority: AnnouncePriority;\n}\n\nexport interface AnnounceOptions {\n /** Custom-event name the paired `LiveRegion` listens on. Must match the `eventName` it was mounted with. Default `DEFAULT_ANNOUNCE_EVENT`. */\n eventName?: string;\n}\n\n/** Default `window` CustomEvent name used when `announce()` / `LiveRegion` are not given an explicit `eventName`. */\nexport const DEFAULT_ANNOUNCE_EVENT = \"hazo_ui:announce\";\n\n/**\n * Dispatch a screen-reader announcement via a `window` CustomEvent. Safe to\n * call from anywhere in the client tree — no-ops during SSR or before a\n * `LiveRegion` has mounted (fire-and-forget; there's no queue/replay).\n *\n * Use `\"polite\"` (default) for ambient updates (\"Sarah joined the canvas\",\n * \"2 new notifications\"). Use `\"assertive\"` only for things the user must\n * hear immediately (errors that interrupt a task).\n *\n * @param message - Text to announce. Empty / whitespace-only messages are dropped (no dispatch).\n * @param priority - `\"polite\"` (default) or `\"assertive\"`.\n * @param options.eventName - Custom-event name to dispatch on. Default `DEFAULT_ANNOUNCE_EVENT`.\n *\n * @example\n * announce(\"2 new notifications\");\n * announce(\"Save failed — check your connection\", \"assertive\");\n *\n * @example\n * // namespaced channel — must match the eventName the LiveRegion was mounted with\n * announce(\"Saved\", \"polite\", { eventName: \"myapp:announce\" });\n */\nexport function announce(\n message: string,\n priority: AnnouncePriority = \"polite\",\n options?: AnnounceOptions,\n): void {\n if (typeof window === \"undefined\") return;\n const trimmed = message.trim();\n if (!trimmed) return;\n const eventName = options?.eventName ?? DEFAULT_ANNOUNCE_EVENT;\n window.dispatchEvent(\n new CustomEvent<LiveAnnouncement>(eventName, {\n detail: { message: trimmed, priority },\n }),\n );\n}\n","// scroll_restore.ts — SSR-safe localStorage read/write helpers backing\n// `useScrollRestore` (../hooks/use_scroll_restore.ts). Pure, framework-free\n// functions (no React) so they're independently testable and usable\n// outside the hook — same split as `remembered_state.ts` /\n// `useRememberedState`. No \"use client\" directive here.\n//\n// Ported from Kinstripe's `src/lib/hooks/useScrollRestore.ts`, which\n// hardcoded the key prefix to `\"kinstripe.scrollPos\"`. Here the prefix is a\n// parameter (`buildScrollRestoreKey`) / hook option, so the package stays\n// app-agnostic.\n\n/** Default localStorage key prefix used when no `prefix` option is given. */\nexport const DEFAULT_SCROLL_RESTORE_PREFIX = \"hazo_ui:scrollPos\";\n\n/**\n * Composes the localStorage key from a prefix, tree id, and view name.\n *\n * @example\n * buildScrollRestoreKey(\"hazo_ui:scrollPos\", \"tree-42\", \"canvas\");\n * // -> \"hazo_ui:scrollPos.tree-42.canvas\"\n */\nexport function buildScrollRestoreKey(prefix: string, treeId: string, viewName: string): string {\n return `${prefix}.${treeId}.${viewName}`;\n}\n\n/**\n * Persists a scroll position (rounded to the nearest pixel) under `key`.\n * SSR-safe — no-ops on the server. Quota / private-mode errors are\n * swallowed; a failed write is non-fatal.\n *\n * @param key - localStorage key (see `buildScrollRestoreKey`).\n * @param scrollY - Scroll offset in pixels.\n */\nexport function saveScrollPos(key: string, scrollY: number): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(key, String(Math.round(scrollY)));\n } catch {\n /* quota exceeded — silently drop */\n }\n}\n\n/**\n * Reads back the scroll position stored under `key`. SSR-safe — returns\n * `null` on the server, when nothing is stored, or when the stored value\n * isn't a finite number.\n *\n * @param key - localStorage key (see `buildScrollRestoreKey`).\n */\nexport function loadScrollPos(key: string): number | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) return null;\n const n = Number.parseInt(raw, 10);\n return Number.isFinite(n) ? n : null;\n } catch {\n return null;\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/lib/remembered_state.ts","../src/lib/announce.ts","../src/lib/scroll_restore.ts","../src/lib/trend_stats.ts"],"names":["twMerge","clsx"],"mappings":"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","file":"index.utils.cjs","sourcesContent":["// Utility functions for hazo_ui component library\n// Provides className merging utility (cn function)\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merges class names using clsx and tailwind-merge\n * @param inputs - Class values to merge\n * @returns Merged class string\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * Sanitizes a user/admin-supplied href against a scheme allowlist to prevent\n * `javascript:`/`data:`/`vbscript:` URI XSS when the value is rendered into an\n * `<a href>`. Allows http(s), mailto, and same-origin absolute paths (`/…` but\n * not protocol-relative `//…`). Returns `undefined` for anything else, so the\n * anchor renders with no href rather than an active malicious one.\n * @param url - Candidate href (may be undefined)\n * @returns The original url if allowed, otherwise undefined\n */\nexport function safeHref(url?: string): string | undefined {\n if (!url) return undefined;\n const trimmed = url.trim();\n const lower = trimmed.toLowerCase();\n if (\n lower.startsWith(\"http://\") ||\n lower.startsWith(\"https://\") ||\n lower.startsWith(\"mailto:\")\n ) {\n return trimmed;\n }\n // Same-origin absolute path, but not protocol-relative \"//host\".\n if (trimmed.startsWith(\"/\") && !trimmed.startsWith(\"//\")) {\n return trimmed;\n }\n return undefined;\n}\n\n","// remembered_state.ts — SSR-safe localStorage read/write/URL-param helpers\n// backing `useRememberedState` (src/hooks/use_remembered_state.ts). Pure,\n// framework-free functions (no React) so they're independently testable and\n// usable outside the hook. No \"use client\" directive here — this module is\n// re-exported from both the main client bundle (`hazo_ui`) and the pure\n// server-safe subpath (`hazo_ui/utils`), same dual-export pattern as `cn`.\n\n/**\n * Reads and JSON-parses the remembered value stored under `key`. SSR-safe —\n * returns `null` on the server, when nothing is stored, or when the stored\n * value is corrupt/unparsable.\n *\n * @param key - localStorage key to read.\n *\n * @example\n * const seed = readRememberedState<MySeed>(\"myapp:tool:cgt\");\n */\nexport function readRememberedState<T>(key: string): T | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(key);\n return raw ? (JSON.parse(raw) as T) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * JSON-stringifies and writes `snapshot` under `key`. SSR-safe — no-ops on\n * the server. Quota / private-mode errors are swallowed; losing a memory\n * write is non-fatal.\n *\n * @param key - localStorage key to write.\n * @param snapshot - Serialisable value to remember.\n *\n * @example\n * writeRememberedState(\"myapp:tool:cgt\", { proceeds: 1000 });\n */\nexport function writeRememberedState<T>(key: string, snapshot: T): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(key, JSON.stringify(snapshot));\n } catch {\n /* quota / private-mode — non-fatal */\n }\n}\n\n/**\n * True when `paramName` is present in the given search string (e.g.\n * `window.location.search`). Generic form of the \"an explicit shared-link /\n * saved-record query param always wins over remembered state\" precedence\n * check — callers supply the param name (e.g. `\"restore\"`); this module\n * never hardcodes one.\n *\n * @param search - A URL search string, e.g. `window.location.search`.\n * @param paramName - The query param to look for.\n *\n * @example\n * hasUrlParam(\"?restore=abc123\", \"restore\"); // true\n */\nexport function hasUrlParam(search: string, paramName: string): boolean {\n try {\n return new URLSearchParams(search).has(paramName);\n } catch {\n return false;\n }\n}\n","// announce.ts — SSR-safe screen-reader announcement bus. Dispatches a\n// `window` CustomEvent that `LiveRegion` (../components/live_region/)\n// listens for. Pure, framework-free (no React) so it's independently\n// testable and usable outside a component. No \"use client\" directive here\n// — this module is re-exported from both the main client bundle\n// (`hazo_ui`) and the pure server-safe subpath (`hazo_ui/utils`), same\n// dual-export pattern as `cn` and the `remembered_state` helpers.\n//\n// Ported from Kinstripe's `src/lib/a11y/announce.ts`, which hardcoded the\n// event name to `\"kinstripe:announce\"`. Here the event name is caller-\n// configurable (`options.eventName`) so multiple apps — or multiple\n// `LiveRegion` instances on the same page — don't collide on a single\n// hardcoded channel; it defaults to `DEFAULT_ANNOUNCE_EVENT` for\n// single-app usage.\n\nexport type AnnouncePriority = \"polite\" | \"assertive\";\n\nexport interface LiveAnnouncement {\n message: string;\n priority: AnnouncePriority;\n}\n\nexport interface AnnounceOptions {\n /** Custom-event name the paired `LiveRegion` listens on. Must match the `eventName` it was mounted with. Default `DEFAULT_ANNOUNCE_EVENT`. */\n eventName?: string;\n}\n\n/** Default `window` CustomEvent name used when `announce()` / `LiveRegion` are not given an explicit `eventName`. */\nexport const DEFAULT_ANNOUNCE_EVENT = \"hazo_ui:announce\";\n\n/**\n * Dispatch a screen-reader announcement via a `window` CustomEvent. Safe to\n * call from anywhere in the client tree — no-ops during SSR or before a\n * `LiveRegion` has mounted (fire-and-forget; there's no queue/replay).\n *\n * Use `\"polite\"` (default) for ambient updates (\"Sarah joined the canvas\",\n * \"2 new notifications\"). Use `\"assertive\"` only for things the user must\n * hear immediately (errors that interrupt a task).\n *\n * @param message - Text to announce. Empty / whitespace-only messages are dropped (no dispatch).\n * @param priority - `\"polite\"` (default) or `\"assertive\"`.\n * @param options.eventName - Custom-event name to dispatch on. Default `DEFAULT_ANNOUNCE_EVENT`.\n *\n * @example\n * announce(\"2 new notifications\");\n * announce(\"Save failed — check your connection\", \"assertive\");\n *\n * @example\n * // namespaced channel — must match the eventName the LiveRegion was mounted with\n * announce(\"Saved\", \"polite\", { eventName: \"myapp:announce\" });\n */\nexport function announce(\n message: string,\n priority: AnnouncePriority = \"polite\",\n options?: AnnounceOptions,\n): void {\n if (typeof window === \"undefined\") return;\n const trimmed = message.trim();\n if (!trimmed) return;\n const eventName = options?.eventName ?? DEFAULT_ANNOUNCE_EVENT;\n window.dispatchEvent(\n new CustomEvent<LiveAnnouncement>(eventName, {\n detail: { message: trimmed, priority },\n }),\n );\n}\n","// scroll_restore.ts — SSR-safe localStorage read/write helpers backing\n// `useScrollRestore` (../hooks/use_scroll_restore.ts). Pure, framework-free\n// functions (no React) so they're independently testable and usable\n// outside the hook — same split as `remembered_state.ts` /\n// `useRememberedState`. No \"use client\" directive here.\n//\n// Ported from Kinstripe's `src/lib/hooks/useScrollRestore.ts`, which\n// hardcoded the key prefix to `\"kinstripe.scrollPos\"`. Here the prefix is a\n// parameter (`buildScrollRestoreKey`) / hook option, so the package stays\n// app-agnostic.\n\n/** Default localStorage key prefix used when no `prefix` option is given. */\nexport const DEFAULT_SCROLL_RESTORE_PREFIX = \"hazo_ui:scrollPos\";\n\n/**\n * Composes the localStorage key from a prefix, tree id, and view name.\n *\n * @example\n * buildScrollRestoreKey(\"hazo_ui:scrollPos\", \"tree-42\", \"canvas\");\n * // -> \"hazo_ui:scrollPos.tree-42.canvas\"\n */\nexport function buildScrollRestoreKey(prefix: string, treeId: string, viewName: string): string {\n return `${prefix}.${treeId}.${viewName}`;\n}\n\n/**\n * Persists a scroll position (rounded to the nearest pixel) under `key`.\n * SSR-safe — no-ops on the server. Quota / private-mode errors are\n * swallowed; a failed write is non-fatal.\n *\n * @param key - localStorage key (see `buildScrollRestoreKey`).\n * @param scrollY - Scroll offset in pixels.\n */\nexport function saveScrollPos(key: string, scrollY: number): void {\n if (typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(key, String(Math.round(scrollY)));\n } catch {\n /* quota exceeded — silently drop */\n }\n}\n\n/**\n * Reads back the scroll position stored under `key`. SSR-safe — returns\n * `null` on the server, when nothing is stored, or when the stored value\n * isn't a finite number.\n *\n * @param key - localStorage key (see `buildScrollRestoreKey`).\n */\nexport function loadScrollPos(key: string): number | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(key);\n if (!raw) return null;\n const n = Number.parseInt(raw, 10);\n return Number.isFinite(n) ? n : null;\n } catch {\n return null;\n }\n}\n","// file_description: Pure, dependency-free helpers to compute trend stats\n// (rolling-window counts + % change vs the prior equal period, plus a YTD\n// monthly series) from a list of timestamped records. Client-safe.\n\nexport interface TrendWindow {\n /** stable key: 'all' | '7d' | '30d' | '90d' | '180d' | 'ytd' */\n key: string;\n /** short display label for the card */\n label: string;\n /** items within the window ('all' = total count) */\n count: number;\n /** items in the immediately-preceding equal-length period; null for 'all' */\n prevCount: number | null;\n /** rounded % change vs prevCount; null when prevCount is null or 0 */\n pctChange: number | null;\n}\n\nexport interface TrendChartPoint {\n /** short label, e.g. 'Jan' */\n label: string;\n /** items in that period */\n count: number;\n}\n\nexport interface TrendStats {\n total: number;\n windows: TrendWindow[];\n ytdMonthly: TrendChartPoint[];\n}\n\nexport interface TrendStatsOptions {\n /** Label for the \"all time\" card. Default: \"All time\". */\n totalLabel?: string;\n /** Custom rolling windows. Default: 7d/30d/90d/180d. */\n windows?: ReadonlyArray<{ key: string; label: string; days: number }>;\n}\n\nconst DAY_MS = 86_400_000;\nconst MONTHS = [\n \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\",\n];\n\nfunction pctOf(count: number, prev: number | null): number | null {\n if (prev === null || prev === 0) return null;\n return Math.round(((count - prev) / prev) * 100);\n}\n\nconst DEFAULT_WINDOWS: ReadonlyArray<{ key: string; label: string; days: number }> = [\n { key: \"7d\", label: \"7 days\", days: 7 },\n { key: \"30d\", label: \"30 days\", days: 30 },\n { key: \"90d\", label: \"3 months\", days: 90 },\n { key: \"180d\", label: \"6 months\", days: 180 },\n];\n\n/**\n * Compute trend stats from timestamped records.\n *\n * Rolling windows (7/30/90/180 days) compare against the immediately-preceding\n * equal-length period. YTD compares against the prior year's same-length\n * period. Rows with missing/invalid timestamps are excluded from all counts.\n */\nexport function computeTrendStats(\n items: ReadonlyArray<{ created_at?: string | null }>,\n now: Date = new Date(),\n options?: TrendStatsOptions,\n): TrendStats {\n const nowMs = now.getTime();\n\n const times: number[] = [];\n for (const item of items) {\n if (!item || !item.created_at) continue;\n const t = new Date(item.created_at).getTime();\n if (!Number.isNaN(t)) times.push(t);\n }\n\n const countBetween = (startMs: number, endMs: number): number =>\n times.reduce((n, t) => (t >= startMs && t < endMs ? n + 1 : n), 0);\n\n const total = times.length;\n const rollingDefs = options?.windows ?? DEFAULT_WINDOWS;\n\n const windows: TrendWindow[] = [\n { key: \"all\", label: options?.totalLabel ?? \"All time\", count: total, prevCount: null, pctChange: null },\n ];\n\n for (const w of rollingDefs) {\n const span = w.days * DAY_MS;\n const count = countBetween(nowMs - span, nowMs);\n const prevCount = countBetween(nowMs - 2 * span, nowMs - span);\n windows.push({\n key: w.key,\n label: w.label,\n count,\n prevCount,\n pctChange: pctOf(count, prevCount),\n });\n }\n\n const ytdStart = new Date(now.getFullYear(), 0, 1).getTime();\n const elapsed = nowMs - ytdStart;\n const ytdCount = countBetween(ytdStart, nowMs);\n const prevYtdStart = new Date(now.getFullYear() - 1, 0, 1).getTime();\n const prevYtdCount = countBetween(prevYtdStart, prevYtdStart + elapsed);\n windows.push({\n key: \"ytd\",\n label: \"YTD\",\n count: ytdCount,\n prevCount: prevYtdCount,\n pctChange: pctOf(ytdCount, prevYtdCount),\n });\n\n const ytdMonthly: TrendChartPoint[] = [];\n const year = now.getFullYear();\n for (let m = 0; m <= now.getMonth(); m++) {\n const monthStart = new Date(year, m, 1).getTime();\n const monthEnd = new Date(year, m + 1, 1).getTime();\n ytdMonthly.push({ label: MONTHS[m], count: countBetween(monthStart, monthEnd) });\n }\n\n return { total, windows, ytdMonthly };\n}\n"]}
@@ -1,4 +1,4 @@
1
- export { A as AnnounceOptions, a as AnnouncePriority, D as DEFAULT_ANNOUNCE_EVENT, L as LiveAnnouncement, b as announce, c as cn, h as hasUrlParam, r as readRememberedState, w as writeRememberedState } from './announce-DAnQDTld.cjs';
1
+ export { A as AnnounceOptions, a as AnnouncePriority, D as DEFAULT_ANNOUNCE_EVENT, L as LiveAnnouncement, T as TrendChartPoint, b as TrendStats, c as TrendStatsOptions, d as TrendWindow, e as announce, f as cn, g as computeTrendStats, h as hasUrlParam, r as readRememberedState, w as writeRememberedState } from './trend_stats-BAatnIt-.cjs';
2
2
  import 'clsx';
3
3
 
4
4
  /** Default localStorage key prefix used when no `prefix` option is given. */
@@ -1,4 +1,4 @@
1
- export { A as AnnounceOptions, a as AnnouncePriority, D as DEFAULT_ANNOUNCE_EVENT, L as LiveAnnouncement, b as announce, c as cn, h as hasUrlParam, r as readRememberedState, w as writeRememberedState } from './announce-DAnQDTld.js';
1
+ export { A as AnnounceOptions, a as AnnouncePriority, D as DEFAULT_ANNOUNCE_EVENT, L as LiveAnnouncement, T as TrendChartPoint, b as TrendStats, c as TrendStatsOptions, d as TrendWindow, e as announce, f as cn, g as computeTrendStats, h as hasUrlParam, r as readRememberedState, w as writeRememberedState } from './trend_stats-BAatnIt-.js';
2
2
  import 'clsx';
3
3
 
4
4
  /** Default localStorage key prefix used when no `prefix` option is given. */
@@ -68,6 +68,80 @@ function loadScrollPos(key) {
68
68
  }
69
69
  }
70
70
 
71
- export { DEFAULT_ANNOUNCE_EVENT, DEFAULT_SCROLL_RESTORE_PREFIX, announce, buildScrollRestoreKey, cn, hasUrlParam, loadScrollPos, readRememberedState, saveScrollPos, writeRememberedState };
71
+ // src/lib/trend_stats.ts
72
+ var DAY_MS = 864e5;
73
+ var MONTHS = [
74
+ "Jan",
75
+ "Feb",
76
+ "Mar",
77
+ "Apr",
78
+ "May",
79
+ "Jun",
80
+ "Jul",
81
+ "Aug",
82
+ "Sep",
83
+ "Oct",
84
+ "Nov",
85
+ "Dec"
86
+ ];
87
+ function pctOf(count, prev) {
88
+ if (prev === null || prev === 0) return null;
89
+ return Math.round((count - prev) / prev * 100);
90
+ }
91
+ var DEFAULT_WINDOWS = [
92
+ { key: "7d", label: "7 days", days: 7 },
93
+ { key: "30d", label: "30 days", days: 30 },
94
+ { key: "90d", label: "3 months", days: 90 },
95
+ { key: "180d", label: "6 months", days: 180 }
96
+ ];
97
+ function computeTrendStats(items, now = /* @__PURE__ */ new Date(), options) {
98
+ const nowMs = now.getTime();
99
+ const times = [];
100
+ for (const item of items) {
101
+ if (!item || !item.created_at) continue;
102
+ const t = new Date(item.created_at).getTime();
103
+ if (!Number.isNaN(t)) times.push(t);
104
+ }
105
+ const countBetween = (startMs, endMs) => times.reduce((n, t) => t >= startMs && t < endMs ? n + 1 : n, 0);
106
+ const total = times.length;
107
+ const rollingDefs = options?.windows ?? DEFAULT_WINDOWS;
108
+ const windows = [
109
+ { key: "all", label: options?.totalLabel ?? "All time", count: total, prevCount: null, pctChange: null }
110
+ ];
111
+ for (const w of rollingDefs) {
112
+ const span = w.days * DAY_MS;
113
+ const count = countBetween(nowMs - span, nowMs);
114
+ const prevCount = countBetween(nowMs - 2 * span, nowMs - span);
115
+ windows.push({
116
+ key: w.key,
117
+ label: w.label,
118
+ count,
119
+ prevCount,
120
+ pctChange: pctOf(count, prevCount)
121
+ });
122
+ }
123
+ const ytdStart = new Date(now.getFullYear(), 0, 1).getTime();
124
+ const elapsed = nowMs - ytdStart;
125
+ const ytdCount = countBetween(ytdStart, nowMs);
126
+ const prevYtdStart = new Date(now.getFullYear() - 1, 0, 1).getTime();
127
+ const prevYtdCount = countBetween(prevYtdStart, prevYtdStart + elapsed);
128
+ windows.push({
129
+ key: "ytd",
130
+ label: "YTD",
131
+ count: ytdCount,
132
+ prevCount: prevYtdCount,
133
+ pctChange: pctOf(ytdCount, prevYtdCount)
134
+ });
135
+ const ytdMonthly = [];
136
+ const year = now.getFullYear();
137
+ for (let m = 0; m <= now.getMonth(); m++) {
138
+ const monthStart = new Date(year, m, 1).getTime();
139
+ const monthEnd = new Date(year, m + 1, 1).getTime();
140
+ ytdMonthly.push({ label: MONTHS[m], count: countBetween(monthStart, monthEnd) });
141
+ }
142
+ return { total, windows, ytdMonthly };
143
+ }
144
+
145
+ export { DEFAULT_ANNOUNCE_EVENT, DEFAULT_SCROLL_RESTORE_PREFIX, announce, buildScrollRestoreKey, cn, computeTrendStats, hasUrlParam, loadScrollPos, readRememberedState, saveScrollPos, writeRememberedState };
72
146
  //# sourceMappingURL=index.utils.js.map
73
147
  //# sourceMappingURL=index.utils.js.map