handy-fluentui 0.1.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/README.md +681 -0
- package/dist/components/fui-button-panel.d.ts +13 -0
- package/dist/components/fui-button-panel.d.ts.map +1 -0
- package/dist/components/fui-image-carousell.d.ts +17 -0
- package/dist/components/fui-image-carousell.d.ts.map +1 -0
- package/dist/components/fui-tab.d.ts +29 -0
- package/dist/components/fui-tab.d.ts.map +1 -0
- package/dist/components/fui-table.d.ts +89 -0
- package/dist/components/fui-table.d.ts.map +1 -0
- package/dist/components/input-checkbox.d.ts +17 -0
- package/dist/components/input-checkbox.d.ts.map +1 -0
- package/dist/components/input-date.d.ts +27 -0
- package/dist/components/input-date.d.ts.map +1 -0
- package/dist/components/input-dropdown.d.ts +33 -0
- package/dist/components/input-dropdown.d.ts.map +1 -0
- package/dist/components/input-group.d.ts +25 -0
- package/dist/components/input-group.d.ts.map +1 -0
- package/dist/components/input-multi-lang.d.ts +35 -0
- package/dist/components/input-multi-lang.d.ts.map +1 -0
- package/dist/components/input-number.d.ts +39 -0
- package/dist/components/input-number.d.ts.map +1 -0
- package/dist/components/input-radio.d.ts +33 -0
- package/dist/components/input-radio.d.ts.map +1 -0
- package/dist/components/input-switch.d.ts +17 -0
- package/dist/components/input-switch.d.ts.map +1 -0
- package/dist/components/input-text.d.ts +19 -0
- package/dist/components/input-text.d.ts.map +1 -0
- package/dist/components/input-textarea.d.ts +20 -0
- package/dist/components/input-textarea.d.ts.map +1 -0
- package/dist/components/input-time.d.ts +31 -0
- package/dist/components/input-time.d.ts.map +1 -0
- package/dist/components/with-input-field.d.ts +49 -0
- package/dist/components/with-input-field.d.ts.map +1 -0
- package/dist/contexts/breadcrumb-context.d.ts +20 -0
- package/dist/contexts/breadcrumb-context.d.ts.map +1 -0
- package/dist/contexts/dialog-context.d.ts +28 -0
- package/dist/contexts/dialog-context.d.ts.map +1 -0
- package/dist/contexts/handy-fluent-ui-context.d.ts +48 -0
- package/dist/contexts/handy-fluent-ui-context.d.ts.map +1 -0
- package/dist/contexts/spinner-context.d.ts +19 -0
- package/dist/contexts/spinner-context.d.ts.map +1 -0
- package/dist/contexts/toast-context.d.ts +17 -0
- package/dist/contexts/toast-context.d.ts.map +1 -0
- package/dist/hooks/use-breadcrumb.d.ts +19 -0
- package/dist/hooks/use-breadcrumb.d.ts.map +1 -0
- package/dist/hooks/use-dialog.d.ts +6 -0
- package/dist/hooks/use-dialog.d.ts.map +1 -0
- package/dist/hooks/use-logger.d.ts +9 -0
- package/dist/hooks/use-logger.d.ts.map +1 -0
- package/dist/hooks/use-mobile.d.ts +4 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-spinner.d.ts +7 -0
- package/dist/hooks/use-spinner.d.ts.map +1 -0
- package/dist/hooks/use-theme.d.ts +8 -0
- package/dist/hooks/use-theme.d.ts.map +1 -0
- package/dist/hooks/use-time-zone.d.ts +17 -0
- package/dist/hooks/use-time-zone.d.ts.map +1 -0
- package/dist/hooks/use-toast.d.ts +9 -0
- package/dist/hooks/use-toast.d.ts.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1571 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/breadcrumb-provider.d.ts +10 -0
- package/dist/providers/breadcrumb-provider.d.ts.map +1 -0
- package/dist/providers/dialog-provider.d.ts +6 -0
- package/dist/providers/dialog-provider.d.ts.map +1 -0
- package/dist/providers/handy-fluent-ui-provider.d.ts +10 -0
- package/dist/providers/handy-fluent-ui-provider.d.ts.map +1 -0
- package/dist/providers/spinner-provider.d.ts +10 -0
- package/dist/providers/spinner-provider.d.ts.map +1 -0
- package/dist/providers/toast-provider.d.ts +9 -0
- package/dist/providers/toast-provider.d.ts.map +1 -0
- package/dist/utils/string-util.d.ts +4 -0
- package/dist/utils/string-util.d.ts.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/contexts/handy-fluent-ui-context.ts","../src/contexts/breadcrumb-context.ts","../src/providers/breadcrumb-provider.tsx","../src/contexts/dialog-context.ts","../src/providers/dialog-provider.tsx","../src/contexts/spinner-context.ts","../src/providers/spinner-provider.tsx","../src/contexts/toast-context.ts","../src/providers/toast-provider.tsx","../src/providers/handy-fluent-ui-provider.tsx","../src/hooks/use-logger.ts","../src/hooks/use-breadcrumb.ts","../src/hooks/use-dialog.ts","../src/hooks/use-mobile.ts","../src/hooks/use-spinner.ts","../src/hooks/use-theme.ts","../src/hooks/use-time-zone.ts","../src/hooks/use-toast.ts","../src/components/fui-button-panel.tsx","../src/components/fui-tab.tsx","../src/utils/string-util.ts","../src/components/with-input-field.tsx","../src/components/input-dropdown.tsx","../src/components/fui-table.tsx","../src/components/fui-image-carousell.tsx","../src/components/input-checkbox.tsx","../src/components/input-date.tsx","../src/components/input-time.tsx","../src/components/input-group.tsx","../src/components/input-text.tsx","../src/components/input-multi-lang.tsx","../src/components/input-number.tsx","../src/components/input-radio.tsx","../src/components/input-switch.tsx","../src/components/input-textarea.tsx"],"sourcesContent":["import {\n Theme,\n} from '@fluentui/react-components';\nimport { createContext } from 'react';\n\nimport { SpinnerContextConfig } from './spinner-context';\nimport { ToastContextConfig } from './toast-context';\n\n// ─── Language ────────────────────────────────────────────────────────────────\n\n/** Provider-level configuration for spinner and toast. */\ntype Component = {\n spinner?: SpinnerContextConfig;\n toast?: ToastContextConfig;\n};\n\n// ─── Theme ───────────────────────────────────────────────────────────────────\n\n/** Active theme key. 'custom' is only selectable when a custom Theme object is supplied in SupportedTheme. */\ntype ThemeType = 'light' | 'dark' | 'custom';\n\n/** Per-slot theme objects for one platform. Omit a key to fall back to the built-in FluentUI theme. */\ntype ThemeMapping = {\n light?: Theme;\n dark?: Theme;\n custom?: Theme;\n};\n\n/** Separate theme sets for web and mobile viewports, plus an optional startup default. */\ntype SupportedTheme = {\n web?: ThemeMapping;\n mobile?: ThemeMapping;\n default?: ThemeType;\n};\n\n// ─── Logging ─────────────────────────────────────────────────────────────────\n\n/** Severity levels for logMessage and useLogger. */\ntype LoggingLevel = 'info' | 'warn' | 'error' | 'debug';\n\n// ─── Config & Context ────────────────────────────────────────────────────────\n\n/** Configuration prop of HandyFluentUiProvider. All fields are optional; sensible defaults are provided. */\ntype HandyFluentUiConfig = {\n /** Viewport width (px) at which the mobile layout activates. Defaults to 600. */\n mobileBreakpoint?: number;\n supportedTheme?: SupportedTheme;\n component?: Component;\n loggerConfig?: {\n /** Custom logger. Defaults to console.log with a [LEVEL] prefix when omitted. */\n logMessage?: (message: string, level: LoggingLevel) => void;\n };\n};\n\n/** Context shape consumed by useTheme, useLogger, and useIsMobile. */\ntype HandyFluentUiContextType = {\n selectedTheme: ThemeType;\n supportedThemeType: ThemeType[];\n switchTheme: (themeType: ThemeType) => void;\n mobileBreakpoint: number;\n // IANA timezone or UTC offset\n timeZone: string;\n logMessage: (message: string, level?: LoggingLevel) => void;\n};\n\nconst HandyFluentUiContext = createContext<HandyFluentUiContextType | undefined>(undefined);\n\nexport { HandyFluentUiContext };\nexport type {\n Component,\n ThemeType,\n SupportedTheme,\n LoggingLevel,\n HandyFluentUiConfig,\n HandyFluentUiContextType,\n};\n","import { createContext } from 'react';\n\n/** Represents a single item in the breadcrumb trail. */\ntype BreadcrumbItem = {\n /** Optional user-provided tag for identifying the item. */\n tag?: string;\n /** Label supplier for the breadcrumb item. */\n label: () => string;\n /** Optional action to trigger when the breadcrumb item is clicked. The trail is automatically truncated up to this item. */\n action?: () => void;\n};\n\n/** Context type for managing the global breadcrumb trail. */\ntype BreadcrumbContextType = {\n /** Current items in the breadcrumb trail. */\n items: BreadcrumbItem[];\n /** State setter for the breadcrumb items. */\n setItems: React.Dispatch<React.SetStateAction<BreadcrumbItem[]>>;\n};\n\nconst BreadcrumbContext = createContext<BreadcrumbContextType | undefined>(undefined);\n\nexport { BreadcrumbContext as FuiBreadcrumbContext };\nexport type { BreadcrumbItem };\n","import { ReactNode, useState } from 'react';\n\nimport { BreadcrumbItem, FuiBreadcrumbContext } from '@context/breadcrumb-context';\n\n/**\n * Provides state management for the global breadcrumb trail.\n * Consumed via useBreadcrumb() hook.\n */\nconst BreadcrumbProvider = ({ children }: { children: ReactNode }) => {\n const [breadcrumbItems, setBreadcrumbItems] = useState<BreadcrumbItem[]>([]);\n\n return (\n <FuiBreadcrumbContext.Provider value={{ items: breadcrumbItems, setItems: setBreadcrumbItems }}>\n {children}\n </FuiBreadcrumbContext.Provider>\n );\n};\n\nexport { BreadcrumbProvider };\n","import { createContext } from 'react';\n\ntype BaseDialogButton = { label: string; icon?: React.ReactElement };\n/** Primary CTA button; action is required. */\ntype PositiveDialogButton = BaseDialogButton & { action: () => void };\n/** Secondary or tertiary button; action is optional. */\ntype NegativeDialogButton = BaseDialogButton & { action?: () => void };\n\n/** Props for openDialog(). primaryButton appears on the right; secondary/tertiary are to its left in order. */\ntype ConfirmationDialogProps = {\n title: string;\n content: string;\n primaryButton: PositiveDialogButton;\n secondaryButton?: NegativeDialogButton;\n tertiaryButton?: NegativeDialogButton;\n};\n\ntype DialogContextType = {\n /** Opens the global confirmation dialog. */\n openDialog: (dialogProps: ConfirmationDialogProps) => void;\n};\n\nconst DialogContext = createContext<DialogContextType>({\n // empty default implementation, should be overridden by provider\n openDialog: () => {},\n});\n\nexport { DialogContext as FuiDialogContext };\nexport type { ConfirmationDialogProps };\n","import {\n Dialog,\n Button,\n DialogSurface,\n DialogBody,\n DialogTitle,\n DialogContent,\n DialogActions,\n} from '@fluentui/react-components';\nimport React, { ReactNode, useCallback, useState } from 'react';\n\nimport { FuiDialogContext, ConfirmationDialogProps } from '@context/dialog-context';\n\ntype FuiDialogButton = {\n label: string;\n icon?: React.ReactElement;\n disabled?: boolean;\n cta?: boolean;\n action?: () => void;\n};\n\ntype DialogProps = {\n title: string;\n content: string;\n buttons: FuiDialogButton[];\n visible: boolean;\n};\n\nconst FuiDialog: React.FC<DialogProps> = ({ title, content, buttons, visible }: DialogProps) => {\n return (\n <Dialog modalType=\"alert\" open={visible}>\n <DialogSurface>\n <DialogBody>\n <DialogTitle>{title}</DialogTitle>\n <DialogContent>{content}</DialogContent>\n <DialogActions>\n {buttons.map((b, index) => {\n return (\n <Button\n key={index}\n // no need to highlight primary button if there's only one button, as it will be visually emphasized by being the only option\n appearance={buttons.length > 1 && (b.cta ?? false) ? 'primary' : 'secondary'}\n disabled={b.disabled}\n icon={b.icon}\n onClick={b.action}\n >\n {b.label}\n </Button>\n );\n })}\n </DialogActions>\n </DialogBody>\n </DialogSurface>\n </Dialog>\n );\n};\n\ntype DialogState = {\n dialogProps?: ConfirmationDialogProps;\n openTime: number;\n closeTime: number;\n};\n\nconst createDialog = (\n { title, content, primaryButton, secondaryButton, tertiaryButton }: ConfirmationDialogProps,\n closeDialog: () => void,\n) => {\n const buttons: FuiDialogButton[] = [{ ...primaryButton, cta: true }];\n if (secondaryButton) {\n buttons.push({ ...secondaryButton, cta: false });\n }\n if (tertiaryButton) {\n buttons.push({ ...tertiaryButton, cta: false });\n }\n\n return (\n <FuiDialog\n // Reverse so the primary (CTA) button ends up on the right visually,\n // while secondary/tertiary remain in descending priority order to the left.\n buttons={buttons.reverse().map(({ action, ...others }) => {\n return {\n ...others,\n action: () => {\n closeDialog();\n if (action) {\n action();\n }\n },\n };\n })}\n content={content}\n title={title}\n visible={true}\n ></FuiDialog>\n );\n};\n\nconst DialogProvider = ({ children }: { children: ReactNode }) => {\n const [dialogState, setDialogState] = useState<DialogState>({\n dialogProps: undefined,\n openTime: 0,\n closeTime: 0,\n });\n\n const openDialog = useCallback((dialogProps: ConfirmationDialogProps) => {\n setDialogState((s) => ({ ...s, dialogProps, openTime: Date.now() }));\n }, []);\n\n // Timestamps instead of a boolean flag so that rapid open→close→open sequences\n // always reflect the latest intent without stale-closure races.\n const dialog =\n dialogState.dialogProps && dialogState.openTime > dialogState.closeTime ? (\n createDialog(dialogState.dialogProps, () =>\n setDialogState((s) => ({ ...s, closeTime: Date.now() })),\n )\n ) : (\n <></>\n );\n\n return (\n <FuiDialogContext.Provider value={{ openDialog }}>\n {children}\n {dialog}\n </FuiDialogContext.Provider>\n );\n};\n\nexport { DialogProvider };\n","import { createContext } from 'react';\n\n/** Global spinner configuration passed to HandyFluentUiProvider via spinnerConfig. */\ntype SpinnerContextConfig = {\n /** Milliseconds before the overlay becomes visible. Prevents flicker on fast operations. Defaults to 300. */\n initialDelay?: number;\n /** Default label supplier when show() is called without an explicit label. */\n label: {\n loading?: () => string;\n }\n};\n\n/** Imperative handle to the global overlay spinner, returned by useSpinner. */\ntype SpinnerContextType = {\n /** Shows the overlay spinner, optionally overriding defaultLabel. */\n show: (label?: string) => void;\n hide: () => void;\n};\n\nconst SpinnerContext = createContext<SpinnerContextType>({\n show: () => {},\n hide: () => {},\n});\n\nexport { SpinnerContext as FuiSpinnerContext };\nexport type { SpinnerContextConfig };","import { makeStyles, Spinner } from '@fluentui/react-components';\nimport { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { FuiSpinnerContext, SpinnerContextConfig } from '@context/spinner-context';\n\nconst useStyles = makeStyles({\n overlay: {\n position: 'fixed',\n inset: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 9999,\n },\n});\n\ntype SpinnerProviderProps = {\n config?: SpinnerContextConfig;\n children: ReactNode;\n};\n\nconst SpinnerProvider = ({ children, config }: SpinnerProviderProps) => {\n const styles = useStyles();\n const { initialDelay, label } = config ?? {};\n\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Counter instead of boolean to correctly handle concurrent show/hide calls.\n const [count, setCount] = useState(0);\n const [loadingLabel, setLoadingLabel] = useState<string | undefined>();\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n };\n }, []);\n\n const show = useCallback(\n (text?: string) => {\n setLoadingLabel(text || label?.loading);\n // Only show spinner if loading > 300ms:\n timerRef.current = setTimeout(() => {\n setCount((c) => c + 1);\n timerRef.current = null; // sentinel: null means the timer has fired, not that it was cancelled\n }, initialDelay ?? 300);\n },\n [config],\n );\n\n const hide = useCallback(() => {\n if (timerRef.current !== null) {\n // cancel incrementing count if loading is done before initialDelay\n clearTimeout(timerRef.current);\n timerRef.current = null;\n } else {\n setCount((c) => Math.max(0, c - 1));\n }\n setLoadingLabel(undefined);\n }, []);\n\n const value = useMemo(() => ({ show, hide }), [show, hide]);\n\n return (\n <FuiSpinnerContext.Provider value={value}>\n {children}\n {count > 0 && (\n <div className={styles.overlay}>\n <Spinner label={loadingLabel} />\n </div>\n )}\n </FuiSpinnerContext.Provider>\n );\n};\n\nexport { SpinnerProvider };\nexport type { SpinnerProviderProps };\n","import { ToastIntent, ToastPosition, ToastProps } from '@fluentui/react-components';\nimport { createContext } from 'react';\n\n/** Toast display configuration passed to HandyFluentUiProvider via toastConfig. */\ntype ToastContextConfig = {\n /** Auto-dismiss delay in milliseconds. */\n dismissTimeout?: number;\n position?: ToastPosition;\n /** Fully custom toast factory. When provided, built-in toast rendering is bypassed entirely. */\n toastCreator?: (message: string, intent: ToastIntent) => React.ReactElement<ToastProps>;\n};\n\n/** Imperative toast handle. Prefer the useToast hook which provides intent-specific helpers. */\ntype ToastContextType = {\n show: (intent: ToastIntent, message: string, dismissLabel?: string, intentLabel?: string) => void;\n};\n\nconst ToastContext = createContext<ToastContextType>({\n show: () => {},\n});\n\nexport { ToastContext as FuiToastContext };\nexport type { ToastContextConfig };\n","import {\n Link,\n Toaster,\n Toast,\n ToastTitle,\n useToastController,\n ToastIntent,\n ToastBody,\n ToastTrigger,\n} from '@fluentui/react-components';\nimport { DismissRegular } from '@fluentui/react-icons';\nimport React, { ReactNode, useCallback, useMemo } from 'react';\n\nimport { FuiToastContext, ToastContextConfig } from '@context/toast-context';\n\ntype ToastProviderProps = {\n config?: ToastContextConfig;\n children: ReactNode;\n};\n\nconst ToastProvider = ({ config, children }: ToastProviderProps) => {\n\n const { dismissTimeout, position, toastCreator } = config ?? {};\n\n const { dispatchToast, updateToast } = useToastController();\n\n const show = useCallback(\n (intent: ToastIntent, message: string, dismissLabel?: string, intentLabel?: string) => {\n if (toastCreator) {\n dispatchToast(toastCreator(message, intent), {\n intent,\n position,\n timeout: intent === 'error' ? -1 : dismissTimeout,\n });\n return;\n }\n\n const dismissAction = dismissLabel ? (\n <ToastTrigger>\n <Link>{dismissLabel}</Link>\n </ToastTrigger>\n ) : (\n <ToastTrigger>\n <DismissRegular />\n </ToastTrigger>\n );\n\n const resolvedLabel = intentLabel ?? (intent.charAt(0).toUpperCase() + intent.slice(1));\n\n const buildContent = (action: React.ReactElement | null | undefined) => (\n <Toast appearance=\"inverted\">\n <ToastTitle action={action}>{resolvedLabel}</ToastTitle>\n <ToastBody>{message}</ToastBody>\n </Toast>\n );\n\n if (intent === 'error') {\n if (dismissTimeout && dismissTimeout > 0) {\n // Show without dismiss button initially; reveal it after dismissTimeout so\n // the user has time to read before being prompted to close.\n const toastId = `fui-toast-${Date.now()}-${Math.random()}`;\n dispatchToast(buildContent(undefined), { intent, position, timeout: -1, toastId });\n setTimeout(() => {\n updateToast({ content: buildContent(dismissAction), timeout: -1, toastId });\n }, dismissTimeout);\n } else {\n // No timeout configured — dismiss button visible immediately.\n dispatchToast(buildContent(dismissAction), { intent, position, timeout: -1 });\n }\n } else {\n dispatchToast(buildContent(dismissAction), { intent, position, timeout: dismissTimeout });\n }\n },\n [config, dispatchToast, updateToast],\n );\n\n const value = useMemo(() => ({ show }), [show]);\n\n return (\n <FuiToastContext.Provider value={value}>\n {children}\n {/* Must be rendered once in app */}\n <Toaster />\n </FuiToastContext.Provider>\n );\n};\n\nexport { ToastProvider };\n","import {\n FluentProvider,\n teamsDarkV21Theme,\n teamsLightV21Theme,\n Theme,\n webDarkTheme,\n webLightTheme,\n} from '@fluentui/react-components';\nimport React, { ReactNode, useCallback, useState } from 'react';\nimport { useMediaQuery } from 'usehooks-ts';\n\nimport {\n HandyFluentUiContext,\n HandyFluentUiConfig,\n LoggingLevel,\n ThemeType,\n} from '@context/handy-fluent-ui-context';\n\nimport { BreadcrumbProvider } from './breadcrumb-provider';\nimport { DialogProvider } from './dialog-provider';\nimport { SpinnerProvider } from './spinner-provider';\nimport { ToastProvider } from './toast-provider';\n\n// ─── Theme constants ─────────────────────────────────────────────────────────\n\ntype ThemeMapping = {\n light?: Theme;\n dark?: Theme;\n custom?: Theme;\n};\n\nconst DESKTOP_THEME = {\n light: webLightTheme,\n dark: webDarkTheme,\n};\n\n// Teams themes provide better mobile UX; Fluent web themes have known issues at mobile sizes\n// (too-small font, components that don't fit the viewport).\nconst MOBILE_THEME = {\n light: teamsLightV21Theme,\n dark: teamsDarkV21Theme,\n};\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nconst mergeThemeMapping = (\n input: ThemeMapping | undefined,\n defaults: ThemeMapping,\n): ThemeMapping => ({\n light: input?.light ?? defaults.light,\n dark: input?.dark ?? defaults.dark,\n custom: input?.custom ?? defaults.custom,\n});\n\nconst resolveThemeMapping = (supportedTheme?: HandyFluentUiConfig['supportedTheme']) => {\n // A custom theme is shared across both platforms unless each is explicitly overridden,\n // so consumers don't have to duplicate the same theme object for web and mobile.\n return {\n web: mergeThemeMapping(supportedTheme?.web, {\n ...DESKTOP_THEME,\n custom: supportedTheme?.mobile?.custom,\n }),\n mobile: mergeThemeMapping(supportedTheme?.mobile, {\n ...MOBILE_THEME,\n custom: supportedTheme?.web?.custom,\n }),\n default: supportedTheme?.default,\n };\n};\n\nconst resolveDefaultThemeType = (\n defaultThemeType?: ThemeType,\n supportedTheme?: ThemeType[],\n): ThemeType => {\n // If default theme type is not provided or is 'custom' but custom theme is not provided, use system preference with fallback to 'light'\n const fallbackThemeType = 'light';\n if (\n defaultThemeType === undefined ||\n (defaultThemeType === 'custom' && !supportedTheme?.includes('custom'))\n ) {\n if (typeof window === 'undefined') {\n return fallbackThemeType; // SSR fallback\n }\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n return defaultThemeType ?? fallbackThemeType;\n};\n\n// ─── Provider ────────────────────────────────────────────────────────────────\n\nconst defaultHandyFluentUiConfig = {\n mobileBreakpoint: 600,\n supportedLanguage: { iso: 'en', name: 'English' },\n supportedTheme: {\n web: DESKTOP_THEME,\n mobile: MOBILE_THEME,\n },\n};\n\ntype HandyFluentUiProviderProps = HandyFluentUiConfig & {\n children: ReactNode;\n};\n\nconst HandyFluentUiProvider = ({\n mobileBreakpoint,\n component,\n supportedTheme,\n loggerConfig: logMessageConfig,\n children,\n}: HandyFluentUiProviderProps) => {\n // resolve theme mapping with fallback to default themes if not provided\n const resolvedThemeMapping = resolveThemeMapping(supportedTheme);\n const supportedThemeType: ThemeType[] =\n resolvedThemeMapping.web.custom || resolvedThemeMapping.mobile.custom\n ? ['light', 'dark', 'custom']\n : ['light', 'dark'];\n const [currentTheme, setCurrentTheme] = useState<ThemeType>(\n resolveDefaultThemeType(supportedTheme?.default, supportedThemeType),\n );\n const resolvedBreakpoint = mobileBreakpoint ?? defaultHandyFluentUiConfig.mobileBreakpoint;\n\n const isMobile = useMediaQuery(`(max-width: ${resolvedBreakpoint}px)`);\n const fluentTheme = isMobile\n ? resolvedThemeMapping.mobile[currentTheme]\n : resolvedThemeMapping.web[currentTheme];\n const switchTheme = useCallback((themeType: ThemeType) => {\n setCurrentTheme(themeType);\n }, []);\n const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n const logMessage = useCallback(\n (message: string, level: LoggingLevel = 'info') => {\n if (logMessageConfig?.logMessage) {\n logMessageConfig.logMessage(message, level);\n } else {\n // eslint-disable-next-line no-console\n console.log(`[${level.toUpperCase()}] ${message}`);\n }\n },\n [logMessageConfig],\n );\n\n return (\n <HandyFluentUiContext.Provider\n value={{\n logMessage,\n mobileBreakpoint: resolvedBreakpoint,\n selectedTheme: currentTheme,\n supportedThemeType,\n switchTheme,\n timeZone,\n }}\n >\n <FluentProvider theme={fluentTheme}>\n <SpinnerProvider config={component?.spinner}>\n <DialogProvider>\n <ToastProvider config={component?.toast}>\n <BreadcrumbProvider>{children}</BreadcrumbProvider>\n </ToastProvider>\n </DialogProvider>\n </SpinnerProvider>\n </FluentProvider>\n </HandyFluentUiContext.Provider>\n );\n};\n\nexport { HandyFluentUiProvider, resolveDefaultThemeType };\nexport type { HandyFluentUiProviderProps };\n","import { useContext } from 'react';\n\nimport { HandyFluentUiContext } from '@context/handy-fluent-ui-context';\n\n/** Returns error/info/warn logging functions that delegate to logMessage in HandyFluentUiContext. */\nconst useLogger = () => {\n const ctx = useContext(HandyFluentUiContext);\n if (!ctx) {\n throw new Error('useLogger must be used within HandyFluentUiProvider');\n }\n\n const logMessage = ctx.logMessage;\n return {\n debug: (msg: string) => logMessage(msg, 'debug'),\n error: (msg: string) => logMessage(msg, 'error'),\n info: (msg: string) => logMessage(msg, 'info'),\n warn: (msg: string) => logMessage(msg, 'warn'),\n };\n};\n\nexport { useLogger };\n","import { useContext } from 'react';\n\nimport { BreadcrumbItem, FuiBreadcrumbContext } from '@context/breadcrumb-context';\n\nimport { useLogger } from './use-logger';\n\n/**\n * Hook to manage a global breadcrumb trail.\n * Actions provided to start() or append() are automatically wrapped to truncate the trail when invoked.\n */\nconst useBreadcrumb = () => {\n const ctx = useContext(FuiBreadcrumbContext);\n if (!ctx) {\n throw new Error('useBreadcrumb must be used within FuiBreadcrumbContextProvider');\n }\n\n const logger = useLogger();\n\n return {\n /** Current breadcrumb items in the trail. */\n items: [...ctx.items],\n\n /** Resets the trail with the provided item. Action is reconstructed to handle truncation. */\n start: (item: BreadcrumbItem) => {\n logger.debug(`[useBreadcrumb] start() with tag ${item.tag}`);\n const action = item.action;\n const wrapped: BreadcrumbItem = {\n ...item,\n action: action\n ? () => {\n action();\n ctx.setItems([wrapped]);\n }\n : undefined,\n };\n ctx.setItems([wrapped]);\n },\n\n /** Appends an item to the current trail. Action is reconstructed to handle truncation. */\n append: (item: BreadcrumbItem) => {\n logger.debug(\n `[useBreadcrumb] append() with tag ${item.tag}, action = ${item.action === undefined}`,\n );\n const action = item.action;\n const wrapped: BreadcrumbItem = {\n ...item,\n action: action\n ? () => {\n action();\n // targetIndex is resolved inside the updater to use the live state\n ctx.setItems((current) => {\n const idx = current.findIndex((i) => i === wrapped);\n return current.slice(0, idx + 1);\n });\n }\n : undefined,\n };\n ctx.setItems((current) => {\n const last = current[current.length - 1];\n if (item.tag !== undefined && last?.tag === item.tag) {\n logger.warn(\n `[useBreadcrumb] append(), the tag of last item is ${item.tag}, ignored append`,\n );\n return current;\n }\n return [...current, wrapped];\n });\n },\n\n /** Get the last item in current trail */\n peek: (): BreadcrumbItem | undefined => {\n return ctx.items[ctx.items.length - 1];\n },\n\n /** Removes items from the trail. If tillTag is provided, removes until that item (inclusive). Otherwise removes one. */\n popTill: (tillTag?: string) => {\n logger.debug(`[useBreadcrumb] popTill(), no of items = ${ctx.items.length}`);\n ctx.setItems((current) => {\n if (tillTag) {\n const index = current.findIndex((item) => item.tag === tillTag);\n if (index === -1) {\n logger.warn(`[useBreadcrumb] popTill(), tag \"${tillTag}\" not found, trail unchanged`);\n return current;\n }\n return current.slice(0, index);\n }\n if (current.length === 0) {\n return current;\n }\n const rtn = current.slice(0, -1);\n logger.debug(`[useBreadcrumb] popTill(), no of items after pop = ${rtn.length}`);\n return rtn;\n });\n },\n };\n};\n\nexport { useBreadcrumb };\n","import { useContext } from 'react';\n\nimport { FuiDialogContext } from '@context/dialog-context';\n\n/** Returns the dialog context handle. Call openDialog() to show a confirmation dialog. */\nconst useDialog = () => useContext(FuiDialogContext);\n\nexport { useDialog };\n","import { useContext } from 'react';\nimport { useMediaQuery } from 'usehooks-ts';\n\nimport { HandyFluentUiContext } from '@context/handy-fluent-ui-context';\n\n/** Returns true when the viewport width is at or below mobileBreakpoint. */\nconst useIsMobile = (): boolean => {\n const ctx = useContext(HandyFluentUiContext);\n if (!ctx) {\n throw new Error('useIsMobile must be used within HandyFluentUiProvider');\n }\n return useMediaQuery(`(max-width: ${ctx.mobileBreakpoint}px)`);\n};\n\nexport { useIsMobile };\n","import { useContext } from 'react';\n\nimport { FuiSpinnerContext } from '@context/spinner-context';\n\n/** Returns show/hide handles for the global overlay spinner. */\nconst useSpinner = () => useContext(FuiSpinnerContext);\n\nexport { useSpinner };\n","import { useContext } from 'react';\n\nimport { HandyFluentUiContext, ThemeType } from '@context/handy-fluent-ui-context';\n\n/** Returns the current theme and a guarded switchTheme that only accepts values in supportedThemeType. */\nconst useTheme = () => {\n const ctx = useContext(HandyFluentUiContext);\n if (!ctx) {\n throw new Error('useTheme must be used within HandyFluentUiProvider');\n }\n\n const { selectedTheme, supportedThemeType, switchTheme } = ctx;\n return {\n currentTheme: selectedTheme,\n switchTheme: (themeType: ThemeType) => {\n // only switch if the themeType is in the supported list to prevent invalid theme switch\n supportedThemeType.includes(themeType) && switchTheme(themeType);\n },\n };\n};\n\nexport { useTheme };\n","import { useContext } from 'react';\n\nimport { HandyFluentUiContext } from '@context/handy-fluent-ui-context';\n\ntype LocalDate = {\n year: number;\n month: number;\n day: number;\n hour: number;\n minute: number;\n second: number;\n};\n\n/** Returns handler to get and set current timezone, and extract date parts of a date in current timezone */\nconst useTimeZone = () => {\n const ctx = useContext(HandyFluentUiContext);\n if (!ctx) {\n throw new Error('useTimezone must be used within HandyFluentUiProvider');\n }\n\n const isValidTimeZone = (tz: string): boolean => {\n try {\n Intl.DateTimeFormat(undefined, { timeZone: tz });\n return true;\n } catch {\n ctx.logMessage(`Invalid timeZone = ${tz}`, 'warn');\n return false;\n }\n };\n\n const setTimeZone = (tz: string) => {\n if (isValidTimeZone(tz)) {\n ctx.timeZone = tz;\n }\n };\n\n const zonedDate2LocalDate = (date: Date, tz?: string): LocalDate => {\n if (tz && !isValidTimeZone(tz)) {\n return {\n year: date.getFullYear(),\n month: date.getMonth(),\n day: date.getDate(),\n hour: date.getHours(),\n minute: date.getMinutes(),\n second: date.getSeconds(),\n };\n }\n\n const parts = new Intl.DateTimeFormat(undefined, {\n timeZone: tz ?? ctx.timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hourCycle: 'h23',\n }).formatToParts(date);\n\n const { year, month, day, hour, minute, second } = Object.fromEntries(\n parts\n .filter(\n (\n part,\n ): part is Intl.DateTimeFormatPart & {\n type: Exclude<Intl.DateTimeFormatPartTypes, 'literal'>;\n } => part.type !== 'literal',\n )\n .map((part) => [part.type, Number(part.value)]),\n );\n\n return {\n year,\n month,\n day,\n hour,\n minute,\n second,\n };\n };\n\n return {\n timeZone: ctx.timeZone,\n setTimeZone,\n zonedDate2LocalDate,\n };\n};\n\nexport { useTimeZone };\nexport type { LocalDate };","import { useContext } from 'react';\n\nimport { FuiToastContext } from '@context/toast-context';\n\n/** Returns intent-specific helpers (success, error, warning, info) wrapping the underlying show() call. */\nconst useToast = () => {\n const { show } = useContext(FuiToastContext);\n return {\n success: (msg: string, dismissLabel?: string, intentLabel?: string) => show('success', msg, dismissLabel, intentLabel),\n error: (msg: string, dismissLabel?: string, intentLabel?: string) => show('error', msg, dismissLabel, intentLabel),\n warning: (msg: string, dismissLabel?: string, intentLabel?: string) => show('warning', msg, dismissLabel, intentLabel),\n info: (msg: string, dismissLabel?: string, intentLabel?: string) => show('info', msg, dismissLabel, intentLabel),\n };\n};\n\nexport { useToast };\n","import { makeStyles, mergeClasses, tokens } from '@fluentui/react-components';\nimport React from 'react';\n\nimport { useIsMobile } from '@hook/use-mobile';\nconst useStyles = makeStyles({\n root: {\n display: 'flex',\n gap: tokens.spacingHorizontalM,\n },\n row: {\n flexDirection: 'row',\n },\n column: {\n flexDirection: 'column',\n alignItems: 'stretch',\n },\n left: {\n justifyContent: 'flex-start',\n },\n right: {\n justifyContent: 'flex-end',\n },\n});\n\n/** Props for FuiButtonPanel. */\ntype ButtonPanelProps = {\n className?: string;\n /** Horizontal alignment of buttons. Defaults to `'right'`. */\n alignItems?: 'left' | 'right';\n children: React.ReactNode;\n};\n\n/** Flex row of action buttons that collapses to a full-width column on mobile. */\nconst FuiButtonPanel: React.FC<ButtonPanelProps> = ({\n className,\n alignItems = 'right',\n children,\n}) => {\n const styles = useStyles();\n const isMobile = useIsMobile();\n\n return (\n <div\n className={mergeClasses(\n styles.root,\n isMobile ? styles.column : styles.row,\n alignItems === 'left' ? styles.left : styles.right,\n className,\n )}\n >\n {children}\n </div>\n );\n};\n\nexport { FuiButtonPanel };\nexport type { ButtonPanelProps };\n","import {\n Tab,\n TabList,\n TabListProps,\n TabProps,\n makeStyles,\n mergeClasses,\n tokens,\n SelectTabEvent,\n SelectTabData,\n} from '@fluentui/react-components';\nimport React from 'react';\n\nimport { useIsMobile } from '@hook/use-mobile';\n\nconst useStyles = makeStyles({\n root: {\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n },\n rootVertical: {\n flexDirection: 'row',\n },\n tabList: {\n width: 'max-content',\n },\n tabListVertical: {\n borderBottom: 'none',\n borderRight: `1px solid ${tokens.colorNeutralStroke2}`,\n minWidth: '0',\n width: 'auto',\n },\n scrollWrapper: {\n width: '100%',\n overflowX: 'auto',\n WebkitOverflowScrolling: 'touch',\n '::-webkit-scrollbar': {\n display: 'none',\n },\n msOverflowStyle: 'none',\n scrollbarWidth: 'none',\n },\n content: {\n paddingTop: tokens.spacingVerticalM,\n flexGrow: 1,\n },\n contentVertical: {\n paddingTop: '0',\n paddingLeft: tokens.spacingHorizontalM,\n },\n tabTextSelected: {\n color: tokens.colorBrandForeground1,\n },\n});\n\n/** Accepted tab identifier type. */\ntype FuiTabValue = string | number;\n\n/** Typed wrapper around SelectTabData that narrows value to T. */\ntype FuiSelectTabData<T extends FuiTabValue> = Omit<SelectTabData, 'value'> & {\n value: T;\n};\n\n/** Config for a single tab. value defaults to name when omitted. */\ntype FuiTabProps<T extends FuiTabValue = FuiTabValue> = Omit<TabProps, 'value'> & {\n name: string;\n value?: T;\n children?: React.ReactNode;\n};\n\nconst TAB_MARKER = Symbol.for('FuiTab');\n\n/** Config-carrier for a single tab. Must be a direct child of FuiTabList. Renders nothing itself. */\nconst FuiTab = Object.assign(\n <T extends FuiTabValue>(_props: FuiTabProps<T>) => null,\n { _marker: TAB_MARKER },\n);\n\n/** Props for FuiTabList. selectedValue and onTabSelect are typed to T. */\ntype FuiTabListProps<T extends FuiTabValue = FuiTabValue> = Omit<\n TabListProps,\n 'selectedValue' | 'onTabSelect'\n> & {\n selectedValue?: T;\n onTabSelect?: (data: FuiSelectTabData<T>) => void;\n children: React.ReactNode;\n};\n\n/** Tab list with an inline content panel. Forces horizontal layout on mobile regardless of the vertical prop. */\nconst FuiTabList = <T extends FuiTabValue>(props: FuiTabListProps<T>) => {\n const { children, vertical, selectedValue, onTabSelect, ...rest } = props;\n const isMobile = useIsMobile();\n const styles = useStyles();\n\n const isVertical = !isMobile && vertical;\n\n // Extract tab definitions from children\n const tabs = React.Children.toArray(children)\n .filter(\n (child): child is React.ReactElement<FuiTabProps<T>> =>\n React.isValidElement(child) && (child.type as any)?._marker === TAB_MARKER,\n )\n .map((child) => ({\n props: child.props,\n value: (child.props.value ?? child.props.name) as T,\n }));\n\n const handleTabSelect = (_ev: SelectTabEvent, data: SelectTabData) => {\n onTabSelect?.(data as FuiSelectTabData<T>);\n };\n\n const tabList = (\n <TabList\n {...rest}\n className={isVertical ? styles.tabListVertical : styles.tabList}\n onTabSelect={handleTabSelect}\n selectedValue={selectedValue}\n vertical={isVertical}\n >\n {tabs.map((tab) => (\n <Tab key={String(tab.value)} {...tab.props} value={tab.value}>\n <span className={tab.value === selectedValue ? styles.tabTextSelected : undefined}>\n {tab.props.name}\n </span>\n </Tab>\n ))}\n </TabList>\n );\n\n const selectedTab = tabs.find((t) => t.value === selectedValue);\n\n return (\n <div className={mergeClasses(styles.root, isVertical && styles.rootVertical)}>\n {isMobile ? <div className={styles.scrollWrapper}>{tabList}</div> : tabList}\n {selectedTab && (\n <div\n className={mergeClasses(styles.content, isVertical && styles.contentVertical)}\n >\n {selectedTab.props.children}\n </div>\n )}\n </div>\n );\n};\n\nexport { FuiTab, FuiTabList };\nexport type { FuiTabProps as TabProps, TabListProps };\n","type TemplateData = Record<string, unknown>;\n\nexport const template = (str: string, data: TemplateData): string => {\n return str.replace(/{{\\s*([\\w.]+)\\s*}}/g, (_, path: string) => {\n const value = path.split('.').reduce<unknown>((obj, key) => {\n if (obj && typeof obj === 'object' && key in obj) {\n return (obj as Record<string, unknown>)[key];\n }\n return undefined;\n }, data);\n\n return value != null ? String(value) : '';\n });\n};\n","import {\n Label,\n InfoLabel,\n makeStyles,\n tokens,\n Caption1,\n useId,\n mergeClasses,\n} from '@fluentui/react-components';\nimport { EraserRegular } from '@fluentui/react-icons';\nimport React from 'react';\n\nimport { useIsMobile } from '@hook/use-mobile';\n\nconst useStyles = makeStyles({\n rootVertical: {\n display: 'flex',\n flexDirection: 'column',\n gap: '2px',\n },\n rootHorizontal: {\n display: 'flex',\n alignItems: 'flex-start',\n gap: tokens.spacingHorizontalM,\n },\n rootHorizontalRow: {\n flexDirection: 'row',\n },\n rootHorizontalColumn: {\n flexDirection: 'column',\n gap: '2px',\n },\n labelContainer: {\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n gap: '4px',\n overflow: 'hidden',\n flexShrink: 1,\n },\n eraserIcon: {\n cursor: 'pointer',\n color: tokens.colorNeutralForeground3,\n fontSize: '16px',\n flexShrink: 0,\n ':hover': {\n color: tokens.colorNeutralForeground2,\n },\n },\n labelHorizontal: {\n minHeight: '32px',\n display: 'flex',\n alignItems: 'center',\n flexShrink: 0,\n },\n labelHorizontalColumn: {\n width: '100% !important',\n minHeight: 'auto',\n },\n labelSmall: { width: '10%' },\n labelMedium: { width: '20%' },\n labelLarge: { width: '30%' },\n labelNone: { width: 'auto' },\n labelComponent: {\n display: 'inline-flex',\n alignItems: 'center',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n minWidth: 0,\n flexShrink: 1,\n },\n labelText: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n },\n fieldGroup: {\n display: 'flex',\n flexDirection: 'column',\n flexGrow: 1,\n width: '100%',\n },\n messageContainer: {\n display: 'flex',\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n gap: tokens.spacingHorizontalM,\n },\n message: {\n lineHeight: tokens.spacingVerticalL,\n paddingLeft: tokens.spacingHorizontalM,\n },\n messagePlaceholder: {\n visibility: 'hidden',\n },\n additionalMessage: {\n flexShrink: 0,\n color: tokens.colorNeutralForeground3,\n },\n errorMessage: {\n color: tokens.colorPaletteRedForeground1,\n },\n infoMessage: {\n color: tokens.colorPaletteGreenForeground1 },\n});\n\n/**\n * Common layout and labeling properties shared across all input components.\n */\ntype FieldLayoutProps = {\n /** The text to display as the field label. Pass `null` to completely omit the label container. */\n label?: string | null;\n /** Whether the field is mandatory (displays a red asterisk). */\n required?: boolean;\n /** Supplemental information displayed in a popover (InfoLabel). Triggers rendering of an info icon. */\n hint?: string;\n /** Error message displayed in red below the input. */\n errorMessage?: string;\n /** Informational message displayed in grey below the input (hidden if errorMessage is present). */\n infoMessage?: string;\n /** If true, the message area (error/info) and its reserved 12px space are not rendered. */\n noMessage?: boolean;\n /** Additional message or component to display on the right side of the message container. */\n additionalMessage?: React.ReactNode;\n /** Display eraser icon or not for clearing the content. Default is true */\n clearable?: boolean;\n} &\n /**\n * Layout direction:\n * - 'vertical' (default): Label above the input.\n * - 'horizontal': Label to the left of the input (stacks on mobile).\n */\n (| { direction?: 'vertical'; labelWidth?: never }\n | { direction: 'horizontal'; labelWidth?: 'small' | 'medium' | 'large' | 'none' }\n );\n\n/**\n * A Higher-Order Component that wraps an input component with consistent\n * labeling, validation messaging, and responsive layout logic.\n *\n * @param WrappedComponent The base input component to be enhanced.\n * @returns A component enhanced with standard field layout behaviors.\n */\nconst withInputField = <P extends { id?: string }>(\n WrappedComponent: React.ComponentType<P>,\n) => {\n const ComponentWithInputField = (props: P & FieldLayoutProps & { onClear?: () => void }) => {\n const {\n label = '',\n required,\n hint,\n errorMessage,\n infoMessage,\n noMessage = false,\n direction = 'vertical',\n labelWidth = 'medium',\n additionalMessage,\n clearable = true,\n onClear,\n ...wrappedProps\n } = props as any;\n\n const styles = useStyles();\n const isMobile = useIsMobile();\n const inputId = useId('input-field');\n const isHorizontal = direction === 'horizontal';\n\n const labelClasses = mergeClasses(\n isHorizontal && styles.labelHorizontal,\n isHorizontal && isMobile && styles.labelHorizontalColumn,\n isHorizontal && labelWidth === 'small' && styles.labelSmall,\n isHorizontal && labelWidth === 'medium' && styles.labelMedium,\n isHorizontal && labelWidth === 'large' && styles.labelLarge,\n isHorizontal && labelWidth === 'none' && styles.labelNone,\n );\n\n const hasLabel = label !== null;\n const labelText = label === undefined || label === '' ? '\\u00A0' : label;\n const labelTextContent = <span className={styles.labelText}>{labelText}</span>;\n\n return (\n <div\n className={\n isHorizontal && hasLabel\n ? mergeClasses(\n styles.rootHorizontal,\n isMobile ? styles.rootHorizontalColumn : styles.rootHorizontalRow,\n )\n : styles.rootVertical\n }\n >\n {hasLabel && (\n <div className={mergeClasses(styles.labelContainer, labelClasses)}>\n {hint ? (\n <InfoLabel\n className={styles.labelComponent}\n data-testid=\"info-label\"\n htmlFor={inputId}\n info={hint}\n required={required}\n >\n {labelTextContent}\n </InfoLabel>\n ) : (\n <Label\n className={styles.labelComponent}\n data-testid=\"label\"\n htmlFor={inputId}\n required={required}\n >\n {labelTextContent}\n </Label>\n )}\n {clearable !== false &&\n onClear &&\n wrappedProps.readOnly !== true &&\n wrappedProps.disabled !== true && (\n <EraserRegular\n className={styles.eraserIcon}\n data-testid=\"eraser-icon\"\n onClick={onClear}\n />\n )}\n </div>\n )}\n <div className={styles.fieldGroup}>\n <WrappedComponent {...(wrappedProps as P)} id={inputId} />\n {!noMessage && (\n <div className={styles.messageContainer}>\n <Caption1\n className={mergeClasses(\n styles.message,\n errorMessage\n ? styles.errorMessage\n : infoMessage\n ? styles.infoMessage\n : styles.messagePlaceholder,\n )}\n >\n {errorMessage ?? infoMessage ?? ' '}\n </Caption1>\n {additionalMessage && (\n <Caption1 className={styles.additionalMessage}>{additionalMessage}</Caption1>\n )}\n </div>\n )}\n </div>\n </div>\n );\n };\n\n return ComponentWithInputField;\n};\n\nexport { withInputField };\nexport type { FieldLayoutProps };\n","import {\n Dropdown,\n DropdownProps,\n Option,\n OptionGroup,\n Input,\n OverlayDrawer,\n DrawerBody,\n DrawerHeader,\n DrawerHeaderTitle,\n makeStyles,\n tokens,\n Listbox,\n Button,\n} from '@fluentui/react-components';\nimport { ChevronDownRegular, DismissRegular } from '@fluentui/react-icons';\nimport React, { useMemo, useState } from 'react';\n\nimport { useIsMobile } from '@hook/use-mobile';\n\nimport { withInputField, FieldLayoutProps } from './with-input-field';\n\nconst useStyles = makeStyles({\n drawer: {\n height: 'auto',\n maxHeight: '60vh',\n overflowY: 'auto',\n },\n drawerHeader: {\n paddingBottom: tokens.spacingVerticalM,\n },\n listboxWrapper: {\n padding: tokens.spacingVerticalM,\n },\n});\n\nexport type InputDropdownOption = {\n disabled?: boolean;\n value: string;\n text: string;\n group?: string;\n /** Custom render function for the option content */\n render?: () => React.ReactNode;\n};\n\ntype BaseInputDropdownProps = Omit<\n DropdownProps,\n 'children' | 'onChange' | 'onOptionSelect' | 'selectedOptions' | 'value'\n> & {\n /** Selected value(s). String for single select, array of strings for multi-select. */\n value: string | string[] | null;\n /** Callback fired when selection changes. */\n onChange: (value: string | string[] | null) => void;\n /** List of options to display. */\n options: InputDropdownOption[];\n /** When true, change events are silently swallowed. Defaults to false. */\n readOnly?: boolean;\n};\n\n// ─── Shared utilities ─────────────────────────────────────────────────────────\n\ntype GroupedOptions = {\n groups: Record<string, InputDropdownOption[]>;\n ungrouped: InputDropdownOption[];\n};\n\nconst computeNewSelection = (\n val: string | null,\n selectedValues: string[],\n multiselect: boolean,\n): string | string[] | null => {\n if (!multiselect) {\n return val;\n }\n if (val == null) {\n return selectedValues;\n }\n return selectedValues.includes(val)\n ? selectedValues.filter((v) => v !== val)\n : [...selectedValues, val];\n};\n\nconst renderGroupedOptions = ({ groups, ungrouped }: GroupedOptions) => {\n const renderOption = (option: InputDropdownOption) => (\n <Option key={option.value} disabled={option.disabled} text={option.text} value={option.value}>\n {option.render ? option.render() : option.text}\n </Option>\n );\n\n return (\n <>\n {ungrouped.map(renderOption)}\n {Object.entries(groups).map(([label, groupOptions]) => (\n <OptionGroup key={label} label={label}>\n {groupOptions.map(renderOption)}\n </OptionGroup>\n ))}\n </>\n );\n};\n\nconst useDropdownValues = (value: string | string[] | null, options: InputDropdownOption[]) => {\n const selectedValues = useMemo(() => {\n if (value == null) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n }, [value]);\n\n const displayValue = useMemo(\n () =>\n options\n .filter((o) => selectedValues.includes(o.value))\n .map((o) => o.text)\n .join(', '),\n [options, selectedValues],\n );\n\n const groupedOptions = useMemo<GroupedOptions>(() => {\n const groups: Record<string, InputDropdownOption[]> = {};\n const ungrouped: InputDropdownOption[] = [];\n options.forEach((option) => {\n if (option.group) {\n (groups[option.group] ??= []).push(option);\n } else {\n ungrouped.push(option);\n }\n });\n return { groups, ungrouped };\n }, [options]);\n\n return { selectedValues, displayValue, groupedOptions };\n};\n\n// ─── Components ───────────────────────────────────────────────────────────────\n\nconst MobileDropdown: React.FC<BaseInputDropdownProps & { id?: string; drawerTitle?: string }> = (props) => {\n const {\n value,\n onChange,\n options,\n placeholder,\n multiselect = false,\n className,\n style,\n disabled,\n readOnly = false,\n drawerTitle,\n id,\n } = props;\n\n const styles = useStyles();\n const [isDrawerOpen, setIsDrawerOpen] = useState(false);\n const { selectedValues, displayValue, groupedOptions } = useDropdownValues(value, options);\n\n const handleOptionSelect = (val: string | null) => {\n onChange(computeNewSelection(val, selectedValues, multiselect));\n if (!multiselect) {\n setIsDrawerOpen(false);\n }\n };\n\n return (\n <>\n <Input\n autoComplete=\"off\"\n className={className}\n contentAfter={\n <ChevronDownRegular\n key={`${id}-chevron`}\n onClick={() => setIsDrawerOpen(true)}\n style={{ cursor: 'pointer' }}\n />\n }\n disabled={disabled}\n id={id}\n onClick={() => setIsDrawerOpen(true)}\n onKeyDown={(e) => e.preventDefault()}\n placeholder={placeholder}\n readOnly={true}\n style={style}\n type=\"text\"\n value={displayValue}\n />\n <OverlayDrawer\n className={styles.drawer}\n onOpenChange={(_, { open }) => setIsDrawerOpen(open)}\n open={isDrawerOpen}\n position=\"bottom\"\n >\n <DrawerHeader className={styles.drawerHeader}>\n <DrawerHeaderTitle\n action={\n <Button\n appearance=\"subtle\"\n aria-label=\"Close\"\n icon={<DismissRegular />}\n onClick={() => setIsDrawerOpen(false)}\n />\n }\n >\n {drawerTitle}\n </DrawerHeaderTitle>\n </DrawerHeader>\n <DrawerBody>\n <div className={styles.listboxWrapper}>\n <Listbox\n multiselect={multiselect}\n onOptionSelect={\n readOnly ? undefined : (_ev, data) => handleOptionSelect(data.optionValue ?? null)\n }\n selectedOptions={selectedValues}\n >\n {renderGroupedOptions(groupedOptions)}\n </Listbox>\n </div>\n </DrawerBody>\n </OverlayDrawer>\n </>\n );\n};\n\nconst RawInputDropdown: React.FC<BaseInputDropdownProps & { id?: string; drawerTitle?: string }> = (props) => {\n const { value, onChange, options, multiselect = false, style, readOnly = false, ...rest } = props;\n const isMobile = useIsMobile();\n const { selectedValues, displayValue, groupedOptions } = useDropdownValues(value, options);\n\n if (isMobile) {\n return <MobileDropdown {...props} />;\n }\n\n const handleOptionSelect = (val: string | null) => {\n onChange(computeNewSelection(val, selectedValues, multiselect));\n };\n\n return (\n <Dropdown\n {...rest}\n aria-labelledby={rest.id}\n multiselect={multiselect}\n onOptionSelect={(_ev, data) => {\n if (!readOnly) {\n handleOptionSelect(data.optionValue ?? null);\n }\n }}\n selectedOptions={selectedValues}\n style={{ width: '100%', ...style }}\n value={displayValue}\n >\n {renderGroupedOptions(groupedOptions)}\n </Dropdown>\n );\n};\n\nconst EnhancedInputdropDown = withInputField(RawInputDropdown);\n\n/** Props for FuiInputDropdown. */\ntype InputDropdownProps = BaseInputDropdownProps & FieldLayoutProps;\n/** Dropdown with single or multi-select. Renders a bottom-sheet drawer on mobile instead of a popup. */\nconst InputDropdown: React.FC<InputDropdownProps> = (props) => {\n const { value, onChange, ...rest } = props;\n const hasValue = Array.isArray(value) ? value.length > 0 : value !== null && value !== '';\n const onClear = hasValue ? () => onChange(props.multiselect === true ? [] : null) : undefined;\n\n return <EnhancedInputdropDown {...rest} drawerTitle={props.label ?? props.placeholder} onChange={onChange} onClear={onClear} value={value} />;\n};\n\n/** @internal Mobile-only dropdown variant used by FuiInputDropdown. Also exported for use in FuiTable's pagination bar. */\nexport { MobileDropdown as FuiMobileDropdown, InputDropdown as FuiInputDropdown };\nexport type { InputDropdownProps };\n","import {\n DataGrid,\n DataGridHeader,\n DataGridRow,\n DataGridHeaderCell,\n DataGridBody,\n DataGridCell,\n createTableColumn,\n TableColumnDefinition,\n Body1Strong,\n tokens,\n makeStyles,\n Body1,\n Button,\n Dropdown,\n Option,\n Divider,\n mergeClasses,\n Tooltip,\n} from '@fluentui/react-components';\nimport {\n ChevronDoubleLeftRegular,\n ChevronDoubleRightRegular,\n ChevronLeftRegular,\n ChevronRightRegular,\n} from '@fluentui/react-icons';\nimport React, { useState } from 'react';\n\nimport { useLogger } from '@hook/use-logger';\nimport { useIsMobile } from '@hook/use-mobile';\nimport { template } from '@util/string-util';\n\nimport { FuiMobileDropdown } from './input-dropdown';\n\n// ── Styles ───────────────────────────────────────────────────────────────────\n\nconst useStyles = makeStyles({\n headerRow: {\n backgroundColor: tokens.colorNeutralBackground3,\n '& > *': { color: tokens.colorNeutralForeground1 },\n width: '100%',\n },\n row: {\n width: '100%',\n },\n headerCell: {\n backgroundColor: tokens.colorNeutralBackground3,\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n },\n ellipsis: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n },\n sortableHeader: {\n cursor: 'pointer',\n },\n cell: {\n paddingLeft: tokens.spacingHorizontalS,\n },\n outerWrapper: {\n width: '100%',\n },\n scrollContainer: {\n width: '100%',\n overflowX: 'auto',\n WebkitOverflowScrolling: 'touch', // smooth scroll on iOS\n },\n paginationBar: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-end',\n gap: tokens.spacingHorizontalS,\n padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalM}`,\n backgroundColor: tokens.colorNeutralBackground2,\n },\n paginationBarMobile: {\n flexDirection: 'column',\n alignItems: 'flex-end',\n padding: `${tokens.spacingVerticalXXS} ${tokens.spacingHorizontalXXS}`, // was XS → XXS\n gap: tokens.spacingHorizontalXS,\n },\n navRow: {\n display: 'flex',\n alignItems: 'center',\n gap: tokens.spacingHorizontalS,\n order: 1,\n },\n navRowMobile: {\n justifyContent: 'center',\n },\n sizeRow: {\n display: 'flex',\n alignItems: 'center',\n gap: tokens.spacingHorizontalS,\n order: 2,\n },\n sizeRowMobile: {\n justifyContent: 'center',\n paddingRight: tokens.spacingHorizontalM,\n },\n listbox: {\n minWidth: 0,\n width: '80px',\n },\n range: {\n fontSize: tokens.fontSizeBase200,\n color: tokens.colorNeutralForeground3,\n fontVariantNumeric: 'tabular-nums',\n minWidth: '90px',\n textAlign: 'center',\n },\n});\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\ntype SortDirection = 'asc' | 'desc';\n\ntype WidthProps = Pick<React.CSSProperties, 'width' | 'minWidth' | 'maxWidth'>;\n\ntype ColumnPropsBase = {\n /** Dot-notation path into the row object, e.g. `\"country.name\"`. */\n field: string;\n header: string;\n style?: React.CSSProperties;\n /** Styles applied specifically to the header cell. */\n headerStyle?: React.CSSProperties;\n /** When true, long header text is truncated with ellipsis. Defaults to false. */\n headerEllipsis?: boolean;\n sortable?: boolean;\n align?: 'left' | 'center' | 'right';\n};\n\n/** Column that renders a formatted string. Mutually exclusive with builder. */\ntype ColumnWithFormatter<T> = ColumnPropsBase & {\n formatter: (value: unknown, row: T) => string;\n builder?: never;\n};\n\n/** Column that renders an arbitrary ReactNode. Mutually exclusive with formatter. */\ntype ColumnWithBuilder<T> = ColumnPropsBase & {\n builder: (value: unknown, row: T) => React.ReactNode;\n formatter?: never;\n};\n\n/** Column with default plain-string rendering. */\ntype ColumnWithNeither = ColumnPropsBase & {\n formatter?: never;\n builder?: never;\n};\n\n/** Column definition union. Use formatter for text cells, builder for rich content, neither for plain string cast. */\ntype ColumnProps<T = Record<string, unknown>> =\n | ColumnWithFormatter<T>\n | ColumnWithBuilder<T>\n | ColumnWithNeither;\n\n/** Label overrides for FuiTable pagination text. All fields are optional; built-in English defaults are used for any omitted field. */\ntype FuiTableLabel = {\n /** Label before the page-size dropdown. Default: 'Rows :' */\n pageSize?: string;\n /** Text shown when there are no rows. Default: 'No data' */\n noData?: string;\n /** Template for the page-range display. Tokens: {{from}} {{to}} {{total}}. Default: '{{from}} to {{to}} of {{total}}' */\n pageRange?: string;\n paginationBar?: {\n next?: string;\n /** Template for fast-forward button. Token: {{n}}. */\n nextN?: string;\n previous?: string;\n /** Template for fast-backward button. Token: {{n}}. */\n previousN?: string;\n };\n};\n\n/** Pagination state. offset is zero-based. */\ntype PaginationProps = {\n offset: number;\n pageSize: number;\n /** Pages to jump when the fast-forward (<</>>) buttons are clicked. Defaults to 5. */\n fastForwardPage?: number;\n totalRecord: number;\n pageSizeOption: number[];\n /** Position of the pagination bar. Defaults to 'bottom'. */\n position?: 'top' | 'bottom';\n};\n\n// ── Column ───────────────────────────────────────────────────────────────────\n// Pure config carrier — renders nothing itself.\n\n// Symbol.for uses the global registry so the same symbol survives HMR module re-evaluation,\n// avoiding the stale-reference problem with child.type === Column identity checks.\nconst COLUMN_MARKER = Symbol.for('FuiColumn');\n\n/** Config-carrier component that declares a table column. Must be a direct child of FuiTable. Renders nothing. */\nconst Column: React.FC<ColumnProps> = Object.assign(() => null, { _marker: COLUMN_MARKER });\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\nconst getField = (obj: Record<string, unknown>, path: string): unknown => {\n return path.split('.').reduce<unknown>((acc, key) => {\n if (acc !== null && typeof acc === 'object') {\n return (acc as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n};\n\nconst getColumnDefs = <T,>(children: React.ReactNode): ColumnProps<T>[] => {\n return React.Children.toArray(children)\n .filter(\n (child): child is React.ReactElement<ColumnProps<T>> =>\n React.isValidElement(child) && (child.type as any)?._marker === COLUMN_MARKER,\n )\n .map((child) => child.props as ColumnProps<T>);\n};\n\nconst renderCell = <T,>(col: ColumnProps<T>, row: T): React.ReactNode => {\n const value = getField(row as Record<string, unknown>, col.field);\n\n if (col.builder) {\n return col.builder(value, row);\n }\n if (col.formatter) {\n return <Body1>{col.formatter(value, row)}</Body1>;\n }\n return <Body1>{value != null ? String(value) : ''}</Body1>;\n};\n\n// ── Pagination ───────────────────────────────────────────────────────────────\ntype PaginationBarProps = PaginationProps & {\n visibleCount: number;\n onPageChange: (offset: number, pageSize: number) => void;\n langLabel?: FuiTableLabel;\n};\n\nconst PaginationBar = ({\n offset,\n pageSize,\n fastForwardPage = 5,\n pageSizeOption,\n totalRecord,\n visibleCount,\n onPageChange,\n langLabel: fuiTableLabel,\n}: PaginationBarProps) => {\n const styles = useStyles();\n\n const paginationBarLabel = fuiTableLabel?.paginationBar;\n\n const from = totalRecord === 0 ? 0 : offset + 1;\n const to = totalRecord === 0 ? 0 : offset + visibleCount;\n const hasPrev = offset > 0;\n const hasNext = offset + pageSize < totalRecord;\n const isMobile = useIsMobile();\n const selectedOption = String(pageSize);\n\n const pageRange =\n totalRecord === 0\n ? fuiTableLabel?.noData || 'No data'\n : fuiTableLabel?.pageRange\n ? template(fuiTableLabel.pageRange, { from, to, total: totalRecord })\n : `${from} to ${to} of ${totalRecord}`;\n const pageSizeLabel = fuiTableLabel?.pageSize ?? 'Rows :';\n\n const nextLabel = paginationBarLabel?.next ?? 'Next page';\n const nextNLabel = paginationBarLabel?.nextN\n ? template(paginationBarLabel.nextN, { n: fastForwardPage })\n : `Next ${fastForwardPage} pages`;\n const prevLabel = paginationBarLabel?.previous ?? 'Previous page';\n const prevNLabel = paginationBarLabel?.previousN\n ? template(paginationBarLabel.previousN, { n: fastForwardPage })\n : `Previous ${fastForwardPage} pages`;\n\n return (\n <div className={mergeClasses(styles.paginationBar, isMobile && styles.paginationBarMobile)}>\n {/* Row 1 — navigation */}\n <div className={mergeClasses(styles.navRow, isMobile && styles.navRowMobile)}>\n <Tooltip content={prevNLabel} relationship=\"label\">\n <Button\n appearance=\"subtle\"\n aria-label={prevNLabel}\n disabled={!hasPrev}\n icon={<ChevronDoubleLeftRegular />}\n onClick={() => onPageChange(Math.max(0, offset - fastForwardPage * pageSize), pageSize)}\n />\n </Tooltip>\n <Tooltip content={prevLabel} relationship=\"label\">\n <Button\n appearance=\"subtle\"\n aria-label={prevLabel}\n disabled={!hasPrev}\n icon={<ChevronLeftRegular />}\n onClick={() => onPageChange(Math.max(0, offset - pageSize), pageSize)}\n />\n </Tooltip>\n <span className={styles.range}>\n <Body1>{pageRange}</Body1>\n </span>\n <Tooltip content={nextLabel} relationship=\"label\">\n <Button\n appearance=\"subtle\"\n aria-label={nextLabel}\n disabled={!hasNext}\n icon={<ChevronRightRegular />}\n onClick={() => onPageChange(offset + pageSize, pageSize)}\n />\n </Tooltip>\n <Tooltip content={nextNLabel} relationship=\"label\">\n <Button\n appearance=\"subtle\"\n aria-label={nextNLabel}\n disabled={!hasNext}\n icon={<ChevronDoubleRightRegular />}\n onClick={() => onPageChange(offset + fastForwardPage * pageSize, pageSize)}\n />\n </Tooltip>{' '}\n {!isMobile && <Divider vertical />}\n </div>\n {/* divider between nav and page size on mobile */}\n {/* Row 2 — page size */}\n <div className={mergeClasses(styles.sizeRow, isMobile && styles.sizeRowMobile)}>\n <Body1>{pageSizeLabel}</Body1>\n {isMobile ? (\n <FuiMobileDropdown\n className={styles.listbox}\n onChange={(val) => {\n if (val && !Array.isArray(val)) {\n onPageChange(offset, Number(val));\n }\n }}\n options={pageSizeOption\n .map((ps) => String(ps))\n .map((psStr) => {\n return { value: psStr, text: psStr };\n })}\n value={selectedOption}\n />\n ) : (\n <Dropdown\n className={styles.listbox}\n listbox={{ className: styles.listbox }}\n onOptionSelect={(_ev, data) => {\n if (data.optionValue) {\n onPageChange(offset, Number(data.optionValue));\n }\n }}\n selectedOptions={[selectedOption]}\n value={selectedOption}\n >\n {pageSizeOption\n .map((ps) => String(ps))\n .map((psStr) => {\n return (\n <Option key={psStr} text={psStr} value={psStr}>\n {psStr}\n </Option>\n );\n })}\n </Dropdown>\n )}\n </div>\n </div>\n );\n};\n\n// ── Table ────────────────────────────────────────────────────────────────────\n\n/** Props for FuiTable. Columns are declared as FuiColumn JSX children. */\ntype TableProps<T extends Record<string, unknown>> = {\n data: T[];\n pagination?: PaginationProps;\n /** Called when the user changes page or clicks a sortable column header. Without this, sort state is local-only and a warning is logged. */\n onPageOrSort?: (\n page?: { offset: number; pageSize: number },\n sort?: { field: string; direction: SortDirection },\n ) => void;\n /**\n * Minimum width of the scrollable table area. The table always expands to fill the parent\n * container; a horizontal scrollbar appears when the parent is narrower than this value.\n * Both `width` and `minWidth` are treated as the minimum — the table always fills available space.\n */\n width?: WidthProps;\n /** Label overrides for pagination text. */\n langLabel?: FuiTableLabel;\n children: React.ReactNode;\n};\n\n/** Data table driven by FuiColumn children. Supports sorting and pagination. */\nconst Table = <T extends Record<string, unknown>>({\n data,\n onPageOrSort,\n pagination,\n width,\n langLabel,\n children,\n}: TableProps<T>) => {\n const [sortField, setSortField] = useState<string | null>(null);\n const [sortDir, setSortDir] = useState<SortDirection>('asc');\n\n const styles = useStyles();\n const logger = useLogger();\n const columns = getColumnDefs(children);\n\n const getCellStyle = (col: ColumnProps<T>): React.CSSProperties => {\n const w = col.style?.width;\n if (w != null) {\n return {\n ...col.style,\n boxSizing: 'border-box',\n flex: `0 0 ${w}`,\n minWidth: 0,\n overflow: 'hidden',\n };\n }\n return col.style ?? {};\n };\n\n const gridColumns: TableColumnDefinition<T>[] = columns.map((col, idx) =>\n createTableColumn<T>({\n columnId: `${col.field}_${idx}`,\n renderHeaderCell: () => col.header,\n renderCell: (row) => renderCell(col, row),\n }),\n );\n\n const handleHeaderClick = (field: string) => {\n if (!onPageOrSort) {\n logger.warn('Sorting is not performed because onSort handler is not provided');\n }\n if (sortField === field) {\n // same column — toggle direction\n const next: SortDirection = sortDir === 'asc' ? 'desc' : 'asc';\n setSortDir(next);\n onPageOrSort?.(pagination, { field, direction: next });\n } else {\n // new column — always start asc\n setSortField(field);\n setSortDir('asc');\n onPageOrSort?.(pagination, { field, direction: 'asc' });\n }\n };\n\n const paginationBar = pagination && (\n <PaginationBar\n onPageChange={(offset, pageSize) => {\n onPageOrSort?.(\n { offset, pageSize },\n sortField ? { field: sortField, direction: sortDir } : undefined,\n );\n }}\n {...pagination}\n langLabel={langLabel}\n visibleCount={data.length}\n />\n );\n\n const sortColumnId = sortField\n ? gridColumns.find((gc) => String(gc.columnId).startsWith(`${sortField}_`))?.columnId\n : undefined;\n\n const fillerRowsCount = pagination ? Math.max(0, pagination.pageSize - data.length) : 0;\n const allItems = [\n ...data,\n ...Array.from({ length: fillerRowsCount }).map(\n (_, i) => ({ _isFiller: true, id: `filler-${i}` }) as any as T,\n ),\n ];\n\n return (\n <div className={styles.outerWrapper}>\n {pagination?.position === 'top' && paginationBar}\n <div className={styles.scrollContainer}>\n <DataGrid\n columns={gridColumns}\n items={allItems}\n sortState={{\n sortColumn: sortColumnId,\n sortDirection: sortDir === 'asc' ? 'ascending' : 'descending',\n }}\n style={{ minWidth: width?.minWidth ?? width?.width, whiteSpace: 'nowrap', width: '100%' }}\n >\n <DataGridHeader>\n <DataGridRow className={styles.headerRow}>\n {({ renderHeaderCell, columnId }) => {\n const colIdx = parseInt(String(columnId).split('_').pop() || '0');\n const col = columns[colIdx];\n return (\n <DataGridHeaderCell\n key={columnId}\n className={mergeClasses(\n styles.headerCell,\n col.sortable && styles.sortableHeader,\n )}\n onClick={col.sortable ? () => handleHeaderClick(col.field) : undefined}\n sortDirection={\n col.sortable && sortField === col.field\n ? sortDir === 'asc'\n ? 'ascending'\n : 'descending'\n : undefined\n }\n style={{ ...getCellStyle(col), ...col.headerStyle, textAlign: col.align }}\n >\n <Body1Strong className={styles.ellipsis}>{renderHeaderCell()}</Body1Strong>\n </DataGridHeaderCell>\n );\n }}\n </DataGridRow>\n </DataGridHeader>\n\n <DataGridBody<T>>\n {({ item, rowId }) => (\n <DataGridRow<T> key={rowId} className={styles.row}>\n {({ renderCell, columnId }) => {\n const colIdx = parseInt(String(columnId).split('_').pop() || '0');\n const col = columns[colIdx];\n return (\n <DataGridCell\n key={columnId}\n className={styles.cell}\n style={{ ...getCellStyle(col), textAlign: col.align }}\n >\n {(item as any)._isFiller ? null : renderCell(item)}\n </DataGridCell>\n );\n }}\n </DataGridRow>\n )}\n </DataGridBody>\n </DataGrid>\n </div>\n {(pagination?.position === 'bottom' || !pagination?.position) && paginationBar}\n </div>\n );\n};\n\nexport { Table as FuiTable, Column as FuiColumn };\nexport type { TableProps, ColumnProps, PaginationProps, FuiTableLabel };\n","import {\n Carousel,\n CarouselNav,\n CarouselNavButton,\n CarouselNavContainer,\n CarouselViewport,\n CarouselSlider,\n CarouselCard,\n CarouselAnnouncerFunction,\n Image,\n} from '@fluentui/react-components';\nimport * as React from 'react';\n\n/** Props for FuiImageCarousel. */\ntype ImageCarouselProps = {\n /** URLs of images to display as carousel slides. */\n images: string[];\n /** Tooltip label overrides for the carousel navigation buttons. */\n langLabel?: {\n autoplay?: string;\n next?: string;\n previous?: string;\n };\n};\n\nconst getAnnouncement: CarouselAnnouncerFunction = (index: number, totalSlides: number) =>\n `Carousel slide ${index + 1} of ${totalSlides}`;\n\n/** Circular image carousel with navigation and autoplay controls. */\nconst ImageCarousel: React.FC<ImageCarouselProps> = ({ images, langLabel: imageCarousellLabel }) => {\n\n return (\n <div style={{ width: '100%' }}>\n <Carousel announcement={getAnnouncement} circular groupSize={1}>\n <CarouselViewport style={{ width: '100%', overflow: 'hidden' }}>\n <CarouselSlider\n style={{\n display: 'flex',\n flexWrap: 'nowrap',\n width: '100%',\n }}\n >\n {images.map((imageSrc, index) => (\n <CarouselCard\n key={`image-${index}`}\n aria-label={`${index + 1} of ${images.length}`}\n id={`carousel-image-${index}`}\n style={{\n aspectRatio: '5/2',\n flexShrink: 0,\n overflow: 'hidden',\n width: '100%',\n }}\n >\n <Image\n fit=\"cover\"\n role=\"presentation\"\n src={imageSrc}\n style={{\n display: 'block',\n height: '100%',\n objectFit: 'cover',\n width: '100%',\n }}\n />\n </CarouselCard>\n ))}\n </CarouselSlider>\n </CarouselViewport>\n\n <CarouselNavContainer\n autoplayTooltip={{\n content: imageCarousellLabel?.autoplay ?? 'Autoplay',\n relationship: 'label',\n }}\n layout=\"inline\"\n nextTooltip={{ content: imageCarousellLabel?.next ?? 'Next image', relationship: 'label' }}\n prevTooltip={{\n content: imageCarousellLabel?.previous ?? 'Previous image',\n relationship: 'label',\n }}\n >\n <CarouselNav>\n {(index) => <CarouselNavButton aria-label={`Carousel Nav Button ${index}`} />}\n </CarouselNav>\n </CarouselNavContainer>\n </Carousel>\n </div>\n );\n};\n\nexport type { ImageCarouselProps };\nexport { ImageCarousel as FuiImageCarousel };\n","import { Checkbox, CheckboxProps, CheckboxOnChangeData } from '@fluentui/react-components';\nimport React from 'react';\n\n/** Props for FuiInputCheckbox. */\ntype InputCheckboxProps = Omit<CheckboxProps, 'onChange'> & {\n /** When true, change events are silently swallowed. Defaults to false. */\n readOnly?: boolean;\n onChange?: (data: CheckboxOnChangeData) => void;\n /** Custom CSS class for the checkbox root. */\n className?: string;\n /** Custom CSS styles for the checkbox root. */\n style?: React.CSSProperties;\n};\n\n/** Checkbox with optional read-only mode that visually appears interactive but ignores changes. */\nconst InputCheckbox: React.FC<InputCheckboxProps> = (props) => {\n const { readOnly = false, onChange, className, style, ...rest } = props;\n\n const handleChange: CheckboxProps['onChange'] = (_ev, data) => {\n if (!readOnly) {\n onChange?.(data);\n }\n };\n\n return <Checkbox {...rest} className={className} onChange={handleChange} style={style} />;\n};\n\nexport { InputCheckbox as FuiInputCheckbox };\nexport type { InputCheckboxProps };\n","import { Calendar } from '@fluentui/react-calendar-compat';\nimport {\n Input,\n OverlayDrawer,\n DrawerBody,\n DrawerHeader,\n DrawerHeaderTitle,\n makeStyles,\n tokens,\n} from '@fluentui/react-components';\nimport { DatePicker, DatePickerProps } from '@fluentui/react-datepicker-compat';\nimport { CalendarRegular } from '@fluentui/react-icons';\nimport React, { useState } from 'react';\n\nimport { useIsMobile } from '@hook/use-mobile';\n\nimport { withInputField, FieldLayoutProps } from './with-input-field';\n\nconst useStyles = makeStyles({\n drawer: {\n height: 'auto',\n maxHeight: '80vh',\n },\n drawerHeader: {\n paddingBottom: tokens.spacingVerticalM,\n },\n calendarWrapper: {\n display: 'flex',\n justifyContent: 'center',\n padding: tokens.spacingVerticalM,\n },\n});\n\ntype BaseInputDateProps = Omit<\n DatePickerProps,\n 'id' | 'value' | 'onSelectDate' | 'onChange' | 'formatDate'\n> & {\n value: Date | null;\n onChange: (date: Date | null | undefined) => void;\n /** Custom date formatter. Defaults to Date.toLocaleDateString(). */\n formatter?: (date: Date | null) => string;\n /** Custom CSS class for the date picker root. */\n className?: string;\n /** Custom CSS styles for the date picker root. */\n style?: React.CSSProperties;\n /** When true, the calendar popup/drawer is suppressed. */\n readOnly?: boolean;\n};\n\nconst defaultFormatter = (date: Date | null) => (date ? date.toLocaleDateString() : '');\n\nconst RawInputDate: React.FC<\n BaseInputDateProps & {\n id?: string;\n drawerTitle?: string;\n }\n> = (props) => {\n const { value, onChange, formatter = defaultFormatter, className, style, readOnly, ...rest } = props;\n const isMobile = useIsMobile();\n\n if (isMobile) {\n return <MobileDate {...props} />;\n }\n\n if (readOnly) {\n return (\n <Input\n className={className}\n id={rest.id}\n placeholder={rest.placeholder}\n readOnly\n style={{ width: '100%', ...style }}\n type=\"text\"\n value={formatter(value)}\n />\n );\n }\n\n return (\n <DatePicker\n {...rest}\n key={`${rest.id}-${value ? 'defined' : 'undefined'}`}\n className={className}\n formatDate={(date) => formatter(date ?? null)}\n onSelectDate={onChange}\n style={{ width: '100%', ...style }}\n value={value ?? undefined}\n />\n );\n};\n\nconst MobileDate: React.FC<\n BaseInputDateProps & {\n id?: string;\n drawerTitle?: string;\n }\n> = (props) => {\n const {\n value,\n onChange,\n formatter = defaultFormatter,\n className,\n style,\n drawerTitle,\n readOnly,\n ...rest\n } = props;\n const styles = useStyles();\n const [isDrawerOpen, setIsDrawerOpen] = useState(false);\n\n const handleInputClick = () => {\n if (!readOnly) {\n setIsDrawerOpen(true);\n }\n };\n\n const handleDateSelect = (date: Date | null | undefined) => {\n onChange(date);\n setIsDrawerOpen(false);\n };\n\n const contentAfter = readOnly ? undefined : (\n <CalendarRegular\n key={`${rest.id}-calendar`}\n onClick={handleInputClick}\n style={{ cursor: 'pointer' }}\n />\n );\n\n const formattedDate = formatter(value);\n\n return (\n <>\n <Input\n {...rest}\n autoComplete=\"off\"\n className={className}\n contentAfter={contentAfter}\n onClick={handleInputClick}\n onKeyDown={(e) => e.preventDefault()}\n readOnly\n style={style}\n type=\"text\"\n value={formattedDate}\n />\n <OverlayDrawer\n className={styles.drawer}\n onOpenChange={(_, { open }) => setIsDrawerOpen(open)}\n open={isDrawerOpen}\n position=\"bottom\"\n >\n {drawerTitle && (\n <DrawerHeader className={styles.drawerHeader}>\n <DrawerHeaderTitle>{drawerTitle}</DrawerHeaderTitle>\n </DrawerHeader>\n )}\n <DrawerBody>\n <div className={styles.calendarWrapper}>\n <Calendar\n key={`${rest.id}-${value ? 'defined' : 'undefined'}`}\n onSelectDate={handleDateSelect}\n value={value ?? undefined}\n />\n </div>\n </DrawerBody>\n </OverlayDrawer>\n </>\n );\n};\n\nconst EnhancedInputDate = withInputField(RawInputDate);\n\n/** Props for FuiInputDate. */\ntype InputDateProps = BaseInputDateProps & FieldLayoutProps;\n/** Date picker. On desktop renders FluentUI DatePicker; on mobile renders a bottom-sheet calendar drawer. */\nconst InputDate: React.FC<InputDateProps> = (props) => {\n const { value, onChange, ...rest } = props;\n const onClear =\n value !== null && !props.readOnly && !props.disabled ? () => onChange(null) : undefined;\n\n return (\n <EnhancedInputDate\n {...rest}\n drawerTitle={props.label ?? props.placeholder}\n onChange={onChange}\n onClear={onClear}\n value={value}\n />\n );\n};\n\n/** @internal Mobile date picker variant used by FuiInputDate on narrow viewports. */\nexport { MobileDate as FuiMobileDate, InputDate as FuiInputDate };\nexport type { InputDateProps };\n","import { Input, InputProps, makeStyles, mergeClasses, tokens } from '@fluentui/react-components';\nimport { ChevronDownRegular, ChevronUpRegular } from '@fluentui/react-icons';\nimport React, { useEffect, useRef, useState } from 'react';\n\nimport { useIsMobile } from '@hook/use-mobile';\n\nimport { withInputField, FieldLayoutProps } from './with-input-field';\n\nconst useStyles = makeStyles({\n arrows: {\n display: 'flex',\n flexDirection: 'column',\n },\n arrowsRow: {\n flexDirection: 'row',\n },\n arrowIcon: {\n cursor: 'pointer',\n },\n arrowIconMobile: {\n fontSize: tokens.fontSizeBase500,\n height: tokens.fontSizeBase500,\n width: tokens.fontSizeBase500,\n },\n arrowIconDisabled: {\n cursor: 'default',\n opacity: 0.4,\n },\n amPm: {\n cursor: 'pointer',\n fontWeight: tokens.fontWeightSemibold,\n paddingRight: tokens.spacingHorizontalXS,\n userSelect: 'none',\n },\n amPmDisabled: {\n cursor: 'default',\n opacity: 0.4,\n },\n});\n\ntype Time = {\n hour: number;\n minute: number;\n second: number;\n};\n\ntype BaseInputTimeProps = Omit<\n InputProps,\n 'contentAfter' | 'contentBefore' | 'defaultValue' | 'id' | 'input' | 'onChange' | 'type' | 'value'\n> & {\n value: Time | null;\n onChange: (time: Time | null) => void;\n /** When true, show the time in 24-hour format, otherwise show AM/PM toggle. Default is true. */\n in24HourFormat?: boolean;\n /** When true, allow user to select a value for seconds. Default is false. */\n withSeconds?: boolean;\n /** When true, incrementing past a segment boundary (e.g. 59m → 0m) also advances the next segment. */\n cascadeCarry?: boolean;\n /** When true, arrows and AM/PM toggle are suppressed. */\n readOnly?: boolean;\n /** Custom CSS class for the input root. */\n className?: string;\n /** Custom CSS styles for the input root. */\n style?: React.CSSProperties;\n};\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\ntype Segment = 'h' | 'm' | 's';\n\nconst NULL_TIME: Time = { hour: 0, minute: 0, second: 0 };\n\nconst formatTime = (value: Time | null, withSeconds: boolean, in24HourFormat: boolean): string => {\n if (value === null) {\n return '';\n }\n const displayH = in24HourFormat ? value.hour : (value.hour % 12 || 12);\n const hStr = String(displayH).padStart(2, '0');\n const mStr = String(value.minute).padStart(2, '0');\n const sStr = String(value.second).padStart(2, '0');\n return withSeconds ? `${hStr}:${mStr}:${sStr}` : `${hStr}:${mStr}`;\n};\n\nconst getSegment = (pos: number | null | undefined, withSeconds: boolean): Segment => {\n if (pos == null) { return withSeconds ? 's' : 'm'; }\n if (pos < 3) { return 'h'; }\n if (pos < 6) { return 'm'; }\n return 's';\n};\n\nconst adjustTime = (value: Time | null, segment: Segment, delta: 1 | -1, advanceNext: boolean): Time => {\n const base = value ?? NULL_TIME;\n\n if (segment === 's') {\n const next = base.second + delta;\n if (advanceNext && next < 0) {\n return adjustTime({ ...base, second: 59 }, 'm', -1, advanceNext);\n }\n if (advanceNext && next >= 60) {\n return adjustTime({ ...base, second: 0 }, 'm', 1, advanceNext);\n }\n return { ...base, second: (next + 60) % 60 };\n }\n\n if (segment === 'm') {\n const next = base.minute + delta;\n if (advanceNext && next < 0) {\n return adjustTime({ ...base, minute: 59 }, 'h', -1, advanceNext);\n }\n if (advanceNext && next >= 60) {\n return adjustTime({ ...base, minute: 0 }, 'h', 1, advanceNext);\n }\n return { ...base, minute: (next + 60) % 60 };\n }\n\n return { ...base, hour: (base.hour + delta + 24) % 24 };\n};\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\nconst RawInputTime: React.FC<BaseInputTimeProps & { id?: string }> = (props) => {\n const {\n value,\n onChange,\n in24HourFormat = true,\n withSeconds = false,\n cascadeCarry = false,\n readOnly = false,\n disabled,\n className,\n style,\n id,\n ...rest\n } = props;\n\n const styles = useStyles();\n const isMobile = useIsMobile();\n const inputRef = useRef<HTMLInputElement>(null);\n const [activeSegment, setActiveSegment] = useState<Segment | null>(null);\n const pendingCursorPos = useRef<number | null>(null);\n\n const interactive = !readOnly && !disabled;\n const isPm = value !== null && value.hour >= 12;\n\n useEffect(() => {\n if (pendingCursorPos.current !== null && inputRef.current) {\n inputRef.current.setSelectionRange(pendingCursorPos.current, pendingCursorPos.current);\n pendingCursorPos.current = null;\n }\n });\n\n const handleClick = () => {\n setActiveSegment(getSegment(inputRef.current?.selectionStart, withSeconds));\n };\n\n const handleFocus = () => {\n setActiveSegment(getSegment(inputRef.current?.selectionStart, withSeconds));\n };\n\n const handleBlur = () => setActiveSegment(null);\n\n const handleArrow = (delta: 1 | -1) => {\n if (!interactive) { return; }\n const segment = activeSegment ?? (withSeconds ? 's' : 'm');\n pendingCursorPos.current = inputRef.current?.selectionStart ?? null;\n onChange(adjustTime(value, segment, delta, cascadeCarry));\n };\n\n const handleAmPmToggle = () => {\n if (!interactive) { return; }\n const base = value ?? NULL_TIME;\n onChange({ ...base, hour: base.hour >= 12 ? base.hour - 12 : base.hour + 12 });\n };\n\n const iconClass = mergeClasses(\n styles.arrowIcon,\n isMobile && styles.arrowIconMobile,\n !interactive && styles.arrowIconDisabled,\n );\n\n const arrows = (\n <div className={mergeClasses(styles.arrows, isMobile && styles.arrowsRow)}>\n <ChevronUpRegular\n className={iconClass}\n onClick={() => handleArrow(1)}\n onMouseDown={(e) => e.preventDefault()}\n />\n <ChevronDownRegular\n className={iconClass}\n onClick={() => handleArrow(-1)}\n onMouseDown={(e) => e.preventDefault()}\n />\n </div>\n );\n\n const amPmToggle = !in24HourFormat && value !== null ? (\n <span\n className={interactive ? styles.amPm : mergeClasses(styles.amPm, styles.amPmDisabled)}\n onClick={interactive ? handleAmPmToggle : undefined}\n onMouseDown={interactive ? (e) => e.preventDefault() : undefined}\n >\n {isPm ? 'PM' : 'AM'}\n </span>\n ) : undefined;\n\n return (\n <Input\n {...rest}\n autoComplete=\"off\"\n className={className}\n contentAfter={arrows}\n contentBefore={amPmToggle}\n disabled={disabled}\n id={id}\n input={{ ref: inputRef, style: { minWidth: withSeconds ? '8ch' : '5ch' } }}\n onBlur={handleBlur}\n onClick={handleClick}\n onFocus={handleFocus}\n onKeyDown={(e) => { if (e.key !== 'Tab') { e.preventDefault(); } }}\n readOnly={readOnly}\n style={{ width: '100%', ...style }}\n type=\"text\"\n value={formatTime(value, withSeconds, in24HourFormat)}\n />\n );\n};\n\nconst EnhancedInputTime = withInputField(RawInputTime);\n\n/** Props for FuiInputTime. */\ntype InputTimeProps = BaseInputTimeProps & FieldLayoutProps;\n\n/** Time picker with up/down arrows. Shows AM/PM toggle when in24HourFormat is false. */\nconst InputTime: React.FC<InputTimeProps> = (props) => {\n const { value, onChange, ...rest } = props;\n const onClear =\n value !== null && !props.readOnly && !props.disabled ? () => onChange(null) : undefined;\n return <EnhancedInputTime {...rest} onChange={onChange} onClear={onClear} value={value} />;\n};\n\nexport { InputTime as FuiInputTime };\nexport type { InputTimeProps, Time as FuiTime };\n","import { makeStyles, tokens } from '@fluentui/react-components';\nimport React from 'react';\n\nimport { useIsMobile } from '@hook/use-mobile';\n\nimport { FieldLayoutProps, withInputField } from './with-input-field';\n\nconst useStyles = makeStyles({\n groupRow: {\n display: 'flex',\n flexDirection: 'row',\n gap: tokens.spacingHorizontalM,\n width: '100%',\n },\n groupColumn: {\n display: 'flex',\n flexDirection: 'column',\n gap: tokens.spacingVerticalXXS,\n width: '100%',\n },\n});\n\ntype GroupableInputProps<V extends string | number | Date> = FieldLayoutProps & {\n value?: V | null;\n onChange: (value: V | null) => void;\n};\n\ntype InputGroupItem<T extends GroupableInputProps<string | number | Date>> = {\n element: React.ReactElement<T>;\n /** Flex-grow factor relative to siblings. Defaults to 1. */\n weight?: number;\n};\n\ntype InputGroupProps<T extends GroupableInputProps<string | number | Date>> = Omit<\n FieldLayoutProps,\n 'label'\n> & {\n label: string;\n items: InputGroupItem<T>[];\n /** Custom CSS class for the group container. */\n className?: string;\n /** Custom CSS styles for the group container. */\n style?: React.CSSProperties;\n};\n\ntype RawInputGroupProps = {\n items: Array<{ element: React.ReactElement<any>; weight?: number }>;\n id?: string;\n className?: string;\n style?: React.CSSProperties;\n};\n\nconst RawInputGroup: React.FC<RawInputGroupProps> = ({ items, className, style }) => {\n const isMobile = useIsMobile();\n const styles = useStyles();\n\n return (\n <div className={`${isMobile ? styles.groupColumn : styles.groupRow} ${className ?? ''}`} style={style}>\n {items.map(({ element, weight = 1 }, index) => {\n const { label, placeholder } = element.props;\n const finalPlaceHolder = placeholder ?? label;\n return (\n <div\n key={index}\n style={isMobile ? { flex: '1 1 auto' } : { flex: `${weight} 1 0px`, minWidth: 0 }}\n >\n {React.cloneElement(element as React.ReactElement<any>, {\n label: null,\n placeholder: finalPlaceHolder,\n noMessage: false,\n })}\n </div>\n );\n })}\n </div>\n );\n\n};\n\nconst EnhancedInputGroup = withInputField(RawInputGroup);\n\n/** Groups multiple inputs under one shared label with weighted distribution. Items stack vertically on mobile regardless of weight. Each item's own label is hidden; the group label takes over. */\nconst InputGroup = <T extends GroupableInputProps<string | number | Date>>(\n props: InputGroupProps<T>,\n): React.ReactElement => {\n const isMobile = useIsMobile();\n const { items, className, style } = props;\n\n const hasValue = items.some(({ element }) => {\n const val = element.props.value;\n return val != null && val !== '';\n });\n\n const onClear = hasValue\n ? () => items.forEach(({ element }) => element.props.onChange(null))\n : undefined;\n\n return (\n <EnhancedInputGroup\n {...(props as any)}\n className={className}\n direction={isMobile ? 'vertical' : props.direction}\n noMessage={true}\n onClear={onClear}\n style={style}\n />\n );\n};\n\nexport { InputGroup as FuiInputGroup };\n/** Props for FuiInputGroup. */\nexport type { InputGroupProps };\n","import { Button, Input, InputProps } from '@fluentui/react-components';\nimport { EyeRegular, EyeOffRegular } from '@fluentui/react-icons';\nimport React, { useState } from 'react';\n\nimport { withInputField, FieldLayoutProps } from './with-input-field';\n\ntype BaseInputTextProps = Omit<\n InputProps,\n 'defaultValue' | 'type' | 'id' | 'value' | 'onChange'\n> & {\n value: string | null;\n onChange: (value: string | null) => void;\n type?: 'text' | 'email' | 'password';\n /** Custom CSS class for the input root. */\n className?: string;\n /** Custom CSS styles for the input root. */\n style?: React.CSSProperties;\n};\n\nconst RawInputText: React.FC<\n BaseInputTextProps & {\n id?: string;\n }\n> = (props) => {\n const {\n type = 'text',\n onChange,\n onKeyDown,\n className,\n style,\n ...rest\n } = props;\n const [showPassword, setShowPassword] = useState(false);\n\n // If type is email, block typing '@' if already present\n const handleKeyDown =\n type === 'email'\n ? (ev: React.KeyboardEvent<HTMLInputElement>) => {\n if (ev.key === '@' && props.value?.includes('@')) {\n ev.preventDefault();\n }\n onKeyDown?.(ev);\n }\n : onKeyDown;\n\n const handleChange = (value: string | null | undefined) => {\n onChange(value ?? null);\n };\n\n const togglePasswordVisibility = () => {\n setShowPassword(!showPassword);\n };\n\n const inputType = type === 'password' && showPassword ? 'text' : type;\n\n return (\n <Input\n {...rest}\n className={className}\n contentAfter={\n type === 'password' ? (\n <Button\n appearance=\"subtle\"\n icon={showPassword ? <EyeOffRegular /> : <EyeRegular />}\n onClick={togglePasswordVisibility}\n size=\"small\"\n type=\"button\"\n />\n ) : rest.contentAfter\n }\n onChange={(_ev, data) => handleChange(data.value)}\n onKeyDown={handleKeyDown}\n style={style}\n type={inputType}\n value={props.value ?? ''}\n />\n );\n};\n\nconst EnhancedInputText = withInputField(RawInputText);\n\n/** Props for FuiInputText. */\ntype InputTextProps = BaseInputTextProps & FieldLayoutProps;\n/** Text input. password type adds a show/hide toggle; email type blocks a second '@' character. */\nconst InputText: React.FC<InputTextProps> = (props) => {\n const { value, onChange, ...rest } = props;\n const onClear = value !== null && value !== '' ? () => onChange(null) : undefined;\n\n return <EnhancedInputText {...rest} onChange={onChange} onClear={onClear} value={value} />;\n};\n\nexport { InputText as FuiInputText };\nexport type { InputTextProps };\n","import {\n Button,\n InputProps,\n OverlayDrawer,\n DrawerBody,\n DrawerHeader,\n DrawerHeaderTitle,\n makeStyles,\n tokens,\n mergeClasses,\n} from '@fluentui/react-components';\nimport { DismissRegular, TranslateRegular } from '@fluentui/react-icons';\nimport React, { useState } from 'react';\n\nimport { useIsMobile } from '@hook/use-mobile';\n\nimport { FuiInputText, InputTextProps } from './input-text';\nimport { withInputField, FieldLayoutProps } from './with-input-field';\n\n/** Holds text in up to three languages, mapped positionally to the slots in SupportedLanguage. Null means the slot is unpopulated. */\ntype MultiLangText = {\n /** Value for the first configured language. */\n valueInLangOne: string | null;\n /** Value for the second configured language. */\n valueInLangTwo: string | null;\n /** Value for the third configured language. */\n valueInLangThree: string | null;\n};\n\ntype BaseInputMultiLangTextProps = Omit<\n InputProps,\n 'defaultValue' | 'type' | 'id' | 'value' | 'onChange' | 'label'\n> & {\n value: MultiLangText | null;\n onChange: (value: MultiLangText | null) => void;\n label: string; // Must provide a label\n /** Language slot names shown in the drawer (up to 3). When fewer than 2 are provided the translate icon is hidden. */\n langLabel?: { languages: string[] };\n /** Custom CSS class for the input root. */\n className?: string;\n /** Custom CSS styles for the input root. */\n style?: React.CSSProperties;\n /** Component used to render each per-language field in the drawer. Must accept InputTextProps. Defaults to FuiInputText. */\n textComponent?: React.ComponentType<InputTextProps>;\n};\n\nconst useStyles = makeStyles({\n drawerBase: {\n height: 'auto',\n },\n drawerMobile: {\n height: '40vh',\n maxHeight: '60vh',\n },\n drawerDesktop: {\n width: '40vw',\n maxWidth: '60vw',\n maxHeight: '100vh',\n },\n drawerBody: {\n display: 'flex',\n flexDirection: 'column',\n gap: tokens.spacingVerticalL,\n padding: tokens.spacingVerticalL,\n overflowY: 'auto',\n },\n});\n\nconst RawInputMultiLangText: React.FC<\n BaseInputMultiLangTextProps & {\n id?: string;\n drawerTitle: string;\n }\n> = (props) => {\n const {\n value,\n onChange,\n disabled,\n drawerTitle,\n className,\n readOnly,\n style,\n langLabel,\n textComponent: TextComponent = FuiInputText,\n ...rest\n } = props;\n const isMobile = useIsMobile();\n\n const languages = (langLabel?.languages ?? []).slice(0, 3);\n const styles = useStyles();\n const [isDrawerOpen, setIsDrawerOpen] = useState(false);\n\n const displayValue = value\n ? (value.valueInLangOne ?? value.valueInLangTwo ?? value.valueInLangThree ?? '')\n : '';\n\n const handleChange = (newVal: string | null) => {\n if (!value) {\n onChange({\n valueInLangOne: newVal || null,\n valueInLangTwo: null,\n valueInLangThree: null,\n });\n return;\n }\n\n if (value.valueInLangOne !== null) {\n onChange({ ...value, valueInLangOne: newVal || null });\n } else if (value.valueInLangTwo !== null) {\n onChange({ ...value, valueInLangTwo: newVal || null });\n } else if (value.valueInLangThree !== null) {\n onChange({ ...value, valueInLangThree: newVal || null });\n } else {\n onChange({ ...value, valueInLangOne: newVal || null });\n }\n };\n\n const handleFieldChange = (field: keyof MultiLangText, newVal: string | null) => {\n const updatedValue: MultiLangText = {\n valueInLangOne: value?.valueInLangOne ?? null,\n valueInLangTwo: value?.valueInLangTwo ?? null,\n valueInLangThree: value?.valueInLangThree ?? null,\n [field]: newVal,\n };\n onChange(updatedValue);\n };\n\n const drawerToggle = (\n <TranslateRegular onClick={() => setIsDrawerOpen(true)} style={{ cursor: 'pointer' }} />\n );\n const drawer = (\n <OverlayDrawer\n className={mergeClasses(\n styles.drawerBase,\n isMobile ? styles.drawerMobile : styles.drawerDesktop,\n )}\n onOpenChange={(_, { open }) => setIsDrawerOpen(open)}\n open={isDrawerOpen}\n position={isMobile ? 'bottom' : 'end'}\n >\n <DrawerHeader>\n <DrawerHeaderTitle\n action={\n <Button\n appearance=\"subtle\"\n aria-label=\"Close\"\n icon={<DismissRegular />}\n onClick={() => setIsDrawerOpen(false)}\n />\n }\n >\n {drawerTitle}\n </DrawerHeaderTitle>\n </DrawerHeader>\n <DrawerBody className={styles.drawerBody}>\n <TextComponent\n disabled={disabled}\n label={languages[0] || 'Lang One'}\n onChange={(val) => handleFieldChange('valueInLangOne', val)}\n readOnly={readOnly}\n value={value?.valueInLangOne ?? null}\n />\n {languages[1] && (\n <TextComponent\n disabled={disabled}\n label={languages[1]}\n onChange={(val) => handleFieldChange('valueInLangTwo', val)}\n readOnly={readOnly}\n value={value?.valueInLangTwo ?? null}\n />\n )}\n {languages[2] && (\n <TextComponent\n disabled={disabled}\n label={languages[2]}\n onChange={(val) => handleFieldChange('valueInLangThree', val)}\n readOnly={readOnly}\n value={value?.valueInLangThree ?? null}\n />\n )}\n </DrawerBody>\n </OverlayDrawer>\n );\n\n return (\n <>\n <TextComponent\n {...rest}\n className={className}\n clearable={false}\n contentAfter={languages.length > 1 ? drawerToggle : undefined}\n disabled={disabled}\n label={null}\n noMessage\n onChange={(value) => handleChange(value)}\n readOnly={readOnly}\n style={style}\n value={displayValue}\n />\n {languages.length > 1 && drawer}\n </>\n );\n};\n\nconst EnhancedInputMultiLangText = withInputField(RawInputMultiLangText);\n\n/** Props for FuiInputMultiLangText. label is required and doubles as the per-language drawer title. */\ntype InputMultiLangTextProps = BaseInputMultiLangTextProps & FieldLayoutProps;\n/** Text input with per-language values. Translate icon opens a drawer with one input per configured language. */\nconst InputMultiLangText: React.FC<InputMultiLangTextProps> = (props) => {\n const { value, onChange } = props;\n const hasValue =\n value && (value.valueInLangOne || value.valueInLangTwo || value.valueInLangThree);\n const onClear = hasValue ? () => onChange(null) : undefined;\n\n return <EnhancedInputMultiLangText {...props} drawerTitle={props.label ?? props.placeholder} onClear={onClear} />;\n};\n\nexport { InputMultiLangText as FuiInputMultiLangText };\nexport type { MultiLangText, InputMultiLangTextProps };\n","import {\n Input,\n InputProps,\n SpinButton,\n SpinButtonChangeEvent,\n SpinButtonOnChangeData,\n makeStyles,\n tokens,\n} from '@fluentui/react-components';\nimport { ChevronDownRegular, ChevronUpRegular } from '@fluentui/react-icons';\nimport React, { useState, useEffect } from 'react';\n\nimport { useIsMobile } from '@hook/use-mobile';\n\nimport { withInputField, FieldLayoutProps } from './with-input-field';\n\nconst useStyles = makeStyles({\n arrows: {\n display: 'flex',\n flexDirection: 'row',\n gap: tokens.spacingHorizontalXS,\n },\n arrowIcon: {\n cursor: 'pointer',\n fontSize: tokens.fontSizeBase500,\n height: tokens.fontSizeBase500,\n width: tokens.fontSizeBase500,\n },\n});\n\n/**\n * Base number input props. Providing step switches the rendered element from a free-form text\n * input to a SpinButton (direct typing is disabled in SpinButton mode).\n * formatter applies only when the field is not focused.\n */\ntype BaseInputNumberProps = Omit<\n InputProps,\n 'defaultValue' | 'type' | 'value' | 'onChange' | 'id' | 'min' | 'max' | 'minLengh' | 'maxLength'\n> & {\n value: number | null;\n onChange: (value: number | null) => void;\n /** When false, the minus key is blocked. Defaults to true. */\n allowNegative?: boolean;\n /** Formats the display value when unfocused. */\n formatter?: (value: number) => string;\n /** Custom CSS class for the number input root. */\n className?: string;\n /** Custom CSS styles for the number input root. */\n style?: React.CSSProperties;\n} & (\n | {\n step?: undefined;\n /** Number of decimal places allowed. Defaults to 0. */\n precision?: number;\n min?: number;\n max?: number;\n }\n | {\n /** Enables SpinButton mode with this increment. precision is fixed at 0 when step is set. */\n step: number;\n precision?: 0;\n min?: number;\n max?: number;\n }\n );\n\nconst RawInputNumber: React.FC<\n BaseInputNumberProps & {\n id?: string;\n }\n> = (props) => {\n const {\n value,\n onChange,\n precision = 0,\n allowNegative = true,\n formatter,\n onFocus,\n onBlur,\n step,\n min,\n max,\n className,\n style,\n ...rest\n } = props;\n\n const isMobile = useIsMobile();\n const styles = useStyles();\n const [isFocused, setIsFocused] = useState(false);\n const [inputValue, setInputValue] = useState<string>(value !== null ? value.toString() : '');\n\n useEffect(() => {\n if (!isFocused) {\n setInputValue(value !== null ? value.toString() : '');\n }\n }, [value, isFocused]);\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n const key = e.key;\n if (\n ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', 'Enter', 'Escape'].includes(key)\n ) {\n return;\n }\n if (key === '-') {\n if (!allowNegative || e.currentTarget.selectionStart !== 0 || inputValue.includes('-')) {\n e.preventDefault();\n }\n return;\n }\n if (key === '.') {\n if (precision <= 0 || inputValue.includes('.')) {\n e.preventDefault();\n }\n return;\n }\n if (/^[0-9]$/.test(key)) {\n const dotIndex = inputValue.indexOf('.');\n if (dotIndex !== -1) {\n const decimalPart = inputValue.split('.')[1] || '';\n if (e.currentTarget.selectionStart! > dotIndex && decimalPart.length >= precision) {\n e.preventDefault();\n }\n }\n return;\n }\n e.preventDefault();\n };\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const val = e.target.value;\n if (val === '' || val === '-' || val === '.') {\n setInputValue(val);\n onChange(null);\n return;\n }\n const numberValue = parseFloat(val);\n if (!isNaN(numberValue)) {\n setInputValue(val);\n onChange(numberValue);\n }\n };\n\n const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {\n setIsFocused(true);\n onFocus?.(e);\n };\n\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n setIsFocused(false);\n if (inputValue === '-' || inputValue === '.') {\n setInputValue('');\n onChange(null);\n } else if (inputValue.endsWith('.')) {\n setInputValue(inputValue.slice(0, -1));\n }\n onBlur?.(e);\n };\n\n if (step) {\n const { appearance, size, ...r } = rest;\n const spinButtonValue = value;\n const spinButtonDisplayValue =\n !isFocused && spinButtonValue !== null\n ? formatter\n ? formatter(spinButtonValue)\n : spinButtonValue.toString()\n : inputValue;\n const onSpinButtonChange = (_ev: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => {\n onChange(data.value ?? null);\n };\n\n if (isMobile) {\n const interactive = !r.disabled && !r.readOnly;\n const handleUp = () => {\n if (!interactive) { return; }\n const next = (spinButtonValue ?? 0) + step;\n if (max !== undefined && next > max) { return; }\n onChange(next);\n };\n const handleDown = () => {\n if (!interactive) { return; }\n const next = (spinButtonValue ?? 0) - step;\n if (min !== undefined && next < min) { return; }\n onChange(next);\n };\n return (\n <Input\n {...r}\n className={className}\n contentAfter={\n <div className={styles.arrows}>\n <ChevronUpRegular\n className={styles.arrowIcon}\n onClick={handleUp}\n onMouseDown={(e) => e.preventDefault()}\n />\n <ChevronDownRegular\n className={styles.arrowIcon}\n onClick={handleDown}\n onMouseDown={(e) => e.preventDefault()}\n />\n </div>\n }\n onKeyDown={(e) => { if (e.key !== 'Tab') { e.preventDefault(); } }}\n style={style}\n type=\"text\"\n value={spinButtonDisplayValue}\n />\n );\n }\n\n return (\n <SpinButton\n {...r}\n appearance={\n appearance === 'filled-darker-shadow'\n ? 'filled-darker'\n : appearance === 'filled-lighter-shadow'\n ? 'filled-lighter'\n : appearance\n }\n className={className}\n displayValue={spinButtonDisplayValue}\n max={max}\n min={min}\n onChange={onSpinButtonChange}\n onKeyDown={(e) => e.preventDefault()}\n size={size === 'large' ? 'medium' : size}\n step={step}\n style={style}\n value={spinButtonValue}\n />\n );\n }\n\n const displayValue =\n !isFocused && value !== null ? (formatter ? formatter(value) : value.toString()) : inputValue;\n\n return (\n <Input\n {...rest}\n className={className}\n onBlur={handleBlur}\n onChange={handleChange}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n style={style}\n type=\"text\"\n value={displayValue}\n />\n );\n};\n\nconst EnhancedInputNumber = withInputField(RawInputNumber);\n\n/** Props for FuiInputNumber. */\ntype InputNumberProps = BaseInputNumberProps & FieldLayoutProps;\n/** Number input with keystroke filtering. Set step to switch to SpinButton mode. */\nconst InputNumber: React.FC<InputNumberProps> = (props) => {\n const { value, onChange, ...rest } = props;\n const onClear = value !== null ? () => onChange(null) : undefined;\n\n return <EnhancedInputNumber {...rest} onChange={onChange} onClear={onClear} value={value} />;\n};\n\nexport { InputNumber as FuiInputNumber };\nexport type { InputNumberProps };\n","import { RadioGroup, RadioGroupProps, RadioGroupOnChangeData } from '@fluentui/react-components';\nimport React from 'react';\n\nimport { withInputField, FieldLayoutProps } from './with-input-field';\n\n// horizontal-stacked is intentionally excluded from layout — not a supported variant here\ntype BaseInputRadioProps = Omit<RadioGroupProps, 'id' | 'layout' | 'onChange'> & {\n layout?: 'vertical' | 'horizontal';\n onChange?: (data: RadioGroupOnChangeData) => void;\n /** Custom CSS class for the radio group root. */\n className?: string;\n /** Custom CSS styles for the radio group root. */\n style?: React.CSSProperties;\n /** When true, change events are silently swallowed. Defaults to false. */\n readOnly?: boolean;\n};\n\n/** Props for FuiInputRadio. */\ntype InputRadioProps = BaseInputRadioProps & FieldLayoutProps;\n\nconst RawInputRadio: React.FC<\n BaseInputRadioProps & {\n id?: string;\n }\n> = (props) => {\n const { onChange, className, style, readOnly = false, ...rest } = props;\n\n const handleChange: RadioGroupProps['onChange'] = (_ev, data) => {\n if (!readOnly) {\n onChange?.(data);\n }\n };\n\n return <RadioGroup {...rest} className={className} onChange={handleChange} style={style} />;\n};\n\n/** Radio group wrapped with a shared label. horizontal-stacked layout is not supported. */\nconst InputRadio = withInputField(RawInputRadio);\n\nexport { InputRadio as FuiInputRadio };\nexport type { InputRadioProps };\n","import { Switch, SwitchProps } from '@fluentui/react-components';\nimport React from 'react';\n\n/** Props for FuiInputSwitch. onChange receives the new boolean directly instead of the raw SwitchProps event. */\ntype InputSwitchProps = Omit<SwitchProps, 'onChange'> & {\n /** When true, change events are silently swallowed. Defaults to false. */\n readOnly?: boolean;\n onChange: (value: boolean) => void;\n /** Custom CSS class for the switch root. */\n className?: string;\n /** Custom CSS styles for the switch root. */\n style?: React.CSSProperties;\n};\n\n/** Toggle switch. readOnly silently ignores changes without any visual indication. */\nconst InputSwitch: React.FC<InputSwitchProps> = (props) => {\n const { readOnly = false, onChange, className, style, ...rest } = props;\n\n const handleChange: SwitchProps['onChange'] = (_ev, data) => {\n if (!readOnly) {\n onChange(data.checked);\n }\n };\n\n return <Switch {...rest} className={className} onChange={handleChange} style={style} />;\n};\n\nexport { InputSwitch as FuiInputSwitch };\nexport type { InputSwitchProps };\n","import { Textarea, TextareaProps } from '@fluentui/react-components';\nimport React from 'react';\n\nimport { withInputField, FieldLayoutProps } from './with-input-field';\n\ntype BaseInputTextAreaProps = Omit<TextareaProps, 'defaultValue' | 'id' | 'value' | 'onChange'> & {\n value: string | null;\n onChange: (value: string | null) => void;\n /** Custom CSS class for the textarea root. */\n className?: string;\n /** Custom CSS styles for the textarea root. */\n style?: React.CSSProperties;\n /** When true, change events are silently swallowed. Defaults to false. */\n readOnly?: boolean;\n};\n\n/** Props for FuiInputTextArea. When maxLength is set, a character counter appears in the message area unless additionalMessage is provided. */\ntype InputTextAreaProps = BaseInputTextAreaProps & FieldLayoutProps;\n\nconst RawTextArea: React.FC<BaseInputTextAreaProps & { id?: string }> = (props) => {\n const { value, onChange, className, style, readOnly = false, ...rest } = props;\n return (\n <Textarea\n {...rest}\n className={className}\n onChange={(_e, data) => {\n if (!readOnly) {\n onChange(data.value ?? null);\n }\n }}\n style={style}\n value={value ?? ''}\n />\n );\n};\n\nconst TextareaWithField = withInputField(RawTextArea);\n\n/** Multi-line text area. Automatically appends a character counter when maxLength is set and no additionalMessage is given. */\nconst InputTextArea: React.FC<InputTextAreaProps> = (props) => {\n const { value, maxLength, additionalMessage, onChange, ...rest } = props;\n\n const charCounter = maxLength !== undefined ? `${(value ?? '').length}/${maxLength}` : undefined;\n const onClear = value !== null && value !== '' ? () => onChange(null) : undefined;\n\n return (\n <TextareaWithField\n {...rest}\n additionalMessage={additionalMessage ?? charCounter}\n maxLength={maxLength}\n onChange={onChange}\n onClear={onClear}\n value={value}\n />\n );\n};\n\nexport { InputTextArea as FuiInputTextArea };\nexport type { InputTextAreaProps };\n"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export { HandyFluentUiProvider } from './providers/handy-fluent-ui-provider';
|
|
2
|
+
export type { HandyFluentUiProviderProps } from './providers/handy-fluent-ui-provider';
|
|
3
|
+
export type { Component, HandyFluentUiConfig, HandyFluentUiContextType, LoggingLevel, SupportedTheme, ThemeType, } from './contexts/handy-fluent-ui-context';
|
|
4
|
+
export type { ConfirmationDialogProps } from './contexts/dialog-context';
|
|
5
|
+
export { useBreadcrumb } from './hooks/use-breadcrumb';
|
|
6
|
+
export { useDialog } from './hooks/use-dialog';
|
|
7
|
+
export { useIsMobile } from './hooks/use-mobile';
|
|
8
|
+
export { useLogger } from './hooks/use-logger';
|
|
9
|
+
export { useSpinner } from './hooks/use-spinner';
|
|
10
|
+
export { useTheme } from './hooks/use-theme';
|
|
11
|
+
export { useTimeZone } from './hooks/use-time-zone';
|
|
12
|
+
export { useToast } from './hooks/use-toast';
|
|
13
|
+
export { FuiButtonPanel } from './components/fui-button-panel';
|
|
14
|
+
export type { ButtonPanelProps } from './components/fui-button-panel';
|
|
15
|
+
export { FuiTab, FuiTabList } from './components/fui-tab';
|
|
16
|
+
export type { TabProps, TabListProps } from './components/fui-tab';
|
|
17
|
+
export { FuiTable, FuiColumn } from './components/fui-table';
|
|
18
|
+
export type { TableProps, ColumnProps, PaginationProps } from './components/fui-table';
|
|
19
|
+
export { FuiImageCarousel } from './components/fui-image-carousell';
|
|
20
|
+
export type { ImageCarouselProps } from './components/fui-image-carousell';
|
|
21
|
+
export { withInputField } from './components/with-input-field';
|
|
22
|
+
export type { FieldLayoutProps } from './components/with-input-field';
|
|
23
|
+
export { FuiInputCheckbox } from './components/input-checkbox';
|
|
24
|
+
export type { InputCheckboxProps } from './components/input-checkbox';
|
|
25
|
+
export { FuiInputDate } from './components/input-date';
|
|
26
|
+
export type { InputDateProps } from './components/input-date';
|
|
27
|
+
export { FuiInputTime } from './components/input-time';
|
|
28
|
+
export type { InputTimeProps } from './components/input-time';
|
|
29
|
+
export { FuiInputDropdown } from './components/input-dropdown';
|
|
30
|
+
export type { InputDropdownOption, InputDropdownProps } from './components/input-dropdown';
|
|
31
|
+
export { FuiInputGroup } from './components/input-group';
|
|
32
|
+
export type { InputGroupProps } from './components/input-group';
|
|
33
|
+
export { FuiInputMultiLangText } from './components/input-multi-lang';
|
|
34
|
+
export type { MultiLangText, InputMultiLangTextProps } from './components/input-multi-lang';
|
|
35
|
+
export { FuiInputNumber } from './components/input-number';
|
|
36
|
+
export type { InputNumberProps } from './components/input-number';
|
|
37
|
+
export { FuiInputRadio } from './components/input-radio';
|
|
38
|
+
export type { InputRadioProps } from './components/input-radio';
|
|
39
|
+
export { FuiInputSwitch } from './components/input-switch';
|
|
40
|
+
export type { InputSwitchProps } from './components/input-switch';
|
|
41
|
+
export { FuiInputText } from './components/input-text';
|
|
42
|
+
export type { InputTextProps } from './components/input-text';
|
|
43
|
+
export { FuiInputTextArea } from './components/input-textarea';
|
|
44
|
+
export type { InputTextAreaProps } from './components/input-textarea';
|
|
45
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,YAAY,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAGvF,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,wBAAwB,EACxB,YAAY,EACZ,cAAc,EACd,SAAS,GACV,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAGzE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,YAAY,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAG3E,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAE3F,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,YAAY,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAE5F,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC"}
|