@marwes-ui/react 0.0.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,45 +1,104 @@
1
- import { createDividerRecipe, createSystem, switchMode, resolveIconSize, resolveIconStrokeWidth, iconRegistry, createButtonRecipe, IconName, ButtonAction, ButtonVariant, createInputRecipe, checkboxRecipe, headingRecipe, paragraphRecipe } from '@marwes-ui/core';
2
- export { ButtonAction, ButtonSize, ButtonVariant, IconName } from '@marwes-ui/core';
3
- import { firstEdition } from '@marwes-ui/presets';
4
- import * as React7 from 'react';
1
+ import '@marwes-ui/presets/firstEdition/styles.css';
2
+ import { createRichTextRecipe, resolveRichTextAllowedFormats, normalizeRichTextHtml, isRichTextHtmlEmpty, createDividerRecipe, createSpacingRecipe, createSliderRecipe, richTextCommandByFormat, resolveIconSize, resolveIconStrokeWidth, iconRegistry, resolveIconA11y, resolveThemeInput, createSpinnerRecipe, createButtonRecipe, ButtonAction, ButtonVariant, IconName, createInputRecipe, createSelectRecipe, resolveSelectMode, createTextareaRecipe, paragraphRecipe, buildInputFieldA11yIds, sanitizeInputOtpValue, createInputOtpRecipe, buildRichTextFieldA11yIds, buildCurrencyHelperText, getCurrencySymbol, createAvatarRecipe, createPurposeSemanticAttributes, checkboxRecipe, buildCheckboxFieldA11yIds, buildCheckboxGroupFieldA11yIds, headingRecipe, createCardRecipe, createToastRecipe, createTooltipRecipe, createAccordionRecipe, buildAccordionFieldA11yIds, radioRecipe, buildRadioGroupFieldA11yIds, createBadgeRecipe, createSwitchRecipe, buildSwitchFieldA11yIds, buildSliderFieldA11yIds, createTabRecipe, resolveTabValue, buildTabGroupA11yIds, moveTabSelection, createDialogRecipe, sanitizeCurrencyValue, themeToCSSVars, extractUsedWeights, extractFontFamilyName, shouldLoadGoogleFont, buildGoogleFontsUrl } from '@marwes-ui/core';
3
+ export { AvatarSize, AvatarType, BadgeVariant, ButtonAction, ButtonSize, ButtonVariant, IconName, Spacings, SwitchSize, createFontStack, mwAvailableFonts, mwFontFallbacks, mwGoogleFontFamilies, mwStyledTheme, mwThemeVarNames, mwThemeVars, mwVar } from '@marwes-ui/core';
4
+ import * as React5 from 'react';
5
5
  import { useEffect } from 'react';
6
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
+ import { createPortal } from 'react-dom';
7
8
 
8
- // src/provider/marwes-provider.tsx
9
- var MarwesContext = React7.createContext(null);
9
+ // src/index.ts
10
+ var MarwesContext = React5.createContext(null);
11
+ var loadedFonts = /* @__PURE__ */ new Set();
12
+ var preconnected = false;
13
+ function themeToRootStyle(theme) {
14
+ return {
15
+ ...themeToCSSVars(theme),
16
+ backgroundColor: theme.color.background,
17
+ color: theme.color.text
18
+ };
19
+ }
20
+ function applyThemeToElement(element, theme) {
21
+ element.setAttribute("data-marwes-theme", "true");
22
+ for (const [property, value] of Object.entries(themeToRootStyle(theme))) {
23
+ if (property === "backgroundColor") {
24
+ element.style.backgroundColor = value;
25
+ continue;
26
+ }
27
+ element.style.setProperty(property, value);
28
+ }
29
+ }
30
+ function ensureFontPreconnect() {
31
+ if (preconnected || typeof document === "undefined") return;
32
+ preconnected = true;
33
+ for (const href of ["https://fonts.googleapis.com", "https://fonts.gstatic.com"]) {
34
+ const linkElement = document.createElement("link");
35
+ linkElement.rel = "preconnect";
36
+ linkElement.href = href;
37
+ if (href.includes("gstatic")) {
38
+ linkElement.crossOrigin = "anonymous";
39
+ }
40
+ document.head.appendChild(linkElement);
41
+ }
42
+ }
43
+ function loadGoogleFontToDocument(family, weights) {
44
+ if (typeof document === "undefined") return;
45
+ const cacheKey = `${family}:${weights.join(",")}`;
46
+ if (loadedFonts.has(cacheKey)) return;
47
+ loadedFonts.add(cacheKey);
48
+ ensureFontPreconnect();
49
+ const linkElement = document.createElement("link");
50
+ linkElement.rel = "stylesheet";
51
+ linkElement.href = buildGoogleFontsUrl(family, weights);
52
+ linkElement.dataset.marwesFont = family;
53
+ document.head.appendChild(linkElement);
54
+ }
55
+ function loadThemeFonts(theme, config = "auto") {
56
+ const weights = extractUsedWeights(theme.typography);
57
+ const fontStacks = [theme.font.primary, theme.font.secondary];
58
+ for (const fontStack of fontStacks) {
59
+ const familyName = extractFontFamilyName(fontStack);
60
+ if (familyName && shouldLoadGoogleFont(familyName, config)) {
61
+ loadGoogleFontToDocument(familyName, weights);
62
+ }
63
+ }
64
+ }
10
65
  function MarwesProvider({
11
- preset = firstEdition,
12
66
  theme,
13
- mode = "light",
67
+ fontLoading = "auto",
14
68
  onModeChange,
15
69
  children
16
70
  }) {
17
- const initialSystem = React7.useMemo(() => {
18
- return createSystem({
19
- preset,
20
- theme: theme ? { ...theme, mode } : { mode }
21
- });
22
- }, [preset, theme, mode]);
23
- const system = React7.useMemo(() => {
24
- if (mode === initialSystem.theme.mode) {
25
- return initialSystem;
26
- }
27
- return switchMode(initialSystem, mode);
28
- }, [initialSystem, mode]);
29
- const themeClass = `mw-theme--${system.theme.mode}`;
30
- return /* @__PURE__ */ jsx(MarwesContext.Provider, { value: { system, onModeChange }, children: /* @__PURE__ */ jsx("div", { className: themeClass, children }) });
31
- }
32
- function useSystem() {
33
- const ctx = React7.useContext(MarwesContext);
71
+ const rootRef = React5.useRef(null);
72
+ const resolved = React5.useMemo(() => resolveThemeInput(theme ?? {}), [theme]);
73
+ const rootStyle = React5.useMemo(
74
+ () => themeToRootStyle(resolved),
75
+ [resolved]
76
+ );
77
+ React5.useEffect(() => {
78
+ if (rootRef.current) {
79
+ applyThemeToElement(rootRef.current, resolved);
80
+ }
81
+ }, [resolved]);
82
+ React5.useEffect(() => {
83
+ loadThemeFonts(resolved, fontLoading);
84
+ }, [resolved, fontLoading]);
85
+ return /* @__PURE__ */ jsx(MarwesContext.Provider, { value: { theme: resolved, onModeChange }, children: /* @__PURE__ */ jsx(
86
+ "div",
87
+ {
88
+ ref: rootRef,
89
+ className: `mw-theme--${resolved.mode}`,
90
+ "data-marwes-theme": "true",
91
+ style: rootStyle,
92
+ children
93
+ }
94
+ ) });
95
+ }
96
+ function useTheme() {
97
+ const ctx = React5.useContext(MarwesContext);
34
98
  if (!ctx) {
35
99
  throw new Error("MarwesProvider is missing. Wrap your app in <MarwesProvider />.");
36
100
  }
37
- return ctx.system;
38
- }
39
-
40
- // src/provider/use-theme.ts
41
- function useTheme() {
42
- return useSystem().theme;
101
+ return ctx.theme;
43
102
  }
44
103
  function Icon({
45
104
  name,
@@ -49,12 +108,13 @@ function Icon({
49
108
  "aria-label": ariaLabel,
50
109
  decorative
51
110
  }) {
52
- const theme = useTheme();
53
- const themeIcon = theme.icon;
54
- const px = resolveIconSize(size ?? themeIcon.size);
55
- const sw = resolveIconStrokeWidth(strokeWidth ?? themeIcon.strokeWidth);
111
+ const px = resolveIconSize(size ?? "sm");
112
+ const sw = resolveIconStrokeWidth(strokeWidth ?? "md");
56
113
  const def = iconRegistry[name];
57
- const isDecorative = decorative || !ariaLabel;
114
+ const a11y = resolveIconA11y({
115
+ ...ariaLabel !== void 0 ? { ariaLabel } : {},
116
+ ...decorative !== void 0 ? { decorative } : {}
117
+ });
58
118
  return /* @__PURE__ */ jsx(
59
119
  "svg",
60
120
  {
@@ -67,9 +127,9 @@ function Icon({
67
127
  strokeLinecap: "round",
68
128
  strokeLinejoin: "round",
69
129
  className,
70
- "aria-hidden": isDecorative ? "true" : void 0,
71
- "aria-label": ariaLabel,
72
- role: isDecorative ? void 0 : "img",
130
+ "aria-hidden": a11y.ariaHidden ? "true" : void 0,
131
+ "aria-label": a11y.ariaLabel,
132
+ role: a11y.role,
73
133
  focusable: "false",
74
134
  children: def.nodes.map((iconNode, nodeIndex) => {
75
135
  const TagName = iconNode.tag;
@@ -78,15 +138,118 @@ function Icon({
78
138
  }
79
139
  );
80
140
  }
141
+ function renderSpinnerSvgNode(spinnerSvgNode, nodeIndex) {
142
+ const TagName = spinnerSvgNode.tag;
143
+ return /* @__PURE__ */ jsx(TagName, { ...spinnerSvgNode.attrs }, nodeIndex);
144
+ }
145
+ function Spinner(props) {
146
+ const {
147
+ className,
148
+ style,
149
+ dataAttributes,
150
+ variant,
151
+ size,
152
+ decorative,
153
+ ariaLabel,
154
+ id,
155
+ ...nativeSpanProps
156
+ } = props;
157
+ const resolvedAriaLabel = ariaLabel ?? (typeof nativeSpanProps["aria-label"] === "string" ? nativeSpanProps["aria-label"] : void 0);
158
+ const spinnerOptions = {
159
+ ...variant !== void 0 ? { variant } : {},
160
+ ...size !== void 0 ? { size } : {},
161
+ ...decorative !== void 0 ? { decorative } : {},
162
+ ...resolvedAriaLabel !== void 0 ? { ariaLabel: resolvedAriaLabel } : {},
163
+ ...id !== void 0 ? { id } : {}
164
+ };
165
+ const renderKit = createSpinnerRecipe(spinnerOptions);
166
+ const mergedClassName = [renderKit.className, className].filter(Boolean).join(" ");
167
+ const mergedStyle = { ...renderKit.vars, ...style };
168
+ return /* @__PURE__ */ jsx(
169
+ "span",
170
+ {
171
+ ...nativeSpanProps,
172
+ ...renderKit.dataAttributes,
173
+ ...dataAttributes,
174
+ className: mergedClassName,
175
+ style: mergedStyle,
176
+ role: renderKit.a11y.role,
177
+ id: renderKit.a11y.id,
178
+ "aria-hidden": renderKit.a11y.ariaHidden ? "true" : void 0,
179
+ "aria-label": renderKit.a11y.ariaLabel,
180
+ "aria-live": renderKit.a11y.ariaLive,
181
+ children: /* @__PURE__ */ jsx(
182
+ "svg",
183
+ {
184
+ className: "mw-spinner__svg",
185
+ viewBox: renderKit.svg.viewBox,
186
+ "aria-hidden": "true",
187
+ focusable: "false",
188
+ children: renderKit.svg.nodes.map(renderSpinnerSvgNode)
189
+ }
190
+ )
191
+ }
192
+ );
193
+ }
194
+ function ButtonSpinner(props) {
195
+ const { inverted = false, style, dataAttributes, ...spinnerProps } = props;
196
+ const spinnerStyle = {
197
+ "--mw-spinner-track-color": inverted ? "color-mix(in srgb, currentColor 80%, transparent)" : "color-mix(in srgb, currentColor 35%, transparent)",
198
+ "--mw-spinner-indicator-color": "currentColor",
199
+ ...style
200
+ };
201
+ return /* @__PURE__ */ jsx(
202
+ Spinner,
203
+ {
204
+ ...spinnerProps,
205
+ variant: props.variant ?? "classic",
206
+ size: props.size ?? "xs",
207
+ decorative: props.decorative ?? true,
208
+ style: spinnerStyle,
209
+ dataAttributes: {
210
+ ...dataAttributes,
211
+ "data-purpose": "button-loading",
212
+ "data-context": "button-loading"
213
+ }
214
+ }
215
+ );
216
+ }
217
+ function EmptyStateSpinner(props) {
218
+ return /* @__PURE__ */ jsx(
219
+ Spinner,
220
+ {
221
+ ...props,
222
+ variant: props.variant ?? "dots-round",
223
+ size: props.size ?? "lg",
224
+ decorative: props.decorative ?? true,
225
+ dataAttributes: {
226
+ ...props.dataAttributes,
227
+ "data-purpose": "empty-state",
228
+ "data-context": "empty-state"
229
+ }
230
+ }
231
+ );
232
+ }
233
+ function isFilledButtonVariant(variant) {
234
+ return variant === "primary" || variant === "success";
235
+ }
81
236
  function Button(props) {
82
- const theme = useTheme();
83
- const kit = createButtonRecipe(theme, props);
237
+ const kit = createButtonRecipe(props);
84
238
  const style = kit.vars;
85
239
  const className = props.className ? `${kit.className} ${props.className}` : kit.className;
240
+ const resolvedVariant = props.variant ?? "primary";
241
+ const resolvedLoading = kit.loading;
242
+ const visibleLabel = resolvedLoading.isLoading && resolvedLoading.loadingLabel !== void 0 ? resolvedLoading.loadingLabel : props.children;
86
243
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
87
- props.iconLeft && /* @__PURE__ */ jsx(Icon, { name: props.iconLeft, size: "xs", decorative: true }),
88
- props.children,
89
- props.iconRight && /* @__PURE__ */ jsx(Icon, { name: props.iconRight, size: "xs", decorative: true })
244
+ resolvedLoading.isLoading ? /* @__PURE__ */ jsx(
245
+ ButtonSpinner,
246
+ {
247
+ variant: resolvedLoading.spinnerVariant,
248
+ inverted: isFilledButtonVariant(resolvedVariant)
249
+ }
250
+ ) : props.iconLeft ? /* @__PURE__ */ jsx(Icon, { name: props.iconLeft, size: "xs", strokeWidth: "sm", decorative: true }) : null,
251
+ visibleLabel,
252
+ !resolvedLoading.isLoading && props.iconRight ? /* @__PURE__ */ jsx(Icon, { name: props.iconRight, size: "xs", strokeWidth: "sm", decorative: true }) : null
90
253
  ] });
91
254
  if (kit.tag === "button") {
92
255
  return /* @__PURE__ */ jsx(
@@ -136,77 +299,357 @@ function Button(props) {
136
299
  }
137
300
  );
138
301
  }
139
- function DangerButton(props) {
140
- const { confirmation = true, ...restProps } = props;
302
+ function isDevelopmentEnvironment() {
303
+ const nodeProcess = globalThis.process;
304
+ const nodeEnv = nodeProcess?.env?.NODE_ENV;
305
+ if (nodeEnv) {
306
+ return nodeEnv !== "production";
307
+ }
308
+ const meta = import.meta;
309
+ if (typeof meta.env?.PROD === "boolean") {
310
+ return !meta.env.PROD;
311
+ }
312
+ if (meta.env?.MODE) {
313
+ return meta.env.MODE !== "production";
314
+ }
315
+ return true;
316
+ }
317
+ function warnForForbiddenPurposeProps(componentName, rawProps, forbiddenProps) {
318
+ if (!isDevelopmentEnvironment()) {
319
+ return;
320
+ }
321
+ const warningByProp = {
322
+ variant: "Use Button if you need a custom visual treatment.",
323
+ action: "Use Button if you need a custom semantic action.",
324
+ as: "Use Button if you need a custom element mode."
325
+ };
326
+ for (const forbiddenProp of forbiddenProps) {
327
+ if (!Object.prototype.hasOwnProperty.call(rawProps, forbiddenProp)) {
328
+ continue;
329
+ }
330
+ console.warn(
331
+ `[marwes] ${componentName} does not support \`${forbiddenProp}\`. ${warningByProp[forbiddenProp]}`
332
+ );
333
+ }
334
+ }
335
+ function omitButtonProps(rawProps, omittedKeys) {
336
+ const forwardedProps = { ...rawProps };
337
+ for (const omittedKey of omittedKeys) {
338
+ delete forwardedProps[omittedKey];
339
+ }
340
+ return forwardedProps;
341
+ }
342
+ function createPurposeButtonDataAttributes(purpose, existingDataAttributes, localDataAttributes = {}) {
343
+ return {
344
+ ...existingDataAttributes,
345
+ ...createPurposeSemanticAttributes(purpose),
346
+ ...localDataAttributes
347
+ };
348
+ }
349
+ function DestructiveButton(props) {
350
+ const rawProps = props;
351
+ warnForForbiddenPurposeProps("DestructiveButton", rawProps, ["variant", "action", "as"]);
352
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action", "as", "href"]);
353
+ const confirmation = props.confirmation ?? true;
141
354
  return /* @__PURE__ */ jsx(
142
355
  Button,
143
356
  {
144
- ...restProps,
357
+ ...forwardedProps,
358
+ as: "button",
145
359
  variant: ButtonVariant.primary,
146
360
  action: ButtonAction.delete,
147
- iconRight: IconName.Minus,
361
+ error: true,
148
362
  confirmation,
149
- dataAttributes: {
150
- ...props.dataAttributes,
151
- "data-destructive": "true",
152
- "data-confirmation-required": confirmation ? "true" : "false"
153
- }
363
+ dataAttributes: createPurposeButtonDataAttributes(
364
+ "destructive",
365
+ forwardedProps.dataAttributes,
366
+ {
367
+ "data-confirmation-required": confirmation ? "true" : "false"
368
+ }
369
+ )
154
370
  }
155
371
  );
156
372
  }
157
373
  function CreateButton(props) {
374
+ const rawProps = props;
375
+ warnForForbiddenPurposeProps("CreateButton", rawProps, ["variant", "action"]);
376
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
158
377
  return /* @__PURE__ */ jsx(
159
378
  Button,
160
379
  {
161
- ...props,
162
- action: "create",
163
- variant: props.variant ?? "primary",
164
- dataAttributes: {
165
- ...props.dataAttributes,
380
+ ...forwardedProps,
381
+ action: ButtonAction.create,
382
+ variant: ButtonVariant.primary,
383
+ dataAttributes: createPurposeButtonDataAttributes("create", forwardedProps.dataAttributes, {
166
384
  "data-creative": "true"
167
- }
385
+ })
168
386
  }
169
387
  );
170
388
  }
171
389
  function SubmitButton(props) {
390
+ const rawProps = props;
391
+ warnForForbiddenPurposeProps("SubmitButton", rawProps, ["variant", "action", "as"]);
392
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action", "as", "href"]);
172
393
  return /* @__PURE__ */ jsx(
173
394
  Button,
174
395
  {
175
- ...props,
396
+ ...forwardedProps,
176
397
  as: "button",
177
- action: "submit",
178
- dataAttributes: {
179
- "data-context": "form-submit",
180
- ...props.dataAttributes
181
- }
398
+ action: ButtonAction.submit,
399
+ variant: ButtonVariant.primary,
400
+ dataAttributes: createPurposeButtonDataAttributes("submit", forwardedProps.dataAttributes)
182
401
  }
183
402
  );
184
403
  }
185
404
  function CancelButton(props) {
405
+ const rawProps = props;
406
+ warnForForbiddenPurposeProps("CancelButton", rawProps, ["variant", "action"]);
407
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
186
408
  return /* @__PURE__ */ jsx(
187
409
  Button,
188
410
  {
189
- ...props,
190
- action: "cancel",
191
- variant: props.variant ?? "secondary",
192
- dataAttributes: {
193
- ...props.dataAttributes,
411
+ ...forwardedProps,
412
+ action: ButtonAction.cancel,
413
+ variant: ButtonVariant.neutral,
414
+ dataAttributes: createPurposeButtonDataAttributes("cancel", forwardedProps.dataAttributes, {
194
415
  "data-cancel": "true"
195
- }
416
+ })
196
417
  }
197
418
  );
198
419
  }
199
420
  function LinkButton(props) {
421
+ const rawProps = props;
422
+ warnForForbiddenPurposeProps("LinkButton", rawProps, ["variant", "action", "as"]);
423
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action", "as"]);
200
424
  return /* @__PURE__ */ jsx(
201
425
  Button,
202
426
  {
203
- ...props,
427
+ ...forwardedProps,
204
428
  as: "a",
205
- action: "navigate",
206
- dataAttributes: {
207
- ...props.dataAttributes,
208
- "data-navigation": "true"
209
- }
429
+ action: ButtonAction.navigate,
430
+ variant: ButtonVariant.text,
431
+ dataAttributes: createPurposeButtonDataAttributes(
432
+ "navigation",
433
+ forwardedProps.dataAttributes,
434
+ {
435
+ "data-navigation": "true"
436
+ }
437
+ )
438
+ }
439
+ );
440
+ }
441
+ function SaveButton(props) {
442
+ const rawProps = props;
443
+ warnForForbiddenPurposeProps("SaveButton", rawProps, ["variant", "action"]);
444
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
445
+ return /* @__PURE__ */ jsx(
446
+ Button,
447
+ {
448
+ ...forwardedProps,
449
+ action: ButtonAction.submit,
450
+ variant: ButtonVariant.primary,
451
+ dataAttributes: createPurposeButtonDataAttributes("save", forwardedProps.dataAttributes, {
452
+ "data-persist": "true"
453
+ })
454
+ }
455
+ );
456
+ }
457
+ function ConfirmButton(props) {
458
+ const rawProps = props;
459
+ warnForForbiddenPurposeProps("ConfirmButton", rawProps, ["variant", "action", "as"]);
460
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action", "as", "href"]);
461
+ return /* @__PURE__ */ jsx(
462
+ Button,
463
+ {
464
+ ...forwardedProps,
465
+ as: "button",
466
+ action: ButtonAction.button,
467
+ variant: ButtonVariant.success,
468
+ dataAttributes: createPurposeButtonDataAttributes("confirm", forwardedProps.dataAttributes)
469
+ }
470
+ );
471
+ }
472
+ function VerifyButton(props) {
473
+ const rawProps = props;
474
+ warnForForbiddenPurposeProps("VerifyButton", rawProps, ["variant", "action", "as"]);
475
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action", "as", "href"]);
476
+ return /* @__PURE__ */ jsx(
477
+ Button,
478
+ {
479
+ ...forwardedProps,
480
+ as: "button",
481
+ action: ButtonAction.button,
482
+ variant: ButtonVariant.secondary,
483
+ iconRight: forwardedProps.iconRight ?? IconName.CheckCircle,
484
+ dataAttributes: createPurposeButtonDataAttributes("verify", forwardedProps.dataAttributes, {
485
+ "data-verification": "true"
486
+ })
487
+ }
488
+ );
489
+ }
490
+ function EditButton(props) {
491
+ const rawProps = props;
492
+ warnForForbiddenPurposeProps("EditButton", rawProps, ["variant", "action"]);
493
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
494
+ return /* @__PURE__ */ jsx(
495
+ Button,
496
+ {
497
+ ...forwardedProps,
498
+ action: ButtonAction.edit,
499
+ variant: ButtonVariant.secondary,
500
+ iconRight: forwardedProps.iconRight ?? IconName.Edit,
501
+ dataAttributes: createPurposeButtonDataAttributes("edit", forwardedProps.dataAttributes, {
502
+ "data-edit": "true"
503
+ })
504
+ }
505
+ );
506
+ }
507
+ function CloseButton(props) {
508
+ const rawProps = props;
509
+ warnForForbiddenPurposeProps("CloseButton", rawProps, ["variant", "action"]);
510
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
511
+ return /* @__PURE__ */ jsx(
512
+ Button,
513
+ {
514
+ ...forwardedProps,
515
+ action: ButtonAction.cancel,
516
+ variant: ButtonVariant.neutral,
517
+ dataAttributes: createPurposeButtonDataAttributes("close", forwardedProps.dataAttributes, {
518
+ "data-close": "true"
519
+ })
520
+ }
521
+ );
522
+ }
523
+ function RefreshButton(props) {
524
+ const rawProps = props;
525
+ warnForForbiddenPurposeProps("RefreshButton", rawProps, ["variant", "action"]);
526
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
527
+ return /* @__PURE__ */ jsx(
528
+ Button,
529
+ {
530
+ ...forwardedProps,
531
+ action: ButtonAction.button,
532
+ variant: ButtonVariant.neutral,
533
+ iconRight: forwardedProps.iconRight ?? IconName.RefreshCw,
534
+ dataAttributes: createPurposeButtonDataAttributes("refresh", forwardedProps.dataAttributes, {
535
+ "data-refresh": "true"
536
+ })
537
+ }
538
+ );
539
+ }
540
+ function UploadButton(props) {
541
+ const rawProps = props;
542
+ warnForForbiddenPurposeProps("UploadButton", rawProps, ["variant", "action"]);
543
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
544
+ return /* @__PURE__ */ jsx(
545
+ Button,
546
+ {
547
+ ...forwardedProps,
548
+ action: ButtonAction.button,
549
+ variant: ButtonVariant.secondary,
550
+ iconRight: forwardedProps.iconRight ?? IconName.Upload,
551
+ dataAttributes: createPurposeButtonDataAttributes("upload", forwardedProps.dataAttributes, {
552
+ "data-transfer": "upload"
553
+ })
554
+ }
555
+ );
556
+ }
557
+ function DownloadButton(props) {
558
+ const rawProps = props;
559
+ warnForForbiddenPurposeProps("DownloadButton", rawProps, ["variant", "action"]);
560
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
561
+ return /* @__PURE__ */ jsx(
562
+ Button,
563
+ {
564
+ ...forwardedProps,
565
+ action: ButtonAction.button,
566
+ variant: ButtonVariant.secondary,
567
+ iconRight: forwardedProps.iconRight ?? IconName.Download,
568
+ dataAttributes: createPurposeButtonDataAttributes("download", forwardedProps.dataAttributes, {
569
+ "data-transfer": "download"
570
+ })
571
+ }
572
+ );
573
+ }
574
+ function CopyButton(props) {
575
+ const rawProps = props;
576
+ warnForForbiddenPurposeProps("CopyButton", rawProps, ["variant", "action"]);
577
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
578
+ return /* @__PURE__ */ jsx(
579
+ Button,
580
+ {
581
+ ...forwardedProps,
582
+ action: ButtonAction.button,
583
+ variant: ButtonVariant.neutral,
584
+ dataAttributes: createPurposeButtonDataAttributes("copy", forwardedProps.dataAttributes, {
585
+ "data-copy": "true"
586
+ })
587
+ }
588
+ );
589
+ }
590
+ function SearchButton(props) {
591
+ const rawProps = props;
592
+ warnForForbiddenPurposeProps("SearchButton", rawProps, ["variant", "action"]);
593
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
594
+ return /* @__PURE__ */ jsx(
595
+ Button,
596
+ {
597
+ ...forwardedProps,
598
+ action: ButtonAction.button,
599
+ variant: ButtonVariant.primary,
600
+ iconRight: forwardedProps.iconRight ?? IconName.Search,
601
+ dataAttributes: createPurposeButtonDataAttributes("search", forwardedProps.dataAttributes, {
602
+ "data-search": "true"
603
+ })
604
+ }
605
+ );
606
+ }
607
+ function FilterButton(props) {
608
+ const rawProps = props;
609
+ warnForForbiddenPurposeProps("FilterButton", rawProps, ["variant", "action"]);
610
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
611
+ return /* @__PURE__ */ jsx(
612
+ Button,
613
+ {
614
+ ...forwardedProps,
615
+ action: ButtonAction.button,
616
+ variant: ButtonVariant.neutral,
617
+ dataAttributes: createPurposeButtonDataAttributes("filter", forwardedProps.dataAttributes, {
618
+ "data-filter": "true"
619
+ })
620
+ }
621
+ );
622
+ }
623
+ function SortButton(props) {
624
+ const rawProps = props;
625
+ warnForForbiddenPurposeProps("SortButton", rawProps, ["variant", "action"]);
626
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
627
+ return /* @__PURE__ */ jsx(
628
+ Button,
629
+ {
630
+ ...forwardedProps,
631
+ action: ButtonAction.button,
632
+ variant: ButtonVariant.neutral,
633
+ dataAttributes: createPurposeButtonDataAttributes("sort", forwardedProps.dataAttributes, {
634
+ "data-sort": "true"
635
+ })
636
+ }
637
+ );
638
+ }
639
+ function DropdownButton(props) {
640
+ const rawProps = props;
641
+ warnForForbiddenPurposeProps("DropdownButton", rawProps, ["variant", "action"]);
642
+ const forwardedProps = omitButtonProps(rawProps, ["variant", "action"]);
643
+ return /* @__PURE__ */ jsx(
644
+ Button,
645
+ {
646
+ ...forwardedProps,
647
+ action: ButtonAction.button,
648
+ variant: ButtonVariant.secondary,
649
+ iconRight: forwardedProps.iconRight ?? IconName.ChevronDown,
650
+ dataAttributes: createPurposeButtonDataAttributes("dropdown", forwardedProps.dataAttributes, {
651
+ "data-dropdown": "true"
652
+ })
210
653
  }
211
654
  );
212
655
  }
@@ -219,24 +662,42 @@ function SecondaryButton(props) {
219
662
  function TextButton(props) {
220
663
  return /* @__PURE__ */ jsx(Button, { ...props, variant: "text", as: "button" });
221
664
  }
665
+ function SuccessButton(props) {
666
+ return /* @__PURE__ */ jsx(
667
+ Button,
668
+ {
669
+ ...props,
670
+ variant: "success",
671
+ as: "button",
672
+ dataAttributes: createPurposeButtonDataAttributes("success", props.dataAttributes)
673
+ }
674
+ );
675
+ }
222
676
  var RENDERKIT_EVENT = "marwes/renderkit/renderkit-update";
677
+ var RENDERKIT_DEBUG_FLAG = "__MARWES_RENDERKIT_DEBUG__";
678
+ function isRenderKitDebugEnabled() {
679
+ if (typeof window === "undefined") {
680
+ return false;
681
+ }
682
+ const renderKitDebugWindow = window;
683
+ return renderKitDebugWindow[RENDERKIT_DEBUG_FLAG] === true;
684
+ }
223
685
  function useRenderKitDebug(renderKit, componentName) {
224
686
  useEffect(() => {
225
- if (typeof window !== "undefined") {
226
- console.log(`[RenderKit Debug] ${componentName}:`, renderKit);
227
- const event = new CustomEvent(RENDERKIT_EVENT, {
228
- detail: {
229
- ...renderKit,
230
- _meta: { component: componentName }
231
- }
232
- });
233
- window.dispatchEvent(event);
687
+ if (!isRenderKitDebugEnabled()) {
688
+ return;
234
689
  }
690
+ const event = new CustomEvent(RENDERKIT_EVENT, {
691
+ detail: {
692
+ ...renderKit,
693
+ _meta: { component: componentName }
694
+ }
695
+ });
696
+ window.dispatchEvent(event);
235
697
  }, [renderKit, componentName]);
236
698
  }
237
699
  function Input(props) {
238
- const theme = useTheme();
239
- const kit = createInputRecipe(theme, props);
700
+ const kit = createInputRecipe(props);
240
701
  useRenderKitDebug(kit, "Input");
241
702
  const style = kit.vars;
242
703
  const className = props.className ? `${kit.className} ${props.className}` : kit.className;
@@ -266,77 +727,443 @@ function Input(props) {
266
727
  }
267
728
  );
268
729
  }
269
- function Checkbox(props) {
270
- const { onCheckedChange, onChange, ...coreProps } = props;
271
- const theme = useTheme();
272
- const kit = checkboxRecipe({ ...coreProps, theme });
273
- const inputRef = React7.useRef(null);
274
- React7.useLayoutEffect(() => {
275
- const el = inputRef.current;
276
- if (!el) return;
277
- el.indeterminate = kit.indeterminate;
278
- }, [kit.indeterminate]);
279
- const handleChange = (e) => {
280
- onChange?.(e);
281
- onCheckedChange?.(e.currentTarget.checked);
282
- };
283
- const { a11y } = kit;
730
+ function SelectArrowIcon(props) {
284
731
  return /* @__PURE__ */ jsx(
285
- "input",
732
+ "svg",
286
733
  {
287
- ref: inputRef,
288
- type: "checkbox",
289
- className: kit.className,
290
- style: kit.vars,
291
- id: a11y.id,
292
- name: a11y.name,
293
- value: a11y.value,
294
- disabled: a11y.disabled === true,
295
- required: a11y.required === true,
296
- "aria-label": a11y.ariaLabel,
297
- "aria-labelledby": a11y.ariaLabelledBy,
298
- "aria-describedby": a11y.ariaDescribedBy,
299
- "aria-checked": a11y.ariaChecked,
300
- "aria-invalid": a11y.ariaInvalid === true ? true : void 0,
301
- checked: kit.checked,
302
- defaultChecked: kit.defaultChecked,
303
- onChange: handleChange
734
+ width: "16",
735
+ height: "16",
736
+ viewBox: "0 0 16 16",
737
+ fill: "none",
738
+ xmlns: "http://www.w3.org/2000/svg",
739
+ className: props.className,
740
+ "aria-hidden": "true",
741
+ focusable: "false",
742
+ children: /* @__PURE__ */ jsx(
743
+ "path",
744
+ {
745
+ d: "M11.5288 5.52876C11.7891 5.26841 12.2111 5.26841 12.4715 5.52876C12.7318 5.78911 12.7318 6.21114 12.4715 6.47147L8.47148 10.4715C8.21115 10.7318 7.78912 10.7318 7.52877 10.4715L3.52876 6.47147C3.26841 6.21112 3.26841 5.78911 3.52876 5.52876C3.78911 5.26841 4.21112 5.26841 4.47147 5.52876L6.58591 7.6432C7.36696 8.42425 8.63329 8.42425 9.41434 7.6432L11.5288 5.52876Z",
746
+ fill: "currentColor"
747
+ }
748
+ )
304
749
  }
305
750
  );
306
751
  }
307
- var Divider = React7.forwardRef((props, ref) => {
308
- const { className: customClassName, style: customStyle, ...opts } = props;
309
- const theme = useTheme();
310
- const kit = createDividerRecipe(theme, opts);
311
- const style = { ...kit.vars, ...customStyle };
312
- const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
313
- return /* @__PURE__ */ jsx("hr", { ref, ...kit.a11y, ...kit.dataAttributes, className, style });
314
- });
315
- Divider.displayName = "Divider";
316
- function H1(props) {
317
- const { children, className: customClassName, style: customStyle, ...opts } = props;
318
- const theme = useTheme();
319
- const kit = headingRecipe({ ...opts, level: 1 }, theme);
320
- const style = { ...kit.vars, ...customStyle };
321
- const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
322
- return /* @__PURE__ */ jsx("h1", { id: kit.a11y.id, "aria-label": kit.a11y.ariaLabel, className, style, children });
752
+ function getInitialSelectValue(props) {
753
+ if (props.value !== void 0) {
754
+ return props.value;
755
+ }
756
+ if (props.defaultValue !== void 0) {
757
+ return props.defaultValue;
758
+ }
759
+ if (props.placeholder !== void 0) {
760
+ return "";
761
+ }
762
+ return props.options[0]?.value ?? "";
323
763
  }
324
- function H2(props) {
325
- const { children, className: customClassName, style: customStyle, ...opts } = props;
326
- const theme = useTheme();
327
- const kit = headingRecipe({ ...opts, level: 2 }, theme);
328
- const style = { ...kit.vars, ...customStyle };
329
- const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
330
- return /* @__PURE__ */ jsx("h2", { id: kit.a11y.id, "aria-label": kit.a11y.ariaLabel, className, style, children });
764
+ function Select(props) {
765
+ const kit = createSelectRecipe(props);
766
+ const mode = resolveSelectMode(props);
767
+ const isControlled = props.value !== void 0;
768
+ const [uncontrolledValue, setUncontrolledValue] = React5.useState(
769
+ () => getInitialSelectValue(props)
770
+ );
771
+ useRenderKitDebug(kit, "Select");
772
+ const style = kit.vars;
773
+ const className = props.className ? `${kit.className} ${props.className}` : kit.className;
774
+ const value = isControlled ? props.value ?? "" : uncontrolledValue;
775
+ const hasPlaceholder = props.placeholder !== void 0;
776
+ const placeholderSelected = hasPlaceholder && value === "";
777
+ const handleChange = (e) => {
778
+ const nextValue = e.target.value;
779
+ if (!isControlled) {
780
+ setUncontrolledValue(nextValue);
781
+ }
782
+ props.onValueChange?.(nextValue);
783
+ };
784
+ const selectElement = /* @__PURE__ */ jsxs(
785
+ "select",
786
+ {
787
+ className,
788
+ style,
789
+ "data-placeholder-selected": placeholderSelected ? "true" : void 0,
790
+ id: kit.a11y.id,
791
+ name: kit.a11y.name,
792
+ disabled: kit.a11y.disabled,
793
+ required: kit.a11y.required,
794
+ "aria-label": kit.a11y.ariaLabel,
795
+ "aria-invalid": kit.a11y.ariaInvalid,
796
+ "aria-describedby": kit.a11y.ariaDescribedBy,
797
+ value,
798
+ onChange: handleChange,
799
+ children: [
800
+ props.placeholder ? /* @__PURE__ */ jsx("option", { value: "", disabled: props.required ? true : void 0, children: props.placeholder }) : null,
801
+ props.options.map((option) => /* @__PURE__ */ jsx(
802
+ "option",
803
+ {
804
+ value: option.value,
805
+ disabled: option.disabled ? true : void 0,
806
+ children: option.label
807
+ },
808
+ option.value
809
+ ))
810
+ ]
811
+ }
812
+ );
813
+ if (mode === "native") {
814
+ return selectElement;
815
+ }
816
+ return /* @__PURE__ */ jsxs("span", { className: "mw-select__control", children: [
817
+ selectElement,
818
+ /* @__PURE__ */ jsx(SelectArrowIcon, { className: "mw-select__control-icon" })
819
+ ] });
331
820
  }
332
- function H3(props) {
333
- const { children, className: customClassName, style: customStyle, ...opts } = props;
334
- const theme = useTheme();
335
- const kit = headingRecipe({ ...opts, level: 3 }, theme);
336
- const style = { ...kit.vars, ...customStyle };
337
- const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
338
- return /* @__PURE__ */ jsx("h3", { id: kit.a11y.id, "aria-label": kit.a11y.ariaLabel, className, style, children });
821
+ function Textarea(props) {
822
+ const kit = createTextareaRecipe(props);
823
+ useRenderKitDebug(kit, "Textarea");
824
+ const style = kit.vars;
825
+ const className = props.className ? `${kit.className} ${props.className}` : kit.className;
826
+ const handleChange = (e) => {
827
+ props.onValueChange?.(e.target.value);
828
+ };
829
+ return /* @__PURE__ */ jsx(
830
+ "textarea",
831
+ {
832
+ className,
833
+ style,
834
+ id: kit.a11y.id,
835
+ name: kit.a11y.name,
836
+ inputMode: kit.a11y.inputMode,
837
+ autoComplete: kit.a11y.autoComplete,
838
+ placeholder: kit.a11y.placeholder,
839
+ disabled: kit.a11y.disabled,
840
+ readOnly: kit.a11y.readOnly,
841
+ required: kit.a11y.required,
842
+ rows: kit.a11y.rows,
843
+ cols: kit.a11y.cols,
844
+ "aria-label": kit.a11y.ariaLabel,
845
+ "aria-invalid": kit.a11y.ariaInvalid,
846
+ "aria-describedby": kit.a11y.ariaDescribedBy,
847
+ value: props.value,
848
+ defaultValue: props.defaultValue,
849
+ onChange: handleChange
850
+ }
851
+ );
852
+ }
853
+ var formatLabels = {
854
+ bold: "Bold",
855
+ italic: "Italic",
856
+ underline: "Underline"
857
+ };
858
+ function getRichTextCommandDocument() {
859
+ return document;
860
+ }
861
+ function mergeRefs(...refs) {
862
+ return (value) => {
863
+ for (const ref of refs) {
864
+ if (!ref) continue;
865
+ if (typeof ref === "function") {
866
+ ref(value);
867
+ continue;
868
+ }
869
+ ref.current = value;
870
+ }
871
+ };
872
+ }
873
+ function isNodeWithinEditor(node, editorElement) {
874
+ if (!node || !editorElement) {
875
+ return false;
876
+ }
877
+ return editorElement.contains(node.nodeType === Node.TEXT_NODE ? node.parentNode : node);
878
+ }
879
+ function getActiveFormatsFromSelection(editorElement) {
880
+ if (!editorElement || typeof window === "undefined" || typeof document === "undefined") {
881
+ return [];
882
+ }
883
+ const commandDocument = getRichTextCommandDocument();
884
+ const selection = window.getSelection();
885
+ const anchorNode = selection?.anchorNode ?? null;
886
+ if (!anchorNode || !isNodeWithinEditor(anchorNode, editorElement)) {
887
+ return [];
888
+ }
889
+ const activeFormats = /* @__PURE__ */ new Set();
890
+ if (typeof commandDocument.queryCommandState === "function") {
891
+ for (const format of Object.keys(richTextCommandByFormat)) {
892
+ try {
893
+ if (commandDocument.queryCommandState(richTextCommandByFormat[format])) {
894
+ activeFormats.add(format);
895
+ }
896
+ } catch {
897
+ }
898
+ }
899
+ }
900
+ if (activeFormats.size > 0) {
901
+ return Array.from(activeFormats);
902
+ }
903
+ let currentNode = anchorNode.nodeType === Node.TEXT_NODE ? anchorNode.parentNode : anchorNode;
904
+ while (currentNode && currentNode !== editorElement) {
905
+ if (!(currentNode instanceof HTMLElement)) {
906
+ currentNode = currentNode.parentNode;
907
+ continue;
908
+ }
909
+ const tagName = currentNode.tagName.toLowerCase();
910
+ if (tagName === "strong" || tagName === "b") activeFormats.add("bold");
911
+ if (tagName === "em" || tagName === "i") activeFormats.add("italic");
912
+ if (tagName === "u") activeFormats.add("underline");
913
+ currentNode = currentNode.parentNode;
914
+ }
915
+ return Array.from(activeFormats);
916
+ }
917
+ function ensureEditorSelection(editorElement) {
918
+ if (typeof window === "undefined") {
919
+ return;
920
+ }
921
+ editorElement.focus();
922
+ const selection = window.getSelection();
923
+ const anchorNode = selection?.anchorNode ?? null;
924
+ if (anchorNode && isNodeWithinEditor(anchorNode, editorElement)) {
925
+ return;
926
+ }
927
+ const range = document.createRange();
928
+ range.selectNodeContents(editorElement);
929
+ range.collapse(false);
930
+ selection?.removeAllRanges();
931
+ selection?.addRange(range);
932
+ }
933
+ function getFormatTagNames(format) {
934
+ if (format === "bold") return ["strong", "b"];
935
+ if (format === "italic") return ["em", "i"];
936
+ return ["u"];
937
+ }
938
+ function findNearestFormatElement(node, editorElement, format) {
939
+ const tagNames = getFormatTagNames(format);
940
+ let currentNode = node?.nodeType === Node.TEXT_NODE ? node.parentNode : node;
941
+ while (currentNode && currentNode !== editorElement) {
942
+ if (currentNode instanceof HTMLElement && tagNames.includes(currentNode.tagName.toLowerCase())) {
943
+ return currentNode;
944
+ }
945
+ currentNode = currentNode.parentNode;
946
+ }
947
+ return null;
948
+ }
949
+ function exitActiveFormatAtCaret(editorElement, format) {
950
+ if (typeof window === "undefined") {
951
+ return false;
952
+ }
953
+ const selection = window.getSelection();
954
+ if (!selection || selection.rangeCount === 0) {
955
+ return false;
956
+ }
957
+ const range = selection.getRangeAt(0);
958
+ const anchorNode = selection.anchorNode;
959
+ if (!range.collapsed || !anchorNode || !isNodeWithinEditor(anchorNode, editorElement)) {
960
+ return false;
961
+ }
962
+ const formatElement = findNearestFormatElement(anchorNode, editorElement, format);
963
+ if (!formatElement || !formatElement.parentNode) {
964
+ return false;
965
+ }
966
+ const trailingRange = document.createRange();
967
+ trailingRange.setStart(range.startContainer, range.startOffset);
968
+ trailingRange.setEndAfter(formatElement);
969
+ const trailingFragment = trailingRange.extractContents();
970
+ const caretTextNode = document.createTextNode("\u200B");
971
+ const parentNode = formatElement.parentNode;
972
+ parentNode.insertBefore(caretTextNode, formatElement.nextSibling);
973
+ parentNode.insertBefore(trailingFragment, caretTextNode.nextSibling);
974
+ if (formatElement.textContent?.replaceAll("\u200B", "").trim().length === 0) {
975
+ formatElement.remove();
976
+ }
977
+ const nextRange = document.createRange();
978
+ nextRange.setStart(caretTextNode, 1);
979
+ nextRange.collapse(true);
980
+ selection.removeAllRanges();
981
+ selection.addRange(nextRange);
982
+ return true;
339
983
  }
984
+ var RichText = React5.forwardRef((props, forwardedRef) => {
985
+ const kit = createRichTextRecipe(props);
986
+ const allowedFormats = React5.useMemo(
987
+ () => resolveRichTextAllowedFormats(props.allowedFormats),
988
+ [props.allowedFormats]
989
+ );
990
+ const normalizedControlledValue = React5.useMemo(
991
+ () => normalizeRichTextHtml(props.value),
992
+ [props.value]
993
+ );
994
+ const initialUncontrolledValue = React5.useMemo(
995
+ () => normalizeRichTextHtml(props.defaultValue),
996
+ [props.defaultValue]
997
+ );
998
+ const isControlled = props.value !== void 0;
999
+ const [uncontrolledHtml, setUncontrolledHtml] = React5.useState(initialUncontrolledValue);
1000
+ const [isEditorEmpty, setIsEditorEmpty] = React5.useState(
1001
+ isRichTextHtmlEmpty(isControlled ? normalizedControlledValue : initialUncontrolledValue)
1002
+ );
1003
+ const [activeFormats, setActiveFormats] = React5.useState([]);
1004
+ const editorElementRef = React5.useRef(null);
1005
+ useRenderKitDebug(kit, "RichText");
1006
+ const editorHtml = isControlled ? normalizedControlledValue : uncontrolledHtml;
1007
+ const style = kit.vars;
1008
+ const className = props.className ? `${kit.className} ${props.className}` : kit.className;
1009
+ const showToolbar = !props.readOnly;
1010
+ const syncEditorState = React5.useCallback(
1011
+ (nextHtml) => {
1012
+ const normalizedHtml = normalizeRichTextHtml(nextHtml);
1013
+ const emptyState = isRichTextHtmlEmpty(normalizedHtml);
1014
+ if (!isControlled) {
1015
+ setUncontrolledHtml(normalizedHtml);
1016
+ }
1017
+ setIsEditorEmpty(emptyState);
1018
+ props.onValueChange?.(normalizedHtml);
1019
+ return normalizedHtml;
1020
+ },
1021
+ [isControlled, props]
1022
+ );
1023
+ const refreshActiveFormats = React5.useCallback(() => {
1024
+ setActiveFormats(getActiveFormatsFromSelection(editorElementRef.current));
1025
+ }, []);
1026
+ React5.useLayoutEffect(() => {
1027
+ const editorElement = editorElementRef.current;
1028
+ if (!editorElement) {
1029
+ return;
1030
+ }
1031
+ const normalizedDomHtml = normalizeRichTextHtml(editorElement.innerHTML);
1032
+ if (normalizedDomHtml !== editorHtml) {
1033
+ editorElement.innerHTML = editorHtml;
1034
+ }
1035
+ setIsEditorEmpty(isRichTextHtmlEmpty(editorHtml));
1036
+ }, [editorHtml]);
1037
+ React5.useEffect(() => {
1038
+ if (typeof document === "undefined") {
1039
+ return void 0;
1040
+ }
1041
+ const handleSelectionChange = () => {
1042
+ refreshActiveFormats();
1043
+ };
1044
+ document.addEventListener("selectionchange", handleSelectionChange);
1045
+ return () => {
1046
+ document.removeEventListener("selectionchange", handleSelectionChange);
1047
+ };
1048
+ }, [refreshActiveFormats]);
1049
+ const handleInput = () => {
1050
+ const editorElement = editorElementRef.current;
1051
+ if (!editorElement || props.disabled || props.readOnly) {
1052
+ return;
1053
+ }
1054
+ syncEditorState(editorElement.innerHTML);
1055
+ refreshActiveFormats();
1056
+ };
1057
+ const toggleFormat = (format) => {
1058
+ if (props.disabled || props.readOnly || typeof document === "undefined") {
1059
+ return;
1060
+ }
1061
+ const commandDocument = getRichTextCommandDocument();
1062
+ const editorElement = editorElementRef.current;
1063
+ if (!editorElement) {
1064
+ return;
1065
+ }
1066
+ ensureEditorSelection(editorElement);
1067
+ const activeFormatsBeforeToggle = getActiveFormatsFromSelection(editorElement);
1068
+ if (exitActiveFormatAtCaret(editorElement, format)) {
1069
+ if (typeof commandDocument.queryCommandState === "function" && commandDocument.queryCommandState(richTextCommandByFormat[format]) && typeof commandDocument.execCommand === "function") {
1070
+ commandDocument.execCommand(richTextCommandByFormat[format]);
1071
+ }
1072
+ if (typeof commandDocument.queryCommandState === "function" && typeof commandDocument.execCommand === "function") {
1073
+ for (const activeFormat of activeFormatsBeforeToggle) {
1074
+ if (activeFormat === format) {
1075
+ continue;
1076
+ }
1077
+ if (!commandDocument.queryCommandState(richTextCommandByFormat[activeFormat])) {
1078
+ commandDocument.execCommand(richTextCommandByFormat[activeFormat]);
1079
+ }
1080
+ }
1081
+ }
1082
+ syncEditorState(editorElement.innerHTML);
1083
+ refreshActiveFormats();
1084
+ return;
1085
+ }
1086
+ if (typeof commandDocument.execCommand === "function") {
1087
+ commandDocument.execCommand(richTextCommandByFormat[format]);
1088
+ }
1089
+ syncEditorState(editorElement.innerHTML);
1090
+ refreshActiveFormats();
1091
+ };
1092
+ const handleKeyDown = (event) => {
1093
+ if (!(event.metaKey || event.ctrlKey) || event.altKey) {
1094
+ return;
1095
+ }
1096
+ const formatByKey = {
1097
+ b: "bold",
1098
+ i: "italic",
1099
+ u: "underline"
1100
+ };
1101
+ const requestedFormat = formatByKey[event.key.toLowerCase()];
1102
+ if (!requestedFormat || !allowedFormats.includes(requestedFormat)) {
1103
+ return;
1104
+ }
1105
+ event.preventDefault();
1106
+ toggleFormat(requestedFormat);
1107
+ };
1108
+ return /* @__PURE__ */ jsxs("div", { className, style, ...kit.dataAttributes, children: [
1109
+ showToolbar && /* @__PURE__ */ jsx("div", { className: "mw-rich-text__toolbar", "data-rich-text-toolbar": true, children: allowedFormats.map((format) => {
1110
+ const isActive = activeFormats.includes(format);
1111
+ const iconName = format === "bold" ? "bold" : format === "italic" ? "italic" : "underline";
1112
+ return /* @__PURE__ */ jsx(
1113
+ "button",
1114
+ {
1115
+ type: "button",
1116
+ className: "mw-rich-text__toolbar-button",
1117
+ "data-format": format,
1118
+ "data-active": isActive ? "true" : void 0,
1119
+ "aria-label": formatLabels[format],
1120
+ "aria-pressed": isActive,
1121
+ disabled: props.disabled,
1122
+ onMouseDown: (event) => {
1123
+ event.preventDefault();
1124
+ },
1125
+ onClick: () => {
1126
+ toggleFormat(format);
1127
+ },
1128
+ children: /* @__PURE__ */ jsx(Icon, { name: iconName, size: "xs", decorative: true })
1129
+ },
1130
+ format
1131
+ );
1132
+ }) }),
1133
+ /* @__PURE__ */ jsx(
1134
+ "div",
1135
+ {
1136
+ ref: mergeRefs(editorElementRef, forwardedRef),
1137
+ className: "mw-rich-text__editor",
1138
+ "data-rich-text-editor": true,
1139
+ "data-empty": isEditorEmpty ? "true" : void 0,
1140
+ "data-placeholder": props.placeholder,
1141
+ id: kit.a11y.id,
1142
+ role: kit.a11y.role,
1143
+ tabIndex: kit.a11y.tabIndex,
1144
+ "aria-label": kit.a11y.ariaLabel,
1145
+ "aria-labelledby": kit.a11y.ariaLabelledBy,
1146
+ "aria-describedby": kit.a11y.ariaDescribedBy,
1147
+ "aria-invalid": kit.a11y.ariaInvalid,
1148
+ "aria-disabled": kit.a11y.ariaDisabled,
1149
+ "aria-readonly": kit.a11y.ariaReadOnly,
1150
+ "aria-required": kit.a11y.ariaRequired,
1151
+ "aria-multiline": kit.a11y.ariaMultiline,
1152
+ contentEditable: !props.disabled && !props.readOnly,
1153
+ suppressContentEditableWarning: true,
1154
+ onInput: handleInput,
1155
+ onKeyDown: handleKeyDown,
1156
+ onFocus: refreshActiveFormats,
1157
+ onBlur: () => {
1158
+ syncEditorState(editorElementRef.current?.innerHTML ?? "");
1159
+ setActiveFormats([]);
1160
+ }
1161
+ }
1162
+ ),
1163
+ props.name && /* @__PURE__ */ jsx("input", { type: "hidden", name: props.name, value: editorHtml, disabled: props.disabled })
1164
+ ] });
1165
+ });
1166
+ RichText.displayName = "RichText";
340
1167
  function Paragraph(props) {
341
1168
  const { children, className: customClassName, style: customStyle, ...opts } = props;
342
1169
  const theme = useTheme();
@@ -348,62 +1175,37 @@ function Paragraph(props) {
348
1175
  function cx(...parts) {
349
1176
  return parts.filter(Boolean).join(" ");
350
1177
  }
351
- function CheckboxField(props) {
352
- const reactId = React7.useId();
353
- const id = props.id ?? `mw-checkbox-${reactId}`;
354
- const hasDescription = props.description !== void 0;
355
- const hasError = props.error !== void 0;
356
- const descId = hasDescription ? `${id}-desc` : void 0;
357
- const errorId = hasError ? `${id}-error` : void 0;
358
- const describedByParts = [props.ariaDescribedBy, descId, errorId].filter(Boolean);
359
- const mergedDescribedBy = describedByParts.length > 0 ? describedByParts.join(" ") : void 0;
360
- const disabled = props.checkbox.disabled || false;
361
- const invalid = hasError || props.checkbox.invalid || false;
362
- const wrapperClass = cx(
363
- "mw-checkbox-field",
364
- disabled && "mw-checkbox-field--disabled",
365
- invalid && "mw-checkbox-field--invalid"
366
- );
367
- const checkboxProps = {
368
- ...props.checkbox,
369
- id,
370
- invalid
371
- };
372
- if (mergedDescribedBy) {
373
- checkboxProps.ariaDescribedBy = mergedDescribedBy;
374
- }
375
- return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
376
- /* @__PURE__ */ jsxs("div", { className: "mw-checkbox-field__row", children: [
377
- /* @__PURE__ */ jsx(Checkbox, { ...checkboxProps }),
378
- /* @__PURE__ */ jsx("label", { className: "mw-checkbox-field__label", htmlFor: id, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) })
379
- ] }),
380
- hasDescription && /* @__PURE__ */ jsx("div", { className: "mw-checkbox-field__description", id: descId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.description }) }),
381
- hasError && /* @__PURE__ */ jsx("div", { className: "mw-checkbox-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
382
- ] });
383
- }
384
- function cx2(...parts) {
385
- return parts.filter(Boolean).join(" ");
1178
+ function hasTextContent(value) {
1179
+ return value !== void 0 && value.trim().length > 0;
386
1180
  }
387
1181
  function InputField(props) {
388
- const reactId = React7.useId();
1182
+ const reactId = React5.useId();
389
1183
  const id = props.id ?? `mw-input-${reactId}`;
390
1184
  const isPasswordField = props.input.type === "password";
391
- const [showPassword, setShowPassword] = React7.useState(false);
1185
+ const [showPassword, setShowPassword] = React5.useState(false);
392
1186
  const isSearchField = props.input.type === "search";
393
- const [searchValue, setSearchValue] = React7.useState(
1187
+ const [searchValue, setSearchValue] = React5.useState(
394
1188
  props.input.value || props.input.defaultValue || ""
395
1189
  );
396
1190
  const hasSearchValue = isSearchField && (props.input.value !== void 0 ? String(props.input.value).length > 0 : String(searchValue).length > 0);
397
- const hasHelperText = props.helperText !== void 0;
398
- const hasError = props.error !== void 0;
399
- const helperTextId = hasHelperText ? `${id}-helper` : void 0;
400
- const errorId = hasError ? `${id}-error` : void 0;
401
- const describedByParts = [props.ariaDescribedBy, helperTextId, errorId].filter(Boolean);
402
- const mergedDescribedBy = describedByParts.length > 0 ? describedByParts.join(" ") : void 0;
1191
+ const hasHelperText = hasTextContent(props.helperText);
1192
+ const hasError = hasTextContent(props.error);
1193
+ const {
1194
+ helperTextId,
1195
+ errorId,
1196
+ describedBy: mergedDescribedBy
1197
+ } = buildInputFieldA11yIds({
1198
+ id,
1199
+ hasHelperText,
1200
+ hasError,
1201
+ externalDescribedBy: props.ariaDescribedBy
1202
+ });
403
1203
  const disabled = props.input.disabled || false;
404
1204
  const readOnly = props.input.readOnly || false;
405
1205
  const invalid = hasError || props.input.invalid || false;
406
- const wrapperClass = cx2(
1206
+ const showSearchClearButton = hasSearchValue && !disabled && !readOnly;
1207
+ const showSearchIcon = isSearchField && !showSearchClearButton;
1208
+ const wrapperClass = cx(
407
1209
  "mw-input-field",
408
1210
  disabled && "mw-input-field--disabled",
409
1211
  invalid && "mw-input-field--invalid",
@@ -440,8 +1242,9 @@ function InputField(props) {
440
1242
  return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
441
1243
  /* @__PURE__ */ jsx("label", { className: "mw-input-field__label", htmlFor: id, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) }),
442
1244
  /* @__PURE__ */ jsxs("div", { className: "mw-input-field__input-wrapper", children: [
1245
+ props.leadingSymbol && /* @__PURE__ */ jsx("span", { className: "mw-input-field__leading-symbol", "aria-hidden": "true", children: props.leadingSymbol }),
443
1246
  /* @__PURE__ */ jsx(Input, { ...inputProps }),
444
- isPasswordField && /* @__PURE__ */ jsx(
1247
+ isPasswordField && !disabled && /* @__PURE__ */ jsx(
445
1248
  "button",
446
1249
  {
447
1250
  type: "button",
@@ -452,7 +1255,8 @@ function InputField(props) {
452
1255
  children: /* @__PURE__ */ jsx(Icon, { name: showPassword ? "eyeOff" : "eye", size: "xs", decorative: true })
453
1256
  }
454
1257
  ),
455
- hasSearchValue && /* @__PURE__ */ jsx(
1258
+ showSearchIcon && /* @__PURE__ */ jsx("span", { className: "mw-input-field__search-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Icon, { name: "search", size: "xs", decorative: true }) }),
1259
+ showSearchClearButton && /* @__PURE__ */ jsx(
456
1260
  "button",
457
1261
  {
458
1262
  type: "button",
@@ -468,61 +1272,2956 @@ function InputField(props) {
468
1272
  hasError && /* @__PURE__ */ jsx("div", { className: "mw-input-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
469
1273
  ] });
470
1274
  }
471
- function SearchField(props) {
472
- const enhancedInput = {
473
- ...props.input,
474
- type: "search",
475
- inputMode: "search"
476
- };
477
- return /* @__PURE__ */ jsx("div", { "data-purpose": "search", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
1275
+ function cx2(...parts) {
1276
+ return parts.filter(Boolean).join(" ");
478
1277
  }
479
- function PasswordField(props) {
480
- const { autoComplete = "current-password", ...restProps } = props;
481
- const enhancedInput = {
482
- ...props.input,
483
- type: "password",
484
- autoComplete
485
- };
486
- return /* @__PURE__ */ jsx("div", { "data-purpose": "password", children: /* @__PURE__ */ jsx(InputField, { ...restProps, input: enhancedInput }) });
1278
+ function hasTextContent2(value) {
1279
+ return value !== void 0 && value.trim().length > 0;
487
1280
  }
488
- function EmailField(props) {
489
- const enhancedInput = {
490
- ...props.input,
491
- type: "email",
492
- inputMode: "email",
493
- autoComplete: "email"
1281
+ function InputOtp(props) {
1282
+ const reactId = React5.useId();
1283
+ const id = props.id ?? `mw-input-otp-${reactId}`;
1284
+ const otpLength = Math.max(1, props.length ?? 6);
1285
+ const hasHelperText = hasTextContent2(props.helperText);
1286
+ const hasError = hasTextContent2(props.error);
1287
+ const invalid = hasError || props.invalid === true;
1288
+ const isControlled = props.value !== void 0;
1289
+ const [uncontrolledValue, setUncontrolledValue] = React5.useState(() => {
1290
+ return sanitizeInputOtpValue(props.defaultValue, otpLength);
1291
+ });
1292
+ const currentValue = sanitizeInputOtpValue(
1293
+ isControlled ? props.value : uncontrolledValue,
1294
+ otpLength
1295
+ );
1296
+ const {
1297
+ helperTextId,
1298
+ errorId,
1299
+ describedBy: mergedDescribedBy
1300
+ } = buildInputFieldA11yIds({
1301
+ id,
1302
+ hasHelperText,
1303
+ hasError,
1304
+ externalDescribedBy: props.ariaDescribedBy
1305
+ });
1306
+ const recipeOptions = {
1307
+ id,
1308
+ value: currentValue,
1309
+ length: otpLength,
1310
+ invalid
494
1311
  };
495
- return /* @__PURE__ */ jsx("div", { "data-purpose": "email", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
496
- }
497
- function PhoneField(props) {
498
- const enhancedInput = {
499
- ...props.input,
500
- type: "tel",
501
- inputMode: "tel",
502
- autoComplete: "tel"
1312
+ if (props.name) {
1313
+ recipeOptions.name = props.name;
1314
+ }
1315
+ if (props.placeholderCharacter) {
1316
+ recipeOptions.placeholderCharacter = props.placeholderCharacter;
1317
+ }
1318
+ if (props.disabled) {
1319
+ recipeOptions.disabled = true;
1320
+ }
1321
+ if (props.readOnly) {
1322
+ recipeOptions.readOnly = true;
1323
+ }
1324
+ if (props.required) {
1325
+ recipeOptions.required = true;
1326
+ }
1327
+ if (mergedDescribedBy) {
1328
+ recipeOptions.describedBy = mergedDescribedBy;
1329
+ }
1330
+ if (props.ariaLabel) {
1331
+ recipeOptions.ariaLabel = props.ariaLabel;
1332
+ }
1333
+ const kit = createInputOtpRecipe(recipeOptions);
1334
+ const className = cx2(kit.className, props.className);
1335
+ const style = kit.vars;
1336
+ const handleChange = (event) => {
1337
+ const nextValue = sanitizeInputOtpValue(event.target.value, otpLength);
1338
+ if (!isControlled) {
1339
+ setUncontrolledValue(nextValue);
1340
+ }
1341
+ props.onValueChange?.(nextValue);
503
1342
  };
504
- return /* @__PURE__ */ jsx("div", { "data-purpose": "phone", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
1343
+ return /* @__PURE__ */ jsxs(
1344
+ "div",
1345
+ {
1346
+ className,
1347
+ style,
1348
+ "data-component": "input-otp",
1349
+ "data-invalid": invalid ? "true" : void 0,
1350
+ "data-disabled": props.disabled ? "true" : void 0,
1351
+ children: [
1352
+ /* @__PURE__ */ jsx("label", { className: "mw-input-otp__label", htmlFor: id, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) }),
1353
+ /* @__PURE__ */ jsxs("div", { className: "mw-input-otp__cells", children: [
1354
+ kit.displayCells.map((displayCell) => /* @__PURE__ */ jsx(
1355
+ "span",
1356
+ {
1357
+ className: cx2("mw-input-otp__cell", displayCell.filled && "mw-input-otp__cell--filled"),
1358
+ "aria-hidden": "true",
1359
+ children: displayCell.character
1360
+ },
1361
+ displayCell.key
1362
+ )),
1363
+ /* @__PURE__ */ jsx(
1364
+ "input",
1365
+ {
1366
+ id: kit.a11y.id,
1367
+ className: "mw-input-otp__input",
1368
+ type: "text",
1369
+ name: kit.a11y.name,
1370
+ inputMode: kit.a11y.inputMode,
1371
+ autoComplete: kit.a11y.autoComplete,
1372
+ maxLength: kit.a11y.maxLength,
1373
+ pattern: kit.a11y.pattern,
1374
+ disabled: kit.a11y.disabled,
1375
+ readOnly: kit.a11y.readOnly,
1376
+ required: kit.a11y.required,
1377
+ "aria-label": kit.a11y.ariaLabel,
1378
+ "aria-invalid": kit.a11y.ariaInvalid,
1379
+ "aria-describedby": kit.a11y.ariaDescribedBy,
1380
+ value: kit.displayValue,
1381
+ onChange: handleChange
1382
+ }
1383
+ )
1384
+ ] }),
1385
+ hasError ? /* @__PURE__ */ jsx("div", { className: "mw-input-otp__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) }) : hasHelperText ? /* @__PURE__ */ jsx("div", { className: "mw-input-otp__helper", id: helperTextId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.helperText }) }) : null
1386
+ ]
1387
+ }
1388
+ );
505
1389
  }
506
- function URLField(props) {
507
- const enhancedInput = {
508
- ...props.input,
509
- type: "url",
510
- inputMode: "url",
511
- autoComplete: "url"
512
- };
513
- return /* @__PURE__ */ jsx("div", { "data-purpose": "url", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
1390
+ function cx3(...parts) {
1391
+ return parts.filter(Boolean).join(" ");
514
1392
  }
515
- function CurrencyField(props) {
516
- const { currency, ...restProps } = props;
517
- const enhancedInput = {
518
- ...props.input,
519
- type: "text",
520
- inputMode: "decimal"
1393
+ function hasTextContent3(value) {
1394
+ return value !== void 0 && value.trim().length > 0;
1395
+ }
1396
+ function getInitialSelectValue2(props) {
1397
+ if (props.value !== void 0) {
1398
+ return props.value;
1399
+ }
1400
+ if (props.defaultValue !== void 0) {
1401
+ return props.defaultValue;
1402
+ }
1403
+ if (props.placeholder !== void 0) {
1404
+ return "";
1405
+ }
1406
+ return props.options[0]?.value ?? "";
1407
+ }
1408
+ function getFirstEnabledOptionIndex(options) {
1409
+ return options.findIndex((option) => !option.disabled);
1410
+ }
1411
+ function getLastEnabledOptionIndex(options) {
1412
+ for (let index = options.length - 1; index >= 0; index -= 1) {
1413
+ if (!options[index]?.disabled) {
1414
+ return index;
1415
+ }
1416
+ }
1417
+ return -1;
1418
+ }
1419
+ function getSelectedOptionIndex(options, value) {
1420
+ return options.findIndex((option) => option.value === value && !option.disabled);
1421
+ }
1422
+ function getInitialActiveOptionIndex(options, value) {
1423
+ const selectedIndex = getSelectedOptionIndex(options, value);
1424
+ if (selectedIndex !== -1) {
1425
+ return selectedIndex;
1426
+ }
1427
+ return getFirstEnabledOptionIndex(options);
1428
+ }
1429
+ function getNextEnabledOptionIndex(options, currentIndex, direction) {
1430
+ if (options.length === 0) {
1431
+ return -1;
1432
+ }
1433
+ let nextIndex = currentIndex;
1434
+ for (let attempts = 0; attempts < options.length; attempts += 1) {
1435
+ nextIndex = (nextIndex + direction + options.length) % options.length;
1436
+ if (!options[nextIndex]?.disabled) {
1437
+ return nextIndex;
1438
+ }
1439
+ }
1440
+ return currentIndex;
1441
+ }
1442
+ function MarwesSelectFieldControl(props) {
1443
+ const { id, select } = props;
1444
+ const listboxId = `${id}-listbox`;
1445
+ const isControlled = select.value !== void 0;
1446
+ const [internalValue, setInternalValue] = React5.useState(() => getInitialSelectValue2(select));
1447
+ const value = isControlled ? select.value ?? "" : internalValue;
1448
+ const [open, setOpen] = React5.useState(false);
1449
+ const [activeIndex, setActiveIndex] = React5.useState(
1450
+ () => getInitialActiveOptionIndex(select.options, value)
1451
+ );
1452
+ const rootRef = React5.useRef(null);
1453
+ const buttonRef = React5.useRef(null);
1454
+ const selectedOption = select.options.find((option) => option.value === value) ?? (select.placeholder === void 0 ? select.options[0] : void 0);
1455
+ const placeholderSelected = select.placeholder !== void 0 && value === "";
1456
+ const displayText = placeholderSelected ? select.placeholder : selectedOption?.label ?? "";
1457
+ React5.useEffect(() => {
1458
+ if (!open) {
1459
+ return;
1460
+ }
1461
+ function handlePointerDown(event) {
1462
+ if (rootRef.current?.contains(event.target)) {
1463
+ return;
1464
+ }
1465
+ setOpen(false);
1466
+ }
1467
+ document.addEventListener("pointerdown", handlePointerDown);
1468
+ return () => {
1469
+ document.removeEventListener("pointerdown", handlePointerDown);
1470
+ };
1471
+ }, [open]);
1472
+ React5.useEffect(() => {
1473
+ if (!open) {
1474
+ return;
1475
+ }
1476
+ setActiveIndex(getInitialActiveOptionIndex(select.options, value));
1477
+ }, [open, select.options, value]);
1478
+ React5.useEffect(() => {
1479
+ if (!select.disabled) {
1480
+ return;
1481
+ }
1482
+ setOpen(false);
1483
+ }, [select.disabled]);
1484
+ const commitValue = (nextValue) => {
1485
+ if (!isControlled) {
1486
+ setInternalValue(nextValue);
1487
+ }
1488
+ select.onValueChange?.(nextValue);
521
1489
  };
522
- const helperText = currency ? props.helperText ? `${props.helperText} (${currency})` : `Amount in ${currency}` : props.helperText;
523
- return /* @__PURE__ */ jsx("div", { "data-purpose": "currency", "data-currency": currency, children: /* @__PURE__ */ jsx(InputField, { ...restProps, input: enhancedInput, helperText: helperText || "" }) });
1490
+ const selectOptionAtIndex = (index) => {
1491
+ const option = select.options[index];
1492
+ if (!option || option.disabled) {
1493
+ return;
1494
+ }
1495
+ commitValue(option.value);
1496
+ setOpen(false);
1497
+ buttonRef.current?.focus();
1498
+ };
1499
+ const handleKeyDown = (event) => {
1500
+ if (select.disabled) {
1501
+ return;
1502
+ }
1503
+ switch (event.key) {
1504
+ case "ArrowDown": {
1505
+ event.preventDefault();
1506
+ if (!open) {
1507
+ setOpen(true);
1508
+ setActiveIndex(getInitialActiveOptionIndex(select.options, value));
1509
+ return;
1510
+ }
1511
+ setActiveIndex((currentIndex) => getNextEnabledOptionIndex(select.options, currentIndex, 1));
1512
+ return;
1513
+ }
1514
+ case "ArrowUp": {
1515
+ event.preventDefault();
1516
+ if (!open) {
1517
+ setOpen(true);
1518
+ setActiveIndex(getInitialActiveOptionIndex(select.options, value));
1519
+ return;
1520
+ }
1521
+ setActiveIndex(
1522
+ (currentIndex) => getNextEnabledOptionIndex(select.options, currentIndex, -1)
1523
+ );
1524
+ return;
1525
+ }
1526
+ case "Home": {
1527
+ if (!open) {
1528
+ return;
1529
+ }
1530
+ event.preventDefault();
1531
+ setActiveIndex(getFirstEnabledOptionIndex(select.options));
1532
+ return;
1533
+ }
1534
+ case "End": {
1535
+ if (!open) {
1536
+ return;
1537
+ }
1538
+ event.preventDefault();
1539
+ setActiveIndex(getLastEnabledOptionIndex(select.options));
1540
+ return;
1541
+ }
1542
+ case "Enter":
1543
+ case " ": {
1544
+ event.preventDefault();
1545
+ if (!open) {
1546
+ setOpen(true);
1547
+ setActiveIndex(getInitialActiveOptionIndex(select.options, value));
1548
+ return;
1549
+ }
1550
+ if (activeIndex !== -1) {
1551
+ selectOptionAtIndex(activeIndex);
1552
+ }
1553
+ return;
1554
+ }
1555
+ case "Escape": {
1556
+ if (!open) {
1557
+ return;
1558
+ }
1559
+ event.preventDefault();
1560
+ setOpen(false);
1561
+ return;
1562
+ }
1563
+ case "Tab": {
1564
+ setOpen(false);
1565
+ return;
1566
+ }
1567
+ default:
1568
+ return;
1569
+ }
1570
+ };
1571
+ return /* @__PURE__ */ jsxs(
1572
+ "div",
1573
+ {
1574
+ ref: rootRef,
1575
+ className: cx3("mw-select-field__control", open && "mw-select-field__control--open"),
1576
+ children: [
1577
+ /* @__PURE__ */ jsxs(
1578
+ "button",
1579
+ {
1580
+ ref: buttonRef,
1581
+ id,
1582
+ type: "button",
1583
+ className: cx3(
1584
+ "mw-select-field__trigger",
1585
+ placeholderSelected && "mw-select-field__trigger--placeholder",
1586
+ select.invalid && "is-invalid",
1587
+ open && "mw-select-field__trigger--open"
1588
+ ),
1589
+ role: "combobox",
1590
+ "aria-controls": listboxId,
1591
+ "aria-expanded": open,
1592
+ "aria-haspopup": "listbox",
1593
+ "aria-describedby": select.describedBy,
1594
+ "aria-invalid": select.invalid ? "true" : void 0,
1595
+ "aria-required": select.required ? "true" : void 0,
1596
+ "aria-activedescendant": open && activeIndex !== -1 ? `${id}-option-${activeIndex}` : void 0,
1597
+ disabled: select.disabled,
1598
+ "data-placeholder-selected": placeholderSelected ? "true" : void 0,
1599
+ onClick: () => {
1600
+ if (select.disabled) {
1601
+ return;
1602
+ }
1603
+ setOpen((currentOpen) => !currentOpen);
1604
+ },
1605
+ onKeyDown: handleKeyDown,
1606
+ children: [
1607
+ /* @__PURE__ */ jsx("span", { className: "mw-select-field__trigger-text", children: displayText }),
1608
+ /* @__PURE__ */ jsx(SelectArrowIcon, { className: "mw-select-field__trigger-icon" })
1609
+ ]
1610
+ }
1611
+ ),
1612
+ select.name ? /* @__PURE__ */ jsx(
1613
+ "input",
1614
+ {
1615
+ "aria-hidden": "true",
1616
+ className: "mw-select-field__proxy-input",
1617
+ name: select.name,
1618
+ type: "hidden",
1619
+ value,
1620
+ readOnly: true
1621
+ }
1622
+ ) : null,
1623
+ open ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("div", { className: "mw-select-field__list", id: listboxId, role: "listbox", tabIndex: -1, children: select.options.map((option, optionIndex) => {
1624
+ const selected = option.value === value;
1625
+ const active = optionIndex === activeIndex;
1626
+ return /* @__PURE__ */ jsxs(
1627
+ "div",
1628
+ {
1629
+ id: `${id}-option-${optionIndex}`,
1630
+ className: cx3(
1631
+ "mw-select-field__option",
1632
+ active && "mw-select-field__option--active",
1633
+ selected && "mw-select-field__option--selected",
1634
+ option.disabled && "mw-select-field__option--disabled"
1635
+ ),
1636
+ role: "option",
1637
+ "aria-selected": selected,
1638
+ "aria-disabled": option.disabled ? "true" : void 0,
1639
+ tabIndex: -1,
1640
+ onClick: () => selectOptionAtIndex(optionIndex),
1641
+ onKeyDown: (event) => {
1642
+ if (option.disabled) {
1643
+ return;
1644
+ }
1645
+ if (event.key === "Enter" || event.key === " ") {
1646
+ event.preventDefault();
1647
+ selectOptionAtIndex(optionIndex);
1648
+ }
1649
+ },
1650
+ onMouseDown: (event) => event.preventDefault(),
1651
+ onMouseEnter: () => {
1652
+ if (!option.disabled) {
1653
+ setActiveIndex(optionIndex);
1654
+ }
1655
+ },
1656
+ children: [
1657
+ /* @__PURE__ */ jsx("span", { className: "mw-select-field__option-label", children: option.label }),
1658
+ selected ? /* @__PURE__ */ jsx(
1659
+ Icon,
1660
+ {
1661
+ className: "mw-select-field__option-check",
1662
+ name: IconName.Check,
1663
+ size: "xs",
1664
+ decorative: true
1665
+ }
1666
+ ) : null
1667
+ ]
1668
+ },
1669
+ option.value
1670
+ );
1671
+ }) }) }) : null
1672
+ ]
1673
+ }
1674
+ );
1675
+ }
1676
+ function SelectField(props) {
1677
+ const reactId = React5.useId();
1678
+ const id = props.id ?? `mw-select-${reactId}`;
1679
+ const mode = resolveSelectMode(props.select);
1680
+ const hasHelperText = hasTextContent3(props.helperText);
1681
+ const hasError = hasTextContent3(props.error);
1682
+ const {
1683
+ helperTextId,
1684
+ errorId,
1685
+ describedBy: mergedDescribedBy
1686
+ } = buildInputFieldA11yIds({
1687
+ id,
1688
+ hasHelperText,
1689
+ hasError,
1690
+ externalDescribedBy: props.ariaDescribedBy
1691
+ });
1692
+ const disabled = props.select.disabled || false;
1693
+ const invalid = hasError || props.select.invalid || false;
1694
+ const wrapperClass = cx3(
1695
+ "mw-input-field",
1696
+ "mw-input-field--select",
1697
+ mode === "marwes" && "mw-input-field--select-marwes",
1698
+ disabled && "mw-input-field--disabled",
1699
+ invalid && "mw-input-field--invalid"
1700
+ );
1701
+ const selectProps = {
1702
+ ...props.select,
1703
+ id,
1704
+ invalid
1705
+ };
1706
+ if (mergedDescribedBy) {
1707
+ selectProps.describedBy = mergedDescribedBy;
1708
+ }
1709
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
1710
+ /* @__PURE__ */ jsx("label", { className: "mw-input-field__label", htmlFor: id, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) }),
1711
+ /* @__PURE__ */ jsx("div", { className: "mw-input-field__input-wrapper", children: mode === "native" ? /* @__PURE__ */ jsx(Select, { ...selectProps, native: true }) : /* @__PURE__ */ jsx(MarwesSelectFieldControl, { id, select: selectProps }) }),
1712
+ hasHelperText && !hasError && /* @__PURE__ */ jsx("div", { className: "mw-input-field__helper", id: helperTextId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.helperText }) }),
1713
+ hasError && /* @__PURE__ */ jsx("div", { className: "mw-input-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
1714
+ ] });
1715
+ }
1716
+ function cx4(...parts) {
1717
+ return parts.filter(Boolean).join(" ");
1718
+ }
1719
+ function hasTextContent4(value) {
1720
+ return value !== void 0 && value.trim().length > 0;
1721
+ }
1722
+ function TextareaField(props) {
1723
+ const reactId = React5.useId();
1724
+ const id = props.id ?? `mw-textarea-${reactId}`;
1725
+ const hasHelperText = hasTextContent4(props.helperText);
1726
+ const hasError = hasTextContent4(props.error);
1727
+ const {
1728
+ helperTextId,
1729
+ errorId,
1730
+ describedBy: mergedDescribedBy
1731
+ } = buildInputFieldA11yIds({
1732
+ id,
1733
+ hasHelperText,
1734
+ hasError,
1735
+ externalDescribedBy: props.ariaDescribedBy
1736
+ });
1737
+ const disabled = props.textarea.disabled || false;
1738
+ const readOnly = props.textarea.readOnly || false;
1739
+ const invalid = hasError || props.textarea.invalid || false;
1740
+ const wrapperClass = cx4(
1741
+ "mw-input-field",
1742
+ "mw-input-field--textarea",
1743
+ disabled && "mw-input-field--disabled",
1744
+ invalid && "mw-input-field--invalid",
1745
+ readOnly && "mw-input-field--readonly"
1746
+ );
1747
+ const textareaProps = {
1748
+ ...props.textarea,
1749
+ id,
1750
+ invalid
1751
+ };
1752
+ if (mergedDescribedBy) {
1753
+ textareaProps.describedBy = mergedDescribedBy;
1754
+ }
1755
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
1756
+ /* @__PURE__ */ jsx("label", { className: "mw-input-field__label", htmlFor: id, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) }),
1757
+ /* @__PURE__ */ jsx("div", { className: "mw-input-field__input-wrapper", children: /* @__PURE__ */ jsx(Textarea, { ...textareaProps }) }),
1758
+ hasHelperText && !hasError && /* @__PURE__ */ jsx("div", { className: "mw-input-field__helper", id: helperTextId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.helperText }) }),
1759
+ hasError && /* @__PURE__ */ jsx("div", { className: "mw-input-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
1760
+ ] });
1761
+ }
1762
+ function cx5(...parts) {
1763
+ return parts.filter(Boolean).join(" ");
1764
+ }
1765
+ function hasTextContent5(value) {
1766
+ return value !== void 0 && value.trim().length > 0;
1767
+ }
1768
+ function RichTextField(props) {
1769
+ const reactId = React5.useId();
1770
+ const id = props.id ?? `mw-rich-text-${reactId}`;
1771
+ const editorRef = React5.useRef(null);
1772
+ const hasHelperText = hasTextContent5(props.helperText);
1773
+ const hasError = hasTextContent5(props.error);
1774
+ const { labelId, helperTextId, errorId, describedBy } = buildRichTextFieldA11yIds({
1775
+ id,
1776
+ hasHelperText,
1777
+ hasError,
1778
+ externalDescribedBy: props.ariaDescribedBy
1779
+ });
1780
+ const disabled = props.editor.disabled || false;
1781
+ const readOnly = props.editor.readOnly || false;
1782
+ const invalid = hasError || props.editor.invalid || false;
1783
+ const wrapperClass = cx5(
1784
+ "mw-input-field",
1785
+ "mw-input-field--rich-text",
1786
+ disabled && "mw-input-field--disabled",
1787
+ invalid && "mw-input-field--invalid",
1788
+ readOnly && "mw-input-field--readonly"
1789
+ );
1790
+ const editorProps = {
1791
+ ...props.editor,
1792
+ id,
1793
+ invalid,
1794
+ labelledBy: labelId
1795
+ };
1796
+ if (describedBy) {
1797
+ editorProps.describedBy = describedBy;
1798
+ }
1799
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
1800
+ /* @__PURE__ */ jsx(
1801
+ "button",
1802
+ {
1803
+ type: "button",
1804
+ className: "mw-input-field__label",
1805
+ id: labelId,
1806
+ onClick: () => {
1807
+ editorRef.current?.focus();
1808
+ },
1809
+ children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label })
1810
+ }
1811
+ ),
1812
+ /* @__PURE__ */ jsx("div", { className: "mw-input-field__input-wrapper", children: /* @__PURE__ */ jsx(RichText, { ref: editorRef, ...editorProps }) }),
1813
+ hasHelperText && !hasError && /* @__PURE__ */ jsx("div", { className: "mw-input-field__helper", id: helperTextId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.helperText }) }),
1814
+ hasError && /* @__PURE__ */ jsx("div", { className: "mw-input-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
1815
+ ] });
1816
+ }
1817
+ function DropdownField(props) {
1818
+ return /* @__PURE__ */ jsx("div", { "data-purpose": "dropdown", children: /* @__PURE__ */ jsx(
1819
+ SelectField,
1820
+ {
1821
+ ...props,
1822
+ select: {
1823
+ ...props.select,
1824
+ native: props.select.native ?? false
1825
+ }
1826
+ }
1827
+ ) });
1828
+ }
1829
+ function SearchField(props) {
1830
+ const enhancedInput = {
1831
+ ...props.input,
1832
+ type: "search",
1833
+ inputMode: "search"
1834
+ };
1835
+ return /* @__PURE__ */ jsx("div", { "data-purpose": "search", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
1836
+ }
1837
+ function PasswordField(props) {
1838
+ const { autoComplete = "current-password", ...restProps } = props;
1839
+ const enhancedInput = {
1840
+ ...props.input,
1841
+ type: "password",
1842
+ autoComplete
1843
+ };
1844
+ return /* @__PURE__ */ jsx("div", { "data-purpose": "password", children: /* @__PURE__ */ jsx(InputField, { ...restProps, input: enhancedInput }) });
1845
+ }
1846
+ function EmailField(props) {
1847
+ const enhancedInput = {
1848
+ ...props.input,
1849
+ type: "email",
1850
+ inputMode: "email",
1851
+ autoComplete: "email"
1852
+ };
1853
+ return /* @__PURE__ */ jsx("div", { "data-purpose": "email", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
1854
+ }
1855
+ function DateOfBirthField(props) {
1856
+ const enhancedInput = {
1857
+ ...props.input,
1858
+ type: "date",
1859
+ autoComplete: "bday"
1860
+ };
1861
+ return /* @__PURE__ */ jsx("div", { "data-purpose": "date-of-birth", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
1862
+ }
1863
+ function ZipCodeField(props) {
1864
+ const enhancedInput = {
1865
+ ...props.input,
1866
+ type: "text",
1867
+ inputMode: "numeric",
1868
+ autoComplete: "postal-code"
1869
+ };
1870
+ return /* @__PURE__ */ jsx("div", { "data-purpose": "zip-code", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
1871
+ }
1872
+ function PhoneField(props) {
1873
+ const enhancedInput = {
1874
+ ...props.input,
1875
+ type: "tel",
1876
+ inputMode: "tel",
1877
+ autoComplete: "tel"
1878
+ };
1879
+ return /* @__PURE__ */ jsx("div", { "data-purpose": "phone", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
1880
+ }
1881
+ function URLField(props) {
1882
+ const enhancedInput = {
1883
+ ...props.input,
1884
+ type: "url",
1885
+ inputMode: "url",
1886
+ autoComplete: "url"
1887
+ };
1888
+ return /* @__PURE__ */ jsx("div", { "data-purpose": "url", children: /* @__PURE__ */ jsx(InputField, { ...props, input: enhancedInput }) });
1889
+ }
1890
+ function CurrencyField(props) {
1891
+ const { currency, ...restProps } = props;
1892
+ const enhancedInput = {
1893
+ ...props.input,
1894
+ type: "text",
1895
+ inputMode: "decimal",
1896
+ onValueChange: (rawValue) => {
1897
+ const sanitizedValue = sanitizeCurrencyValue(rawValue);
1898
+ props.input?.onValueChange?.(sanitizedValue);
1899
+ }
1900
+ };
1901
+ const helperText = buildCurrencyHelperText(props.helperText, currency);
1902
+ const leadingSymbol = getCurrencySymbol(currency);
1903
+ return /* @__PURE__ */ jsx("div", { "data-purpose": "currency", "data-currency": currency, children: /* @__PURE__ */ jsx(
1904
+ InputField,
1905
+ {
1906
+ ...restProps,
1907
+ input: enhancedInput,
1908
+ helperText: helperText || "",
1909
+ ...leadingSymbol ? { leadingSymbol } : {}
1910
+ }
1911
+ ) });
1912
+ }
1913
+ function renderAvatarContent(content, isOuterShellAccessible, isDecorative) {
1914
+ if (content.type === "image") {
1915
+ return /* @__PURE__ */ jsx(
1916
+ "img",
1917
+ {
1918
+ className: "mw-avatar__image",
1919
+ src: content.src,
1920
+ alt: isDecorative ? "" : content.alt ?? ""
1921
+ }
1922
+ );
1923
+ }
1924
+ if (content.type === "initials") {
1925
+ return /* @__PURE__ */ jsx(
1926
+ "span",
1927
+ {
1928
+ "aria-hidden": isOuterShellAccessible ? "true" : void 0,
1929
+ className: "mw-avatar__initials",
1930
+ children: content.initials
1931
+ }
1932
+ );
1933
+ }
1934
+ return /* @__PURE__ */ jsx(Icon, { name: content.iconName ?? "user", className: "mw-avatar__icon", decorative: true });
1935
+ }
1936
+ function Avatar(props) {
1937
+ const {
1938
+ className,
1939
+ style,
1940
+ dataAttributes,
1941
+ size,
1942
+ type,
1943
+ initials,
1944
+ src,
1945
+ alt,
1946
+ iconName,
1947
+ decorative,
1948
+ ariaLabel,
1949
+ ...nativeSpanProps
1950
+ } = props;
1951
+ const ariaLabelFromNativeProps = typeof nativeSpanProps["aria-label"] === "string" ? nativeSpanProps["aria-label"] : void 0;
1952
+ const avatarOptions = {};
1953
+ if (size !== void 0) avatarOptions.size = size;
1954
+ if (type !== void 0) avatarOptions.type = type;
1955
+ if (initials !== void 0) avatarOptions.initials = initials;
1956
+ if (src !== void 0) avatarOptions.src = src;
1957
+ if (alt !== void 0) avatarOptions.alt = alt;
1958
+ if (iconName !== void 0) avatarOptions.iconName = iconName;
1959
+ if (decorative !== void 0) avatarOptions.decorative = decorative;
1960
+ const resolvedAriaLabel = ariaLabel ?? ariaLabelFromNativeProps;
1961
+ if (resolvedAriaLabel !== void 0) {
1962
+ avatarOptions.ariaLabel = resolvedAriaLabel;
1963
+ }
1964
+ const kit = createAvatarRecipe(avatarOptions);
1965
+ const mergedClassName = [kit.className, className].filter(Boolean).join(" ");
1966
+ const mergedStyle = { ...kit.vars, ...style };
1967
+ const isOuterShellAccessible = kit.a11y.role === "img";
1968
+ const isDecorative = kit.a11y.ariaHidden === true;
1969
+ return /* @__PURE__ */ jsx(
1970
+ "span",
1971
+ {
1972
+ ...nativeSpanProps,
1973
+ ...kit.dataAttributes,
1974
+ ...dataAttributes,
1975
+ className: mergedClassName,
1976
+ style: mergedStyle,
1977
+ role: kit.a11y.role,
1978
+ "aria-hidden": isDecorative ? "true" : void 0,
1979
+ "aria-label": kit.a11y.ariaLabel,
1980
+ children: renderAvatarContent(kit.content, isOuterShellAccessible, isDecorative)
1981
+ }
1982
+ );
1983
+ }
1984
+ function buildAvatarOptions(props) {
1985
+ const avatarOptions = {};
1986
+ if (props.size !== void 0) avatarOptions.size = props.size;
1987
+ if (props.type !== void 0) avatarOptions.type = props.type;
1988
+ if (props.initials !== void 0) avatarOptions.initials = props.initials;
1989
+ if (props.src !== void 0) avatarOptions.src = props.src;
1990
+ if (props.alt !== void 0) avatarOptions.alt = props.alt;
1991
+ if (props.iconName !== void 0) avatarOptions.iconName = props.iconName;
1992
+ if (props.decorative !== void 0) avatarOptions.decorative = props.decorative;
1993
+ const nativeAriaLabel = typeof props["aria-label"] === "string" ? props["aria-label"] : void 0;
1994
+ const resolvedAriaLabel = props.ariaLabel ?? nativeAriaLabel;
1995
+ if (resolvedAriaLabel !== void 0) {
1996
+ avatarOptions.ariaLabel = resolvedAriaLabel;
1997
+ }
1998
+ return avatarOptions;
1999
+ }
2000
+ function resolveAvatarBadgeLabel(avatarOptions, statusLabel) {
2001
+ const avatarKit = createAvatarRecipe(avatarOptions);
2002
+ if (avatarKit.a11y.ariaHidden) {
2003
+ return void 0;
2004
+ }
2005
+ if (avatarKit.content.type === "image") {
2006
+ return avatarKit.content.alt ? `${avatarKit.content.alt}, ${statusLabel}` : statusLabel;
2007
+ }
2008
+ return avatarKit.a11y.ariaLabel ? `${avatarKit.a11y.ariaLabel}, ${statusLabel}` : statusLabel;
2009
+ }
2010
+ function AvatarBadge(props) {
2011
+ const {
2012
+ className,
2013
+ dataAttributes,
2014
+ statusLabel = "Online",
2015
+ decorative,
2016
+ style,
2017
+ size,
2018
+ type,
2019
+ initials,
2020
+ src,
2021
+ alt,
2022
+ iconName,
2023
+ ariaLabel,
2024
+ ...nativeSpanProps
2025
+ } = props;
2026
+ const avatarOptions = buildAvatarOptions(props);
2027
+ const avatarKit = createAvatarRecipe(avatarOptions);
2028
+ const accessibleLabel = resolveAvatarBadgeLabel(avatarOptions, statusLabel);
2029
+ const resolvedSize = avatarKit.dataAttributes["data-size"];
2030
+ const mergedClassName = ["mw-avatar-badge", `mw-avatar-badge--${resolvedSize}`, className].filter(Boolean).join(" ");
2031
+ const innerAvatarProps = { decorative: true };
2032
+ if (size !== void 0) innerAvatarProps.size = size;
2033
+ if (type !== void 0) innerAvatarProps.type = type;
2034
+ if (initials !== void 0) innerAvatarProps.initials = initials;
2035
+ if (src !== void 0) innerAvatarProps.src = src;
2036
+ if (alt !== void 0) innerAvatarProps.alt = alt;
2037
+ if (iconName !== void 0) innerAvatarProps.iconName = iconName;
2038
+ if (ariaLabel !== void 0) innerAvatarProps.ariaLabel = ariaLabel;
2039
+ return /* @__PURE__ */ jsxs(
2040
+ "span",
2041
+ {
2042
+ ...nativeSpanProps,
2043
+ ...dataAttributes,
2044
+ className: mergedClassName,
2045
+ style,
2046
+ "data-component": "avatar-badge",
2047
+ "data-size": resolvedSize,
2048
+ "data-status": "online",
2049
+ role: decorative ? void 0 : "img",
2050
+ "aria-hidden": decorative ? "true" : void 0,
2051
+ "aria-label": decorative ? void 0 : accessibleLabel,
2052
+ children: [
2053
+ /* @__PURE__ */ jsx(Avatar, { ...innerAvatarProps }),
2054
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "mw-avatar-badge__indicator" })
2055
+ ]
2056
+ }
2057
+ );
2058
+ }
2059
+ function AvatarGroup(props) {
2060
+ const {
2061
+ items,
2062
+ overflowCount,
2063
+ overflowLabel,
2064
+ ariaLabel,
2065
+ className,
2066
+ dataAttributes,
2067
+ ...nativeFieldsetProps
2068
+ } = props;
2069
+ const nativeAriaLabel = typeof nativeFieldsetProps["aria-label"] === "string" ? nativeFieldsetProps["aria-label"] : void 0;
2070
+ const groupLabel = ariaLabel ?? nativeAriaLabel ?? "Avatar group";
2071
+ const mergedClassName = ["mw-avatar-group", className].filter(Boolean).join(" ");
2072
+ const shouldRenderOverflowCounter = overflowCount !== void 0 && overflowCount > 0;
2073
+ const resolvedOverflowLabel = overflowLabel ?? `${overflowCount} more people`;
2074
+ return /* @__PURE__ */ jsxs(
2075
+ "fieldset",
2076
+ {
2077
+ ...nativeFieldsetProps,
2078
+ ...dataAttributes,
2079
+ className: mergedClassName,
2080
+ "data-component": "avatar-group",
2081
+ "aria-label": groupLabel,
2082
+ children: [
2083
+ items.map((item, itemIndex) => /* @__PURE__ */ jsx(
2084
+ "span",
2085
+ {
2086
+ className: "mw-avatar-group__item",
2087
+ children: /* @__PURE__ */ jsx(Avatar, { ...item, size: "medium" })
2088
+ },
2089
+ item.id ?? `${itemIndex}-${item.initials ?? item.alt ?? "avatar"}`
2090
+ )),
2091
+ shouldRenderOverflowCounter ? /* @__PURE__ */ jsxs("span", { "aria-label": resolvedOverflowLabel, className: "mw-avatar-group__counter", role: "img", children: [
2092
+ "+",
2093
+ overflowCount
2094
+ ] }) : null
2095
+ ]
2096
+ }
2097
+ );
2098
+ }
2099
+ function ProfileAvatar(props) {
2100
+ return /* @__PURE__ */ jsx(
2101
+ Avatar,
2102
+ {
2103
+ ...props,
2104
+ dataAttributes: {
2105
+ ...props.dataAttributes,
2106
+ ...createPurposeSemanticAttributes("profile")
2107
+ }
2108
+ }
2109
+ );
2110
+ }
2111
+ function PresenceAvatar(props) {
2112
+ return /* @__PURE__ */ jsx(
2113
+ AvatarBadge,
2114
+ {
2115
+ ...props,
2116
+ dataAttributes: {
2117
+ ...props.dataAttributes,
2118
+ ...createPurposeSemanticAttributes("presence")
2119
+ }
2120
+ }
2121
+ );
2122
+ }
2123
+ function TeamAvatarGroup(props) {
2124
+ return /* @__PURE__ */ jsx(
2125
+ AvatarGroup,
2126
+ {
2127
+ ...props,
2128
+ dataAttributes: {
2129
+ ...props.dataAttributes,
2130
+ ...createPurposeSemanticAttributes("team")
2131
+ }
2132
+ }
2133
+ );
2134
+ }
2135
+ function Checkbox(props) {
2136
+ const { onCheckedChange, onChange, ...coreProps } = props;
2137
+ const kit = checkboxRecipe({ ...coreProps });
2138
+ const inputRef = React5.useRef(null);
2139
+ React5.useLayoutEffect(() => {
2140
+ const el = inputRef.current;
2141
+ if (!el) return;
2142
+ el.indeterminate = kit.indeterminate;
2143
+ }, [kit.indeterminate]);
2144
+ const handleChange = (e) => {
2145
+ onChange?.(e);
2146
+ onCheckedChange?.(e.currentTarget.checked);
2147
+ };
2148
+ const { a11y } = kit;
2149
+ return /* @__PURE__ */ jsx(
2150
+ "input",
2151
+ {
2152
+ ref: inputRef,
2153
+ type: "checkbox",
2154
+ className: kit.className,
2155
+ style: kit.vars,
2156
+ id: a11y.id,
2157
+ name: a11y.name,
2158
+ value: a11y.value,
2159
+ disabled: a11y.disabled === true,
2160
+ required: a11y.required === true,
2161
+ "aria-label": a11y.ariaLabel,
2162
+ "aria-labelledby": a11y.ariaLabelledBy,
2163
+ "aria-describedby": a11y.ariaDescribedBy,
2164
+ "aria-checked": a11y.ariaChecked,
2165
+ "aria-invalid": a11y.ariaInvalid === true ? true : void 0,
2166
+ checked: kit.checked,
2167
+ defaultChecked: kit.defaultChecked,
2168
+ onChange: handleChange
2169
+ }
2170
+ );
2171
+ }
2172
+ function cx6(...parts) {
2173
+ return parts.filter(Boolean).join(" ");
2174
+ }
2175
+ function hasContent(value) {
2176
+ if (value === void 0 || value === null || value === false) {
2177
+ return false;
2178
+ }
2179
+ if (typeof value === "string") {
2180
+ return value.trim().length > 0;
2181
+ }
2182
+ return true;
2183
+ }
2184
+ function CheckboxField(props) {
2185
+ const reactId = React5.useId();
2186
+ const id = props.id ?? `mw-checkbox-${reactId}`;
2187
+ const hasDescription = hasContent(props.description);
2188
+ const hasError = hasContent(props.error);
2189
+ const {
2190
+ descriptionId: descId,
2191
+ errorId,
2192
+ describedBy: mergedDescribedBy
2193
+ } = buildCheckboxFieldA11yIds({
2194
+ id,
2195
+ hasDescription,
2196
+ hasError,
2197
+ externalDescribedBy: props.ariaDescribedBy
2198
+ });
2199
+ const disabled = props.checkbox.disabled || false;
2200
+ const invalid = hasError || props.checkbox.invalid || false;
2201
+ const wrapperClass = cx6(
2202
+ "mw-checkbox-field",
2203
+ disabled && "mw-checkbox-field--disabled",
2204
+ invalid && "mw-checkbox-field--invalid"
2205
+ );
2206
+ const checkboxProps = {
2207
+ ...props.checkbox,
2208
+ id,
2209
+ invalid
2210
+ };
2211
+ if (mergedDescribedBy) {
2212
+ checkboxProps.ariaDescribedBy = mergedDescribedBy;
2213
+ }
2214
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
2215
+ /* @__PURE__ */ jsxs("div", { className: "mw-checkbox-field__row", children: [
2216
+ /* @__PURE__ */ jsx(Checkbox, { ...checkboxProps }),
2217
+ /* @__PURE__ */ jsx("label", { className: "mw-checkbox-field__label", htmlFor: id, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) })
2218
+ ] }),
2219
+ hasDescription && /* @__PURE__ */ jsx("div", { className: "mw-checkbox-field__description", id: descId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.description }) }),
2220
+ hasError && /* @__PURE__ */ jsx("div", { className: "mw-checkbox-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
2221
+ ] });
2222
+ }
2223
+ function hasContent2(value) {
2224
+ if (value === void 0 || value === null || value === false) return false;
2225
+ if (typeof value === "string") return value.trim().length > 0;
2226
+ return true;
2227
+ }
2228
+ function cx7(...parts) {
2229
+ return parts.filter(Boolean).join(" ");
2230
+ }
2231
+ function orderSelectedValues(values, options) {
2232
+ const optionValues = new Set(options.map((option) => option.value));
2233
+ const selectedValues = new Set(values);
2234
+ const knownValues = options.map((option) => option.value).filter((value) => selectedValues.has(value));
2235
+ const unknownValues = values.filter((value) => !optionValues.has(value));
2236
+ return [...knownValues, ...unknownValues];
2237
+ }
2238
+ function CheckboxGroupField(props) {
2239
+ const reactId = React5.useId();
2240
+ const id = props.id ?? `mw-checkbox-group-${reactId}`;
2241
+ const hasDescription = hasContent2(props.description);
2242
+ const hasError = hasContent2(props.error);
2243
+ const isInvalid = hasError;
2244
+ const { labelId, descriptionId, errorId, describedBy } = buildCheckboxGroupFieldA11yIds({
2245
+ id,
2246
+ hasDescription,
2247
+ hasError,
2248
+ externalDescribedBy: props.ariaDescribedBy
2249
+ });
2250
+ const isControlled = props.value !== void 0;
2251
+ const [internalValue, setInternalValue] = React5.useState(
2252
+ orderSelectedValues(props.defaultValue ?? [], props.options)
2253
+ );
2254
+ const selectedValues = orderSelectedValues(
2255
+ isControlled ? props.value ?? [] : internalValue,
2256
+ props.options
2257
+ );
2258
+ const selectedValueSet = new Set(selectedValues);
2259
+ const handleToggle = (nextValue) => {
2260
+ const rawNextValue = selectedValueSet.has(nextValue) ? selectedValues.filter((value) => value !== nextValue) : [...selectedValues, nextValue];
2261
+ const orderedNextValue = orderSelectedValues(rawNextValue, props.options);
2262
+ if (!isControlled) {
2263
+ setInternalValue(orderedNextValue);
2264
+ }
2265
+ props.onChange?.(orderedNextValue);
2266
+ };
2267
+ const wrapperClass = cx7(
2268
+ "mw-checkbox-group-field",
2269
+ props.disabled && "mw-checkbox-group-field--disabled",
2270
+ isInvalid && "mw-checkbox-group-field--invalid"
2271
+ );
2272
+ return /* @__PURE__ */ jsxs(
2273
+ "fieldset",
2274
+ {
2275
+ className: wrapperClass,
2276
+ "aria-labelledby": labelId,
2277
+ "aria-describedby": describedBy,
2278
+ "aria-invalid": isInvalid ? true : void 0,
2279
+ "aria-required": props.required ? true : void 0,
2280
+ disabled: props.disabled ? true : void 0,
2281
+ ...props.dataAttributes,
2282
+ children: [
2283
+ /* @__PURE__ */ jsx("legend", { className: "mw-checkbox-group-field__label", id: labelId, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) }),
2284
+ hasDescription && /* @__PURE__ */ jsx("div", { className: "mw-checkbox-group-field__description", id: descriptionId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.description }) }),
2285
+ /* @__PURE__ */ jsx("div", { className: "mw-checkbox-group-field__options", children: props.options.map((option, index) => {
2286
+ const optionId = `${id}-option-${index}`;
2287
+ const isOptionDisabled = props.disabled || option.disabled || false;
2288
+ const checkboxProps = {
2289
+ ...props.checkbox ?? {},
2290
+ id: optionId,
2291
+ value: option.value,
2292
+ checked: selectedValueSet.has(option.value),
2293
+ disabled: isOptionDisabled,
2294
+ invalid: isInvalid,
2295
+ onCheckedChange: () => handleToggle(option.value)
2296
+ };
2297
+ if (props.name !== void 0) {
2298
+ checkboxProps.name = props.name;
2299
+ }
2300
+ if (option.indeterminate !== void 0) {
2301
+ checkboxProps.indeterminate = option.indeterminate;
2302
+ }
2303
+ return /* @__PURE__ */ jsxs(
2304
+ "label",
2305
+ {
2306
+ className: "mw-checkbox-group-field__option",
2307
+ htmlFor: optionId,
2308
+ children: [
2309
+ /* @__PURE__ */ jsx(Checkbox, { ...checkboxProps }),
2310
+ /* @__PURE__ */ jsx(Paragraph, { size: "md", children: option.label })
2311
+ ]
2312
+ },
2313
+ option.value
2314
+ );
2315
+ }) }),
2316
+ hasError && /* @__PURE__ */ jsx("div", { className: "mw-checkbox-group-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
2317
+ ]
2318
+ }
2319
+ );
2320
+ }
2321
+ var Divider = React5.forwardRef((props, ref) => {
2322
+ const { className: customClassName, style: customStyle, ...opts } = props;
2323
+ const kit = createDividerRecipe(opts);
2324
+ const style = { ...kit.vars, ...customStyle };
2325
+ const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
2326
+ return /* @__PURE__ */ jsx("hr", { ref, ...kit.a11y, ...kit.dataAttributes, className, style });
2327
+ });
2328
+ Divider.displayName = "Divider";
2329
+ var Spacing = React5.forwardRef((props, ref) => {
2330
+ const { className: customClassName, scale, size, spacing, style: customStyle } = props;
2331
+ const resolvedSize = spacing ?? size;
2332
+ const kit = createSpacingRecipe({
2333
+ ...resolvedSize !== void 0 ? { size: resolvedSize } : {},
2334
+ ...scale !== void 0 ? { scale } : {}
2335
+ });
2336
+ const style = { ...kit.vars, ...customStyle };
2337
+ const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
2338
+ return /* @__PURE__ */ jsx("div", { ref, ...kit.a11y, ...kit.dataAttributes, className, style });
2339
+ });
2340
+ Spacing.displayName = "Spacing";
2341
+ var Spacer = Spacing;
2342
+ function H1(props) {
2343
+ const { children, className: customClassName, style: customStyle, ...opts } = props;
2344
+ const theme = useTheme();
2345
+ const kit = headingRecipe({ ...opts, level: 1 }, theme);
2346
+ const style = { ...kit.vars, ...customStyle };
2347
+ const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
2348
+ return /* @__PURE__ */ jsx("h1", { id: kit.a11y.id, "aria-label": kit.a11y.ariaLabel, className, style, children });
2349
+ }
2350
+ function H2(props) {
2351
+ const { children, className: customClassName, style: customStyle, ...opts } = props;
2352
+ const theme = useTheme();
2353
+ const kit = headingRecipe({ ...opts, level: 2 }, theme);
2354
+ const style = { ...kit.vars, ...customStyle };
2355
+ const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
2356
+ return /* @__PURE__ */ jsx("h2", { id: kit.a11y.id, "aria-label": kit.a11y.ariaLabel, className, style, children });
2357
+ }
2358
+ function H3(props) {
2359
+ const { children, className: customClassName, style: customStyle, ...opts } = props;
2360
+ const theme = useTheme();
2361
+ const kit = headingRecipe({ ...opts, level: 3 }, theme);
2362
+ const style = { ...kit.vars, ...customStyle };
2363
+ const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
2364
+ return /* @__PURE__ */ jsx("h3", { id: kit.a11y.id, "aria-label": kit.a11y.ariaLabel, className, style, children });
2365
+ }
2366
+ function Card(props) {
2367
+ const { title, children, className, dataAttributes, ...nativeDivProps } = props;
2368
+ const kit = createCardRecipe(dataAttributes ? { dataAttributes } : {});
2369
+ return /* @__PURE__ */ jsxs(
2370
+ "div",
2371
+ {
2372
+ ...nativeDivProps,
2373
+ ...kit.dataAttributes,
2374
+ className: [kit.className, className].filter(Boolean).join(" "),
2375
+ children: [
2376
+ title ? /* @__PURE__ */ jsx("div", { className: "mw-card__header", children: /* @__PURE__ */ jsx("span", { className: "mw-card__title", children: title }) }) : null,
2377
+ /* @__PURE__ */ jsx("div", { className: "mw-card__body", children })
2378
+ ]
2379
+ }
2380
+ );
2381
+ }
2382
+ function ProductCard(props) {
2383
+ return /* @__PURE__ */ jsx(
2384
+ Card,
2385
+ {
2386
+ ...props,
2387
+ dataAttributes: {
2388
+ ...props.dataAttributes,
2389
+ "data-purpose": "product-card"
2390
+ }
2391
+ }
2392
+ );
2393
+ }
2394
+ function ProfileCard(props) {
2395
+ return /* @__PURE__ */ jsx(
2396
+ Card,
2397
+ {
2398
+ ...props,
2399
+ dataAttributes: {
2400
+ ...props.dataAttributes,
2401
+ "data-purpose": "profile-card"
2402
+ }
2403
+ }
2404
+ );
2405
+ }
2406
+ function StatCard(props) {
2407
+ return /* @__PURE__ */ jsx(
2408
+ Card,
2409
+ {
2410
+ ...props,
2411
+ dataAttributes: {
2412
+ ...props.dataAttributes,
2413
+ "data-purpose": "stat-card"
2414
+ }
2415
+ }
2416
+ );
2417
+ }
2418
+ function cx8(...parts) {
2419
+ return parts.filter(Boolean).join(" ");
2420
+ }
2421
+ function Toast(props) {
2422
+ const { children, icon, action, onDismiss, className, id, dataAttributes, ...coreProps } = props;
2423
+ const kit = createToastRecipe(coreProps);
2424
+ const { a11y } = kit;
2425
+ return /* @__PURE__ */ jsxs(
2426
+ "div",
2427
+ {
2428
+ id,
2429
+ className: cx8(kit.className, className),
2430
+ role: a11y.role,
2431
+ "aria-live": a11y.ariaLive,
2432
+ "aria-atomic": "true",
2433
+ ...kit.dataAttributes,
2434
+ ...dataAttributes,
2435
+ children: [
2436
+ icon && /* @__PURE__ */ jsx("span", { className: "mw-toast__icon", "aria-hidden": "true", children: icon }),
2437
+ /* @__PURE__ */ jsxs("div", { className: "mw-toast__body", children: [
2438
+ /* @__PURE__ */ jsx("span", { className: "mw-toast__text", children }),
2439
+ action && /* @__PURE__ */ jsx("span", { className: "mw-toast__action", children: action })
2440
+ ] }),
2441
+ onDismiss && /* @__PURE__ */ jsx(
2442
+ "button",
2443
+ {
2444
+ type: "button",
2445
+ className: "mw-toast__dismiss",
2446
+ "aria-label": "Dismiss",
2447
+ onClick: onDismiss
2448
+ }
2449
+ )
2450
+ ]
2451
+ }
2452
+ );
2453
+ }
2454
+ function getDefaultIcon(iconName) {
2455
+ return /* @__PURE__ */ jsx(Icon, { name: iconName, decorative: true });
2456
+ }
2457
+ function SuccessToast(props) {
2458
+ return /* @__PURE__ */ jsx(
2459
+ Toast,
2460
+ {
2461
+ ...props,
2462
+ variant: props.variant ?? "outline",
2463
+ ariaLive: props.ariaLive ?? "polite",
2464
+ icon: props.icon ?? getDefaultIcon(IconName.Check),
2465
+ dataAttributes: {
2466
+ ...props.dataAttributes,
2467
+ ...createPurposeSemanticAttributes("success-toast")
2468
+ }
2469
+ }
2470
+ );
2471
+ }
2472
+ function ErrorToast(props) {
2473
+ return /* @__PURE__ */ jsx(
2474
+ Toast,
2475
+ {
2476
+ ...props,
2477
+ variant: props.variant ?? "outline",
2478
+ ariaLive: props.ariaLive ?? "assertive",
2479
+ icon: props.icon ?? getDefaultIcon(IconName.XCircle),
2480
+ dataAttributes: {
2481
+ ...props.dataAttributes,
2482
+ ...createPurposeSemanticAttributes("error-toast")
2483
+ }
2484
+ }
2485
+ );
2486
+ }
2487
+ function WarningToast(props) {
2488
+ return /* @__PURE__ */ jsx(
2489
+ Toast,
2490
+ {
2491
+ ...props,
2492
+ variant: props.variant ?? "outline",
2493
+ ariaLive: props.ariaLive ?? "polite",
2494
+ icon: props.icon ?? getDefaultIcon(IconName.AlertTriangle),
2495
+ dataAttributes: {
2496
+ ...props.dataAttributes,
2497
+ ...createPurposeSemanticAttributes("warning-toast")
2498
+ }
2499
+ }
2500
+ );
2501
+ }
2502
+ function InfoToast(props) {
2503
+ return /* @__PURE__ */ jsx(
2504
+ Toast,
2505
+ {
2506
+ ...props,
2507
+ variant: props.variant ?? "outline",
2508
+ ariaLive: props.ariaLive ?? "polite",
2509
+ icon: props.icon ?? getDefaultIcon(IconName.Info),
2510
+ dataAttributes: {
2511
+ ...props.dataAttributes,
2512
+ ...createPurposeSemanticAttributes("info-toast")
2513
+ }
2514
+ }
2515
+ );
2516
+ }
2517
+ function cx9(...parts) {
2518
+ return parts.filter(Boolean).join(" ");
2519
+ }
2520
+ function renderToastByIntent(toast, onDismiss) {
2521
+ const sharedProps = {
2522
+ id: toast.id,
2523
+ children: toast.children
2524
+ };
2525
+ const dismissHandler = onDismiss ? () => onDismiss(toast.id) : void 0;
2526
+ if (toast.icon !== void 0) {
2527
+ sharedProps.icon = toast.icon;
2528
+ }
2529
+ if (toast.action !== void 0) {
2530
+ sharedProps.action = toast.action;
2531
+ }
2532
+ if (dismissHandler) {
2533
+ sharedProps.onDismiss = dismissHandler;
2534
+ }
2535
+ if (toast.className !== void 0) {
2536
+ sharedProps.className = toast.className;
2537
+ }
2538
+ if (toast.variant !== void 0) {
2539
+ sharedProps.variant = toast.variant;
2540
+ }
2541
+ if (toast.ariaLive !== void 0) {
2542
+ sharedProps.ariaLive = toast.ariaLive;
2543
+ }
2544
+ if (toast.dataAttributes !== void 0 || toast.intent !== void 0) {
2545
+ sharedProps.dataAttributes = {
2546
+ ...toast.dataAttributes ?? {},
2547
+ ...toast.intent !== void 0 ? { "data-intent": toast.intent } : {}
2548
+ };
2549
+ }
2550
+ switch (toast.intent) {
2551
+ case "success":
2552
+ return /* @__PURE__ */ jsx(SuccessToast, { ...sharedProps });
2553
+ case "error":
2554
+ return /* @__PURE__ */ jsx(ErrorToast, { ...sharedProps });
2555
+ case "warning":
2556
+ return /* @__PURE__ */ jsx(WarningToast, { ...sharedProps });
2557
+ case "info":
2558
+ return /* @__PURE__ */ jsx(InfoToast, { ...sharedProps });
2559
+ default:
2560
+ return /* @__PURE__ */ jsx(Toast, { ...sharedProps });
2561
+ }
2562
+ }
2563
+ function ToastViewportItem(props) {
2564
+ const timerHandleRef = React5.useRef(null);
2565
+ const timerStartedAtRef = React5.useRef(null);
2566
+ const remainingDurationRef = React5.useRef(null);
2567
+ const pointerInsideRef = React5.useRef(false);
2568
+ const focusInsideRef = React5.useRef(false);
2569
+ const clearDismissTimer = React5.useCallback(() => {
2570
+ if (timerHandleRef.current === null) {
2571
+ return;
2572
+ }
2573
+ window.clearTimeout(timerHandleRef.current);
2574
+ timerHandleRef.current = null;
2575
+ timerStartedAtRef.current = null;
2576
+ }, []);
2577
+ const scheduleDismissTimer = React5.useCallback(
2578
+ (delay) => {
2579
+ if (!props.onDismiss || delay <= 0 || pointerInsideRef.current || focusInsideRef.current || timerHandleRef.current !== null) {
2580
+ return;
2581
+ }
2582
+ timerStartedAtRef.current = Date.now();
2583
+ timerHandleRef.current = window.setTimeout(() => {
2584
+ timerHandleRef.current = null;
2585
+ timerStartedAtRef.current = null;
2586
+ remainingDurationRef.current = 0;
2587
+ props.onDismiss?.(props.toast.id);
2588
+ }, delay);
2589
+ },
2590
+ [props.onDismiss, props.toast.id]
2591
+ );
2592
+ const pauseDismissTimer = React5.useCallback(() => {
2593
+ if (timerHandleRef.current === null || timerStartedAtRef.current === null) {
2594
+ return;
2595
+ }
2596
+ const elapsed = Date.now() - timerStartedAtRef.current;
2597
+ const remainingDuration = remainingDurationRef.current ?? 0;
2598
+ remainingDurationRef.current = Math.max(remainingDuration - elapsed, 0);
2599
+ clearDismissTimer();
2600
+ }, [clearDismissTimer]);
2601
+ const resumeDismissTimer = React5.useCallback(() => {
2602
+ if (pointerInsideRef.current || focusInsideRef.current) {
2603
+ return;
2604
+ }
2605
+ const remainingDuration = remainingDurationRef.current;
2606
+ if (remainingDuration === null || remainingDuration === void 0 || remainingDuration <= 0) {
2607
+ return;
2608
+ }
2609
+ scheduleDismissTimer(remainingDuration);
2610
+ }, [scheduleDismissTimer]);
2611
+ React5.useEffect(() => {
2612
+ clearDismissTimer();
2613
+ pointerInsideRef.current = false;
2614
+ focusInsideRef.current = false;
2615
+ if (!props.onDismiss || props.toast.duration === void 0 || props.toast.duration === null) {
2616
+ remainingDurationRef.current = null;
2617
+ return;
2618
+ }
2619
+ if (props.toast.duration <= 0) {
2620
+ remainingDurationRef.current = 0;
2621
+ return;
2622
+ }
2623
+ remainingDurationRef.current = props.toast.duration;
2624
+ scheduleDismissTimer(props.toast.duration);
2625
+ return () => {
2626
+ clearDismissTimer();
2627
+ };
2628
+ }, [clearDismissTimer, props.onDismiss, props.toast.duration, scheduleDismissTimer]);
2629
+ return /* @__PURE__ */ jsx(
2630
+ "div",
2631
+ {
2632
+ className: "mw-toast-container__item",
2633
+ onMouseEnter: () => {
2634
+ pointerInsideRef.current = true;
2635
+ pauseDismissTimer();
2636
+ },
2637
+ onMouseLeave: () => {
2638
+ pointerInsideRef.current = false;
2639
+ resumeDismissTimer();
2640
+ },
2641
+ onFocusCapture: () => {
2642
+ focusInsideRef.current = true;
2643
+ pauseDismissTimer();
2644
+ },
2645
+ onBlurCapture: (event) => {
2646
+ if (event.currentTarget.contains(event.relatedTarget)) {
2647
+ return;
2648
+ }
2649
+ focusInsideRef.current = false;
2650
+ resumeDismissTimer();
2651
+ },
2652
+ children: renderToastByIntent(props.toast, props.onDismiss)
2653
+ }
2654
+ );
2655
+ }
2656
+ function ToastContainer(props) {
2657
+ const placement = props.placement ?? "top-right";
2658
+ const visibleToasts = props.maxVisible && props.maxVisible > 0 ? props.toasts.slice(-props.maxVisible) : props.toasts;
2659
+ return /* @__PURE__ */ jsx("div", { className: cx9("mw-toast-container", `mw-toast-container--${placement}`, props.className), children: visibleToasts.map((toast) => /* @__PURE__ */ jsx(
2660
+ ToastViewportItem,
2661
+ {
2662
+ toast,
2663
+ ...props.onDismiss ? { onDismiss: props.onDismiss } : {}
2664
+ },
2665
+ toast.id
2666
+ )) });
2667
+ }
2668
+ var ToastContext = React5.createContext(null);
2669
+ function ToastProvider(props) {
2670
+ const [toasts, setToasts] = React5.useState([]);
2671
+ const idRef = React5.useRef(0);
2672
+ const dismiss = React5.useCallback((id) => {
2673
+ setToasts((currentToasts) => {
2674
+ const toast = currentToasts.find((item) => item.id === id);
2675
+ toast?.onDismiss?.();
2676
+ return currentToasts.filter((item) => item.id !== id);
2677
+ });
2678
+ }, []);
2679
+ const clear = React5.useCallback(() => {
2680
+ setToasts((currentToasts) => {
2681
+ for (const toast of currentToasts) {
2682
+ toast.onDismiss?.();
2683
+ }
2684
+ return [];
2685
+ });
2686
+ }, []);
2687
+ const show = React5.useCallback(
2688
+ (toast) => {
2689
+ idRef.current += 1;
2690
+ const id = `mw-toast-${idRef.current}`;
2691
+ setToasts((currentToasts) => [
2692
+ ...currentToasts,
2693
+ {
2694
+ ...toast,
2695
+ id,
2696
+ duration: toast.duration === void 0 ? props.defaultDuration === void 0 ? 4e3 : props.defaultDuration : toast.duration
2697
+ }
2698
+ ]);
2699
+ return id;
2700
+ },
2701
+ [props.defaultDuration]
2702
+ );
2703
+ const value = React5.useMemo(
2704
+ () => ({
2705
+ show,
2706
+ dismiss,
2707
+ clear
2708
+ }),
2709
+ [clear, dismiss, show]
2710
+ );
2711
+ return /* @__PURE__ */ jsxs(ToastContext.Provider, { value, children: [
2712
+ props.children,
2713
+ /* @__PURE__ */ jsx(
2714
+ ToastContainer,
2715
+ {
2716
+ toasts,
2717
+ onDismiss: dismiss,
2718
+ ...props.placement ? { placement: props.placement } : {},
2719
+ ...props.maxVisible !== void 0 ? { maxVisible: props.maxVisible } : {},
2720
+ ...props.className ? { className: props.className } : {}
2721
+ }
2722
+ )
2723
+ ] });
2724
+ }
2725
+ function useToast() {
2726
+ const context = React5.useContext(ToastContext);
2727
+ if (!context) {
2728
+ throw new Error("ToastProvider is missing. Wrap your app in <ToastProvider />.");
2729
+ }
2730
+ return context;
2731
+ }
2732
+ function Tooltip(props) {
2733
+ const { children, className, style, dataAttributes, id, ...nativeSpanProps } = props;
2734
+ const tooltipOptions = {};
2735
+ if (id !== void 0) {
2736
+ tooltipOptions.id = id;
2737
+ }
2738
+ const kit = createTooltipRecipe(tooltipOptions);
2739
+ const mergedClassName = [kit.className, className].filter(Boolean).join(" ");
2740
+ const mergedStyle = { ...kit.vars, ...style };
2741
+ return /* @__PURE__ */ jsx(
2742
+ "span",
2743
+ {
2744
+ ...nativeSpanProps,
2745
+ ...kit.dataAttributes,
2746
+ ...dataAttributes,
2747
+ id: kit.a11y.id,
2748
+ className: mergedClassName,
2749
+ style: mergedStyle,
2750
+ role: kit.a11y.role,
2751
+ children
2752
+ }
2753
+ );
2754
+ }
2755
+ var TOOLTIP_EXIT_DURATION_MS = 160;
2756
+ function cx10(...parts) {
2757
+ return parts.filter(Boolean).join(" ");
2758
+ }
2759
+ function TooltipGroup(props) {
2760
+ const reactId = React5.useId();
2761
+ const {
2762
+ content,
2763
+ icon = IconName.HelpCircle,
2764
+ triggerLabel = "Show tooltip",
2765
+ open,
2766
+ defaultOpen = false,
2767
+ onOpenChange,
2768
+ tooltipId,
2769
+ tooltipClassName,
2770
+ triggerClassName,
2771
+ dataAttributes,
2772
+ className,
2773
+ id,
2774
+ onMouseEnter,
2775
+ onMouseLeave,
2776
+ onFocus,
2777
+ onBlur,
2778
+ onKeyDown,
2779
+ ...nativeSpanProps
2780
+ } = props;
2781
+ const [internalOpen, setInternalOpen] = React5.useState(defaultOpen);
2782
+ const isControlled = open !== void 0;
2783
+ const resolvedOpen = isControlled ? open : internalOpen;
2784
+ const [isTooltipMounted, setIsTooltipMounted] = React5.useState(resolvedOpen);
2785
+ const resolvedTooltipId = tooltipId ?? `${id ?? `mw-tooltip-group-${reactId}`}-tooltip`;
2786
+ React5.useEffect(() => {
2787
+ if (resolvedOpen) {
2788
+ setIsTooltipMounted(true);
2789
+ return;
2790
+ }
2791
+ const timeoutId = window.setTimeout(() => {
2792
+ setIsTooltipMounted(false);
2793
+ }, TOOLTIP_EXIT_DURATION_MS);
2794
+ return () => {
2795
+ window.clearTimeout(timeoutId);
2796
+ };
2797
+ }, [resolvedOpen]);
2798
+ const updateOpen = React5.useCallback(
2799
+ (nextOpen) => {
2800
+ if (resolvedOpen === nextOpen) {
2801
+ return;
2802
+ }
2803
+ if (!isControlled) {
2804
+ setInternalOpen(nextOpen);
2805
+ }
2806
+ onOpenChange?.(nextOpen);
2807
+ },
2808
+ [isControlled, onOpenChange, resolvedOpen]
2809
+ );
2810
+ return /* @__PURE__ */ jsxs(
2811
+ "span",
2812
+ {
2813
+ ...nativeSpanProps,
2814
+ ...dataAttributes,
2815
+ id,
2816
+ className: cx10("mw-tooltip-group", className),
2817
+ "data-component": "tooltip-group",
2818
+ "data-open": resolvedOpen ? "true" : void 0,
2819
+ onMouseEnter: (event) => {
2820
+ onMouseEnter?.(event);
2821
+ updateOpen(true);
2822
+ },
2823
+ onMouseLeave: (event) => {
2824
+ onMouseLeave?.(event);
2825
+ updateOpen(false);
2826
+ },
2827
+ onFocus: (event) => {
2828
+ onFocus?.(event);
2829
+ updateOpen(true);
2830
+ },
2831
+ onBlur: (event) => {
2832
+ onBlur?.(event);
2833
+ const nextFocusedElement = event.relatedTarget;
2834
+ if (nextFocusedElement instanceof Node && event.currentTarget.contains(nextFocusedElement)) {
2835
+ return;
2836
+ }
2837
+ updateOpen(false);
2838
+ },
2839
+ onKeyDown: (event) => {
2840
+ onKeyDown?.(event);
2841
+ if (event.key === "Escape") {
2842
+ updateOpen(false);
2843
+ }
2844
+ },
2845
+ children: [
2846
+ isTooltipMounted ? /* @__PURE__ */ jsx(
2847
+ Tooltip,
2848
+ {
2849
+ id: resolvedTooltipId,
2850
+ className: tooltipClassName,
2851
+ "data-state": resolvedOpen ? "open" : "closed",
2852
+ "aria-hidden": resolvedOpen ? void 0 : "true",
2853
+ children: content
2854
+ }
2855
+ ) : null,
2856
+ /* @__PURE__ */ jsx(
2857
+ "button",
2858
+ {
2859
+ type: "button",
2860
+ className: cx10("mw-tooltip-group__trigger", triggerClassName),
2861
+ "aria-label": triggerLabel,
2862
+ "aria-describedby": resolvedOpen ? resolvedTooltipId : void 0,
2863
+ children: /* @__PURE__ */ jsx(Icon, { name: icon, decorative: true })
2864
+ }
2865
+ )
2866
+ ]
2867
+ }
2868
+ );
2869
+ }
2870
+ function Accordion(props) {
2871
+ const { title, children, className, onToggle, id: idProp, open, disabled } = props;
2872
+ const autoId = React5.useId();
2873
+ const resolvedId = idProp ?? autoId.replace(/:/g, "");
2874
+ const opts = { id: resolvedId };
2875
+ if (open !== void 0) opts.open = open;
2876
+ if (disabled !== void 0) opts.disabled = disabled;
2877
+ const kit = createAccordionRecipe(opts);
2878
+ const { a11y } = kit;
2879
+ function handleTriggerClick() {
2880
+ if (disabled) return;
2881
+ onToggle?.();
2882
+ }
2883
+ return /* @__PURE__ */ jsxs("div", { className: [kit.className, className].filter(Boolean).join(" "), children: [
2884
+ /* @__PURE__ */ jsxs(
2885
+ "button",
2886
+ {
2887
+ id: a11y.triggerId,
2888
+ type: "button",
2889
+ className: "mw-accordion__trigger",
2890
+ "aria-expanded": a11y.ariaExpanded,
2891
+ "aria-controls": a11y.panelId,
2892
+ "aria-disabled": a11y.ariaDisabled,
2893
+ disabled,
2894
+ onClick: handleTriggerClick,
2895
+ children: [
2896
+ /* @__PURE__ */ jsx("span", { className: "mw-accordion__title", children: title }),
2897
+ /* @__PURE__ */ jsx("span", { className: "mw-accordion__icon", "aria-hidden": "true" })
2898
+ ]
2899
+ }
2900
+ ),
2901
+ /* @__PURE__ */ jsx(
2902
+ "section",
2903
+ {
2904
+ id: a11y.panelId,
2905
+ "aria-labelledby": a11y.triggerId,
2906
+ className: "mw-accordion__panel",
2907
+ hidden: !open,
2908
+ children: /* @__PURE__ */ jsx("div", { className: "mw-accordion__content", children })
2909
+ }
2910
+ )
2911
+ ] });
2912
+ }
2913
+ function hasContent3(value) {
2914
+ if (value === void 0 || value === null || value === false) return false;
2915
+ if (typeof value === "string") return value.trim().length > 0;
2916
+ return true;
2917
+ }
2918
+ function cx11(...parts) {
2919
+ return parts.filter(Boolean).join(" ");
2920
+ }
2921
+ function resolveAccordionItemContent(item) {
2922
+ return item.content ?? item.children;
2923
+ }
2924
+ function AccordionField(props) {
2925
+ const reactId = React5.useId();
2926
+ const id = props.id ?? `mw-accordion-field-${reactId}`;
2927
+ const multipleAllowed = props.multiple ?? true;
2928
+ const hasDescription = hasContent3(props.description);
2929
+ const hasError = hasContent3(props.error);
2930
+ const isInvalid = hasError || false;
2931
+ const { labelId, descriptionId, errorId, describedBy } = buildAccordionFieldA11yIds({
2932
+ id,
2933
+ hasDescription,
2934
+ hasError,
2935
+ externalDescribedBy: props.ariaDescribedBy
2936
+ });
2937
+ const isControlled = props.openItems !== void 0;
2938
+ const [internalOpenItems, setInternalOpenItems] = React5.useState(
2939
+ props.defaultOpenItems ?? []
2940
+ );
2941
+ const openItems = isControlled ? props.openItems ?? [] : internalOpenItems;
2942
+ const handleToggle = (itemValue) => {
2943
+ const isCurrentlyOpen = openItems.includes(itemValue);
2944
+ let nextOpenItems;
2945
+ if (isCurrentlyOpen) {
2946
+ nextOpenItems = openItems.filter((v) => v !== itemValue);
2947
+ } else if (multipleAllowed) {
2948
+ nextOpenItems = [...openItems, itemValue];
2949
+ } else {
2950
+ nextOpenItems = [itemValue];
2951
+ }
2952
+ if (!isControlled) {
2953
+ setInternalOpenItems(nextOpenItems);
2954
+ }
2955
+ props.onOpenItemsChange?.(nextOpenItems);
2956
+ };
2957
+ const wrapperClass = cx11(
2958
+ "mw-accordion-field",
2959
+ props.disabled && "mw-accordion-field--disabled",
2960
+ isInvalid && "mw-accordion-field--invalid"
2961
+ );
2962
+ return /* @__PURE__ */ jsxs(
2963
+ "fieldset",
2964
+ {
2965
+ className: wrapperClass,
2966
+ "aria-labelledby": labelId,
2967
+ "aria-describedby": describedBy,
2968
+ "aria-invalid": isInvalid ? true : void 0,
2969
+ ...props.dataAttributes,
2970
+ children: [
2971
+ /* @__PURE__ */ jsx("legend", { className: "mw-accordion-field__label", id: labelId, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) }),
2972
+ /* @__PURE__ */ jsx("div", { className: "mw-accordion-field__items", children: props.items.map((item) => {
2973
+ const isDisabled = props.disabled || item.disabled || false;
2974
+ const isOpen = openItems.includes(item.value);
2975
+ return /* @__PURE__ */ jsx(
2976
+ Accordion,
2977
+ {
2978
+ id: `${id}-item-${item.value}`,
2979
+ title: item.title,
2980
+ open: isOpen,
2981
+ disabled: isDisabled,
2982
+ onToggle: () => handleToggle(item.value),
2983
+ children: resolveAccordionItemContent(item)
2984
+ },
2985
+ item.value
2986
+ );
2987
+ }) }),
2988
+ hasDescription && /* @__PURE__ */ jsx("div", { className: "mw-accordion-field__description", id: descriptionId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.description }) }),
2989
+ hasError && /* @__PURE__ */ jsx("div", { className: "mw-accordion-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
2990
+ ]
2991
+ }
2992
+ );
2993
+ }
2994
+ function FAQAccordion(props) {
2995
+ return /* @__PURE__ */ jsx(
2996
+ AccordionField,
2997
+ {
2998
+ ...props,
2999
+ multiple: false,
3000
+ dataAttributes: {
3001
+ ...props.dataAttributes,
3002
+ "data-purpose": "faq"
3003
+ }
3004
+ }
3005
+ );
3006
+ }
3007
+ function SettingsAccordion(props) {
3008
+ return /* @__PURE__ */ jsx(
3009
+ AccordionField,
3010
+ {
3011
+ ...props,
3012
+ multiple: true,
3013
+ dataAttributes: {
3014
+ ...props.dataAttributes,
3015
+ "data-purpose": "settings"
3016
+ }
3017
+ }
3018
+ );
3019
+ }
3020
+ function SectionsAccordion(props) {
3021
+ return /* @__PURE__ */ jsx(
3022
+ AccordionField,
3023
+ {
3024
+ ...props,
3025
+ dataAttributes: {
3026
+ ...props.dataAttributes,
3027
+ "data-purpose": "sections"
3028
+ }
3029
+ }
3030
+ );
3031
+ }
3032
+ function Radio(props) {
3033
+ const { onCheckedChange, onChange, ...coreProps } = props;
3034
+ const kit = radioRecipe(coreProps);
3035
+ const { a11y } = kit;
3036
+ const handleChange = (e) => {
3037
+ onChange?.(e);
3038
+ onCheckedChange?.(e.currentTarget.checked);
3039
+ };
3040
+ return /* @__PURE__ */ jsx(
3041
+ "input",
3042
+ {
3043
+ type: "radio",
3044
+ className: kit.className,
3045
+ id: a11y.id,
3046
+ name: a11y.name,
3047
+ value: a11y.value,
3048
+ disabled: a11y.disabled === true,
3049
+ required: a11y.required === true,
3050
+ "aria-label": a11y.ariaLabel,
3051
+ "aria-labelledby": a11y.ariaLabelledBy,
3052
+ "aria-describedby": a11y.ariaDescribedBy,
3053
+ "aria-invalid": a11y.ariaInvalid === true ? true : void 0,
3054
+ checked: kit.checked,
3055
+ defaultChecked: kit.defaultChecked,
3056
+ onChange: handleChange
3057
+ }
3058
+ );
3059
+ }
3060
+ function hasContent4(value) {
3061
+ if (value === void 0 || value === null || value === false) return false;
3062
+ if (typeof value === "string") return value.trim().length > 0;
3063
+ return true;
3064
+ }
3065
+ function cx12(...parts) {
3066
+ return parts.filter(Boolean).join(" ");
3067
+ }
3068
+ function RadioGroupField(props) {
3069
+ const reactId = React5.useId();
3070
+ const id = props.id ?? `mw-radio-group-${reactId}`;
3071
+ const hasDescription = hasContent4(props.description);
3072
+ const hasError = hasContent4(props.error);
3073
+ const isInvalid = hasError || false;
3074
+ const { labelId, descriptionId, errorId, describedBy } = buildRadioGroupFieldA11yIds({
3075
+ id,
3076
+ hasDescription,
3077
+ hasError,
3078
+ externalDescribedBy: props.ariaDescribedBy
3079
+ });
3080
+ const isControlled = props.value !== void 0;
3081
+ const [internalValue, setInternalValue] = React5.useState(props.defaultValue);
3082
+ const selectedValue = isControlled ? props.value : internalValue;
3083
+ const handleSelect = (optionValue) => {
3084
+ if (!isControlled) {
3085
+ setInternalValue(optionValue);
3086
+ }
3087
+ props.onChange?.(optionValue);
3088
+ };
3089
+ const wrapperClass = cx12(
3090
+ "mw-radio-group-field",
3091
+ props.disabled && "mw-radio-group-field--disabled",
3092
+ isInvalid && "mw-radio-group-field--invalid"
3093
+ );
3094
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClass, ...props.dataAttributes, children: [
3095
+ /* @__PURE__ */ jsx("div", { className: "mw-radio-group-field__label", id: labelId, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) }),
3096
+ hasDescription && /* @__PURE__ */ jsx("div", { className: "mw-radio-group-field__description", id: descriptionId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.description }) }),
3097
+ /* @__PURE__ */ jsx(
3098
+ "div",
3099
+ {
3100
+ role: "radiogroup",
3101
+ "aria-labelledby": labelId,
3102
+ "aria-describedby": describedBy,
3103
+ "aria-invalid": isInvalid ? true : void 0,
3104
+ "aria-required": props.required ? true : void 0,
3105
+ className: "mw-radio-group-field__options",
3106
+ children: props.options.map(({ value, label, disabled: optionDisabled }) => {
3107
+ const optionId = `${id}-option-${value}`;
3108
+ const isDisabled = props.disabled || optionDisabled || false;
3109
+ return /* @__PURE__ */ jsxs("label", { className: "mw-radio-group-field__option", htmlFor: optionId, children: [
3110
+ /* @__PURE__ */ jsx(
3111
+ Radio,
3112
+ {
3113
+ id: optionId,
3114
+ name: props.name,
3115
+ value,
3116
+ checked: selectedValue === value,
3117
+ disabled: isDisabled,
3118
+ invalid: isInvalid,
3119
+ ...props.required ? { required: true } : {},
3120
+ onCheckedChange: (checked) => {
3121
+ if (checked) handleSelect(value);
3122
+ }
3123
+ }
3124
+ ),
3125
+ /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: label })
3126
+ ] }, value);
3127
+ })
3128
+ }
3129
+ ),
3130
+ hasError && /* @__PURE__ */ jsx("div", { className: "mw-radio-group-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
3131
+ ] });
3132
+ }
3133
+ function YesNoRadioGroup(props) {
3134
+ const { yesLabel = "Yes", noLabel = "No", ...restProps } = props;
3135
+ const options = [
3136
+ { value: "yes", label: yesLabel },
3137
+ { value: "no", label: noLabel }
3138
+ ];
3139
+ return /* @__PURE__ */ jsx(
3140
+ RadioGroupField,
3141
+ {
3142
+ ...restProps,
3143
+ options,
3144
+ dataAttributes: {
3145
+ ...props.dataAttributes,
3146
+ "data-purpose": "binary-choice"
3147
+ }
3148
+ }
3149
+ );
3150
+ }
3151
+ function RatingRadioGroup(props) {
3152
+ const { min = 1, max = 5, labelFn = String, ...restProps } = props;
3153
+ const options = Array.from({ length: max - min + 1 }, (_, i) => {
3154
+ const value = min + i;
3155
+ return { value: String(value), label: labelFn(value) };
3156
+ });
3157
+ return /* @__PURE__ */ jsx(
3158
+ RadioGroupField,
3159
+ {
3160
+ ...restProps,
3161
+ options,
3162
+ dataAttributes: {
3163
+ ...props.dataAttributes,
3164
+ "data-purpose": "rating"
3165
+ }
3166
+ }
3167
+ );
3168
+ }
3169
+ function OptionRadioGroup(props) {
3170
+ return /* @__PURE__ */ jsx(
3171
+ RadioGroupField,
3172
+ {
3173
+ ...props,
3174
+ dataAttributes: {
3175
+ ...props.dataAttributes,
3176
+ "data-purpose": "selection"
3177
+ }
3178
+ }
3179
+ );
3180
+ }
3181
+ function Badge(props) {
3182
+ const { children, className, id, dataAttributes, ...coreProps } = props;
3183
+ const kit = createBadgeRecipe(coreProps);
3184
+ return /* @__PURE__ */ jsx(
3185
+ "span",
3186
+ {
3187
+ id,
3188
+ className: [kit.className, className].filter(Boolean).join(" "),
3189
+ "aria-label": kit.a11y.ariaLabel,
3190
+ ...kit.dataAttributes,
3191
+ ...dataAttributes,
3192
+ children
3193
+ }
3194
+ );
3195
+ }
3196
+ function cx13(...parts) {
3197
+ return parts.filter(Boolean).join(" ");
3198
+ }
3199
+ function BadgeGroup(props) {
3200
+ const reactId = React5.useId();
3201
+ const id = props.id ?? `mw-badge-group-${reactId}`;
3202
+ const labelId = `${id}-label`;
3203
+ const className = cx13("mw-badge-group", props.className);
3204
+ return /* @__PURE__ */ jsxs("fieldset", { className, "aria-labelledby": labelId, ...props.dataAttributes, children: [
3205
+ /* @__PURE__ */ jsx("legend", { className: "mw-badge-group__label", id: labelId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.label }) }),
3206
+ /* @__PURE__ */ jsx("div", { className: "mw-badge-group__items", children: props.children })
3207
+ ] });
3208
+ }
3209
+ function StatusBadge(props) {
3210
+ return /* @__PURE__ */ jsx(
3211
+ Badge,
3212
+ {
3213
+ ...props,
3214
+ dataAttributes: {
3215
+ ...props.dataAttributes,
3216
+ ...createPurposeSemanticAttributes("status")
3217
+ }
3218
+ }
3219
+ );
3220
+ }
3221
+ function PriorityBadge(props) {
3222
+ return /* @__PURE__ */ jsx(
3223
+ Badge,
3224
+ {
3225
+ ...props,
3226
+ dataAttributes: {
3227
+ ...props.dataAttributes,
3228
+ ...createPurposeSemanticAttributes("priority")
3229
+ }
3230
+ }
3231
+ );
3232
+ }
3233
+ function NotificationBadge(props) {
3234
+ return /* @__PURE__ */ jsx(
3235
+ Badge,
3236
+ {
3237
+ ...props,
3238
+ dataAttributes: {
3239
+ ...props.dataAttributes,
3240
+ ...createPurposeSemanticAttributes("notification")
3241
+ }
3242
+ }
3243
+ );
3244
+ }
3245
+ function Switch(props) {
3246
+ const { children, className, id, onCheckedChange, onClick, ...coreProps } = props;
3247
+ const kit = createSwitchRecipe(coreProps);
3248
+ const { a11y } = kit;
3249
+ const isDisabled = a11y.ariaDisabled === true;
3250
+ const handleClick = (event) => {
3251
+ onClick?.(event);
3252
+ if (isDisabled || event.defaultPrevented) {
3253
+ return;
3254
+ }
3255
+ onCheckedChange?.(!a11y.ariaChecked);
3256
+ };
3257
+ return /* @__PURE__ */ jsxs(
3258
+ "button",
3259
+ {
3260
+ id,
3261
+ type: "button",
3262
+ role: a11y.role,
3263
+ disabled: isDisabled,
3264
+ "aria-checked": a11y.ariaChecked,
3265
+ "aria-disabled": a11y.ariaDisabled,
3266
+ "aria-label": a11y.ariaLabel,
3267
+ "aria-labelledby": a11y.ariaLabelledby,
3268
+ "aria-describedby": a11y.ariaDescribedBy,
3269
+ className: [kit.className, className].filter(Boolean).join(" "),
3270
+ style: kit.vars,
3271
+ onClick: handleClick,
3272
+ children: [
3273
+ /* @__PURE__ */ jsx("span", { className: "mw-switch__track", children: /* @__PURE__ */ jsx("span", { className: "mw-switch__thumb" }) }),
3274
+ children
3275
+ ]
3276
+ }
3277
+ );
3278
+ }
3279
+ function cx14(...parts) {
3280
+ return parts.filter(Boolean).join(" ");
3281
+ }
3282
+ function hasContent5(value) {
3283
+ if (value === void 0 || value === null || value === false) {
3284
+ return false;
3285
+ }
3286
+ if (typeof value === "string") {
3287
+ return value.trim().length > 0;
3288
+ }
3289
+ return true;
3290
+ }
3291
+ function SwitchField(props) {
3292
+ const reactId = React5.useId();
3293
+ const id = props.id ?? `mw-switch-${reactId}`;
3294
+ const hasDescription = hasContent5(props.description);
3295
+ const hasError = hasContent5(props.error);
3296
+ const { labelId, descriptionId, errorId, describedBy } = buildSwitchFieldA11yIds({
3297
+ id,
3298
+ hasDescription,
3299
+ hasError,
3300
+ externalDescribedBy: props.ariaDescribedBy
3301
+ });
3302
+ const disabled = props.switch.disabled || false;
3303
+ const invalid = hasError;
3304
+ const wrapperClass = cx14(
3305
+ "mw-switch-field",
3306
+ disabled && "mw-switch-field--disabled",
3307
+ invalid && "mw-switch-field--invalid"
3308
+ );
3309
+ const {
3310
+ ariaLabel: _ignoredAriaLabel,
3311
+ ariaLabelledby: _ignoredAriaLabelledby,
3312
+ ariaDescribedBy: _ignoredAriaDescribedBy,
3313
+ children: _ignoredChildren,
3314
+ ...switchProps
3315
+ } = props.switch;
3316
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClass, ...props.dataAttributes, children: [
3317
+ /* @__PURE__ */ jsxs("div", { className: "mw-switch-field__row", children: [
3318
+ /* @__PURE__ */ jsx(
3319
+ Switch,
3320
+ {
3321
+ ...switchProps,
3322
+ id,
3323
+ ariaLabelledby: labelId,
3324
+ ...describedBy ? { ariaDescribedBy: describedBy } : {}
3325
+ }
3326
+ ),
3327
+ /* @__PURE__ */ jsx("span", { className: "mw-switch-field__label", id: labelId, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) })
3328
+ ] }),
3329
+ hasDescription && /* @__PURE__ */ jsx("div", { className: "mw-switch-field__description", id: descriptionId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.description }) }),
3330
+ hasError && /* @__PURE__ */ jsx("div", { className: "mw-switch-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
3331
+ ] });
3332
+ }
3333
+ function FeatureToggle(props) {
3334
+ return /* @__PURE__ */ jsx(
3335
+ SwitchField,
3336
+ {
3337
+ ...props,
3338
+ dataAttributes: {
3339
+ ...props.dataAttributes,
3340
+ "data-purpose": "feature-toggle"
3341
+ }
3342
+ }
3343
+ );
3344
+ }
3345
+ function PreferenceSwitch(props) {
3346
+ return /* @__PURE__ */ jsx(
3347
+ SwitchField,
3348
+ {
3349
+ ...props,
3350
+ dataAttributes: {
3351
+ ...props.dataAttributes,
3352
+ "data-purpose": "preference"
3353
+ }
3354
+ }
3355
+ );
3356
+ }
3357
+ function PermissionSwitch(props) {
3358
+ return /* @__PURE__ */ jsx(
3359
+ SwitchField,
3360
+ {
3361
+ ...props,
3362
+ dataAttributes: {
3363
+ ...props.dataAttributes,
3364
+ "data-purpose": "permission"
3365
+ }
3366
+ }
3367
+ );
3368
+ }
3369
+ function buildSliderOptions(options) {
3370
+ const sliderOptions = {};
3371
+ if (options.id !== void 0) sliderOptions.id = options.id;
3372
+ if (options.name !== void 0) sliderOptions.name = options.name;
3373
+ if (options.min !== void 0) sliderOptions.min = options.min;
3374
+ if (options.max !== void 0) sliderOptions.max = options.max;
3375
+ if (options.step !== void 0) sliderOptions.step = options.step;
3376
+ if (options.value !== void 0) sliderOptions.value = options.value;
3377
+ if (options.defaultValue !== void 0) sliderOptions.defaultValue = options.defaultValue;
3378
+ if (options.disabled !== void 0) sliderOptions.disabled = options.disabled;
3379
+ if (options.required !== void 0) sliderOptions.required = options.required;
3380
+ if (options.showTooltip !== void 0) sliderOptions.showTooltip = options.showTooltip;
3381
+ if (options.showTouchArea !== void 0) sliderOptions.showTouchArea = options.showTouchArea;
3382
+ if (options.orientation !== void 0) sliderOptions.orientation = options.orientation;
3383
+ if (options.ariaLabel !== void 0) sliderOptions.ariaLabel = options.ariaLabel;
3384
+ if (options.ariaLabelledBy !== void 0) sliderOptions.ariaLabelledBy = options.ariaLabelledBy;
3385
+ if (options.ariaDescribedBy !== void 0) sliderOptions.ariaDescribedBy = options.ariaDescribedBy;
3386
+ if (options.ariaValueText !== void 0) sliderOptions.ariaValueText = options.ariaValueText;
3387
+ return sliderOptions;
3388
+ }
3389
+ function resolveSliderValue(options) {
3390
+ return createSliderRecipe(buildSliderOptions(options)).value;
3391
+ }
3392
+ var Slider = React5.forwardRef((props, ref) => {
3393
+ const {
3394
+ id,
3395
+ name,
3396
+ min,
3397
+ max,
3398
+ step,
3399
+ value,
3400
+ defaultValue,
3401
+ disabled,
3402
+ required,
3403
+ showTooltip,
3404
+ showTouchArea,
3405
+ orientation,
3406
+ ariaLabel,
3407
+ ariaLabelledBy,
3408
+ ariaDescribedBy,
3409
+ ariaValueText,
3410
+ className: customClassName,
3411
+ style: customStyle,
3412
+ onValueChange,
3413
+ onChange,
3414
+ ...inputProps
3415
+ } = props;
3416
+ const isControlled = value !== void 0;
3417
+ const [uncontrolledValue, setUncontrolledValue] = React5.useState(
3418
+ () => resolveSliderValue({ min, max, step, value, defaultValue })
3419
+ );
3420
+ React5.useEffect(() => {
3421
+ if (!isControlled) {
3422
+ setUncontrolledValue(resolveSliderValue({ min, max, step, defaultValue }));
3423
+ }
3424
+ }, [defaultValue, isControlled, max, min, step]);
3425
+ const currentValue = isControlled ? resolveSliderValue({ min, max, step, value }) : uncontrolledValue;
3426
+ const kit = createSliderRecipe(
3427
+ buildSliderOptions({
3428
+ id,
3429
+ name,
3430
+ min,
3431
+ max,
3432
+ step,
3433
+ value: currentValue,
3434
+ disabled,
3435
+ required,
3436
+ showTooltip,
3437
+ showTouchArea,
3438
+ orientation,
3439
+ ariaLabel,
3440
+ ariaLabelledBy,
3441
+ ariaDescribedBy,
3442
+ ariaValueText
3443
+ })
3444
+ );
3445
+ useRenderKitDebug(kit, "Slider");
3446
+ const className = customClassName ? `${kit.className} ${customClassName}` : kit.className;
3447
+ const style = { ...kit.vars, ...customStyle };
3448
+ const handleChange = (event) => {
3449
+ const nextValue = Number(event.currentTarget.value);
3450
+ if (!isControlled) {
3451
+ setUncontrolledValue(nextValue);
3452
+ }
3453
+ onChange?.(event);
3454
+ onValueChange?.(nextValue);
3455
+ };
3456
+ return /* @__PURE__ */ jsx("div", { className, style, ...kit.dataAttributes, children: /* @__PURE__ */ jsxs("div", { className: "mw-slider__control", children: [
3457
+ /* @__PURE__ */ jsx(
3458
+ "input",
3459
+ {
3460
+ ...inputProps,
3461
+ ref,
3462
+ type: kit.a11y.type,
3463
+ id: kit.a11y.id,
3464
+ name: kit.a11y.name,
3465
+ min: kit.a11y.min,
3466
+ max: kit.a11y.max,
3467
+ step: kit.a11y.step,
3468
+ disabled: kit.a11y.disabled === true,
3469
+ required: kit.a11y.required === true,
3470
+ "aria-label": kit.a11y.ariaLabel,
3471
+ "aria-labelledby": kit.a11y.ariaLabelledBy,
3472
+ "aria-describedby": kit.a11y.ariaDescribedBy,
3473
+ "aria-valuetext": kit.a11y.ariaValueText,
3474
+ "aria-orientation": kit.a11y.ariaOrientation,
3475
+ className: kit.inputClassName,
3476
+ value: currentValue,
3477
+ onChange: handleChange
3478
+ }
3479
+ ),
3480
+ /* @__PURE__ */ jsxs("div", { className: "mw-slider__visual", "aria-hidden": "true", children: [
3481
+ /* @__PURE__ */ jsx("span", { className: "mw-slider__track" }),
3482
+ /* @__PURE__ */ jsx("span", { className: "mw-slider__fill" }),
3483
+ /* @__PURE__ */ jsx("span", { className: "mw-slider__touch-area" }),
3484
+ /* @__PURE__ */ jsx("span", { className: "mw-slider__thumb" })
3485
+ ] }),
3486
+ kit.showTooltip ? /* @__PURE__ */ jsx("span", { className: "mw-slider__tooltip", "aria-hidden": "true", children: currentValue }) : null
3487
+ ] }) });
3488
+ });
3489
+ Slider.displayName = "Slider";
3490
+ function cx15(...parts) {
3491
+ return parts.filter(Boolean).join(" ");
3492
+ }
3493
+ function hasContent6(value) {
3494
+ if (value === void 0 || value === null || value === false) {
3495
+ return false;
3496
+ }
3497
+ if (typeof value === "string") {
3498
+ return value.trim().length > 0;
3499
+ }
3500
+ return true;
3501
+ }
3502
+ function resolveEdgeValueLabel(value, fallback) {
3503
+ return value ?? `${fallback}`;
3504
+ }
3505
+ function SliderField(props) {
3506
+ const reactId = React5.useId();
3507
+ const id = props.id ?? `mw-slider-${reactId}`;
3508
+ const hasDescription = hasContent6(props.description);
3509
+ const hasError = hasContent6(props.error);
3510
+ const { labelId, descriptionId, errorId, describedBy } = buildSliderFieldA11yIds({
3511
+ id,
3512
+ hasDescription,
3513
+ hasError,
3514
+ externalDescribedBy: props.ariaDescribedBy
3515
+ });
3516
+ const disabled = props.slider.disabled || false;
3517
+ const labelPosition = props.labelPosition ?? "top";
3518
+ const showEdgeValues = props.showEdgeValues !== false;
3519
+ const minValue = props.slider.min ?? 0;
3520
+ const maxValue = props.slider.max ?? 100;
3521
+ const minValueLabel = resolveEdgeValueLabel(props.minValueLabel, minValue);
3522
+ const maxValueLabel = resolveEdgeValueLabel(props.maxValueLabel, maxValue);
3523
+ const wrapperClass = cx15(
3524
+ "mw-slider-field",
3525
+ labelPosition === "top" && "mw-slider-field--label-top",
3526
+ labelPosition === "inline" && "mw-slider-field--label-inline",
3527
+ disabled && "mw-slider-field--disabled",
3528
+ hasError && "mw-slider-field--invalid"
3529
+ );
3530
+ const {
3531
+ ariaLabel: _ignoredAriaLabel,
3532
+ ariaLabelledBy: _ignoredAriaLabelledBy,
3533
+ ariaDescribedBy: _ignoredAriaDescribedBy,
3534
+ style: sliderStyle,
3535
+ ...sliderProps
3536
+ } = props.slider;
3537
+ const renderEdgeValue = (position, value) => /* @__PURE__ */ jsx("span", { className: `mw-slider-field__edge-value mw-slider-field__edge-value--${position}`, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: value }) });
3538
+ return /* @__PURE__ */ jsxs("div", { className: wrapperClass, "data-label-position": labelPosition, ...props.dataAttributes, children: [
3539
+ /* @__PURE__ */ jsx("div", { className: "mw-slider-field__header", children: /* @__PURE__ */ jsx("div", { className: "mw-slider-field__label", id: labelId, children: /* @__PURE__ */ jsx(Paragraph, { size: "md", children: props.label }) }) }),
3540
+ hasDescription && /* @__PURE__ */ jsx("div", { className: "mw-slider-field__description", id: descriptionId, children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.description }) }),
3541
+ labelPosition === "top" && showEdgeValues ? /* @__PURE__ */ jsxs("div", { className: "mw-slider-field__values-row", children: [
3542
+ renderEdgeValue("min", minValueLabel),
3543
+ renderEdgeValue("max", maxValueLabel)
3544
+ ] }) : null,
3545
+ /* @__PURE__ */ jsxs("div", { className: "mw-slider-field__control-row", children: [
3546
+ labelPosition === "inline" && showEdgeValues ? renderEdgeValue("min", minValueLabel) : null,
3547
+ /* @__PURE__ */ jsx("div", { className: "mw-slider-field__slider", children: /* @__PURE__ */ jsx(
3548
+ Slider,
3549
+ {
3550
+ ...sliderProps,
3551
+ id,
3552
+ ariaLabelledBy: labelId,
3553
+ ...describedBy ? { ariaDescribedBy: describedBy } : {},
3554
+ "aria-invalid": hasError ? true : void 0,
3555
+ style: { width: "100%", ...sliderStyle ?? {} }
3556
+ }
3557
+ ) }),
3558
+ labelPosition === "inline" && showEdgeValues ? renderEdgeValue("max", maxValueLabel) : null
3559
+ ] }),
3560
+ hasError && /* @__PURE__ */ jsx("div", { className: "mw-slider-field__error", id: errorId, "aria-live": "polite", children: /* @__PURE__ */ jsx(Paragraph, { size: "sm", children: props.error }) })
3561
+ ] });
3562
+ }
3563
+ function VolumeSlider(props) {
3564
+ const { orientation, slider, ...fieldProps } = props;
3565
+ return /* @__PURE__ */ jsx(
3566
+ SliderField,
3567
+ {
3568
+ ...fieldProps,
3569
+ label: props.label ?? "Volume",
3570
+ minValueLabel: props.minValueLabel ?? "0",
3571
+ maxValueLabel: props.maxValueLabel ?? "100",
3572
+ slider: {
3573
+ min: 0,
3574
+ max: 100,
3575
+ step: 1,
3576
+ showTooltip: true,
3577
+ ...orientation !== void 0 ? { orientation } : {},
3578
+ ...slider
3579
+ },
3580
+ dataAttributes: {
3581
+ ...props.dataAttributes,
3582
+ "data-purpose": "volume"
3583
+ }
3584
+ }
3585
+ );
3586
+ }
3587
+ function BrightnessSlider(props) {
3588
+ const { orientation, slider, ...fieldProps } = props;
3589
+ return /* @__PURE__ */ jsx(
3590
+ SliderField,
3591
+ {
3592
+ ...fieldProps,
3593
+ label: props.label ?? "Brightness",
3594
+ minValueLabel: props.minValueLabel ?? "0",
3595
+ maxValueLabel: props.maxValueLabel ?? "100",
3596
+ slider: {
3597
+ min: 0,
3598
+ max: 100,
3599
+ step: 1,
3600
+ showTooltip: true,
3601
+ ...orientation !== void 0 ? { orientation } : {},
3602
+ ...slider
3603
+ },
3604
+ dataAttributes: {
3605
+ ...props.dataAttributes,
3606
+ "data-purpose": "brightness"
3607
+ }
3608
+ }
3609
+ );
3610
+ }
3611
+ function RadiusSlider(props) {
3612
+ const { orientation, slider, ...fieldProps } = props;
3613
+ return /* @__PURE__ */ jsx(
3614
+ SliderField,
3615
+ {
3616
+ ...fieldProps,
3617
+ label: props.label ?? "Radius",
3618
+ minValueLabel: props.minValueLabel ?? "0px",
3619
+ maxValueLabel: props.maxValueLabel ?? "48px",
3620
+ slider: {
3621
+ min: 0,
3622
+ max: 48,
3623
+ step: 2,
3624
+ showTooltip: true,
3625
+ ...orientation !== void 0 ? { orientation } : {},
3626
+ ...slider
3627
+ },
3628
+ dataAttributes: {
3629
+ ...props.dataAttributes,
3630
+ "data-purpose": "radius"
3631
+ }
3632
+ }
3633
+ );
3634
+ }
3635
+ function Tab(props) {
3636
+ const { children, className, onClick, id, ...coreProps } = props;
3637
+ const kit = createTabRecipe(coreProps);
3638
+ const { a11y } = kit;
3639
+ return /* @__PURE__ */ jsx(
3640
+ "button",
3641
+ {
3642
+ id,
3643
+ className: [kit.className, className].filter(Boolean).join(" "),
3644
+ style: Object.keys(kit.vars).length > 0 ? kit.vars : void 0,
3645
+ role: a11y.role,
3646
+ "aria-selected": a11y.ariaSelected,
3647
+ "aria-disabled": a11y.ariaDisabled,
3648
+ "aria-label": a11y.ariaLabel,
3649
+ "aria-controls": a11y.ariaControls,
3650
+ tabIndex: a11y.tabIndex,
3651
+ disabled: coreProps.disabled,
3652
+ onClick,
3653
+ type: "button",
3654
+ children
3655
+ }
3656
+ );
3657
+ }
3658
+ function cx16(...parts) {
3659
+ return parts.filter(Boolean).join(" ");
3660
+ }
3661
+ function hasContent7(value) {
3662
+ if (value === void 0 || value === null || value === false) {
3663
+ return false;
3664
+ }
3665
+ if (typeof value === "string") {
3666
+ return value.trim().length > 0;
3667
+ }
3668
+ return true;
3669
+ }
3670
+ function focusTab(tabId) {
3671
+ if (typeof document === "undefined") {
3672
+ return;
3673
+ }
3674
+ const tab = document.getElementById(tabId);
3675
+ if (tab instanceof HTMLButtonElement) {
3676
+ tab.focus();
3677
+ }
3678
+ }
3679
+ function toItemState(tab) {
3680
+ const itemState = { value: tab.value };
3681
+ if (tab.disabled) {
3682
+ itemState.disabled = true;
3683
+ }
3684
+ return itemState;
3685
+ }
3686
+ function renderPanelContent(children) {
3687
+ if (typeof children === "string" || typeof children === "number") {
3688
+ return /* @__PURE__ */ jsx(Paragraph, { size: "md", children });
3689
+ }
3690
+ return children;
3691
+ }
3692
+ function TabPanel(props) {
3693
+ return /* @__PURE__ */ jsx(
3694
+ "div",
3695
+ {
3696
+ id: props.id,
3697
+ role: "tabpanel",
3698
+ "aria-labelledby": props.tabId,
3699
+ className: cx16("mw-tab-group__panel", props.className),
3700
+ hidden: props.hidden,
3701
+ tabIndex: props.hidden ? void 0 : 0,
3702
+ children: renderPanelContent(props.children)
3703
+ }
3704
+ );
3705
+ }
3706
+ function TabGroup(props) {
3707
+ const reactId = React5.useId();
3708
+ const id = props.id ?? `mw-tab-group-${reactId}`;
3709
+ const hasLabel = hasContent7(props.label);
3710
+ const itemStates = React5.useMemo(
3711
+ () => props.tabs.map((tab) => toItemState(tab)),
3712
+ [props.tabs]
3713
+ );
3714
+ const isControlled = props.activeTab !== void 0;
3715
+ const [internalActiveTab, setInternalActiveTab] = React5.useState(
3716
+ () => resolveTabValue(itemStates, props.defaultActiveTab)
3717
+ );
3718
+ const resolvedActiveTab = React5.useMemo(
3719
+ () => resolveTabValue(itemStates, isControlled ? props.activeTab : internalActiveTab),
3720
+ [internalActiveTab, isControlled, itemStates, props.activeTab]
3721
+ );
3722
+ React5.useEffect(() => {
3723
+ if (!isControlled) {
3724
+ setInternalActiveTab(
3725
+ (currentValue) => resolveTabValue(itemStates, currentValue ?? props.defaultActiveTab)
3726
+ );
3727
+ }
3728
+ }, [isControlled, itemStates, props.defaultActiveTab]);
3729
+ const a11yIds = React5.useMemo(
3730
+ () => buildTabGroupA11yIds({
3731
+ id,
3732
+ itemValues: props.tabs.map((tab) => tab.value),
3733
+ hasLabel
3734
+ }),
3735
+ [hasLabel, id, props.tabs]
3736
+ );
3737
+ const selectTab = React5.useCallback(
3738
+ (nextValue) => {
3739
+ const resolvedValue = resolveTabValue(itemStates, nextValue);
3740
+ if (!resolvedValue) {
3741
+ return;
3742
+ }
3743
+ if (!isControlled) {
3744
+ setInternalActiveTab(resolvedValue);
3745
+ }
3746
+ if (resolvedValue !== resolvedActiveTab) {
3747
+ props.onActiveTabChange?.(resolvedValue);
3748
+ }
3749
+ },
3750
+ [isControlled, itemStates, props.onActiveTabChange, resolvedActiveTab]
3751
+ );
3752
+ const handleKeyDown = React5.useCallback(
3753
+ (event) => {
3754
+ let direction;
3755
+ switch (event.key) {
3756
+ case "ArrowRight":
3757
+ direction = "next";
3758
+ break;
3759
+ case "ArrowLeft":
3760
+ direction = "previous";
3761
+ break;
3762
+ case "Home":
3763
+ direction = "start";
3764
+ break;
3765
+ case "End":
3766
+ direction = "end";
3767
+ break;
3768
+ default:
3769
+ return;
3770
+ }
3771
+ event.preventDefault();
3772
+ const nextValue = moveTabSelection(itemStates, resolvedActiveTab, direction);
3773
+ if (!nextValue) {
3774
+ return;
3775
+ }
3776
+ selectTab(nextValue);
3777
+ const nextTabId = a11yIds.tabIds[nextValue];
3778
+ if (nextTabId) {
3779
+ focusTab(nextTabId);
3780
+ }
3781
+ },
3782
+ [a11yIds.tabIds, itemStates, resolvedActiveTab, selectTab]
3783
+ );
3784
+ return /* @__PURE__ */ jsxs("section", { className: cx16("mw-tab-group", props.className), ...props.dataAttributes, children: [
3785
+ hasLabel && /* @__PURE__ */ jsx("div", { className: "mw-tab-group__header", children: /* @__PURE__ */ jsx(Paragraph, { size: "md", id: a11yIds.labelId ?? `${id}-label`, children: props.label }) }),
3786
+ /* @__PURE__ */ jsx(
3787
+ "div",
3788
+ {
3789
+ id: a11yIds.tabListId,
3790
+ className: "mw-tab-group__list",
3791
+ role: "tablist",
3792
+ "aria-label": hasLabel ? void 0 : props.ariaLabel ?? "Tabs",
3793
+ "aria-labelledby": hasLabel ? a11yIds.labelId : void 0,
3794
+ onKeyDown: handleKeyDown,
3795
+ children: props.tabs.map((tab) => {
3796
+ const tabId = a11yIds.tabIds[tab.value] ?? `${id}-tab-${tab.value}`;
3797
+ const panelId = a11yIds.panelIds[tab.value] ?? `${id}-panel-${tab.value}`;
3798
+ const tabProps = {
3799
+ id: tabId,
3800
+ selected: tab.value === resolvedActiveTab,
3801
+ ariaControls: panelId,
3802
+ onClick: () => selectTab(tab.value)
3803
+ };
3804
+ if (tab.disabled) {
3805
+ tabProps.disabled = true;
3806
+ }
3807
+ if (tab.ariaLabel) {
3808
+ tabProps.ariaLabel = tab.ariaLabel;
3809
+ }
3810
+ return /* @__PURE__ */ jsx(Tab, { ...tabProps, children: tab.label }, tab.value);
3811
+ })
3812
+ }
3813
+ ),
3814
+ /* @__PURE__ */ jsx("div", { className: "mw-tab-group__panels", children: props.tabs.map((tab) => {
3815
+ const panelId = a11yIds.panelIds[tab.value] ?? `${id}-panel-${tab.value}`;
3816
+ const tabId = a11yIds.tabIds[tab.value] ?? `${id}-tab-${tab.value}`;
3817
+ return /* @__PURE__ */ jsx(
3818
+ TabPanel,
3819
+ {
3820
+ id: panelId,
3821
+ tabId,
3822
+ hidden: tab.value !== resolvedActiveTab,
3823
+ children: tab.panel
3824
+ },
3825
+ tab.value
3826
+ );
3827
+ }) })
3828
+ ] });
3829
+ }
3830
+ function NavigationTabs(props) {
3831
+ return /* @__PURE__ */ jsx(
3832
+ TabGroup,
3833
+ {
3834
+ ...props,
3835
+ ariaLabel: props.ariaLabel ?? "Navigation tabs",
3836
+ dataAttributes: {
3837
+ ...props.dataAttributes,
3838
+ "data-purpose": "navigation-tabs"
3839
+ }
3840
+ }
3841
+ );
3842
+ }
3843
+ function ContentTabs(props) {
3844
+ return /* @__PURE__ */ jsx(
3845
+ TabGroup,
3846
+ {
3847
+ ...props,
3848
+ ariaLabel: props.ariaLabel ?? "Content tabs",
3849
+ dataAttributes: {
3850
+ ...props.dataAttributes,
3851
+ "data-purpose": "content-tabs"
3852
+ }
3853
+ }
3854
+ );
3855
+ }
3856
+ function SettingsTabs(props) {
3857
+ return /* @__PURE__ */ jsx(
3858
+ TabGroup,
3859
+ {
3860
+ ...props,
3861
+ ariaLabel: props.ariaLabel ?? "Settings tabs",
3862
+ dataAttributes: {
3863
+ ...props.dataAttributes,
3864
+ "data-purpose": "settings-tabs"
3865
+ }
3866
+ }
3867
+ );
3868
+ }
3869
+ function cx17(...parts) {
3870
+ return parts.filter(Boolean).join(" ");
3871
+ }
3872
+ function hasContent8(value) {
3873
+ if (value === void 0 || value === null || value === false) {
3874
+ return false;
3875
+ }
3876
+ if (typeof value === "string") {
3877
+ return value.trim().length > 0;
3878
+ }
3879
+ return true;
3880
+ }
3881
+ function Dialog(props) {
3882
+ const reactId = React5.useId();
3883
+ const id = props.id ?? `mw-dialog-${reactId}`;
3884
+ const titleId = `${id}-title`;
3885
+ const descriptionId = `${id}-description`;
3886
+ const hasTitle = hasContent8(props.title);
3887
+ const hasDescription = hasContent8(props.description);
3888
+ const hasFooter = hasContent8(props.footer) && (props.showFooter ?? true);
3889
+ const dismissible = (props.dismissible ?? true) && props.onClose !== void 0;
3890
+ const dialogOptions = {
3891
+ showFooter: hasFooter,
3892
+ dismissible,
3893
+ ...props.modal !== void 0 ? { modal: props.modal } : {}
3894
+ };
3895
+ if (props.dataAttributes) {
3896
+ dialogOptions.dataAttributes = props.dataAttributes;
3897
+ }
3898
+ if (props.size) {
3899
+ dialogOptions.size = props.size;
3900
+ }
3901
+ if (props.ariaLabel) {
3902
+ dialogOptions.ariaLabel = props.ariaLabel;
3903
+ }
3904
+ if (props.ariaLabelledBy) {
3905
+ dialogOptions.ariaLabelledBy = props.ariaLabelledBy;
3906
+ } else if (props.ariaLabel === void 0 && hasTitle) {
3907
+ dialogOptions.ariaLabelledBy = titleId;
3908
+ }
3909
+ if (props.ariaDescribedBy) {
3910
+ dialogOptions.ariaDescribedBy = props.ariaDescribedBy;
3911
+ } else if (hasDescription) {
3912
+ dialogOptions.ariaDescribedBy = descriptionId;
3913
+ }
3914
+ const kit = createDialogRecipe(dialogOptions);
3915
+ return /* @__PURE__ */ jsxs(
3916
+ "section",
3917
+ {
3918
+ id,
3919
+ className: cx17(kit.className, props.className),
3920
+ role: kit.a11y.role,
3921
+ ...kit.a11y.ariaModal ? { "aria-modal": "true" } : {},
3922
+ ...kit.a11y.ariaLabel ? { "aria-label": kit.a11y.ariaLabel } : {},
3923
+ ...kit.a11y.ariaLabelledBy ? { "aria-labelledby": kit.a11y.ariaLabelledBy } : {},
3924
+ ...kit.a11y.ariaDescribedBy ? { "aria-describedby": kit.a11y.ariaDescribedBy } : {},
3925
+ tabIndex: -1,
3926
+ ...kit.dataAttributes,
3927
+ children: [
3928
+ (hasTitle || kit.showCloseButton) && /* @__PURE__ */ jsxs(Fragment, { children: [
3929
+ /* @__PURE__ */ jsxs("header", { className: "mw-dialog__header", children: [
3930
+ hasTitle ? /* @__PURE__ */ jsx("div", { className: "mw-dialog__heading-group", children: /* @__PURE__ */ jsx("h2", { className: "mw-dialog__title", id: titleId, children: props.title }) }) : /* @__PURE__ */ jsx("span", { className: "mw-dialog__spacer", "aria-hidden": "true" }),
3931
+ kit.showCloseButton && props.onClose && /* @__PURE__ */ jsx(
3932
+ "button",
3933
+ {
3934
+ type: "button",
3935
+ className: "mw-dialog__close",
3936
+ "aria-label": "Close dialog",
3937
+ onClick: props.onClose,
3938
+ children: /* @__PURE__ */ jsx(Icon, { name: IconName.X, decorative: true })
3939
+ }
3940
+ )
3941
+ ] }),
3942
+ /* @__PURE__ */ jsx("div", { className: "mw-dialog__header-divider", "aria-hidden": "true" })
3943
+ ] }),
3944
+ /* @__PURE__ */ jsxs("div", { className: "mw-dialog__content", children: [
3945
+ hasDescription && /* @__PURE__ */ jsx("p", { className: "mw-dialog__description", id: descriptionId, children: props.description }),
3946
+ props.children
3947
+ ] }),
3948
+ hasFooter && /* @__PURE__ */ jsxs(Fragment, { children: [
3949
+ /* @__PURE__ */ jsx("div", { className: "mw-dialog__footer-divider", "aria-hidden": "true" }),
3950
+ /* @__PURE__ */ jsx("footer", { className: "mw-dialog__footer", children: props.footer })
3951
+ ] })
3952
+ ]
3953
+ }
3954
+ );
3955
+ }
3956
+ function cx18(...parts) {
3957
+ return parts.filter(Boolean).join(" ");
3958
+ }
3959
+ function getFocusableElements(container) {
3960
+ if (!container) {
3961
+ return [];
3962
+ }
3963
+ return Array.from(
3964
+ container.querySelectorAll(
3965
+ [
3966
+ "button:not([disabled])",
3967
+ "[href]",
3968
+ "input:not([disabled])",
3969
+ "select:not([disabled])",
3970
+ "textarea:not([disabled])",
3971
+ "[tabindex]:not([tabindex='-1'])"
3972
+ ].join(",")
3973
+ )
3974
+ ).filter(
3975
+ (element) => !element.hasAttribute("hidden") && element.getAttribute("aria-hidden") !== "true"
3976
+ );
3977
+ }
3978
+ function focusFirstElement(container) {
3979
+ const focusableElements = getFocusableElements(container);
3980
+ const firstFocusable = focusableElements[0];
3981
+ if (firstFocusable) {
3982
+ firstFocusable.focus();
3983
+ return;
3984
+ }
3985
+ container?.focus();
3986
+ }
3987
+ function DialogModal(props) {
3988
+ const {
3989
+ open,
3990
+ defaultOpen = false,
3991
+ onOpenChange,
3992
+ closeOnEscape = true,
3993
+ closeOnScrimClick = true,
3994
+ restoreFocus = true,
3995
+ portalTarget,
3996
+ overlayClassName,
3997
+ footer,
3998
+ ...dialogProps
3999
+ } = props;
4000
+ const isControlled = open !== void 0;
4001
+ const [internalOpen, setInternalOpen] = React5.useState(defaultOpen);
4002
+ const resolvedOpen = isControlled ? open : internalOpen;
4003
+ const overlayRef = React5.useRef(null);
4004
+ const surfaceRef = React5.useRef(null);
4005
+ const lastFocusedElementRef = React5.useRef(null);
4006
+ const close = React5.useCallback(() => {
4007
+ if (!resolvedOpen) {
4008
+ return;
4009
+ }
4010
+ if (!isControlled) {
4011
+ setInternalOpen(false);
4012
+ }
4013
+ onOpenChange?.(false);
4014
+ }, [isControlled, onOpenChange, resolvedOpen]);
4015
+ React5.useEffect(() => {
4016
+ if (!resolvedOpen || typeof document === "undefined") {
4017
+ return;
4018
+ }
4019
+ const previousOverflow = document.body.style.overflow;
4020
+ lastFocusedElementRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
4021
+ document.body.style.overflow = "hidden";
4022
+ const frameId = window.requestAnimationFrame(() => {
4023
+ const dialogElement = overlayRef.current?.querySelector(".mw-dialog") ?? null;
4024
+ focusFirstElement(dialogElement);
4025
+ });
4026
+ return () => {
4027
+ window.cancelAnimationFrame(frameId);
4028
+ document.body.style.overflow = previousOverflow;
4029
+ if (restoreFocus) {
4030
+ lastFocusedElementRef.current?.focus();
4031
+ }
4032
+ };
4033
+ }, [resolvedOpen, restoreFocus]);
4034
+ React5.useEffect(() => {
4035
+ if (!resolvedOpen || !closeOnEscape || typeof document === "undefined") {
4036
+ return;
4037
+ }
4038
+ const handleKeyDown2 = (event) => {
4039
+ if (event.key === "Escape") {
4040
+ event.preventDefault();
4041
+ close();
4042
+ }
4043
+ };
4044
+ document.addEventListener("keydown", handleKeyDown2);
4045
+ return () => {
4046
+ document.removeEventListener("keydown", handleKeyDown2);
4047
+ };
4048
+ }, [close, closeOnEscape, resolvedOpen]);
4049
+ const handleKeyDown = React5.useCallback(
4050
+ (event) => {
4051
+ if (event.key === "Escape" && closeOnEscape) {
4052
+ event.preventDefault();
4053
+ event.stopPropagation();
4054
+ close();
4055
+ return;
4056
+ }
4057
+ if (event.key !== "Tab") {
4058
+ return;
4059
+ }
4060
+ const dialogElement = overlayRef.current?.querySelector(".mw-dialog") ?? null;
4061
+ const focusableElements = getFocusableElements(dialogElement);
4062
+ if (focusableElements.length === 0) {
4063
+ event.preventDefault();
4064
+ dialogElement?.focus();
4065
+ return;
4066
+ }
4067
+ const firstFocusable = focusableElements[0];
4068
+ const lastFocusable = focusableElements[focusableElements.length - 1];
4069
+ const activeElement = document.activeElement;
4070
+ if (event.shiftKey && activeElement === firstFocusable) {
4071
+ event.preventDefault();
4072
+ lastFocusable?.focus();
4073
+ } else if (!event.shiftKey && activeElement === lastFocusable) {
4074
+ event.preventDefault();
4075
+ firstFocusable?.focus();
4076
+ }
4077
+ },
4078
+ [close, closeOnEscape]
4079
+ );
4080
+ const renderedFooter = React5.useMemo(
4081
+ () => typeof footer === "function" ? footer({ close }) : footer,
4082
+ [close, footer]
4083
+ );
4084
+ if (!resolvedOpen || typeof document === "undefined") {
4085
+ return null;
4086
+ }
4087
+ const modalMarkup = /* @__PURE__ */ jsxs(
4088
+ "div",
4089
+ {
4090
+ ref: overlayRef,
4091
+ className: cx18("mw-dialog-modal", overlayClassName),
4092
+ onClick: (event) => {
4093
+ if (!closeOnScrimClick) {
4094
+ return;
4095
+ }
4096
+ const clickTarget = event.target;
4097
+ if (!(clickTarget instanceof Node)) {
4098
+ return;
4099
+ }
4100
+ if (surfaceRef.current?.contains(clickTarget)) {
4101
+ return;
4102
+ }
4103
+ close();
4104
+ },
4105
+ onKeyDown: handleKeyDown,
4106
+ children: [
4107
+ /* @__PURE__ */ jsx("div", { className: "mw-dialog-modal__scrim", "aria-hidden": "true" }),
4108
+ /* @__PURE__ */ jsx("div", { ref: surfaceRef, className: "mw-dialog-modal__surface", children: /* @__PURE__ */ jsx(Dialog, { ...dialogProps, modal: true, footer: renderedFooter, onClose: close }) })
4109
+ ]
4110
+ }
4111
+ );
4112
+ if (portalTarget === null) {
4113
+ return modalMarkup;
4114
+ }
4115
+ return createPortal(modalMarkup, portalTarget ?? document.body);
4116
+ }
4117
+ function ConfirmDialog(props) {
4118
+ const {
4119
+ confirmLabel = "Confirm",
4120
+ cancelLabel = "Cancel",
4121
+ onConfirm,
4122
+ onCancel,
4123
+ dataAttributes,
4124
+ ...dialogProps
4125
+ } = props;
4126
+ return /* @__PURE__ */ jsx(
4127
+ DialogModal,
4128
+ {
4129
+ ...dialogProps,
4130
+ dataAttributes: {
4131
+ ...dataAttributes,
4132
+ ...createPurposeSemanticAttributes("confirm-dialog")
4133
+ },
4134
+ footer: ({ close }) => /* @__PURE__ */ jsxs(Fragment, { children: [
4135
+ /* @__PURE__ */ jsx(
4136
+ CancelButton,
4137
+ {
4138
+ onClick: () => {
4139
+ onCancel?.();
4140
+ close();
4141
+ },
4142
+ children: cancelLabel
4143
+ }
4144
+ ),
4145
+ /* @__PURE__ */ jsx(
4146
+ ConfirmButton,
4147
+ {
4148
+ onClick: () => {
4149
+ onConfirm?.();
4150
+ close();
4151
+ },
4152
+ children: confirmLabel
4153
+ }
4154
+ )
4155
+ ] })
4156
+ }
4157
+ );
4158
+ }
4159
+ function DestructiveDialog(props) {
4160
+ const {
4161
+ confirmLabel = "Delete",
4162
+ cancelLabel = "Cancel",
4163
+ onConfirm,
4164
+ onCancel,
4165
+ dataAttributes,
4166
+ ...dialogProps
4167
+ } = props;
4168
+ return /* @__PURE__ */ jsx(
4169
+ DialogModal,
4170
+ {
4171
+ ...dialogProps,
4172
+ dataAttributes: {
4173
+ ...dataAttributes,
4174
+ ...createPurposeSemanticAttributes("destructive-dialog")
4175
+ },
4176
+ footer: ({ close }) => /* @__PURE__ */ jsxs(Fragment, { children: [
4177
+ /* @__PURE__ */ jsx(
4178
+ CancelButton,
4179
+ {
4180
+ onClick: () => {
4181
+ onCancel?.();
4182
+ close();
4183
+ },
4184
+ children: cancelLabel
4185
+ }
4186
+ ),
4187
+ /* @__PURE__ */ jsx(
4188
+ DestructiveButton,
4189
+ {
4190
+ onClick: () => {
4191
+ onConfirm?.();
4192
+ close();
4193
+ },
4194
+ children: confirmLabel
4195
+ }
4196
+ )
4197
+ ] })
4198
+ }
4199
+ );
4200
+ }
4201
+ function InfoDialog(props) {
4202
+ const { acknowledgeLabel = "Okay", onAcknowledge, dataAttributes, ...dialogProps } = props;
4203
+ return /* @__PURE__ */ jsx(
4204
+ DialogModal,
4205
+ {
4206
+ ...dialogProps,
4207
+ dataAttributes: {
4208
+ ...dataAttributes,
4209
+ ...createPurposeSemanticAttributes("info-dialog")
4210
+ },
4211
+ footer: ({ close }) => /* @__PURE__ */ jsx(
4212
+ ConfirmButton,
4213
+ {
4214
+ onClick: () => {
4215
+ onAcknowledge?.();
4216
+ close();
4217
+ },
4218
+ children: acknowledgeLabel
4219
+ }
4220
+ )
4221
+ }
4222
+ );
524
4223
  }
525
4224
 
526
- export { Button, CancelButton, Checkbox, CheckboxField, CreateButton, CurrencyField, DangerButton, Divider, EmailField, H1, H2, H3, Icon, Input, InputField, LinkButton, MarwesProvider, Paragraph, PasswordField, PhoneField, PrimaryButton, SearchField, SecondaryButton, SubmitButton, TextButton, URLField, useRenderKitDebug, useSystem, useTheme };
4225
+ export { Accordion, AccordionField, Avatar, AvatarBadge, AvatarGroup, Badge, BadgeGroup, BrightnessSlider, Button, ButtonSpinner, CancelButton, Card, Checkbox, CheckboxField, CheckboxGroupField, CloseButton, ConfirmButton, ConfirmDialog, ContentTabs, CopyButton, CreateButton, CurrencyField, DateOfBirthField, DestructiveButton, DestructiveDialog, Dialog, DialogModal, Divider, DownloadButton, DropdownButton, DropdownField, EditButton, EmailField, EmptyStateSpinner, ErrorToast, FAQAccordion, FeatureToggle, FilterButton, H1, H2, H3, Icon, InfoDialog, InfoToast, Input, InputField, InputOtp, LinkButton, MarwesProvider, NavigationTabs, NotificationBadge, OptionRadioGroup, Paragraph, PasswordField, PermissionSwitch, PhoneField, PreferenceSwitch, PresenceAvatar, PrimaryButton, PriorityBadge, ProductCard, ProfileAvatar, ProfileCard, Radio, RadioGroupField, RadiusSlider, RatingRadioGroup, RefreshButton, RichText, RichTextField, SaveButton, SearchButton, SearchField, SecondaryButton, SectionsAccordion, Select, SelectField, SettingsAccordion, SettingsTabs, Slider, SliderField, SortButton, Spacer, Spacing, Spinner, StatCard, StatusBadge, SubmitButton, SuccessButton, SuccessToast, Switch, SwitchField, Tab, TabGroup, TabPanel, TeamAvatarGroup, TextButton, Textarea, TextareaField, Toast, ToastContainer, ToastProvider, Tooltip, TooltipGroup, URLField, UploadButton, VerifyButton, VolumeSlider, WarningToast, YesNoRadioGroup, ZipCodeField, useTheme, useToast };
527
4226
  //# sourceMappingURL=index.js.map
528
4227
  //# sourceMappingURL=index.js.map