hazo_ui 6.9.0 → 6.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGE_LOG.md +146 -0
- package/dist/index.cjs +451 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -3
- package/dist/index.d.ts +44 -3
- package/dist/index.js +453 -96
- package/dist/index.js.map +1 -1
- package/dist/index.locale-picker.cjs +348 -0
- package/dist/index.locale-picker.cjs.map +1 -0
- package/dist/index.locale-picker.d.cts +52 -0
- package/dist/index.locale-picker.d.ts +52 -0
- package/dist/index.locale-picker.js +325 -0
- package/dist/index.locale-picker.js.map +1 -0
- package/package.json +26 -6
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
|
|
6
|
+
var lucideReact = require('lucide-react');
|
|
7
|
+
var clsx = require('clsx');
|
|
8
|
+
var tailwindMerge = require('tailwind-merge');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
var reactSlot = require('@radix-ui/react-slot');
|
|
11
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
12
|
+
|
|
13
|
+
function _interopNamespace(e) {
|
|
14
|
+
if (e && e.__esModule) return e;
|
|
15
|
+
var n = Object.create(null);
|
|
16
|
+
if (e) {
|
|
17
|
+
Object.keys(e).forEach(function (k) {
|
|
18
|
+
if (k !== 'default') {
|
|
19
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
20
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return e[k]; }
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
n.default = e;
|
|
28
|
+
return Object.freeze(n);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
32
|
+
var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMenuPrimitive);
|
|
33
|
+
|
|
34
|
+
function cn(...inputs) {
|
|
35
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
36
|
+
}
|
|
37
|
+
function safeHref(url) {
|
|
38
|
+
if (!url) return void 0;
|
|
39
|
+
const trimmed = url.trim();
|
|
40
|
+
const lower = trimmed.toLowerCase();
|
|
41
|
+
if (lower.startsWith("http://") || lower.startsWith("https://") || lower.startsWith("mailto:")) {
|
|
42
|
+
return trimmed;
|
|
43
|
+
}
|
|
44
|
+
if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
|
|
45
|
+
return trimmed;
|
|
46
|
+
}
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
var DropdownMenu = DropdownMenuPrimitive__namespace.Root;
|
|
50
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive__namespace.Trigger;
|
|
51
|
+
var DropdownMenuRadioGroup = DropdownMenuPrimitive__namespace.RadioGroup;
|
|
52
|
+
var DropdownMenuSubTrigger = React__namespace.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
53
|
+
DropdownMenuPrimitive__namespace.SubTrigger,
|
|
54
|
+
{
|
|
55
|
+
ref,
|
|
56
|
+
className: cn(
|
|
57
|
+
"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",
|
|
58
|
+
inset && "pl-8",
|
|
59
|
+
className
|
|
60
|
+
),
|
|
61
|
+
...props,
|
|
62
|
+
children: [
|
|
63
|
+
children,
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "ml-auto h-4 w-4" })
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
));
|
|
68
|
+
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive__namespace.SubTrigger.displayName;
|
|
69
|
+
var DropdownMenuSubContent = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
70
|
+
DropdownMenuPrimitive__namespace.SubContent,
|
|
71
|
+
{
|
|
72
|
+
ref,
|
|
73
|
+
className: cn(
|
|
74
|
+
"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",
|
|
75
|
+
className
|
|
76
|
+
),
|
|
77
|
+
...props
|
|
78
|
+
}
|
|
79
|
+
));
|
|
80
|
+
DropdownMenuSubContent.displayName = DropdownMenuPrimitive__namespace.SubContent.displayName;
|
|
81
|
+
var DropdownMenuContent = React__namespace.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
82
|
+
DropdownMenuPrimitive__namespace.Content,
|
|
83
|
+
{
|
|
84
|
+
ref,
|
|
85
|
+
sideOffset,
|
|
86
|
+
className: cn(
|
|
87
|
+
"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",
|
|
88
|
+
className
|
|
89
|
+
),
|
|
90
|
+
...props
|
|
91
|
+
}
|
|
92
|
+
) }));
|
|
93
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive__namespace.Content.displayName;
|
|
94
|
+
var DropdownMenuItem = React__namespace.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
95
|
+
DropdownMenuPrimitive__namespace.Item,
|
|
96
|
+
{
|
|
97
|
+
ref,
|
|
98
|
+
className: cn(
|
|
99
|
+
"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",
|
|
100
|
+
inset && "pl-8",
|
|
101
|
+
className
|
|
102
|
+
),
|
|
103
|
+
...props
|
|
104
|
+
}
|
|
105
|
+
));
|
|
106
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive__namespace.Item.displayName;
|
|
107
|
+
var DropdownMenuCheckboxItem = React__namespace.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
108
|
+
DropdownMenuPrimitive__namespace.CheckboxItem,
|
|
109
|
+
{
|
|
110
|
+
ref,
|
|
111
|
+
className: cn(
|
|
112
|
+
"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",
|
|
113
|
+
className
|
|
114
|
+
),
|
|
115
|
+
checked,
|
|
116
|
+
...props,
|
|
117
|
+
children: [
|
|
118
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }) }) }),
|
|
119
|
+
children
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
));
|
|
123
|
+
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive__namespace.CheckboxItem.displayName;
|
|
124
|
+
var DropdownMenuRadioItem = React__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
125
|
+
DropdownMenuPrimitive__namespace.RadioItem,
|
|
126
|
+
{
|
|
127
|
+
ref,
|
|
128
|
+
className: cn(
|
|
129
|
+
"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",
|
|
130
|
+
className
|
|
131
|
+
),
|
|
132
|
+
...props,
|
|
133
|
+
children: [
|
|
134
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: "h-2 w-2 fill-current" }) }) }),
|
|
135
|
+
children
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
));
|
|
139
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive__namespace.RadioItem.displayName;
|
|
140
|
+
var DropdownMenuLabel = React__namespace.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
141
|
+
DropdownMenuPrimitive__namespace.Label,
|
|
142
|
+
{
|
|
143
|
+
ref,
|
|
144
|
+
className: cn(
|
|
145
|
+
"px-2 py-1.5 text-sm font-semibold",
|
|
146
|
+
inset && "pl-8",
|
|
147
|
+
className
|
|
148
|
+
),
|
|
149
|
+
...props
|
|
150
|
+
}
|
|
151
|
+
));
|
|
152
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive__namespace.Label.displayName;
|
|
153
|
+
var DropdownMenuSeparator = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
154
|
+
DropdownMenuPrimitive__namespace.Separator,
|
|
155
|
+
{
|
|
156
|
+
ref,
|
|
157
|
+
className: cn("-mx-1 my-1 h-px bg-muted", className),
|
|
158
|
+
...props
|
|
159
|
+
}
|
|
160
|
+
));
|
|
161
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive__namespace.Separator.displayName;
|
|
162
|
+
var buttonVariants = classVarianceAuthority.cva(
|
|
163
|
+
"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",
|
|
164
|
+
{
|
|
165
|
+
variants: {
|
|
166
|
+
variant: {
|
|
167
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
168
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
169
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
170
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
171
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
172
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
173
|
+
},
|
|
174
|
+
size: {
|
|
175
|
+
default: "h-10 px-4 py-2",
|
|
176
|
+
sm: "h-9 rounded-md px-3",
|
|
177
|
+
lg: "h-11 rounded-md px-8",
|
|
178
|
+
icon: "h-10 w-10"
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
defaultVariants: {
|
|
182
|
+
variant: "default",
|
|
183
|
+
size: "default"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
var Button = React__namespace.forwardRef(
|
|
188
|
+
({ className, variant, size, asChild = false, style, ...props }, ref) => {
|
|
189
|
+
const Comp = asChild ? reactSlot.Slot : "button";
|
|
190
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
191
|
+
Comp,
|
|
192
|
+
{
|
|
193
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
194
|
+
style,
|
|
195
|
+
ref,
|
|
196
|
+
...props
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
Button.displayName = "Button";
|
|
202
|
+
var native_name_cache = /* @__PURE__ */ new Map();
|
|
203
|
+
function get_native_name(code) {
|
|
204
|
+
const cached = native_name_cache.get(code);
|
|
205
|
+
if (cached !== void 0) return cached;
|
|
206
|
+
let name = code;
|
|
207
|
+
if (typeof Intl !== "undefined" && "DisplayNames" in Intl) {
|
|
208
|
+
try {
|
|
209
|
+
const display_names = new Intl.DisplayNames([code], {
|
|
210
|
+
type: "language",
|
|
211
|
+
languageDisplay: "standard"
|
|
212
|
+
});
|
|
213
|
+
name = display_names.of(code) ?? code;
|
|
214
|
+
} catch {
|
|
215
|
+
name = code;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
native_name_cache.set(code, name);
|
|
219
|
+
return name;
|
|
220
|
+
}
|
|
221
|
+
function build_label(code, display) {
|
|
222
|
+
if (display === "code") return code.toUpperCase();
|
|
223
|
+
const native = get_native_name(code);
|
|
224
|
+
if (display === "native+code") return `${native} (${code.toUpperCase()})`;
|
|
225
|
+
return native;
|
|
226
|
+
}
|
|
227
|
+
var STRIPE_FLAGS = {
|
|
228
|
+
de: { dir: "h", colors: ["#000000", "#DD0000", "#FFCE00"] },
|
|
229
|
+
fr: { dir: "v", colors: ["#0055A4", "#FFFFFF", "#EF4135"] },
|
|
230
|
+
it: { dir: "v", colors: ["#009246", "#FFFFFF", "#CE2B37"] },
|
|
231
|
+
es: { dir: "h", colors: ["#AA151B", "#F1BF00", "#AA151B"] },
|
|
232
|
+
pt: { dir: "v", colors: ["#046A38", "#FFFFFF", "#DA291C"] },
|
|
233
|
+
nl: { dir: "h", colors: ["#AE1C28", "#FFFFFF", "#21468B"] }
|
|
234
|
+
};
|
|
235
|
+
var NORDIC_CROSS_FLAGS = {
|
|
236
|
+
sv: { bg: "#006AA7", cross: "#FECC00" },
|
|
237
|
+
fi: { bg: "#FFFFFF", cross: "#003580" }
|
|
238
|
+
};
|
|
239
|
+
function StripeFlag({
|
|
240
|
+
dir,
|
|
241
|
+
colors
|
|
242
|
+
}) {
|
|
243
|
+
const band = 12 / colors.length;
|
|
244
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 12", width: "16", height: "12", "aria-hidden": "true", focusable: "false", children: colors.map(
|
|
245
|
+
(color, i) => dir === "h" ? /* @__PURE__ */ jsxRuntime.jsx("rect", { x: 0, y: i * band, width: 16, height: band, fill: color }, i) : /* @__PURE__ */ jsxRuntime.jsx("rect", { x: i * (16 / colors.length), y: 0, width: 16 / colors.length, height: 12, fill: color }, i)
|
|
246
|
+
) });
|
|
247
|
+
}
|
|
248
|
+
function NordicCrossFlag({ bg, cross }) {
|
|
249
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 16 12", width: "16", height: "12", "aria-hidden": "true", focusable: "false", children: [
|
|
250
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "16", height: "12", fill: bg }),
|
|
251
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "5", width: "2", height: "12", fill: cross }),
|
|
252
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { y: "5", width: "16", height: "2", fill: cross })
|
|
253
|
+
] });
|
|
254
|
+
}
|
|
255
|
+
function get_flag_node(code) {
|
|
256
|
+
const lang = code.toLowerCase().split(/[-_]/)[0];
|
|
257
|
+
const cross = NORDIC_CROSS_FLAGS[lang];
|
|
258
|
+
if (cross) return /* @__PURE__ */ jsxRuntime.jsx(NordicCrossFlag, { ...cross });
|
|
259
|
+
const stripes = STRIPE_FLAGS[lang];
|
|
260
|
+
if (stripes) return /* @__PURE__ */ jsxRuntime.jsx(StripeFlag, { ...stripes });
|
|
261
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "h-3 w-3", "aria-hidden": "true" });
|
|
262
|
+
}
|
|
263
|
+
function FlagIcon({ code }) {
|
|
264
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_locale_picker_flag inline-flex h-3.5 w-4 shrink-0 items-center justify-center overflow-hidden rounded-[2px]", children: get_flag_node(code) });
|
|
265
|
+
}
|
|
266
|
+
function LocalePicker({
|
|
267
|
+
variant = "dropdown",
|
|
268
|
+
show = "auto",
|
|
269
|
+
display = "native",
|
|
270
|
+
flags = false,
|
|
271
|
+
alternates,
|
|
272
|
+
activeLocale,
|
|
273
|
+
triggerLabel = "Change language",
|
|
274
|
+
className
|
|
275
|
+
}) {
|
|
276
|
+
const options = React__namespace.useMemo(() => {
|
|
277
|
+
return Object.entries(alternates ?? {}).map(([code, url]) => {
|
|
278
|
+
const href = safeHref(url);
|
|
279
|
+
if (!href) return null;
|
|
280
|
+
return { code, href, label: build_label(code, display) };
|
|
281
|
+
}).filter((o) => o !== null);
|
|
282
|
+
}, [alternates, display]);
|
|
283
|
+
if (show === "never") return null;
|
|
284
|
+
if (options.length === 0) return null;
|
|
285
|
+
if (show === "auto" && options.length < 2) return null;
|
|
286
|
+
if (variant === "inline") {
|
|
287
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
288
|
+
"nav",
|
|
289
|
+
{
|
|
290
|
+
"aria-label": triggerLabel,
|
|
291
|
+
className: cn("cls_locale_picker_inline flex items-center gap-1", className),
|
|
292
|
+
children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
293
|
+
"a",
|
|
294
|
+
{
|
|
295
|
+
href: opt.href,
|
|
296
|
+
lang: opt.code,
|
|
297
|
+
"aria-current": opt.code === activeLocale ? "true" : void 0,
|
|
298
|
+
className: cn(
|
|
299
|
+
"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",
|
|
300
|
+
opt.code === activeLocale && "bg-accent font-medium text-accent-foreground"
|
|
301
|
+
),
|
|
302
|
+
children: [
|
|
303
|
+
flags && /* @__PURE__ */ jsxRuntime.jsx(FlagIcon, { code: opt.code }),
|
|
304
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: opt.label })
|
|
305
|
+
]
|
|
306
|
+
},
|
|
307
|
+
opt.code
|
|
308
|
+
))
|
|
309
|
+
}
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
const active_option = options.find((o) => o.code === activeLocale);
|
|
313
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
|
|
314
|
+
/* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
315
|
+
Button,
|
|
316
|
+
{
|
|
317
|
+
variant: "outline",
|
|
318
|
+
size: "sm",
|
|
319
|
+
lang: activeLocale,
|
|
320
|
+
"aria-label": triggerLabel,
|
|
321
|
+
className: cn("cls_locale_picker_trigger gap-1.5", className),
|
|
322
|
+
children: [
|
|
323
|
+
flags && /* @__PURE__ */ jsxRuntime.jsx(FlagIcon, { code: active_option?.code ?? options[0].code }),
|
|
324
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "cls_locale_picker_trigger_label", children: variant === "compact" ? (active_option ?? options[0]).code.toUpperCase() : (active_option ?? options[0]).label }),
|
|
325
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3.5 w-3.5 opacity-60", "aria-hidden": "true" })
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
) }),
|
|
329
|
+
/* @__PURE__ */ jsxRuntime.jsx(DropdownMenuContent, { align: "end", className: "cls_locale_picker_content", children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuRadioGroup, { value: activeLocale, children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.RadioItem, { value: opt.code, asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
330
|
+
"a",
|
|
331
|
+
{
|
|
332
|
+
href: opt.href,
|
|
333
|
+
lang: opt.code,
|
|
334
|
+
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",
|
|
335
|
+
children: [
|
|
336
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Circle, { className: "h-2 w-2 fill-current" }) }) }),
|
|
337
|
+
flags && /* @__PURE__ */ jsxRuntime.jsx(FlagIcon, { code: opt.code }),
|
|
338
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: opt.label })
|
|
339
|
+
]
|
|
340
|
+
}
|
|
341
|
+
) }, opt.code)) }) })
|
|
342
|
+
] });
|
|
343
|
+
}
|
|
344
|
+
LocalePicker.displayName = "LocalePicker";
|
|
345
|
+
|
|
346
|
+
exports.LocalePicker = LocalePicker;
|
|
347
|
+
//# sourceMappingURL=index.locale-picker.cjs.map
|
|
348
|
+
//# sourceMappingURL=index.locale-picker.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/dropdown-menu.tsx","../src/components/ui/button.tsx","../src/components/locale_picker/index.tsx"],"names":["twMerge","clsx","DropdownMenuPrimitive","React","jsxs","jsx","ChevronRight","Check","Circle","cva","React2","Slot","Globe","React3","ChevronDown","DropdownMenuPrimitive2"],"mappings":"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","file":"index.locale-picker.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","// 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","\"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\";\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 a plain English \"Change language\". */\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 = \"Change language\",\n className,\n}: LocalePickerProps): React.ReactElement | null {\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={triggerLabel}\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={triggerLabel}\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"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* LocalePicker — standard language switcher for hazo_* apps (FR-030).
|
|
5
|
+
*
|
|
6
|
+
* Purely prop-driven: no hazo_i18n dependency, no context, no fetch. A
|
|
7
|
+
* consumer supplies `alternates` (the same locale -> URL map used for
|
|
8
|
+
* `<head>` hreflang) and this renders a picker that can only ever offer
|
|
9
|
+
* URLs that exist. Works identically whether hazo_i18n exists or not —
|
|
10
|
+
* today it doesn't, so this component has zero runtime dependency on it.
|
|
11
|
+
*
|
|
12
|
+
* Built on the same Radix DropdownMenu primitives as
|
|
13
|
+
* `src/components/ui/dropdown-menu.tsx`, but each option is rendered as a
|
|
14
|
+
* real `<a href>` (via Radix's `asChild`) rather than a JS-only click
|
|
15
|
+
* handler, so it stays crawlable and middle-click-openable.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
type LocalePickerVariant = "dropdown" | "inline" | "compact";
|
|
19
|
+
type LocalePickerShow = "auto" | "always" | "never";
|
|
20
|
+
type LocalePickerDisplay = "native" | "native+code" | "code";
|
|
21
|
+
interface LocalePickerProps {
|
|
22
|
+
/** Visual form. `dropdown` (default) and `compact` are Radix dropdown
|
|
23
|
+
* menus; `inline` renders a flat row of links with no popover. */
|
|
24
|
+
variant?: LocalePickerVariant;
|
|
25
|
+
/** `auto` (default) renders nothing when fewer than two locales are
|
|
26
|
+
* offered — single-locale apps need no conditional around this
|
|
27
|
+
* component. `always` / `never` override that. */
|
|
28
|
+
show?: LocalePickerShow;
|
|
29
|
+
/** How each option's label is built. Default `native` — the language's
|
|
30
|
+
* own name in its own script (`Deutsch`, `Svenska`), not an English
|
|
31
|
+
* name and not a flag (PRD-hazo_i18n §11.2). */
|
|
32
|
+
display?: LocalePickerDisplay;
|
|
33
|
+
/** Render an inline SVG flag alongside each option. Default false.
|
|
34
|
+
* Never emoji — Segoe UI Emoji ships no regional-indicator glyphs, so
|
|
35
|
+
* flag emoji render as two letter-boxes on Windows Chrome/Edge. */
|
|
36
|
+
flags?: boolean;
|
|
37
|
+
/** hreflang code -> URL for the current page. The picker can only ever
|
|
38
|
+
* offer locales present here — same map used for `<head>` hreflang. */
|
|
39
|
+
alternates: Record<string, string>;
|
|
40
|
+
/** Currently active locale, used to mark the selected option. */
|
|
41
|
+
activeLocale?: string;
|
|
42
|
+
/** aria-label for the trigger (dropdown/compact) or the `<nav>`
|
|
43
|
+
* (inline). Defaults to a plain English "Change language". */
|
|
44
|
+
triggerLabel?: string;
|
|
45
|
+
className?: string;
|
|
46
|
+
}
|
|
47
|
+
declare function LocalePicker({ variant, show, display, flags, alternates, activeLocale, triggerLabel, className, }: LocalePickerProps): React.ReactElement | null;
|
|
48
|
+
declare namespace LocalePicker {
|
|
49
|
+
var displayName: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { LocalePicker, type LocalePickerDisplay, type LocalePickerProps, type LocalePickerShow, type LocalePickerVariant };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* LocalePicker — standard language switcher for hazo_* apps (FR-030).
|
|
5
|
+
*
|
|
6
|
+
* Purely prop-driven: no hazo_i18n dependency, no context, no fetch. A
|
|
7
|
+
* consumer supplies `alternates` (the same locale -> URL map used for
|
|
8
|
+
* `<head>` hreflang) and this renders a picker that can only ever offer
|
|
9
|
+
* URLs that exist. Works identically whether hazo_i18n exists or not —
|
|
10
|
+
* today it doesn't, so this component has zero runtime dependency on it.
|
|
11
|
+
*
|
|
12
|
+
* Built on the same Radix DropdownMenu primitives as
|
|
13
|
+
* `src/components/ui/dropdown-menu.tsx`, but each option is rendered as a
|
|
14
|
+
* real `<a href>` (via Radix's `asChild`) rather than a JS-only click
|
|
15
|
+
* handler, so it stays crawlable and middle-click-openable.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
type LocalePickerVariant = "dropdown" | "inline" | "compact";
|
|
19
|
+
type LocalePickerShow = "auto" | "always" | "never";
|
|
20
|
+
type LocalePickerDisplay = "native" | "native+code" | "code";
|
|
21
|
+
interface LocalePickerProps {
|
|
22
|
+
/** Visual form. `dropdown` (default) and `compact` are Radix dropdown
|
|
23
|
+
* menus; `inline` renders a flat row of links with no popover. */
|
|
24
|
+
variant?: LocalePickerVariant;
|
|
25
|
+
/** `auto` (default) renders nothing when fewer than two locales are
|
|
26
|
+
* offered — single-locale apps need no conditional around this
|
|
27
|
+
* component. `always` / `never` override that. */
|
|
28
|
+
show?: LocalePickerShow;
|
|
29
|
+
/** How each option's label is built. Default `native` — the language's
|
|
30
|
+
* own name in its own script (`Deutsch`, `Svenska`), not an English
|
|
31
|
+
* name and not a flag (PRD-hazo_i18n §11.2). */
|
|
32
|
+
display?: LocalePickerDisplay;
|
|
33
|
+
/** Render an inline SVG flag alongside each option. Default false.
|
|
34
|
+
* Never emoji — Segoe UI Emoji ships no regional-indicator glyphs, so
|
|
35
|
+
* flag emoji render as two letter-boxes on Windows Chrome/Edge. */
|
|
36
|
+
flags?: boolean;
|
|
37
|
+
/** hreflang code -> URL for the current page. The picker can only ever
|
|
38
|
+
* offer locales present here — same map used for `<head>` hreflang. */
|
|
39
|
+
alternates: Record<string, string>;
|
|
40
|
+
/** Currently active locale, used to mark the selected option. */
|
|
41
|
+
activeLocale?: string;
|
|
42
|
+
/** aria-label for the trigger (dropdown/compact) or the `<nav>`
|
|
43
|
+
* (inline). Defaults to a plain English "Change language". */
|
|
44
|
+
triggerLabel?: string;
|
|
45
|
+
className?: string;
|
|
46
|
+
}
|
|
47
|
+
declare function LocalePicker({ variant, show, display, flags, alternates, activeLocale, triggerLabel, className, }: LocalePickerProps): React.ReactElement | null;
|
|
48
|
+
declare namespace LocalePicker {
|
|
49
|
+
var displayName: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { LocalePicker, type LocalePickerDisplay, type LocalePickerProps, type LocalePickerShow, type LocalePickerVariant };
|