@allxsmith/bestax-bulma 5.56.0 → 5.57.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/esm/columns/Column.js +1 -0
- package/dist/esm/columns/Column.js.map +1 -1
- package/dist/esm/columns/Columns.js +1 -0
- package/dist/esm/columns/Columns.js.map +1 -1
- package/dist/esm/components/Avatar.js +1 -0
- package/dist/esm/components/Avatar.js.map +1 -1
- package/dist/esm/components/Avatars.js +1 -0
- package/dist/esm/components/Avatars.js.map +1 -1
- package/dist/esm/components/Badge.js +1 -0
- package/dist/esm/components/Badge.js.map +1 -1
- package/dist/esm/components/Breadcrumb.js +1 -0
- package/dist/esm/components/Breadcrumb.js.map +1 -1
- package/dist/esm/components/Card.js +1 -0
- package/dist/esm/components/Card.js.map +1 -1
- package/dist/esm/components/Carousel.js +1 -0
- package/dist/esm/components/Carousel.js.map +1 -1
- package/dist/esm/components/Collapse.js +1 -0
- package/dist/esm/components/Collapse.js.map +1 -1
- package/dist/esm/components/Collapses.js +1 -0
- package/dist/esm/components/Collapses.js.map +1 -1
- package/dist/esm/components/Command.js +1 -0
- package/dist/esm/components/Command.js.map +1 -1
- package/dist/esm/components/ContextMenu.js +1 -0
- package/dist/esm/components/ContextMenu.js.map +1 -1
- package/dist/esm/components/DataTable.js +1 -0
- package/dist/esm/components/DataTable.js.map +1 -1
- package/dist/esm/components/Dialog.js +1 -0
- package/dist/esm/components/Dialog.js.map +1 -1
- package/dist/esm/components/Dropdown.js +5 -1
- package/dist/esm/components/Dropdown.js.map +1 -1
- package/dist/esm/components/EmptyState.js +1 -0
- package/dist/esm/components/EmptyState.js.map +1 -1
- package/dist/esm/components/HoverCard.js +1 -0
- package/dist/esm/components/HoverCard.js.map +1 -1
- package/dist/esm/components/Loading.js +1 -0
- package/dist/esm/components/Loading.js.map +1 -1
- package/dist/esm/components/Menu.js +1 -0
- package/dist/esm/components/Menu.js.map +1 -1
- package/dist/esm/components/Message.js +1 -0
- package/dist/esm/components/Message.js.map +1 -1
- package/dist/esm/components/Modal.js +1 -0
- package/dist/esm/components/Modal.js.map +1 -1
- package/dist/esm/components/Navbar.js +1 -0
- package/dist/esm/components/Navbar.js.map +1 -1
- package/dist/esm/components/Pagination.js +1 -0
- package/dist/esm/components/Pagination.js.map +1 -1
- package/dist/esm/components/Panel.js +1 -0
- package/dist/esm/components/Panel.js.map +1 -1
- package/dist/esm/components/Popover.js +1 -0
- package/dist/esm/components/Popover.js.map +1 -1
- package/dist/esm/components/Reveal.js +1 -0
- package/dist/esm/components/Reveal.js.map +1 -1
- package/dist/esm/components/ScrollArea.js +1 -0
- package/dist/esm/components/ScrollArea.js.map +1 -1
- package/dist/esm/components/SegmentedControl.js +1 -0
- package/dist/esm/components/SegmentedControl.js.map +1 -1
- package/dist/esm/components/Sidebar.js +1 -0
- package/dist/esm/components/Sidebar.js.map +1 -1
- package/dist/esm/components/Steps.js +1 -0
- package/dist/esm/components/Steps.js.map +1 -1
- package/dist/esm/components/Tabs.js +1 -0
- package/dist/esm/components/Tabs.js.map +1 -1
- package/dist/esm/components/Timeline.js +1 -0
- package/dist/esm/components/Timeline.js.map +1 -1
- package/dist/esm/components/Toast.js +1 -0
- package/dist/esm/components/Toast.js.map +1 -1
- package/dist/esm/components/Tooltip.js +1 -0
- package/dist/esm/components/Tooltip.js.map +1 -1
- package/dist/esm/components/TreeView.js +1 -0
- package/dist/esm/components/TreeView.js.map +1 -1
- package/dist/esm/components/collapsesContext.js +1 -0
- package/dist/esm/components/collapsesContext.js.map +1 -1
- package/dist/esm/components/useDataTable.js +1 -0
- package/dist/esm/components/useDataTable.js.map +1 -1
- package/dist/esm/elements/Block.js +1 -0
- package/dist/esm/elements/Block.js.map +1 -1
- package/dist/esm/elements/Box.js +1 -0
- package/dist/esm/elements/Box.js.map +1 -1
- package/dist/esm/elements/Button.js +1 -0
- package/dist/esm/elements/Button.js.map +1 -1
- package/dist/esm/elements/Buttons.js +1 -0
- package/dist/esm/elements/Buttons.js.map +1 -1
- package/dist/esm/elements/Code.js +1 -0
- package/dist/esm/elements/Code.js.map +1 -1
- package/dist/esm/elements/ColorSwatch.js +1 -0
- package/dist/esm/elements/ColorSwatch.js.map +1 -1
- package/dist/esm/elements/Content.js +1 -0
- package/dist/esm/elements/Content.js.map +1 -1
- package/dist/esm/elements/Delete.js +1 -0
- package/dist/esm/elements/Delete.js.map +1 -1
- package/dist/esm/elements/DescriptionList.js +1 -0
- package/dist/esm/elements/DescriptionList.js.map +1 -1
- package/dist/esm/elements/Divider.js +1 -0
- package/dist/esm/elements/Divider.js.map +1 -1
- package/dist/esm/elements/Emphasis.js +1 -0
- package/dist/esm/elements/Emphasis.js.map +1 -1
- package/dist/esm/elements/Figure.js +1 -0
- package/dist/esm/elements/Figure.js.map +1 -1
- package/dist/esm/elements/Icon.js +1 -0
- package/dist/esm/elements/Icon.js.map +1 -1
- package/dist/esm/elements/IconText.js +1 -0
- package/dist/esm/elements/IconText.js.map +1 -1
- package/dist/esm/elements/Image.js +1 -0
- package/dist/esm/elements/Image.js.map +1 -1
- package/dist/esm/elements/Kbd.js +1 -0
- package/dist/esm/elements/Kbd.js.map +1 -1
- package/dist/esm/elements/Link.js +1 -0
- package/dist/esm/elements/Link.js.map +1 -1
- package/dist/esm/elements/LinkButton.js +1 -0
- package/dist/esm/elements/LinkButton.js.map +1 -1
- package/dist/esm/elements/ListItem.js +1 -0
- package/dist/esm/elements/ListItem.js.map +1 -1
- package/dist/esm/elements/Loader.js +1 -0
- package/dist/esm/elements/Loader.js.map +1 -1
- package/dist/esm/elements/Notification.js +1 -0
- package/dist/esm/elements/Notification.js.map +1 -1
- package/dist/esm/elements/OrderedList.js +1 -0
- package/dist/esm/elements/OrderedList.js.map +1 -1
- package/dist/esm/elements/Paragraph.js +1 -0
- package/dist/esm/elements/Paragraph.js.map +1 -1
- package/dist/esm/elements/Pre.js +1 -0
- package/dist/esm/elements/Pre.js.map +1 -1
- package/dist/esm/elements/Progress.js +1 -0
- package/dist/esm/elements/Progress.js.map +1 -1
- package/dist/esm/elements/RingProgress.js +1 -0
- package/dist/esm/elements/RingProgress.js.map +1 -1
- package/dist/esm/elements/Skeleton.js +1 -0
- package/dist/esm/elements/Skeleton.js.map +1 -1
- package/dist/esm/elements/Span.js +1 -0
- package/dist/esm/elements/Span.js.map +1 -1
- package/dist/esm/elements/Strong.js +1 -0
- package/dist/esm/elements/Strong.js.map +1 -1
- package/dist/esm/elements/SubTitle.js +1 -0
- package/dist/esm/elements/SubTitle.js.map +1 -1
- package/dist/esm/elements/Table.js +1 -0
- package/dist/esm/elements/Table.js.map +1 -1
- package/dist/esm/elements/Tag.js +1 -0
- package/dist/esm/elements/Tag.js.map +1 -1
- package/dist/esm/elements/Tags.js +1 -0
- package/dist/esm/elements/Tags.js.map +1 -1
- package/dist/esm/elements/Tbody.js +1 -0
- package/dist/esm/elements/Tbody.js.map +1 -1
- package/dist/esm/elements/Td.js +1 -0
- package/dist/esm/elements/Td.js.map +1 -1
- package/dist/esm/elements/Tfoot.js +1 -0
- package/dist/esm/elements/Tfoot.js.map +1 -1
- package/dist/esm/elements/Th.js +1 -0
- package/dist/esm/elements/Th.js.map +1 -1
- package/dist/esm/elements/Thead.js +1 -0
- package/dist/esm/elements/Thead.js.map +1 -1
- package/dist/esm/elements/Title.js +1 -0
- package/dist/esm/elements/Title.js.map +1 -1
- package/dist/esm/elements/ToggleButton.js +1 -0
- package/dist/esm/elements/ToggleButton.js.map +1 -1
- package/dist/esm/elements/Tr.js +1 -0
- package/dist/esm/elements/Tr.js.map +1 -1
- package/dist/esm/elements/UnorderedList.js +1 -0
- package/dist/esm/elements/UnorderedList.js.map +1 -1
- package/dist/esm/elements/iconProps.js +1 -0
- package/dist/esm/elements/iconProps.js.map +1 -1
- package/dist/esm/form/Autocomplete.js +1 -0
- package/dist/esm/form/Autocomplete.js.map +1 -1
- package/dist/esm/form/Checkbox.js +1 -0
- package/dist/esm/form/Checkbox.js.map +1 -1
- package/dist/esm/form/CheckboxCard.js +1 -0
- package/dist/esm/form/CheckboxCard.js.map +1 -1
- package/dist/esm/form/Checkboxes.js +1 -0
- package/dist/esm/form/Checkboxes.js.map +1 -1
- package/dist/esm/form/ColorInput.js +1 -0
- package/dist/esm/form/ColorInput.js.map +1 -1
- package/dist/esm/form/ColorInputBase.js +1 -0
- package/dist/esm/form/ColorInputBase.js.map +1 -1
- package/dist/esm/form/ColorPicker.js +1 -0
- package/dist/esm/form/ColorPicker.js.map +1 -1
- package/dist/esm/form/Combobox.js +1 -0
- package/dist/esm/form/Combobox.js.map +1 -1
- package/dist/esm/form/Control.js +1 -0
- package/dist/esm/form/Control.js.map +1 -1
- package/dist/esm/form/DateInput.js +1 -0
- package/dist/esm/form/DateInput.js.map +1 -1
- package/dist/esm/form/DateInputBase.js +1 -0
- package/dist/esm/form/DateInputBase.js.map +1 -1
- package/dist/esm/form/DateRangeInput.js +1 -0
- package/dist/esm/form/DateRangeInput.js.map +1 -1
- package/dist/esm/form/DateRangeInputBase.js +1 -0
- package/dist/esm/form/DateRangeInputBase.js.map +1 -1
- package/dist/esm/form/DateTimeInput.js +1 -0
- package/dist/esm/form/DateTimeInput.js.map +1 -1
- package/dist/esm/form/DateTimeInputBase.js +1 -0
- package/dist/esm/form/DateTimeInputBase.js.map +1 -1
- package/dist/esm/form/Dropzone.js +1 -0
- package/dist/esm/form/Dropzone.js.map +1 -1
- package/dist/esm/form/Field.js +1 -0
- package/dist/esm/form/Field.js.map +1 -1
- package/dist/esm/form/Fieldset.js +1 -0
- package/dist/esm/form/Fieldset.js.map +1 -1
- package/dist/esm/form/File.js +1 -0
- package/dist/esm/form/File.js.map +1 -1
- package/dist/esm/form/FormContext.js +1 -0
- package/dist/esm/form/FormContext.js.map +1 -1
- package/dist/esm/form/Input.js +1 -0
- package/dist/esm/form/Input.js.map +1 -1
- package/dist/esm/form/InputBase.js +1 -0
- package/dist/esm/form/InputBase.js.map +1 -1
- package/dist/esm/form/Numberinput.js +1 -0
- package/dist/esm/form/Numberinput.js.map +1 -1
- package/dist/esm/form/PinInput.js +1 -0
- package/dist/esm/form/PinInput.js.map +1 -1
- package/dist/esm/form/Radio.js +1 -0
- package/dist/esm/form/Radio.js.map +1 -1
- package/dist/esm/form/RadioCard.js +1 -0
- package/dist/esm/form/RadioCard.js.map +1 -1
- package/dist/esm/form/Radios.js +1 -0
- package/dist/esm/form/Radios.js.map +1 -1
- package/dist/esm/form/Rate.js +1 -0
- package/dist/esm/form/Rate.js.map +1 -1
- package/dist/esm/form/Select.js +1 -0
- package/dist/esm/form/Select.js.map +1 -1
- package/dist/esm/form/SelectBase.js +1 -0
- package/dist/esm/form/SelectBase.js.map +1 -1
- package/dist/esm/form/Slider.js +1 -0
- package/dist/esm/form/Slider.js.map +1 -1
- package/dist/esm/form/Switch.js +1 -0
- package/dist/esm/form/Switch.js.map +1 -1
- package/dist/esm/form/Taginput.js +1 -0
- package/dist/esm/form/Taginput.js.map +1 -1
- package/dist/esm/form/TextArea.js +1 -0
- package/dist/esm/form/TextArea.js.map +1 -1
- package/dist/esm/form/TextAreaBase.js +1 -0
- package/dist/esm/form/TextAreaBase.js.map +1 -1
- package/dist/esm/form/TimeInput.js +1 -0
- package/dist/esm/form/TimeInput.js.map +1 -1
- package/dist/esm/form/TimeInputBase.js +1 -0
- package/dist/esm/form/TimeInputBase.js.map +1 -1
- package/dist/esm/form/_colorInternals/EyeDropperButton.js +1 -0
- package/dist/esm/form/_colorInternals/EyeDropperButton.js.map +1 -1
- package/dist/esm/form/_colorInternals/pickerState.js +1 -0
- package/dist/esm/form/_colorInternals/pickerState.js.map +1 -1
- package/dist/esm/form/_pickerInternals/Calendar.js +1 -0
- package/dist/esm/form/_pickerInternals/Calendar.js.map +1 -1
- package/dist/esm/form/_pickerInternals/PickerPopover.js +1 -0
- package/dist/esm/form/_pickerInternals/PickerPopover.js.map +1 -1
- package/dist/esm/form/_pickerInternals/TimeWheels.js +1 -0
- package/dist/esm/form/_pickerInternals/TimeWheels.js.map +1 -1
- package/dist/esm/form/_pickerInternals/useLocaleDefaults.js +1 -0
- package/dist/esm/form/_pickerInternals/useLocaleDefaults.js.map +1 -1
- package/dist/esm/form/_pickerInternals/useNativeMobilePicker.js +1 -0
- package/dist/esm/form/_pickerInternals/useNativeMobilePicker.js.map +1 -1
- package/dist/esm/form/_pickerInternals/useSegmentedEntry.js +1 -0
- package/dist/esm/form/_pickerInternals/useSegmentedEntry.js.map +1 -1
- package/dist/esm/form/controlLoading.js +1 -0
- package/dist/esm/form/controlLoading.js.map +1 -1
- package/dist/esm/form/groupFieldset.js +1 -0
- package/dist/esm/form/groupFieldset.js.map +1 -1
- package/dist/esm/form/useAutoLabelId.js +1 -0
- package/dist/esm/form/useAutoLabelId.js.map +1 -1
- package/dist/esm/grid/Cell.js +1 -0
- package/dist/esm/grid/Cell.js.map +1 -1
- package/dist/esm/grid/Grid.js +1 -0
- package/dist/esm/grid/Grid.js.map +1 -1
- package/dist/esm/helpers/ClientOnly.js +1 -0
- package/dist/esm/helpers/ClientOnly.js.map +1 -1
- package/dist/esm/helpers/Config.js +1 -0
- package/dist/esm/helpers/Config.js.map +1 -1
- package/dist/esm/helpers/LocaleProvider.js +1 -0
- package/dist/esm/helpers/LocaleProvider.js.map +1 -1
- package/dist/esm/helpers/Theme.js +1 -0
- package/dist/esm/helpers/Theme.js.map +1 -1
- package/dist/esm/helpers/flattenChildren.js +1 -0
- package/dist/esm/helpers/flattenChildren.js.map +1 -1
- package/dist/esm/helpers/inertProps.js +1 -0
- package/dist/esm/helpers/inertProps.js.map +1 -1
- package/dist/esm/helpers/localeFormat.js +1 -0
- package/dist/esm/helpers/localeFormat.js.map +1 -1
- package/dist/esm/helpers/overlayStack.js +1 -0
- package/dist/esm/helpers/overlayStack.js.map +1 -1
- package/dist/esm/helpers/portal.js +1 -0
- package/dist/esm/helpers/portal.js.map +1 -1
- package/dist/esm/helpers/scrollLock.js +1 -0
- package/dist/esm/helpers/scrollLock.js.map +1 -1
- package/dist/esm/helpers/statusRegion.js +1 -0
- package/dist/esm/helpers/statusRegion.js.map +1 -1
- package/dist/esm/helpers/typeahead.js +1 -0
- package/dist/esm/helpers/typeahead.js.map +1 -1
- package/dist/esm/helpers/useAnchoredPosition.js +1 -0
- package/dist/esm/helpers/useAnchoredPosition.js.map +1 -1
- package/dist/esm/helpers/useBulmaClasses.js +1 -0
- package/dist/esm/helpers/useBulmaClasses.js.map +1 -1
- package/dist/esm/helpers/useClientLayoutEffect.js +1 -0
- package/dist/esm/helpers/useClientLayoutEffect.js.map +1 -1
- package/dist/esm/helpers/useColorClasses.js +1 -0
- package/dist/esm/helpers/useColorClasses.js.map +1 -1
- package/dist/esm/helpers/useComboboxEngine.js +1 -0
- package/dist/esm/helpers/useComboboxEngine.js.map +1 -1
- package/dist/esm/helpers/useContextMenuTrigger.js +1 -0
- package/dist/esm/helpers/useContextMenuTrigger.js.map +1 -1
- package/dist/esm/helpers/useFlexboxClasses.js +1 -0
- package/dist/esm/helpers/useFlexboxClasses.js.map +1 -1
- package/dist/esm/helpers/useFocusTrap.js +1 -0
- package/dist/esm/helpers/useFocusTrap.js.map +1 -1
- package/dist/esm/helpers/useHoverOpen.js +1 -0
- package/dist/esm/helpers/useHoverOpen.js.map +1 -1
- package/dist/esm/helpers/useInertSiblings.js +1 -0
- package/dist/esm/helpers/useInertSiblings.js.map +1 -1
- package/dist/esm/helpers/useIsHydrated.js +1 -0
- package/dist/esm/helpers/useIsHydrated.js.map +1 -1
- package/dist/esm/helpers/useLatestRef.js +1 -0
- package/dist/esm/helpers/useLatestRef.js.map +1 -1
- package/dist/esm/helpers/useMenuKeys.js +1 -0
- package/dist/esm/helpers/useMenuKeys.js.map +1 -1
- package/dist/esm/helpers/useOtherClasses.js +1 -0
- package/dist/esm/helpers/useOtherClasses.js.map +1 -1
- package/dist/esm/helpers/useSpacingClasses.js +1 -0
- package/dist/esm/helpers/useSpacingClasses.js.map +1 -1
- package/dist/esm/helpers/useTreeView.js +1 -0
- package/dist/esm/helpers/useTreeView.js.map +1 -1
- package/dist/esm/helpers/useTypographyClasses.js +1 -0
- package/dist/esm/helpers/useTypographyClasses.js.map +1 -1
- package/dist/esm/helpers/useVisibilityClasses.js +1 -0
- package/dist/esm/helpers/useVisibilityClasses.js.map +1 -1
- package/dist/esm/layout/Container.js +1 -0
- package/dist/esm/layout/Container.js.map +1 -1
- package/dist/esm/layout/Footer.js +1 -0
- package/dist/esm/layout/Footer.js.map +1 -1
- package/dist/esm/layout/Hero.js +1 -0
- package/dist/esm/layout/Hero.js.map +1 -1
- package/dist/esm/layout/Level.js +1 -0
- package/dist/esm/layout/Level.js.map +1 -1
- package/dist/esm/layout/Media.js +1 -0
- package/dist/esm/layout/Media.js.map +1 -1
- package/dist/esm/layout/Section.js +1 -0
- package/dist/esm/layout/Section.js.map +1 -1
- package/dist/esm/layout/Splitter.js +1 -0
- package/dist/esm/layout/Splitter.js.map +1 -1
- package/dist/index.cjs +4 -1
- package/dist/index.cjs.map +1 -1
- package/package.json +28 -27
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverCard.js","sources":["../../../src/components/HoverCard.tsx"],"sourcesContent":["import React, {\n cloneElement,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { Portal } from '../helpers/portal';\nimport { useIsHydrated } from '../helpers/useIsHydrated';\nimport { marginGap, useAnchoredPosition } from '../helpers/useAnchoredPosition';\nimport { chain, useHoverOpen } from '../helpers/useHoverOpen';\nimport { isTabbableKind } from '../helpers/useFocusTrap';\nimport { isDev, warnOnce } from '../helpers/devWarnings';\nimport type { PickerPosition } from '../form/_pickerInternals/pickerTypes';\n\n/**\n * Where the card opens against its trigger: below (`bottom-*`) or above\n * (`top-*`), lined up with the trigger's left or right edge. `auto` picks the\n * one that keeps the card in the viewport, preferring below and lined up on\n * the left. The same union `Popover` and the date and time pickers take.\n */\nexport type HoverCardPosition = PickerPosition;\n\n/**\n * Props for the HoverCard component. `className`, `id`, the other HTML\n * attributes and the helper props land on the `span` around the trigger, not\n * on the card; `contentClassName` reaches the card.\n * @extraProp {string} [className] - Additional classes for the `span` around the trigger. The card takes `contentClassName`.\n */\nexport interface HoverCardProps\n extends\n Omit<React.HTMLAttributes<HTMLSpanElement>, 'color' | 'children'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /**\n * The element the card previews, such as a link or a `Button`. The element\n * itself has to take focus, so keyboard users can open the card too: a\n * link inside a `<span>` doesn't do, since focus comes back to the trigger\n * and its ARIA is on it. HoverCard gives it no role and no tab stop, since\n * it can't know what the element is, and a development build warns when\n * it can't take focus: use a link or a button, or give the element\n * `tabIndex={0}`. A disabled button can't take focus either. HoverCard adds\n * `aria-expanded` and `aria-controls`, both naming the card only while it\n * is on the page, so it has to be a single element that passes those to\n * its DOM node. Its own click and keys stay its own, and the card doesn't\n * toggle on them, except Escape while the card is open, which closes the\n * card before the trigger sees it.\n */\n trigger: React.ReactElement;\n /**\n * The card's content: a preview whose links and buttons are fine, but not a\n * form, which belongs in a `Popover`. The card pads itself, so content goes\n * straight in.\n */\n children?: React.ReactNode;\n /**\n * Controlled open state. When set, hover, focus and Escape only report\n * through `onOpenChange`, so an action inside the card can close it. While\n * the card is open, Escape is reported, and when focus is in the card, on\n * its trigger or nowhere, the key stops there even if you keep the card\n * open, so a `Modal` around it doesn't close from the keyboard until the\n * card does.\n */\n open?: boolean;\n /**\n * Initial open state when uncontrolled. A card that starts open stays open\n * until the pointer or focus has been and gone, or Escape closes it.\n * @defaultValue false\n */\n defaultOpen?: boolean;\n /**\n * Called with the state asked for: when `openDelay` or `closeDelay` runs\n * out, and right away on Escape. Fires in both controlled and uncontrolled\n * use. An Escape it reports stops at the card when focus is in the card,\n * on its trigger or nowhere, so nothing around it sees that key. With\n * focus anywhere else, the card still closes and the key goes on to\n * whatever has focus.\n */\n onOpenChange?: (open: boolean) => void;\n /**\n * How long the pointer or keyboard focus waits on the trigger before the\n * card opens, in milliseconds.\n * @defaultValue 600\n */\n openDelay?: number;\n /**\n * How long the card stays after the pointer and focus have left the trigger\n * and the card, in milliseconds. It is the time the pointer has to cross\n * the gap between the trigger and the card: with `0` the card closes as the\n * pointer leaves the trigger, before the pointer can reach it.\n * @defaultValue 300\n */\n closeDelay?: number;\n /**\n * Where the card opens against the trigger.\n * @defaultValue 'bottom-left'\n */\n position?: HoverCardPosition;\n /**\n * Render the card through `Portal`, into the `portalContainer` a\n * `ConfigProvider` sets, `document.body` by default, fixed to the viewport,\n * so an ancestor's `overflow`, `transform` or stacking context can't clip\n * it. A trigger in running text needs it too, since the card's block\n * content can't sit inside a `<p>`. The card then shows from the commit\n * after hydration, never in server markup, and it sits in the Tab order\n * where its container is. At the end of `<body>`, the default, Tab reaches\n * it only after the rest of the page, and focus leaving the trigger on the\n * way closes it, so keyboard users can open it, read it and close it with\n * Escape, and whatever it links to has to be reachable from the page as\n * well. It is measured against the trigger when it opens and on resize and\n * scroll, so it doesn't follow content that changes size while it is open.\n * Theming variables set on an ancestor of the trigger reach it only when its\n * container is inside that ancestor.\n * @defaultValue false\n */\n appendToBody?: boolean;\n /**\n * Open the card with a tap on a touch screen. Touch has no hover, so\n * without this a phone or tablet never opens the card. With it, a tap on\n * the trigger opens the card at once, and it stays until a second tap on\n * the trigger, a tap outside the trigger and the card, or Escape. The tap\n * still does whatever the trigger does, so turn this on only for a trigger\n * with no tap action of its own, such as a `Button` with no `onClick`: on\n * a link, the first tap would follow the link rather than show the card.\n * Mouse and pen work the same either way.\n * @defaultValue false\n */\n openOnTap?: boolean;\n /** Additional classes for the card (`.hover-card-content`). */\n contentClassName?: string;\n}\n\n/**\n * The `HoverCard` component shows a card previewing what's behind a link or a button while the pointer rests on it or keyboard focus is on it.\n *\n * Nothing moves focus when the card opens, and nothing traps it. In place,\n * the card comes right after the trigger, so Tab goes from the trigger into\n * its links and tabbing past them closes it. The pointer can move onto the\n * card, Escape closes it from anywhere, and by default touch doesn't open it,\n * so tapping the trigger just does what the trigger does. `openOnTap` opens\n * it with a tap, for a trigger with no tap action of its own. For hints with nothing to\n * click use `Tooltip`, and for content opened on purpose, such as a form,\n * use `Popover`.\n *\n * @function\n * @param {HoverCardProps} props - Props for the HoverCard component.\n * @returns {JSX.Element} The trigger in its wrapper, and the card while open.\n *\n * @example\n * <HoverCard trigger={<a href=\"/people/ada\">Ada Lovelace</a>}>\n * <Title as=\"p\" size=\"6\">Ada Lovelace</Title>\n * <SubTitle as=\"p\" size=\"6\">Analytical Engine team</SubTitle>\n * </HoverCard>\n */\nexport const HoverCard: React.FC<HoverCardProps> = ({\n trigger,\n children,\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n openDelay = 600,\n closeDelay = 300,\n position = 'bottom-left',\n appendToBody = false,\n openOnTap = false,\n className,\n contentClassName,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const {\n onPointerEnter,\n onPointerOver,\n onPointerLeave,\n onPointerDown,\n onPointerUp,\n onFocus,\n onBlur,\n ...attrs\n } = rest;\n const rootRef = useRef<HTMLSpanElement>(null);\n const cardRef = useRef<HTMLDivElement>(null);\n const cardId = `${useId()}-card`;\n\n const isControlled = controlledOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const isOpen = controlledOpen ?? internalOpen;\n\n const requestOpen = useCallback(\n (next: boolean) => {\n onOpenChange?.(next);\n if (!isControlled) setInternalOpen(next);\n },\n [isControlled, onOpenChange]\n );\n\n // A portaled card has no server markup, so it only exists from the commit\n // after hydration, and nothing measures it before then.\n const hydrated = useIsHydrated();\n const cardMounted = isOpen && (hydrated || !appendToBody);\n\n const resolved = useAnchoredPosition(rootRef, cardRef, {\n active: cardMounted,\n position,\n fixed: appendToBody,\n // The gap comes from `--bulma-hover-card-offset` in the stylesheet, so\n // the coordinates leave it out and `auto` reads it off the card.\n offset: 0,\n styledGap: marginGap,\n });\n\n // The trigger renders first inside the wrapper. Read when needed rather\n // than held, so a trigger that remounted is still the one found.\n const triggerRef = useMemo(\n () => ({\n get current() {\n const first = (rootRef.current as HTMLSpanElement).firstElementChild;\n return first && first !== cardRef.current\n ? (first as HTMLElement)\n : null;\n },\n }),\n []\n );\n\n const hover = useHoverOpen({\n open: isOpen,\n onOpenChange: requestOpen,\n openDelay,\n closeDelay,\n triggerRef,\n floatingRef: cardRef,\n openOnTap,\n });\n\n // A trigger that can't take focus leaves keyboard users no way to open the\n // card. It has to be the trigger element itself, not something inside it,\n // since focus comes back to it and its ARIA is on it. Judged by what the\n // element is rather than by its styles, which can hide it for now. After\n // every commit, since the trigger can change, and only in development.\n useEffect(() => {\n if (!isDev()) return;\n const triggerNode = triggerRef.current;\n if (!triggerNode) return;\n if (!triggerNode.matches(':disabled') && isTabbableKind(triggerNode)) {\n return;\n }\n warnOnce(\n 'HoverCard:unfocusable-trigger',\n \"[bestax-bulma] <HoverCard> has a trigger that can't take focus, so \" +\n \"keyboard users can't open the card. Use a link or a button as the \" +\n 'trigger, or give it tabIndex={0}.'\n );\n });\n\n // Expanded only while the card is on the page, so a portaled card that\n // waits for hydration isn't announced before it exists.\n const clonedTrigger = cloneElement(\n trigger as React.ReactElement<Record<string, unknown>>,\n {\n 'aria-expanded': cardMounted,\n 'aria-controls': cardMounted ? cardId : undefined,\n }\n );\n\n const rootClasses = classNames(\n usePrefixedClassNames('hover-card', { 'is-active': cardMounted }),\n bulmaHelperClasses,\n className\n );\n const cardClasses = classNames(\n usePrefixedClassNames('hover-card-content', {\n [`is-${resolved.position}`]: true,\n 'is-portal': appendToBody,\n }),\n contentClassName\n );\n\n return (\n // The ref after the spread: React 19 hands a function component a `ref`\n // prop like any other, and the wrapper has to stay ours. The card is in\n // the wrapper's React tree even when portaled, so the hover and focus\n // handlers here hear from both.\n <span\n className={rootClasses}\n {...attrs}\n onPointerEnter={chain(onPointerEnter, hover.onPointerEnter)}\n onPointerOver={chain(onPointerOver, hover.onPointerOver)}\n onPointerLeave={chain(onPointerLeave, hover.onPointerLeave)}\n onFocus={chain(onFocus, hover.onFocus)}\n onBlur={chain(onBlur, hover.onBlur)}\n onPointerDown={chain(onPointerDown, hover.onPointerDown)}\n onPointerUp={chain(onPointerUp, hover.onPointerUp)}\n ref={rootRef}\n >\n {clonedTrigger}\n {isOpen && (\n <Portal disabled={!appendToBody}>\n <div\n ref={cardRef}\n id={cardId}\n className={cardClasses}\n style={\n appendToBody\n ? {\n position: 'fixed',\n top: resolved.top,\n left: resolved.left,\n }\n : undefined\n }\n >\n {children}\n </div>\n </Portal>\n )}\n </span>\n );\n};\n\nexport default HoverCard;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HoverCard.js","sources":["../../../src/components/HoverCard.tsx"],"sourcesContent":["import React, {\n cloneElement,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { Portal } from '../helpers/portal';\nimport { useIsHydrated } from '../helpers/useIsHydrated';\nimport { marginGap, useAnchoredPosition } from '../helpers/useAnchoredPosition';\nimport { chain, useHoverOpen } from '../helpers/useHoverOpen';\nimport { isTabbableKind } from '../helpers/useFocusTrap';\nimport { isDev, warnOnce } from '../helpers/devWarnings';\nimport type { PickerPosition } from '../form/_pickerInternals/pickerTypes';\n\n/**\n * Where the card opens against its trigger: below (`bottom-*`) or above\n * (`top-*`), lined up with the trigger's left or right edge. `auto` picks the\n * one that keeps the card in the viewport, preferring below and lined up on\n * the left. The same union `Popover` and the date and time pickers take.\n */\nexport type HoverCardPosition = PickerPosition;\n\n/**\n * Props for the HoverCard component. `className`, `id`, the other HTML\n * attributes and the helper props land on the `span` around the trigger, not\n * on the card; `contentClassName` reaches the card.\n * @extraProp {string} [className] - Additional classes for the `span` around the trigger. The card takes `contentClassName`.\n */\nexport interface HoverCardProps\n extends\n Omit<React.HTMLAttributes<HTMLSpanElement>, 'color' | 'children'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /**\n * The element the card previews, such as a link or a `Button`. The element\n * itself has to take focus, so keyboard users can open the card too: a\n * link inside a `<span>` doesn't do, since focus comes back to the trigger\n * and its ARIA is on it. HoverCard gives it no role and no tab stop, since\n * it can't know what the element is, and a development build warns when\n * it can't take focus: use a link or a button, or give the element\n * `tabIndex={0}`. A disabled button can't take focus either. HoverCard adds\n * `aria-expanded` and `aria-controls`, both naming the card only while it\n * is on the page, so it has to be a single element that passes those to\n * its DOM node. Its own click and keys stay its own, and the card doesn't\n * toggle on them, except Escape while the card is open, which closes the\n * card before the trigger sees it.\n */\n trigger: React.ReactElement;\n /**\n * The card's content: a preview whose links and buttons are fine, but not a\n * form, which belongs in a `Popover`. The card pads itself, so content goes\n * straight in.\n */\n children?: React.ReactNode;\n /**\n * Controlled open state. When set, hover, focus and Escape only report\n * through `onOpenChange`, so an action inside the card can close it. While\n * the card is open, Escape is reported, and when focus is in the card, on\n * its trigger or nowhere, the key stops there even if you keep the card\n * open, so a `Modal` around it doesn't close from the keyboard until the\n * card does.\n */\n open?: boolean;\n /**\n * Initial open state when uncontrolled. A card that starts open stays open\n * until the pointer or focus has been and gone, or Escape closes it.\n * @defaultValue false\n */\n defaultOpen?: boolean;\n /**\n * Called with the state asked for: when `openDelay` or `closeDelay` runs\n * out, and right away on Escape. Fires in both controlled and uncontrolled\n * use. An Escape it reports stops at the card when focus is in the card,\n * on its trigger or nowhere, so nothing around it sees that key. With\n * focus anywhere else, the card still closes and the key goes on to\n * whatever has focus.\n */\n onOpenChange?: (open: boolean) => void;\n /**\n * How long the pointer or keyboard focus waits on the trigger before the\n * card opens, in milliseconds.\n * @defaultValue 600\n */\n openDelay?: number;\n /**\n * How long the card stays after the pointer and focus have left the trigger\n * and the card, in milliseconds. It is the time the pointer has to cross\n * the gap between the trigger and the card: with `0` the card closes as the\n * pointer leaves the trigger, before the pointer can reach it.\n * @defaultValue 300\n */\n closeDelay?: number;\n /**\n * Where the card opens against the trigger.\n * @defaultValue 'bottom-left'\n */\n position?: HoverCardPosition;\n /**\n * Render the card through `Portal`, into the `portalContainer` a\n * `ConfigProvider` sets, `document.body` by default, fixed to the viewport,\n * so an ancestor's `overflow`, `transform` or stacking context can't clip\n * it. A trigger in running text needs it too, since the card's block\n * content can't sit inside a `<p>`. The card then shows from the commit\n * after hydration, never in server markup, and it sits in the Tab order\n * where its container is. At the end of `<body>`, the default, Tab reaches\n * it only after the rest of the page, and focus leaving the trigger on the\n * way closes it, so keyboard users can open it, read it and close it with\n * Escape, and whatever it links to has to be reachable from the page as\n * well. It is measured against the trigger when it opens and on resize and\n * scroll, so it doesn't follow content that changes size while it is open.\n * Theming variables set on an ancestor of the trigger reach it only when its\n * container is inside that ancestor.\n * @defaultValue false\n */\n appendToBody?: boolean;\n /**\n * Open the card with a tap on a touch screen. Touch has no hover, so\n * without this a phone or tablet never opens the card. With it, a tap on\n * the trigger opens the card at once, and it stays until a second tap on\n * the trigger, a tap outside the trigger and the card, or Escape. The tap\n * still does whatever the trigger does, so turn this on only for a trigger\n * with no tap action of its own, such as a `Button` with no `onClick`: on\n * a link, the first tap would follow the link rather than show the card.\n * Mouse and pen work the same either way.\n * @defaultValue false\n */\n openOnTap?: boolean;\n /** Additional classes for the card (`.hover-card-content`). */\n contentClassName?: string;\n}\n\n/**\n * The `HoverCard` component shows a card previewing what's behind a link or a button while the pointer rests on it or keyboard focus is on it.\n *\n * Nothing moves focus when the card opens, and nothing traps it. In place,\n * the card comes right after the trigger, so Tab goes from the trigger into\n * its links and tabbing past them closes it. The pointer can move onto the\n * card, Escape closes it from anywhere, and by default touch doesn't open it,\n * so tapping the trigger just does what the trigger does. `openOnTap` opens\n * it with a tap, for a trigger with no tap action of its own. For hints with nothing to\n * click use `Tooltip`, and for content opened on purpose, such as a form,\n * use `Popover`.\n *\n * @function\n * @param {HoverCardProps} props - Props for the HoverCard component.\n * @returns {JSX.Element} The trigger in its wrapper, and the card while open.\n *\n * @example\n * <HoverCard trigger={<a href=\"/people/ada\">Ada Lovelace</a>}>\n * <Title as=\"p\" size=\"6\">Ada Lovelace</Title>\n * <SubTitle as=\"p\" size=\"6\">Analytical Engine team</SubTitle>\n * </HoverCard>\n */\nexport const HoverCard: React.FC<HoverCardProps> = ({\n trigger,\n children,\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n openDelay = 600,\n closeDelay = 300,\n position = 'bottom-left',\n appendToBody = false,\n openOnTap = false,\n className,\n contentClassName,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const {\n onPointerEnter,\n onPointerOver,\n onPointerLeave,\n onPointerDown,\n onPointerUp,\n onFocus,\n onBlur,\n ...attrs\n } = rest;\n const rootRef = useRef<HTMLSpanElement>(null);\n const cardRef = useRef<HTMLDivElement>(null);\n const cardId = `${useId()}-card`;\n\n const isControlled = controlledOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const isOpen = controlledOpen ?? internalOpen;\n\n const requestOpen = useCallback(\n (next: boolean) => {\n onOpenChange?.(next);\n if (!isControlled) setInternalOpen(next);\n },\n [isControlled, onOpenChange]\n );\n\n // A portaled card has no server markup, so it only exists from the commit\n // after hydration, and nothing measures it before then.\n const hydrated = useIsHydrated();\n const cardMounted = isOpen && (hydrated || !appendToBody);\n\n const resolved = useAnchoredPosition(rootRef, cardRef, {\n active: cardMounted,\n position,\n fixed: appendToBody,\n // The gap comes from `--bulma-hover-card-offset` in the stylesheet, so\n // the coordinates leave it out and `auto` reads it off the card.\n offset: 0,\n styledGap: marginGap,\n });\n\n // The trigger renders first inside the wrapper. Read when needed rather\n // than held, so a trigger that remounted is still the one found.\n const triggerRef = useMemo(\n () => ({\n get current() {\n const first = (rootRef.current as HTMLSpanElement).firstElementChild;\n return first && first !== cardRef.current\n ? (first as HTMLElement)\n : null;\n },\n }),\n []\n );\n\n const hover = useHoverOpen({\n open: isOpen,\n onOpenChange: requestOpen,\n openDelay,\n closeDelay,\n triggerRef,\n floatingRef: cardRef,\n openOnTap,\n });\n\n // A trigger that can't take focus leaves keyboard users no way to open the\n // card. It has to be the trigger element itself, not something inside it,\n // since focus comes back to it and its ARIA is on it. Judged by what the\n // element is rather than by its styles, which can hide it for now. After\n // every commit, since the trigger can change, and only in development.\n useEffect(() => {\n if (!isDev()) return;\n const triggerNode = triggerRef.current;\n if (!triggerNode) return;\n if (!triggerNode.matches(':disabled') && isTabbableKind(triggerNode)) {\n return;\n }\n warnOnce(\n 'HoverCard:unfocusable-trigger',\n \"[bestax-bulma] <HoverCard> has a trigger that can't take focus, so \" +\n \"keyboard users can't open the card. Use a link or a button as the \" +\n 'trigger, or give it tabIndex={0}.'\n );\n });\n\n // Expanded only while the card is on the page, so a portaled card that\n // waits for hydration isn't announced before it exists.\n const clonedTrigger = cloneElement(\n trigger as React.ReactElement<Record<string, unknown>>,\n {\n 'aria-expanded': cardMounted,\n 'aria-controls': cardMounted ? cardId : undefined,\n }\n );\n\n const rootClasses = classNames(\n usePrefixedClassNames('hover-card', { 'is-active': cardMounted }),\n bulmaHelperClasses,\n className\n );\n const cardClasses = classNames(\n usePrefixedClassNames('hover-card-content', {\n [`is-${resolved.position}`]: true,\n 'is-portal': appendToBody,\n }),\n contentClassName\n );\n\n return (\n // The ref after the spread: React 19 hands a function component a `ref`\n // prop like any other, and the wrapper has to stay ours. The card is in\n // the wrapper's React tree even when portaled, so the hover and focus\n // handlers here hear from both.\n <span\n className={rootClasses}\n {...attrs}\n onPointerEnter={chain(onPointerEnter, hover.onPointerEnter)}\n onPointerOver={chain(onPointerOver, hover.onPointerOver)}\n onPointerLeave={chain(onPointerLeave, hover.onPointerLeave)}\n onFocus={chain(onFocus, hover.onFocus)}\n onBlur={chain(onBlur, hover.onBlur)}\n onPointerDown={chain(onPointerDown, hover.onPointerDown)}\n onPointerUp={chain(onPointerUp, hover.onPointerUp)}\n ref={rootRef}\n >\n {clonedTrigger}\n {isOpen && (\n <Portal disabled={!appendToBody}>\n <div\n ref={cardRef}\n id={cardId}\n className={cardClasses}\n style={\n appendToBody\n ? {\n position: 'fixed',\n top: resolved.top,\n left: resolved.left,\n }\n : undefined\n }\n >\n {children}\n </div>\n </Portal>\n )}\n </span>\n );\n};\n\nexport default HoverCard;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
'use client';
|
|
2
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Loading.js","sources":["../../../src/components/Loading.tsx"],"sourcesContent":["import React from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { useScrollLock } from '../helpers/scrollLock';\nimport { useLatestRef } from '../helpers/useLatestRef';\nimport { useOverlayStack } from '../helpers/overlayStack';\nimport { useInertSiblings } from '../helpers/useInertSiblings';\n\n/**\n * Overlay opacity levels for the Loading background.\n */\nexport type LoadingOverlay = 'light' | 'dark' | 'opaque';\n\n/**\n * Color variants for the Loading spinner.\n */\nexport type LoadingColor =\n 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n\n/**\n * Props for the Loading component.\n * @extraProp {React.ReactNode} [children] - Content to display below the spinner.\n * @extraProp {string} [className] - Additional CSS classes.\n */\nexport interface LoadingProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor' | 'size' | 'overlay'> {\n /**\n * Whether the loading overlay is visible. While it is, what it covers is\n * inert, out of reach of Tab, Enter, Space and screen readers as well as\n * the mouse: the other children of the element it's rendered in, so render\n * it directly inside the element it covers, or with `isFullPage` the rest\n * of the page. Its own content, the cancel button included, stays\n * reachable. Only what's there when it turns on is made inert, and an\n * element that was inert already is left as it was. A control under it\n * that had focus loses it, and gets it back when the loading goes away,\n * unless focus has moved on in the meantime. Show one at a time over the\n * same content: two that cover each other, such as two in one container\n * or two full-page ones, make each other inert, cancel buttons and all.\n */\n active?: boolean;\n /**\n * Cover the entire viewport. While it's active, the rest of the page is\n * inert, as it is under a modal, rather than only the element it's\n * rendered in. A full-page loading also takes its turn with\n * Modal and Sidebar for Escape: while it's the topmost open overlay, the\n * Modal or Sidebar under it doesn't answer Escape or hold Tab, whether or\n * not the loading can be cancelled.\n */\n isFullPage?: boolean;\n /** Size of the loading spinner. */\n size?: 'small' | 'medium' | 'large';\n /** Color variant for the spinner. Default is light grey. */\n color?: LoadingColor;\n /**\n * Show a cancel button and allow closing, by a click on the overlay or by\n * Escape. With `isFullPage`, the loading is an overlay like Modal and\n * Sidebar: only the topmost open overlay answers Escape, so a full-page\n * loading shown over a Modal cancels first, and the Modal closes on the\n * next Escape. Without it, Escape cancels once no Modal, Dialog, Sidebar or\n * full-page Loading is open. Either way it marks the Escape it cancels on as\n * used with `preventDefault()`. An Escape a popup on the page closed on, by\n * calling `preventDefault()`, doesn't cancel.\n */\n canCancel?: boolean;\n /** Callback when cancel is triggered. */\n onCancel?: () => void;\n /** Additional classes for the overlay. */\n overlayClassName?: string;\n /** Additional classes for the spinner icon. */\n iconClassName?: string;\n /** Custom loading indicator element. */\n indicator?: React.ReactNode;\n /** Style of the loading overlay. */\n overlay?: LoadingOverlay;\n}\n\n/**\n * The `Loading` component provides a loading overlay with a spinner animation.\n *\n * @function\n * @param {LoadingProps} props - Props for the Loading component.\n * @returns {JSX.Element | null} The rendered loading overlay or null if not active.\n *\n * @example\n * // Full page loading\n * <Loading active isFullPage />\n *\n * @example\n * // Container loading with message\n * <div style={{ position: 'relative', height: '200px' }}>\n * <Loading active>Loading data...</Loading>\n * </div>\n *\n * @example\n * // With color variant\n * <Loading active color=\"primary\" />\n *\n * @example\n * // With cancel functionality\n * <Loading\n * active={isLoading}\n * canCancel\n * onCancel={() => setIsLoading(false)}\n * />\n */\nexport const Loading: React.FC<LoadingProps> = ({\n active = false,\n isFullPage = false,\n size,\n color,\n canCancel = false,\n onCancel,\n children,\n className,\n overlayClassName,\n iconClassName,\n indicator,\n overlay,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n // Generate Bulma classes with prefix\n const loadingClasses = usePrefixedClassNames('loading', {\n 'is-active': active,\n 'is-full-page': isFullPage,\n 'is-cancelable': canCancel,\n [`is-${overlay}`]: !!overlay,\n [`is-${color}`]: !!color,\n });\n\n const iconClasses = usePrefixedClassNames('loading-icon', {\n [`is-${size}`]: size,\n });\n\n // Combine classes\n const combinedClasses = classNames(\n loadingClasses,\n bulmaHelperClasses,\n className\n );\n const combinedOverlayClasses = classNames(\n usePrefixedClassNames('loading-overlay'),\n overlayClassName\n );\n const combinedIconClasses = classNames(iconClasses, iconClassName);\n const loadingContentClass = usePrefixedClassNames('loading-content');\n const loadingIconCustomClass = usePrefixedClassNames('loading-icon-custom');\n const loadingTextClass = usePrefixedClassNames('loading-text');\n const loadingCancelClass = usePrefixedClassNames('loading-cancel');\n\n // Handle cancel click\n const handleOverlayClick = () => {\n if (canCancel && onCancel) {\n onCancel();\n }\n };\n\n // Read when Escape arrives, so the key listener stays put while `onCancel`\n // changes identity, as an inline one does on every render of the parent.\n const onCancelRef = useLatestRef(onCancel);\n const hasOnCancel = Boolean(onCancel);\n\n // A full-page loading covers everything under it, so it joins the stack of\n // open overlays and takes Escape from them while it's on top. One inside a\n // container covers only that, so it stays out and waits, as a Toast does,\n // until no overlay is open.\n const isTopmost = useOverlayStack(active && isFullPage);\n\n // What the overlay covers ignores the mouse already, and is made inert so\n // Tab and screen readers skip it too: the container's other children, or\n // with `isFullPage` the rest of the page.\n const loadingRef = React.useRef<HTMLDivElement>(null);\n useInertSiblings(loadingRef, active, isFullPage);\n\n // Handle escape key. On `window`, as in `Modal`, so a popup on the page has\n // had the key first, and an Escape it closed on doesn't cancel as well. One\n // that cancels is marked used, so nothing under it acts on it too.\n React.useEffect(() => {\n if (!active || !canCancel || !hasOnCancel) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Escape' || e.defaultPrevented || !isTopmost()) return;\n e.preventDefault();\n onCancelRef.current?.();\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [active, canCancel, hasOnCancel, onCancelRef, isTopmost]);\n\n // Prevent body scroll when full page loading is active. Ref-counted through\n // the shared helper so an overlapping Modal/Dialog/Sidebar doesn't have its\n // lock cleared when this one releases.\n useScrollLock(isFullPage && active);\n\n if (!active) {\n return null;\n }\n\n return (\n <div\n className={combinedClasses}\n role=\"alert\"\n aria-busy=\"true\"\n aria-label=\"Loading\"\n {...rest}\n ref={loadingRef}\n >\n <div\n className={combinedOverlayClasses}\n onClick={handleOverlayClick}\n aria-hidden=\"true\"\n />\n <div className={loadingContentClass}>\n {indicator ? (\n <span className={loadingIconCustomClass}>{indicator}</span>\n ) : (\n <span className={combinedIconClasses} />\n )}\n {children && <div className={loadingTextClass}>{children}</div>}\n {canCancel && (\n <button\n type=\"button\"\n className={loadingCancelClass}\n onClick={onCancel}\n aria-label=\"Cancel loading\"\n >\n Cancel\n </button>\n )}\n </div>\n </div>\n );\n};\n\nexport default Loading;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Loading.js","sources":["../../../src/components/Loading.tsx"],"sourcesContent":["import React from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { useScrollLock } from '../helpers/scrollLock';\nimport { useLatestRef } from '../helpers/useLatestRef';\nimport { useOverlayStack } from '../helpers/overlayStack';\nimport { useInertSiblings } from '../helpers/useInertSiblings';\n\n/**\n * Overlay opacity levels for the Loading background.\n */\nexport type LoadingOverlay = 'light' | 'dark' | 'opaque';\n\n/**\n * Color variants for the Loading spinner.\n */\nexport type LoadingColor =\n 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n\n/**\n * Props for the Loading component.\n * @extraProp {React.ReactNode} [children] - Content to display below the spinner.\n * @extraProp {string} [className] - Additional CSS classes.\n */\nexport interface LoadingProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor' | 'size' | 'overlay'> {\n /**\n * Whether the loading overlay is visible. While it is, what it covers is\n * inert, out of reach of Tab, Enter, Space and screen readers as well as\n * the mouse: the other children of the element it's rendered in, so render\n * it directly inside the element it covers, or with `isFullPage` the rest\n * of the page. Its own content, the cancel button included, stays\n * reachable. Only what's there when it turns on is made inert, and an\n * element that was inert already is left as it was. A control under it\n * that had focus loses it, and gets it back when the loading goes away,\n * unless focus has moved on in the meantime. Show one at a time over the\n * same content: two that cover each other, such as two in one container\n * or two full-page ones, make each other inert, cancel buttons and all.\n */\n active?: boolean;\n /**\n * Cover the entire viewport. While it's active, the rest of the page is\n * inert, as it is under a modal, rather than only the element it's\n * rendered in. A full-page loading also takes its turn with\n * Modal and Sidebar for Escape: while it's the topmost open overlay, the\n * Modal or Sidebar under it doesn't answer Escape or hold Tab, whether or\n * not the loading can be cancelled.\n */\n isFullPage?: boolean;\n /** Size of the loading spinner. */\n size?: 'small' | 'medium' | 'large';\n /** Color variant for the spinner. Default is light grey. */\n color?: LoadingColor;\n /**\n * Show a cancel button and allow closing, by a click on the overlay or by\n * Escape. With `isFullPage`, the loading is an overlay like Modal and\n * Sidebar: only the topmost open overlay answers Escape, so a full-page\n * loading shown over a Modal cancels first, and the Modal closes on the\n * next Escape. Without it, Escape cancels once no Modal, Dialog, Sidebar or\n * full-page Loading is open. Either way it marks the Escape it cancels on as\n * used with `preventDefault()`. An Escape a popup on the page closed on, by\n * calling `preventDefault()`, doesn't cancel.\n */\n canCancel?: boolean;\n /** Callback when cancel is triggered. */\n onCancel?: () => void;\n /** Additional classes for the overlay. */\n overlayClassName?: string;\n /** Additional classes for the spinner icon. */\n iconClassName?: string;\n /** Custom loading indicator element. */\n indicator?: React.ReactNode;\n /** Style of the loading overlay. */\n overlay?: LoadingOverlay;\n}\n\n/**\n * The `Loading` component provides a loading overlay with a spinner animation.\n *\n * @function\n * @param {LoadingProps} props - Props for the Loading component.\n * @returns {JSX.Element | null} The rendered loading overlay or null if not active.\n *\n * @example\n * // Full page loading\n * <Loading active isFullPage />\n *\n * @example\n * // Container loading with message\n * <div style={{ position: 'relative', height: '200px' }}>\n * <Loading active>Loading data...</Loading>\n * </div>\n *\n * @example\n * // With color variant\n * <Loading active color=\"primary\" />\n *\n * @example\n * // With cancel functionality\n * <Loading\n * active={isLoading}\n * canCancel\n * onCancel={() => setIsLoading(false)}\n * />\n */\nexport const Loading: React.FC<LoadingProps> = ({\n active = false,\n isFullPage = false,\n size,\n color,\n canCancel = false,\n onCancel,\n children,\n className,\n overlayClassName,\n iconClassName,\n indicator,\n overlay,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n // Generate Bulma classes with prefix\n const loadingClasses = usePrefixedClassNames('loading', {\n 'is-active': active,\n 'is-full-page': isFullPage,\n 'is-cancelable': canCancel,\n [`is-${overlay}`]: !!overlay,\n [`is-${color}`]: !!color,\n });\n\n const iconClasses = usePrefixedClassNames('loading-icon', {\n [`is-${size}`]: size,\n });\n\n // Combine classes\n const combinedClasses = classNames(\n loadingClasses,\n bulmaHelperClasses,\n className\n );\n const combinedOverlayClasses = classNames(\n usePrefixedClassNames('loading-overlay'),\n overlayClassName\n );\n const combinedIconClasses = classNames(iconClasses, iconClassName);\n const loadingContentClass = usePrefixedClassNames('loading-content');\n const loadingIconCustomClass = usePrefixedClassNames('loading-icon-custom');\n const loadingTextClass = usePrefixedClassNames('loading-text');\n const loadingCancelClass = usePrefixedClassNames('loading-cancel');\n\n // Handle cancel click\n const handleOverlayClick = () => {\n if (canCancel && onCancel) {\n onCancel();\n }\n };\n\n // Read when Escape arrives, so the key listener stays put while `onCancel`\n // changes identity, as an inline one does on every render of the parent.\n const onCancelRef = useLatestRef(onCancel);\n const hasOnCancel = Boolean(onCancel);\n\n // A full-page loading covers everything under it, so it joins the stack of\n // open overlays and takes Escape from them while it's on top. One inside a\n // container covers only that, so it stays out and waits, as a Toast does,\n // until no overlay is open.\n const isTopmost = useOverlayStack(active && isFullPage);\n\n // What the overlay covers ignores the mouse already, and is made inert so\n // Tab and screen readers skip it too: the container's other children, or\n // with `isFullPage` the rest of the page.\n const loadingRef = React.useRef<HTMLDivElement>(null);\n useInertSiblings(loadingRef, active, isFullPage);\n\n // Handle escape key. On `window`, as in `Modal`, so a popup on the page has\n // had the key first, and an Escape it closed on doesn't cancel as well. One\n // that cancels is marked used, so nothing under it acts on it too.\n React.useEffect(() => {\n if (!active || !canCancel || !hasOnCancel) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Escape' || e.defaultPrevented || !isTopmost()) return;\n e.preventDefault();\n onCancelRef.current?.();\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [active, canCancel, hasOnCancel, onCancelRef, isTopmost]);\n\n // Prevent body scroll when full page loading is active. Ref-counted through\n // the shared helper so an overlapping Modal/Dialog/Sidebar doesn't have its\n // lock cleared when this one releases.\n useScrollLock(isFullPage && active);\n\n if (!active) {\n return null;\n }\n\n return (\n <div\n className={combinedClasses}\n role=\"alert\"\n aria-busy=\"true\"\n aria-label=\"Loading\"\n {...rest}\n ref={loadingRef}\n >\n <div\n className={combinedOverlayClasses}\n onClick={handleOverlayClick}\n aria-hidden=\"true\"\n />\n <div className={loadingContentClass}>\n {indicator ? (\n <span className={loadingIconCustomClass}>{indicator}</span>\n ) : (\n <span className={combinedIconClasses} />\n )}\n {children && <div className={loadingTextClass}>{children}</div>}\n {canCancel && (\n <button\n type=\"button\"\n className={loadingCancelClass}\n onClick={onCancel}\n aria-label=\"Cancel loading\"\n >\n Cancel\n </button>\n )}\n </div>\n </div>\n );\n};\n\nexport default Loading;\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
'use client';
|
|
2
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
4
|
import React, { createContext, forwardRef, useContext, useId, useRef, useState } from 'react';
|
|
4
5
|
import { classNames, usePrefixedClassNames } from '../helpers/classNames.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Menu.js","sources":["../../../src/components/Menu.tsx"],"sourcesContent":["import React, {\n createContext,\n forwardRef,\n useContext,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { omitAttrs } from '../helpers/anchorAttrs';\nimport { buttonType } from '../helpers/buttonType';\nimport { inertProps } from '../helpers/inertProps';\nimport { getActiveElementInTree } from '../helpers/shadowDom';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport {\n isCustomElement,\n type PolymorphicComponent,\n} from '../helpers/polymorphic';\n\n// Context to track MenuList nesting level\nconst MenuListLevelContext = createContext(0);\n\n/**\n * Props for the Menu component.\n */\nexport interface MenuProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>,\n BulmaClassesProps {\n /** Additional CSS classes. */\n className?: string;\n /** Menu content (labels, lists, items, etc). */\n children: React.ReactNode;\n}\n\n/**\n * The `Menu` component provides Bulma's vertical navigation menu: a simple, accessible sidebar or section menu for your Bulma React UI.\n *\n * @function\n * @param {MenuProps} props - Props for the Menu component.\n * @returns {JSX.Element} The rendered menu.\n * @see {@link https://bulma.io/documentation/components/menu/ | Bulma Menu documentation}\n */\nconst MenuComponent: React.FC<MenuProps> = ({\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n // Generate Bulma classes with prefix\n const bulmaClasses = usePrefixedClassNames('menu');\n\n return (\n <aside\n className={classNames(bulmaClasses, bulmaHelperClasses, className)}\n {...rest}\n >\n {children}\n </aside>\n );\n};\n\n/**\n * Props for the MenuLabel component.\n */\nexport interface MenuLabelProps\n extends\n Omit<React.HTMLAttributes<HTMLParagraphElement>, keyof BulmaClassesProps>,\n BulmaClassesProps {\n /** Additional CSS classes. */\n className?: string;\n /** Label content. */\n children: React.ReactNode;\n}\n\n/**\n * Bulma Menu label component.\n *\n * @function\n * @param {MenuLabelProps} props - Props for the MenuLabel component.\n * @returns {JSX.Element} The rendered menu label.\n */\nexport const MenuLabel: React.FC<MenuLabelProps> = ({\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n return (\n <p\n className={classNames(\n usePrefixedClassNames('menu-label'),\n className,\n bulmaHelperClasses\n )}\n {...rest}\n >\n {children}\n </p>\n );\n};\n\n/**\n * Props for the MenuList component.\n * @extraProp {React.AriaRole} [role] - Ignored: every level renders `role=\"list\"` in its place, so a menu or tree role can't go here.\n */\nexport interface MenuListProps\n extends\n Omit<React.HTMLAttributes<HTMLUListElement>, keyof BulmaClassesProps>,\n BulmaClassesProps {\n /** Additional CSS classes. */\n className?: string;\n /** List items. */\n children: React.ReactNode;\n}\n\n/**\n * MenuList applies `menu-list` class only at the top level (not for nested lists).\n *\n * Every level renders `role=\"list\"`, which Safari needs: WebKit stops\n * exposing a `<ul>` as a list once its markers are hidden, and Bulma's reset\n * hides them.\n *\n * @function\n * @param {MenuListProps} props - Props for the MenuList component.\n * @returns {JSX.Element} The rendered menu list.\n */\nexport const MenuList: React.FC<MenuListProps> = ({\n className,\n children,\n ...props\n}) => {\n const level = useContext(MenuListLevelContext);\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n const ulClass = classNames(className, bulmaHelperClasses, {\n [usePrefixedClassNames('menu-list')]: level === 0,\n });\n\n // Increment level for nested MenuLists. role=\"list\" restates the <ul>'s\n // own role, for Safari: WebKit stops exposing a list as one once its\n // markers are hidden, as Bulma's reset hides them, unless the role is set\n // explicitly. After the spread, so a caller's role can't take it away.\n return (\n <MenuListLevelContext.Provider value={level + 1}>\n <ul className={ulClass || undefined} {...rest} role=\"list\">\n {children}\n </ul>\n </MenuListLevelContext.Provider>\n );\n};\n\n/**\n * The MenuItem component's own props.\n *\n * A menu item is two elements: a wrapping `<li>` and, inside it, the element\n * `as` names. The props here are the ones the `<li>` consumes; everything else\n * follows `as` onto the inner element.\n */\nexport interface MenuItemOwnProps extends BulmaClassesProps {\n /** Additional CSS classes for the wrapping `<li>`. */\n className?: string;\n /** Item content and optional nested MenuList. */\n children: React.ReactNode;\n /**\n * Marks the item as the current one. It adds Bulma's `is-active` class, and\n * `aria-current=\"page\"` on the element `as` renders, so assistive tech can\n * tell which item is current too. An `aria-current` you pass wins, even\n * `undefined`: use it to say something else (`\"location\"` for a section of\n * one page, say), or `aria-current={false}` to turn it off. A menu should\n * mark one page, so when the section above the current page is `active` too,\n * give it `aria-current=\"location\"`, and give an `active` item that isn't\n * navigation, such as an `as=\"button\"` filter, `aria-current={false}`.\n */\n active?: boolean;\n /** Inline styles for the wrapping `<li>`. */\n style?: React.CSSProperties;\n /** `id` for the wrapping `<li>`. */\n id?: string;\n /** `title` for the wrapping `<li>`. */\n title?: string;\n /** ARIA role for the wrapping `<li>`. */\n role?: React.AriaRole;\n /** Tab index for the wrapping `<li>`. */\n tabIndex?: number;\n /** Test id for the wrapping `<li>`. */\n 'data-testid'?: string;\n}\n\n/**\n * Props for the MenuItem component. Everything the `<li>` does not consume\n * follows `as` onto the inner element: with the default `'a'` that means `href`\n * and the other anchor attributes, and with `as={Link}` it means that\n * component's own props.\n *\n * @extraProp {PolymorphicRef<React.ElementType>} [ref] - Ref forwarded to the inner element `as` renders, not the wrapping `<li>`, typed from `as`: the DOM node for an intrinsic tag, or whatever handle a custom component exposes.\n */\nexport type MenuItemProps<T extends React.ElementType = 'a'> =\n MenuItemOwnProps &\n Omit<React.ComponentPropsWithoutRef<T>, keyof MenuItemOwnProps | 'as'> & {\n /**\n * Custom link component (e.g. `Link` from router).\n *\n * `'button'` renders `type=\"button\"` unless you pass `type=\"submit\"` or `type=\"reset\"`, so\n * an item inside a form does not submit it.\n */\n as?: T;\n };\n\n/**\n * `href` alone — annotated so a typo is a compile error rather than a silent\n * no-op, the way both siblings' sets are.\n */\nconst STRIP_FROM_NON_LINK: Readonly<Record<'href', true>> = { href: true };\n\n/**\n * The shape the implementation destructures. The public contract is the generic\n * `MenuItemProps<T>` above — the body cannot see through `T`.\n */\ntype MenuItemImplProps = MenuItemOwnProps & {\n as?: React.ElementType;\n type?: React.ButtonHTMLAttributes<HTMLButtonElement>['type'];\n};\n\n/**\n * MenuItem supports `as` prop for custom link components, e.g., react-router-dom Link.\n *\n * Give each item an `href`, a router link through `as`, or `as=\"button\"`, so\n * the keyboard can reach it: an `<a>` with no `href` isn't a link, and Tab\n * skips it.\n *\n * @function\n * @param {MenuItemProps} props - Props for the MenuItem component.\n * @param {React.Ref} ref - Forwarded ref to the inner element `as` renders.\n * @returns {JSX.Element} The rendered menu item.\n */\nexport const MenuItem = forwardRef(function MenuItem(\n itemProps: MenuItemProps,\n ref: React.Ref<HTMLElement>\n) {\n const {\n className,\n children,\n active,\n as: Component = 'a',\n 'data-testid': testId,\n style,\n id,\n title,\n role,\n tabIndex,\n ...rest\n } = itemProps as MenuItemImplProps;\n const { bulmaHelperClasses, rest: forwarded } = useBulmaClasses(rest);\n // `href` reaches an anchor or a custom component (which owns its own prop\n // contract), but not another intrinsic tag — `<span href>` is invalid HTML.\n // The same rule Avatar applies through `isLinkLike` and Button through its\n // intrinsic-only strip. Before #641 `href` was an own prop re-applied only\n // for `as=\"a\"`; deriving it from `as` must not quietly widen that.\n const isLinkLike =\n Component === 'a' ||\n typeof Component !== 'string' ||\n isCustomElement(Component);\n // `href` ALONE. `Dropdown.Item` strips every anchor-only attribute except\n // `type`; `Level.Item` strips all of them, plus `rel`.\n //\n // Not because nothing else can arrive: `as` here is an open `React.ElementType`,\n // and a non-fresh spread skips excess-property checking, so a typed caller\n // CAN deliver `target` or `download` and they are forwarded. The set stays at\n // `href` because widening it would be wrong for an open `as` — `referrerPolicy`\n // on `as=\"img\"`, `target` on `as=\"form\"` and `media` on `as=\"source\"` are all\n // legal, and a flat strip would delete them. Getting that right needs a\n // per-attribute-per-element rule, which `bestax-migrate` already models in\n // `LINK_ATTR_ELEMENTS`.\n const linkProps = isLinkLike\n ? forwarded\n : omitAttrs(forwarded, STRIP_FROM_NON_LINK);\n const itemClass = classNames(\n { [usePrefixedClassNames('is-active')]: active },\n bulmaHelperClasses\n );\n\n // Split children into label and nested MenuList(s)\n const labelChildren: React.ReactNode[] = [];\n const nestedMenuLists: React.ReactNode[] = [];\n React.Children.forEach(children, child => {\n if (React.isValidElement(child) && child.type === MenuList) {\n nestedMenuLists.push(child);\n } else {\n labelChildren.push(child);\n }\n });\n\n return (\n <li\n className={className}\n data-testid={testId}\n style={style}\n id={id}\n title={title}\n role={role}\n tabIndex={tabIndex}\n >\n <Component\n ref={ref}\n className={itemClass || undefined}\n // The active item is the current page, the way Pagination marks its\n // page. Before the spread, so an `aria-current` the caller passes\n // decides, `false` and `undefined` included. bestax-migrate converts\n // `is-active` to `active` only beside an `aria-current` of the\n // element's own, and relies on that to render the same markup.\n aria-current={active ? 'page' : undefined}\n {...linkProps}\n // A menu item inside a form must not submit it, and `<button>` defaults\n // to type=\"submit\". A sidebar menu sitting in a form is ordinary. A\n // caller's `submit` or `reset` still wins. Anything else becomes\n // `button`, since HTML reads a value it does not define for a button as\n // submit too; `buttonType` says more.\n //\n // After `linkProps`, reading through it rather than before it: React\n // treats `type={undefined}` as \"remove the attribute\", and a spread\n // carrying the key with no value is how that arrives, so a default\n // spread first would be erased by it. `Dropdown.Item` and `Avatar`\n // apply their button type after the spread too.\n {...(Component === 'button'\n ? { type: buttonType(linkProps.type) }\n : {})}\n >\n {labelChildren}\n </Component>\n {nestedMenuLists}\n </li>\n );\n}) as PolymorphicComponent<MenuItemOwnProps, 'a'>;\n\nMenuItem.displayName = 'MenuItem';\n\n/**\n * Props for the MenuSection component. The helper props and the other\n * attributes land on the wrapping `<div>`.\n */\nexport interface MenuSectionProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, keyof BulmaClassesProps>,\n BulmaClassesProps {\n /** Additional CSS classes for the wrapping `<div>`. */\n className?: string;\n /** **Required.** The section's heading, drawn like `Menu.Label` inside the button that opens and closes it. Keep links and buttons out of it, since it's inside one. */\n label: React.ReactNode;\n /**\n * The `Menu.List` of links the section shows while it's open. The section\n * itself goes directly in `Menu`, beside its labels and lists: inside a\n * `Menu.Item` it would render inside the item's link, and inside a\n * `Menu.List` it wouldn't be a list item.\n */\n children: React.ReactNode;\n /** Controlled open state. If provided, the section is controlled, and its button only reports through `onOpenChange`. */\n open?: boolean;\n /** Initial open state for uncontrolled usage. Open the section that holds the current page, so the reader sees where they are. */\n defaultOpen?: boolean;\n /** Called with the state the button asks for (`true` to open) each time it is clicked or activated with Enter or Space, in every mode. Pair it with `open` to let the button drive a controlled section. */\n onOpenChange?: (open: boolean) => void;\n}\n\n/**\n * A section of the menu that opens and closes: its heading is a button drawn like `Menu.Label`, and its `Menu.List` of links shows while it's open.\n *\n * It's APG's disclosure navigation, for a sidebar of link groups: the links\n * stay ordinary links, each its own tab stop, and a closed section's list is\n * `hidden` and `inert`, so Tab and assistive tech skip it. It goes directly in\n * `Menu`, holding a `Menu.List`. Closing it while focus is on one of its links\n * moves focus to its heading.\n *\n * @function\n * @param {MenuSectionProps} props - Props for the MenuSection component.\n * @returns {JSX.Element} The rendered menu section.\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-navigation/ | APG Disclosure Navigation Menu example}\n *\n * @example\n * <Menu>\n * <Menu.Section label=\"Components\" defaultOpen>\n * <Menu.List>\n * <Menu.Item href=\"/button\" active>Button</Menu.Item>\n * <Menu.Item href=\"/card\">Card</Menu.Item>\n * </Menu.List>\n * </Menu.Section>\n * </Menu>\n */\nexport const MenuSection: React.FC<MenuSectionProps> = ({\n className,\n label,\n children,\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const sectionClass = usePrefixedClassNames('menu-section');\n const toggleClass = usePrefixedClassNames('menu-section-toggle');\n const labelClass = usePrefixedClassNames('menu-section-label');\n const chevronClass = usePrefixedClassNames('menu-section-chevron');\n const listId = useId();\n const toggleRef = useRef<HTMLButtonElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n // The caller owns the state when `open` is set, and the section does\n // otherwise, as with Collapse. The button reports in both modes.\n const isControlled = controlledOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const isOpen = controlledOpen ?? internalOpen;\n\n const handleClick = () => {\n const next = !isOpen;\n onOpenChange?.(next);\n if (!isControlled) setInternalOpen(next);\n };\n\n // An app holding `open` can close a section while focus is on one of its\n // links, as a sidebar that keeps only the current route's section open\n // does after a link is followed. The browser then drops focus to <body>\n // a frame later, and the next Tab starts from the top of the page. The\n // heading is where the reader was, so focus goes there. A layout effect,\n // because it runs in the same task as the commit that hid the list, while\n // the link still has focus. A close from the button itself finds focus on\n // the button and leaves it.\n useClientLayoutEffect(() => {\n if (isOpen) return;\n const list = listRef.current!;\n if (list.contains(getActiveElementInTree(list))) {\n toggleRef.current!.focus();\n }\n }, [isOpen]);\n\n // A real button, so Enter and Space work with no key handler, and\n // `type=\"button\"`, so a menu inside a form isn't submitted by it.\n //\n // A closed list is `hidden`, so it isn't drawn and find-in-page doesn't\n // reach it, and `inert`, so its links stay out of Tab and assistive tech\n // even if a stylesheet sets `display` on it and shows it anyway. The markup\n // is the same from the server and on both React majors, which `inertProps`\n // sees to. It stays mounted, so `aria-controls` always names an element\n // that exists.\n return (\n <div\n className={classNames(sectionClass, bulmaHelperClasses, className)}\n {...rest}\n >\n <button\n ref={toggleRef}\n type=\"button\"\n className={toggleClass}\n aria-expanded={isOpen}\n aria-controls={listId}\n onClick={handleClick}\n >\n <span className={labelClass}>{label}</span>\n <span className={chevronClass} aria-hidden=\"true\" />\n </button>\n <div ref={listRef} id={listId} hidden={!isOpen} {...inertProps(!isOpen)}>\n {children}\n </div>\n </div>\n );\n};\n\n// Attach static subcomponents\nexport const Menu = withSubComponents(\n MenuComponent,\n {\n Label: MenuLabel,\n List: MenuList,\n Item: MenuItem,\n Section: MenuSection,\n },\n 'Menu'\n);\n\nexport default Menu;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Menu.js","sources":["../../../src/components/Menu.tsx"],"sourcesContent":["import React, {\n createContext,\n forwardRef,\n useContext,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { classNames, usePrefixedClassNames } from '../helpers/classNames';\nimport { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { omitAttrs } from '../helpers/anchorAttrs';\nimport { buttonType } from '../helpers/buttonType';\nimport { inertProps } from '../helpers/inertProps';\nimport { getActiveElementInTree } from '../helpers/shadowDom';\nimport { useClientLayoutEffect } from '../helpers/useClientLayoutEffect';\nimport {\n isCustomElement,\n type PolymorphicComponent,\n} from '../helpers/polymorphic';\n\n// Context to track MenuList nesting level\nconst MenuListLevelContext = createContext(0);\n\n/**\n * Props for the Menu component.\n */\nexport interface MenuProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>,\n BulmaClassesProps {\n /** Additional CSS classes. */\n className?: string;\n /** Menu content (labels, lists, items, etc). */\n children: React.ReactNode;\n}\n\n/**\n * The `Menu` component provides Bulma's vertical navigation menu: a simple, accessible sidebar or section menu for your Bulma React UI.\n *\n * @function\n * @param {MenuProps} props - Props for the Menu component.\n * @returns {JSX.Element} The rendered menu.\n * @see {@link https://bulma.io/documentation/components/menu/ | Bulma Menu documentation}\n */\nconst MenuComponent: React.FC<MenuProps> = ({\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n // Generate Bulma classes with prefix\n const bulmaClasses = usePrefixedClassNames('menu');\n\n return (\n <aside\n className={classNames(bulmaClasses, bulmaHelperClasses, className)}\n {...rest}\n >\n {children}\n </aside>\n );\n};\n\n/**\n * Props for the MenuLabel component.\n */\nexport interface MenuLabelProps\n extends\n Omit<React.HTMLAttributes<HTMLParagraphElement>, keyof BulmaClassesProps>,\n BulmaClassesProps {\n /** Additional CSS classes. */\n className?: string;\n /** Label content. */\n children: React.ReactNode;\n}\n\n/**\n * Bulma Menu label component.\n *\n * @function\n * @param {MenuLabelProps} props - Props for the MenuLabel component.\n * @returns {JSX.Element} The rendered menu label.\n */\nexport const MenuLabel: React.FC<MenuLabelProps> = ({\n className,\n children,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n return (\n <p\n className={classNames(\n usePrefixedClassNames('menu-label'),\n className,\n bulmaHelperClasses\n )}\n {...rest}\n >\n {children}\n </p>\n );\n};\n\n/**\n * Props for the MenuList component.\n * @extraProp {React.AriaRole} [role] - Ignored: every level renders `role=\"list\"` in its place, so a menu or tree role can't go here.\n */\nexport interface MenuListProps\n extends\n Omit<React.HTMLAttributes<HTMLUListElement>, keyof BulmaClassesProps>,\n BulmaClassesProps {\n /** Additional CSS classes. */\n className?: string;\n /** List items. */\n children: React.ReactNode;\n}\n\n/**\n * MenuList applies `menu-list` class only at the top level (not for nested lists).\n *\n * Every level renders `role=\"list\"`, which Safari needs: WebKit stops\n * exposing a `<ul>` as a list once its markers are hidden, and Bulma's reset\n * hides them.\n *\n * @function\n * @param {MenuListProps} props - Props for the MenuList component.\n * @returns {JSX.Element} The rendered menu list.\n */\nexport const MenuList: React.FC<MenuListProps> = ({\n className,\n children,\n ...props\n}) => {\n const level = useContext(MenuListLevelContext);\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n const ulClass = classNames(className, bulmaHelperClasses, {\n [usePrefixedClassNames('menu-list')]: level === 0,\n });\n\n // Increment level for nested MenuLists. role=\"list\" restates the <ul>'s\n // own role, for Safari: WebKit stops exposing a list as one once its\n // markers are hidden, as Bulma's reset hides them, unless the role is set\n // explicitly. After the spread, so a caller's role can't take it away.\n return (\n <MenuListLevelContext.Provider value={level + 1}>\n <ul className={ulClass || undefined} {...rest} role=\"list\">\n {children}\n </ul>\n </MenuListLevelContext.Provider>\n );\n};\n\n/**\n * The MenuItem component's own props.\n *\n * A menu item is two elements: a wrapping `<li>` and, inside it, the element\n * `as` names. The props here are the ones the `<li>` consumes; everything else\n * follows `as` onto the inner element.\n */\nexport interface MenuItemOwnProps extends BulmaClassesProps {\n /** Additional CSS classes for the wrapping `<li>`. */\n className?: string;\n /** Item content and optional nested MenuList. */\n children: React.ReactNode;\n /**\n * Marks the item as the current one. It adds Bulma's `is-active` class, and\n * `aria-current=\"page\"` on the element `as` renders, so assistive tech can\n * tell which item is current too. An `aria-current` you pass wins, even\n * `undefined`: use it to say something else (`\"location\"` for a section of\n * one page, say), or `aria-current={false}` to turn it off. A menu should\n * mark one page, so when the section above the current page is `active` too,\n * give it `aria-current=\"location\"`, and give an `active` item that isn't\n * navigation, such as an `as=\"button\"` filter, `aria-current={false}`.\n */\n active?: boolean;\n /** Inline styles for the wrapping `<li>`. */\n style?: React.CSSProperties;\n /** `id` for the wrapping `<li>`. */\n id?: string;\n /** `title` for the wrapping `<li>`. */\n title?: string;\n /** ARIA role for the wrapping `<li>`. */\n role?: React.AriaRole;\n /** Tab index for the wrapping `<li>`. */\n tabIndex?: number;\n /** Test id for the wrapping `<li>`. */\n 'data-testid'?: string;\n}\n\n/**\n * Props for the MenuItem component. Everything the `<li>` does not consume\n * follows `as` onto the inner element: with the default `'a'` that means `href`\n * and the other anchor attributes, and with `as={Link}` it means that\n * component's own props.\n *\n * @extraProp {PolymorphicRef<React.ElementType>} [ref] - Ref forwarded to the inner element `as` renders, not the wrapping `<li>`, typed from `as`: the DOM node for an intrinsic tag, or whatever handle a custom component exposes.\n */\nexport type MenuItemProps<T extends React.ElementType = 'a'> =\n MenuItemOwnProps &\n Omit<React.ComponentPropsWithoutRef<T>, keyof MenuItemOwnProps | 'as'> & {\n /**\n * Custom link component (e.g. `Link` from router).\n *\n * `'button'` renders `type=\"button\"` unless you pass `type=\"submit\"` or `type=\"reset\"`, so\n * an item inside a form does not submit it.\n */\n as?: T;\n };\n\n/**\n * `href` alone — annotated so a typo is a compile error rather than a silent\n * no-op, the way both siblings' sets are.\n */\nconst STRIP_FROM_NON_LINK: Readonly<Record<'href', true>> = { href: true };\n\n/**\n * The shape the implementation destructures. The public contract is the generic\n * `MenuItemProps<T>` above — the body cannot see through `T`.\n */\ntype MenuItemImplProps = MenuItemOwnProps & {\n as?: React.ElementType;\n type?: React.ButtonHTMLAttributes<HTMLButtonElement>['type'];\n};\n\n/**\n * MenuItem supports `as` prop for custom link components, e.g., react-router-dom Link.\n *\n * Give each item an `href`, a router link through `as`, or `as=\"button\"`, so\n * the keyboard can reach it: an `<a>` with no `href` isn't a link, and Tab\n * skips it.\n *\n * @function\n * @param {MenuItemProps} props - Props for the MenuItem component.\n * @param {React.Ref} ref - Forwarded ref to the inner element `as` renders.\n * @returns {JSX.Element} The rendered menu item.\n */\nexport const MenuItem = forwardRef(function MenuItem(\n itemProps: MenuItemProps,\n ref: React.Ref<HTMLElement>\n) {\n const {\n className,\n children,\n active,\n as: Component = 'a',\n 'data-testid': testId,\n style,\n id,\n title,\n role,\n tabIndex,\n ...rest\n } = itemProps as MenuItemImplProps;\n const { bulmaHelperClasses, rest: forwarded } = useBulmaClasses(rest);\n // `href` reaches an anchor or a custom component (which owns its own prop\n // contract), but not another intrinsic tag — `<span href>` is invalid HTML.\n // The same rule Avatar applies through `isLinkLike` and Button through its\n // intrinsic-only strip. Before #641 `href` was an own prop re-applied only\n // for `as=\"a\"`; deriving it from `as` must not quietly widen that.\n const isLinkLike =\n Component === 'a' ||\n typeof Component !== 'string' ||\n isCustomElement(Component);\n // `href` ALONE. `Dropdown.Item` strips every anchor-only attribute except\n // `type`; `Level.Item` strips all of them, plus `rel`.\n //\n // Not because nothing else can arrive: `as` here is an open `React.ElementType`,\n // and a non-fresh spread skips excess-property checking, so a typed caller\n // CAN deliver `target` or `download` and they are forwarded. The set stays at\n // `href` because widening it would be wrong for an open `as` — `referrerPolicy`\n // on `as=\"img\"`, `target` on `as=\"form\"` and `media` on `as=\"source\"` are all\n // legal, and a flat strip would delete them. Getting that right needs a\n // per-attribute-per-element rule, which `bestax-migrate` already models in\n // `LINK_ATTR_ELEMENTS`.\n const linkProps = isLinkLike\n ? forwarded\n : omitAttrs(forwarded, STRIP_FROM_NON_LINK);\n const itemClass = classNames(\n { [usePrefixedClassNames('is-active')]: active },\n bulmaHelperClasses\n );\n\n // Split children into label and nested MenuList(s)\n const labelChildren: React.ReactNode[] = [];\n const nestedMenuLists: React.ReactNode[] = [];\n React.Children.forEach(children, child => {\n if (React.isValidElement(child) && child.type === MenuList) {\n nestedMenuLists.push(child);\n } else {\n labelChildren.push(child);\n }\n });\n\n return (\n <li\n className={className}\n data-testid={testId}\n style={style}\n id={id}\n title={title}\n role={role}\n tabIndex={tabIndex}\n >\n <Component\n ref={ref}\n className={itemClass || undefined}\n // The active item is the current page, the way Pagination marks its\n // page. Before the spread, so an `aria-current` the caller passes\n // decides, `false` and `undefined` included. bestax-migrate converts\n // `is-active` to `active` only beside an `aria-current` of the\n // element's own, and relies on that to render the same markup.\n aria-current={active ? 'page' : undefined}\n {...linkProps}\n // A menu item inside a form must not submit it, and `<button>` defaults\n // to type=\"submit\". A sidebar menu sitting in a form is ordinary. A\n // caller's `submit` or `reset` still wins. Anything else becomes\n // `button`, since HTML reads a value it does not define for a button as\n // submit too; `buttonType` says more.\n //\n // After `linkProps`, reading through it rather than before it: React\n // treats `type={undefined}` as \"remove the attribute\", and a spread\n // carrying the key with no value is how that arrives, so a default\n // spread first would be erased by it. `Dropdown.Item` and `Avatar`\n // apply their button type after the spread too.\n {...(Component === 'button'\n ? { type: buttonType(linkProps.type) }\n : {})}\n >\n {labelChildren}\n </Component>\n {nestedMenuLists}\n </li>\n );\n}) as PolymorphicComponent<MenuItemOwnProps, 'a'>;\n\nMenuItem.displayName = 'MenuItem';\n\n/**\n * Props for the MenuSection component. The helper props and the other\n * attributes land on the wrapping `<div>`.\n */\nexport interface MenuSectionProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, keyof BulmaClassesProps>,\n BulmaClassesProps {\n /** Additional CSS classes for the wrapping `<div>`. */\n className?: string;\n /** **Required.** The section's heading, drawn like `Menu.Label` inside the button that opens and closes it. Keep links and buttons out of it, since it's inside one. */\n label: React.ReactNode;\n /**\n * The `Menu.List` of links the section shows while it's open. The section\n * itself goes directly in `Menu`, beside its labels and lists: inside a\n * `Menu.Item` it would render inside the item's link, and inside a\n * `Menu.List` it wouldn't be a list item.\n */\n children: React.ReactNode;\n /** Controlled open state. If provided, the section is controlled, and its button only reports through `onOpenChange`. */\n open?: boolean;\n /** Initial open state for uncontrolled usage. Open the section that holds the current page, so the reader sees where they are. */\n defaultOpen?: boolean;\n /** Called with the state the button asks for (`true` to open) each time it is clicked or activated with Enter or Space, in every mode. Pair it with `open` to let the button drive a controlled section. */\n onOpenChange?: (open: boolean) => void;\n}\n\n/**\n * A section of the menu that opens and closes: its heading is a button drawn like `Menu.Label`, and its `Menu.List` of links shows while it's open.\n *\n * It's APG's disclosure navigation, for a sidebar of link groups: the links\n * stay ordinary links, each its own tab stop, and a closed section's list is\n * `hidden` and `inert`, so Tab and assistive tech skip it. It goes directly in\n * `Menu`, holding a `Menu.List`. Closing it while focus is on one of its links\n * moves focus to its heading.\n *\n * @function\n * @param {MenuSectionProps} props - Props for the MenuSection component.\n * @returns {JSX.Element} The rendered menu section.\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-navigation/ | APG Disclosure Navigation Menu example}\n *\n * @example\n * <Menu>\n * <Menu.Section label=\"Components\" defaultOpen>\n * <Menu.List>\n * <Menu.Item href=\"/button\" active>Button</Menu.Item>\n * <Menu.Item href=\"/card\">Card</Menu.Item>\n * </Menu.List>\n * </Menu.Section>\n * </Menu>\n */\nexport const MenuSection: React.FC<MenuSectionProps> = ({\n className,\n label,\n children,\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n ...props\n}) => {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n const sectionClass = usePrefixedClassNames('menu-section');\n const toggleClass = usePrefixedClassNames('menu-section-toggle');\n const labelClass = usePrefixedClassNames('menu-section-label');\n const chevronClass = usePrefixedClassNames('menu-section-chevron');\n const listId = useId();\n const toggleRef = useRef<HTMLButtonElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n\n // The caller owns the state when `open` is set, and the section does\n // otherwise, as with Collapse. The button reports in both modes.\n const isControlled = controlledOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const isOpen = controlledOpen ?? internalOpen;\n\n const handleClick = () => {\n const next = !isOpen;\n onOpenChange?.(next);\n if (!isControlled) setInternalOpen(next);\n };\n\n // An app holding `open` can close a section while focus is on one of its\n // links, as a sidebar that keeps only the current route's section open\n // does after a link is followed. The browser then drops focus to <body>\n // a frame later, and the next Tab starts from the top of the page. The\n // heading is where the reader was, so focus goes there. A layout effect,\n // because it runs in the same task as the commit that hid the list, while\n // the link still has focus. A close from the button itself finds focus on\n // the button and leaves it.\n useClientLayoutEffect(() => {\n if (isOpen) return;\n const list = listRef.current!;\n if (list.contains(getActiveElementInTree(list))) {\n toggleRef.current!.focus();\n }\n }, [isOpen]);\n\n // A real button, so Enter and Space work with no key handler, and\n // `type=\"button\"`, so a menu inside a form isn't submitted by it.\n //\n // A closed list is `hidden`, so it isn't drawn and find-in-page doesn't\n // reach it, and `inert`, so its links stay out of Tab and assistive tech\n // even if a stylesheet sets `display` on it and shows it anyway. The markup\n // is the same from the server and on both React majors, which `inertProps`\n // sees to. It stays mounted, so `aria-controls` always names an element\n // that exists.\n return (\n <div\n className={classNames(sectionClass, bulmaHelperClasses, className)}\n {...rest}\n >\n <button\n ref={toggleRef}\n type=\"button\"\n className={toggleClass}\n aria-expanded={isOpen}\n aria-controls={listId}\n onClick={handleClick}\n >\n <span className={labelClass}>{label}</span>\n <span className={chevronClass} aria-hidden=\"true\" />\n </button>\n <div ref={listRef} id={listId} hidden={!isOpen} {...inertProps(!isOpen)}>\n {children}\n </div>\n </div>\n );\n};\n\n// Attach static subcomponents\nexport const Menu = withSubComponents(\n MenuComponent,\n {\n Label: MenuLabel,\n List: MenuList,\n Item: MenuItem,\n Section: MenuSection,\n },\n 'Menu'\n);\n\nexport default Menu;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
'use client';
|
|
2
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
4
|
import { classNames, usePrefixedClassNames, prefixedClassNames } from '../helpers/classNames.js';
|
|
4
5
|
import { withSubComponents } from '../helpers/withSubComponents.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Message.js","sources":["../../../src/components/Message.tsx"],"sourcesContent":["import React from 'react';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { useConfig } from '../helpers/Config';\n\nconst validMessageSizes = ['small', 'medium', 'large'] as const;\n/**\n * Valid size values for the Message component (Bulma message sizes).\n */\nexport type MessageSize = (typeof validMessageSizes)[number];\n\n/**\n * Props for the Message component.\n */\nexport interface MessageProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, 'title'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor' | 'size'> {\n /** Additional CSS classes. */\n className?: string;\n /** Title string/node (renders header section). */\n title?: React.ReactNode;\n /** Text color for the message (Bulma helper). */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Bulma color modifier for the message. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color for the message (Bulma helper). */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Size of the message. */\n size?: MessageSize;\n /** Callback for the close (\"X\") button. */\n onClose?: () => void;\n /** Body content for the message. */\n children?: React.ReactNode;\n}\n\n/**\n * The `Message` component provides Bulma's flexible notice/message box for your Bulma React UI.\n *\n * @function\n * @param {MessageProps} props - Props for the Message component.\n * @returns {JSX.Element} The rendered message.\n * @see {@link https://bulma.io/documentation/components/message/ | Bulma Message documentation}\n */\nconst MessageComponent: React.FC<MessageProps> = ({\n className,\n title,\n textColor,\n color,\n bgColor,\n size,\n onClose,\n children,\n ...props\n}) => {\n const { classPrefix } = useConfig();\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n // Generate Bulma classes with prefix\n const bulmaClasses = usePrefixedClassNames('message', {\n [`is-${color}`]: color,\n [`is-${size}`]: size && validMessageSizes.includes(size),\n });\n const deleteClass = usePrefixedClassNames('delete');\n\n const messageClasses = classNames(\n bulmaClasses,\n bulmaHelperClasses,\n className\n );\n\n return (\n <article className={messageClasses} {...rest} data-testid=\"message\">\n {(title || onClose) && (\n <div className={prefixedClassNames(classPrefix, 'message-header')}>\n {title && <span>{title}</span>}\n {onClose && (\n <button\n className={deleteClass}\n aria-label=\"delete\"\n onClick={onClose}\n type=\"button\"\n data-testid=\"message-close\"\n />\n )}\n </div>\n )}\n {children && (\n <div\n className={prefixedClassNames(classPrefix, 'message-body')}\n data-testid=\"message-body\"\n >\n {children}\n </div>\n )}\n </article>\n );\n};\n\n// Compound components for flexible composition\n\n/**\n * Props for the Message.Header compound component.\n */\nexport interface MessageHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n /** Header content (title, close button, etc.). */\n children?: React.ReactNode;\n}\n\n/**\n * Props for the Message.Body compound component.\n */\nexport interface MessageBodyProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n /** Message body content. */\n children?: React.ReactNode;\n}\n\n/**\n * Message header compound component. Renders a `.message-header` element.\n *\n * @function\n * @param {MessageHeaderProps} props - Props for the MessageHeader component.\n * @returns {JSX.Element} The rendered message header.\n */\nconst MessageHeader: React.FC<MessageHeaderProps> = ({\n className,\n children,\n ...props\n}) => (\n <div\n className={classNames(usePrefixedClassNames('message-header'), className)}\n {...props}\n >\n {children}\n </div>\n);\n\n/**\n * Message body compound component. Renders a `.message-body` element.\n *\n * @function\n * @param {MessageBodyProps} props - Props for the MessageBody component.\n * @returns {JSX.Element} The rendered message body.\n */\nconst MessageBody: React.FC<MessageBodyProps> = ({\n className,\n children,\n ...props\n}) => (\n <div\n className={classNames(usePrefixedClassNames('message-body'), className)}\n {...props}\n >\n {children}\n </div>\n);\n\n// Attach compound components\nexport const Message = withSubComponents(\n MessageComponent,\n {\n Header: MessageHeader,\n Body: MessageBody,\n },\n 'Message'\n);\n\nexport default Message;\n"],"names":["_jsxs","_jsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Message.js","sources":["../../../src/components/Message.tsx"],"sourcesContent":["import React from 'react';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { useConfig } from '../helpers/Config';\n\nconst validMessageSizes = ['small', 'medium', 'large'] as const;\n/**\n * Valid size values for the Message component (Bulma message sizes).\n */\nexport type MessageSize = (typeof validMessageSizes)[number];\n\n/**\n * Props for the Message component.\n */\nexport interface MessageProps\n extends\n Omit<React.HTMLAttributes<HTMLElement>, 'title'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor' | 'size'> {\n /** Additional CSS classes. */\n className?: string;\n /** Title string/node (renders header section). */\n title?: React.ReactNode;\n /** Text color for the message (Bulma helper). */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Bulma color modifier for the message. */\n color?: 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';\n /** Background color for the message (Bulma helper). */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Size of the message. */\n size?: MessageSize;\n /** Callback for the close (\"X\") button. */\n onClose?: () => void;\n /** Body content for the message. */\n children?: React.ReactNode;\n}\n\n/**\n * The `Message` component provides Bulma's flexible notice/message box for your Bulma React UI.\n *\n * @function\n * @param {MessageProps} props - Props for the Message component.\n * @returns {JSX.Element} The rendered message.\n * @see {@link https://bulma.io/documentation/components/message/ | Bulma Message documentation}\n */\nconst MessageComponent: React.FC<MessageProps> = ({\n className,\n title,\n textColor,\n color,\n bgColor,\n size,\n onClose,\n children,\n ...props\n}) => {\n const { classPrefix } = useConfig();\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n // Generate Bulma classes with prefix\n const bulmaClasses = usePrefixedClassNames('message', {\n [`is-${color}`]: color,\n [`is-${size}`]: size && validMessageSizes.includes(size),\n });\n const deleteClass = usePrefixedClassNames('delete');\n\n const messageClasses = classNames(\n bulmaClasses,\n bulmaHelperClasses,\n className\n );\n\n return (\n <article className={messageClasses} {...rest} data-testid=\"message\">\n {(title || onClose) && (\n <div className={prefixedClassNames(classPrefix, 'message-header')}>\n {title && <span>{title}</span>}\n {onClose && (\n <button\n className={deleteClass}\n aria-label=\"delete\"\n onClick={onClose}\n type=\"button\"\n data-testid=\"message-close\"\n />\n )}\n </div>\n )}\n {children && (\n <div\n className={prefixedClassNames(classPrefix, 'message-body')}\n data-testid=\"message-body\"\n >\n {children}\n </div>\n )}\n </article>\n );\n};\n\n// Compound components for flexible composition\n\n/**\n * Props for the Message.Header compound component.\n */\nexport interface MessageHeaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n /** Header content (title, close button, etc.). */\n children?: React.ReactNode;\n}\n\n/**\n * Props for the Message.Body compound component.\n */\nexport interface MessageBodyProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n /** Message body content. */\n children?: React.ReactNode;\n}\n\n/**\n * Message header compound component. Renders a `.message-header` element.\n *\n * @function\n * @param {MessageHeaderProps} props - Props for the MessageHeader component.\n * @returns {JSX.Element} The rendered message header.\n */\nconst MessageHeader: React.FC<MessageHeaderProps> = ({\n className,\n children,\n ...props\n}) => (\n <div\n className={classNames(usePrefixedClassNames('message-header'), className)}\n {...props}\n >\n {children}\n </div>\n);\n\n/**\n * Message body compound component. Renders a `.message-body` element.\n *\n * @function\n * @param {MessageBodyProps} props - Props for the MessageBody component.\n * @returns {JSX.Element} The rendered message body.\n */\nconst MessageBody: React.FC<MessageBodyProps> = ({\n className,\n children,\n ...props\n}) => (\n <div\n className={classNames(usePrefixedClassNames('message-body'), className)}\n {...props}\n >\n {children}\n </div>\n);\n\n// Attach compound components\nexport const Message = withSubComponents(\n MessageComponent,\n {\n Header: MessageHeader,\n Body: MessageBody,\n },\n 'Message'\n);\n\nexport default Message;\n"],"names":["_jsxs","_jsx"],"mappings":";;;;;;;;AAcA,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAU;AA+B/D;;;;;;;AAOG;AACH,MAAM,gBAAgB,GAA2B,CAAC,EAChD,SAAS,EACT,KAAK,EACL,SAAS,EACT,KAAK,EACL,OAAO,EACP,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,GAAG,KAAK,EACT,KAAI;AACH,IAAA,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,EAAE;AACnC,IAAA,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC;AACnD,QAAA,KAAK,EAAE,SAAS;AAChB,QAAA,eAAe,EAAE,OAAO;AACxB,QAAA,GAAG,KAAK;AACT,KAAA,CAAC;;AAGF,IAAA,MAAM,YAAY,GAAG,qBAAqB,CAAC,SAAS,EAAE;AACpD,QAAA,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,GAAG,KAAK;AACtB,QAAA,CAAC,CAAA,GAAA,EAAM,IAAI,CAAA,CAAE,GAAG,IAAI,IAAI,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC;AACzD,KAAA,CAAC;AACF,IAAA,MAAM,WAAW,GAAG,qBAAqB,CAAC,QAAQ,CAAC;IAEnD,MAAM,cAAc,GAAG,UAAU,CAC/B,YAAY,EACZ,kBAAkB,EAClB,SAAS,CACV;AAED,IAAA,QACEA,IAAA,CAAA,SAAA,EAAA,EAAS,SAAS,EAAE,cAAc,KAAM,IAAI,EAAA,aAAA,EAAc,SAAS,EAAA,QAAA,EAAA,CAChE,CAAC,KAAK,IAAI,OAAO,MAChBA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,kBAAkB,CAAC,WAAW,EAAE,gBAAgB,CAAC,EAAA,QAAA,EAAA,CAC9D,KAAK,IAAIC,GAAA,CAAA,MAAA,EAAA,EAAA,QAAA,EAAO,KAAK,EAAA,CAAQ,EAC7B,OAAO,KACNA,GAAA,CAAA,QAAA,EAAA,EACE,SAAS,EAAE,WAAW,gBACX,QAAQ,EACnB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAC,QAAQ,iBACD,eAAe,EAAA,CAC3B,CACH,CAAA,EAAA,CACG,CACP,EACA,QAAQ,KACPA,aACE,SAAS,EAAE,kBAAkB,CAAC,WAAW,EAAE,cAAc,CAAC,EAAA,aAAA,EAC9C,cAAc,EAAA,QAAA,EAEzB,QAAQ,GACL,CACP,CAAA,EAAA,CACO;AAEd,CAAC;AAwBD;;;;;;AAMG;AACH,MAAM,aAAa,GAAiC,CAAC,EACnD,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,MACCA,GAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,UAAU,CAAC,qBAAqB,CAAC,gBAAgB,CAAC,EAAE,SAAS,CAAC,KACrE,KAAK,EAAA,QAAA,EAER,QAAQ,EAAA,CACL,CACP;AAED;;;;;;AAMG;AACH,MAAM,WAAW,GAA+B,CAAC,EAC/C,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,MACCA,GAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,UAAU,CAAC,qBAAqB,CAAC,cAAc,CAAC,EAAE,SAAS,CAAC,KACnE,KAAK,EAAA,QAAA,EAER,QAAQ,EAAA,CACL,CACP;AAED;AACO,MAAM,OAAO,GAAG,iBAAiB,CACtC,gBAAgB,EAChB;AACE,IAAA,MAAM,EAAE,aAAa;AACrB,IAAA,IAAI,EAAE,WAAW;CAClB,EACD,SAAS;;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
'use client';
|
|
2
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
4
|
import React, { createContext, forwardRef, useRef, useCallback, useId, useEffect, useContext } from 'react';
|
|
4
5
|
import { createPortal } from 'react-dom';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.js","sources":["../../../src/components/Modal.tsx"],"sourcesContent":["import React, {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useRef,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { buttonType } from '../helpers/buttonType';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { useConfig } from '../helpers/Config';\nimport { useScrollLock } from '../helpers/scrollLock';\nimport {\n getActiveElementInTree,\n getDeepestActiveElement,\n} from '../helpers/shadowDom';\nimport { usePortalContainer } from '../helpers/portal';\nimport { LocalePortalScope } from '../helpers/LocaleProvider';\nimport { useIsHydrated } from '../helpers/useIsHydrated';\nimport { useLatestRef } from '../helpers/useLatestRef';\nimport { useOverlayStack } from '../helpers/overlayStack';\nimport { focusTabStop, trapTab } from '../helpers/useFocusTrap';\n\n/**\n * Props for the Modal component.\n * @extraProp {React.Ref<HTMLDivElement>} [ref] - Ref forwarded to the root `.modal` element.\n */\nexport interface ModalProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'title'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Whether the modal is open/visible. */\n active?: boolean;\n /** Alias for `active`. Whether the modal is open/visible. */\n isActive?: boolean; // Alias for active\n /**\n * Called to ask for the modal to close. The props form calls it from the\n * background and the close button it renders. In the compound form,\n * `Modal.Close` calls it unless you give it an `onClick` of your own, and\n * `Modal.Background` doesn't call it on its own: pass it\n * `onClick={onClose}` for a click on the background to close the modal.\n * Escape calls it in both forms unless `closeOnEscape` is `false`.\n */\n onClose?: () => void;\n /** Additional CSS classes for the modal. */\n className?: string;\n /** Text color for modal content. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color for modal content. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Title/header for modal-card variant. (Legacy API only) */\n modalCardTitle?: React.ReactNode;\n /** Footer for modal-card variant. (Legacy API only) */\n modalCardFoot?: React.ReactNode;\n /**\n * Modal style: `'card'` for modal-card, `'content'` for modal-content. (Legacy API only)\n * @defaultValue auto\n */\n type?: 'card' | 'content';\n /** Modal body/content or compound components. */\n children?: React.ReactNode;\n /**\n * Close the modal when the Escape key is pressed (calls `onClose`). Only the\n * topmost open overlay responds, whichever Modal, Dialog, Sidebar or\n * full-page Loading opened last, so Escape closes one layer at a time. The\n * modal marks the Escape it closes on as used with `preventDefault()`, and\n * a Toast waits until no overlay is open. Turned off, a modal on top still\n * keeps Escape from the layers under it. A popup inside it, such as a\n * Dropdown's menu or a date picker's calendar, takes its own Escape first,\n * and so does content that calls `preventDefault()` on it.\n * @defaultValue true\n */\n closeOnEscape?: boolean;\n /**\n * Lock body scroll while the modal is active. Ref-counted and shared with\n * `Dialog`, `Sidebar` and `Loading`, so whichever overlay closes first does\n * not unlock the page underneath one that is still open.\n * @defaultValue true\n */\n lockScroll?: boolean;\n /**\n * Renders the modal into a portal target instead of inline, so it isn't\n * clipped by an ancestor with `overflow: hidden`, `filter` or `transform`.\n * `true` portals to the `portalContainer` a `ConfigProvider` sets,\n * `document.body` by default; a string is used as a\n * `document.querySelector` selector; an element is used directly. Renders\n * inline on the server and while hydrating, moving into the portal once the\n * client takes over, so hydration matches.\n * @defaultValue false\n */\n portal?: boolean | string | HTMLElement;\n}\n\n/**\n * Props for Modal.Background component.\n * @extraProp {React.MouseEventHandler<HTMLDivElement>} [onClick] - Called when the background is clicked. The background doesn't call the modal's `onClose` on its own, so pass `onClick={onClose}` for a click on it to close the modal.\n */\nexport interface ModalBackgroundProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Content component.\n */\nexport interface ModalContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card component.\n */\nexport interface ModalCardProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card.Head component.\n */\nexport interface ModalCardHeadProps extends React.HTMLAttributes<HTMLElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card.Title component.\n */\nexport interface ModalCardTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card.Body component.\n */\nexport interface ModalCardBodyProps extends React.HTMLAttributes<HTMLElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card.Foot component.\n */\nexport interface ModalCardFootProps extends React.HTMLAttributes<HTMLElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Close component.\n * @extraProp {'button' | 'submit' | 'reset'} [type='button'] - Button type. Defaults to `'button'`, so a close button inside a form does not submit it. Pass `'submit'` or `'reset'` and yours is used; any other value, or a spread carrying `type: undefined`, renders `'button'`.\n * @extraProp {string} [aria-label='close'] - Accessible name. Pass your own to replace it. An empty one, or a spread carrying `'aria-label': undefined`, keeps the default rather than leaving the button unnamed.\n * @extraProp {React.MouseEventHandler<HTMLButtonElement>} [onClick] - Called when the button is clicked. Without one, the button calls the `onClose` of the `Modal` around it. Yours replaces that rather than running before it, so call `onClose` from it if the button should still close the modal.\n */\nexport interface ModalCloseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Additional CSS classes. */\n className?: string;\n /** Size of the close button (only applies to 'floating' variant). */\n size?: 'small' | 'medium' | 'large';\n /** Button variant. 'delete' (default) for modal card headers, 'floating' for overlay close button. */\n variant?: 'delete' | 'floating';\n}\n\n// The enclosing modal's `onClose`, for a `Modal.Close` written as a part, so\n// it closes the modal the way the button the props form renders does.\nconst ModalCloseContext = createContext<(() => void) | undefined>(undefined);\n\n/**\n * Modal.Background - Renders the modal background overlay. Pass it\n * `onClick={onClose}` for a click on it to close the modal.\n *\n * @function\n * @param {ModalBackgroundProps} props - Component props.\n * @returns {JSX.Element} Modal background element.\n */\nconst ModalBackground: React.FC<ModalBackgroundProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-background'),\n className\n );\n return <div className={classes} {...props} />;\n};\n\n/**\n * Modal.Content - Renders modal content wrapper for custom content.\n *\n * @function\n * @param {ModalContentProps} props - Component props.\n * @returns {JSX.Element} Modal content element.\n */\nconst ModalContent: React.FC<ModalContentProps> = ({ className, ...props }) => {\n const classes = classNames(usePrefixedClassNames('modal-content'), className);\n return <div className={classes} {...props} />;\n};\n\n/**\n * Modal.Card.Head - Renders modal card header section.\n *\n * @function\n * @param {ModalCardHeadProps} props - Component props.\n * @returns {JSX.Element} Modal card header element.\n */\nconst ModalCardHead: React.FC<ModalCardHeadProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-card-head'),\n className\n );\n return <header className={classes} {...props} />;\n};\n\n/**\n * Modal.Card.Title - Renders modal card title.\n *\n * @function\n * @param {ModalCardTitleProps} props - Component props.\n * @returns {JSX.Element} Modal card title element.\n */\nconst ModalCardTitle: React.FC<ModalCardTitleProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-card-title'),\n className\n );\n return <p className={classes} {...props} />;\n};\n\n/**\n * Modal.Card.Body - Renders modal card body section.\n *\n * @function\n * @param {ModalCardBodyProps} props - Component props.\n * @returns {JSX.Element} Modal card body element.\n */\nconst ModalCardBody: React.FC<ModalCardBodyProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-card-body'),\n className\n );\n return <section className={classes} {...props} />;\n};\n\n/**\n * Modal.Card.Foot - Renders modal card footer section.\n *\n * @function\n * @param {ModalCardFootProps} props - Component props.\n * @returns {JSX.Element} Modal card footer element.\n */\nconst ModalCardFoot: React.FC<ModalCardFootProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-card-foot'),\n className\n );\n return <footer className={classes} {...props} />;\n};\n\n/**\n * Modal.Card - Renders modal card wrapper with compound components.\n * Use with Modal.Card.Head, Modal.Card.Title, Modal.Card.Body, and Modal.Card.Foot.\n *\n * @function\n * @param {ModalCardProps} props - Component props.\n * @returns {JSX.Element} Modal card element.\n */\nconst ModalCardComponent: React.FC<ModalCardProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(usePrefixedClassNames('modal-card'), className);\n return <div className={classes} {...props} />;\n};\n\nconst ModalCard = withSubComponents(ModalCardComponent, {\n Head: ModalCardHead,\n Title: ModalCardTitle,\n Body: ModalCardBody,\n Foot: ModalCardFoot,\n});\n\n/**\n * Modal.Close - Renders modal close button with two variant styles. It calls\n * the modal's `onClose` unless given an `onClick` of its own.\n *\n * @function\n * @param {ModalCloseProps} props - Component props.\n * @returns {JSX.Element} Close button element.\n *\n * @remarks\n * Supports two variants:\n * - 'delete' (default): For use in modal card headers, renders with 'delete' class\n * - 'floating': For floating overlay close button, renders with 'modal-close' class\n *\n * The size prop only applies to the 'floating' variant.\n */\nconst ModalClose: React.FC<ModalCloseProps> = ({\n className,\n size = 'large',\n variant = 'delete',\n onClick,\n ...props\n}) => {\n const onClose = useContext(ModalCloseContext);\n const classes = classNames(\n usePrefixedClassNames(\n variant === 'delete' ? 'delete' : 'modal-close',\n variant === 'floating' && size && { [`is-${size}`]: true }\n ),\n className\n );\n return (\n <button\n className={classes}\n {...props}\n // After the spread, reading through it: a key the spread carries with no\n // value would otherwise erase the default, leaving a nameless button\n // that submits the form around it. An empty label falls back too: the\n // button is drawn as an icon, so `''` would leave it unnamed. A caller's\n // own value still wins; `buttonType` says more.\n aria-label={props['aria-label'] || 'close'}\n type={buttonType(props.type)}\n // A caller's own `onClick` replaces the close rather than running\n // before it, unlike `Popover.Close`: this button used to close only\n // through that handler, so a caller already closing there, as with\n // `onClick={onClose}`, would otherwise close twice.\n onClick={onClick ?? (onClose && (() => onClose()))}\n />\n );\n};\n\n/**\n * The `Modal` component provides an empty, accessible overlay for arbitrary content — for a ready-made confirm or alert, reach for `Dialog` instead.\n *\n * @function\n * @param {ModalProps} props - Props for the Modal component.\n * @returns {JSX.Element} The rendered modal.\n *\n * @example\n * // Legacy API\n * <Modal active={isOpen} onClose={handleClose} modalCardTitle=\"Title\">\n * Content\n * </Modal>\n *\n * @example\n * // Compound Component API\n * <Modal isActive={isOpen} onClose={handleClose}>\n * <Modal.Background onClick={handleClose} />\n * <Modal.Card>\n * <Modal.Card.Head>\n * <Modal.Card.Title>Title</Modal.Card.Title>\n * <Modal.Close />\n * </Modal.Card.Head>\n * <Modal.Card.Body>Content</Modal.Card.Body>\n * </Modal.Card>\n * </Modal>\n *\n * @see {@link https://bulma.io/documentation/components/modal/ | Bulma Modal documentation}\n */\nconst ModalRoot = forwardRef<HTMLDivElement, ModalProps>(function ModalRoot(\n {\n active,\n isActive,\n onClose,\n className,\n textColor,\n bgColor,\n modalCardTitle,\n modalCardFoot,\n type,\n children,\n closeOnEscape = true,\n lockScroll = true,\n portal = false,\n role,\n 'aria-modal': ariaModalProp,\n ...props\n },\n ref\n) {\n const { classPrefix, portalContainer } = useConfig();\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n // Support both active and isActive props\n const isModalActive = active ?? isActive ?? false;\n\n const modalRootRef = useRef<HTMLDivElement>(null);\n\n // Cleanup returned by a consumer's callback ref on attach, held until detach.\n const consumerCleanupRef = useRef<(() => void) | null>(null);\n\n // The forwarded ref and the internal one must both see the node: focus\n // management and the Tab trap read `modalRootRef`, while consumers expect\n // their own ref to resolve.\n const combinedRef = useCallback(\n (node: HTMLDivElement | null) => {\n (modalRootRef as React.MutableRefObject<HTMLDivElement | null>).current =\n node;\n if (typeof ref === 'function') {\n // React 19 lets a callback ref return a cleanup function and detaches\n // by running it instead of calling the ref with `null`; React 18\n // discards the return value entirely. Returning it from here would be\n // a React-19-only contract, so instead we hold the cleanup and run it\n // ourselves on detach — a consumer's cleanup ref then behaves the same\n // on both majors of the CI matrix. Same shape as `Dropdown`.\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 const previouslyFocusedRef = useRef<HTMLElement | null>(null);\n const generatedTitleId = useId();\n // A portal has no server-rendered counterpart, so the server render and the\n // hydrating render have to stay inline and only move into the portal once\n // we're past hydration.\n const onClient = useIsHydrated();\n const resolveContainer = usePortalContainer();\n // Moving into the portal, or from one portal target to another, remounts\n // the modal's subtree, so any effect holding a DOM node from before the move\n // is holding a detached one. Effects that touch the modal's nodes key on\n // this, on `portal` and on `defaultTarget`, so they re-run against the new\n // tree.\n const isPortaled = Boolean(portal) && onClient;\n // The configured `portalContainer` only places a modal portaled with\n // `portal` set to `true`. In place, or with a target of its own, a change\n // to it moves nothing, so it mustn't re-run the effects either.\n const defaultTarget =\n isPortaled && portal === true ? portalContainer : undefined;\n\n useScrollLock(isModalActive && lockScroll);\n\n // Read when Escape arrives, so the key listener stays put while `onClose`\n // changes identity, as an inline one does on every render of the parent.\n const onCloseRef = useLatestRef(onClose);\n\n // Joins the stack of open overlays, so the keyboard handling below only\n // applies while this modal is on top.\n const isTopmost = useOverlayStack(isModalActive);\n\n // Escape closes, only for the topmost overlay. The listener is on\n // `window`, where a keydown arrives last, so everything inside the modal\n // has had the key first: React's handlers, and `document` listeners added\n // after this one, such as a date picker's.\n useEffect(() => {\n if (!isModalActive) return undefined;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Escape' || !isTopmost()) return;\n // Something inside already used this Escape, such as a popup that\n // closed on it, so the modal waits for the next one. One the modal\n // closes on is marked used, so nothing under it acts on it as well.\n if (closeOnEscape && onCloseRef.current && !e.defaultPrevented) {\n e.preventDefault();\n onCloseRef.current();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [isModalActive, closeOnEscape, onCloseRef, isTopmost]);\n\n // Keep Tab within the modal: `aria-modal` hides the rest of the page from\n // assistive technology, so the keyboard order has to agree. Only while\n // it's the topmost modal overlay, so an overlay that isn't modal, such as\n // a Sidebar without an overlay, takes Escape from it but leaves it Tab.\n // It's the trap `useFocusTrap` sets, so it wraps at the stops Tab really\n // visits, skipping hidden, inert and closed content, and sends back a Tab\n // the browser still takes out. On `window` for the same reason as Escape:\n // a trap inside, such as a portaled popup's, has had the Tab first, and\n // one it used is left where it put focus. It reads the modal's node as\n // each key arrives, so a portal move that remounts the node, including one\n // to a selector that only starts matching while the modal is open, keeps\n // it trapped.\n useEffect(() => {\n if (!isModalActive) return undefined;\n return trapTab(\n () => modalRootRef.current,\n window,\n () => isTopmost('modal')\n );\n }, [isModalActive, isTopmost]);\n\n // Move focus into the modal on open, restore it on close\n useEffect(() => {\n if (!isModalActive) return undefined;\n\n // The element that had focus, wherever it sits: a portaled modal renders\n // under `document.body` while its opener can be inside a shadow root.\n previouslyFocusedRef.current =\n getDeepestActiveElement() as HTMLElement | null;\n const node = modalRootRef.current;\n if (node) focusTabStop(node);\n\n return () => {\n // Only hand focus back if this modal still owns it: closing a background\n // modal must not pull focus out of one that is still open on top. A\n // removed subtree leaves focus on <body>, which still counts as ours.\n const activeElement = getActiveElementInTree(node);\n if (\n activeElement &&\n activeElement !== document.body &&\n !node?.contains(activeElement)\n ) {\n return;\n }\n previouslyFocusedRef.current?.focus?.();\n };\n // `isPortaled` flips once when a hydrated portal modal moves out of the\n // inline tree, and `portal` or `defaultTarget` changing moves a portaled\n // one to another target; re-running rebinds focus onto the remounted\n // nodes. The cleanup above restores focus to the pre-open element first\n // (the detached subtree has left focus on <body>), so the re-run re-records\n // the same element and restore-on-close still lands in the right place.\n }, [isModalActive, isPortaled, portal, defaultTarget]);\n\n // Check if children contain compound components\n const hasCompoundComponents = React.Children.toArray(children).some(\n child =>\n React.isValidElement(child) &&\n (child.type === ModalBackground ||\n child.type === ModalContent ||\n child.type === ModalCard ||\n child.type === ModalClose)\n );\n\n // Generate Bulma classes with prefix\n const bulmaClasses = usePrefixedClassNames('modal', {\n 'is-active': isModalActive,\n });\n const deleteClass = usePrefixedClassNames('delete');\n\n const modalClasses = classNames(bulmaClasses, bulmaHelperClasses, className);\n\n const resolvedRole = role ?? (isModalActive ? 'dialog' : undefined);\n const resolvedAriaModal =\n ariaModalProp ??\n (isModalActive && resolvedRole !== 'presentation' ? 'true' : undefined);\n // A dialog needs an accessible name: the legacy card title is wired up\n // automatically, compound users pass their own aria-label/aria-labelledby\n // (both arrive in `rest`, which is spread last and so wins).\n const titleId = modalCardTitle ? generatedTitleId : undefined;\n\n let modalElement: React.ReactElement;\n\n // If using compound components, render children as-is\n if (hasCompoundComponents) {\n modalElement = (\n <div\n className={modalClasses}\n ref={combinedRef}\n role={resolvedRole}\n aria-modal={resolvedAriaModal}\n tabIndex={-1}\n {...rest}\n data-testid=\"modal\"\n >\n {children}\n </div>\n );\n } else {\n // Legacy API: EXPLICIT type wins; fallback to auto detection if not provided\n let isModalCard: boolean;\n if (type === 'card') isModalCard = true;\n else if (type === 'content') isModalCard = false;\n else isModalCard = !!modalCardTitle || !!modalCardFoot;\n\n modalElement = (\n <div\n className={modalClasses}\n ref={combinedRef}\n role={resolvedRole}\n aria-modal={resolvedAriaModal}\n aria-labelledby={titleId}\n tabIndex={-1}\n {...rest}\n data-testid=\"modal\"\n >\n <div\n className={prefixedClassNames(classPrefix, 'modal-background')}\n onClick={onClose}\n data-testid=\"modal-background\"\n />\n {isModalCard ? (\n <div className={prefixedClassNames(classPrefix, 'modal-card')}>\n {modalCardTitle && (\n <header\n className={prefixedClassNames(classPrefix, 'modal-card-head')}\n >\n <p\n id={titleId}\n className={prefixedClassNames(\n classPrefix,\n 'modal-card-title'\n )}\n >\n {modalCardTitle}\n </p>\n {onClose && (\n <button\n className={deleteClass}\n aria-label=\"close\"\n onClick={onClose}\n type=\"button\"\n data-testid=\"modal-close\"\n />\n )}\n </header>\n )}\n <section\n className={prefixedClassNames(classPrefix, 'modal-card-body')}\n data-testid=\"modal-body\"\n >\n {children}\n </section>\n {modalCardFoot && (\n <footer\n className={prefixedClassNames(classPrefix, 'modal-card-foot')}\n >\n {modalCardFoot}\n </footer>\n )}\n </div>\n ) : (\n <div\n className={prefixedClassNames(classPrefix, 'modal-content')}\n data-testid=\"modal-content\"\n >\n {children}\n </div>\n )}\n {/* Show floating close button for modal-content, or for modal-card when no header */}\n {(!isModalCard || (!modalCardTitle && onClose)) && onClose && (\n <button\n className={prefixedClassNames(\n classPrefix,\n 'modal-close',\n 'is-large'\n )}\n aria-label=\"close\"\n onClick={onClose}\n type=\"button\"\n data-testid=\"modal-close-float\"\n />\n )}\n </div>\n );\n }\n\n // In both forms, so a `Modal.Close` anywhere inside closes this modal.\n modalElement = (\n <ModalCloseContext.Provider value={onClose}>\n {modalElement}\n </ModalCloseContext.Provider>\n );\n\n if (isPortaled) {\n const target = resolveContainer(\n typeof portal === 'boolean' ? undefined : portal\n );\n return createPortal(\n <LocalePortalScope target={target}>{modalElement}</LocalePortalScope>,\n target\n );\n }\n\n return modalElement;\n});\n\nexport const Modal = withSubComponents(\n ModalRoot,\n {\n Background: ModalBackground,\n Content: ModalContent,\n Card: ModalCard,\n Close: ModalClose,\n },\n 'Modal'\n);\nexport default Modal;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Modal.js","sources":["../../../src/components/Modal.tsx"],"sourcesContent":["import React, {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useId,\n useRef,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n classNames,\n usePrefixedClassNames,\n prefixedClassNames,\n} from '../helpers/classNames';\nimport { withSubComponents } from '../helpers/withSubComponents';\nimport { buttonType } from '../helpers/buttonType';\nimport {\n useBulmaClasses,\n BulmaClassesProps,\n validColors,\n} from '../helpers/useBulmaClasses';\nimport { useConfig } from '../helpers/Config';\nimport { useScrollLock } from '../helpers/scrollLock';\nimport {\n getActiveElementInTree,\n getDeepestActiveElement,\n} from '../helpers/shadowDom';\nimport { usePortalContainer } from '../helpers/portal';\nimport { LocalePortalScope } from '../helpers/LocaleProvider';\nimport { useIsHydrated } from '../helpers/useIsHydrated';\nimport { useLatestRef } from '../helpers/useLatestRef';\nimport { useOverlayStack } from '../helpers/overlayStack';\nimport { focusTabStop, trapTab } from '../helpers/useFocusTrap';\n\n/**\n * Props for the Modal component.\n * @extraProp {React.Ref<HTMLDivElement>} [ref] - Ref forwarded to the root `.modal` element.\n */\nexport interface ModalProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'color' | 'title'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /** Whether the modal is open/visible. */\n active?: boolean;\n /** Alias for `active`. Whether the modal is open/visible. */\n isActive?: boolean; // Alias for active\n /**\n * Called to ask for the modal to close. The props form calls it from the\n * background and the close button it renders. In the compound form,\n * `Modal.Close` calls it unless you give it an `onClick` of your own, and\n * `Modal.Background` doesn't call it on its own: pass it\n * `onClick={onClose}` for a click on the background to close the modal.\n * Escape calls it in both forms unless `closeOnEscape` is `false`.\n */\n onClose?: () => void;\n /** Additional CSS classes for the modal. */\n className?: string;\n /** Text color for modal content. */\n textColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Background color for modal content. */\n bgColor?: (typeof validColors)[number] | 'inherit' | 'current';\n /** Title/header for modal-card variant. (Legacy API only) */\n modalCardTitle?: React.ReactNode;\n /** Footer for modal-card variant. (Legacy API only) */\n modalCardFoot?: React.ReactNode;\n /**\n * Modal style: `'card'` for modal-card, `'content'` for modal-content. (Legacy API only)\n * @defaultValue auto\n */\n type?: 'card' | 'content';\n /** Modal body/content or compound components. */\n children?: React.ReactNode;\n /**\n * Close the modal when the Escape key is pressed (calls `onClose`). Only the\n * topmost open overlay responds, whichever Modal, Dialog, Sidebar or\n * full-page Loading opened last, so Escape closes one layer at a time. The\n * modal marks the Escape it closes on as used with `preventDefault()`, and\n * a Toast waits until no overlay is open. Turned off, a modal on top still\n * keeps Escape from the layers under it. A popup inside it, such as a\n * Dropdown's menu or a date picker's calendar, takes its own Escape first,\n * and so does content that calls `preventDefault()` on it.\n * @defaultValue true\n */\n closeOnEscape?: boolean;\n /**\n * Lock body scroll while the modal is active. Ref-counted and shared with\n * `Dialog`, `Sidebar` and `Loading`, so whichever overlay closes first does\n * not unlock the page underneath one that is still open.\n * @defaultValue true\n */\n lockScroll?: boolean;\n /**\n * Renders the modal into a portal target instead of inline, so it isn't\n * clipped by an ancestor with `overflow: hidden`, `filter` or `transform`.\n * `true` portals to the `portalContainer` a `ConfigProvider` sets,\n * `document.body` by default; a string is used as a\n * `document.querySelector` selector; an element is used directly. Renders\n * inline on the server and while hydrating, moving into the portal once the\n * client takes over, so hydration matches.\n * @defaultValue false\n */\n portal?: boolean | string | HTMLElement;\n}\n\n/**\n * Props for Modal.Background component.\n * @extraProp {React.MouseEventHandler<HTMLDivElement>} [onClick] - Called when the background is clicked. The background doesn't call the modal's `onClose` on its own, so pass `onClick={onClose}` for a click on it to close the modal.\n */\nexport interface ModalBackgroundProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Content component.\n */\nexport interface ModalContentProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card component.\n */\nexport interface ModalCardProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card.Head component.\n */\nexport interface ModalCardHeadProps extends React.HTMLAttributes<HTMLElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card.Title component.\n */\nexport interface ModalCardTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card.Body component.\n */\nexport interface ModalCardBodyProps extends React.HTMLAttributes<HTMLElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Card.Foot component.\n */\nexport interface ModalCardFootProps extends React.HTMLAttributes<HTMLElement> {\n /** Additional CSS classes. */\n className?: string;\n}\n\n/**\n * Props for Modal.Close component.\n * @extraProp {'button' | 'submit' | 'reset'} [type='button'] - Button type. Defaults to `'button'`, so a close button inside a form does not submit it. Pass `'submit'` or `'reset'` and yours is used; any other value, or a spread carrying `type: undefined`, renders `'button'`.\n * @extraProp {string} [aria-label='close'] - Accessible name. Pass your own to replace it. An empty one, or a spread carrying `'aria-label': undefined`, keeps the default rather than leaving the button unnamed.\n * @extraProp {React.MouseEventHandler<HTMLButtonElement>} [onClick] - Called when the button is clicked. Without one, the button calls the `onClose` of the `Modal` around it. Yours replaces that rather than running before it, so call `onClose` from it if the button should still close the modal.\n */\nexport interface ModalCloseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Additional CSS classes. */\n className?: string;\n /** Size of the close button (only applies to 'floating' variant). */\n size?: 'small' | 'medium' | 'large';\n /** Button variant. 'delete' (default) for modal card headers, 'floating' for overlay close button. */\n variant?: 'delete' | 'floating';\n}\n\n// The enclosing modal's `onClose`, for a `Modal.Close` written as a part, so\n// it closes the modal the way the button the props form renders does.\nconst ModalCloseContext = createContext<(() => void) | undefined>(undefined);\n\n/**\n * Modal.Background - Renders the modal background overlay. Pass it\n * `onClick={onClose}` for a click on it to close the modal.\n *\n * @function\n * @param {ModalBackgroundProps} props - Component props.\n * @returns {JSX.Element} Modal background element.\n */\nconst ModalBackground: React.FC<ModalBackgroundProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-background'),\n className\n );\n return <div className={classes} {...props} />;\n};\n\n/**\n * Modal.Content - Renders modal content wrapper for custom content.\n *\n * @function\n * @param {ModalContentProps} props - Component props.\n * @returns {JSX.Element} Modal content element.\n */\nconst ModalContent: React.FC<ModalContentProps> = ({ className, ...props }) => {\n const classes = classNames(usePrefixedClassNames('modal-content'), className);\n return <div className={classes} {...props} />;\n};\n\n/**\n * Modal.Card.Head - Renders modal card header section.\n *\n * @function\n * @param {ModalCardHeadProps} props - Component props.\n * @returns {JSX.Element} Modal card header element.\n */\nconst ModalCardHead: React.FC<ModalCardHeadProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-card-head'),\n className\n );\n return <header className={classes} {...props} />;\n};\n\n/**\n * Modal.Card.Title - Renders modal card title.\n *\n * @function\n * @param {ModalCardTitleProps} props - Component props.\n * @returns {JSX.Element} Modal card title element.\n */\nconst ModalCardTitle: React.FC<ModalCardTitleProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-card-title'),\n className\n );\n return <p className={classes} {...props} />;\n};\n\n/**\n * Modal.Card.Body - Renders modal card body section.\n *\n * @function\n * @param {ModalCardBodyProps} props - Component props.\n * @returns {JSX.Element} Modal card body element.\n */\nconst ModalCardBody: React.FC<ModalCardBodyProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-card-body'),\n className\n );\n return <section className={classes} {...props} />;\n};\n\n/**\n * Modal.Card.Foot - Renders modal card footer section.\n *\n * @function\n * @param {ModalCardFootProps} props - Component props.\n * @returns {JSX.Element} Modal card footer element.\n */\nconst ModalCardFoot: React.FC<ModalCardFootProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(\n usePrefixedClassNames('modal-card-foot'),\n className\n );\n return <footer className={classes} {...props} />;\n};\n\n/**\n * Modal.Card - Renders modal card wrapper with compound components.\n * Use with Modal.Card.Head, Modal.Card.Title, Modal.Card.Body, and Modal.Card.Foot.\n *\n * @function\n * @param {ModalCardProps} props - Component props.\n * @returns {JSX.Element} Modal card element.\n */\nconst ModalCardComponent: React.FC<ModalCardProps> = ({\n className,\n ...props\n}) => {\n const classes = classNames(usePrefixedClassNames('modal-card'), className);\n return <div className={classes} {...props} />;\n};\n\nconst ModalCard = withSubComponents(ModalCardComponent, {\n Head: ModalCardHead,\n Title: ModalCardTitle,\n Body: ModalCardBody,\n Foot: ModalCardFoot,\n});\n\n/**\n * Modal.Close - Renders modal close button with two variant styles. It calls\n * the modal's `onClose` unless given an `onClick` of its own.\n *\n * @function\n * @param {ModalCloseProps} props - Component props.\n * @returns {JSX.Element} Close button element.\n *\n * @remarks\n * Supports two variants:\n * - 'delete' (default): For use in modal card headers, renders with 'delete' class\n * - 'floating': For floating overlay close button, renders with 'modal-close' class\n *\n * The size prop only applies to the 'floating' variant.\n */\nconst ModalClose: React.FC<ModalCloseProps> = ({\n className,\n size = 'large',\n variant = 'delete',\n onClick,\n ...props\n}) => {\n const onClose = useContext(ModalCloseContext);\n const classes = classNames(\n usePrefixedClassNames(\n variant === 'delete' ? 'delete' : 'modal-close',\n variant === 'floating' && size && { [`is-${size}`]: true }\n ),\n className\n );\n return (\n <button\n className={classes}\n {...props}\n // After the spread, reading through it: a key the spread carries with no\n // value would otherwise erase the default, leaving a nameless button\n // that submits the form around it. An empty label falls back too: the\n // button is drawn as an icon, so `''` would leave it unnamed. A caller's\n // own value still wins; `buttonType` says more.\n aria-label={props['aria-label'] || 'close'}\n type={buttonType(props.type)}\n // A caller's own `onClick` replaces the close rather than running\n // before it, unlike `Popover.Close`: this button used to close only\n // through that handler, so a caller already closing there, as with\n // `onClick={onClose}`, would otherwise close twice.\n onClick={onClick ?? (onClose && (() => onClose()))}\n />\n );\n};\n\n/**\n * The `Modal` component provides an empty, accessible overlay for arbitrary content — for a ready-made confirm or alert, reach for `Dialog` instead.\n *\n * @function\n * @param {ModalProps} props - Props for the Modal component.\n * @returns {JSX.Element} The rendered modal.\n *\n * @example\n * // Legacy API\n * <Modal active={isOpen} onClose={handleClose} modalCardTitle=\"Title\">\n * Content\n * </Modal>\n *\n * @example\n * // Compound Component API\n * <Modal isActive={isOpen} onClose={handleClose}>\n * <Modal.Background onClick={handleClose} />\n * <Modal.Card>\n * <Modal.Card.Head>\n * <Modal.Card.Title>Title</Modal.Card.Title>\n * <Modal.Close />\n * </Modal.Card.Head>\n * <Modal.Card.Body>Content</Modal.Card.Body>\n * </Modal.Card>\n * </Modal>\n *\n * @see {@link https://bulma.io/documentation/components/modal/ | Bulma Modal documentation}\n */\nconst ModalRoot = forwardRef<HTMLDivElement, ModalProps>(function ModalRoot(\n {\n active,\n isActive,\n onClose,\n className,\n textColor,\n bgColor,\n modalCardTitle,\n modalCardFoot,\n type,\n children,\n closeOnEscape = true,\n lockScroll = true,\n portal = false,\n role,\n 'aria-modal': ariaModalProp,\n ...props\n },\n ref\n) {\n const { classPrefix, portalContainer } = useConfig();\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n ...props,\n });\n\n // Support both active and isActive props\n const isModalActive = active ?? isActive ?? false;\n\n const modalRootRef = useRef<HTMLDivElement>(null);\n\n // Cleanup returned by a consumer's callback ref on attach, held until detach.\n const consumerCleanupRef = useRef<(() => void) | null>(null);\n\n // The forwarded ref and the internal one must both see the node: focus\n // management and the Tab trap read `modalRootRef`, while consumers expect\n // their own ref to resolve.\n const combinedRef = useCallback(\n (node: HTMLDivElement | null) => {\n (modalRootRef as React.MutableRefObject<HTMLDivElement | null>).current =\n node;\n if (typeof ref === 'function') {\n // React 19 lets a callback ref return a cleanup function and detaches\n // by running it instead of calling the ref with `null`; React 18\n // discards the return value entirely. Returning it from here would be\n // a React-19-only contract, so instead we hold the cleanup and run it\n // ourselves on detach — a consumer's cleanup ref then behaves the same\n // on both majors of the CI matrix. Same shape as `Dropdown`.\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 const previouslyFocusedRef = useRef<HTMLElement | null>(null);\n const generatedTitleId = useId();\n // A portal has no server-rendered counterpart, so the server render and the\n // hydrating render have to stay inline and only move into the portal once\n // we're past hydration.\n const onClient = useIsHydrated();\n const resolveContainer = usePortalContainer();\n // Moving into the portal, or from one portal target to another, remounts\n // the modal's subtree, so any effect holding a DOM node from before the move\n // is holding a detached one. Effects that touch the modal's nodes key on\n // this, on `portal` and on `defaultTarget`, so they re-run against the new\n // tree.\n const isPortaled = Boolean(portal) && onClient;\n // The configured `portalContainer` only places a modal portaled with\n // `portal` set to `true`. In place, or with a target of its own, a change\n // to it moves nothing, so it mustn't re-run the effects either.\n const defaultTarget =\n isPortaled && portal === true ? portalContainer : undefined;\n\n useScrollLock(isModalActive && lockScroll);\n\n // Read when Escape arrives, so the key listener stays put while `onClose`\n // changes identity, as an inline one does on every render of the parent.\n const onCloseRef = useLatestRef(onClose);\n\n // Joins the stack of open overlays, so the keyboard handling below only\n // applies while this modal is on top.\n const isTopmost = useOverlayStack(isModalActive);\n\n // Escape closes, only for the topmost overlay. The listener is on\n // `window`, where a keydown arrives last, so everything inside the modal\n // has had the key first: React's handlers, and `document` listeners added\n // after this one, such as a date picker's.\n useEffect(() => {\n if (!isModalActive) return undefined;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Escape' || !isTopmost()) return;\n // Something inside already used this Escape, such as a popup that\n // closed on it, so the modal waits for the next one. One the modal\n // closes on is marked used, so nothing under it acts on it as well.\n if (closeOnEscape && onCloseRef.current && !e.defaultPrevented) {\n e.preventDefault();\n onCloseRef.current();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [isModalActive, closeOnEscape, onCloseRef, isTopmost]);\n\n // Keep Tab within the modal: `aria-modal` hides the rest of the page from\n // assistive technology, so the keyboard order has to agree. Only while\n // it's the topmost modal overlay, so an overlay that isn't modal, such as\n // a Sidebar without an overlay, takes Escape from it but leaves it Tab.\n // It's the trap `useFocusTrap` sets, so it wraps at the stops Tab really\n // visits, skipping hidden, inert and closed content, and sends back a Tab\n // the browser still takes out. On `window` for the same reason as Escape:\n // a trap inside, such as a portaled popup's, has had the Tab first, and\n // one it used is left where it put focus. It reads the modal's node as\n // each key arrives, so a portal move that remounts the node, including one\n // to a selector that only starts matching while the modal is open, keeps\n // it trapped.\n useEffect(() => {\n if (!isModalActive) return undefined;\n return trapTab(\n () => modalRootRef.current,\n window,\n () => isTopmost('modal')\n );\n }, [isModalActive, isTopmost]);\n\n // Move focus into the modal on open, restore it on close\n useEffect(() => {\n if (!isModalActive) return undefined;\n\n // The element that had focus, wherever it sits: a portaled modal renders\n // under `document.body` while its opener can be inside a shadow root.\n previouslyFocusedRef.current =\n getDeepestActiveElement() as HTMLElement | null;\n const node = modalRootRef.current;\n if (node) focusTabStop(node);\n\n return () => {\n // Only hand focus back if this modal still owns it: closing a background\n // modal must not pull focus out of one that is still open on top. A\n // removed subtree leaves focus on <body>, which still counts as ours.\n const activeElement = getActiveElementInTree(node);\n if (\n activeElement &&\n activeElement !== document.body &&\n !node?.contains(activeElement)\n ) {\n return;\n }\n previouslyFocusedRef.current?.focus?.();\n };\n // `isPortaled` flips once when a hydrated portal modal moves out of the\n // inline tree, and `portal` or `defaultTarget` changing moves a portaled\n // one to another target; re-running rebinds focus onto the remounted\n // nodes. The cleanup above restores focus to the pre-open element first\n // (the detached subtree has left focus on <body>), so the re-run re-records\n // the same element and restore-on-close still lands in the right place.\n }, [isModalActive, isPortaled, portal, defaultTarget]);\n\n // Check if children contain compound components\n const hasCompoundComponents = React.Children.toArray(children).some(\n child =>\n React.isValidElement(child) &&\n (child.type === ModalBackground ||\n child.type === ModalContent ||\n child.type === ModalCard ||\n child.type === ModalClose)\n );\n\n // Generate Bulma classes with prefix\n const bulmaClasses = usePrefixedClassNames('modal', {\n 'is-active': isModalActive,\n });\n const deleteClass = usePrefixedClassNames('delete');\n\n const modalClasses = classNames(bulmaClasses, bulmaHelperClasses, className);\n\n const resolvedRole = role ?? (isModalActive ? 'dialog' : undefined);\n const resolvedAriaModal =\n ariaModalProp ??\n (isModalActive && resolvedRole !== 'presentation' ? 'true' : undefined);\n // A dialog needs an accessible name: the legacy card title is wired up\n // automatically, compound users pass their own aria-label/aria-labelledby\n // (both arrive in `rest`, which is spread last and so wins).\n const titleId = modalCardTitle ? generatedTitleId : undefined;\n\n let modalElement: React.ReactElement;\n\n // If using compound components, render children as-is\n if (hasCompoundComponents) {\n modalElement = (\n <div\n className={modalClasses}\n ref={combinedRef}\n role={resolvedRole}\n aria-modal={resolvedAriaModal}\n tabIndex={-1}\n {...rest}\n data-testid=\"modal\"\n >\n {children}\n </div>\n );\n } else {\n // Legacy API: EXPLICIT type wins; fallback to auto detection if not provided\n let isModalCard: boolean;\n if (type === 'card') isModalCard = true;\n else if (type === 'content') isModalCard = false;\n else isModalCard = !!modalCardTitle || !!modalCardFoot;\n\n modalElement = (\n <div\n className={modalClasses}\n ref={combinedRef}\n role={resolvedRole}\n aria-modal={resolvedAriaModal}\n aria-labelledby={titleId}\n tabIndex={-1}\n {...rest}\n data-testid=\"modal\"\n >\n <div\n className={prefixedClassNames(classPrefix, 'modal-background')}\n onClick={onClose}\n data-testid=\"modal-background\"\n />\n {isModalCard ? (\n <div className={prefixedClassNames(classPrefix, 'modal-card')}>\n {modalCardTitle && (\n <header\n className={prefixedClassNames(classPrefix, 'modal-card-head')}\n >\n <p\n id={titleId}\n className={prefixedClassNames(\n classPrefix,\n 'modal-card-title'\n )}\n >\n {modalCardTitle}\n </p>\n {onClose && (\n <button\n className={deleteClass}\n aria-label=\"close\"\n onClick={onClose}\n type=\"button\"\n data-testid=\"modal-close\"\n />\n )}\n </header>\n )}\n <section\n className={prefixedClassNames(classPrefix, 'modal-card-body')}\n data-testid=\"modal-body\"\n >\n {children}\n </section>\n {modalCardFoot && (\n <footer\n className={prefixedClassNames(classPrefix, 'modal-card-foot')}\n >\n {modalCardFoot}\n </footer>\n )}\n </div>\n ) : (\n <div\n className={prefixedClassNames(classPrefix, 'modal-content')}\n data-testid=\"modal-content\"\n >\n {children}\n </div>\n )}\n {/* Show floating close button for modal-content, or for modal-card when no header */}\n {(!isModalCard || (!modalCardTitle && onClose)) && onClose && (\n <button\n className={prefixedClassNames(\n classPrefix,\n 'modal-close',\n 'is-large'\n )}\n aria-label=\"close\"\n onClick={onClose}\n type=\"button\"\n data-testid=\"modal-close-float\"\n />\n )}\n </div>\n );\n }\n\n // In both forms, so a `Modal.Close` anywhere inside closes this modal.\n modalElement = (\n <ModalCloseContext.Provider value={onClose}>\n {modalElement}\n </ModalCloseContext.Provider>\n );\n\n if (isPortaled) {\n const target = resolveContainer(\n typeof portal === 'boolean' ? undefined : portal\n );\n return createPortal(\n <LocalePortalScope target={target}>{modalElement}</LocalePortalScope>,\n target\n );\n }\n\n return modalElement;\n});\n\nexport const Modal = withSubComponents(\n ModalRoot,\n {\n Background: ModalBackground,\n Content: ModalContent,\n Card: ModalCard,\n Close: ModalClose,\n },\n 'Modal'\n);\nexport default Modal;\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
'use client';
|
|
2
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
4
|
import React, { forwardRef, useContext, useState, useEffect } from 'react';
|
|
4
5
|
import { usePrefixedClassNames, classNames } from '../helpers/classNames.js';
|