@allxsmith/bestax-bulma 5.34.1 → 5.34.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"Toast.js","sources":["../../../src/components/Toast.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useEffect,\n useRef,\n useState,\n useCallback,\n useSyncExternalStore,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { isEventInside } from '../helpers/shadowDom';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { usePortalContainer } from '../helpers/portal';\nimport { groupIntoPositionStacks } from '../helpers/positionStacks';\n\n/** Color/style type presets for toast messages. */\nexport type ToastType =\n 'default' | 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n\n/** Screen positions where toasts can be displayed. */\nexport type ToastPosition =\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right';\n\n/**\n * Props for the Toast component.\n * @extraProp {string} [className] - Additional CSS classes.\n * @extraProp {React.Ref<HTMLDivElement>} [ref] - Ref forwarded to the toast element.\n */\nexport interface ToastProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n Omit<BulmaClassesProps, 'color'> {\n /** The message to display (required). */\n message: string;\n /** Color variant — colors the toast **background**. */\n type?: ToastType;\n /** Color variant — colors the **action button** text. */\n actionType?: ToastType;\n /**\n * Position on the screen. Default: 'top-right'. On a standalone `<Toast>`\n * this places it. Through `toast.show()` it places that toast, and a toast\n * shown without one goes to `ToastContainer`'s `position` instead.\n */\n position?: ToastPosition;\n /** Duration in ms before auto-close. `0` disables auto-close. */\n duration?: number;\n /** Keeps the toast visible until dismissed. */\n indefinite?: boolean;\n /** Whether clicking the toast (or outside it) dismisses it. */\n dismissible?: boolean;\n /** Show an explicit close (X) button. Default: false. */\n closable?: boolean;\n /** Pill-shaped (rounded corners). */\n rounded?: boolean;\n /** Pause auto-close timer on hover. Default: false. */\n pauseOnHover?: boolean;\n /** Whether the toast can be dismissed with Escape. Default: true. */\n cancelable?: boolean;\n /** Text for an action button (e.g. \"Undo\"). */\n actionText?: string;\n /** Text for a cancel button. */\n cancelText?: string;\n /** Callback when the action button is clicked. */\n onAction?: () => void;\n /** Callback when toast closes. */\n onClose?: () => void;\n /** CSS selector or DOM node to mount the toast into. */\n container?: string | HTMLElement;\n /** Renders inline instead of using a portal. */\n inline?: boolean;\n}\n\n/**\n * The `Toast` component provides brief notification messages with optional action and cancel buttons.\n *\n * @function\n * @param {ToastProps} props - Props for the Toast component.\n * @param {React.Ref<HTMLDivElement>} ref - Forwarded ref to the toast element.\n * @returns {JSX.Element | null} The rendered toast component.\n *\n * @example\n * // Basic toast\n * <Toast message=\"Operation successful!\" type=\"success\" />\n *\n * @example\n * // Toast with action button\n * <Toast message=\"Item deleted\" actionText=\"Undo\" onAction={handleUndo} />\n */\nexport const Toast = forwardRef<HTMLDivElement, ToastProps>(\n (\n {\n message,\n type = 'default',\n actionType,\n position = 'top-right',\n duration = 2000,\n indefinite = false,\n dismissible = true,\n closable = false,\n rounded = false,\n pauseOnHover = false,\n cancelable = true,\n actionText,\n cancelText,\n onAction,\n onClose,\n container,\n inline = false,\n className,\n ...props\n },\n ref\n ) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const resolveContainer = usePortalContainer();\n const [isVisible, setIsVisible] = useState(true);\n const [isPaused, setIsPaused] = useState(false);\n const toastRef = useRef<HTMLDivElement | null>(null);\n\n // Cleanup returned by a consumer's callback ref on attach, held until detach.\n const consumerCleanupRef = useRef<(() => void) | null>(null);\n const handleClose = useCallback(() => {\n setIsVisible(false);\n onClose?.();\n }, [onClose]);\n\n const handleAction = useCallback(() => {\n onAction?.();\n handleClose();\n }, [onAction, handleClose]);\n\n useEffect(() => {\n if (indefinite || duration === 0 || isPaused) return undefined;\n\n const timer = setTimeout(() => {\n handleClose();\n }, duration);\n\n return () => clearTimeout(timer);\n }, [duration, indefinite, isPaused, handleClose]);\n\n const handleMouseEnter = useCallback(() => {\n if (pauseOnHover) {\n setIsPaused(true);\n }\n }, [pauseOnHover]);\n\n const handleMouseLeave = useCallback(() => {\n if (pauseOnHover) {\n setIsPaused(false);\n }\n }, [pauseOnHover]);\n\n // Click-outside dismiss — deferred so the click that spawned the toast\n // doesn't immediately dismiss it before it's even visible.\n useEffect(() => {\n if (!dismissible || !isVisible) return undefined;\n\n const handleDocumentClick = (e: MouseEvent) => {\n if (toastRef.current && !isEventInside(e, toastRef.current)) {\n handleClose();\n }\n };\n\n const raf = requestAnimationFrame(() => {\n document.addEventListener('click', handleDocumentClick);\n });\n\n return () => {\n cancelAnimationFrame(raf);\n document.removeEventListener('click', handleDocumentClick);\n };\n }, [dismissible, isVisible, handleClose]);\n\n useEffect(() => {\n if (!cancelable) return undefined;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n handleClose();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [cancelable, handleClose]);\n\n const containerClasses = usePrefixedClassNames('toast-container', {\n [`is-${position}`]: true,\n });\n\n const toastClasses = usePrefixedClassNames('toast', {\n [`is-${type}`]: type !== 'default',\n [`is-action-${actionType}`]: !!actionType && actionType !== 'default',\n 'is-rounded': rounded,\n });\n\n const combinedClasses = classNames(\n toastClasses,\n bulmaHelperClasses,\n className\n );\n const toastMessageClass = usePrefixedClassNames('toast-message');\n const toastActionsClass = usePrefixedClassNames('toast-actions');\n const toastCancelClass = usePrefixedClassNames('toast-cancel');\n const toastActionClass = usePrefixedClassNames('toast-action');\n const toastButtonClass = usePrefixedClassNames('button');\n const toastCloseClass = usePrefixedClassNames('delete', 'is-small');\n\n const setRef = useCallback(\n (node: HTMLDivElement | null) => {\n toastRef.current = node;\n if (typeof ref === 'function') {\n // React 19 lets a callback ref return a cleanup function and detaches by\n // running it instead of calling the ref with `null`; React 18 discards the\n // return value entirely. Returning it from here would be a React-19-only\n // contract, so we hold the cleanup and run it ourselves on detach — the\n // same shape as `Dropdown`, `Modal`, `Dialog`, `Sidebar` and `Carousel`.\n // The form controls that merge a forwarded ref still discard the cleanup\n // and detach with `ref(null)`, so this is not yet library-wide — grep\n // `typeof ref === 'function'` for the current split. Memoized because an\n // unstable ref identity makes React detach and re-attach on every render,\n // which would run that cleanup each time.\n if (node === null) {\n const consumerCleanup = consumerCleanupRef.current;\n consumerCleanupRef.current = null;\n if (consumerCleanup) {\n consumerCleanup();\n } else {\n ref(null);\n }\n return;\n }\n const cleanup: unknown = ref(node);\n consumerCleanupRef.current =\n typeof cleanup === 'function' ? (cleanup as () => void) : null;\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }\n },\n [ref]\n );\n\n if (!isVisible) {\n return null;\n }\n\n const toastElement = (\n <div\n ref={setRef}\n className={combinedClasses}\n role=\"alert\"\n aria-live={\n type === 'danger' || type === 'warning' ? 'assertive' : 'polite'\n }\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={dismissible ? handleClose : undefined}\n {...rest}\n >\n <span className={toastMessageClass}>{message}</span>\n {(cancelText || actionText) && (\n <div className={toastActionsClass}>\n {cancelText && (\n <span className={toastCancelClass}>\n <button\n type=\"button\"\n className={toastButtonClass}\n onClick={e => {\n e.stopPropagation();\n handleClose();\n }}\n >\n {cancelText}\n </button>\n </span>\n )}\n {actionText && (\n <span className={toastActionClass}>\n <button\n type=\"button\"\n className={toastButtonClass}\n onClick={e => {\n e.stopPropagation();\n handleAction();\n }}\n >\n {actionText}\n </button>\n </span>\n )}\n </div>\n )}\n {closable && (\n <button\n type=\"button\"\n className={toastCloseClass}\n onClick={e => {\n e.stopPropagation();\n handleClose();\n }}\n aria-label=\"Close\"\n />\n )}\n </div>\n );\n\n if (inline) {\n return toastElement;\n }\n\n const toastContent = <div className={containerClasses}>{toastElement}</div>;\n\n if (typeof document !== 'undefined') {\n return createPortal(toastContent, resolveContainer(container));\n }\n\n return null;\n }\n);\n\nToast.displayName = 'Toast';\n\n// Toast Manager for programmatic toasts\n\n/**\n * Options for showing a programmatic toast. Extends ToastProps with a required message.\n */\nexport interface ToastOptions extends Omit<ToastProps, 'message'> {\n /** The message to display. */\n message: string;\n /**\n * When true, toasts enter a FIFO queue and display one at a time, one queue\n * across every `position`. Default false.\n */\n queue?: boolean;\n}\n\n/**\n * Internal representation of a toast instance.\n */\nexport interface ToastInstance {\n /** Unique identifier for this toast. */\n id: string;\n /** Configuration options for the toast. */\n props: ToastOptions;\n}\n\nlet toastId = 0;\nconst toastListeners: Set<(toasts: ToastInstance[]) => void> = new Set();\nlet toasts: ToastInstance[] = [];\n\n// Queued toasts: FIFO queue, one at a time\nlet queuedToasts: ToastInstance[] = [];\nlet currentQueuedToast: ToastInstance | null = null;\n\n// The server has nowhere to portal a toast to, and its copy of this module is\n// shared by every request, so server rendering reads an empty list. Hydration\n// reads it too, which keeps the first client render matching the server's.\nconst noToasts: ToastInstance[] = [];\nconst getServerToasts = () => noToasts;\n\n// What a container shows right now: the stacked toasts, then the queued one on\n// screen. ToastContainer renders from this rather than from updates alone, so\n// toasts raised before it mounted still appear. It is replaced rather than\n// mutated, and only when listeners are notified, because useSyncExternalStore\n// needs the same array back between changes. An empty list is `noToasts`\n// itself, so a container that hydrates with nothing to show reads the same\n// snapshot the server did and has no reason to render again.\nlet visibleToasts: ToastInstance[] = noToasts;\nconst getVisibleToasts = () => visibleToasts;\n\nconst notifyListeners = () => {\n const allVisible = [...toasts];\n if (currentQueuedToast) {\n allVisible.push(currentQueuedToast);\n }\n visibleToasts = allVisible.length > 0 ? allVisible : noToasts;\n toastListeners.forEach(listener => listener([...allVisible]));\n};\n\nconst processQueuedToast = () => {\n if (currentQueuedToast || queuedToasts.length === 0) return;\n currentQueuedToast = queuedToasts.shift()!;\n notifyListeners();\n};\n\n/**\n * Programmatic toast API for showing, closing, and managing toasts.\n *\n * @example\n * toast.success('Saved!');\n * toast.show({ message: 'Item deleted', actionText: 'Undo', onAction: handleUndo });\n */\nexport const toast = {\n /**\n * Show a toast with the given options.\n * @param {ToastOptions} options - Toast configuration.\n * @returns {string} The unique ID of the created toast.\n */\n show: (options: ToastOptions): string => {\n const id = `toast-${++toastId}`;\n const instance = { id, props: options };\n\n if (options.queue) {\n queuedToasts.push(instance);\n processQueuedToast();\n } else {\n toasts.push(instance);\n notifyListeners();\n }\n\n return id;\n },\n\n /**\n * Show a success toast.\n * @param {string} message - The message to display.\n * @param {Partial<ToastOptions>} [options] - Additional options.\n * @returns {string} The toast ID.\n */\n success: (message: string, options?: Partial<ToastOptions>): string => {\n return toast.show({ message, type: 'success', ...options });\n },\n\n /**\n * Show a danger toast.\n * @param {string} message - The message to display.\n * @param {Partial<ToastOptions>} [options] - Additional options.\n * @returns {string} The toast ID.\n */\n danger: (message: string, options?: Partial<ToastOptions>): string => {\n return toast.show({ message, type: 'danger', ...options });\n },\n\n /**\n * Show a warning toast.\n * @param {string} message - The message to display.\n * @param {Partial<ToastOptions>} [options] - Additional options.\n * @returns {string} The toast ID.\n */\n warning: (message: string, options?: Partial<ToastOptions>): string => {\n return toast.show({ message, type: 'warning', ...options });\n },\n\n /**\n * Show an info toast.\n * @param {string} message - The message to display.\n * @param {Partial<ToastOptions>} [options] - Additional options.\n * @returns {string} The toast ID.\n */\n info: (message: string, options?: Partial<ToastOptions>): string => {\n return toast.show({ message, type: 'info', ...options });\n },\n\n /**\n * Close a specific toast by ID.\n * @param {string} id - The toast ID to close.\n */\n close: (id: string): void => {\n if (currentQueuedToast && currentQueuedToast.id === id) {\n currentQueuedToast = null;\n processQueuedToast();\n } else {\n queuedToasts = queuedToasts.filter(t => t.id !== id);\n toasts = toasts.filter(t => t.id !== id);\n }\n notifyListeners();\n },\n\n /** Close all toasts and clear the queue. */\n closeAll: (): void => {\n toasts = [];\n queuedToasts = [];\n currentQueuedToast = null;\n notifyListeners();\n },\n\n /**\n * Subscribe to toast state changes.\n * @param {(toasts: ToastInstance[]) => void} listener - Callback invoked on changes.\n * @returns {() => void} Unsubscribe function.\n */\n subscribe: (listener: (toasts: ToastInstance[]) => void): (() => void) => {\n toastListeners.add(listener);\n return () => toastListeners.delete(listener);\n },\n};\n\n// The order ToastContainer renders its stacks in: across the top of the\n// screen, then across the bottom.\nconst toastStackOrder: readonly ToastPosition[] = [\n 'top-left',\n 'top-center',\n 'top-right',\n 'bottom-left',\n 'bottom-center',\n 'bottom-right',\n];\n\n/**\n * Container component for rendering programmatic toasts.\n * Place once at your app root to enable the toast API. A toast shown with a\n * `position` appears there, and one shown without goes to the container's\n * `position`.\n *\n * @function\n * @param {{ position?: ToastPosition }} props - Container props.\n * @returns {JSX.Element | null} The rendered toast container, or null if empty.\n */\nexport const ToastContainer: React.FC<{\n /**\n * Where a toast shown without a `position` of its own appears. Default:\n * 'top-right'. When it changes, those toasts move without remounting, but\n * one shown with its own `position` equal to the old or new value\n * remounts and starts over as if it had just been shown.\n */\n position?: ToastPosition;\n}> = ({ position = 'top-right' }) => {\n // Starts from the toasts already showing instead of an empty list, then\n // follows changes.\n const toastList = useSyncExternalStore(\n toast.subscribe,\n getVisibleToasts,\n getServerToasts\n );\n const resolveContainer = usePortalContainer();\n\n if (typeof document === 'undefined' || toastList.length === 0) {\n return null;\n }\n\n const stacks = groupIntoPositionStacks(\n toastList,\n t => t.props.position,\n position,\n toastStackOrder\n );\n\n return createPortal(\n stacks.map(stack => (\n <div key={stack.key} className={`toast-container is-${stack.position}`}>\n {stack.items.map(t => {\n const { queue: _queue, ...toastProps } = t.props;\n return (\n <Toast\n key={t.id}\n {...toastProps}\n position={stack.position}\n onClose={() => toast.close(t.id)}\n />\n );\n })}\n </div>\n )),\n resolveContainer()\n );\n};\n\nexport default Toast;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
1
+ {"version":3,"file":"Toast.js","sources":["../../../src/components/Toast.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useEffect,\n useRef,\n useState,\n useCallback,\n useSyncExternalStore,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { isEventInside } from '../helpers/shadowDom';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { usePortalContainer } from '../helpers/portal';\nimport { groupIntoPositionStacks } from '../helpers/positionStacks';\n\n/** Color/style type presets for toast messages. */\nexport type ToastType =\n 'default' | 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n\n/** Screen positions where toasts can be displayed. */\nexport type ToastPosition =\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right';\n\n/**\n * Props for the Toast component.\n * @extraProp {string} [className] - Additional CSS classes.\n * @extraProp {React.Ref<HTMLDivElement>} [ref] - Ref forwarded to the toast element.\n */\nexport interface ToastProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n Omit<BulmaClassesProps, 'color'> {\n /** The message to display (required). */\n message: string;\n /** Color variant — colors the toast **background**. */\n type?: ToastType;\n /** Color variant — colors the **action button** text. */\n actionType?: ToastType;\n /**\n * Position on the screen. Default: 'top-right'. On a standalone `<Toast>`\n * this places it. Through `toast.show()` it places that toast, and a toast\n * shown without one goes to `ToastContainer`'s `position` instead.\n */\n position?: ToastPosition;\n /** Duration in ms before auto-close. `0` disables auto-close. */\n duration?: number;\n /** Keeps the toast visible until dismissed. */\n indefinite?: boolean;\n /** Whether clicking the toast (or outside it) dismisses it. */\n dismissible?: boolean;\n /** Show an explicit close (X) button. Default: false. */\n closable?: boolean;\n /** Pill-shaped (rounded corners). */\n rounded?: boolean;\n /** Pause auto-close timer on hover. Default: false. */\n pauseOnHover?: boolean;\n /**\n * Whether the toast can be dismissed with Escape. An Escape a popup on the\n * page closed on, by calling `preventDefault()`, leaves it up. Default: true.\n */\n cancelable?: boolean;\n /** Text for an action button (e.g. \"Undo\"). */\n actionText?: string;\n /** Text for a cancel button. */\n cancelText?: string;\n /** Callback when the action button is clicked. */\n onAction?: () => void;\n /** Callback when toast closes. */\n onClose?: () => void;\n /** CSS selector or DOM node to mount the toast into. */\n container?: string | HTMLElement;\n /** Renders inline instead of using a portal. */\n inline?: boolean;\n}\n\n/**\n * The `Toast` component provides brief notification messages with optional action and cancel buttons.\n *\n * @function\n * @param {ToastProps} props - Props for the Toast component.\n * @param {React.Ref<HTMLDivElement>} ref - Forwarded ref to the toast element.\n * @returns {JSX.Element | null} The rendered toast component.\n *\n * @example\n * // Basic toast\n * <Toast message=\"Operation successful!\" type=\"success\" />\n *\n * @example\n * // Toast with action button\n * <Toast message=\"Item deleted\" actionText=\"Undo\" onAction={handleUndo} />\n */\nexport const Toast = forwardRef<HTMLDivElement, ToastProps>(\n (\n {\n message,\n type = 'default',\n actionType,\n position = 'top-right',\n duration = 2000,\n indefinite = false,\n dismissible = true,\n closable = false,\n rounded = false,\n pauseOnHover = false,\n cancelable = true,\n actionText,\n cancelText,\n onAction,\n onClose,\n container,\n inline = false,\n className,\n ...props\n },\n ref\n ) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const resolveContainer = usePortalContainer();\n const [isVisible, setIsVisible] = useState(true);\n const [isPaused, setIsPaused] = useState(false);\n const toastRef = useRef<HTMLDivElement | null>(null);\n\n // Cleanup returned by a consumer's callback ref on attach, held until detach.\n const consumerCleanupRef = useRef<(() => void) | null>(null);\n const handleClose = useCallback(() => {\n setIsVisible(false);\n onClose?.();\n }, [onClose]);\n\n const handleAction = useCallback(() => {\n onAction?.();\n handleClose();\n }, [onAction, handleClose]);\n\n useEffect(() => {\n if (indefinite || duration === 0 || isPaused) return undefined;\n\n const timer = setTimeout(() => {\n handleClose();\n }, duration);\n\n return () => clearTimeout(timer);\n }, [duration, indefinite, isPaused, handleClose]);\n\n const handleMouseEnter = useCallback(() => {\n if (pauseOnHover) {\n setIsPaused(true);\n }\n }, [pauseOnHover]);\n\n const handleMouseLeave = useCallback(() => {\n if (pauseOnHover) {\n setIsPaused(false);\n }\n }, [pauseOnHover]);\n\n // Click-outside dismiss — deferred so the click that spawned the toast\n // doesn't immediately dismiss it before it's even visible.\n useEffect(() => {\n if (!dismissible || !isVisible) return undefined;\n\n const handleDocumentClick = (e: MouseEvent) => {\n if (toastRef.current && !isEventInside(e, toastRef.current)) {\n handleClose();\n }\n };\n\n const raf = requestAnimationFrame(() => {\n document.addEventListener('click', handleDocumentClick);\n });\n\n return () => {\n cancelAnimationFrame(raf);\n document.removeEventListener('click', handleDocumentClick);\n };\n }, [dismissible, isVisible, handleClose]);\n\n // On `window`, as in `Modal`, so a popup on the page has had the key\n // first, and an Escape it closed on doesn't dismiss the toast as well.\n useEffect(() => {\n if (!cancelable || !isVisible) return undefined;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && !e.defaultPrevented) {\n handleClose();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [cancelable, isVisible, handleClose]);\n\n const containerClasses = usePrefixedClassNames('toast-container', {\n [`is-${position}`]: true,\n });\n\n const toastClasses = usePrefixedClassNames('toast', {\n [`is-${type}`]: type !== 'default',\n [`is-action-${actionType}`]: !!actionType && actionType !== 'default',\n 'is-rounded': rounded,\n });\n\n const combinedClasses = classNames(\n toastClasses,\n bulmaHelperClasses,\n className\n );\n const toastMessageClass = usePrefixedClassNames('toast-message');\n const toastActionsClass = usePrefixedClassNames('toast-actions');\n const toastCancelClass = usePrefixedClassNames('toast-cancel');\n const toastActionClass = usePrefixedClassNames('toast-action');\n const toastButtonClass = usePrefixedClassNames('button');\n const toastCloseClass = usePrefixedClassNames('delete', 'is-small');\n\n const setRef = useCallback(\n (node: HTMLDivElement | null) => {\n toastRef.current = node;\n if (typeof ref === 'function') {\n // React 19 lets a callback ref return a cleanup function and detaches by\n // running it instead of calling the ref with `null`; React 18 discards the\n // return value entirely. Returning it from here would be a React-19-only\n // contract, so we hold the cleanup and run it ourselves on detach — the\n // same shape as `Dropdown`, `Modal`, `Dialog`, `Sidebar` and `Carousel`.\n // The form controls that merge a forwarded ref still discard the cleanup\n // and detach with `ref(null)`, so this is not yet library-wide — grep\n // `typeof ref === 'function'` for the current split. Memoized because an\n // unstable ref identity makes React detach and re-attach on every render,\n // which would run that cleanup each time.\n if (node === null) {\n const consumerCleanup = consumerCleanupRef.current;\n consumerCleanupRef.current = null;\n if (consumerCleanup) {\n consumerCleanup();\n } else {\n ref(null);\n }\n return;\n }\n const cleanup: unknown = ref(node);\n consumerCleanupRef.current =\n typeof cleanup === 'function' ? (cleanup as () => void) : null;\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;\n }\n },\n [ref]\n );\n\n if (!isVisible) {\n return null;\n }\n\n const toastElement = (\n <div\n ref={setRef}\n className={combinedClasses}\n role=\"alert\"\n aria-live={\n type === 'danger' || type === 'warning' ? 'assertive' : 'polite'\n }\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onClick={dismissible ? handleClose : undefined}\n {...rest}\n >\n <span className={toastMessageClass}>{message}</span>\n {(cancelText || actionText) && (\n <div className={toastActionsClass}>\n {cancelText && (\n <span className={toastCancelClass}>\n <button\n type=\"button\"\n className={toastButtonClass}\n onClick={e => {\n e.stopPropagation();\n handleClose();\n }}\n >\n {cancelText}\n </button>\n </span>\n )}\n {actionText && (\n <span className={toastActionClass}>\n <button\n type=\"button\"\n className={toastButtonClass}\n onClick={e => {\n e.stopPropagation();\n handleAction();\n }}\n >\n {actionText}\n </button>\n </span>\n )}\n </div>\n )}\n {closable && (\n <button\n type=\"button\"\n className={toastCloseClass}\n onClick={e => {\n e.stopPropagation();\n handleClose();\n }}\n aria-label=\"Close\"\n />\n )}\n </div>\n );\n\n if (inline) {\n return toastElement;\n }\n\n const toastContent = <div className={containerClasses}>{toastElement}</div>;\n\n if (typeof document !== 'undefined') {\n return createPortal(toastContent, resolveContainer(container));\n }\n\n return null;\n }\n);\n\nToast.displayName = 'Toast';\n\n// Toast Manager for programmatic toasts\n\n/**\n * Options for showing a programmatic toast. Extends ToastProps with a required message.\n */\nexport interface ToastOptions extends Omit<ToastProps, 'message'> {\n /** The message to display. */\n message: string;\n /**\n * When true, toasts enter a FIFO queue and display one at a time, one queue\n * across every `position`. Default false.\n */\n queue?: boolean;\n}\n\n/**\n * Internal representation of a toast instance.\n */\nexport interface ToastInstance {\n /** Unique identifier for this toast. */\n id: string;\n /** Configuration options for the toast. */\n props: ToastOptions;\n}\n\nlet toastId = 0;\nconst toastListeners: Set<(toasts: ToastInstance[]) => void> = new Set();\nlet toasts: ToastInstance[] = [];\n\n// Queued toasts: FIFO queue, one at a time\nlet queuedToasts: ToastInstance[] = [];\nlet currentQueuedToast: ToastInstance | null = null;\n\n// The server has nowhere to portal a toast to, and its copy of this module is\n// shared by every request, so server rendering reads an empty list. Hydration\n// reads it too, which keeps the first client render matching the server's.\nconst noToasts: ToastInstance[] = [];\nconst getServerToasts = () => noToasts;\n\n// What a container shows right now: the stacked toasts, then the queued one on\n// screen. ToastContainer renders from this rather than from updates alone, so\n// toasts raised before it mounted still appear. It is replaced rather than\n// mutated, and only when listeners are notified, because useSyncExternalStore\n// needs the same array back between changes. An empty list is `noToasts`\n// itself, so a container that hydrates with nothing to show reads the same\n// snapshot the server did and has no reason to render again.\nlet visibleToasts: ToastInstance[] = noToasts;\nconst getVisibleToasts = () => visibleToasts;\n\nconst notifyListeners = () => {\n const allVisible = [...toasts];\n if (currentQueuedToast) {\n allVisible.push(currentQueuedToast);\n }\n visibleToasts = allVisible.length > 0 ? allVisible : noToasts;\n toastListeners.forEach(listener => listener([...allVisible]));\n};\n\nconst processQueuedToast = () => {\n if (currentQueuedToast || queuedToasts.length === 0) return;\n currentQueuedToast = queuedToasts.shift()!;\n notifyListeners();\n};\n\n/**\n * Programmatic toast API for showing, closing, and managing toasts.\n *\n * @example\n * toast.success('Saved!');\n * toast.show({ message: 'Item deleted', actionText: 'Undo', onAction: handleUndo });\n */\nexport const toast = {\n /**\n * Show a toast with the given options.\n * @param {ToastOptions} options - Toast configuration.\n * @returns {string} The unique ID of the created toast.\n */\n show: (options: ToastOptions): string => {\n const id = `toast-${++toastId}`;\n const instance = { id, props: options };\n\n if (options.queue) {\n queuedToasts.push(instance);\n processQueuedToast();\n } else {\n toasts.push(instance);\n notifyListeners();\n }\n\n return id;\n },\n\n /**\n * Show a success toast.\n * @param {string} message - The message to display.\n * @param {Partial<ToastOptions>} [options] - Additional options.\n * @returns {string} The toast ID.\n */\n success: (message: string, options?: Partial<ToastOptions>): string => {\n return toast.show({ message, type: 'success', ...options });\n },\n\n /**\n * Show a danger toast.\n * @param {string} message - The message to display.\n * @param {Partial<ToastOptions>} [options] - Additional options.\n * @returns {string} The toast ID.\n */\n danger: (message: string, options?: Partial<ToastOptions>): string => {\n return toast.show({ message, type: 'danger', ...options });\n },\n\n /**\n * Show a warning toast.\n * @param {string} message - The message to display.\n * @param {Partial<ToastOptions>} [options] - Additional options.\n * @returns {string} The toast ID.\n */\n warning: (message: string, options?: Partial<ToastOptions>): string => {\n return toast.show({ message, type: 'warning', ...options });\n },\n\n /**\n * Show an info toast.\n * @param {string} message - The message to display.\n * @param {Partial<ToastOptions>} [options] - Additional options.\n * @returns {string} The toast ID.\n */\n info: (message: string, options?: Partial<ToastOptions>): string => {\n return toast.show({ message, type: 'info', ...options });\n },\n\n /**\n * Close a specific toast by ID.\n * @param {string} id - The toast ID to close.\n */\n close: (id: string): void => {\n if (currentQueuedToast && currentQueuedToast.id === id) {\n currentQueuedToast = null;\n processQueuedToast();\n } else {\n queuedToasts = queuedToasts.filter(t => t.id !== id);\n toasts = toasts.filter(t => t.id !== id);\n }\n notifyListeners();\n },\n\n /** Close all toasts and clear the queue. */\n closeAll: (): void => {\n toasts = [];\n queuedToasts = [];\n currentQueuedToast = null;\n notifyListeners();\n },\n\n /**\n * Subscribe to toast state changes.\n * @param {(toasts: ToastInstance[]) => void} listener - Callback invoked on changes.\n * @returns {() => void} Unsubscribe function.\n */\n subscribe: (listener: (toasts: ToastInstance[]) => void): (() => void) => {\n toastListeners.add(listener);\n return () => toastListeners.delete(listener);\n },\n};\n\n// The order ToastContainer renders its stacks in: across the top of the\n// screen, then across the bottom.\nconst toastStackOrder: readonly ToastPosition[] = [\n 'top-left',\n 'top-center',\n 'top-right',\n 'bottom-left',\n 'bottom-center',\n 'bottom-right',\n];\n\n/**\n * Container component for rendering programmatic toasts.\n * Place once at your app root to enable the toast API. A toast shown with a\n * `position` appears there, and one shown without goes to the container's\n * `position`.\n *\n * @function\n * @param {{ position?: ToastPosition }} props - Container props.\n * @returns {JSX.Element | null} The rendered toast container, or null if empty.\n */\nexport const ToastContainer: React.FC<{\n /**\n * Where a toast shown without a `position` of its own appears. Default:\n * 'top-right'. When it changes, those toasts move without remounting, but\n * one shown with its own `position` equal to the old or new value\n * remounts and starts over as if it had just been shown.\n */\n position?: ToastPosition;\n}> = ({ position = 'top-right' }) => {\n // Starts from the toasts already showing instead of an empty list, then\n // follows changes.\n const toastList = useSyncExternalStore(\n toast.subscribe,\n getVisibleToasts,\n getServerToasts\n );\n const resolveContainer = usePortalContainer();\n\n if (typeof document === 'undefined' || toastList.length === 0) {\n return null;\n }\n\n const stacks = groupIntoPositionStacks(\n toastList,\n t => t.props.position,\n position,\n toastStackOrder\n );\n\n return createPortal(\n stacks.map(stack => (\n <div key={stack.key} className={`toast-container is-${stack.position}`}>\n {stack.items.map(t => {\n const { queue: _queue, ...toastProps } = t.props;\n return (\n <Toast\n key={t.id}\n {...toastProps}\n position={stack.position}\n onClose={() => toast.close(t.id)}\n />\n );\n })}\n </div>\n )),\n resolveContainer()\n );\n};\n\nexport default Toast;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
@@ -14,6 +14,18 @@ import { spokenText, StatusRegion } from '../helpers/statusRegion.js';
14
14
  // it's handed while that content is on screen because of the user's typing.
15
15
  const typedNoMatches = [{ id: 'empty' }];
16
16
  const nothingToAnnounce = [];
17
+ // A press on an option would take focus from the field, since an option
18
+ // can't hold it, and nothing would put it back. Cancelling the press keeps
19
+ // it there, as the ARIA Authoring Practices' combobox does, and the click
20
+ // still picks the option.
21
+ const keepFocus = (e) => e.preventDefault();
22
+ // An IME that's composing owns every key: Enter confirms what it composed,
23
+ // and the arrows move through its candidates. Safari can say so with
24
+ // `keyCode` 229 rather than `isComposing`.
25
+ const isComposing = (e) => e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229;
26
+ // Whether an option can be picked. The arrows still reach a disabled one, so
27
+ // a screen reader user finds it.
28
+ const isEnabled = (item) => typeof item === 'string' || !item.disabled;
17
29
  /**
18
30
  * The `Autocomplete` component provides an input field with dropdown suggestions that filter based on user input.
19
31
  *
@@ -39,6 +51,11 @@ const nothingToAnnounce = [];
39
51
  * />
40
52
  */
41
53
  const Autocomplete = forwardRef(({ data = [], value: controlledValue, placeholder, field = 'label', clearable = false, openOnFocus = false, keepFirst = false, keepOpen = false, selectOnClickOutside = false, maxHeight = 200, loading = false, disabled = false, checkInfiniteScroll = false, infiniteScrollDistance = 50, color, size, onInput, onSelect, onActiveChange, onInfiniteScroll, itemTemplate, header, footer, empty, name, form, required, id,
54
+ // Deprecated no-ops, taken here so they stay off the wrapper.
55
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- deprecated no-op
56
+ selected,
57
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- deprecated no-op
58
+ dropdown,
42
59
  // Field props
43
60
  label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName, className, ...props }, ref) => {
44
61
  const insideField = useInsideField();
@@ -168,13 +185,17 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
168
185
  }, [keepFirst, isActive, filteredData.length, inputValue]);
169
186
  // Handle keyboard navigation
170
187
  const handleKeyDown = useCallback((e) => {
171
- if (disabled)
188
+ if (disabled || isComposing(e))
172
189
  return;
173
190
  switch (e.key) {
174
191
  case 'ArrowDown':
175
192
  e.preventDefault();
176
193
  if (!isActive) {
194
+ // A closed list opens on its first enabled option, as the ARIA
195
+ // Authoring Practices' combobox does. Alt+Down Arrow opens it
196
+ // without a highlight.
177
197
  setIsActive(true);
198
+ setHighlightedIndex(e.altKey ? -1 : filteredData.map(isEnabled).indexOf(true));
178
199
  }
179
200
  else {
180
201
  setHighlightedIndex(prev => prev < filteredData.length - 1 ? prev + 1 : prev);
@@ -182,27 +203,56 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
182
203
  break;
183
204
  case 'ArrowUp':
184
205
  e.preventDefault();
185
- setHighlightedIndex(prev => (prev > 0 ? prev - 1 : prev));
206
+ if (!isActive) {
207
+ // And Up Arrow opens it on its last enabled option.
208
+ setIsActive(true);
209
+ setHighlightedIndex(filteredData.map(isEnabled).lastIndexOf(true));
210
+ }
211
+ else {
212
+ setHighlightedIndex(prev => (prev > 0 ? prev - 1 : prev));
213
+ }
186
214
  break;
187
215
  case 'Enter':
188
- e.preventDefault();
189
- if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {
216
+ // With the list open on a highlighted option it can pick, Enter
217
+ // is that option's. Otherwise it closes the list and goes on, so
218
+ // a form around the field submits, as it would from any text
219
+ // field.
220
+ if (isActive &&
221
+ highlightedIndex >= 0 &&
222
+ filteredData[highlightedIndex] &&
223
+ isEnabled(filteredData[highlightedIndex])) {
224
+ e.preventDefault();
190
225
  handleSelect(filteredData[highlightedIndex]);
191
226
  }
227
+ else {
228
+ setIsActive(false);
229
+ }
192
230
  break;
193
231
  case 'Escape':
194
- e.preventDefault();
232
+ // Only closing the dropdown claims the key. With it closed, the
233
+ // key goes on to a Modal around the field.
234
+ if (menuOpen)
235
+ e.preventDefault();
195
236
  setIsActive(false);
196
237
  setHighlightedIndex(-1);
197
238
  break;
198
239
  case 'Tab':
199
- if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {
240
+ if (isActive &&
241
+ highlightedIndex >= 0 &&
242
+ filteredData[highlightedIndex]) {
200
243
  handleSelect(filteredData[highlightedIndex]);
201
244
  }
202
245
  setIsActive(false);
203
246
  break;
204
247
  }
205
- }, [disabled, isActive, highlightedIndex, filteredData, handleSelect]);
248
+ }, [
249
+ disabled,
250
+ isActive,
251
+ menuOpen,
252
+ highlightedIndex,
253
+ filteredData,
254
+ handleSelect,
255
+ ]);
206
256
  // Handle dropdown scroll for infinite scroll
207
257
  const handleDropdownScroll = useCallback(() => {
208
258
  if (!checkInfiniteScroll || !dropdownRef.current)
@@ -302,17 +352,17 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
302
352
  return null;
303
353
  return spokenText(node);
304
354
  }, []);
305
- const autocompleteElement = (jsxs("div", { ref: containerRef, className: combinedClasses, ...rest, children: [jsxs("div", { className: controlClasses, children: [jsx("input", { ref: combinedRef, type: "text", className: inputClasses, id: controlId, value: inputValue, placeholder: placeholder, disabled: disabled, name: name, form: form, required: required, onChange: handleInputChange, onFocus: handleFocus, onKeyDown: handleKeyDown, role: "combobox", "aria-expanded": listOpen, "aria-controls": listOpen ? listboxId : undefined, "aria-activedescendant": activeOptionId, "aria-haspopup": "listbox", "aria-autocomplete": "list", autoComplete: "off" }), showClear && (jsx("button", { type: "button", className: iconRightClickableClass, onClick: handleClear, "aria-label": "Clear", children: jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", width: "16", height: "16", "aria-hidden": "true", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })), loading && (jsx("span", { className: iconRightClass, children: jsx("span", { className: loaderClass }) }))] }), menuOpen && (jsx("div", { className: dropdownMenuClasses, children: jsxs("div", { ref: dropdownRef, className: dropdownContentClass, style: { maxHeight: `${maxHeight}px`, overflowY: 'auto' }, onScroll: handleDropdownScroll, children: [header && jsx("div", { className: dropdownHeaderClass, children: header }), listOpen ? (jsx("div", { id: listboxId, role: "listbox", "aria-labelledby": listLabelId, "aria-label": listLabelId ? undefined : 'Suggestions', children: filteredData.map((item, index) => {
355
+ const autocompleteElement = (jsxs("div", { ref: containerRef, className: combinedClasses, ...rest, children: [jsxs("div", { className: controlClasses, children: [jsx("input", { ref: combinedRef, type: "text", className: inputClasses, id: controlId, value: inputValue, placeholder: placeholder, disabled: disabled, name: name, form: form, required: required, onChange: handleInputChange, onFocus: handleFocus, onKeyDown: handleKeyDown, role: "combobox", "aria-expanded": listOpen, "aria-controls": listOpen ? listboxId : undefined, "aria-activedescendant": activeOptionId, "aria-haspopup": "listbox", "aria-autocomplete": "list", autoComplete: "off" }), showClear && (jsx("button", { type: "button", className: iconRightClickableClass, onClick: handleClear, "aria-label": "Clear", children: jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", width: "16", height: "16", "aria-hidden": "true", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })), loading && (jsx("span", { className: iconRightClass, children: jsx("span", { className: loaderClass }) }))] }), menuOpen && (jsx("div", { className: dropdownMenuClasses, children: jsxs("div", { ref: dropdownRef, className: dropdownContentClass, style: { maxHeight: `${maxHeight}px`, overflowY: 'auto' }, onScroll: handleDropdownScroll, children: [header && jsx("div", { className: dropdownHeaderClass, children: header }), listOpen ? (jsx("div", { id: listboxId, role: "listbox", "aria-labelledby": listLabelId, "aria-label": listLabelId ? undefined : 'Suggestions', onMouseDown: keepFocus, children: filteredData.map((item, index) => {
306
356
  const isDisabled = typeof item !== 'string' && item.disabled;
307
357
  const isHighlighted = index === highlightedIndex;
308
358
  const itemClasses = prefixedClassNames(classPrefix, 'dropdown-item', {
309
359
  'is-active': isHighlighted,
310
360
  'is-disabled': isDisabled,
311
361
  });
312
- return (jsx("a", { id: `${listboxId}-${index}`, "data-index": index, className: itemClasses, onClick: () => !isDisabled && handleSelect(item), onMouseEnter: () => !isDisabled && setHighlightedIndex(index), role: "option", "aria-selected": isHighlighted, "aria-disabled": isDisabled, children: itemTemplate
362
+ return (jsx("a", { id: `${listboxId}-${index}`, "data-index": index, className: itemClasses, onClick: () => !isDisabled && handleSelect(item), onMouseEnter: () => !isDisabled && setHighlightedIndex(index), role: "option", "aria-selected": isHighlighted && !isDisabled, "aria-disabled": isDisabled, children: itemTemplate
313
363
  ? itemTemplate(item)
314
364
  : getDisplayValue(item) }, index));
315
- }) })) : (jsx("div", { ref: emptyRef, className: emptyItemClasses, children: empty })), footer && jsx("div", { className: dropdownFooterClass, children: footer })] }) })), jsx(StatusRegion, { items: emptyItems, describe: describeEmpty })] }));
365
+ }) })) : (jsx("div", { ref: emptyRef, className: emptyItemClasses, onMouseDown: keepFocus, children: empty })), footer && jsx("div", { className: dropdownFooterClass, children: footer })] }) })), jsx(StatusRegion, { items: emptyItems, describe: describeEmpty })] }));
316
366
  if (!insideField) {
317
367
  return (jsxs(Field, { label: label, labelSize: labelSize, labelProps: fieldLabelProps, horizontal: horizontal, className: fieldClassName, children: [autocompleteElement, messageEl] }));
318
368
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Autocomplete.js","sources":["../../../src/form/Autocomplete.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useState,\n useRef,\n useEffect,\n useCallback,\n useId,\n} from 'react';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { useConfig } from '../helpers/Config';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { useInsideField } from './FormContext';\nimport { Field } from './Field';\nimport { FormFieldProps } from './fieldProps';\nimport { useAutoLabelId } from './useAutoLabelId';\nimport { useControlLoading } from './controlLoading';\nimport { StatusRegion, spokenText } from '../helpers/statusRegion';\n\n/**\n * An item in the Autocomplete dropdown list.\n */\nexport interface AutocompleteItem {\n /** The value used for filtering and selection. */\n value: string;\n /** Display label (optional). */\n label?: string;\n /** Whether the item is disabled and unselectable. */\n disabled?: boolean;\n [key: string]: unknown;\n}\n\n// What the status region announces: the `empty` content, as the one item\n// it's handed while that content is on screen because of the user's typing.\nconst typedNoMatches = [{ id: 'empty' }];\nconst nothingToAnnounce: Array<{ id: string }> = [];\n\n/**\n * Props for the Autocomplete component.\n * @extraProp {string} [className] - Additional CSS classes.\n * @extraProp {React.Ref<HTMLInputElement>} [ref] - Ref forwarded to the input element.\n */\nexport interface AutocompleteProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onInput'>,\n Omit<BulmaClassesProps, 'color'>,\n FormFieldProps {\n /** Field label, associated with the text input via `htmlFor`: through your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose label names the input instead when it points at it. The `Field` points its label there itself when the Autocomplete has no `id` and no inner `Field` sits between them (and the `Field` is not `grouped` or `hasAddons`); a label you wire by hand with `labelProps.htmlFor` points at the input with that `id`. The label naming the input also names the open suggestion list, through `aria-labelledby`, when it has an id: this label always does, and an outer `Field`'s does unless you wired it by hand without an `id` in its `labelProps`. Otherwise the list is named \"Suggestions\". */\n label?: React.ReactNode;\n /** Props for the label element. An explicit `htmlFor` here overrides the automatic association (the input then gets no generated id). While the label names the input, the suggestion list's `aria-labelledby` points at it, through an `id` here when you give one and a generated one otherwise. */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Applied to the inner text input (the labellable control), not the wrapper div. */\n id?: string;\n /** The options data to display (required). */\n data: AutocompleteItem[] | string[];\n /** The current input value (controlled). */\n value?: string;\n /** The selected item (controlled). */\n selected?: AutocompleteItem | string | null;\n /** Placeholder text for the input. */\n placeholder?: string;\n /** Object property to use as the display field. */\n field?: string;\n /**\n * Whether to show a clear button while the input holds a value.\n * It hides while the input is disabled, and gives way to a loading\n * spinner at the same right edge: the one `loading` draws, or that of a\n * `Control` with `isLoading` around the Autocomplete.\n */\n clearable?: boolean;\n /** Open dropdown when input is focused. */\n openOnFocus?: boolean;\n /** Keep first option highlighted. */\n keepFirst?: boolean;\n /** Keep dropdown open after selection. */\n keepOpen?: boolean;\n /** Select highlighted item on click outside. */\n selectOnClickOutside?: boolean;\n /** Maximum dropdown height in pixels. */\n maxHeight?: number;\n /** Render as dropdown style. */\n dropdown?: boolean;\n /**\n * Show a loading spinner in the input.\n * Under `prefers-reduced-motion: reduce` the spinner stops and stays\n * drawn (with bestax's CSS loaded).\n */\n loading?: boolean;\n /** Whether the input is disabled. */\n disabled?: boolean;\n /** Enables infinite scroll detection in the dropdown. */\n checkInfiniteScroll?: boolean;\n /** Distance in pixels from the bottom to trigger `onInfiniteScroll`. */\n infiniteScrollDistance?: number;\n /** Input color variant. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Size variant. */\n size?: 'small' | 'medium' | 'large';\n /** Form field name. Forwarded to the inner `<input>`. */\n name?: string;\n /** Optional id of the form the input belongs to. */\n form?: string;\n /** Marks the field as required for native HTML form validation. */\n required?: boolean;\n /** Callback when input value changes. */\n onInput?: (value: string) => void;\n /** Callback when item is selected. */\n onSelect?: (item: AutocompleteItem | string | null) => void;\n /** Callback when dropdown active state changes. */\n onActiveChange?: (active: boolean) => void;\n /** Callback when scrolled to bottom (infinite scroll). */\n onInfiniteScroll?: () => void;\n /** Custom render for items. */\n itemTemplate?: (item: AutocompleteItem | string) => React.ReactNode;\n /** Custom header at the top of the dropdown. It sits above the list of options rather than in it, so assistive technology doesn't count it as one. */\n header?: React.ReactNode;\n /** Custom footer at the bottom of the dropdown. It sits below the list of options rather than in it, so assistive technology doesn't count it as one. */\n footer?: React.ReactNode;\n /**\n * A message the dropdown shows in place of the options when nothing\n * matches. Keep it to text: `Tab` closes the list, so a keyboard user\n * can't reach a link or button in it. It sits beside the list of options\n * rather than in it, so the input's `aria-expanded` stays false while it\n * shows. When the user's typing leaves nothing that matches, a polite\n * status region announces its text: once each time the matches run out.\n * The text is read when they first run out, and isn't read again as it\n * changes while they stay out, so a message that names the query is heard\n * for that first query only. Keep it static.\n * Opening the list without typing, or emptying the field, announces\n * nothing. While `loading`, or a `Control` with `isLoading` around the\n * Autocomplete, is on, it waits, and it's announced once loading ends\n * with nothing matching. Without `empty`, the dropdown closes when nothing\n * matches and nothing is announced.\n */\n empty?: React.ReactNode;\n}\n\n/**\n * The `Autocomplete` component provides an input field with dropdown suggestions that filter based on user input.\n *\n * @function\n * @param {AutocompleteProps} props - Props for the Autocomplete component.\n * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the input element.\n * @returns {JSX.Element} The rendered autocomplete component.\n *\n * @example\n * // Basic usage with string array\n * <Autocomplete\n * data={['Apple', 'Banana', 'Cherry']}\n * placeholder=\"Search fruit...\"\n * onSelect={(item) => console.log(item)}\n * />\n *\n * @example\n * // With object data\n * <Autocomplete\n * data={[{ value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }]}\n * field=\"label\"\n * onSelect={(item) => console.log(item)}\n * />\n */\nexport const Autocomplete = forwardRef<HTMLInputElement, AutocompleteProps>(\n (\n {\n data = [],\n value: controlledValue,\n placeholder,\n field = 'label',\n clearable = false,\n openOnFocus = false,\n keepFirst = false,\n keepOpen = false,\n selectOnClickOutside = false,\n maxHeight = 200,\n loading = false,\n disabled = false,\n checkInfiniteScroll = false,\n infiniteScrollDistance = 50,\n color,\n size,\n onInput,\n onSelect,\n onActiveChange,\n onInfiniteScroll,\n itemTemplate,\n header,\n footer,\n empty,\n name,\n form,\n required,\n id,\n // Field props\n label,\n labelSize,\n labelProps,\n horizontal,\n message,\n messageColor,\n fieldClassName,\n className,\n ...props\n },\n ref\n ) => {\n const insideField = useInsideField();\n // The suggestion list points `aria-labelledby` at the label that names\n // the input, so it needs that label's id.\n const {\n controlId,\n fieldLabelProps,\n labelId: listLabelId,\n } = useAutoLabelId({\n label,\n id,\n labelProps,\n rendersLabel: !insideField,\n needsLabelId: true,\n });\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const { classPrefix } = useConfig();\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const [internalValue, setInternalValue] = useState('');\n const [isActive, setIsActive] = useState(false);\n // Whether the user has typed since the list opened, since only typing\n // gets the `empty` content announced. Closing the list resets it (during\n // render, React's pattern for adjusting state when other state changes),\n // so opening the list again without typing stays quiet.\n const [typed, setTyped] = useState(false);\n if (typed && !isActive) setTyped(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const listboxId = `${useId()}-listbox`;\n\n // Use controlled or internal value\n const inputValue =\n controlledValue !== undefined ? controlledValue : internalValue;\n\n // Get display value from item\n const getDisplayValue = (item: AutocompleteItem | string): string => {\n if (typeof item === 'string') return item;\n const fieldValue = item[field];\n if (typeof fieldValue === 'string') return fieldValue;\n return item.value || '';\n };\n\n // Filter data based on input\n const filteredData = data.filter(item => {\n const displayValue = getDisplayValue(item);\n return displayValue.toLowerCase().includes(inputValue.toLowerCase());\n });\n\n // The dropdown shows the options or, when nothing matches, the `empty`\n // content. The listbox holds only options, so it's on screen only while\n // there are some.\n const menuOpen = isActive && (filteredData.length > 0 || !!empty);\n const listOpen = isActive && filteredData.length > 0;\n\n // Handle input change\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n if (controlledValue === undefined) {\n setInternalValue(newValue);\n }\n onInput?.(newValue);\n setTyped(true);\n if (!isActive && newValue) {\n setIsActive(true);\n }\n },\n [controlledValue, isActive, onInput]\n );\n\n // Handle item selection\n const handleSelect = useCallback(\n (item: AutocompleteItem | string) => {\n if (typeof item !== 'string' && item.disabled) return;\n\n const displayValue = getDisplayValue(item);\n if (controlledValue === undefined) {\n setInternalValue(displayValue);\n }\n onInput?.(displayValue);\n onSelect?.(item);\n\n if (!keepOpen) {\n setIsActive(false);\n }\n setHighlightedIndex(-1);\n },\n [controlledValue, field, keepOpen, onInput, onSelect]\n );\n\n // Handle clear\n const handleClear = useCallback(() => {\n if (controlledValue === undefined) {\n setInternalValue('');\n }\n onInput?.('');\n onSelect?.(null);\n inputRef.current?.focus();\n }, [controlledValue, onInput, onSelect]);\n\n // Handle focus\n const handleFocus = useCallback(() => {\n if (openOnFocus && !disabled) {\n setIsActive(true);\n }\n }, [openOnFocus, disabled]);\n\n // Handle blur (click outside)\n useEffect(() => {\n if (!isActive) return undefined;\n\n const handleClickOutside = (e: MouseEvent) => {\n if (!containerRef.current) return;\n\n // Use composedPath() to correctly detect clicks inside Shadow DOM\n const path = e.composedPath();\n const isInside = path.includes(containerRef.current);\n\n if (!isInside) {\n if (selectOnClickOutside && highlightedIndex >= 0) {\n handleSelect(filteredData[highlightedIndex]);\n }\n setIsActive(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }, [\n isActive,\n selectOnClickOutside,\n highlightedIndex,\n filteredData,\n handleSelect,\n ]);\n\n // Notify active state change\n useEffect(() => {\n onActiveChange?.(isActive);\n }, [isActive, onActiveChange]);\n\n // Keep first highlighted\n useEffect(() => {\n if (keepFirst && isActive && filteredData.length > 0) {\n setHighlightedIndex(0);\n }\n }, [keepFirst, isActive, filteredData.length, inputValue]);\n\n // Handle keyboard navigation\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled) return;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!isActive) {\n setIsActive(true);\n } else {\n setHighlightedIndex(prev =>\n prev < filteredData.length - 1 ? prev + 1 : prev\n );\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n setHighlightedIndex(prev => (prev > 0 ? prev - 1 : prev));\n break;\n case 'Enter':\n e.preventDefault();\n if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {\n handleSelect(filteredData[highlightedIndex]);\n }\n break;\n case 'Escape':\n e.preventDefault();\n setIsActive(false);\n setHighlightedIndex(-1);\n break;\n case 'Tab':\n if (highlightedIndex >= 0 && filteredData[highlightedIndex]) {\n handleSelect(filteredData[highlightedIndex]);\n }\n setIsActive(false);\n break;\n }\n },\n [disabled, isActive, highlightedIndex, filteredData, handleSelect]\n );\n\n // Handle dropdown scroll for infinite scroll\n const handleDropdownScroll = useCallback(() => {\n if (!checkInfiniteScroll || !dropdownRef.current) return;\n\n const { scrollTop, scrollHeight, clientHeight } = dropdownRef.current;\n if (scrollHeight - scrollTop - clientHeight <= infiniteScrollDistance) {\n onInfiniteScroll?.();\n }\n }, [checkInfiniteScroll, infiniteScrollDistance, onInfiniteScroll]);\n\n // Scroll highlighted item into view\n useEffect(() => {\n if (highlightedIndex >= 0 && dropdownRef.current) {\n const highlightedEl = dropdownRef.current.querySelector(\n `[data-index=\"${highlightedIndex}\"]`\n );\n if (\n highlightedEl &&\n typeof highlightedEl.scrollIntoView === 'function'\n ) {\n highlightedEl.scrollIntoView({ block: 'nearest' });\n }\n }\n }, [highlightedIndex]);\n\n // Combined ref\n const combinedRef = useCallback(\n (node: HTMLInputElement | null) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n }\n },\n [ref]\n );\n\n // Generate classes\n const autocompleteClasses = usePrefixedClassNames('autocomplete', {\n 'is-active': isActive,\n [`is-${size}`]: !!size,\n });\n\n const inputClasses = usePrefixedClassNames('input', {\n [`is-${color}`]: !!color,\n [`is-${size}`]: !!size,\n 'is-loading': loading,\n });\n\n const controlClasses = usePrefixedClassNames(\n 'control',\n 'is-expanded',\n 'has-icons-right'\n );\n\n const dropdownMenuClasses = usePrefixedClassNames('dropdown-menu', {\n 'is-active': menuOpen,\n });\n\n const dropdownContentClass = usePrefixedClassNames('dropdown-content');\n const dropdownHeaderClass = usePrefixedClassNames('dropdown-header');\n const dropdownFooterClass = usePrefixedClassNames('dropdown-footer');\n const emptyItemClasses = usePrefixedClassNames(\n 'dropdown-item',\n 'has-text-grey'\n );\n\n const iconRightClickableClass = usePrefixedClassNames(\n 'icon',\n 'is-right',\n 'is-clickable'\n );\n const iconRightClass = usePrefixedClassNames('icon', 'is-right');\n const loaderClass = usePrefixedClassNames('loader', 'is-loading');\n\n const combinedClasses = classNames(\n autocompleteClasses,\n bulmaHelperClasses,\n className\n );\n\n const helpClass = usePrefixedClassNames('help', {\n [`is-${messageColor}`]: !!messageColor,\n });\n const messageEl = message ? <p className={helpClass}>{message}</p> : null;\n\n // The clear button gives way to a spinner at its spot: the `loading` one,\n // or that of a loading Control this sits in.\n const controlLoading = useControlLoading();\n const showClear =\n clearable && !!inputValue && !disabled && !loading && !controlLoading;\n\n // The combobox controls its listbox and points at the highlighted option.\n // The listbox takes its name from the label that names the combobox, the\n // one this renders or a surrounding Field's, so the two say the same\n // thing. When no label names the combobox, or the one that does has no\n // id to point at, the list keeps a fallback name. While the dropdown\n // shows only the `empty` content there's no listbox, so the combobox is\n // collapsed and points at nothing.\n const activeOptionId =\n listOpen &&\n highlightedIndex >= 0 &&\n highlightedIndex < filteredData.length\n ? `${listboxId}-${highlightedIndex}`\n : undefined;\n\n // A polite status region, in the page from the start so it's there\n // before anything is written into it, announces the `empty` content\n // when the user's typing leaves nothing that matches what's in the\n // field. It follows what's on screen, so results that come in after the\n // typing count too. It's said once each time that happens, not again on\n // each keystroke while nothing matches. An empty field isn't a search,\n // so it stays quiet then, even with no data. While `loading`, or a\n // loading Control around it, says results are on their way, it waits,\n // and it's said once loading ends with nothing matching.\n const emptyItems =\n typed &&\n menuOpen &&\n !listOpen &&\n !!inputValue &&\n !loading &&\n !controlLoading\n ? typedNoMatches\n : nothingToAnnounce;\n // The region reads the text on screen, whatever `empty` renders.\n const emptyRef = useRef<HTMLDivElement>(null);\n const describeEmpty = useCallback(() => {\n const node = emptyRef.current;\n /* istanbul ignore if: it's only announced while it's on screen */\n if (!node) return null;\n return spokenText(node);\n }, []);\n\n const autocompleteElement = (\n <div ref={containerRef} className={combinedClasses} {...rest}>\n <div className={controlClasses}>\n <input\n ref={combinedRef}\n type=\"text\"\n className={inputClasses}\n id={controlId}\n value={inputValue}\n placeholder={placeholder}\n disabled={disabled}\n name={name}\n form={form}\n required={required}\n onChange={handleInputChange}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n role=\"combobox\"\n aria-expanded={listOpen}\n aria-controls={listOpen ? listboxId : undefined}\n aria-activedescendant={activeOptionId}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n />\n {showClear && (\n <button\n type=\"button\"\n className={iconRightClickableClass}\n onClick={handleClear}\n aria-label=\"Clear\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n width=\"16\"\n height=\"16\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n {loading && (\n <span className={iconRightClass}>\n <span className={loaderClass} />\n </span>\n )}\n </div>\n\n {menuOpen && (\n <div className={dropdownMenuClasses}>\n <div\n ref={dropdownRef}\n className={dropdownContentClass}\n style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto' }}\n onScroll={handleDropdownScroll}\n >\n {header && <div className={dropdownHeaderClass}>{header}</div>}\n\n {listOpen ? (\n <div\n id={listboxId}\n role=\"listbox\"\n aria-labelledby={listLabelId}\n aria-label={listLabelId ? undefined : 'Suggestions'}\n >\n {filteredData.map((item, index) => {\n const isDisabled =\n typeof item !== 'string' && item.disabled;\n const isHighlighted = index === highlightedIndex;\n\n const itemClasses = prefixedClassNames(\n classPrefix,\n 'dropdown-item',\n {\n 'is-active': isHighlighted,\n 'is-disabled': isDisabled,\n }\n );\n\n return (\n <a\n key={index}\n id={`${listboxId}-${index}`}\n data-index={index}\n className={itemClasses}\n onClick={() => !isDisabled && handleSelect(item)}\n onMouseEnter={() =>\n !isDisabled && setHighlightedIndex(index)\n }\n role=\"option\"\n aria-selected={isHighlighted}\n aria-disabled={isDisabled}\n >\n {itemTemplate\n ? itemTemplate(item)\n : getDisplayValue(item)}\n </a>\n );\n })}\n </div>\n ) : (\n <div ref={emptyRef} className={emptyItemClasses}>\n {empty}\n </div>\n )}\n\n {footer && <div className={dropdownFooterClass}>{footer}</div>}\n </div>\n </div>\n )}\n\n <StatusRegion items={emptyItems} describe={describeEmpty} />\n </div>\n );\n\n if (!insideField) {\n return (\n <Field\n label={label}\n labelSize={labelSize}\n labelProps={fieldLabelProps}\n horizontal={horizontal}\n className={fieldClassName}\n >\n {autocompleteElement}\n {messageEl}\n </Field>\n );\n }\n\n return (\n <>\n {autocompleteElement}\n {messageEl}\n </>\n );\n }\n);\n\nAutocomplete.displayName = 'Autocomplete';\n\nexport default Autocomplete;\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"Autocomplete.js","sources":["../../../src/form/Autocomplete.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useState,\n useRef,\n useEffect,\n useCallback,\n useId,\n} from 'react';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { useConfig } from '../helpers/Config';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { useInsideField } from './FormContext';\nimport { Field } from './Field';\nimport { FormFieldProps } from './fieldProps';\nimport { useAutoLabelId } from './useAutoLabelId';\nimport { useControlLoading } from './controlLoading';\nimport { StatusRegion, spokenText } from '../helpers/statusRegion';\n\n/**\n * An item in the Autocomplete dropdown list.\n */\nexport interface AutocompleteItem {\n /** The value used for filtering and selection. */\n value: string;\n /** Display label (optional). */\n label?: string;\n /** Whether the item is disabled and unselectable. */\n disabled?: boolean;\n [key: string]: unknown;\n}\n\n// What the status region announces: the `empty` content, as the one item\n// it's handed while that content is on screen because of the user's typing.\nconst typedNoMatches = [{ id: 'empty' }];\nconst nothingToAnnounce: Array<{ id: string }> = [];\n\n// A press on an option would take focus from the field, since an option\n// can't hold it, and nothing would put it back. Cancelling the press keeps\n// it there, as the ARIA Authoring Practices' combobox does, and the click\n// still picks the option.\nconst keepFocus = (e: React.MouseEvent) => e.preventDefault();\n\n// An IME that's composing owns every key: Enter confirms what it composed,\n// and the arrows move through its candidates. Safari can say so with\n// `keyCode` 229 rather than `isComposing`.\nconst isComposing = (e: React.KeyboardEvent): boolean =>\n e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229;\n\n// Whether an option can be picked. The arrows still reach a disabled one, so\n// a screen reader user finds it.\nconst isEnabled = (item: AutocompleteItem | string): boolean =>\n typeof item === 'string' || !item.disabled;\n\n/**\n * Props for the Autocomplete component.\n * @extraProp {string} [className] - Additional CSS classes.\n * @extraProp {React.Ref<HTMLInputElement>} [ref] - Ref forwarded to the input element.\n */\nexport interface AutocompleteProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onInput'>,\n Omit<BulmaClassesProps, 'color'>,\n FormFieldProps {\n /** Field label, associated with the text input via `htmlFor`: through your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose label names the input instead when it points at it. The `Field` points its label there itself when the Autocomplete has no `id` and no inner `Field` sits between them (and the `Field` is not `grouped` or `hasAddons`); a label you wire by hand with `labelProps.htmlFor` points at the input with that `id`. The label naming the input also names the open suggestion list, through `aria-labelledby`, when it has an id: this label always does, and an outer `Field`'s does unless you wired it by hand without an `id` in its `labelProps`. Otherwise the list is named \"Suggestions\". */\n label?: React.ReactNode;\n /** Props for the label element. An explicit `htmlFor` here overrides the automatic association (the input then gets no generated id). While the label names the input, the suggestion list's `aria-labelledby` points at it, through an `id` here when you give one and a generated one otherwise. */\n labelProps?: React.LabelHTMLAttributes<HTMLLabelElement> & {\n [key: string]: unknown;\n };\n /** Applied to the inner text input (the labellable control), not the wrapper div. */\n id?: string;\n /** The options data to display (required). */\n data: AutocompleteItem[] | string[];\n /** The current input value (controlled). */\n value?: string;\n /**\n * Does nothing: Autocomplete doesn't read it.\n *\n * @deprecated Nothing reads it, and `onSelect` is what reports a pick. It\n * will be removed in the next major version.\n */\n selected?: AutocompleteItem | string | null;\n /** Placeholder text for the input. */\n placeholder?: string;\n /** Object property to use as the display field. */\n field?: string;\n /**\n * Whether to show a clear button while the input holds a value.\n * It hides while the input is disabled, and gives way to a loading\n * spinner at the same right edge: the one `loading` draws, or that of a\n * `Control` with `isLoading` around the Autocomplete.\n */\n clearable?: boolean;\n /** Open dropdown when input is focused. */\n openOnFocus?: boolean;\n /**\n * Keep the first option highlighted whenever the list opens, Up Arrow and\n * Alt+Down Arrow included, and whenever the text in the field changes.\n * While the list is open on a highlighted option that isn't disabled, Enter\n * picks it rather than submitting a form around the field.\n */\n keepFirst?: boolean;\n /** Keep dropdown open after selection. */\n keepOpen?: boolean;\n /** Select highlighted item on click outside. */\n selectOnClickOutside?: boolean;\n /** Maximum dropdown height in pixels. */\n maxHeight?: number;\n /**\n * Does nothing: Autocomplete doesn't read it, and always shows its\n * suggestions in a dropdown.\n *\n * @deprecated It will be removed in the next major version, with nothing\n * in its place.\n */\n dropdown?: boolean;\n /**\n * Show a loading spinner in the input.\n * Under `prefers-reduced-motion: reduce` the spinner stops and stays\n * drawn (with bestax's CSS loaded).\n */\n loading?: boolean;\n /** Whether the input is disabled. */\n disabled?: boolean;\n /** Enables infinite scroll detection in the dropdown. */\n checkInfiniteScroll?: boolean;\n /** Distance in pixels from the bottom to trigger `onInfiniteScroll`. */\n infiniteScrollDistance?: number;\n /** Input color variant. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Size variant. */\n size?: 'small' | 'medium' | 'large';\n /** Form field name. Forwarded to the inner `<input>`. */\n name?: string;\n /** Optional id of the form the input belongs to. */\n form?: string;\n /** Marks the field as required for native HTML form validation. */\n required?: boolean;\n /** Callback when input value changes. */\n onInput?: (value: string) => void;\n /** Callback when item is selected. */\n onSelect?: (item: AutocompleteItem | string | null) => void;\n /** Callback when dropdown active state changes. */\n onActiveChange?: (active: boolean) => void;\n /** Callback when scrolled to bottom (infinite scroll). */\n onInfiniteScroll?: () => void;\n /** Custom render for items. */\n itemTemplate?: (item: AutocompleteItem | string) => React.ReactNode;\n /** Custom header at the top of the dropdown. It sits above the list of options rather than in it, so assistive technology doesn't count it as one. */\n header?: React.ReactNode;\n /** Custom footer at the bottom of the dropdown. It sits below the list of options rather than in it, so assistive technology doesn't count it as one. */\n footer?: React.ReactNode;\n /**\n * A message the dropdown shows in place of the options when nothing\n * matches. Keep it to text: `Tab` closes the list, so a keyboard user\n * can't reach a link or button in it. It sits beside the list of options\n * rather than in it, so the input's `aria-expanded` stays false while it\n * shows. When the user's typing leaves nothing that matches, a polite\n * status region announces its text: once each time the matches run out.\n * The text is read when they first run out, and isn't read again as it\n * changes while they stay out, so a message that names the query is heard\n * for that first query only. Keep it static.\n * Opening the list without typing, or emptying the field, announces\n * nothing. While `loading`, or a `Control` with `isLoading` around the\n * Autocomplete, is on, it waits, and it's announced once loading ends\n * with nothing matching. Without `empty`, the dropdown closes when nothing\n * matches and nothing is announced.\n */\n empty?: React.ReactNode;\n}\n\n/**\n * The `Autocomplete` component provides an input field with dropdown suggestions that filter based on user input.\n *\n * @function\n * @param {AutocompleteProps} props - Props for the Autocomplete component.\n * @param {React.Ref<HTMLInputElement>} ref - Forwarded ref to the input element.\n * @returns {JSX.Element} The rendered autocomplete component.\n *\n * @example\n * // Basic usage with string array\n * <Autocomplete\n * data={['Apple', 'Banana', 'Cherry']}\n * placeholder=\"Search fruit...\"\n * onSelect={(item) => console.log(item)}\n * />\n *\n * @example\n * // With object data\n * <Autocomplete\n * data={[{ value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }]}\n * field=\"label\"\n * onSelect={(item) => console.log(item)}\n * />\n */\nexport const Autocomplete = forwardRef<HTMLInputElement, AutocompleteProps>(\n (\n {\n data = [],\n value: controlledValue,\n placeholder,\n field = 'label',\n clearable = false,\n openOnFocus = false,\n keepFirst = false,\n keepOpen = false,\n selectOnClickOutside = false,\n maxHeight = 200,\n loading = false,\n disabled = false,\n checkInfiniteScroll = false,\n infiniteScrollDistance = 50,\n color,\n size,\n onInput,\n onSelect,\n onActiveChange,\n onInfiniteScroll,\n itemTemplate,\n header,\n footer,\n empty,\n name,\n form,\n required,\n id,\n // Deprecated no-ops, taken here so they stay off the wrapper.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- deprecated no-op\n selected,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars -- deprecated no-op\n dropdown,\n // Field props\n label,\n labelSize,\n labelProps,\n horizontal,\n message,\n messageColor,\n fieldClassName,\n className,\n ...props\n },\n ref\n ) => {\n const insideField = useInsideField();\n // The suggestion list points `aria-labelledby` at the label that names\n // the input, so it needs that label's id.\n const {\n controlId,\n fieldLabelProps,\n labelId: listLabelId,\n } = useAutoLabelId({\n label,\n id,\n labelProps,\n rendersLabel: !insideField,\n needsLabelId: true,\n });\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const { classPrefix } = useConfig();\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const [internalValue, setInternalValue] = useState('');\n const [isActive, setIsActive] = useState(false);\n // Whether the user has typed since the list opened, since only typing\n // gets the `empty` content announced. Closing the list resets it (during\n // render, React's pattern for adjusting state when other state changes),\n // so opening the list again without typing stays quiet.\n const [typed, setTyped] = useState(false);\n if (typed && !isActive) setTyped(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const listboxId = `${useId()}-listbox`;\n\n // Use controlled or internal value\n const inputValue =\n controlledValue !== undefined ? controlledValue : internalValue;\n\n // Get display value from item\n const getDisplayValue = (item: AutocompleteItem | string): string => {\n if (typeof item === 'string') return item;\n const fieldValue = item[field];\n if (typeof fieldValue === 'string') return fieldValue;\n return item.value || '';\n };\n\n // Filter data based on input\n const filteredData = data.filter(item => {\n const displayValue = getDisplayValue(item);\n return displayValue.toLowerCase().includes(inputValue.toLowerCase());\n });\n\n // The dropdown shows the options or, when nothing matches, the `empty`\n // content. The listbox holds only options, so it's on screen only while\n // there are some.\n const menuOpen = isActive && (filteredData.length > 0 || !!empty);\n const listOpen = isActive && filteredData.length > 0;\n\n // Handle input change\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n if (controlledValue === undefined) {\n setInternalValue(newValue);\n }\n onInput?.(newValue);\n setTyped(true);\n if (!isActive && newValue) {\n setIsActive(true);\n }\n },\n [controlledValue, isActive, onInput]\n );\n\n // Handle item selection\n const handleSelect = useCallback(\n (item: AutocompleteItem | string) => {\n if (typeof item !== 'string' && item.disabled) return;\n\n const displayValue = getDisplayValue(item);\n if (controlledValue === undefined) {\n setInternalValue(displayValue);\n }\n onInput?.(displayValue);\n onSelect?.(item);\n\n if (!keepOpen) {\n setIsActive(false);\n }\n setHighlightedIndex(-1);\n },\n [controlledValue, field, keepOpen, onInput, onSelect]\n );\n\n // Handle clear\n const handleClear = useCallback(() => {\n if (controlledValue === undefined) {\n setInternalValue('');\n }\n onInput?.('');\n onSelect?.(null);\n inputRef.current?.focus();\n }, [controlledValue, onInput, onSelect]);\n\n // Handle focus\n const handleFocus = useCallback(() => {\n if (openOnFocus && !disabled) {\n setIsActive(true);\n }\n }, [openOnFocus, disabled]);\n\n // Handle blur (click outside)\n useEffect(() => {\n if (!isActive) return undefined;\n\n const handleClickOutside = (e: MouseEvent) => {\n if (!containerRef.current) return;\n\n // Use composedPath() to correctly detect clicks inside Shadow DOM\n const path = e.composedPath();\n const isInside = path.includes(containerRef.current);\n\n if (!isInside) {\n if (selectOnClickOutside && highlightedIndex >= 0) {\n handleSelect(filteredData[highlightedIndex]);\n }\n setIsActive(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () =>\n document.removeEventListener('mousedown', handleClickOutside);\n }, [\n isActive,\n selectOnClickOutside,\n highlightedIndex,\n filteredData,\n handleSelect,\n ]);\n\n // Notify active state change\n useEffect(() => {\n onActiveChange?.(isActive);\n }, [isActive, onActiveChange]);\n\n // Keep first highlighted\n useEffect(() => {\n if (keepFirst && isActive && filteredData.length > 0) {\n setHighlightedIndex(0);\n }\n }, [keepFirst, isActive, filteredData.length, inputValue]);\n\n // Handle keyboard navigation\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled || isComposing(e)) return;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!isActive) {\n // A closed list opens on its first enabled option, as the ARIA\n // Authoring Practices' combobox does. Alt+Down Arrow opens it\n // without a highlight.\n setIsActive(true);\n setHighlightedIndex(\n e.altKey ? -1 : filteredData.map(isEnabled).indexOf(true)\n );\n } else {\n setHighlightedIndex(prev =>\n prev < filteredData.length - 1 ? prev + 1 : prev\n );\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (!isActive) {\n // And Up Arrow opens it on its last enabled option.\n setIsActive(true);\n setHighlightedIndex(\n filteredData.map(isEnabled).lastIndexOf(true)\n );\n } else {\n setHighlightedIndex(prev => (prev > 0 ? prev - 1 : prev));\n }\n break;\n case 'Enter':\n // With the list open on a highlighted option it can pick, Enter\n // is that option's. Otherwise it closes the list and goes on, so\n // a form around the field submits, as it would from any text\n // field.\n if (\n isActive &&\n highlightedIndex >= 0 &&\n filteredData[highlightedIndex] &&\n isEnabled(filteredData[highlightedIndex])\n ) {\n e.preventDefault();\n handleSelect(filteredData[highlightedIndex]);\n } else {\n setIsActive(false);\n }\n break;\n case 'Escape':\n // Only closing the dropdown claims the key. With it closed, the\n // key goes on to a Modal around the field.\n if (menuOpen) e.preventDefault();\n setIsActive(false);\n setHighlightedIndex(-1);\n break;\n case 'Tab':\n if (\n isActive &&\n highlightedIndex >= 0 &&\n filteredData[highlightedIndex]\n ) {\n handleSelect(filteredData[highlightedIndex]);\n }\n setIsActive(false);\n break;\n }\n },\n [\n disabled,\n isActive,\n menuOpen,\n highlightedIndex,\n filteredData,\n handleSelect,\n ]\n );\n\n // Handle dropdown scroll for infinite scroll\n const handleDropdownScroll = useCallback(() => {\n if (!checkInfiniteScroll || !dropdownRef.current) return;\n\n const { scrollTop, scrollHeight, clientHeight } = dropdownRef.current;\n if (scrollHeight - scrollTop - clientHeight <= infiniteScrollDistance) {\n onInfiniteScroll?.();\n }\n }, [checkInfiniteScroll, infiniteScrollDistance, onInfiniteScroll]);\n\n // Scroll highlighted item into view\n useEffect(() => {\n if (highlightedIndex >= 0 && dropdownRef.current) {\n const highlightedEl = dropdownRef.current.querySelector(\n `[data-index=\"${highlightedIndex}\"]`\n );\n if (\n highlightedEl &&\n typeof highlightedEl.scrollIntoView === 'function'\n ) {\n highlightedEl.scrollIntoView({ block: 'nearest' });\n }\n }\n }, [highlightedIndex]);\n\n // Combined ref\n const combinedRef = useCallback(\n (node: HTMLInputElement | null) => {\n (inputRef as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current =\n node;\n }\n },\n [ref]\n );\n\n // Generate classes\n const autocompleteClasses = usePrefixedClassNames('autocomplete', {\n 'is-active': isActive,\n [`is-${size}`]: !!size,\n });\n\n const inputClasses = usePrefixedClassNames('input', {\n [`is-${color}`]: !!color,\n [`is-${size}`]: !!size,\n 'is-loading': loading,\n });\n\n const controlClasses = usePrefixedClassNames(\n 'control',\n 'is-expanded',\n 'has-icons-right'\n );\n\n const dropdownMenuClasses = usePrefixedClassNames('dropdown-menu', {\n 'is-active': menuOpen,\n });\n\n const dropdownContentClass = usePrefixedClassNames('dropdown-content');\n const dropdownHeaderClass = usePrefixedClassNames('dropdown-header');\n const dropdownFooterClass = usePrefixedClassNames('dropdown-footer');\n const emptyItemClasses = usePrefixedClassNames(\n 'dropdown-item',\n 'has-text-grey'\n );\n\n const iconRightClickableClass = usePrefixedClassNames(\n 'icon',\n 'is-right',\n 'is-clickable'\n );\n const iconRightClass = usePrefixedClassNames('icon', 'is-right');\n const loaderClass = usePrefixedClassNames('loader', 'is-loading');\n\n const combinedClasses = classNames(\n autocompleteClasses,\n bulmaHelperClasses,\n className\n );\n\n const helpClass = usePrefixedClassNames('help', {\n [`is-${messageColor}`]: !!messageColor,\n });\n const messageEl = message ? <p className={helpClass}>{message}</p> : null;\n\n // The clear button gives way to a spinner at its spot: the `loading` one,\n // or that of a loading Control this sits in.\n const controlLoading = useControlLoading();\n const showClear =\n clearable && !!inputValue && !disabled && !loading && !controlLoading;\n\n // The combobox controls its listbox and points at the highlighted option.\n // The listbox takes its name from the label that names the combobox, the\n // one this renders or a surrounding Field's, so the two say the same\n // thing. When no label names the combobox, or the one that does has no\n // id to point at, the list keeps a fallback name. While the dropdown\n // shows only the `empty` content there's no listbox, so the combobox is\n // collapsed and points at nothing.\n const activeOptionId =\n listOpen &&\n highlightedIndex >= 0 &&\n highlightedIndex < filteredData.length\n ? `${listboxId}-${highlightedIndex}`\n : undefined;\n\n // A polite status region, in the page from the start so it's there\n // before anything is written into it, announces the `empty` content\n // when the user's typing leaves nothing that matches what's in the\n // field. It follows what's on screen, so results that come in after the\n // typing count too. It's said once each time that happens, not again on\n // each keystroke while nothing matches. An empty field isn't a search,\n // so it stays quiet then, even with no data. While `loading`, or a\n // loading Control around it, says results are on their way, it waits,\n // and it's said once loading ends with nothing matching.\n const emptyItems =\n typed &&\n menuOpen &&\n !listOpen &&\n !!inputValue &&\n !loading &&\n !controlLoading\n ? typedNoMatches\n : nothingToAnnounce;\n // The region reads the text on screen, whatever `empty` renders.\n const emptyRef = useRef<HTMLDivElement>(null);\n const describeEmpty = useCallback(() => {\n const node = emptyRef.current;\n /* istanbul ignore if: it's only announced while it's on screen */\n if (!node) return null;\n return spokenText(node);\n }, []);\n\n const autocompleteElement = (\n <div ref={containerRef} className={combinedClasses} {...rest}>\n <div className={controlClasses}>\n <input\n ref={combinedRef}\n type=\"text\"\n className={inputClasses}\n id={controlId}\n value={inputValue}\n placeholder={placeholder}\n disabled={disabled}\n name={name}\n form={form}\n required={required}\n onChange={handleInputChange}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n role=\"combobox\"\n aria-expanded={listOpen}\n aria-controls={listOpen ? listboxId : undefined}\n aria-activedescendant={activeOptionId}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n autoComplete=\"off\"\n />\n {showClear && (\n <button\n type=\"button\"\n className={iconRightClickableClass}\n onClick={handleClear}\n aria-label=\"Clear\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n width=\"16\"\n height=\"16\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n )}\n {loading && (\n <span className={iconRightClass}>\n <span className={loaderClass} />\n </span>\n )}\n </div>\n\n {menuOpen && (\n <div className={dropdownMenuClasses}>\n <div\n ref={dropdownRef}\n className={dropdownContentClass}\n style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto' }}\n onScroll={handleDropdownScroll}\n >\n {header && <div className={dropdownHeaderClass}>{header}</div>}\n\n {listOpen ? (\n <div\n id={listboxId}\n role=\"listbox\"\n aria-labelledby={listLabelId}\n aria-label={listLabelId ? undefined : 'Suggestions'}\n onMouseDown={keepFocus}\n >\n {filteredData.map((item, index) => {\n const isDisabled =\n typeof item !== 'string' && item.disabled;\n const isHighlighted = index === highlightedIndex;\n\n const itemClasses = prefixedClassNames(\n classPrefix,\n 'dropdown-item',\n {\n 'is-active': isHighlighted,\n 'is-disabled': isDisabled,\n }\n );\n\n return (\n <a\n key={index}\n id={`${listboxId}-${index}`}\n data-index={index}\n className={itemClasses}\n onClick={() => !isDisabled && handleSelect(item)}\n onMouseEnter={() =>\n !isDisabled && setHighlightedIndex(index)\n }\n role=\"option\"\n aria-selected={isHighlighted && !isDisabled}\n aria-disabled={isDisabled}\n >\n {itemTemplate\n ? itemTemplate(item)\n : getDisplayValue(item)}\n </a>\n );\n })}\n </div>\n ) : (\n <div\n ref={emptyRef}\n className={emptyItemClasses}\n onMouseDown={keepFocus}\n >\n {empty}\n </div>\n )}\n\n {footer && <div className={dropdownFooterClass}>{footer}</div>}\n </div>\n </div>\n )}\n\n <StatusRegion items={emptyItems} describe={describeEmpty} />\n </div>\n );\n\n if (!insideField) {\n return (\n <Field\n label={label}\n labelSize={labelSize}\n labelProps={fieldLabelProps}\n horizontal={horizontal}\n className={fieldClassName}\n >\n {autocompleteElement}\n {messageEl}\n </Field>\n );\n }\n\n return (\n <>\n {autocompleteElement}\n {messageEl}\n </>\n );\n }\n);\n\nAutocomplete.displayName = 'Autocomplete';\n\nexport default Autocomplete;\n"],"names":["_jsx","_jsxs","_Fragment"],"mappings":"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"}
@@ -266,6 +266,10 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
266
266
  }
267
267
  break;
268
268
  case 'Escape':
269
+ // Closing the suggestions claims the key, so a Modal around the
270
+ // field stays open. With none showing, the key goes on to it.
271
+ if (isActive && filteredData.length > 0)
272
+ e.preventDefault();
269
273
  setIsActive(false);
270
274
  setHighlightedIndex(-1);
271
275
  break;