From 99ea807aee9830cc579e0f93c66cf20229a91029 Mon Sep 17 00:00:00 2001 From: BlackPoretsky <20vinipuh02@gmail.com> Date: Sun, 5 Oct 2025 23:40:41 +0300 Subject: [PATCH 01/11] feat(headless/components): update api and imports --- .../src/modules/auth/view/ui/Auth/Auth.tsx | 2 +- .../AuthorizationMethodContent.tsx | 2 +- .../InputUsernameContent.tsx | 2 +- .../VerificationCodeContent.tsx | 2 +- .../view/ui/AuthCallback/AuthCallback.tsx | 2 +- .../modules/auth/vm/useAuthorizationMethod.ts | 2 +- .../modules/auth/vm/useVerificationCode.ts | 2 +- frontend/src/shared/ui/Dialog/ui/Dialog.tsx | 2 +- .../ui/InputVerificationCode.tsx | 2 +- .../widgets/ToastNotification/ui/Toast.tsx | 2 +- .../headless/components/eslint.config.js | 3 +- .../ui/uikit/headless/components/package.json | 13 + .../Accordion/header/AccordionHeader.tsx | 6 +- .../Accordion/item/AccordionItem.tsx | 32 +- .../Accordion/item/AccordionItemContext.ts | 6 +- .../components/Accordion/item/styleHooks.ts | 6 +- .../Accordion/panel/AccordionPanel.tsx | 8 +- .../panel/AccordionPanelDataAttributes.ts | 2 +- .../Accordion/root/AccordionRoot.tsx | 44 ++- .../Accordion/root/AccordionRootContext.ts | 13 +- .../Accordion/trigger/AccordionTrigger.tsx | 11 +- .../Avatar/fallback/AvatarFallback.tsx | 6 +- .../components/Avatar/image/AvatarImage.tsx | 6 +- .../Avatar/image/useImageLoadingStatus.ts | 4 +- .../src/components/Avatar/root/AvatarRoot.tsx | 6 +- .../Avatar/root/AvatarRootContext.ts | 6 +- .../Checkbox/indicator/CheckboxIndicator.tsx | 10 +- .../CheckboxIndicatorDataAttributes.ts | 2 +- .../components/Checkbox/root/CheckboxRoot.tsx | 32 +- .../Checkbox/root/CheckboxRootContext.ts | 6 +- .../utils/useCustomStyleHookMapping.ts | 4 +- .../CheckboxGroup/CheckboxGroup.tsx | 34 +- .../CheckboxGroup/CheckboxGroupContext.ts | 14 +- .../CheckboxGroup/useCheckboxGroupParent.ts | 23 +- .../Collapsible/panel/CollapsiblePanel.tsx | 8 +- .../panel/CollapsiblePanelDataAttributes.ts | 2 +- .../Collapsible/panel/useCollapsiblePanel.ts | 14 +- .../Collapsible/root/CollapsibleRoot.tsx | 17 +- .../root/CollapsibleRootContext.ts | 8 +- .../components/Collapsible/root/styleHooks.ts | 6 +- .../Collapsible/root/useCollapsibleRoot.ts | 26 +- .../trigger/CollapsibleTrigger.tsx | 14 +- .../CollapsibleTriggerDataAttributes.ts | 2 +- .../src/components/Composite/composite.ts | 6 +- .../Composite/item/CompositeItem.tsx | 10 +- .../Composite/item/useCompositeItem.ts | 4 +- .../Composite/list/CompositeList.tsx | 2 +- .../Composite/list/CompositeListContext.ts | 6 +- .../Composite/list/useCompositeListItem.ts | 2 +- .../Composite/root/CompositeRoot.tsx | 15 +- .../Composite/root/CompositeRootContext.ts | 10 +- .../Composite/root/useCompositeRoot.ts | 17 +- .../ContextMenu/root/ContextMenuRoot.tsx | 17 +- .../root/ContextMenuRootContext.ts | 14 +- .../trigger/ContextMenuTrigger.tsx | 66 ++-- .../Dialog/backdrop/DialogBackdrop.tsx | 32 +- .../backdrop/DialogBackdropDataAttributes.ts | 2 +- .../components/Dialog/close/DialogClose.tsx | 12 +- .../components/Dialog/close/useDialogClose.ts | 16 +- .../Dialog/description/DialogDescription.tsx | 16 +- .../components/Dialog/popup/DialogPopup.tsx | 133 ++++--- .../Dialog/popup/DialogPopupDataAttributes.ts | 2 +- .../components/Dialog/popup/useDialogPopup.ts | 117 ------ .../components/Dialog/portal/DialogPortal.tsx | 13 +- .../Dialog/portal/DialogPortalContext.ts | 2 - .../src/components/Dialog/root/DialogRoot.tsx | 129 +++++-- .../Dialog/root/DialogRootContext.ts | 41 +- .../components/Dialog/root/useDialogRoot.ts | 325 +++------------- .../components/src/components/Dialog/store.ts | 136 +++++++ .../components/Dialog/title/DialogTitle.tsx | 17 +- .../Dialog/trigger/DialogTrigger.tsx | 15 +- .../trigger/DialogTriggerDataAttributes.ts | 2 +- .../components/Dialog/utils/DialogContext.ts | 25 -- .../components/Field/control/FieldControl.tsx | 44 ++- .../Field/control/FieldControlContext.ts | 8 +- .../control/useFieldControlValidation.ts | 7 +- .../Field/description/FieldDescription.tsx | 6 +- .../src/components/Field/error/FieldError.tsx | 7 +- .../src/components/Field/label/FieldLabel.tsx | 8 +- .../src/components/Field/root/FieldRoot.tsx | 11 +- .../components/Field/root/FieldRootContext.ts | 8 +- .../Field/slot/FieldControlSlot.tsx | 6 +- .../Field/validity/FieldValidity.tsx | 2 +- .../Fieldset/legend/FieldsetLegend.tsx | 6 +- .../components/Fieldset/root/FieldsetRoot.tsx | 10 +- .../Fieldset/root/FieldsetRootContext.ts | 6 +- .../components/src/components/Form/Form.tsx | 17 +- .../src/components/Form/FormContext.ts | 7 +- .../components/src/components/Input/Input.tsx | 2 +- .../src/components/Menu/arrow/MenuArrow.tsx | 14 +- .../Menu/arrow/MenuArrowDataAttributes.ts | 2 +- .../components/Menu/backdrop/MenuBackdrop.tsx | 17 +- .../backdrop/MenuBackdropDataAttributes.ts | 2 +- .../MenuCheckboxItemIndicator.tsx | 6 +- ...MenuCheckboxItemIndicatorDataAttributes.ts | 2 +- .../Menu/checkbox-item/MenuCheckboxItem.tsx | 52 +-- .../checkbox-item/MenuCheckboxItemContext.ts | 4 +- .../Menu/group-label/MenuGroupLabel.tsx | 7 +- .../src/components/Menu/group/MenuGroup.tsx | 6 +- .../components/Menu/group/MenuGroupContext.ts | 4 +- .../src/components/Menu/item/MenuItem.tsx | 31 +- .../src/components/Menu/item/useMenuItem.ts | 9 +- .../src/components/Menu/popup/MenuPopup.tsx | 78 ++-- .../Menu/popup/MenuPopupDataAttributes.ts | 2 +- .../src/components/Menu/portal/MenuPortal.tsx | 5 +- .../Menu/positioner/MenuPositioner.tsx | 104 ++--- .../Menu/positioner/MenuPositionerContext.ts | 18 +- .../MenuPositionerDataAttributes.ts | 2 +- .../Menu/radio-group/MenuRadioGroup.tsx | 30 +- .../Menu/radio-group/MenuRadioGroupContext.ts | 8 +- .../MenuRadioItemIndicator.tsx | 6 +- .../MenuRadioItemIndicatorDataAttributes.ts | 2 +- .../Menu/radio-item/MenuRadioItem.tsx | 50 +-- .../Menu/radio-item/MenuRadioItemContext.ts | 4 +- .../src/components/Menu/root/MenuRoot.tsx | 152 ++++---- .../components/Menu/root/MenuRootContext.ts | 30 +- .../Menu/submenu-root/MenuSubmenuRoot.tsx | 31 +- .../submenu-trigger/MenuSubmenuTrigger.tsx | 13 +- .../MenuSubmenuTriggerDataAttributes.ts | 2 +- .../components/Menu/trigger/MenuTrigger.tsx | 51 +-- .../Menu/trigger/MenuTriggerDataAttributes.ts | 2 +- .../components/Menu/utils/findRootOwnerId.ts | 13 + .../components/Menu/utils/styleHookMapping.ts | 4 +- .../src/components/Menu/utils/types.ts | 8 + .../src/components/Menubar/Menubar.tsx | 51 +-- .../src/components/Menubar/MenubarContext.ts | 12 +- .../Meter/indicator/MeterIndicator.tsx | 8 +- .../src/components/Meter/label/MeterLabel.tsx | 6 +- .../src/components/Meter/root/MeterRoot.tsx | 13 +- .../components/Meter/root/MeterRootContext.ts | 6 +- .../src/components/Meter/track/MeterTrack.tsx | 6 +- .../src/components/Meter/value/MeterValue.tsx | 6 +- .../decrement/NumberFieldDecrement.tsx | 14 +- .../NumberField/group/NumberFieldGroup.tsx | 6 +- .../increment/NumberFieldIncrement.tsx | 14 +- .../NumberField/input/NumberFieldInput.tsx | 187 ++++++--- .../NumberField/root/NumberFieldRoot.tsx | 168 ++++++--- .../root/NumberFieldRootContext.ts | 12 +- .../NumberField/root/useNumberFieldButton.ts | 64 +++- .../NumberFieldScrubAreaCursor.tsx | 12 +- .../scrub-area/NumberFieldScrubArea.tsx | 48 ++- .../scrub-area/NumberFieldScrubAreaContext.ts | 4 +- .../NumberField/utils/getViewportRect.ts | 2 +- .../NumberField/utils/styleHooks.ts | 2 +- .../utils/subscribeToVisualViewportResize.ts | 4 +- .../components/NumberField/utils/validate.ts | 4 +- .../focus-funnel/PinInputFocusFunnel.tsx | 4 +- .../PinInput/group/PinInputGroup.tsx | 4 +- .../components/PinInput/pin/PinInputPin.tsx | 4 +- .../components/PinInput/pin/handleEvents.ts | 6 +- .../components/PinInput/root/PinInputRoot.tsx | 10 +- .../PinInput/root/PinInputRootContext.ts | 2 +- .../components/PinInput/utils/styleHooks.ts | 4 +- .../components/Popover/arrow/PopoverArrow.tsx | 14 +- .../arrow/PopoverArrowDataAttributes.ts | 2 +- .../Popover/backdrop/PopoverBackdrop.tsx | 17 +- .../backdrop/PopoverBackdropDataAttributes.ts | 2 +- .../components/Popover/close/PopoverClose.tsx | 9 +- .../description/PopoverDescription.tsx | 7 +- .../components/Popover/popup/PopoverPopup.tsx | 85 +++-- .../popup/PopoverPopupDataAttributes.ts | 2 +- .../Popover/portal/PopoverPortal.tsx | 6 +- .../Popover/portal/PopoverPortalContext.ts | 2 +- .../Popover/positioner/PopoverPositioner.tsx | 26 +- .../positioner/PopoverPositionerContext.ts | 14 +- .../PopoverPositionerDataAttributes.ts | 2 +- .../components/Popover/root/PopoverRoot.tsx | 80 ++-- .../Popover/root/PopoverRootContext.ts | 30 +- .../components/Popover/title/PopoverTitle.tsx | 7 +- .../Popover/trigger/PopoverTrigger.tsx | 13 +- .../trigger/PopoverTriggerDataAttributes.ts | 2 +- .../Progress/indicator/ProgressIndicator.tsx | 8 +- .../Progress/label/ProgressLabel.tsx | 6 +- .../components/Progress/root/ProgressRoot.tsx | 13 +- .../Progress/root/ProgressRootContext.ts | 6 +- .../components/Progress/root/styleHooks.ts | 2 +- .../Progress/track/ProgressTrack.tsx | 6 +- .../Progress/value/ProgressValue.tsx | 6 +- .../Radio/indicator/RadioIndicator.tsx | 8 +- .../src/components/Radio/root/RadioRoot.tsx | 47 +-- .../components/Radio/root/RadioRootContext.ts | 6 +- .../src/components/Radio/utils/styleHooks.ts | 9 +- .../src/components/RadioGroup/RadioGroup.tsx | 62 +-- .../RadioGroup/RadioGroupContext.ts | 14 +- .../components/Select/arrow/SelectArrow.tsx | 18 +- .../Select/arrow/SelectArrowDataAttributes.ts | 2 +- .../Select/backdrop/SelectBackdrop.tsx | 10 +- .../backdrop/SelectBackdropDataAttributes.ts | 2 +- .../Select/group-label/SelectGroupLabel.tsx | 6 +- .../components/Select/group/SelectGroup.tsx | 8 +- .../Select/group/SelectGroupContext.ts | 4 +- .../src/components/Select/icon/SelectIcon.tsx | 4 +- .../Select/icon/SelectIconDataAttributes.ts | 2 +- .../item-indicator/SelectItemIndicator.tsx | 8 +- .../Select/item-text/SelectItemText.tsx | 6 +- .../src/components/Select/item/SelectItem.tsx | 16 +- .../Select/item/SelectItemContext.ts | 6 +- .../src/components/Select/list/SelectList.tsx | 6 +- .../components/Select/popup/SelectPopup.tsx | 30 +- .../Select/popup/SelectPopupDataAttributes.ts | 2 +- .../components/Select/portal/SelectPortal.tsx | 6 +- .../Select/positioner/SelectPositioner.tsx | 26 +- .../positioner/SelectPositionerContext.ts | 10 +- .../SelectPositionerDataAttributes.ts | 2 +- .../src/components/Select/root/SelectRoot.tsx | 24 +- .../Select/root/SelectRootContext.ts | 8 +- .../components/Select/root/useSelectRoot.ts | 22 +- .../Select/scroll-arrow/SelectScrollArrow.tsx | 10 +- .../SelectScrollDownArrow.tsx | 4 +- .../SelectScrollDownArrowDataAttributes.ts | 2 +- .../scroll-up-arrow/SelectScrollUpArrow.tsx | 4 +- .../SelectScrollUpArrowDataAttributes.ts | 2 +- .../components/src/components/Select/store.ts | 2 +- .../Select/trigger/SelectTrigger.tsx | 22 +- .../trigger/SelectTriggerDataAttributes.ts | 2 +- .../components/Select/value/SelectValue.tsx | 10 +- .../src/components/Separator/Separator.ts | 6 +- .../Slider/control/SliderControl.tsx | 18 +- .../Slider/indicator/SliderIndicator.tsx | 6 +- .../src/components/Slider/root/SliderRoot.tsx | 24 +- .../Slider/root/SliderRootContext.ts | 8 +- .../src/components/Slider/root/styleHooks.ts | 2 +- .../components/Slider/thumb/SliderThumb.tsx | 18 +- .../components/Slider/track/SliderTrack.tsx | 6 +- .../components/Slider/utils/getMidpoint.ts | 2 +- .../components/Slider/utils/getSliderValue.ts | 2 +- .../Slider/utils/valueArrayToPercentages.ts | 4 +- .../components/Slider/value/SliderValue.tsx | 8 +- .../components/src/components/Slot/Slot.ts | 2 +- .../components/src/components/Slot/index.ts | 2 +- .../src/components/Switch/root/SwitchRoot.tsx | 38 +- .../Switch/root/SwitchRootContext.ts | 4 +- .../src/components/Switch/styleHooks.ts | 2 +- .../components/Switch/thumb/SwitchThumb.tsx | 6 +- .../Tabs/indicator/TabsIndicator.tsx | 9 +- .../src/components/Tabs/list/TabsList.tsx | 54 +-- .../components/Tabs/list/TabsListContext.ts | 10 +- .../src/components/Tabs/panel/TabsPanel.tsx | 6 +- .../src/components/Tabs/root/TabsRoot.tsx | 89 +++-- .../components/Tabs/root/TabsRootContext.ts | 15 +- .../src/components/Tabs/root/styleHooks.ts | 2 +- .../src/components/Tabs/tab/TabsTab.tsx | 46 ++- .../src/components/Textarea/Textarea.tsx | 2 +- .../components/Toast/action/ToastAction.tsx | 6 +- .../src/components/Toast/close/ToastClose.tsx | 6 +- .../components/Toast/createToastManager.ts | 2 +- .../Toast/description/ToastDescription.tsx | 6 +- .../components/Toast/portal/ToastPortal.tsx | 4 +- .../Toast/provider/ToastProvider.tsx | 14 +- .../Toast/provider/ToastProviderContext.ts | 8 +- .../src/components/Toast/root/ToastRoot.tsx | 14 +- .../components/Toast/root/ToastRootContext.ts | 8 +- .../src/components/Toast/title/ToastTitle.tsx | 6 +- .../src/components/Toast/useToastManager.ts | 7 +- .../components/Toast/utils/focusVisible.ts | 2 +- .../Toast/viewport/ToastViewport.tsx | 14 +- .../Toast/viewport/ToastViewportContext.ts | 4 +- .../src/components/Toggle/Toggle.tsx | 36 +- .../components/ToggleGroup/ToggleGroup.tsx | 76 ++-- .../ToggleGroup/ToggleGroupContext.ts | 15 +- .../Toolbar/button/ToolbarButton.tsx | 4 +- .../components/Toolbar/group/ToolbarGroup.tsx | 10 +- .../Toolbar/group/ToolbarGroupContext.ts | 10 +- .../src/components/Toolbar/index.parts.ts | 2 +- .../components/Toolbar/input/ToolbarInput.tsx | 6 +- .../components/Toolbar/link/ToolbarLink.tsx | 4 +- .../components/Toolbar/root/ToolbarRoot.tsx | 28 +- .../Toolbar/root/ToolbarRootContext.ts | 12 +- .../Toolbar/separator/ToolbarSeparator.tsx | 4 +- .../components/Tooltip/arrow/TooltipArrow.tsx | 14 +- .../arrow/TooltipArrowDataAttributes.ts | 2 +- .../components/Tooltip/popup/TooltipPopup.tsx | 24 +- .../popup/TooltipPopupDataAttributes.ts | 2 +- .../Tooltip/portal/TooltipPortal.tsx | 4 +- .../Tooltip/portal/TooltipPortalContext.ts | 2 - .../Tooltip/positioner/TooltipPositioner.tsx | 20 +- .../positioner/TooltipPositionerContext.ts | 12 +- .../TooltipPositionerDataAttributes.ts | 2 +- .../positioner/useTooltipPositioner.ts | 10 +- .../Tooltip/provider/TooltipProvider.tsx | 2 +- .../provider/TooltipProviderContext.ts | 8 +- .../components/Tooltip/root/TooltipRoot.tsx | 307 +++++++++++++-- .../Tooltip/root/TooltipRootContext.ts | 19 +- .../components/Tooltip/root/useTooltipRoot.ts | 260 ------------- .../Tooltip/trigger/TooltipTrigger.tsx | 8 +- .../trigger/TooltipTriggerDataAttributes.ts | 2 +- .../components/src/components/index.ts | 2 + .../src/components/use-button/useButton.ts | 11 +- .../src/components/use-render/useRender.ts | 6 +- .../components/src/lib/FloatingPortalLite.tsx | 2 +- .../components/src/lib/FocusGuard.tsx | 2 +- .../src/lib/createHeadlessUIEventDetails.ts | 60 ++- .../src/lib/hooks/useAnchorPositioning.ts | 35 +- .../src/lib/hooks/useAnchorPositioningDoc.md | 11 +- .../components/src/lib/hooks/useDirection.ts | 11 +- .../src/lib/hooks/useFocusableWhenDisabled.ts | 2 +- .../src/lib/hooks/useHeadlessUiId.ts | 2 +- .../src/lib/hooks/useRenderElement.tsx | 2 +- .../components/src/lib/parseNumeric.ts | 208 ++++++++-- .../components/src/lib/resolveValueLabel.ts | 2 +- .../src/lib/translateOpenChangeReason.ts | 22 +- .../components/FloatingDelayGroup.tsx | 9 +- .../components/FloatingFocusManager.tsx | 262 +++++++++---- .../components/FloatingPortal.tsx | 29 +- .../floating-ui-react/hooks/useClick.ts | 72 +++- .../floating-ui-react/hooks/useDismiss.ts | 60 +-- .../floating-ui-react/hooks/useFloating.ts | 2 +- .../hooks/useFloatingRootContext.ts | 14 +- .../floating-ui-react/hooks/useFocus.ts | 20 +- .../floating-ui-react/hooks/useHover.ts | 37 +- .../hooks/useListNavigation.ts | 356 +++++++++--------- .../src/packages/floating-ui-react/types.ts | 8 +- .../uikit/headless/components/tsconfig.json | 4 +- .../uikit/headless/components/vite.config.ts | 4 +- .../hooks/src/hooks/useAnimationFinished.ts | 80 ++-- .../hooks/src/hooks/useAnimationFrame.ts | 4 +- .../hooks/src/hooks/useControlledState.ts | 2 +- .../headless/hooks/src/hooks/useDidUpdate.ts | 19 +- .../src/hooks/useEnhancedClickHandler.ts | 38 +- .../hooks/src/hooks/useEnhancedEffect.ts | 2 +- .../hooks/src/hooks/useEventCallback.ts | 15 +- .../hooks/src/hooks/useForcedRerendering.ts | 2 +- .../uikit/headless/hooks/src/hooks/useId.ts | 2 +- .../headless/hooks/src/hooks/useInterval.ts | 2 - .../hooks/src/hooks/useIsoLayoutEffect.ts | 2 +- .../headless/hooks/src/hooks/useLatestRef.ts | 11 +- .../hooks/src/hooks/useOpenChangeComplete.ts | 2 +- .../hooks/src/hooks/useOpenInteractionType.ts | 10 +- .../headless/hooks/src/hooks/useScrollLock.ts | 6 +- .../hooks/src/hooks/useStore/ReactStor.ts | 245 ++++++++++++ .../hooks/src/hooks/useStore/Store.ts | 12 +- .../hooks/src/hooks/useStore/index.ts | 1 + .../headless/hooks/src/hooks/useTimeout.ts | 2 +- .../hooks/src/hooks/useTransitionStatus.ts | 4 +- .../ui/uikit/headless/hooks/tsconfig.json | 2 +- pnpm-lock.yaml | 119 ++++++ pnpm-workspace.yaml | 3 + 337 files changed, 4039 insertions(+), 3224 deletions(-) delete mode 100644 packages/ui/uikit/headless/components/src/components/Dialog/popup/useDialogPopup.ts create mode 100644 packages/ui/uikit/headless/components/src/components/Dialog/store.ts delete mode 100644 packages/ui/uikit/headless/components/src/components/Dialog/utils/DialogContext.ts create mode 100644 packages/ui/uikit/headless/components/src/components/Menu/utils/findRootOwnerId.ts create mode 100644 packages/ui/uikit/headless/components/src/components/Menu/utils/types.ts delete mode 100644 packages/ui/uikit/headless/components/src/components/Tooltip/root/useTooltipRoot.ts create mode 100644 packages/ui/uikit/headless/hooks/src/hooks/useStore/ReactStor.ts diff --git a/frontend/src/modules/auth/view/ui/Auth/Auth.tsx b/frontend/src/modules/auth/view/ui/Auth/Auth.tsx index 70ecebb5..f0032bc9 100644 --- a/frontend/src/modules/auth/view/ui/Auth/Auth.tsx +++ b/frontend/src/modules/auth/view/ui/Auth/Auth.tsx @@ -1,4 +1,4 @@ -'use client'; + import type { JSX } from 'react'; import type { TAuthContent } from '../../../types/TAuthContent'; diff --git a/frontend/src/modules/auth/view/ui/Auth/AuthorizationMethodContent/AuthorizationMethodContent.tsx b/frontend/src/modules/auth/view/ui/Auth/AuthorizationMethodContent/AuthorizationMethodContent.tsx index 6762ad2f..476919ec 100644 --- a/frontend/src/modules/auth/view/ui/Auth/AuthorizationMethodContent/AuthorizationMethodContent.tsx +++ b/frontend/src/modules/auth/view/ui/Auth/AuthorizationMethodContent/AuthorizationMethodContent.tsx @@ -1,4 +1,4 @@ -'use client'; + import type { TAuthProvider } from '@shared/query'; import type { ChangeEvent } from 'react'; diff --git a/frontend/src/modules/auth/view/ui/Auth/InputUsernameContent/InputUsernameContent.tsx b/frontend/src/modules/auth/view/ui/Auth/InputUsernameContent/InputUsernameContent.tsx index 65aa84af..076c55f4 100644 --- a/frontend/src/modules/auth/view/ui/Auth/InputUsernameContent/InputUsernameContent.tsx +++ b/frontend/src/modules/auth/view/ui/Auth/InputUsernameContent/InputUsernameContent.tsx @@ -1,4 +1,4 @@ -'use client'; + import type { ChangeEvent } from 'react'; import { LoadingButton } from '@shared/ui/Button'; diff --git a/frontend/src/modules/auth/view/ui/Auth/VerificationCodeContent/VerificationCodeContent.tsx b/frontend/src/modules/auth/view/ui/Auth/VerificationCodeContent/VerificationCodeContent.tsx index ca69b118..cadadacd 100644 --- a/frontend/src/modules/auth/view/ui/Auth/VerificationCodeContent/VerificationCodeContent.tsx +++ b/frontend/src/modules/auth/view/ui/Auth/VerificationCodeContent/VerificationCodeContent.tsx @@ -1,4 +1,4 @@ -'use client'; + import { ArrowIcon, EmailIcon } from '@shared/icons'; diff --git a/frontend/src/modules/auth/view/ui/AuthCallback/AuthCallback.tsx b/frontend/src/modules/auth/view/ui/AuthCallback/AuthCallback.tsx index 3ec5086e..dbd78e73 100644 --- a/frontend/src/modules/auth/view/ui/AuthCallback/AuthCallback.tsx +++ b/frontend/src/modules/auth/view/ui/AuthCallback/AuthCallback.tsx @@ -1,4 +1,4 @@ -'use client'; + import type { JSX } from 'react'; import { FadeTransition } from '@shared/ui/FadeTransition'; diff --git a/frontend/src/modules/auth/vm/useAuthorizationMethod.ts b/frontend/src/modules/auth/vm/useAuthorizationMethod.ts index 92f32c36..dd877135 100644 --- a/frontend/src/modules/auth/vm/useAuthorizationMethod.ts +++ b/frontend/src/modules/auth/vm/useAuthorizationMethod.ts @@ -1,4 +1,4 @@ -'use client'; + import { useUnit } from 'effector-react'; import { useEffect, useRef } from 'react'; diff --git a/frontend/src/modules/auth/vm/useVerificationCode.ts b/frontend/src/modules/auth/vm/useVerificationCode.ts index 558251cb..b5191fa8 100644 --- a/frontend/src/modules/auth/vm/useVerificationCode.ts +++ b/frontend/src/modules/auth/vm/useVerificationCode.ts @@ -1,4 +1,4 @@ -'use client'; + import type { TVerifyInputHandler } from '@shared/ui/Input'; import { useUnit } from 'effector-react'; diff --git a/frontend/src/shared/ui/Dialog/ui/Dialog.tsx b/frontend/src/shared/ui/Dialog/ui/Dialog.tsx index e442e1ee..21b6de29 100644 --- a/frontend/src/shared/ui/Dialog/ui/Dialog.tsx +++ b/frontend/src/shared/ui/Dialog/ui/Dialog.tsx @@ -1,4 +1,4 @@ -'use client'; + import type { TDialogProps } from '../types/TDialogProps'; import clsx from 'clsx'; diff --git a/frontend/src/shared/ui/Input/InputVerificationCode/ui/InputVerificationCode.tsx b/frontend/src/shared/ui/Input/InputVerificationCode/ui/InputVerificationCode.tsx index d4d3ff45..0f054c73 100644 --- a/frontend/src/shared/ui/Input/InputVerificationCode/ui/InputVerificationCode.tsx +++ b/frontend/src/shared/ui/Input/InputVerificationCode/ui/InputVerificationCode.tsx @@ -1,4 +1,4 @@ -'use client'; + import type { ChangeEvent, ClipboardEvent, KeyboardEvent, MouseEvent } from 'react'; diff --git a/frontend/src/widgets/ToastNotification/ui/Toast.tsx b/frontend/src/widgets/ToastNotification/ui/Toast.tsx index ba6d7bea..2a0ca4a6 100644 --- a/frontend/src/widgets/ToastNotification/ui/Toast.tsx +++ b/frontend/src/widgets/ToastNotification/ui/Toast.tsx @@ -1,4 +1,4 @@ -'use client'; + import type { JSX, MouseEvent } from 'react'; import type { TNotificationKind, TToastProps } from '../types/TToastProps'; diff --git a/packages/ui/uikit/headless/components/eslint.config.js b/packages/ui/uikit/headless/components/eslint.config.js index ea294a0a..32e416f7 100644 --- a/packages/ui/uikit/headless/components/eslint.config.js +++ b/packages/ui/uikit/headless/components/eslint.config.js @@ -24,7 +24,8 @@ export default createEslintConfig( format: ['camelCase', 'UPPER_CASE', 'PascalCase'], leadingUnderscore: 'allow', trailingUnderscore: 'allow' - }] + }], + 'ts/no-empty-object-type': 'off' } }, stylistic: { diff --git a/packages/ui/uikit/headless/components/package.json b/packages/ui/uikit/headless/components/package.json index 43d13a87..7dcab70f 100644 --- a/packages/ui/uikit/headless/components/package.json +++ b/packages/ui/uikit/headless/components/package.json @@ -80,6 +80,11 @@ "import": "./dist/components/Input/index.es.js", "require": "./dist/components/Input/index.cjs.js" }, + "./list": { + "types": "./dist/components/List/index.d.ts", + "import": "./dist/components/List/index.es.js", + "require": "./dist/components/List/index.cjs.js" + }, "./menu": { "types": "./dist/components/Menu/index.d.ts", "import": "./dist/components/Menu/index.es.js", @@ -115,6 +120,11 @@ "import": "./dist/components/Progress/index.es.js", "require": "./dist/components/Progress/index.cjs.js" }, + "./qr-code": { + "types": "./dist/components/QrCode/index.d.ts", + "import": "./dist/components/QrCode/index.es.js", + "require": "./dist/components/QrCode/index.cjs.js" + }, "./radio": { "types": "./dist/components/Radio/index.d.ts", "import": "./dist/components/Radio/index.es.js", @@ -230,6 +240,8 @@ "@floating-ui/react-dom": "catalog:", "@floating-ui/utils": "catalog:", "@vitejs/plugin-react": "catalog:", + "qr-code-styling": "catalog:", + "qrcode": "catalog:", "tabbable": "catalog:", "vite": "catalog:" }, @@ -241,6 +253,7 @@ "@testing-library/react": "catalog:", "@testing-library/user-event": "catalog:", "@types/node": "catalog:", + "@types/qrcode": "catalog:", "@types/react": "catalog:", "@types/react-dom": "catalog:", "@vitest/ui": "catalog:", diff --git a/packages/ui/uikit/headless/components/src/components/Accordion/header/AccordionHeader.tsx b/packages/ui/uikit/headless/components/src/components/Accordion/header/AccordionHeader.tsx index 7110ca6c..bf4ef86c 100644 --- a/packages/ui/uikit/headless/components/src/components/Accordion/header/AccordionHeader.tsx +++ b/packages/ui/uikit/headless/components/src/components/Accordion/header/AccordionHeader.tsx @@ -1,8 +1,6 @@ -'use client'; +import { useRenderElement } from '~@lib/hooks'; -import { useRenderElement } from '@lib/hooks'; - -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { useAccordionItemContext } from '../item/AccordionItemContext'; import { accordionStyleHookMapping } from '../item/styleHooks'; diff --git a/packages/ui/uikit/headless/components/src/components/Accordion/item/AccordionItem.tsx b/packages/ui/uikit/headless/components/src/components/Accordion/item/AccordionItem.tsx index e9e59283..f74cb6e1 100644 --- a/packages/ui/uikit/headless/components/src/components/Accordion/item/AccordionItem.tsx +++ b/packages/ui/uikit/headless/components/src/components/Accordion/item/AccordionItem.tsx @@ -1,13 +1,10 @@ -'use client'; - import React from 'react'; import { useEventCallback, useMergedRef } from '@flippo-ui/hooks'; +import { EMPTY_OBJECT } from '~@lib/constants'; +import { useHeadlessUiId, useRenderElement } from '~@lib/hooks'; -import { EMPTY_OBJECT } from '@lib/constants'; -import { useHeadlessUiId, useRenderElement } from '@lib/hooks'; - -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { CollapsibleRootContext } from '../../Collapsible/root/CollapsibleRootContext'; import { useCollapsibleRoot } from '../../Collapsible/root/useCollapsibleRoot'; @@ -15,13 +12,13 @@ import { useCompositeListItem } from '../../Composite/list/useCompositeListItem' import { useAccordionRootContext } from '../root/AccordionRootContext'; import type { CollapsibleRoot } from '../../Collapsible/root/CollapsibleRoot'; -import type { TCollapsibleRootContext } from '../../Collapsible/root/CollapsibleRootContext'; +import type { CollapsibleRootContextValue } from '../../Collapsible/root/CollapsibleRootContext'; import type { AccordionRoot } from '../root/AccordionRoot'; import { AccordionItemContext } from './AccordionItemContext'; import { accordionStyleHookMapping } from './styleHooks'; -import type { TAccordionItemContext } from './AccordionItemContext'; +import type { AccordionItemContextValue } from './AccordionItemContext'; /** * Groups an accordion header with the corresponding panel. @@ -70,10 +67,17 @@ export function AccordionItem(componentProps: AccordionItem.Props) { return false; }, [openValues, value]); - const onOpenChange = useEventCallback((nextOpen: boolean) => { - handleValueChange(value, nextOpen); - onOpenChangeProp?.(nextOpen); - }); + const onOpenChange = useEventCallback( + (nextOpen: boolean, eventDetails: CollapsibleRoot.ChangeEventDetails) => { + onOpenChangeProp?.(nextOpen, eventDetails); + + if (eventDetails.isCanceled) { + return; + } + + handleValueChange(value, nextOpen); + } + ); const collapsible = useCollapsibleRoot({ open: isOpen, @@ -90,7 +94,7 @@ export function AccordionItem(componentProps: AccordionItem.Props) { [collapsible.open, collapsible.disabled, collapsible.mounted] ); - const collapsibleContext: TCollapsibleRootContext = React.useMemo( + const collapsibleContext: CollapsibleRootContextValue = React.useMemo( () => ({ ...collapsible, onOpenChange, @@ -117,7 +121,7 @@ export function AccordionItem(componentProps: AccordionItem.Props) { const [triggerId, setTriggerId] = React.useState(useHeadlessUiId()); - const accordionItemContext: TAccordionItemContext = React.useMemo( + const accordionItemContext: AccordionItemContextValue = React.useMemo( () => ({ open: isOpen, state, diff --git a/packages/ui/uikit/headless/components/src/components/Accordion/item/AccordionItemContext.ts b/packages/ui/uikit/headless/components/src/components/Accordion/item/AccordionItemContext.ts index a50cac90..81eccc7e 100644 --- a/packages/ui/uikit/headless/components/src/components/Accordion/item/AccordionItemContext.ts +++ b/packages/ui/uikit/headless/components/src/components/Accordion/item/AccordionItemContext.ts @@ -1,17 +1,15 @@ -'use client'; - import React from 'react'; import type { AccordionItem } from './AccordionItem'; -export type TAccordionItemContext = { +export type AccordionItemContextValue = { open: boolean; state: AccordionItem.State; setTriggerId: (id: string | undefined) => void; triggerId?: string; }; -export const AccordionItemContext = React.createContext( +export const AccordionItemContext = React.createContext( undefined ); diff --git a/packages/ui/uikit/headless/components/src/components/Accordion/item/styleHooks.ts b/packages/ui/uikit/headless/components/src/components/Accordion/item/styleHooks.ts index 423cbd76..5a0e4974 100644 --- a/packages/ui/uikit/headless/components/src/components/Accordion/item/styleHooks.ts +++ b/packages/ui/uikit/headless/components/src/components/Accordion/item/styleHooks.ts @@ -1,7 +1,7 @@ -import { collapsibleOpenStateMapping } from '@lib/collapsibleOpenStateMapping'; -import { transitionStatusMapping } from '@lib/styleHookMapping'; +import { collapsibleOpenStateMapping } from '~@lib/collapsibleOpenStateMapping'; +import { transitionStatusMapping } from '~@lib/styleHookMapping'; -import type { CustomStyleHookMapping } from '@lib/getStyleHookProps'; +import type { CustomStyleHookMapping } from '~@lib/getStyleHookProps'; import { AccordionItemDataAttributes } from './AccordionItemDataAttributes'; diff --git a/packages/ui/uikit/headless/components/src/components/Accordion/panel/AccordionPanel.tsx b/packages/ui/uikit/headless/components/src/components/Accordion/panel/AccordionPanel.tsx index 158f481a..ae5af080 100644 --- a/packages/ui/uikit/headless/components/src/components/Accordion/panel/AccordionPanel.tsx +++ b/packages/ui/uikit/headless/components/src/components/Accordion/panel/AccordionPanel.tsx @@ -1,13 +1,11 @@ -'use client'; - import React from 'react'; import { useIsoLayoutEffect, useOpenChangeComplete } from '@flippo-ui/hooks'; -import { useRenderElement } from '@lib/hooks'; -import { warn } from '@lib/warn'; +import { useRenderElement } from '~@lib/hooks'; +import { warn } from '~@lib/warn'; import type { TransitionStatus } from '@flippo-ui/hooks'; -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { useCollapsiblePanel } from '../../Collapsible/panel/useCollapsiblePanel'; import { useCollapsibleRootContext } from '../../Collapsible/root/CollapsibleRootContext'; diff --git a/packages/ui/uikit/headless/components/src/components/Accordion/panel/AccordionPanelDataAttributes.ts b/packages/ui/uikit/headless/components/src/components/Accordion/panel/AccordionPanelDataAttributes.ts index 4cd381cf..46e06b3c 100644 --- a/packages/ui/uikit/headless/components/src/components/Accordion/panel/AccordionPanelDataAttributes.ts +++ b/packages/ui/uikit/headless/components/src/components/Accordion/panel/AccordionPanelDataAttributes.ts @@ -1,4 +1,4 @@ -import { TransitionStatusDataAttributes } from '@lib/styleHookMapping'; +import { TransitionStatusDataAttributes } from '~@lib/styleHookMapping'; export enum AccordionPanelDataAttributes { /** diff --git a/packages/ui/uikit/headless/components/src/components/Accordion/root/AccordionRoot.tsx b/packages/ui/uikit/headless/components/src/components/Accordion/root/AccordionRoot.tsx index 982c38b8..c5499a8a 100644 --- a/packages/ui/uikit/headless/components/src/components/Accordion/root/AccordionRoot.tsx +++ b/packages/ui/uikit/headless/components/src/components/Accordion/root/AccordionRoot.tsx @@ -1,19 +1,18 @@ -'use client'; - import React from 'react'; import { useControlledState, useEventCallback, useIsoLayoutEffect } from '@flippo-ui/hooks'; +import { createChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import { useDirection, useRenderElement } from '~@lib/hooks'; +import { warn } from '~@lib/warn'; -import { useDirection, useRenderElement } from '@lib/hooks'; -import { warn } from '@lib/warn'; - -import type { HeadlessUIComponentProps, Orientation } from '@lib/types'; +import type { HeadlessUIChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import type { HeadlessUIComponentProps, Orientation } from '~@lib/types'; import { CompositeList } from '../../Composite/list/CompositeList'; import { AccordionRootContext } from './AccordionRootContext'; -import type { TAccordionRootContext } from './AccordionRootContext'; +import type { AccordionRootContextValue } from './AccordionRootContext'; const rootStyleHookMapping = { value: () => null @@ -36,7 +35,7 @@ export function AccordionRoot(componentProps: AccordionRoot.Props) { keepMounted: keepMountedProp, loop = true, onValueChange: onValueChangeProp, - openMultiple = true, + multiple = true, orientation = 'vertical', value: valueProp, defaultValue: defaultValueProp, @@ -79,26 +78,36 @@ export function AccordionRoot(componentProps: AccordionRoot.Props) { const handleValueChange = React.useCallback( (newValue: number | string, nextOpen: boolean) => { - if (!openMultiple) { + const details = createChangeEventDetails('none'); + if (!multiple) { const nextValue = value[0] === newValue ? [] : [newValue]; + onValueChange(nextValue, details); + if (details.isCanceled) { + return; + } setValue(nextValue); - onValueChange(nextValue); } else if (nextOpen) { const nextOpenValues = value.slice(); nextOpenValues.push(newValue); + onValueChange(nextOpenValues, details); + if (details.isCanceled) { + return; + } setValue(nextOpenValues); - onValueChange(nextOpenValues); } else { const nextOpenValues = value.filter((v) => v !== newValue); + onValueChange(nextOpenValues, details); + if (details.isCanceled) { + return; + } setValue(nextOpenValues); - onValueChange(nextOpenValues); } }, [ + multiple, onValueChange, - openMultiple, setValue, value ] @@ -113,7 +122,7 @@ export function AccordionRoot(componentProps: AccordionRoot.Props) { [value, disabled, orientation] ); - const contextValue: TAccordionRootContext = React.useMemo( + const contextValue: AccordionRootContextValue = React.useMemo( () => ({ accordionItemRefs, direction, @@ -210,12 +219,12 @@ export namespace AccordionRoot { * Event handler called when an accordion item is expanded or collapsed. * Provides the new value as an argument. */ - onValueChange?: (value: AccordionValue) => void; + onValueChange?: (value: AccordionValue, eventDetails: ChangeEventDetails) => void; /** * Whether multiple items can be open at the same time. * @default true */ - openMultiple?: boolean; + multiple?: boolean; /** * The visual orientation of the accordion. * Controls whether roving focus uses left/right or up/down arrow keys. @@ -223,4 +232,7 @@ export namespace AccordionRoot { */ orientation?: Orientation; } & HeadlessUIComponentProps<'div', State>; + + export type ChangeEventReason = 'trigger-press' | 'none'; + export type ChangeEventDetails = HeadlessUIChangeEventDetails; } diff --git a/packages/ui/uikit/headless/components/src/components/Accordion/root/AccordionRootContext.ts b/packages/ui/uikit/headless/components/src/components/Accordion/root/AccordionRootContext.ts index dd0af0b2..f40cb501 100644 --- a/packages/ui/uikit/headless/components/src/components/Accordion/root/AccordionRootContext.ts +++ b/packages/ui/uikit/headless/components/src/components/Accordion/root/AccordionRootContext.ts @@ -1,14 +1,13 @@ -'use client'; -import * as React from 'react'; +import React from 'react'; -import type { TTextDirection } from '@lib/hooks'; -import type { Orientation } from '@lib/types'; +import type { TextDirection } from '~@lib/hooks'; +import type { Orientation } from '~@lib/types'; import type { AccordionRoot, AccordionValue } from './AccordionRoot'; -export type TAccordionRootContext = { +export type AccordionRootContextValue = { accordionItemRefs: React.RefObject<(HTMLElement | null)[]>; - direction: TTextDirection; + direction: TextDirection; disabled: boolean; handleValueChange: (newValue: number | string, nextOpen: boolean) => void; hiddenUntilFound: boolean; @@ -19,7 +18,7 @@ export type TAccordionRootContext = { value: AccordionValue; }; -export const AccordionRootContext = React.createContext( +export const AccordionRootContext = React.createContext( undefined ); diff --git a/packages/ui/uikit/headless/components/src/components/Accordion/trigger/AccordionTrigger.tsx b/packages/ui/uikit/headless/components/src/components/Accordion/trigger/AccordionTrigger.tsx index 6098f05b..d1a14ae0 100644 --- a/packages/ui/uikit/headless/components/src/components/Accordion/trigger/AccordionTrigger.tsx +++ b/packages/ui/uikit/headless/components/src/components/Accordion/trigger/AccordionTrigger.tsx @@ -1,14 +1,11 @@ -'use client'; - import React from 'react'; import { useIsoLayoutEffect } from '@flippo-ui/hooks'; +import { triggerOpenStateMapping } from '~@lib/collapsibleOpenStateMapping'; +import { useRenderElement } from '~@lib/hooks'; +import { isElementDisabled } from '~@lib/isElementDisabled'; -import { triggerOpenStateMapping } from '@lib/collapsibleOpenStateMapping'; -import { useRenderElement } from '@lib/hooks'; -import { isElementDisabled } from '@lib/isElementDisabled'; - -import type { HeadlessUIComponentProps, NativeButtonProps } from '@lib/types'; +import type { HeadlessUIComponentProps, NativeButtonProps } from '~@lib/types'; import { useCollapsibleRootContext } from '../../Collapsible/root/CollapsibleRootContext'; import { diff --git a/packages/ui/uikit/headless/components/src/components/Avatar/fallback/AvatarFallback.tsx b/packages/ui/uikit/headless/components/src/components/Avatar/fallback/AvatarFallback.tsx index 1ca4dc22..294adf2b 100644 --- a/packages/ui/uikit/headless/components/src/components/Avatar/fallback/AvatarFallback.tsx +++ b/packages/ui/uikit/headless/components/src/components/Avatar/fallback/AvatarFallback.tsx @@ -1,12 +1,12 @@ -'use client'; + import React from 'react'; import { useTimeout } from '@flippo-ui/hooks'; -import { useRenderElement } from '@lib/hooks'; +import { useRenderElement } from '~@lib/hooks'; -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { useAvatarRootContext } from '../root/AvatarRootContext'; import { avatarStyleHookMapping } from '../root/styleHooks'; diff --git a/packages/ui/uikit/headless/components/src/components/Avatar/image/AvatarImage.tsx b/packages/ui/uikit/headless/components/src/components/Avatar/image/AvatarImage.tsx index fddd6fe5..d793a96c 100644 --- a/packages/ui/uikit/headless/components/src/components/Avatar/image/AvatarImage.tsx +++ b/packages/ui/uikit/headless/components/src/components/Avatar/image/AvatarImage.tsx @@ -1,12 +1,12 @@ -'use client'; + import React from 'react'; import { useEventCallback, useIsoLayoutEffect } from '@flippo-ui/hooks'; -import { useRenderElement } from '@lib/hooks'; +import { useRenderElement } from '~@lib/hooks'; -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { useAvatarRootContext } from '../root/AvatarRootContext'; import { avatarStyleHookMapping } from '../root/styleHooks'; diff --git a/packages/ui/uikit/headless/components/src/components/Avatar/image/useImageLoadingStatus.ts b/packages/ui/uikit/headless/components/src/components/Avatar/image/useImageLoadingStatus.ts index 5dd571f2..6f0cbaa5 100644 --- a/packages/ui/uikit/headless/components/src/components/Avatar/image/useImageLoadingStatus.ts +++ b/packages/ui/uikit/headless/components/src/components/Avatar/image/useImageLoadingStatus.ts @@ -1,10 +1,10 @@ -'use client'; + import React from 'react'; import { useIsoLayoutEffect } from '@flippo-ui/hooks'; -import { NOOP } from '@lib/noop'; +import { NOOP } from '~@lib/noop'; export type ImageLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'; diff --git a/packages/ui/uikit/headless/components/src/components/Avatar/root/AvatarRoot.tsx b/packages/ui/uikit/headless/components/src/components/Avatar/root/AvatarRoot.tsx index 45ea494a..a2371b32 100644 --- a/packages/ui/uikit/headless/components/src/components/Avatar/root/AvatarRoot.tsx +++ b/packages/ui/uikit/headless/components/src/components/Avatar/root/AvatarRoot.tsx @@ -1,10 +1,10 @@ -'use client'; + import React from 'react'; -import { useRenderElement } from '@lib/hooks'; +import { useRenderElement } from '~@lib/hooks'; -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { AvatarRootContext } from './AvatarRootContext'; import { avatarStyleHookMapping } from './styleHooks'; diff --git a/packages/ui/uikit/headless/components/src/components/Avatar/root/AvatarRootContext.ts b/packages/ui/uikit/headless/components/src/components/Avatar/root/AvatarRootContext.ts index fd21f8fc..c0b7da6a 100644 --- a/packages/ui/uikit/headless/components/src/components/Avatar/root/AvatarRootContext.ts +++ b/packages/ui/uikit/headless/components/src/components/Avatar/root/AvatarRootContext.ts @@ -1,15 +1,13 @@ -'use client'; - import React from 'react'; import type { ImageLoadingStatus } from './AvatarRoot'; -export type TAvatarRootContext = { +export type AvatarRootContextValue = { imageLoadingStatus: ImageLoadingStatus; setImageLoadingStatus: React.Dispatch>; }; -export const AvatarRootContext = React.createContext(undefined); +export const AvatarRootContext = React.createContext(undefined); export function useAvatarRootContext() { const context = React.use(AvatarRootContext); diff --git a/packages/ui/uikit/headless/components/src/components/Checkbox/indicator/CheckboxIndicator.tsx b/packages/ui/uikit/headless/components/src/components/Checkbox/indicator/CheckboxIndicator.tsx index 076764aa..c2d8148f 100644 --- a/packages/ui/uikit/headless/components/src/components/Checkbox/indicator/CheckboxIndicator.tsx +++ b/packages/ui/uikit/headless/components/src/components/Checkbox/indicator/CheckboxIndicator.tsx @@ -1,4 +1,4 @@ -'use client'; + import React from 'react'; @@ -6,11 +6,11 @@ import { useOpenChangeComplete, useTransitionStatus } from '@flippo-ui/hooks'; import type { TransitionStatus } from '@flippo-ui/hooks'; -import { useRenderElement } from '@lib/hooks'; -import { transitionStatusMapping } from '@lib/styleHookMapping'; +import { useRenderElement } from '~@lib/hooks'; +import { transitionStatusMapping } from '~@lib/styleHookMapping'; -import type { CustomStyleHookMapping } from '@lib/getStyleHookProps'; -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { CustomStyleHookMapping } from '~@lib/getStyleHookProps'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { fieldValidityMapping } from '../../Field/utils/constants'; import { useCheckboxRootContext } from '../root/CheckboxRootContext'; diff --git a/packages/ui/uikit/headless/components/src/components/Checkbox/indicator/CheckboxIndicatorDataAttributes.ts b/packages/ui/uikit/headless/components/src/components/Checkbox/indicator/CheckboxIndicatorDataAttributes.ts index f48be822..6227f181 100644 --- a/packages/ui/uikit/headless/components/src/components/Checkbox/indicator/CheckboxIndicatorDataAttributes.ts +++ b/packages/ui/uikit/headless/components/src/components/Checkbox/indicator/CheckboxIndicatorDataAttributes.ts @@ -1,4 +1,4 @@ -import { TransitionStatusDataAttributes } from '@lib/styleHookMapping'; +import { TransitionStatusDataAttributes } from '~@lib/styleHookMapping'; export enum CheckboxIndicatorDataAttributes { /** diff --git a/packages/ui/uikit/headless/components/src/components/Checkbox/root/CheckboxRoot.tsx b/packages/ui/uikit/headless/components/src/components/Checkbox/root/CheckboxRoot.tsx index e7d4d9c3..a03decca 100644 --- a/packages/ui/uikit/headless/components/src/components/Checkbox/root/CheckboxRoot.tsx +++ b/packages/ui/uikit/headless/components/src/components/Checkbox/root/CheckboxRoot.tsx @@ -1,5 +1,3 @@ -'use client'; - import React from 'react'; import { @@ -8,12 +6,13 @@ import { useIsoLayoutEffect, useMergedRef } from '@flippo-ui/hooks'; +import { createChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import { useHeadlessUiId, useRenderElement } from '~@lib/hooks'; +import { mergeProps } from '~@lib/merge'; +import { visuallyHidden } from '~@lib/visuallyHidden'; -import { useHeadlessUiId, useRenderElement } from '@lib/hooks'; -import { mergeProps } from '@lib/merge'; -import { visuallyHidden } from '@lib/visuallyHidden'; - -import type { HeadlessUIComponentProps, NativeButtonProps } from '@lib/types'; +import type { HeadlessUIChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import type { HeadlessUIComponentProps, NativeButtonProps } from '~@lib/types'; import { useCheckboxGroupContext } from '../../CheckboxGroup/CheckboxGroupContext'; import { useFieldControlValidation } from '../../Field/control/useFieldControlValidation'; @@ -217,12 +216,18 @@ export function CheckboxRoot(componentProps: CheckboxRoot.Props) { } const nextChecked = event.target.checked; + const details = createChangeEventDetails('none', event.nativeEvent); + + groupOnChange?.(nextChecked, details); + onCheckedChange(nextChecked, details); + if (details.isCanceled) { + return; + } + + clearErrors(name); setDirty(nextChecked !== validityData.initialValue); setCheckedState(nextChecked); - groupOnChange?.(nextChecked, event.nativeEvent); - onCheckedChange(nextChecked, event.nativeEvent); - clearErrors(name); if (!groupContext) { setFilled(nextChecked); @@ -240,7 +245,7 @@ export function CheckboxRoot(componentProps: CheckboxRoot.Props) { ? [...groupValue, value] : groupValue.filter((item) => item !== value); - setGroupValue(nextGroupValue, event.nativeEvent); + setGroupValue(nextGroupValue, details); setFilled(nextGroupValue.length > 0); if (validationMode === 'onChange') { @@ -395,7 +400,7 @@ export namespace CheckboxRoot { * @param {boolean} checked The new checked state. * @param {Event} event The corresponding event that initiated the change. */ - onCheckedChange?: (checked: boolean, event: Event) => void; + onCheckedChange?: (checked: boolean, eventDetails: ChangeEventDetails) => void; /** * Whether the user should be unable to tick or untick the checkbox. * @default false @@ -427,4 +432,7 @@ export namespace CheckboxRoot { */ value?: string; } & NativeButtonProps & Omit, 'onChange' | 'value'>; + + export type ChangeEventReason = 'none'; + export type ChangeEventDetails = HeadlessUIChangeEventDetails; } diff --git a/packages/ui/uikit/headless/components/src/components/Checkbox/root/CheckboxRootContext.ts b/packages/ui/uikit/headless/components/src/components/Checkbox/root/CheckboxRootContext.ts index 9830fdb9..f89cc768 100644 --- a/packages/ui/uikit/headless/components/src/components/Checkbox/root/CheckboxRootContext.ts +++ b/packages/ui/uikit/headless/components/src/components/Checkbox/root/CheckboxRootContext.ts @@ -1,12 +1,10 @@ -'use client'; - import React from 'react'; import type { CheckboxRoot } from './CheckboxRoot'; -export type TCheckboxRootContext = CheckboxRoot.State; +export type CheckboxRootContextValue = CheckboxRoot.State; -export const CheckboxRootContext = React.createContext(undefined); +export const CheckboxRootContext = React.createContext(undefined); export function useCheckboxRootContext() { const context = React.use(CheckboxRootContext); diff --git a/packages/ui/uikit/headless/components/src/components/Checkbox/utils/useCustomStyleHookMapping.ts b/packages/ui/uikit/headless/components/src/components/Checkbox/utils/useCustomStyleHookMapping.ts index 5804c0d4..f6a0c85f 100644 --- a/packages/ui/uikit/headless/components/src/components/Checkbox/utils/useCustomStyleHookMapping.ts +++ b/packages/ui/uikit/headless/components/src/components/Checkbox/utils/useCustomStyleHookMapping.ts @@ -1,8 +1,8 @@ -'use client'; + import React from 'react'; -import type { CustomStyleHookMapping } from '@lib/getStyleHookProps'; +import type { CustomStyleHookMapping } from '~@lib/getStyleHookProps'; import { CheckboxRootDataAttributes } from '../root/CheckboxRootDataAttributes'; diff --git a/packages/ui/uikit/headless/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/ui/uikit/headless/components/src/components/CheckboxGroup/CheckboxGroup.tsx index c085e1af..81277344 100644 --- a/packages/ui/uikit/headless/components/src/components/CheckboxGroup/CheckboxGroup.tsx +++ b/packages/ui/uikit/headless/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -1,12 +1,10 @@ -'use client'; - import React from 'react'; import { useControlledState, useEventCallback } from '@flippo-ui/hooks'; +import { useHeadlessUiId, useRenderElement } from '~@lib/hooks'; -import { useHeadlessUiId, useRenderElement } from '@lib/hooks'; - -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { PARENT_CHECKBOX } from '../Checkbox/root/CheckboxRoot'; import { useFieldControlValidation } from '../Field/control/useFieldControlValidation'; @@ -19,7 +17,7 @@ import type { FieldRoot } from '../Field/root/FieldRoot'; import { CheckboxGroupContext } from './CheckboxGroupContext'; import { useCheckboxGroupParent } from './useCheckboxGroupParent'; -import type { TCheckboxGroupContext } from './CheckboxGroupContext'; +import type { CheckboxGroupContextValue } from './CheckboxGroupContext'; /** * Provides a shared state to a series of checkboxes. @@ -59,10 +57,17 @@ export function CheckboxGroup(componentProps: CheckboxGroup.Props) { caller: 'CheckboxGroup' }); - const setValue = useEventCallback((v: string[], event: Event) => { - setValueUnwrapped(v); - onValueChange?.(v, event); - }); + const setValue = useEventCallback( + (v: string[], eventDetails: CheckboxGroup.ChangeEventDetails) => { + onValueChange?.(v, eventDetails); + + if (eventDetails.isCanceled) { + return; + } + + setValueUnwrapped(v); + } + ); const parent = useCheckboxGroupParent({ allValues, @@ -97,7 +102,7 @@ export function CheckboxGroup(componentProps: CheckboxGroup.Props) { [fieldState, disabled] ); - const contextValue: TCheckboxGroupContext = React.useMemo( + const contextValue: CheckboxGroupContextValue = React.useMemo( () => ({ allValues, value, @@ -131,7 +136,7 @@ export function CheckboxGroup(componentProps: CheckboxGroup.Props) { }); return ( - {element} + {element} ); } @@ -160,7 +165,7 @@ export namespace CheckboxGroup { * Event handler called when a checkbox in the group is ticked or unticked. * Provides the new value as an argument. */ - onValueChange?: (value: string[], event: Event) => void; + onValueChange?: (value: string[], eventDetails: ChangeEventDetails) => void; /** * Names of all checkboxes in the group. Use this when creating a parent checkbox. */ @@ -171,4 +176,7 @@ export namespace CheckboxGroup { */ disabled?: boolean; } & HeadlessUIComponentProps<'div', State>; + + export type ChangeEventReason = 'none'; + export type ChangeEventDetails = HeadlessUIChangeEventDetails; } diff --git a/packages/ui/uikit/headless/components/src/components/CheckboxGroup/CheckboxGroupContext.ts b/packages/ui/uikit/headless/components/src/components/CheckboxGroup/CheckboxGroupContext.ts index 4cd8c3ee..195a3515 100644 --- a/packages/ui/uikit/headless/components/src/components/CheckboxGroup/CheckboxGroupContext.ts +++ b/packages/ui/uikit/headless/components/src/components/CheckboxGroup/CheckboxGroupContext.ts @@ -1,15 +1,15 @@ -'use client'; - import React from 'react'; +import type { HeadlessUIChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; + import type { useFieldControlValidation } from '../Field/control/useFieldControlValidation'; import type { useCheckboxGroupParent } from './useCheckboxGroupParent'; -export type TCheckboxGroupContext = { +export type CheckboxGroupContextValue = { value: string[] | undefined; defaultValue: string[] | undefined; - setValue: (value: string[], event: Event) => void; + setValue: (value: string[], eventDetails: HeadlessUIChangeEventDetails<'none'>) => void; allValues: string[] | undefined; parent: useCheckboxGroupParent.ReturnValue; disabled: boolean; @@ -17,12 +17,12 @@ export type TCheckboxGroupContext = { registerControlRef: (element: HTMLButtonElement | null) => void; }; -export const CheckboxGroupContext = React.createContext( +export const CheckboxGroupContext = React.createContext( undefined ); -export function useCheckboxGroupContext(optional: false): TCheckboxGroupContext; -export function useCheckboxGroupContext(optional?: true): TCheckboxGroupContext | undefined; +export function useCheckboxGroupContext(optional: false): CheckboxGroupContextValue; +export function useCheckboxGroupContext(optional?: true): CheckboxGroupContextValue | undefined; export function useCheckboxGroupContext(optional = true) { const context = React.use(CheckboxGroupContext); diff --git a/packages/ui/uikit/headless/components/src/components/CheckboxGroup/useCheckboxGroupParent.ts b/packages/ui/uikit/headless/components/src/components/CheckboxGroup/useCheckboxGroupParent.ts index 8c1c0023..93490beb 100644 --- a/packages/ui/uikit/headless/components/src/components/CheckboxGroup/useCheckboxGroupParent.ts +++ b/packages/ui/uikit/headless/components/src/components/CheckboxGroup/useCheckboxGroupParent.ts @@ -1,10 +1,9 @@ -'use client'; - import React from 'react'; import { useEventCallback } from '@flippo-ui/hooks'; +import { useHeadlessUiId } from '~@lib/hooks'; -import { useHeadlessUiId } from '@lib/hooks'; +import type { HeadlessUIChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; const EMPTY: string[] = []; @@ -30,7 +29,7 @@ export function useCheckboxGroupParent( indeterminate, checked, 'aria-controls': allValues.map((v) => `${id}-${v}`).join(' '), - onCheckedChange(_, event) { + onCheckedChange(_, eventDetails) { const uncontrolledState = uncontrolledStateRef.current; // None except the disabled ones that are checked, which can't be changed. @@ -51,24 +50,24 @@ export function useCheckboxGroupParent( if (allOnOrOff) { if (value.length === all.length) { - onValueChange(none, event); + onValueChange(none, eventDetails); } else { - onValueChange(all, event); + onValueChange(all, eventDetails); } return; } if (status === 'mixed') { - onValueChange(all, event); + onValueChange(all, eventDetails); setStatus('on'); } else if (status === 'on') { - onValueChange(none, event); + onValueChange(none, eventDetails); setStatus('off'); } else if (status === 'off') { - onValueChange(uncontrolledState, event); + onValueChange(uncontrolledState, eventDetails); setStatus('mixed'); } } @@ -126,7 +125,7 @@ export namespace useCheckboxGroupParent { export type Parameters = { allValues?: string[]; value?: string[]; - onValueChange?: (value: string[], event: Event) => void; + onValueChange?: (value: string[], eventDetails: HeadlessUIChangeEventDetails<'none'>) => void; }; export type ReturnValue = { @@ -138,13 +137,13 @@ export namespace useCheckboxGroupParent { 'indeterminate': boolean; 'checked': boolean; 'aria-controls': string; - 'onCheckedChange': (checked: boolean, event: Event) => void; + 'onCheckedChange': (checked: boolean, eventDetails: HeadlessUIChangeEventDetails<'none'>) => void; }; getChildProps: (name: string) => { name: string; id: string; checked: boolean; - onCheckedChange: (checked: boolean, event: Event) => void; + onCheckedChange: (checked: boolean, eventDetails: HeadlessUIChangeEventDetails<'none'>) => void; }; }; } diff --git a/packages/ui/uikit/headless/components/src/components/Collapsible/panel/CollapsiblePanel.tsx b/packages/ui/uikit/headless/components/src/components/Collapsible/panel/CollapsiblePanel.tsx index 338af3b2..3266c62f 100644 --- a/packages/ui/uikit/headless/components/src/components/Collapsible/panel/CollapsiblePanel.tsx +++ b/packages/ui/uikit/headless/components/src/components/Collapsible/panel/CollapsiblePanel.tsx @@ -1,13 +1,11 @@ -'use client'; - import React from 'react'; import { useIsoLayoutEffect, useOpenChangeComplete } from '@flippo-ui/hooks'; -import { useRenderElement } from '@lib/hooks'; -import { warn } from '@lib/warn'; +import { useRenderElement } from '~@lib/hooks'; +import { warn } from '~@lib/warn'; import type { TransitionStatus } from '@flippo-ui/hooks'; -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { useCollapsibleRootContext } from '../root/CollapsibleRootContext'; import { collapsibleStyleHookMapping } from '../root/styleHooks'; diff --git a/packages/ui/uikit/headless/components/src/components/Collapsible/panel/CollapsiblePanelDataAttributes.ts b/packages/ui/uikit/headless/components/src/components/Collapsible/panel/CollapsiblePanelDataAttributes.ts index d409c21f..567ecefe 100644 --- a/packages/ui/uikit/headless/components/src/components/Collapsible/panel/CollapsiblePanelDataAttributes.ts +++ b/packages/ui/uikit/headless/components/src/components/Collapsible/panel/CollapsiblePanelDataAttributes.ts @@ -1,4 +1,4 @@ -import { TransitionStatusDataAttributes } from '@lib/styleHookMapping'; +import { TransitionStatusDataAttributes } from '~@lib/styleHookMapping'; export enum CollapsiblePanelDataAttributes { /** diff --git a/packages/ui/uikit/headless/components/src/components/Collapsible/panel/useCollapsiblePanel.ts b/packages/ui/uikit/headless/components/src/components/Collapsible/panel/useCollapsiblePanel.ts index b34451de..6375fdf0 100644 --- a/packages/ui/uikit/headless/components/src/components/Collapsible/panel/useCollapsiblePanel.ts +++ b/packages/ui/uikit/headless/components/src/components/Collapsible/panel/useCollapsiblePanel.ts @@ -1,5 +1,3 @@ -'use client'; - import React from 'react'; import { @@ -9,10 +7,12 @@ import { useMergedRef, useOnMount } from '@flippo-ui/hooks'; -import { warn } from '@lib/warn'; +import { createChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import { warn } from '~@lib/warn'; -import type { HTMLProps } from '@lib/types'; +import type { HTMLProps } from '~@lib/types'; +import type { CollapsibleRoot } from '../root/CollapsibleRoot'; import type { AnimationType, Dimensions } from '../root/useCollapsibleRoot'; import { CollapsiblePanelDataAttributes } from './CollapsiblePanelDataAttributes'; @@ -379,10 +379,10 @@ export function useCollapsiblePanel( return undefined; } - function handleBeforeMatch() { + function handleBeforeMatch(event: Event) { isBeforeMatchRef.current = true; setOpen(true); - onOpenChange(true); + onOpenChange(true, createChangeEventDetails('none', event)); } panel.addEventListener('beforematch', handleBeforeMatch); @@ -435,7 +435,7 @@ export namespace useCollapsiblePanel { * Whether the collapsible panel is currently mounted. */ mounted: boolean; - onOpenChange: (open: boolean) => void; + onOpenChange: (open: boolean, eventDetails: CollapsibleRoot.ChangeEventDetails) => void; /** * Whether the collapsible panel is currently open. */ diff --git a/packages/ui/uikit/headless/components/src/components/Collapsible/root/CollapsibleRoot.tsx b/packages/ui/uikit/headless/components/src/components/Collapsible/root/CollapsibleRoot.tsx index 4b7791b1..8183e114 100644 --- a/packages/ui/uikit/headless/components/src/components/Collapsible/root/CollapsibleRoot.tsx +++ b/packages/ui/uikit/headless/components/src/components/Collapsible/root/CollapsibleRoot.tsx @@ -1,18 +1,16 @@ -'use client'; - import React from 'react'; import { useEventCallback } from '@flippo-ui/hooks'; +import { useRenderElement } from '~@lib/hooks'; -import { useRenderElement } from '@lib/hooks'; - -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { CollapsibleRootContext } from './CollapsibleRootContext'; import { collapsibleStyleHookMapping } from './styleHooks'; import { useCollapsibleRoot } from './useCollapsibleRoot'; -import type { TCollapsibleRootContext } from './CollapsibleRootContext'; +import type { CollapsibleRootContextValue } from './CollapsibleRootContext'; /** * Groups all parts of the collapsible. @@ -52,7 +50,7 @@ export function CollapsibleRoot(componentProps: CollapsibleRoot.Props) { [collapsible.open, collapsible.disabled, collapsible.transitionStatus] ); - const contextValue: TCollapsibleRootContext = React.useMemo( + const contextValue: CollapsibleRootContextValue = React.useMemo( () => ({ ...collapsible, onOpenChange, @@ -104,7 +102,7 @@ export namespace CollapsibleRoot { /** * Event handler called when the panel is opened or closed. */ - onOpenChange?: (open: boolean) => void; + onOpenChange?: (open: boolean, eventDetails: ChangeEventDetails) => void; /** * Whether the component should ignore user interaction. * @default false @@ -112,4 +110,7 @@ export namespace CollapsibleRoot { disabled?: boolean; render?: HeadlessUIComponentProps<'div', State>['render'] | null; } & Omit, 'render'>; + + export type ChangeEventReason = 'trigger-press' | 'none'; + export type ChangeEventDetails = HeadlessUIChangeEventDetails; } diff --git a/packages/ui/uikit/headless/components/src/components/Collapsible/root/CollapsibleRootContext.ts b/packages/ui/uikit/headless/components/src/components/Collapsible/root/CollapsibleRootContext.ts index 930b187c..b3fa58e4 100644 --- a/packages/ui/uikit/headless/components/src/components/Collapsible/root/CollapsibleRootContext.ts +++ b/packages/ui/uikit/headless/components/src/components/Collapsible/root/CollapsibleRootContext.ts @@ -1,5 +1,3 @@ -'use client'; - import React from 'react'; import type { TransitionStatus } from '@flippo-ui/hooks'; @@ -7,13 +5,13 @@ import type { TransitionStatus } from '@flippo-ui/hooks'; import type { CollapsibleRoot } from './CollapsibleRoot'; import type { useCollapsibleRoot } from './useCollapsibleRoot'; -export type TCollapsibleRootContext = { - onOpenChange: (open: boolean) => void; +export type CollapsibleRootContextValue = { + onOpenChange: (open: boolean, eventDetails: CollapsibleRoot.ChangeEventDetails) => void; state: CollapsibleRoot.State; transitionStatus: TransitionStatus; } & useCollapsibleRoot.ReturnValue; -export const CollapsibleRootContext = React.createContext( +export const CollapsibleRootContext = React.createContext( undefined ); diff --git a/packages/ui/uikit/headless/components/src/components/Collapsible/root/styleHooks.ts b/packages/ui/uikit/headless/components/src/components/Collapsible/root/styleHooks.ts index bdeb319f..8bd50d83 100644 --- a/packages/ui/uikit/headless/components/src/components/Collapsible/root/styleHooks.ts +++ b/packages/ui/uikit/headless/components/src/components/Collapsible/root/styleHooks.ts @@ -1,7 +1,7 @@ -import { collapsibleOpenStateMapping as commonCollapsibleMapping } from '@lib/collapsibleOpenStateMapping'; -import { transitionStatusMapping } from '@lib/styleHookMapping'; +import { collapsibleOpenStateMapping as commonCollapsibleMapping } from '~@lib/collapsibleOpenStateMapping'; +import { transitionStatusMapping } from '~@lib/styleHookMapping'; -import type { CustomStyleHookMapping } from '@lib/getStyleHookProps'; +import type { CustomStyleHookMapping } from '~@lib/getStyleHookProps'; import type { CollapsibleRoot } from './CollapsibleRoot'; diff --git a/packages/ui/uikit/headless/components/src/components/Collapsible/root/useCollapsibleRoot.ts b/packages/ui/uikit/headless/components/src/components/Collapsible/root/useCollapsibleRoot.ts index c0332d54..beb91556 100644 --- a/packages/ui/uikit/headless/components/src/components/Collapsible/root/useCollapsibleRoot.ts +++ b/packages/ui/uikit/headless/components/src/components/Collapsible/root/useCollapsibleRoot.ts @@ -1,5 +1,3 @@ -'use client'; - import React from 'react'; import { @@ -9,10 +7,12 @@ import { useIsoLayoutEffect, useTransitionStatus } from '@flippo-ui/hooks'; +import { createChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import { useHeadlessUiId } from '~@lib/hooks'; import type { TransitionStatus } from '@flippo-ui/hooks'; -import { useHeadlessUiId } from '@lib/hooks'; +import type { CollapsibleRoot } from './CollapsibleRoot'; export type AnimationType = 'css-transition' | 'css-animation' | 'none' | null; @@ -60,8 +60,15 @@ export function useCollapsibleRoot( const runOnceAnimationsFinish = useAnimationFinished(panelRef, false); - const handleTrigger = useEventCallback(() => { + const handleTrigger = useEventCallback((event: React.MouseEvent | React.KeyboardEvent) => { const nextOpen = !open; + const eventDetails = createChangeEventDetails('trigger-press', event.nativeEvent); + + onOpenChange(nextOpen, eventDetails); + + if (eventDetails.isCanceled) { + return; + } const panel = panelRef.current; @@ -87,12 +94,9 @@ export function useCollapsibleRoot( } setOpen(nextOpen); - onOpenChange(nextOpen); - if (animationTypeRef.current === 'none') { - if (mounted && !nextOpen) { - setMounted(false); - } + if (animationTypeRef.current === 'none' && mounted && !nextOpen) { + setMounted(false); } }); @@ -179,7 +183,7 @@ export namespace useCollapsibleRoot { /** * Event handler called when the panel is opened or closed. */ - onOpenChange: (open: boolean) => void; + onOpenChange: (open: boolean, eventDetails: CollapsibleRoot.ChangeEventDetails) => void; /** * Whether the component should ignore user interaction. * @default false @@ -194,7 +198,7 @@ export namespace useCollapsibleRoot { * Whether the component should ignore user interaction. */ disabled: boolean; - handleTrigger: () => void; + handleTrigger: (event: React.MouseEvent | React.KeyboardEvent) => void; /** * The height of the panel. */ diff --git a/packages/ui/uikit/headless/components/src/components/Collapsible/trigger/CollapsibleTrigger.tsx b/packages/ui/uikit/headless/components/src/components/Collapsible/trigger/CollapsibleTrigger.tsx index 1db85ffc..835c0586 100644 --- a/packages/ui/uikit/headless/components/src/components/Collapsible/trigger/CollapsibleTrigger.tsx +++ b/packages/ui/uikit/headless/components/src/components/Collapsible/trigger/CollapsibleTrigger.tsx @@ -1,20 +1,18 @@ -'use client'; - import React from 'react'; -import { triggerOpenStateMapping } from '@lib/collapsibleOpenStateMapping'; -import { useRenderElement } from '@lib/hooks'; -import { transitionStatusMapping } from '@lib/styleHookMapping'; +import { triggerOpenStateMapping } from '~@lib/collapsibleOpenStateMapping'; +import { useRenderElement } from '~@lib/hooks'; +import { transitionStatusMapping } from '~@lib/styleHookMapping'; -import type { CustomStyleHookMapping } from '@lib/getStyleHookProps'; -import type { HeadlessUIComponentProps, NativeButtonProps } from '@lib/types'; +import type { StateAttributesMapping } from '~@lib/getStyleHookProps'; +import type { HeadlessUIComponentProps, NativeButtonProps } from '~@lib/types'; import { useButton } from '../../use-button'; import { useCollapsibleRootContext } from '../root/CollapsibleRootContext'; import type { CollapsibleRoot } from '../root/CollapsibleRoot'; -const styleHookMapping: CustomStyleHookMapping = { +const styleHookMapping: StateAttributesMapping = { ...triggerOpenStateMapping, ...transitionStatusMapping }; diff --git a/packages/ui/uikit/headless/components/src/components/Collapsible/trigger/CollapsibleTriggerDataAttributes.ts b/packages/ui/uikit/headless/components/src/components/Collapsible/trigger/CollapsibleTriggerDataAttributes.ts index 12eea5d0..ba7f1f17 100644 --- a/packages/ui/uikit/headless/components/src/components/Collapsible/trigger/CollapsibleTriggerDataAttributes.ts +++ b/packages/ui/uikit/headless/components/src/components/Collapsible/trigger/CollapsibleTriggerDataAttributes.ts @@ -1,4 +1,4 @@ -import { CommonCollapsibleTriggerDataAttributes } from '@lib/collapsibleOpenStateMapping'; +import { CommonCollapsibleTriggerDataAttributes } from '~@lib/collapsibleOpenStateMapping'; export enum CollapsibleTriggerDataAttributes { /** diff --git a/packages/ui/uikit/headless/components/src/components/Composite/composite.ts b/packages/ui/uikit/headless/components/src/components/Composite/composite.ts index 5804ec0a..f5247fe7 100644 --- a/packages/ui/uikit/headless/components/src/components/Composite/composite.ts +++ b/packages/ui/uikit/headless/components/src/components/Composite/composite.ts @@ -1,4 +1,4 @@ -import type { TTextDirection } from '@lib/hooks/useDirection'; +import type { TextDirection } from '~@lib/hooks/useDirection'; export { createGridCellMap, @@ -11,7 +11,7 @@ export { isIndexOutOfListBounds, isListIndexDisabled, stopEvent -} from '@packages/floating-ui-react/utils'; +} from '~@packages/floating-ui-react/utils'; export type Dimensions = { width: number; @@ -77,7 +77,7 @@ export function isNativeInput( export function scrollIntoViewIfNeeded( scrollContainer: HTMLElement | null, element: HTMLElement | null, - direction: TTextDirection, + direction: TextDirection, orientation: 'horizontal' | 'vertical' | 'both' ) { if (!scrollContainer || !element || !element.scrollTo) { diff --git a/packages/ui/uikit/headless/components/src/components/Composite/item/CompositeItem.tsx b/packages/ui/uikit/headless/components/src/components/Composite/item/CompositeItem.tsx index 94bc9c24..f83e37cb 100644 --- a/packages/ui/uikit/headless/components/src/components/Composite/item/CompositeItem.tsx +++ b/packages/ui/uikit/headless/components/src/components/Composite/item/CompositeItem.tsx @@ -1,12 +1,12 @@ -'use client'; + import type React from 'react'; -import { EMPTY_ARRAY, EMPTY_OBJECT } from '@lib/constants'; -import { useRenderElement } from '@lib/hooks'; +import { EMPTY_ARRAY, EMPTY_OBJECT } from '~@lib/constants'; +import { useRenderElement } from '~@lib/hooks'; -import type { CustomStyleHookMapping } from '@lib/getStyleHookProps'; -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { CustomStyleHookMapping } from '~@lib/getStyleHookProps'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { useCompositeItem } from './useCompositeItem'; diff --git a/packages/ui/uikit/headless/components/src/components/Composite/item/useCompositeItem.ts b/packages/ui/uikit/headless/components/src/components/Composite/item/useCompositeItem.ts index 23c056a2..239dce5f 100644 --- a/packages/ui/uikit/headless/components/src/components/Composite/item/useCompositeItem.ts +++ b/packages/ui/uikit/headless/components/src/components/Composite/item/useCompositeItem.ts @@ -1,10 +1,10 @@ -'use client'; + import React from 'react'; import { useMergedRef } from '@flippo-ui/hooks'; -import type { HTMLProps } from '@lib/types'; +import type { HTMLProps } from '~@lib/types'; import { useCompositeListItem } from '../list/useCompositeListItem'; import { useCompositeRootContext } from '../root/CompositeRootContext'; diff --git a/packages/ui/uikit/headless/components/src/components/Composite/list/CompositeList.tsx b/packages/ui/uikit/headless/components/src/components/Composite/list/CompositeList.tsx index e3149699..d941bf17 100644 --- a/packages/ui/uikit/headless/components/src/components/Composite/list/CompositeList.tsx +++ b/packages/ui/uikit/headless/components/src/components/Composite/list/CompositeList.tsx @@ -1,4 +1,4 @@ -'use client'; + import React from 'react'; diff --git a/packages/ui/uikit/headless/components/src/components/Composite/list/CompositeListContext.ts b/packages/ui/uikit/headless/components/src/components/Composite/list/CompositeListContext.ts index 1913595d..1175a7d0 100644 --- a/packages/ui/uikit/headless/components/src/components/Composite/list/CompositeListContext.ts +++ b/packages/ui/uikit/headless/components/src/components/Composite/list/CompositeListContext.ts @@ -1,8 +1,6 @@ -'use client'; - import React from 'react'; -export type TCompositeListContext = { +export type CompositeListContextValue = { register: (node: Element, metadata: Metadata) => void; unregister: (node: Element) => void; subscribeMapChange: (fn: (map: Map) => void) => () => void; @@ -11,7 +9,7 @@ export type TCompositeListContext = { nextIndexRef: React.RefObject; }; -export const CompositeListContext = React.createContext>({ +export const CompositeListContext = React.createContext>({ register: () => {}, unregister: () => {}, subscribeMapChange: () => () => {}, diff --git a/packages/ui/uikit/headless/components/src/components/Composite/list/useCompositeListItem.ts b/packages/ui/uikit/headless/components/src/components/Composite/list/useCompositeListItem.ts index 12752b9d..3609570e 100644 --- a/packages/ui/uikit/headless/components/src/components/Composite/list/useCompositeListItem.ts +++ b/packages/ui/uikit/headless/components/src/components/Composite/list/useCompositeListItem.ts @@ -1,4 +1,4 @@ -'use client'; + import React from 'react'; diff --git a/packages/ui/uikit/headless/components/src/components/Composite/root/CompositeRoot.tsx b/packages/ui/uikit/headless/components/src/components/Composite/root/CompositeRoot.tsx index 4744f45a..1d15c0c8 100644 --- a/packages/ui/uikit/headless/components/src/components/Composite/root/CompositeRoot.tsx +++ b/packages/ui/uikit/headless/components/src/components/Composite/root/CompositeRoot.tsx @@ -1,14 +1,11 @@ -'use client'; - import React from 'react'; import { useEventCallback } from '@flippo-ui/hooks'; +import { EMPTY_ARRAY, EMPTY_OBJECT } from '~@lib/constants'; +import { useDirection, useRenderElement } from '~@lib/hooks'; -import { EMPTY_ARRAY, EMPTY_OBJECT } from '@lib/constants'; -import { useDirection, useRenderElement } from '@lib/hooks'; - -import type { CustomStyleHookMapping } from '@lib/getStyleHookProps'; -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { CustomStyleHookMapping } from '~@lib/getStyleHookProps'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { CompositeList } from '../list/CompositeList'; @@ -18,7 +15,7 @@ import type { CompositeMetadata } from '../list/CompositeList'; import { CompositeRootContext } from './CompositeRootContext'; import { useCompositeRoot } from './useCompositeRoot'; -import type { TCompositeRootContext } from './CompositeRootContext'; +import type { CompositeRootContextValue } from './CompositeRootContext'; /** * @internal @@ -90,7 +87,7 @@ export function CompositeRoot ({ highlightedIndex, onHighlightedIndexChange, highlightItemOnHover }), [highlightedIndex, onHighlightedIndexChange, highlightItemOnHover] ); diff --git a/packages/ui/uikit/headless/components/src/components/Composite/root/CompositeRootContext.ts b/packages/ui/uikit/headless/components/src/components/Composite/root/CompositeRootContext.ts index 2d76ae60..58bad0e3 100644 --- a/packages/ui/uikit/headless/components/src/components/Composite/root/CompositeRootContext.ts +++ b/packages/ui/uikit/headless/components/src/components/Composite/root/CompositeRootContext.ts @@ -1,19 +1,17 @@ -'use client'; - import React from 'react'; -export type TCompositeRootContext = { +export type CompositeRootContextValue = { highlightedIndex: number; onHighlightedIndexChange: (index: number, shouldScrollIntoView?: boolean) => void; highlightItemOnHover: boolean; }; -export const CompositeRootContext = React.createContext( +export const CompositeRootContext = React.createContext( undefined ); -export function useCompositeRootContext(optional: true): TCompositeRootContext | undefined; -export function useCompositeRootContext(optional?: false): TCompositeRootContext; +export function useCompositeRootContext(optional: true): CompositeRootContextValue | undefined; +export function useCompositeRootContext(optional?: false): CompositeRootContextValue; export function useCompositeRootContext(optional = false) { const context = React.use(CompositeRootContext); diff --git a/packages/ui/uikit/headless/components/src/components/Composite/root/useCompositeRoot.ts b/packages/ui/uikit/headless/components/src/components/Composite/root/useCompositeRoot.ts index b57f01d0..b5bf6570 100644 --- a/packages/ui/uikit/headless/components/src/components/Composite/root/useCompositeRoot.ts +++ b/packages/ui/uikit/headless/components/src/components/Composite/root/useCompositeRoot.ts @@ -1,16 +1,13 @@ -'use client'; - import React from 'react'; import { useEventCallback, useIsoLayoutEffect, useMergedRef } from '@flippo-ui/hooks'; +import { EMPTY_ARRAY } from '~@lib/constants'; +import { isElementDisabled } from '~@lib/isElementDisabled'; +import { ownerDocument } from '~@lib/owner'; +import { activeElement } from '~@packages/floating-ui-react/utils'; -import { EMPTY_ARRAY } from '@lib/constants'; -import { isElementDisabled } from '@lib/isElementDisabled'; -import { ownerDocument } from '@lib/owner'; -import { activeElement } from '@packages/floating-ui-react/utils'; - -import type { TTextDirection } from '@lib/hooks'; -import type { HTMLProps } from '@lib/types'; +import type { TextDirection } from '~@lib/hooks'; +import type { HTMLProps } from '~@lib/types'; import { ALL_KEYS, @@ -50,7 +47,7 @@ export type UseCompositeRootParameters = { highlightedIndex?: number; onHighlightedIndexChange?: (index: number) => void; dense?: boolean; - direction: TTextDirection; + direction: TextDirection; itemSizes?: Array; rootRef?: React.Ref; /** diff --git a/packages/ui/uikit/headless/components/src/components/ContextMenu/root/ContextMenuRoot.tsx b/packages/ui/uikit/headless/components/src/components/ContextMenu/root/ContextMenuRoot.tsx index 707fcb06..40e3e221 100644 --- a/packages/ui/uikit/headless/components/src/components/ContextMenu/root/ContextMenuRoot.tsx +++ b/packages/ui/uikit/headless/components/src/components/ContextMenu/root/ContextMenuRoot.tsx @@ -1,15 +1,17 @@ -'use client'; - import React from 'react'; import { useId } from '@flippo-ui/hooks'; +import type { HeadlessUIChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; + import { Menu } from '../../Menu'; import { MenuRootContext } from '../../Menu/root/MenuRootContext'; +import type { MenuRoot } from '../../Menu/root/MenuRoot'; + import { ContextMenuRootContext } from './ContextMenuRootContext'; -import type { TContextMenuRootContext } from './ContextMenuRootContext'; +import type { ContextMenuRootContextValue } from './ContextMenuRootContext'; /** * A component that creates a context menu activated by right clicking or long pressing. @@ -18,7 +20,7 @@ import type { TContextMenuRootContext } from './ContextMenuRootContext'; * Documentation: [Base UI Context Menu](https://base-ui.com/react/components/context-menu) */ export function ContextMenuRoot(props: ContextMenuRoot.Props) { - const [anchor, setAnchor] = React.useState({ + const [anchor, setAnchor] = React.useState({ getBoundingClientRect() { return DOMRect.fromRect({ width: 0, @@ -31,12 +33,12 @@ export function ContextMenuRoot(props: ContextMenuRoot.Props) { const backdropRef = React.useRef(null); const internalBackdropRef = React.useRef(null); - const actionsRef: TContextMenuRootContext['actionsRef'] = React.useRef(null); + const actionsRef: ContextMenuRootContextValue['actionsRef'] = React.useRef(null); const positionerRef = React.useRef(null); const allowMouseUpTriggerRef = React.useRef(true); const id = useId(); - const contextValue: TContextMenuRootContext = React.useMemo( + const contextValue: ContextMenuRootContextValue = React.useMemo( () => ({ anchor, setAnchor, @@ -63,4 +65,7 @@ export namespace ContextMenuRoot { export type State = object; export type Props = Omit; + + export type ChangeEventReason = MenuRoot.ChangeEventReason; + export type ChangeEventDetails = HeadlessUIChangeEventDetails; } diff --git a/packages/ui/uikit/headless/components/src/components/ContextMenu/root/ContextMenuRootContext.ts b/packages/ui/uikit/headless/components/src/components/ContextMenu/root/ContextMenuRootContext.ts index 7496aaad..70556fe0 100644 --- a/packages/ui/uikit/headless/components/src/components/ContextMenu/root/ContextMenuRootContext.ts +++ b/packages/ui/uikit/headless/components/src/components/ContextMenu/root/ContextMenuRootContext.ts @@ -1,26 +1,26 @@ import React from 'react'; -import type { TBaseOpenChangeReason } from '@lib/translateOpenChangeReason'; +import type { ContextMenuRoot } from './ContextMenuRoot'; -export type TContextMenuRootContext = { +export type ContextMenuRootContextValue = { anchor: { getBoundingClientRect: () => DOMRect }; - setAnchor: React.Dispatch>; + setAnchor: React.Dispatch>; backdropRef: React.RefObject; internalBackdropRef: React.RefObject; actionsRef: React.RefObject<{ - setOpen: (nextOpen: boolean, event?: Event, reason?: TBaseOpenChangeReason) => void; + setOpen: (nextOpen: boolean, eventDetails: ContextMenuRoot.ChangeEventDetails) => void; } | null>; positionerRef: React.RefObject; allowMouseUpTriggerRef: React.RefObject; rootId: string | undefined; }; -export const ContextMenuRootContext = React.createContext( +export const ContextMenuRootContext = React.createContext( undefined ); -export function useContextMenuRootContext(optional: false): TContextMenuRootContext; -export function useContextMenuRootContext(optional?: true): TContextMenuRootContext | undefined; +export function useContextMenuRootContext(optional: false): ContextMenuRootContextValue; +export function useContextMenuRootContext(optional?: true): ContextMenuRootContextValue | undefined; export function useContextMenuRootContext(optional = true) { const context = React.use(ContextMenuRootContext); diff --git a/packages/ui/uikit/headless/components/src/components/ContextMenu/trigger/ContextMenuTrigger.tsx b/packages/ui/uikit/headless/components/src/components/ContextMenu/trigger/ContextMenuTrigger.tsx index c1c283d2..080d11a1 100644 --- a/packages/ui/uikit/headless/components/src/components/ContextMenu/trigger/ContextMenuTrigger.tsx +++ b/packages/ui/uikit/headless/components/src/components/ContextMenu/trigger/ContextMenuTrigger.tsx @@ -1,15 +1,14 @@ -'use client'; - import React from 'react'; import { useEventCallback, useTimeout } from '@flippo-ui/hooks'; +import { createChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import { useRenderElement } from '~@lib/hooks'; +import { ownerDocument } from '~@lib/owner'; +import { contains, getTarget, stopEvent } from '~@packages/floating-ui-react/utils'; -import { useRenderElement } from '@lib/hooks'; -import { ownerDocument } from '@lib/owner'; -import { contains, getTarget, stopEvent } from '@packages/floating-ui-react/utils'; - -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { HeadlessUIComponentProps } from '~@lib/types'; +import { findRootOwnerId } from '../../Menu/utils/findRootOwnerId'; import { useContextMenuRootContext } from '../root/ContextMenuRootContext'; const LONG_PRESS_DELAY = 500; @@ -36,7 +35,8 @@ export function ContextMenuTrigger(componentProps: ContextMenuTrigger.Props) { internalBackdropRef, backdropRef, positionerRef, - allowMouseUpTriggerRef + allowMouseUpTriggerRef, + rootId } = useContextMenuRootContext(false); const triggerRef = React.useRef(null); @@ -45,27 +45,29 @@ export function ContextMenuTrigger(componentProps: ContextMenuTrigger.Props) { const allowMouseUpTimeout = useTimeout(); const allowMouseUpRef = React.useRef(false); - const handleLongPress = useEventCallback((x: number, y: number, event: Event) => { - const isTouchEvent = event.type.startsWith('touch'); - - setAnchor({ - getBoundingClientRect() { - return DOMRect.fromRect({ - width: isTouchEvent ? 10 : 0, - height: isTouchEvent ? 10 : 0, - x, - y - }); - } - }); + const handleLongPress = useEventCallback( + (x: number, y: number, event: MouseEvent | TouchEvent) => { + const isTouchEvent = event.type.startsWith('touch'); + + setAnchor({ + getBoundingClientRect() { + return DOMRect.fromRect({ + width: isTouchEvent ? 10 : 0, + height: isTouchEvent ? 10 : 0, + x, + y + }); + } + }); - allowMouseUpRef.current = false; - actionsRef.current?.setOpen(true, event); + allowMouseUpRef.current = false; + actionsRef.current?.setOpen(true, createChangeEventDetails('trigger-press', event)); - allowMouseUpTimeout.start(LONG_PRESS_DELAY, () => { - allowMouseUpRef.current = true; - }); - }); + allowMouseUpTimeout.start(LONG_PRESS_DELAY, () => { + allowMouseUpRef.current = true; + }); + } + ); const handleContextMenu = useEventCallback((event: React.MouseEvent) => { allowMouseUpTriggerRef.current = true; @@ -85,11 +87,17 @@ export function ContextMenuTrigger(componentProps: ContextMenuTrigger.Props) { allowMouseUpTimeout.clear(); allowMouseUpRef.current = false; - if (contains(positionerRef.current, getTarget(mouseEvent) as Element | null)) { + const mouseUpTarget = getTarget(mouseEvent) as Element | null; + + if (contains(positionerRef.current, mouseUpTarget)) { + return; + } + + if (rootId && mouseUpTarget && findRootOwnerId(mouseUpTarget) === rootId) { return; } - actionsRef.current?.setOpen(false, mouseEvent, 'cancel-open'); + actionsRef.current?.setOpen(false, createChangeEventDetails('cancel-open', mouseEvent)); }, { once: true } ); diff --git a/packages/ui/uikit/headless/components/src/components/Dialog/backdrop/DialogBackdrop.tsx b/packages/ui/uikit/headless/components/src/components/Dialog/backdrop/DialogBackdrop.tsx index 2cbe4f86..f664c96d 100644 --- a/packages/ui/uikit/headless/components/src/components/Dialog/backdrop/DialogBackdrop.tsx +++ b/packages/ui/uikit/headless/components/src/components/Dialog/backdrop/DialogBackdrop.tsx @@ -1,19 +1,16 @@ -'use client'; - import React from 'react'; -import type { TransitionStatus } from '@flippo-ui/hooks'; - -import { useRenderElement } from '@lib/hooks'; -import { popupStateMapping } from '@lib/popupStateMapping'; -import { transitionStatusMapping } from '@lib/styleHookMapping'; +import { useRenderElement } from '~@lib/hooks'; +import { popupStateMapping } from '~@lib/popupStateMapping'; +import { transitionStatusMapping } from '~@lib/styleHookMapping'; -import type { CustomStyleHookMapping } from '@lib/getStyleHookProps'; -import type { HeadlessUIComponentProps } from '@lib/types'; +import type { TransitionStatus } from '@flippo-ui/hooks'; +import type { StateAttributesMapping } from '~@lib/getStyleHookProps'; +import type { HeadlessUIComponentProps } from '~@lib/types'; import { useDialogRootContext } from '../root/DialogRootContext'; -const customStyleHookMapping: CustomStyleHookMapping = { +const customStyleHookMapping: StateAttributesMapping = { ...popupStateMapping, ...transitionStatusMapping }; @@ -35,13 +32,12 @@ export function DialogBackdrop(componentProps: DialogBackdrop.Props) { ...elementProps } = componentProps; - const { - open, - nested, - mounted, - transitionStatus, - backdropRef - } = useDialogRootContext(); + const { store } = useDialogRootContext(); + + const open = store.useState('open'); + const nested = store.useState('nested'); + const mounted = store.useState('mounted'); + const transitionStatus = store.useState('transitionStatus'); const state: DialogBackdrop.State = React.useMemo( () => ({ @@ -53,7 +49,7 @@ export function DialogBackdrop(componentProps: DialogBackdrop.Props) { return useRenderElement('div', componentProps, { state, - ref: [backdropRef, ref], + ref: [store.context.backdropRef, ref], customStyleHookMapping, props: [{ role: 'presentation', diff --git a/packages/ui/uikit/headless/components/src/components/Dialog/backdrop/DialogBackdropDataAttributes.ts b/packages/ui/uikit/headless/components/src/components/Dialog/backdrop/DialogBackdropDataAttributes.ts index 2d6bf3af..91bf751b 100644 --- a/packages/ui/uikit/headless/components/src/components/Dialog/backdrop/DialogBackdropDataAttributes.ts +++ b/packages/ui/uikit/headless/components/src/components/Dialog/backdrop/DialogBackdropDataAttributes.ts @@ -1,4 +1,4 @@ -import { CommonPopupDataAttributes } from '@lib/popupStateMapping'; +import { CommonPopupDataAttributes } from '~@lib/popupStateMapping'; export enum DialogBackdropDataAttributes { /** diff --git a/packages/ui/uikit/headless/components/src/components/Dialog/close/DialogClose.tsx b/packages/ui/uikit/headless/components/src/components/Dialog/close/DialogClose.tsx index bccbd9b1..c60ada1b 100644 --- a/packages/ui/uikit/headless/components/src/components/Dialog/close/DialogClose.tsx +++ b/packages/ui/uikit/headless/components/src/components/Dialog/close/DialogClose.tsx @@ -1,10 +1,8 @@ -'use client'; - import React from 'react'; -import { useRenderElement } from '@lib/hooks'; +import { useRenderElement } from '~@lib/hooks'; -import type { HeadlessUIComponentProps, NativeButtonProps } from '@lib/types'; +import type { HeadlessUIComponentProps, NativeButtonProps } from '~@lib/types'; import { useDialogRootContext } from '../root/DialogRootContext'; @@ -27,11 +25,13 @@ export function DialogClose(componentProps: DialogClose.Props) { ref, ...elementProps } = componentProps; - const { open, setOpen } = useDialogRootContext(); + const { store } = useDialogRootContext(); + const open = store.useState('open'); + const { getRootProps, buttonRef } = useDialogClose({ disabled, open, - setOpen, + setOpen: store.setOpen, nativeButton }); diff --git a/packages/ui/uikit/headless/components/src/components/Dialog/close/useDialogClose.ts b/packages/ui/uikit/headless/components/src/components/Dialog/close/useDialogClose.ts index 35cd3589..789ebb26 100644 --- a/packages/ui/uikit/headless/components/src/components/Dialog/close/useDialogClose.ts +++ b/packages/ui/uikit/headless/components/src/components/Dialog/close/useDialogClose.ts @@ -1,12 +1,10 @@ -'use client'; - import type React from 'react'; import { useEventCallback } from '@flippo-ui/hooks'; +import { createChangeEventDetails } from '~@lib/createHeadlessUIEventDetails'; +import { mergeProps } from '~@lib/merge'; -import { mergeProps } from '@lib/merge'; - -import type { HTMLProps } from '@lib/types'; +import type { HTMLProps } from '~@lib/types'; import { useButton } from '../../use-button/useButton'; @@ -22,7 +20,7 @@ export function useDialogClose(params: useDialogClose.Parameters): useDialogClos const handleClick = useEventCallback((event: React.MouseEvent) => { if (open) { - setOpen(false, event.nativeEvent, 'close-press'); + setOpen(false, createChangeEventDetails('close-press', event.nativeEvent)); } }); @@ -53,11 +51,7 @@ export namespace useDialogClose { /** * Event handler called when the dialog is opened or closed. */ - setOpen: ( - open: boolean, - event: Event | undefined, - reason: DialogRoot.OpenChangeReason | undefined, - ) => void; + setOpen: (open: boolean, eventDetails: DialogRoot.ChangeEventDetails) => void; /** * Whether the component renders a native `