@neut/ui 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/calendar/Calendar/Calendar.d.ts +10 -0
- package/dist/components/calendar/Calendar/Calendar.js +306 -0
- package/dist/components/calendar/Calendar/Calendar.js.map +1 -0
- package/dist/components/calendar/Calendar/Calendar.types.d.ts +62 -0
- package/dist/components/calendar/Calendar/Calendar.utils.d.ts +21 -0
- package/dist/components/calendar/Calendar/Calendar.utils.js +68 -0
- package/dist/components/calendar/Calendar/Calendar.utils.js.map +1 -0
- package/dist/components/calendar/Calendar/index.d.ts +2 -0
- package/dist/components/calendar/index.d.ts +2 -0
- package/dist/components/calendar/index.js +2 -0
- package/dist/components/combobox/Combobox/Combobox.context.d.ts +3 -0
- package/dist/components/combobox/Combobox/Combobox.context.js +12 -0
- package/dist/components/combobox/Combobox/Combobox.context.js.map +1 -0
- package/dist/components/combobox/Combobox/Combobox.d.ts +3 -0
- package/dist/components/combobox/Combobox/Combobox.js +60 -0
- package/dist/components/combobox/Combobox/Combobox.js.map +1 -0
- package/dist/components/combobox/Combobox/Combobox.types.d.ts +40 -0
- package/dist/components/combobox/Combobox/index.d.ts +2 -0
- package/dist/components/combobox/ComboboxChip/ComboboxChip.d.ts +7 -0
- package/dist/components/combobox/ComboboxChip/ComboboxChip.js +35 -0
- package/dist/components/combobox/ComboboxChip/ComboboxChip.js.map +1 -0
- package/dist/components/combobox/ComboboxChip/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxChips/ComboboxChips.d.ts +5 -0
- package/dist/components/combobox/ComboboxChips/ComboboxChips.js +16 -0
- package/dist/components/combobox/ComboboxChips/ComboboxChips.js.map +1 -0
- package/dist/components/combobox/ComboboxChips/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxChipsInput/ComboboxChipsInput.d.ts +4 -0
- package/dist/components/combobox/ComboboxChipsInput/ComboboxChipsInput.js +27 -0
- package/dist/components/combobox/ComboboxChipsInput/ComboboxChipsInput.js.map +1 -0
- package/dist/components/combobox/ComboboxChipsInput/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxClear/ComboboxClear.d.ts +4 -0
- package/dist/components/combobox/ComboboxClear/ComboboxClear.js +30 -0
- package/dist/components/combobox/ComboboxClear/ComboboxClear.js.map +1 -0
- package/dist/components/combobox/ComboboxClear/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxCollection/ComboboxCollection.d.ts +5 -0
- package/dist/components/combobox/ComboboxCollection/ComboboxCollection.js +20 -0
- package/dist/components/combobox/ComboboxCollection/ComboboxCollection.js.map +1 -0
- package/dist/components/combobox/ComboboxCollection/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxContent/ComboboxContent.d.ts +2 -0
- package/dist/components/combobox/ComboboxContent/ComboboxContent.js +49 -0
- package/dist/components/combobox/ComboboxContent/ComboboxContent.js.map +1 -0
- package/dist/components/combobox/ComboboxContent/ComboboxContent.types.d.ts +12 -0
- package/dist/components/combobox/ComboboxContent/ComboboxContent.utils.d.ts +2 -0
- package/dist/components/combobox/ComboboxContent/ComboboxContent.utils.js +6 -0
- package/dist/components/combobox/ComboboxContent/ComboboxContent.utils.js.map +1 -0
- package/dist/components/combobox/ComboboxContent/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxContent/useComboboxContent.d.ts +13 -0
- package/dist/components/combobox/ComboboxContent/useComboboxContent.js +48 -0
- package/dist/components/combobox/ComboboxContent/useComboboxContent.js.map +1 -0
- package/dist/components/combobox/ComboboxEmpty/ComboboxEmpty.d.ts +5 -0
- package/dist/components/combobox/ComboboxEmpty/ComboboxEmpty.js +14 -0
- package/dist/components/combobox/ComboboxEmpty/ComboboxEmpty.js.map +1 -0
- package/dist/components/combobox/ComboboxEmpty/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxGroup/ComboboxGroup.d.ts +5 -0
- package/dist/components/combobox/ComboboxGroup/ComboboxGroup.js +13 -0
- package/dist/components/combobox/ComboboxGroup/ComboboxGroup.js.map +1 -0
- package/dist/components/combobox/ComboboxGroup/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxInput/ComboboxInput.d.ts +9 -0
- package/dist/components/combobox/ComboboxInput/ComboboxInput.js +85 -0
- package/dist/components/combobox/ComboboxInput/ComboboxInput.js.map +1 -0
- package/dist/components/combobox/ComboboxInput/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxItem/ComboboxItem.d.ts +7 -0
- package/dist/components/combobox/ComboboxItem/ComboboxItem.js +40 -0
- package/dist/components/combobox/ComboboxItem/ComboboxItem.js.map +1 -0
- package/dist/components/combobox/ComboboxItem/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxLabel/ComboboxLabel.d.ts +5 -0
- package/dist/components/combobox/ComboboxLabel/ComboboxLabel.js +14 -0
- package/dist/components/combobox/ComboboxLabel/ComboboxLabel.js.map +1 -0
- package/dist/components/combobox/ComboboxLabel/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxList/ComboboxList.d.ts +5 -0
- package/dist/components/combobox/ComboboxList/ComboboxList.js +22 -0
- package/dist/components/combobox/ComboboxList/ComboboxList.js.map +1 -0
- package/dist/components/combobox/ComboboxList/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxSeparator/ComboboxSeparator.d.ts +3 -0
- package/dist/components/combobox/ComboboxSeparator/ComboboxSeparator.js +14 -0
- package/dist/components/combobox/ComboboxSeparator/ComboboxSeparator.js.map +1 -0
- package/dist/components/combobox/ComboboxSeparator/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxTrigger/ComboboxTrigger.d.ts +6 -0
- package/dist/components/combobox/ComboboxTrigger/ComboboxTrigger.js +34 -0
- package/dist/components/combobox/ComboboxTrigger/ComboboxTrigger.js.map +1 -0
- package/dist/components/combobox/ComboboxTrigger/index.d.ts +1 -0
- package/dist/components/combobox/ComboboxValue/ComboboxValue.d.ts +5 -0
- package/dist/components/combobox/ComboboxValue/ComboboxValue.js +15 -0
- package/dist/components/combobox/ComboboxValue/ComboboxValue.js.map +1 -0
- package/dist/components/combobox/ComboboxValue/index.d.ts +1 -0
- package/dist/components/combobox/index.d.ts +18 -0
- package/dist/components/combobox/index.js +18 -0
- package/dist/components/combobox/useComboboxAnchor/index.d.ts +1 -0
- package/dist/components/combobox/useComboboxAnchor/useComboboxAnchor.d.ts +1 -0
- package/dist/components/combobox/useComboboxAnchor/useComboboxAnchor.js +9 -0
- package/dist/components/combobox/useComboboxAnchor/useComboboxAnchor.js.map +1 -0
- package/dist/components/date-picker/DatePicker/DatePicker.d.ts +11 -0
- package/dist/components/date-picker/DatePicker/DatePicker.js +136 -0
- package/dist/components/date-picker/DatePicker/DatePicker.js.map +1 -0
- package/dist/components/date-picker/DatePicker/DatePicker.types.d.ts +32 -0
- package/dist/components/date-picker/DatePicker/index.d.ts +2 -0
- package/dist/components/date-picker/index.d.ts +2 -0
- package/dist/components/date-picker/index.js +2 -0
- package/dist/components/dialog/Dialog/Dialog.context.d.ts +2 -1
- package/dist/components/dialog/Dialog/Dialog.context.js.map +1 -1
- package/dist/components/dialog/Dialog/Dialog.js +21 -12
- package/dist/components/dialog/Dialog/Dialog.js.map +1 -1
- package/dist/components/dialog/Dialog/Dialog.types.d.ts +13 -1
- package/dist/components/dialog/Dialog/index.d.ts +1 -0
- package/dist/components/dialog/DialogTrigger/DialogTrigger.d.ts +4 -2
- package/dist/components/dialog/DialogTrigger/DialogTrigger.js +27 -6
- package/dist/components/dialog/DialogTrigger/DialogTrigger.js.map +1 -1
- package/dist/components/dialog/DialogTrigger/DialogTrigger.types.d.ts +3 -0
- package/dist/components/dialog/DialogTrigger/index.d.ts +3 -0
- package/dist/components/dialog/DialogTrigger/useDialogTrigger.d.ts +13 -2
- package/dist/components/dialog/DialogTrigger/useDialogTrigger.js +15 -19
- package/dist/components/dialog/DialogTrigger/useDialogTrigger.js.map +1 -1
- package/dist/components/dialog/index.js +3 -2
- package/dist/components/empty/Empty/Empty.d.ts +2 -0
- package/dist/components/empty/Empty/Empty.js +18 -0
- package/dist/components/empty/Empty/Empty.js.map +1 -0
- package/dist/components/empty/Empty/index.d.ts +1 -0
- package/dist/components/empty/EmptyContent/EmptyContent.d.ts +2 -0
- package/dist/components/empty/EmptyContent/EmptyContent.js +18 -0
- package/dist/components/empty/EmptyContent/EmptyContent.js.map +1 -0
- package/dist/components/empty/EmptyContent/index.d.ts +1 -0
- package/dist/components/empty/EmptyDescription/EmptyDescription.d.ts +2 -0
- package/dist/components/empty/EmptyDescription/EmptyDescription.js +18 -0
- package/dist/components/empty/EmptyDescription/EmptyDescription.js.map +1 -0
- package/dist/components/empty/EmptyDescription/index.d.ts +1 -0
- package/dist/components/empty/EmptyHeader/EmptyHeader.d.ts +2 -0
- package/dist/components/empty/EmptyHeader/EmptyHeader.js +18 -0
- package/dist/components/empty/EmptyHeader/EmptyHeader.js.map +1 -0
- package/dist/components/empty/EmptyHeader/index.d.ts +1 -0
- package/dist/components/empty/EmptyMedia/EmptyMedia.d.ts +4 -0
- package/dist/components/empty/EmptyMedia/EmptyMedia.js +27 -0
- package/dist/components/empty/EmptyMedia/EmptyMedia.js.map +1 -0
- package/dist/components/empty/EmptyMedia/EmptyMedia.styles.d.ts +3 -0
- package/dist/components/empty/EmptyMedia/EmptyMedia.styles.js +13 -0
- package/dist/components/empty/EmptyMedia/EmptyMedia.styles.js.map +1 -0
- package/dist/components/empty/EmptyMedia/EmptyMedia.types.d.ts +3 -0
- package/dist/components/empty/EmptyMedia/index.d.ts +2 -0
- package/dist/components/empty/EmptyTitle/EmptyTitle.d.ts +2 -0
- package/dist/components/empty/EmptyTitle/EmptyTitle.js +18 -0
- package/dist/components/empty/EmptyTitle/EmptyTitle.js.map +1 -0
- package/dist/components/empty/EmptyTitle/index.d.ts +1 -0
- package/dist/components/empty/index.d.ts +7 -0
- package/dist/components/empty/index.js +7 -0
- package/dist/components/image/Image.utils.js.map +1 -1
- package/dist/components/popover/Popover/Popover.context.d.ts +3 -0
- package/dist/components/popover/Popover/Popover.context.js +12 -0
- package/dist/components/popover/Popover/Popover.context.js.map +1 -0
- package/dist/components/popover/Popover/Popover.d.ts +18 -0
- package/dist/components/popover/Popover/Popover.js +37 -0
- package/dist/components/popover/Popover/Popover.js.map +1 -0
- package/dist/components/popover/Popover/Popover.types.d.ts +24 -0
- package/dist/components/popover/Popover/index.d.ts +3 -0
- package/dist/components/popover/PopoverContent/PopoverContent.d.ts +6 -0
- package/dist/components/popover/PopoverContent/PopoverContent.js +72 -0
- package/dist/components/popover/PopoverContent/PopoverContent.js.map +1 -0
- package/dist/components/popover/PopoverContent/PopoverContent.types.d.ts +16 -0
- package/dist/components/popover/PopoverContent/PopoverContent.utils.d.ts +20 -0
- package/dist/components/popover/PopoverContent/PopoverContent.utils.js +36 -0
- package/dist/components/popover/PopoverContent/PopoverContent.utils.js.map +1 -0
- package/dist/components/popover/PopoverContent/index.d.ts +6 -0
- package/dist/components/popover/PopoverContent/usePopoverContent.d.ts +11 -0
- package/dist/components/popover/PopoverContent/usePopoverContent.js +42 -0
- package/dist/components/popover/PopoverContent/usePopoverContent.js.map +1 -0
- package/dist/components/popover/PopoverDescription/PopoverDescription.d.ts +2 -0
- package/dist/components/popover/PopoverDescription/PopoverDescription.js +18 -0
- package/dist/components/popover/PopoverDescription/PopoverDescription.js.map +1 -0
- package/dist/components/popover/PopoverDescription/index.d.ts +1 -0
- package/dist/components/popover/PopoverHeader/PopoverHeader.d.ts +2 -0
- package/dist/components/popover/PopoverHeader/PopoverHeader.js +18 -0
- package/dist/components/popover/PopoverHeader/PopoverHeader.js.map +1 -0
- package/dist/components/popover/PopoverHeader/index.d.ts +1 -0
- package/dist/components/popover/PopoverTitle/PopoverTitle.d.ts +2 -0
- package/dist/components/popover/PopoverTitle/PopoverTitle.js +18 -0
- package/dist/components/popover/PopoverTitle/PopoverTitle.js.map +1 -0
- package/dist/components/popover/PopoverTitle/index.d.ts +1 -0
- package/dist/components/popover/PopoverTrigger/PopoverTrigger.d.ts +4 -0
- package/dist/components/popover/PopoverTrigger/PopoverTrigger.js +35 -0
- package/dist/components/popover/PopoverTrigger/PopoverTrigger.js.map +1 -0
- package/dist/components/popover/PopoverTrigger/PopoverTrigger.types.d.ts +3 -0
- package/dist/components/popover/PopoverTrigger/index.d.ts +4 -0
- package/dist/components/popover/PopoverTrigger/usePopoverTrigger.d.ts +14 -0
- package/dist/components/popover/PopoverTrigger/usePopoverTrigger.js +35 -0
- package/dist/components/popover/PopoverTrigger/usePopoverTrigger.js.map +1 -0
- package/dist/components/popover/index.d.ts +9 -0
- package/dist/components/popover/index.js +7 -0
- package/dist/components/radio-group/RadioGroup/RadioGroup.context.d.ts +3 -0
- package/dist/components/radio-group/RadioGroup/RadioGroup.context.js +12 -0
- package/dist/components/radio-group/RadioGroup/RadioGroup.context.js.map +1 -0
- package/dist/components/radio-group/RadioGroup/RadioGroup.d.ts +15 -0
- package/dist/components/radio-group/RadioGroup/RadioGroup.js +56 -0
- package/dist/components/radio-group/RadioGroup/RadioGroup.js.map +1 -0
- package/dist/components/radio-group/RadioGroup/RadioGroup.types.d.ts +22 -0
- package/dist/components/radio-group/RadioGroup/index.d.ts +3 -0
- package/dist/components/radio-group/RadioGroupItem/RadioGroupItem.d.ts +6 -0
- package/dist/components/radio-group/RadioGroupItem/RadioGroupItem.js +80 -0
- package/dist/components/radio-group/RadioGroupItem/RadioGroupItem.js.map +1 -0
- package/dist/components/radio-group/RadioGroupItem/RadioGroupItem.types.d.ts +9 -0
- package/dist/components/radio-group/RadioGroupItem/index.d.ts +2 -0
- package/dist/components/radio-group/index.d.ts +4 -0
- package/dist/components/radio-group/index.js +3 -0
- package/dist/components/select/Select/Select.context.d.ts +3 -3
- package/dist/components/select/Select/Select.context.js.map +1 -1
- package/dist/components/select/Select/Select.d.ts +5 -2
- package/dist/components/select/Select/Select.js +1 -1
- package/dist/components/select/Select/Select.js.map +1 -1
- package/dist/components/select/Select/Select.types.d.ts +19 -15
- package/dist/components/select/Select/index.d.ts +1 -1
- package/dist/components/select/SelectContent/SelectContent.js +2 -2
- package/dist/components/select/SelectContent/SelectContent.js.map +1 -1
- package/dist/components/select/SelectContent/SelectContent.utils.d.ts +2 -1
- package/dist/components/select/SelectContent/SelectContent.utils.js +2 -2
- package/dist/components/select/SelectContent/SelectContent.utils.js.map +1 -1
- package/dist/components/select/SelectContent/useSelectContent.js +6 -2
- package/dist/components/select/SelectContent/useSelectContent.js.map +1 -1
- package/dist/components/select/SelectItem/SelectItem.js +1 -1
- package/dist/components/select/SelectItem/SelectItem.js.map +1 -1
- package/dist/components/select/SelectItem/SelectItem.types.d.ts +3 -2
- package/dist/components/select/SelectItem/useSelectItem.d.ts +2 -1
- package/dist/components/select/SelectItem/useSelectItem.js +1 -1
- package/dist/components/select/SelectItem/useSelectItem.js.map +1 -1
- package/dist/components/select/SelectValue/SelectValue.js +1 -1
- package/dist/components/select/SelectValue/SelectValue.js.map +1 -1
- package/dist/components/toast/Toast/Toast.d.ts +3 -0
- package/dist/components/toast/Toast/Toast.js +181 -0
- package/dist/components/toast/Toast/Toast.js.map +1 -0
- package/dist/components/toast/Toast/Toast.styles.d.ts +6 -0
- package/dist/components/toast/Toast/Toast.styles.js +27 -0
- package/dist/components/toast/Toast/Toast.styles.js.map +1 -0
- package/dist/components/toast/Toast/Toast.types.d.ts +90 -0
- package/dist/components/toast/Toast/Toast.types.js +6 -0
- package/dist/components/toast/Toast/Toast.types.js.map +1 -0
- package/dist/components/toast/Toast/index.d.ts +2 -0
- package/dist/components/toast/{components → Toaster}/Toaster.d.ts +1 -1
- package/dist/components/toast/Toaster/Toaster.js +102 -0
- package/dist/components/toast/Toaster/Toaster.js.map +1 -0
- package/dist/components/toast/Toaster/Toaster.styles.d.ts +1 -0
- package/dist/components/toast/Toaster/Toaster.styles.js +6 -0
- package/dist/components/toast/Toaster/Toaster.styles.js.map +1 -0
- package/dist/components/toast/Toaster/Toaster.types.d.ts +44 -0
- package/dist/components/toast/Toaster/Toaster.utils.d.ts +7 -0
- package/dist/components/toast/Toaster/Toaster.utils.js +33 -0
- package/dist/components/toast/Toaster/Toaster.utils.js.map +1 -0
- package/dist/components/toast/Toaster/index.d.ts +3 -0
- package/dist/components/toast/index.d.ts +5 -10
- package/dist/components/toast/index.js +4 -5
- package/dist/components/toast/state/index.d.ts +1 -0
- package/dist/components/toast/state/toast.d.ts +24 -0
- package/dist/components/toast/state/toast.js +116 -0
- package/dist/components/toast/state/toast.js.map +1 -0
- package/dist/components/toggle/Toggle/Toggle.d.ts +3 -0
- package/dist/components/toggle/Toggle/Toggle.js +49 -0
- package/dist/components/toggle/Toggle/Toggle.js.map +1 -0
- package/dist/components/toggle/Toggle/Toggle.styles.d.ts +4 -0
- package/dist/components/toggle/Toggle/Toggle.styles.js +23 -0
- package/dist/components/toggle/Toggle/Toggle.styles.js.map +1 -0
- package/dist/components/toggle/Toggle/Toggle.types.d.ts +12 -0
- package/dist/components/toggle/Toggle/index.d.ts +3 -0
- package/dist/components/toggle/index.d.ts +2 -0
- package/dist/components/toggle/index.js +3 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.context.d.ts +36 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.context.js +40 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.context.js.map +1 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.d.ts +18 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.js +94 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.js.map +1 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.styles.d.ts +8 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.styles.js +7 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.styles.js.map +1 -0
- package/dist/components/toggle-group/ToggleGroup/ToggleGroup.types.d.ts +104 -0
- package/dist/components/toggle-group/ToggleGroup/create-change-event-details.d.ts +8 -0
- package/dist/components/toggle-group/ToggleGroup/create-change-event-details.js +25 -0
- package/dist/components/toggle-group/ToggleGroup/create-change-event-details.js.map +1 -0
- package/dist/components/toggle-group/ToggleGroup/index.d.ts +3 -0
- package/dist/components/toggle-group/ToggleGroup/useToggleGroupKeyboard.d.ts +17 -0
- package/dist/components/toggle-group/ToggleGroup/useToggleGroupKeyboard.js +47 -0
- package/dist/components/toggle-group/ToggleGroup/useToggleGroupKeyboard.js.map +1 -0
- package/dist/components/toggle-group/ToggleGroupItem/ToggleGroupItem.d.ts +11 -0
- package/dist/components/toggle-group/ToggleGroupItem/ToggleGroupItem.js +88 -0
- package/dist/components/toggle-group/ToggleGroupItem/ToggleGroupItem.js.map +1 -0
- package/dist/components/toggle-group/ToggleGroupItem/ToggleGroupItem.styles.d.ts +12 -0
- package/dist/components/toggle-group/ToggleGroupItem/ToggleGroupItem.styles.js +7 -0
- package/dist/components/toggle-group/ToggleGroupItem/ToggleGroupItem.styles.js.map +1 -0
- package/dist/components/toggle-group/ToggleGroupItem/ToggleGroupItem.types.d.ts +20 -0
- package/dist/components/toggle-group/ToggleGroupItem/index.d.ts +2 -0
- package/dist/components/toggle-group/call-event-handler.d.ts +5 -0
- package/dist/components/toggle-group/call-event-handler.js +9 -0
- package/dist/components/toggle-group/call-event-handler.js.map +1 -0
- package/dist/components/toggle-group/index.d.ts +4 -0
- package/dist/components/toggle-group/index.js +3 -0
- package/dist/components/tooltip/Tooltip/Tooltip.js +51 -50
- package/dist/components/tooltip/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/tooltip/TooltipArrow/TooltipArrow.d.ts +3 -28
- package/dist/components/tooltip/TooltipArrow/TooltipArrow.js +13 -45
- package/dist/components/tooltip/TooltipArrow/TooltipArrow.js.map +1 -1
- package/dist/components/tooltip/TooltipContent/TooltipContent.context.d.ts +2 -0
- package/dist/components/tooltip/TooltipContent/TooltipContent.context.js.map +1 -1
- package/dist/components/tooltip/TooltipContent/TooltipContent.js +2 -1
- package/dist/components/tooltip/TooltipContent/TooltipContent.js.map +1 -1
- package/dist/components/tooltip/TooltipContent/TooltipContent.types.d.ts +3 -2
- package/dist/components/tooltip/TooltipContent/TooltipContent.utils.d.ts +2 -1
- package/dist/components/tooltip/TooltipContent/TooltipContent.utils.js +8 -4
- package/dist/components/tooltip/TooltipContent/TooltipContent.utils.js.map +1 -1
- package/dist/components/tooltip/TooltipContent/useTooltipContent.js +20 -19
- package/dist/components/tooltip/TooltipContent/useTooltipContent.js.map +1 -1
- package/dist/components/tooltip/TooltipProvider/TooltipProvider.context.d.ts +3 -0
- package/dist/components/tooltip/TooltipProvider/TooltipProvider.context.js +10 -0
- package/dist/components/tooltip/TooltipProvider/TooltipProvider.context.js.map +1 -0
- package/dist/components/tooltip/TooltipProvider/TooltipProvider.d.ts +3 -0
- package/dist/components/tooltip/TooltipProvider/TooltipProvider.js +20 -0
- package/dist/components/tooltip/TooltipProvider/TooltipProvider.js.map +1 -0
- package/dist/components/tooltip/TooltipProvider/TooltipProvider.types.d.ts +11 -0
- package/dist/components/tooltip/TooltipProvider/index.d.ts +3 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/components/tooltip/index.js +7 -6
- package/dist/index.d.ts +8 -0
- package/dist/index.js +153 -115
- package/dist/ui.css +1 -1
- package/package.json +7 -6
- package/dist/components/toast/components/Assets.d.ts +0 -9
- package/dist/components/toast/components/Assets.js +0 -32
- package/dist/components/toast/components/Assets.js.map +0 -1
- package/dist/components/toast/components/Toast.d.ts +0 -3
- package/dist/components/toast/components/Toast.js +0 -152
- package/dist/components/toast/components/Toast.js.map +0 -1
- package/dist/components/toast/components/ToastActions.d.ts +0 -12
- package/dist/components/toast/components/ToastActions.js +0 -62
- package/dist/components/toast/components/ToastActions.js.map +0 -1
- package/dist/components/toast/components/ToastContent.d.ts +0 -9
- package/dist/components/toast/components/ToastContent.js +0 -36
- package/dist/components/toast/components/ToastContent.js.map +0 -1
- package/dist/components/toast/components/ToastIcon.d.ts +0 -9
- package/dist/components/toast/components/ToastIcon.js +0 -59
- package/dist/components/toast/components/ToastIcon.js.map +0 -1
- package/dist/components/toast/components/Toaster.js +0 -163
- package/dist/components/toast/components/Toaster.js.map +0 -1
- package/dist/components/toast/constants.d.ts +0 -16
- package/dist/components/toast/constants.js +0 -6
- package/dist/components/toast/constants.js.map +0 -1
- package/dist/components/toast/hooks/useSwipe.d.ts +0 -23
- package/dist/components/toast/hooks/useSwipe.js +0 -59
- package/dist/components/toast/hooks/useSwipe.js.map +0 -1
- package/dist/components/toast/hooks/useTheme.d.ts +0 -2
- package/dist/components/toast/hooks/useTheme.js +0 -22
- package/dist/components/toast/hooks/useTheme.js.map +0 -1
- package/dist/components/toast/hooks/useToastHeight.d.ts +0 -11
- package/dist/components/toast/hooks/useToastHeight.js +0 -35
- package/dist/components/toast/hooks/useToastHeight.js.map +0 -1
- package/dist/components/toast/hooks/useToastSubscription.d.ts +0 -5
- package/dist/components/toast/hooks/useToastSubscription.js +0 -38
- package/dist/components/toast/hooks/useToastSubscription.js.map +0 -1
- package/dist/components/toast/hooks/useToastTimer.d.ts +0 -11
- package/dist/components/toast/hooks/useToastTimer.js +0 -22
- package/dist/components/toast/hooks/useToastTimer.js.map +0 -1
- package/dist/components/toast/hooks/useToasterKeyboard.d.ts +0 -7
- package/dist/components/toast/hooks/useToasterKeyboard.js +0 -14
- package/dist/components/toast/hooks/useToasterKeyboard.js.map +0 -1
- package/dist/components/toast/hooks.d.ts +0 -13
- package/dist/components/toast/hooks.js +0 -37
- package/dist/components/toast/hooks.js.map +0 -1
- package/dist/components/toast/state.d.ts +0 -52
- package/dist/components/toast/state.js +0 -170
- package/dist/components/toast/state.js.map +0 -1
- package/dist/components/toast/types.d.ts +0 -168
- package/dist/components/toast/types.js +0 -6
- package/dist/components/toast/types.js.map +0 -1
- package/dist/components/toast/utils.d.ts +0 -10
- package/dist/components/toast/utils.js +0 -39
- package/dist/components/toast/utils.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Image.utils.js","names":[],"sources":["../../../src/components/image/Image.utils.ts"],"sourcesContent":["/**\n * handle-loading.ts\n * 单一职责:封装图片加载完成后的所有副作用——decode、回调触发、开发环境警告。\n * 纯 TypeScript,不包含任何 JSX 或组件代码。\n */\n\nimport { mergeProps, splitProps } from \"solid-js\";\nimport { warnOnce } from \"~/utils\";\nimport { imageConfigDefault } from \"./Image.config\";\nimport type {\n ImageConfig,\n ImageConfigComplete,\n ImageLoaderProps,\n ImageLoaderWithConfig,\n ImageProps,\n ImgProps,\n ImgPropsResult,\n LoadingValue,\n OnLoad,\n OnLoadingComplete,\n PlaceholderStyle,\n PlaceholderValue,\n StaticImageData,\n StaticImport,\n StaticRequire,\n} from \"./Image.types\";\n\n// ─── 类型补充 ─────────────────────────────────────────────────────────────────\n\n/** 用于追踪每个 img 节点已处理的 src,避免重复触发 */\ntype ImgWithDataProp = HTMLImageElement & { \"data-loaded-src\"?: string };\n\n// ─── 主函数 ───────────────────────────────────────────────────────────────────\n\n/**\n * 在图片加载/hydrate 后调用。\n * - 使用 img.decode() 确保像素已解码再触发回调\n * - 清除 blur placeholder\n * - 开发环境下输出 fill / sizes 相关警告\n */\nexport function handleLoading(\n img: ImgWithDataProp,\n placeholder: PlaceholderValue,\n onLoad: OnLoad | undefined,\n onLoadingComplete: OnLoadingComplete | undefined,\n setBlurComplete: (v: boolean) => void,\n unoptimized: boolean,\n sizesInput: string | undefined,\n): void {\n const src = img?.src;\n // 同一张图只处理一次\n if (!img || img[\"data-loaded-src\"] === src) return;\n img[\"data-loaded-src\"] = src;\n\n const p: Promise<void> = \"decode\" in img ? img.decode() : Promise.resolve();\n\n p.catch(() => {}).then(() => {\n // 若组件已卸载则提前退出\n if (!img.parentElement || !img.isConnected) return;\n\n if (placeholder !== \"empty\") {\n setBlurComplete(true);\n }\n\n if (onLoad) {\n const event = new Event(\"load\");\n Object.defineProperty(event, \"target\", { writable: false, value: img });\n onLoad(\n event as Event & { currentTarget: HTMLImageElement; target: Element },\n );\n }\n\n if (onLoadingComplete) {\n onLoadingComplete(img);\n }\n\n if (import.meta.env.DEV) {\n warnFillUsage(img, unoptimized, sizesInput);\n warnAspectRatioMismatch(img);\n }\n });\n}\n\n// ─── 开发警告辅助 ──────────────────────────────────────────────────────────────\n\nfunction warnFillUsage(\n img: HTMLImageElement,\n unoptimized: boolean,\n sizesInput: string | undefined,\n): void {\n if (img.getAttribute(\"data-nimg\") !== \"fill\") return;\n\n const origSrc =\n new URL(img.src, \"http://n\").searchParams.get(\"url\") || img.src;\n\n if (!unoptimized) {\n const widthViewportRatio =\n img.getBoundingClientRect().width / window.innerWidth;\n if (widthViewportRatio < 0.6) {\n if (sizesInput === \"100vw\") {\n console.warn(\n `[Image] src=\"${origSrc}\" 设置了 fill 和 sizes=\"100vw\",但实际渲染宽度不足视口宽度,请调整 sizes 以提升性能。`,\n );\n } else if (!sizesInput) {\n console.warn(\n `[Image] src=\"${origSrc}\" 设置了 fill 但缺少 sizes 属性,请添加以提升性能。`,\n );\n }\n }\n }\n\n if (img.parentElement) {\n const { position } = window.getComputedStyle(img.parentElement);\n const valid = [\"absolute\", \"fixed\", \"relative\"];\n if (!valid.includes(position)) {\n console.warn(\n `[Image] src=\"${origSrc}\" 设置了 fill,但父元素 position=\"${position}\",应为 ${valid.join(\" | \")} 之一。`,\n );\n }\n }\n\n if (img.height === 0) {\n console.warn(\n `[Image] src=\"${origSrc}\" 设置了 fill 且高度为 0,请为父元素设置明确高度。`,\n );\n }\n}\n\nfunction warnAspectRatioMismatch(img: HTMLImageElement): void {\n const heightModified = img.height.toString() !== img.getAttribute(\"height\");\n const widthModified = img.width.toString() !== img.getAttribute(\"width\");\n if (\n (heightModified && !widthModified) ||\n (!heightModified && widthModified)\n ) {\n const origSrc =\n new URL(img.src, \"http://n\").searchParams.get(\"url\") || img.src;\n console.warn(\n `[Image] src=\"${origSrc}\" 仅修改了 width 或 height 其中之一,请同时添加 width: \"auto\" 或 height: \"auto\" 样式以保持宽高比。`,\n );\n }\n}\n\ninterface GetImgPropsOptions {\n imgConf: ImageConfigComplete;\n blurComplete: boolean;\n showAltText: boolean;\n}\n\nexport const VALID_LOADING_VALUES = [\"lazy\", \"eager\", undefined] as const;\n// Object-fit values that are not valid background-size values\nconst INVALID_BACKGROUND_SIZE_VALUES = [\n \"-moz-initial\",\n \"fill\",\n \"none\",\n \"scale-down\",\n undefined,\n];\n\nlet perfObserver: PerformanceObserver | undefined;\nconst allImgs = new Map<\n string,\n { src: string; loading: LoadingValue; placeholder: PlaceholderValue }\n>();\n\nexport function getImgProps(\n props: ImageProps,\n { imgConf, blurComplete, showAltText }: GetImgPropsOptions,\n): ImgPropsResult {\n const merged = mergeProps(\n {\n // loader: defaultLoader,\n fill: false,\n priority: false,\n preload: false,\n placeholder: \"empty\",\n unoptimized: imgConf.unoptimized,\n decoding: \"async\",\n } as const,\n props,\n );\n const [local, others] = splitProps(merged, [\n \"src\",\n \"loader\",\n \"quality\",\n \"width\",\n \"height\",\n \"fill\",\n \"sizes\",\n \"priority\",\n \"placeholder\",\n \"blurDataURL\",\n \"unoptimized\",\n \"overrideSrc\",\n \"onLoad\",\n \"onLoadingComplete\",\n \"layout\",\n \"style\",\n \"preload\",\n \"loading\",\n \"objectFit\",\n \"objectPosition\",\n \"lazyBoundary\",\n \"lazyRoot\",\n \"fetchpriority\",\n \"class\",\n \"decoding\",\n ]);\n\n let config: ImageConfig;\n const c = imgConf || imageConfigDefault;\n\n if (\"allSizes\" in c) {\n config = c as ImageConfig;\n } else {\n const allSizes = [...c.deviceSizes, ...c.imageSizes].sort((a, b) => a - b);\n const deviceSizes = c.deviceSizes.sort((a, b) => a - b);\n const qualities = c.qualities?.sort((a, b) => a - b);\n config = { ...c, allSizes, deviceSizes, qualities };\n }\n\n if (typeof defaultLoader === \"undefined\") {\n throw new Error(\n \"images.loaderFile detected but the file is missing default export.\\nRead more: https://nextjs.org/docs/messages/invalid-images-config\",\n );\n }\n\n let style = local.style;\n let sizes = local.sizes;\n let fill = local.fill;\n\n const loader: ImageLoaderWithConfig = local.loader || defaultLoader;\n\n if (local.layout) {\n if (local.layout === \"fill\") {\n fill = true;\n }\n const layoutToStyle: Record<string, Record<string, string> | undefined> = {\n intrinsic: { maxWidth: \"100%\", height: \"auto\" },\n responsive: { width: \"100%\", height: \"auto\" },\n };\n const layoutToSizes: Record<string, string | undefined> = {\n responsive: \"100vw\",\n fill: \"100vw\",\n };\n const layoutStyle = layoutToStyle[local.layout];\n if (layoutStyle) {\n style = { ...style, ...layoutStyle };\n }\n const layoutSizes = layoutToSizes[local.layout];\n if (layoutSizes && !sizes) {\n sizes = layoutSizes;\n }\n }\n\n let staticSrc = \"\";\n let blurDataURL = local.blurDataURL;\n let widthInt = getInt(local.width);\n let heightInt = getInt(local.height);\n let blurWidth: number | undefined;\n let blurHeight: number | undefined;\n\n if (isStaticImport(local.src)) {\n const staticImageData = isStaticRequire(local.src)\n ? local.src.default\n : local.src;\n\n if (!staticImageData.src) {\n throw new Error(\n `An object should only be passed to the image component src parameter if it comes from a static image import. It must include src. Received ${JSON.stringify(\n staticImageData,\n )}`,\n );\n }\n if (!staticImageData.height || !staticImageData.width) {\n throw new Error(\n `An object should only be passed to the image component src parameter if it comes from a static image import. It must include height and width. Received ${JSON.stringify(\n staticImageData,\n )}`,\n );\n }\n\n blurWidth = staticImageData.blurWidth;\n blurHeight = staticImageData.blurHeight;\n blurDataURL = blurDataURL || staticImageData.blurDataURL;\n staticSrc = staticImageData.src;\n\n if (!fill) {\n if (!widthInt && !heightInt) {\n widthInt = staticImageData.width;\n heightInt = staticImageData.height;\n } else if (widthInt && !heightInt) {\n const ratio = widthInt / staticImageData.width;\n heightInt = Math.round(staticImageData.height * ratio);\n } else if (!widthInt && heightInt) {\n const ratio = heightInt / staticImageData.height;\n widthInt = Math.round(staticImageData.width * ratio);\n }\n }\n }\n const src = typeof local.src === \"string\" ? local.src : staticSrc;\n\n let unoptimized = local.unoptimized;\n let isLazy =\n !local.priority &&\n !local.preload &&\n (local.loading === \"lazy\" || typeof local.loading === \"undefined\");\n if (!src || src.startsWith(\"data:\") || src.startsWith(\"blob:\")) {\n // https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\n unoptimized = true;\n isLazy = false;\n }\n if (config.unoptimized) {\n unoptimized = true;\n }\n if (!config.dangerouslyAllowSVG && src.split(\"?\", 1)[0].endsWith(\".svg\")) {\n // Special case to make svg serve as-is to avoid proxying\n // through the built-in Image Optimization API.\n unoptimized = true;\n }\n\n const qualityInt = getInt(local.quality);\n\n if (!import.meta.env.PROD) {\n if (config.output === \"export\" && !unoptimized) {\n throw new Error(\n `Image Optimization using the default loader is not compatible with \\`{ output: 'export' }\\`.\n Possible solutions:\n - Remove \\`{ output: 'export' }\\` and run \"next start\" to run server mode including the Image Optimization API.\n - Configure \\`{ images: { unoptimized: true } }\\` in \\`next.config.js\\` to disable the Image Optimization API.\n Read more: https://nextjs.org/docs/messages/export-image-api`,\n );\n }\n if (!src) {\n // React doesn't show the stack trace and there's\n // no `src` to help identify which image, so we\n // instead console.error(ref) during mount.\n unoptimized = true;\n } else {\n if (fill) {\n if (local.width) {\n throw new Error(\n `Image with src \"${src}\" has both \"width\" and \"fill\" properties. Only one should be used.`,\n );\n }\n if (local.height) {\n throw new Error(\n `Image with src \"${src}\" has both \"height\" and \"fill\" properties. Only one should be used.`,\n );\n }\n if (style?.position && style.position !== \"absolute\") {\n throw new Error(\n `Image with src \"${src}\" has both \"fill\" and \"style.position\" properties. Images with \"fill\" always use position absolute - it cannot be modified.`,\n );\n }\n if (style?.width && style.width !== \"100%\") {\n throw new Error(\n `Image with src \"${src}\" has both \"fill\" and \"style.width\" properties. Images with \"fill\" always use width 100% - it cannot be modified.`,\n );\n }\n if (style?.height && style.height !== \"100%\") {\n throw new Error(\n `Image with src \"${src}\" has both \"fill\" and \"style.height\" properties. Images with \"fill\" always use height 100% - it cannot be modified.`,\n );\n }\n } else {\n if (typeof widthInt === \"undefined\") {\n throw new Error(\n `Image with src \"${src}\" is missing required \"width\" property.`,\n );\n } else if (Number.isNaN(widthInt)) {\n throw new Error(\n `Image with src \"${src}\" has invalid \"width\" property. Expected a numeric value in pixels but received \"${local.width}\".`,\n );\n }\n if (typeof heightInt === \"undefined\") {\n throw new Error(\n `Image with src \"${src}\" is missing required \"height\" property.`,\n );\n } else if (Number.isNaN(heightInt)) {\n throw new Error(\n `Image with src \"${src}\" has invalid \"height\" property. Expected a numeric value in pixels but received \"${local.height}\".`,\n );\n }\n\n // biome-ignore lint/suspicious/noControlCharactersInRegex: no-control-regex\n if (/^[\\x00-\\x20]/.test(src)) {\n throw new Error(\n `Image with src \"${src}\" cannot start with a space or control character. Use src.trimStart() to remove it or encodeURIComponent(src) to keep it.`,\n );\n }\n // biome-ignore lint/suspicious/noControlCharactersInRegex: no-control-regex\n if (/[\\x00-\\x20]$/.test(src)) {\n throw new Error(\n `Image with src \"${src}\" cannot end with a space or control character. Use src.trimEnd() to remove it or encodeURIComponent(src) to keep it.`,\n );\n }\n }\n }\n if (!VALID_LOADING_VALUES.includes(local.loading)) {\n throw new Error(\n `Image with src \"${src}\" has invalid \"loading\" property. Provided \"${local.loading}\" should be one of ${VALID_LOADING_VALUES.map(\n String,\n ).join(\",\")}.`,\n );\n }\n if (local.priority && local.loading === \"lazy\") {\n throw new Error(\n `Image with src \"${src}\" has both \"priority\" and \"loading='lazy'\" properties. Only one should be used.`,\n );\n }\n if (local.preload && local.loading === \"lazy\") {\n throw new Error(\n `Image with src \"${src}\" has both \"preload\" and \"loading='lazy'\" properties. Only one should be used.`,\n );\n }\n if (local.preload && local.priority) {\n throw new Error(\n `Image with src \"${src}\" has both \"preload\" and \"priority\" properties. Only \"preload\" should be used.`,\n );\n }\n if (\n local.placeholder !== \"empty\" &&\n local.placeholder !== \"blur\" &&\n !local.placeholder.startsWith(\"data:image/\")\n ) {\n throw new Error(\n `Image with src \"${src}\" has invalid \"placeholder\" property \"${local.placeholder}\".`,\n );\n }\n if (local.placeholder !== \"empty\") {\n if (widthInt && heightInt && widthInt * heightInt < 1600) {\n warnOnce(\n `Image with src \"${src}\" is smaller than 40x40. Consider removing the \"placeholder\" property to improve performance.`,\n );\n }\n }\n if (\n qualityInt &&\n config.qualities &&\n !config.qualities.includes(qualityInt)\n ) {\n warnOnce(\n `Image with src \"${src}\" is using quality \"${qualityInt}\" which is not configured in images.qualities [${config.qualities.join(\", \")}]. Please update your config to [${[...config.qualities, qualityInt].sort().join(\", \")}].` +\n `\\nRead more: https://nextjs.org/docs/messages/next-image-unconfigured-qualities`,\n );\n }\n if (local.placeholder === \"blur\" && !blurDataURL) {\n const VALID_BLUR_EXT = [\"jpeg\", \"png\", \"webp\", \"avif\"]; // should match next-image-loader\n\n throw new Error(\n `Image with src \"${src}\" has \"placeholder='blur'\" property but is missing the \"blurDataURL\" property.\n Possible solutions:\n - Add a \"blurDataURL\" property, the contents should be a small Data URL to represent the image\n - Change the \"src\" property to a static import with one of the supported file types: ${VALID_BLUR_EXT.join(\n \",\",\n )} (animated images not supported)\n - Remove the \"placeholder\" property, effectively no blur effect\n Read more: https://nextjs.org/docs/messages/placeholder-blur-data-url`,\n );\n }\n if (\"ref\" in others) {\n warnOnce(\n `Image with src \"${src}\" is using unsupported \"ref\" property. Consider using the \"onLoad\" property instead.`,\n );\n }\n\n if (!unoptimized) {\n const urlStr = loader({\n config,\n src,\n width: widthInt || 400,\n quality: qualityInt || 75,\n });\n let url: URL | undefined;\n try {\n url = new URL(urlStr);\n } catch (err) {\n console.error(err);\n }\n if (urlStr === src || (url && url.pathname === src && !url.search)) {\n warnOnce(\n `Image with src \"${src}\" has a \"loader\" property that does not implement width. Please implement it or use the \"unoptimized\" property instead.` +\n `\\nRead more: https://nextjs.org/docs/messages/next-image-missing-loader-width`,\n );\n }\n }\n\n if (local.onLoadingComplete) {\n warnOnce(\n `Image with src \"${src}\" is using deprecated \"onLoadingComplete\" property. Please use the \"onLoad\" property instead.`,\n );\n }\n\n for (const [legacyKey, legacyValue] of Object.entries({\n layout: local.layout,\n objectFit: local.objectFit,\n objectPosition: local.objectPosition,\n lazyBoundary: local.lazyBoundary,\n lazyRoot: local.lazyRoot,\n })) {\n if (legacyValue) {\n warnOnce(\n `Image with src \"${src}\" has legacy prop \"${legacyKey}\". Did you forget to run the codemod?` +\n `\\nRead more: https://nextjs.org/docs/messages/next-image-upgrade-to-13`,\n );\n }\n }\n\n if (\n typeof window !== \"undefined\" &&\n !perfObserver &&\n window.PerformanceObserver\n ) {\n perfObserver = new PerformanceObserver((entryList) => {\n for (const entry of entryList.getEntries()) {\n // @ts-expect-error - missing \"LargestContentfulPaint\" class with \"element\" prop\n const imgSrc = entry?.element?.src || \"\";\n const lcpImage = allImgs.get(imgSrc);\n if (\n lcpImage &&\n lcpImage.loading === \"lazy\" &&\n lcpImage.placeholder === \"empty\" &&\n !lcpImage.src.startsWith(\"data:\") &&\n !lcpImage.src.startsWith(\"blob:\")\n ) {\n // https://web.dev/lcp/#measure-lcp-in-javascript\n warnOnce(\n `Image with src \"${lcpImage.src}\" was detected as the Largest Contentful Paint (LCP). Please add the \\`loading=\"eager\"\\` property if this image is above the fold.` +\n `\\nRead more: https://nextjs.org/docs/app/api-reference/components/image#loading`,\n );\n }\n }\n });\n try {\n perfObserver.observe({\n type: \"largest-contentful-paint\",\n buffered: true,\n });\n } catch (err) {\n // Log error but don't crash the app\n console.error(err);\n }\n }\n }\n\n const imgStyle = Object.assign(\n fill\n ? {\n position: \"absolute\",\n height: \"100%\",\n width: \"100%\",\n left: 0,\n top: 0,\n right: 0,\n bottom: 0,\n objectFit: local.objectFit,\n objectPosition: local.objectPosition,\n }\n : {},\n showAltText ? {} : { color: \"transparent\" },\n style,\n );\n\n const backgroundImage =\n !blurComplete && local.placeholder !== \"empty\"\n ? local.placeholder === \"blur\"\n ? `url(\"data:image/svg+xml;charset=utf-8,${getImageBlurSvg({\n widthInt,\n heightInt,\n blurWidth,\n blurHeight,\n blurDataURL: blurDataURL || \"\", // assume not undefined\n objectFit: imgStyle.objectFit,\n })}\")`\n : `url(\"${local.placeholder}\")` // assume `data:image/`\n : null;\n\n const backgroundSize = !INVALID_BACKGROUND_SIZE_VALUES.includes(\n imgStyle.objectFit,\n )\n ? imgStyle.objectFit\n : imgStyle.objectFit === \"fill\"\n ? \"100% 100%\" // the background-size equivalent of `fill`\n : \"cover\";\n\n const placeholderStyle: PlaceholderStyle = backgroundImage\n ? {\n \"background-size\": backgroundSize,\n \"background-position\": imgStyle.objectPosition || \"50% 50%\",\n \"background-repeat\": \"no-repeat\",\n \"background-image\": backgroundImage,\n }\n : {};\n\n if (import.meta.env.DEV) {\n if (\n placeholderStyle[\"background-image\"] &&\n local.placeholder === \"blur\" &&\n blurDataURL?.startsWith(\"/\")\n ) {\n // During `next dev`, we don't want to generate blur placeholders with webpack\n // because it can delay starting the dev server. Instead, `next-image-loader.js`\n // will inline a special url to lazily generate the blur placeholder at request time.\n placeholderStyle[\"background-image\"] = `url(\"${blurDataURL}\")`;\n }\n }\n\n const imgAttributes = generateImgAttrs({\n config,\n src,\n unoptimized,\n width: widthInt,\n quality: qualityInt,\n sizes,\n loader,\n });\n\n const loadingFinal = isLazy ? \"lazy\" : local.loading;\n\n if (!import.meta.env.PROD) {\n if (typeof window !== \"undefined\") {\n let fullUrl: URL;\n try {\n fullUrl = new URL(imgAttributes.src);\n } catch (e) {\n console.error(e);\n fullUrl = new URL(imgAttributes.src, window.location.href);\n }\n allImgs.set(fullUrl.href, {\n src,\n loading: loadingFinal,\n placeholder: local.placeholder,\n });\n }\n }\n\n const newProps: ImgProps = {\n ...others,\n loading: loadingFinal,\n fetchpriority: local.fetchpriority,\n width: widthInt,\n height: heightInt,\n decoding: local.decoding,\n class: local.class,\n style: { ...imgStyle, ...placeholderStyle },\n sizes: imgAttributes.sizes,\n srcSet: imgAttributes.srcSet,\n src: local.overrideSrc || imgAttributes.src,\n };\n const meta = {\n unoptimized,\n preload: local.preload || local.priority,\n placeholder: local.placeholder,\n fill,\n };\n return { props: newProps, meta };\n}\n\nfunction defaultLoader({ src, width, quality }: ImageLoaderProps): string {\n if (import.meta.env.DEV) {\n const missingValues: string[] = [];\n if (!src) missingValues.push(\"src\");\n if (!width) missingValues.push(\"width\");\n if (missingValues.length > 0) {\n throw new Error(\n `[defaultLoader] 缺少必要属性:${missingValues.join(\", \")}。` +\n `请确认调用方式正确,或提供自定义 loader。`,\n );\n }\n }\n\n // 如果 src 本身已是带参数的 URL(外部图片),直接返回\n if (src.startsWith(\"http://\") || src.startsWith(\"https://\")) {\n return src;\n }\n\n // 本地图片:追加 w / q 参数(供自定义服务器处理)\n const params = new URLSearchParams();\n params.set(\"url\", src);\n params.set(\"w\", String(width));\n if (quality) params.set(\"q\", String(quality));\n return `/_image?${params.toString()}`;\n}\n\nfunction getInt(x: unknown): number | undefined {\n if (typeof x === \"undefined\") {\n return x;\n }\n if (typeof x === \"number\") {\n return Number.isFinite(x) ? x : NaN;\n }\n if (typeof x === \"string\" && /^[0-9]+$/.test(x)) {\n return parseInt(x, 10);\n }\n return NaN;\n}\n\nfunction isStaticRequire(\n src: StaticRequire | StaticImageData,\n): src is StaticRequire {\n return (src as StaticRequire).default !== undefined;\n}\n\nfunction isStaticImageData(\n src: StaticRequire | StaticImageData,\n): src is StaticImageData {\n return (src as StaticImageData).src !== undefined;\n}\n\nfunction isStaticImport(src: string | StaticImport): src is StaticImport {\n return (\n !!src &&\n typeof src === \"object\" &&\n (isStaticRequire(src as StaticImport) ||\n isStaticImageData(src as StaticImport))\n );\n}\n\nfunction getImageBlurSvg({\n widthInt,\n heightInt,\n blurWidth,\n blurHeight,\n blurDataURL,\n objectFit,\n}: {\n widthInt?: number;\n heightInt?: number;\n blurWidth?: number;\n blurHeight?: number;\n blurDataURL: string;\n objectFit?: string;\n}): string {\n const std = 20;\n const svgWidth = blurWidth ? blurWidth * 40 : widthInt;\n const svgHeight = blurHeight ? blurHeight * 40 : heightInt;\n\n const viewBox =\n svgWidth && svgHeight ? `viewBox='0 0 ${svgWidth} ${svgHeight}'` : \"\";\n const preserveAspectRatio = viewBox\n ? \"none\"\n : objectFit === \"contain\"\n ? \"xMidYMid\"\n : objectFit === \"cover\"\n ? \"xMidYMid slice\"\n : \"none\";\n\n return `%3Csvg xmlns='http://www.w3.org/2000/svg' ${viewBox}%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='${std}'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='${std}'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='${preserveAspectRatio}' style='filter: url(%23b);' href='${blurDataURL}'/%3E%3C/svg%3E`;\n}\n\ntype GenImgAttrsData = {\n config: ImageConfig;\n src: string;\n unoptimized: boolean;\n loader: ImageLoaderWithConfig;\n width?: number;\n quality?: number;\n sizes?: string;\n};\n\ntype GenImgAttrsResult = {\n src: string;\n srcSet: string | undefined;\n sizes: string | undefined;\n};\n\nfunction generateImgAttrs({\n config,\n src,\n unoptimized,\n width,\n quality,\n sizes,\n loader,\n}: GenImgAttrsData): GenImgAttrsResult {\n if (unoptimized) {\n return { src, srcSet: undefined, sizes: undefined };\n }\n\n const { widths, kind } = getWidths(config, width, sizes);\n const last = widths.length - 1;\n\n return {\n sizes: !sizes && kind === \"w\" ? \"100vw\" : sizes,\n srcSet: widths\n .map(\n (w, i) =>\n `${loader({ config, src, quality, width: w })} ${\n kind === \"w\" ? w : i + 1\n }${kind}`,\n )\n .join(\", \"),\n\n // It's intended to keep `src` the last attribute because React updates\n // attributes in order. If we keep `src` the first one, Safari will\n // immediately start to fetch `src`, before `sizes` and `srcSet` are even\n // updated by React. That causes multiple unnecessary requests if `srcSet`\n // and `sizes` are defined.\n // This bug cannot be reproduced in Chrome or Firefox.\n src: loader({ config, src, quality, width: widths[last] }),\n };\n}\n\nfunction getWidths(\n { deviceSizes, allSizes }: ImageConfig,\n width: number | undefined,\n sizes: string | undefined,\n): { widths: number[]; kind: \"w\" | \"x\" } {\n if (sizes) {\n // Find all the \"vw\" percent sizes used in the sizes prop\n const viewportWidthRe = /(^|\\s)(1?\\d?\\d)vw/g;\n const percentSizes = [];\n for (\n let match: RegExpExecArray | null;\n // biome-ignore lint/suspicious/noAssignInExpressions: nextjs code\n (match = viewportWidthRe.exec(sizes));\n match\n ) {\n percentSizes.push(Number.parseInt(match[2], 10));\n }\n if (percentSizes.length) {\n const smallestRatio = Math.min(...percentSizes) * 0.01;\n return {\n widths: allSizes.filter((s) => s >= deviceSizes[0] * smallestRatio),\n kind: \"w\",\n };\n }\n return { widths: allSizes, kind: \"w\" };\n }\n if (typeof width !== \"number\") {\n return { widths: deviceSizes, kind: \"w\" };\n }\n\n const widths = [\n ...new Set(\n // > This means that most OLED screens that say they are 3x resolution,\n // > are actually 3x in the green color, but only 1.5x in the red and\n // > blue colors. Showing a 3x resolution image in the app vs a 2x\n // > resolution image will be visually the same, though the 3x image\n // > takes significantly more data. Even true 3x resolution screens are\n // > wasteful as the human eye cannot see that level of detail without\n // > something like a magnifying glass.\n // https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/capping-image-fidelity-on-ultra-high-resolution-devices.html\n [width, width * 2 /*, width * 3*/].map(\n (w) => allSizes.find((p) => p >= w) || allSizes[allSizes.length - 1],\n ),\n ),\n ];\n return { widths, kind: \"x\" };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Image.utils.js","names":[],"sources":["../../../src/components/image/Image.utils.ts"],"sourcesContent":["/**\n * handle-loading.ts\n * 单一职责:封装图片加载完成后的所有副作用——decode、回调触发、开发环境警告。\n * 纯 TypeScript,不包含任何 JSX 或组件代码。\n */\n\nimport { mergeProps, splitProps } from \"solid-js\";\nimport { warnOnce } from \"~/utils\";\nimport { imageConfigDefault } from \"./Image.config\";\nimport type {\n ImageConfig,\n ImageConfigComplete,\n ImageLoaderProps,\n ImageLoaderWithConfig,\n ImageProps,\n ImgProps,\n ImgPropsResult,\n LoadingValue,\n OnLoad,\n OnLoadingComplete,\n PlaceholderStyle,\n PlaceholderValue,\n StaticImageData,\n StaticImport,\n StaticRequire,\n} from \"./Image.types\";\n\n// ─── 类型补充 ─────────────────────────────────────────────────────────────────\n\n/** 用于追踪每个 img 节点已处理的 src,避免重复触发 */\ntype ImgWithDataProp = HTMLImageElement & { \"data-loaded-src\"?: string };\n\n// ─── 主函数 ───────────────────────────────────────────────────────────────────\n\n/**\n * 在图片加载/hydrate 后调用。\n * - 使用 img.decode() 确保像素已解码再触发回调\n * - 清除 blur placeholder\n * - 开发环境下输出 fill / sizes 相关警告\n */\nexport function handleLoading(\n img: ImgWithDataProp,\n placeholder: PlaceholderValue,\n onLoad: OnLoad | undefined,\n onLoadingComplete: OnLoadingComplete | undefined,\n setBlurComplete: (v: boolean) => void,\n unoptimized: boolean,\n sizesInput: string | undefined,\n): void {\n const src = img?.src;\n // 同一张图只处理一次\n if (!img || img[\"data-loaded-src\"] === src) return;\n img[\"data-loaded-src\"] = src;\n\n const p: Promise<void> = \"decode\" in img ? img.decode() : Promise.resolve();\n\n p.catch(() => {}).then(() => {\n // 若组件已卸载则提前退出\n if (!img.parentElement || !img.isConnected) return;\n\n if (placeholder !== \"empty\") {\n setBlurComplete(true);\n }\n\n if (onLoad) {\n const event = new Event(\"load\");\n Object.defineProperty(event, \"target\", { writable: false, value: img });\n onLoad(\n event as Event & { currentTarget: HTMLImageElement; target: Element },\n );\n }\n\n if (onLoadingComplete) {\n onLoadingComplete(img);\n }\n\n if (import.meta.env.DEV) {\n warnFillUsage(img, unoptimized, sizesInput);\n warnAspectRatioMismatch(img);\n }\n });\n}\n\n// ─── 开发警告辅助 ──────────────────────────────────────────────────────────────\n\nfunction warnFillUsage(\n img: HTMLImageElement,\n unoptimized: boolean,\n sizesInput: string | undefined,\n): void {\n if (img.getAttribute(\"data-nimg\") !== \"fill\") return;\n\n const origSrc =\n new URL(img.src, \"http://n\").searchParams.get(\"url\") || img.src;\n\n if (!unoptimized) {\n const widthViewportRatio =\n img.getBoundingClientRect().width / window.innerWidth;\n if (widthViewportRatio < 0.6) {\n if (sizesInput === \"100vw\") {\n console.warn(\n `[Image] src=\"${origSrc}\" 设置了 fill 和 sizes=\"100vw\",但实际渲染宽度不足视口宽度,请调整 sizes 以提升性能。`,\n );\n } else if (!sizesInput) {\n console.warn(\n `[Image] src=\"${origSrc}\" 设置了 fill 但缺少 sizes 属性,请添加以提升性能。`,\n );\n }\n }\n }\n\n if (img.parentElement) {\n const { position } = window.getComputedStyle(img.parentElement);\n const valid = [\"absolute\", \"fixed\", \"relative\"];\n if (!valid.includes(position)) {\n console.warn(\n `[Image] src=\"${origSrc}\" 设置了 fill,但父元素 position=\"${position}\",应为 ${valid.join(\" | \")} 之一。`,\n );\n }\n }\n\n if (img.height === 0) {\n console.warn(\n `[Image] src=\"${origSrc}\" 设置了 fill 且高度为 0,请为父元素设置明确高度。`,\n );\n }\n}\n\nfunction warnAspectRatioMismatch(img: HTMLImageElement): void {\n const heightModified = img.height.toString() !== img.getAttribute(\"height\");\n const widthModified = img.width.toString() !== img.getAttribute(\"width\");\n if (\n (heightModified && !widthModified) ||\n (!heightModified && widthModified)\n ) {\n const origSrc =\n new URL(img.src, \"http://n\").searchParams.get(\"url\") || img.src;\n console.warn(\n `[Image] src=\"${origSrc}\" 仅修改了 width 或 height 其中之一,请同时添加 width: \"auto\" 或 height: \"auto\" 样式以保持宽高比。`,\n );\n }\n}\n\ninterface GetImgPropsOptions {\n imgConf: ImageConfigComplete;\n blurComplete: boolean;\n showAltText: boolean;\n}\n\nexport const VALID_LOADING_VALUES = [\"lazy\", \"eager\", undefined] as const;\n// Object-fit values that are not valid background-size values\nconst INVALID_BACKGROUND_SIZE_VALUES = [\n \"-moz-initial\",\n \"fill\",\n \"none\",\n \"scale-down\",\n undefined,\n];\n\nlet perfObserver: PerformanceObserver | undefined;\nconst allImgs = new Map<\n string,\n { src: string; loading: LoadingValue; placeholder: PlaceholderValue }\n>();\n\nexport function getImgProps(\n props: ImageProps,\n { imgConf, blurComplete, showAltText }: GetImgPropsOptions,\n): ImgPropsResult {\n const merged = mergeProps(\n {\n // loader: defaultLoader,\n fill: false,\n priority: false,\n preload: false,\n placeholder: \"empty\",\n unoptimized: imgConf.unoptimized,\n decoding: \"async\",\n } as const,\n props,\n );\n const [local, others] = splitProps(merged, [\n \"src\",\n \"loader\",\n \"quality\",\n \"width\",\n \"height\",\n \"fill\",\n \"sizes\",\n \"priority\",\n \"placeholder\",\n \"blurDataURL\",\n \"unoptimized\",\n \"overrideSrc\",\n \"onLoad\",\n \"onLoadingComplete\",\n \"layout\",\n \"style\",\n \"preload\",\n \"loading\",\n \"objectFit\",\n \"objectPosition\",\n \"lazyBoundary\",\n \"lazyRoot\",\n \"fetchpriority\",\n \"class\",\n \"decoding\",\n ]);\n\n let config: ImageConfig;\n const c = imgConf || imageConfigDefault;\n\n if (\"allSizes\" in c) {\n config = c as ImageConfig;\n } else {\n const allSizes = [...c.deviceSizes, ...c.imageSizes].sort((a, b) => a - b);\n const deviceSizes = c.deviceSizes.sort((a, b) => a - b);\n const qualities = c.qualities?.sort((a, b) => a - b);\n config = { ...c, allSizes, deviceSizes, qualities };\n }\n\n if (typeof defaultLoader === \"undefined\") {\n throw new Error(\n \"images.loaderFile detected but the file is missing default export.\\nRead more: https://nextjs.org/docs/messages/invalid-images-config\",\n );\n }\n\n let style = local.style;\n let sizes = local.sizes;\n let fill = local.fill;\n\n const loader: ImageLoaderWithConfig = local.loader || defaultLoader;\n\n if (local.layout) {\n if (local.layout === \"fill\") {\n fill = true;\n }\n const layoutToStyle: Record<string, Record<string, string> | undefined> = {\n intrinsic: { maxWidth: \"100%\", height: \"auto\" },\n responsive: { width: \"100%\", height: \"auto\" },\n };\n const layoutToSizes: Record<string, string | undefined> = {\n responsive: \"100vw\",\n fill: \"100vw\",\n };\n const layoutStyle = layoutToStyle[local.layout];\n if (layoutStyle) {\n style = { ...style, ...layoutStyle };\n }\n const layoutSizes = layoutToSizes[local.layout];\n if (layoutSizes && !sizes) {\n sizes = layoutSizes;\n }\n }\n\n let staticSrc = \"\";\n let blurDataURL = local.blurDataURL;\n let widthInt = getInt(local.width);\n let heightInt = getInt(local.height);\n let blurWidth: number | undefined;\n let blurHeight: number | undefined;\n\n if (isStaticImport(local.src)) {\n const staticImageData = isStaticRequire(local.src)\n ? local.src.default\n : local.src;\n\n if (!staticImageData.src) {\n throw new Error(\n `An object should only be passed to the image component src parameter if it comes from a static image import. It must include src. Received ${JSON.stringify(\n staticImageData,\n )}`,\n );\n }\n if (!staticImageData.height || !staticImageData.width) {\n throw new Error(\n `An object should only be passed to the image component src parameter if it comes from a static image import. It must include height and width. Received ${JSON.stringify(\n staticImageData,\n )}`,\n );\n }\n\n blurWidth = staticImageData.blurWidth;\n blurHeight = staticImageData.blurHeight;\n blurDataURL = blurDataURL || staticImageData.blurDataURL;\n staticSrc = staticImageData.src;\n\n if (!fill) {\n if (!widthInt && !heightInt) {\n widthInt = staticImageData.width;\n heightInt = staticImageData.height;\n } else if (widthInt && !heightInt) {\n const ratio = widthInt / staticImageData.width;\n heightInt = Math.round(staticImageData.height * ratio);\n } else if (!widthInt && heightInt) {\n const ratio = heightInt / staticImageData.height;\n widthInt = Math.round(staticImageData.width * ratio);\n }\n }\n }\n const src = typeof local.src === \"string\" ? local.src : staticSrc;\n\n let unoptimized = local.unoptimized;\n let isLazy =\n !local.priority &&\n !local.preload &&\n (local.loading === \"lazy\" || typeof local.loading === \"undefined\");\n if (!src || src.startsWith(\"data:\") || src.startsWith(\"blob:\")) {\n // https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\n unoptimized = true;\n isLazy = false;\n }\n if (config.unoptimized) {\n unoptimized = true;\n }\n if (!config.dangerouslyAllowSVG && src.split(\"?\", 1)[0].endsWith(\".svg\")) {\n // Special case to make svg serve as-is to avoid proxying\n // through the built-in Image Optimization API.\n unoptimized = true;\n }\n\n const qualityInt = getInt(local.quality);\n\n if (!import.meta.env.PROD) {\n if (config.output === \"export\" && !unoptimized) {\n throw new Error(\n `Image Optimization using the default loader is not compatible with \\`{ output: 'export' }\\`.\n Possible solutions:\n - Remove \\`{ output: 'export' }\\` and run \"next start\" to run server mode including the Image Optimization API.\n - Configure \\`{ images: { unoptimized: true } }\\` in \\`next.config.js\\` to disable the Image Optimization API.\n Read more: https://nextjs.org/docs/messages/export-image-api`,\n );\n }\n if (!src) {\n // React doesn't show the stack trace and there's\n // no `src` to help identify which image, so we\n // instead console.error(ref) during mount.\n unoptimized = true;\n } else {\n if (fill) {\n if (local.width) {\n throw new Error(\n `Image with src \"${src}\" has both \"width\" and \"fill\" properties. Only one should be used.`,\n );\n }\n if (local.height) {\n throw new Error(\n `Image with src \"${src}\" has both \"height\" and \"fill\" properties. Only one should be used.`,\n );\n }\n if (style?.position && style.position !== \"absolute\") {\n throw new Error(\n `Image with src \"${src}\" has both \"fill\" and \"style.position\" properties. Images with \"fill\" always use position absolute - it cannot be modified.`,\n );\n }\n if (style?.width && style.width !== \"100%\") {\n throw new Error(\n `Image with src \"${src}\" has both \"fill\" and \"style.width\" properties. Images with \"fill\" always use width 100% - it cannot be modified.`,\n );\n }\n if (style?.height && style.height !== \"100%\") {\n throw new Error(\n `Image with src \"${src}\" has both \"fill\" and \"style.height\" properties. Images with \"fill\" always use height 100% - it cannot be modified.`,\n );\n }\n } else {\n if (typeof widthInt === \"undefined\") {\n throw new Error(\n `Image with src \"${src}\" is missing required \"width\" property.`,\n );\n } else if (Number.isNaN(widthInt)) {\n throw new Error(\n `Image with src \"${src}\" has invalid \"width\" property. Expected a numeric value in pixels but received \"${local.width}\".`,\n );\n }\n if (typeof heightInt === \"undefined\") {\n throw new Error(\n `Image with src \"${src}\" is missing required \"height\" property.`,\n );\n } else if (Number.isNaN(heightInt)) {\n throw new Error(\n `Image with src \"${src}\" has invalid \"height\" property. Expected a numeric value in pixels but received \"${local.height}\".`,\n );\n }\n\n // biome-ignore lint/suspicious/noControlCharactersInRegex: no-control-regex\n if (/^[\\x00-\\x20]/.test(src)) {\n throw new Error(\n `Image with src \"${src}\" cannot start with a space or control character. Use src.trimStart() to remove it or encodeURIComponent(src) to keep it.`,\n );\n }\n // biome-ignore lint/suspicious/noControlCharactersInRegex: no-control-regex\n if (/[\\x00-\\x20]$/.test(src)) {\n throw new Error(\n `Image with src \"${src}\" cannot end with a space or control character. Use src.trimEnd() to remove it or encodeURIComponent(src) to keep it.`,\n );\n }\n }\n }\n if (!VALID_LOADING_VALUES.includes(local.loading)) {\n throw new Error(\n `Image with src \"${src}\" has invalid \"loading\" property. Provided \"${local.loading}\" should be one of ${VALID_LOADING_VALUES.map(\n String,\n ).join(\",\")}.`,\n );\n }\n if (local.priority && local.loading === \"lazy\") {\n throw new Error(\n `Image with src \"${src}\" has both \"priority\" and \"loading='lazy'\" properties. Only one should be used.`,\n );\n }\n if (local.preload && local.loading === \"lazy\") {\n throw new Error(\n `Image with src \"${src}\" has both \"preload\" and \"loading='lazy'\" properties. Only one should be used.`,\n );\n }\n if (local.preload && local.priority) {\n throw new Error(\n `Image with src \"${src}\" has both \"preload\" and \"priority\" properties. Only \"preload\" should be used.`,\n );\n }\n if (\n local.placeholder !== \"empty\" &&\n local.placeholder !== \"blur\" &&\n !local.placeholder.startsWith(\"data:image/\")\n ) {\n throw new Error(\n `Image with src \"${src}\" has invalid \"placeholder\" property \"${local.placeholder}\".`,\n );\n }\n if (local.placeholder !== \"empty\") {\n if (widthInt && heightInt && widthInt * heightInt < 1600) {\n warnOnce(\n `Image with src \"${src}\" is smaller than 40x40. Consider removing the \"placeholder\" property to improve performance.`,\n );\n }\n }\n if (\n qualityInt &&\n config.qualities &&\n !config.qualities.includes(qualityInt)\n ) {\n warnOnce(\n `Image with src \"${src}\" is using quality \"${qualityInt}\" which is not configured in images.qualities [${config.qualities.join(\", \")}]. Please update your config to [${[...config.qualities, qualityInt].sort().join(\", \")}].` +\n `\\nRead more: https://nextjs.org/docs/messages/next-image-unconfigured-qualities`,\n );\n }\n if (local.placeholder === \"blur\" && !blurDataURL) {\n const VALID_BLUR_EXT = [\"jpeg\", \"png\", \"webp\", \"avif\"]; // should match next-image-loader\n\n throw new Error(\n `Image with src \"${src}\" has \"placeholder='blur'\" property but is missing the \"blurDataURL\" property.\n Possible solutions:\n - Add a \"blurDataURL\" property, the contents should be a small Data URL to represent the image\n - Change the \"src\" property to a static import with one of the supported file types: ${VALID_BLUR_EXT.join(\n \",\",\n )} (animated images not supported)\n - Remove the \"placeholder\" property, effectively no blur effect\n Read more: https://nextjs.org/docs/messages/placeholder-blur-data-url`,\n );\n }\n if (\"ref\" in others) {\n warnOnce(\n `Image with src \"${src}\" is using unsupported \"ref\" property. Consider using the \"onLoad\" property instead.`,\n );\n }\n\n if (!unoptimized) {\n const urlStr = loader({\n config,\n src,\n width: widthInt || 400,\n quality: qualityInt || 75,\n });\n let url: URL | undefined;\n try {\n url = new URL(urlStr);\n } catch (err) {\n console.error(err);\n }\n if (urlStr === src || (url && url.pathname === src && !url.search)) {\n warnOnce(\n `Image with src \"${src}\" has a \"loader\" property that does not implement width. Please implement it or use the \"unoptimized\" property instead.` +\n `\\nRead more: https://nextjs.org/docs/messages/next-image-missing-loader-width`,\n );\n }\n }\n\n if (local.onLoadingComplete) {\n warnOnce(\n `Image with src \"${src}\" is using deprecated \"onLoadingComplete\" property. Please use the \"onLoad\" property instead.`,\n );\n }\n\n for (const [legacyKey, legacyValue] of Object.entries({\n layout: local.layout,\n objectFit: local.objectFit,\n objectPosition: local.objectPosition,\n lazyBoundary: local.lazyBoundary,\n lazyRoot: local.lazyRoot,\n })) {\n if (legacyValue) {\n warnOnce(\n `Image with src \"${src}\" has legacy prop \"${legacyKey}\". Did you forget to run the codemod?` +\n `\\nRead more: https://nextjs.org/docs/messages/next-image-upgrade-to-13`,\n );\n }\n }\n\n if (\n typeof window !== \"undefined\" &&\n !perfObserver &&\n window.PerformanceObserver\n ) {\n perfObserver = new PerformanceObserver((entryList) => {\n for (const entry of entryList.getEntries()) {\n // @ts-expect-error - missing \"LargestContentfulPaint\" class with \"element\" prop\n const imgSrc = entry?.element?.src || \"\";\n const lcpImage = allImgs.get(imgSrc);\n if (\n lcpImage &&\n lcpImage.loading === \"lazy\" &&\n lcpImage.placeholder === \"empty\" &&\n !lcpImage.src.startsWith(\"data:\") &&\n !lcpImage.src.startsWith(\"blob:\")\n ) {\n // https://web.dev/lcp/#measure-lcp-in-javascript\n warnOnce(\n `Image with src \"${lcpImage.src}\" was detected as the Largest Contentful Paint (LCP). Please add the \\`loading=\"eager\"\\` property if this image is above the fold.` +\n `\\nRead more: https://nextjs.org/docs/app/api-reference/components/image#loading`,\n );\n }\n }\n });\n try {\n perfObserver.observe({\n type: \"largest-contentful-paint\",\n buffered: true,\n });\n } catch (err) {\n // Log error but don't crash the app\n console.error(err);\n }\n }\n }\n\n const imgStyle = Object.assign(\n fill\n ? {\n position: \"absolute\",\n height: \"100%\",\n width: \"100%\",\n left: 0,\n top: 0,\n right: 0,\n bottom: 0,\n objectFit: local.objectFit,\n objectPosition: local.objectPosition,\n }\n : {},\n showAltText ? {} : { color: \"transparent\" },\n style,\n );\n\n const backgroundImage =\n !blurComplete && local.placeholder !== \"empty\"\n ? local.placeholder === \"blur\"\n ? `url(\"data:image/svg+xml;charset=utf-8,${getImageBlurSvg({\n widthInt,\n heightInt,\n blurWidth,\n blurHeight,\n blurDataURL: blurDataURL || \"\", // assume not undefined\n objectFit: imgStyle.objectFit,\n })}\")`\n : `url(\"${local.placeholder}\")` // assume `data:image/`\n : null;\n\n const backgroundSize = !INVALID_BACKGROUND_SIZE_VALUES.includes(\n imgStyle.objectFit,\n )\n ? imgStyle.objectFit\n : imgStyle.objectFit === \"fill\"\n ? \"100% 100%\" // the background-size equivalent of `fill`\n : \"cover\";\n\n const placeholderStyle: PlaceholderStyle = backgroundImage\n ? {\n \"background-size\": backgroundSize,\n \"background-position\": imgStyle.objectPosition || \"50% 50%\",\n \"background-repeat\": \"no-repeat\",\n \"background-image\": backgroundImage,\n }\n : {};\n\n if (import.meta.env.DEV) {\n if (\n placeholderStyle[\"background-image\"] &&\n local.placeholder === \"blur\" &&\n blurDataURL?.startsWith(\"/\")\n ) {\n // During `next dev`, we don't want to generate blur placeholders with webpack\n // because it can delay starting the dev server. Instead, `next-image-loader.js`\n // will inline a special url to lazily generate the blur placeholder at request time.\n placeholderStyle[\"background-image\"] = `url(\"${blurDataURL}\")`;\n }\n }\n\n const imgAttributes = generateImgAttrs({\n config,\n src,\n unoptimized,\n width: widthInt,\n quality: qualityInt,\n sizes,\n loader,\n });\n\n const loadingFinal = isLazy ? \"lazy\" : local.loading;\n\n if (!import.meta.env.PROD) {\n if (typeof window !== \"undefined\") {\n let fullUrl: URL;\n try {\n fullUrl = new URL(imgAttributes.src);\n } catch (e) {\n console.error(e);\n fullUrl = new URL(imgAttributes.src, window.location.href);\n }\n allImgs.set(fullUrl.href, {\n src,\n loading: loadingFinal,\n placeholder: local.placeholder,\n });\n }\n }\n\n const newProps: ImgProps = {\n ...others,\n loading: loadingFinal,\n fetchpriority: local.fetchpriority,\n width: widthInt,\n height: heightInt,\n decoding: local.decoding,\n class: local.class,\n style: { ...imgStyle, ...placeholderStyle },\n sizes: imgAttributes.sizes,\n srcSet: imgAttributes.srcSet,\n src: local.overrideSrc || imgAttributes.src,\n };\n const meta = {\n unoptimized,\n preload: local.preload || local.priority,\n placeholder: local.placeholder,\n fill,\n };\n return { props: newProps, meta };\n}\n\nfunction defaultLoader({ src, width, quality }: ImageLoaderProps): string {\n if (import.meta.env.DEV) {\n const missingValues: string[] = [];\n if (!src) missingValues.push(\"src\");\n if (!width) missingValues.push(\"width\");\n if (missingValues.length > 0) {\n throw new Error(\n `[defaultLoader] 缺少必要属性:${missingValues.join(\", \")}。` +\n `请确认调用方式正确,或提供自定义 loader。`,\n );\n }\n }\n\n // 如果 src 本身已是带参数的 URL(外部图片),直接返回\n if (src.startsWith(\"http://\") || src.startsWith(\"https://\")) {\n return src;\n }\n\n // 本地图片:追加 w / q 参数(供自定义服务器处理)\n const params = new URLSearchParams();\n params.set(\"url\", src);\n params.set(\"w\", String(width));\n if (quality) params.set(\"q\", String(quality));\n return `/_image?${params.toString()}`;\n}\n\nfunction getInt(x: unknown): number | undefined {\n if (typeof x === \"undefined\") {\n return x;\n }\n if (typeof x === \"number\") {\n return Number.isFinite(x) ? x : NaN;\n }\n if (typeof x === \"string\" && /^[0-9]+$/.test(x)) {\n return parseInt(x, 10);\n }\n return NaN;\n}\n\nfunction isStaticRequire(\n src: StaticRequire | StaticImageData,\n): src is StaticRequire {\n return (src as StaticRequire).default !== undefined;\n}\n\nfunction isStaticImageData(\n src: StaticRequire | StaticImageData,\n): src is StaticImageData {\n return (src as StaticImageData).src !== undefined;\n}\n\nfunction isStaticImport(src: string | StaticImport): src is StaticImport {\n return (\n !!src &&\n typeof src === \"object\" &&\n (isStaticRequire(src as StaticImport) ||\n isStaticImageData(src as StaticImport))\n );\n}\n\nfunction getImageBlurSvg({\n widthInt,\n heightInt,\n blurWidth,\n blurHeight,\n blurDataURL,\n objectFit,\n}: {\n widthInt?: number;\n heightInt?: number;\n blurWidth?: number;\n blurHeight?: number;\n blurDataURL: string;\n objectFit?: string;\n}): string {\n const std = 20;\n const svgWidth = blurWidth ? blurWidth * 40 : widthInt;\n const svgHeight = blurHeight ? blurHeight * 40 : heightInt;\n\n const viewBox =\n svgWidth && svgHeight ? `viewBox='0 0 ${svgWidth} ${svgHeight}'` : \"\";\n const preserveAspectRatio = viewBox\n ? \"none\"\n : objectFit === \"contain\"\n ? \"xMidYMid\"\n : objectFit === \"cover\"\n ? \"xMidYMid slice\"\n : \"none\";\n\n return `%3Csvg xmlns='http://www.w3.org/2000/svg' ${viewBox}%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeGaussianBlur stdDeviation='${std}'/%3E%3CfeColorMatrix values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 100 -1' result='s'/%3E%3CfeFlood x='0' y='0' width='100%25' height='100%25'/%3E%3CfeComposite operator='out' in='s'/%3E%3CfeComposite in2='SourceGraphic'/%3E%3CfeGaussianBlur stdDeviation='${std}'/%3E%3C/filter%3E%3Cimage width='100%25' height='100%25' x='0' y='0' preserveAspectRatio='${preserveAspectRatio}' style='filter: url(%23b);' href='${blurDataURL}'/%3E%3C/svg%3E`;\n}\n\ntype GenImgAttrsData = {\n config: ImageConfig;\n src: string;\n unoptimized: boolean;\n loader: ImageLoaderWithConfig;\n width?: number;\n quality?: number;\n sizes?: string;\n};\n\ntype GenImgAttrsResult = {\n src: string;\n srcSet: string | undefined;\n sizes: string | undefined;\n};\n\nfunction generateImgAttrs({\n config,\n src,\n unoptimized,\n width,\n quality,\n sizes,\n loader,\n}: GenImgAttrsData): GenImgAttrsResult {\n if (unoptimized) {\n return { src, srcSet: undefined, sizes: undefined };\n }\n\n const { widths, kind } = getWidths(config, width, sizes);\n const last = widths.length - 1;\n\n return {\n sizes: !sizes && kind === \"w\" ? \"100vw\" : sizes,\n srcSet: widths\n .map(\n (w, i) =>\n `${loader({ config, src, quality, width: w })} ${\n kind === \"w\" ? w : i + 1\n }${kind}`,\n )\n .join(\", \"),\n\n // It's intended to keep `src` the last attribute because React updates\n // attributes in order. If we keep `src` the first one, Safari will\n // immediately start to fetch `src`, before `sizes` and `srcSet` are even\n // updated by React. That causes multiple unnecessary requests if `srcSet`\n // and `sizes` are defined.\n // This bug cannot be reproduced in Chrome or Firefox.\n src: loader({ config, src, quality, width: widths[last] }),\n };\n}\n\nfunction getWidths(\n { deviceSizes, allSizes }: ImageConfig,\n width: number | undefined,\n sizes: string | undefined,\n): { widths: number[]; kind: \"w\" | \"x\" } {\n if (sizes) {\n // Find all the \"vw\" percent sizes used in the sizes prop\n const viewportWidthRe = /(^|\\s)(1?\\d?\\d)vw/g;\n const percentSizes = [];\n for (\n let match: RegExpExecArray | null;\n // biome-ignore lint/suspicious/noAssignInExpressions: nextjs code\n (match = viewportWidthRe.exec(sizes));\n match\n ) {\n percentSizes.push(Number.parseInt(match[2], 10));\n }\n if (percentSizes.length) {\n const smallestRatio = Math.min(...percentSizes) * 0.01;\n return {\n widths: allSizes.filter((s) => s >= deviceSizes[0] * smallestRatio),\n kind: \"w\",\n };\n }\n return { widths: allSizes, kind: \"w\" };\n }\n if (typeof width !== \"number\") {\n return { widths: deviceSizes, kind: \"w\" };\n }\n\n const widths = [\n ...new Set(\n // > This means that most OLED screens that say they are 3x resolution,\n // > are actually 3x in the green color, but only 1.5x in the red and\n // > blue colors. Showing a 3x resolution image in the app vs a 2x\n // > resolution image will be visually the same, though the 3x image\n // > takes significantly more data. Even true 3x resolution screens are\n // > wasteful as the human eye cannot see that level of detail without\n // > something like a magnifying glass.\n // https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/capping-image-fidelity-on-ultra-high-resolution-devices.html\n [width, width * 2 /*, width * 3*/].map(\n (w) => allSizes.find((p) => p >= w) || allSizes[allSizes.length - 1],\n ),\n ),\n ];\n return { widths, kind: \"x\" };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createContext as e, useContext as t } from "solid-js";
|
|
2
|
+
//#region src/components/popover/Popover/Popover.context.ts
|
|
3
|
+
var n = e();
|
|
4
|
+
function r(e) {
|
|
5
|
+
let r = t(n);
|
|
6
|
+
if (!r) throw Error(`<${e}> 必须渲染在 <Popover> 内部`);
|
|
7
|
+
return r;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { n as PopoverContext, r as usePopoverContext };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=Popover.context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.context.js","names":[],"sources":["../../../../src/components/popover/Popover/Popover.context.ts"],"sourcesContent":["import { createContext, useContext } from \"solid-js\";\nimport type { PopoverContextValue } from \"./Popover.types\";\n\nexport const PopoverContext = createContext<PopoverContextValue>();\n\nexport function usePopoverContext(component: string): PopoverContextValue {\n const ctx = useContext(PopoverContext);\n if (!ctx) {\n throw new Error(`<${component}> 必须渲染在 <Popover> 内部`);\n }\n return ctx;\n}\n"],"mappings":";;AAGA,IAAa,IAAiB,EAAmC;AAEjE,SAAgB,EAAkB,GAAwC;CACxE,IAAM,IAAM,EAAW,CAAc;CACrC,IAAI,CAAC,GACH,MAAU,MAAM,IAAI,EAAU,qBAAqB;CAErD,OAAO;AACT"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { JSX } from 'solid-js';
|
|
2
|
+
import { PopoverProps } from './Popover.types';
|
|
3
|
+
/**
|
|
4
|
+
* Popover 根组件:不渲染任何 DOM,只负责状态管理 + 提供 context。
|
|
5
|
+
* 真正的展示交给 <PopoverTrigger>/<PopoverContent>。
|
|
6
|
+
*
|
|
7
|
+
* 这是 shadcn Base UI 版本 Popover 的 SolidJS 移植:Base UI 的 Root 同样不渲染
|
|
8
|
+
* 自己的 HTML 元素,只作为状态容器使用。
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <Popover>
|
|
13
|
+
* <PopoverTrigger>打开</PopoverTrigger>
|
|
14
|
+
* <PopoverContent>内容</PopoverContent>
|
|
15
|
+
* </Popover>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function Popover(props: PopoverProps): JSX.Element;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { PopoverContext as e } from "./Popover.context.js";
|
|
2
|
+
import { createComponent as t } from "solid-js/web";
|
|
3
|
+
import { createMemo as n, createSignal as r, createUniqueId as i } from "solid-js";
|
|
4
|
+
//#region src/components/popover/Popover/Popover.tsx
|
|
5
|
+
function a(a) {
|
|
6
|
+
let [o, s] = r(a.defaultOpen ?? !1), c = n(() => a.open === void 0 ? o() : a.open), l = n(() => !!a.disabled), u = n(() => !!a.modal), [d, f] = r(), [p, m] = r(), h = (e) => {
|
|
7
|
+
a.open === void 0 && s(e), a.onOpenChange?.(e);
|
|
8
|
+
}, g = {
|
|
9
|
+
open: c,
|
|
10
|
+
disabled: l,
|
|
11
|
+
modal: u,
|
|
12
|
+
contentId: `popover-${i()}`,
|
|
13
|
+
reference: d,
|
|
14
|
+
setReference: f,
|
|
15
|
+
floating: p,
|
|
16
|
+
setFloating: m,
|
|
17
|
+
openPopover: () => {
|
|
18
|
+
l() || h(!0);
|
|
19
|
+
},
|
|
20
|
+
closePopover: () => {
|
|
21
|
+
h(!1);
|
|
22
|
+
},
|
|
23
|
+
togglePopover: () => {
|
|
24
|
+
l() || h(!c());
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return t(e.Provider, {
|
|
28
|
+
value: g,
|
|
29
|
+
get children() {
|
|
30
|
+
return a.children;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { a as Popover };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=Popover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.js","names":["createMemo","createSignal","createUniqueId","JSX","PopoverContext","PopoverContextValue","PopoverProps","Popover","props","Element","internalOpen","setInternalOpen","defaultOpen","open","undefined","disabled","modal","reference","setReference","floating","setFloating","HTMLElement","commit","next","onOpenChange","openPopover","closePopover","togglePopover","contentId","ctx","_$createComponent","Provider","value","children"],"sources":["../../../../src/components/popover/Popover/Popover.tsx"],"sourcesContent":["import { createMemo, createSignal, createUniqueId, type JSX } from \"solid-js\";\nimport { PopoverContext } from \"./Popover.context\";\nimport type { PopoverContextValue, PopoverProps } from \"./Popover.types\";\n\n/**\n * Popover 根组件:不渲染任何 DOM,只负责状态管理 + 提供 context。\n * 真正的展示交给 <PopoverTrigger>/<PopoverContent>。\n *\n * 这是 shadcn Base UI 版本 Popover 的 SolidJS 移植:Base UI 的 Root 同样不渲染\n * 自己的 HTML 元素,只作为状态容器使用。\n *\n * @example\n * ```tsx\n * <Popover>\n * <PopoverTrigger>打开</PopoverTrigger>\n * <PopoverContent>内容</PopoverContent>\n * </Popover>\n * ```\n */\nexport function Popover(props: PopoverProps): JSX.Element {\n const [internalOpen, setInternalOpen] = createSignal(\n props.defaultOpen ?? false,\n );\n const open = createMemo(() =>\n props.open !== undefined ? props.open : internalOpen(),\n );\n const disabled = createMemo(() => !!props.disabled);\n const modal = createMemo(() => !!props.modal);\n\n const [reference, setReference] = createSignal<Element>();\n const [floating, setFloating] = createSignal<HTMLElement>();\n\n const commit = (next: boolean) => {\n if (props.open === undefined) setInternalOpen(next);\n props.onOpenChange?.(next);\n };\n\n const openPopover = () => {\n if (disabled()) return;\n commit(true);\n };\n\n const closePopover = () => {\n commit(false);\n };\n\n const togglePopover = () => {\n if (disabled()) return;\n commit(!open());\n };\n\n const contentId = `popover-${createUniqueId()}`;\n\n const ctx: PopoverContextValue = {\n open,\n disabled,\n modal,\n contentId,\n reference,\n setReference,\n floating,\n setFloating,\n openPopover,\n closePopover,\n togglePopover,\n };\n\n return (\n <PopoverContext.Provider value={ctx}>\n {props.children}\n </PopoverContext.Provider>\n );\n}\n"],"mappings":";;;;AAmBA,SAAgBO,EAAQC,GAAkC;CACxD,IAAM,CAACE,GAAcC,KAAmBV,EACtCO,EAAMI,eAAe,EACvB,GACMC,IAAOb,QACXQ,EAAMK,SAASC,KAAAA,IAAyBJ,EAAa,IAA1BF,EAAMK,IACnC,GACME,IAAWf,QAAiB,CAAC,CAACQ,EAAMO,QAAQ,GAC5CC,IAAQhB,QAAiB,CAAC,CAACQ,EAAMQ,KAAK,GAEtC,CAACC,GAAWC,KAAgBjB,EAAsB,GAClD,CAACkB,GAAUC,KAAenB,EAA0B,GAEpDqB,KAAUC,MAAkB;EAEhCf,AADIA,EAAMK,SAASC,KAAAA,KAAWH,EAAgBY,CAAI,GAClDf,EAAMgB,eAAeD,CAAI;CAC3B,GAkBMM,IAA2B;EAC/BhB;EACAE;EACAC;EACAY,WAAAA,WAN2B1B,EAAe;EAO1Ce;EACAC;EACAC;EACAC;EACAK,mBAzBwB;GACpBV,EAAS,KACbO,EAAO,EAAI;EACb;EAuBEI,oBArByB;GACzBJ,EAAO,EAAK;EACd;EAoBEK,qBAlB0B;GACtBZ,EAAS,KACbO,EAAO,CAACT,EAAK,CAAC;EAChB;CAgBA;CAEA,OAAAiB,EACG1B,EAAe2B,UAAQ;EAACC,OAAOH;EAAG,IAAAI,WAAA;GAAA,OAChCzB,EAAMyB;EAAQ;CAAA,CAAA;AAGrB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Accessor, ParentProps } from 'solid-js';
|
|
2
|
+
export interface PopoverProps extends ParentProps {
|
|
3
|
+
/** 受控打开状态;不传则内部自管理(非受控模式) */
|
|
4
|
+
open?: boolean;
|
|
5
|
+
/** 非受控模式下的初始打开状态 */
|
|
6
|
+
defaultOpen?: boolean;
|
|
7
|
+
onOpenChange?: (open: boolean) => void;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** 是否启用 modal 模式(当前仅透传,不实现焦点陷阱) */
|
|
10
|
+
modal?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface PopoverContextValue {
|
|
13
|
+
open: Accessor<boolean>;
|
|
14
|
+
disabled: Accessor<boolean>;
|
|
15
|
+
modal: Accessor<boolean>;
|
|
16
|
+
contentId: string;
|
|
17
|
+
reference: Accessor<Element | undefined>;
|
|
18
|
+
setReference: (el: Element | undefined) => void;
|
|
19
|
+
floating: Accessor<HTMLElement | undefined>;
|
|
20
|
+
setFloating: (el: HTMLElement | undefined) => void;
|
|
21
|
+
openPopover: () => void;
|
|
22
|
+
closePopover: () => void;
|
|
23
|
+
togglePopover: () => void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { PopoverContentProps } from './PopoverContent.types';
|
|
2
|
+
/**
|
|
3
|
+
* Popover 的浮层内容。挂 Portal 到 body,用 position:fixed 定位。
|
|
4
|
+
* 当前实现打开时挂载、关闭时直接卸载;进场动画由 data-open + RAF 驱动。
|
|
5
|
+
*/
|
|
6
|
+
export declare function PopoverContent(props: PopoverContentProps): import("solid-js").JSX.Element;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { clsx as e } from "../../../utils/clsx.js";
|
|
2
|
+
import { getAlignment as t, getSide as n } from "../../../lib/positioner/core/placement.js";
|
|
3
|
+
import { getPopoverTransformOrigin as r } from "./PopoverContent.utils.js";
|
|
4
|
+
import { usePopoverContent as i } from "./usePopoverContent.js";
|
|
5
|
+
import { Portal as a, createComponent as o, effect as s, insert as c, mergeProps as l, setAttribute as u, spread as d, style as f, template as p, use as m } from "solid-js/web";
|
|
6
|
+
import { Show as h, onCleanup as g, splitProps as _ } from "solid-js";
|
|
7
|
+
//#region src/components/popover/PopoverContent/PopoverContent.tsx
|
|
8
|
+
var v = /*#__PURE__*/ p("<div style=z-index:50><div role=dialog data-slot=popover-content>");
|
|
9
|
+
function y(p) {
|
|
10
|
+
let { ctx: y, pos: b, animationState: x } = i(() => p), [S, C] = _(p, [
|
|
11
|
+
"side",
|
|
12
|
+
"align",
|
|
13
|
+
"sideOffset",
|
|
14
|
+
"alignOffset",
|
|
15
|
+
"collisionPadding",
|
|
16
|
+
"class",
|
|
17
|
+
"classList",
|
|
18
|
+
"style",
|
|
19
|
+
"children"
|
|
20
|
+
]);
|
|
21
|
+
return o(h, {
|
|
22
|
+
get when() {
|
|
23
|
+
return y.open();
|
|
24
|
+
},
|
|
25
|
+
get children() {
|
|
26
|
+
return o(a, { get children() {
|
|
27
|
+
var i = v(), a = i.firstChild;
|
|
28
|
+
return m((e) => {
|
|
29
|
+
y.setFloating(e), g(() => y.setFloating(void 0));
|
|
30
|
+
}, i), d(a, l({
|
|
31
|
+
get id() {
|
|
32
|
+
return y.contentId;
|
|
33
|
+
},
|
|
34
|
+
get "data-open"() {
|
|
35
|
+
return x() === "open" ? "" : void 0;
|
|
36
|
+
},
|
|
37
|
+
get "data-closed"() {
|
|
38
|
+
return x() === "closed" ? "" : void 0;
|
|
39
|
+
},
|
|
40
|
+
get "data-side"() {
|
|
41
|
+
return n(b.placement());
|
|
42
|
+
},
|
|
43
|
+
get "data-align"() {
|
|
44
|
+
return t(b.placement()) ?? "center";
|
|
45
|
+
},
|
|
46
|
+
get style() {
|
|
47
|
+
return {
|
|
48
|
+
"transform-origin": r(b.placement()),
|
|
49
|
+
...typeof S.style == "object" ? S.style : void 0
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
get class() {
|
|
53
|
+
return e("z-50 flex w-72 flex-col gap-2.5 overflow-hidden rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100", "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", "data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95", "data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", S.class);
|
|
54
|
+
}
|
|
55
|
+
}, C), !1, !0), c(a, () => S.children), s((e) => {
|
|
56
|
+
var t = b.placement(), n = {
|
|
57
|
+
...b.floatingStyles(),
|
|
58
|
+
opacity: +!!b.isPositioned()
|
|
59
|
+
};
|
|
60
|
+
return t !== e.e && u(i, "data-placement", e.e = t), e.t = f(i, n, e.t), e;
|
|
61
|
+
}, {
|
|
62
|
+
e: void 0,
|
|
63
|
+
t: void 0
|
|
64
|
+
}), i;
|
|
65
|
+
} });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { y as PopoverContent };
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=PopoverContent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PopoverContent.js","names":["Show","onCleanup","splitProps","Portal","clsx","getAlignment","getSide","usePopoverContent","getPopoverTransformOrigin","PopoverContentProps","PopoverContent","props","ctx","pos","animationState","local","rest","_$createComponent","when","open","children","_el$","_tmpl$","_el$2","firstChild","_$use","el","setFloating","undefined","_$spread","_$mergeProps","id","contentId","data-open","data-closed","data-side","placement","data-align","style","class","_$insert","_$effect","_p$","_v$","_v$2","floatingStyles","opacity","isPositioned","e","_$setAttribute","t","_$style"],"sources":["../../../../src/components/popover/PopoverContent/PopoverContent.tsx"],"sourcesContent":["import { Show, onCleanup, splitProps } from \"solid-js\";\nimport { Portal } from \"solid-js/web\";\nimport { clsx } from \"~/utils\";\nimport { getAlignment, getSide } from \"~/lib\";\nimport { usePopoverContent } from \"./usePopoverContent\";\nimport { getPopoverTransformOrigin } from \"./PopoverContent.utils\";\nimport type { PopoverContentProps } from \"./PopoverContent.types\";\n\n/**\n * Popover 的浮层内容。挂 Portal 到 body,用 position:fixed 定位。\n * 当前实现打开时挂载、关闭时直接卸载;进场动画由 data-open + RAF 驱动。\n */\nexport function PopoverContent(props: PopoverContentProps) {\n const { ctx, pos, animationState } = usePopoverContent(() => props);\n\n const [local, rest] = splitProps(props, [\n \"side\",\n \"align\",\n \"sideOffset\",\n \"alignOffset\",\n \"collisionPadding\",\n \"class\",\n \"classList\",\n \"style\",\n \"children\",\n ]);\n\n return (\n <Show when={ctx.open()}>\n <Portal>\n {/*\n 外层:只负责定位(position:fixed 来自 floatingStyles),不参与动画。\n 内层:真正的视觉样式 + 进出场动画。分层的原因和 Select/Tooltip 相同:\n 同一个元素不能同时用 transform 做定位和做动画。\n */}\n <div\n ref={(el) => {\n ctx.setFloating(el);\n onCleanup(() => ctx.setFloating(undefined));\n }}\n data-placement={pos.placement()}\n style={{\n ...pos.floatingStyles(),\n \"z-index\": 50,\n opacity: pos.isPositioned() ? 1 : 0,\n }}\n >\n <div\n id={ctx.contentId}\n role=\"dialog\"\n data-slot=\"popover-content\"\n data-open={animationState() === \"open\" ? \"\" : undefined}\n data-closed={animationState() === \"closed\" ? \"\" : undefined}\n data-side={getSide(pos.placement())}\n data-align={getAlignment(pos.placement()) ?? \"center\"}\n style={{\n \"transform-origin\": getPopoverTransformOrigin(pos.placement()),\n ...(typeof local.style === \"object\" ? local.style : undefined),\n }}\n class={clsx(\n \"z-50 flex w-72 flex-col gap-2.5 overflow-hidden rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n \"data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95\",\n \"data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n local.class,\n )}\n {...rest}\n >\n {local.children}\n </div>\n </div>\n </Portal>\n </Show>\n );\n}\n"],"mappings":";;;;;;;;AAYA,SAAgBU,EAAeC,GAA4B;CACzD,IAAM,EAAEC,QAAKC,QAAKC,sBAAmBP,QAAwBI,CAAK,GAE5D,CAACI,GAAOC,KAAQd,EAAWS,GAAO;EACtC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CAAU,CACX;CAED,OAAAM,EACGjB,GAAI;EAAA,IAACkB,OAAI;GAAA,OAAEN,EAAIO,KAAK;EAAC;EAAA,IAAAC,WAAA;GAAA,OAAAH,EACnBd,GAAM,EAAA,IAAAiB,WAAA;IAAA,IAAAC,IAAAC,EAAA,GAAAC,IAAAF,EAAAG;IAgBF,OAhBEC,GAOGC,MAAO;KAEXzB,AADAW,EAAIe,YAAYD,CAAE,GAClBzB,QAAgBW,EAAIe,YAAYC,KAAAA,CAAS,CAAC;IAC5C,GAACP,CAAA,GAAAQ,EAAAN,GAAAO,EAAA;KAAA,IASCC,KAAE;MAAA,OAAEnB,EAAIoB;KAAS;KAAA,IAAA,cAAA;MAAA,OAGNlB,EAAe,MAAM,SAAS,KAAKc,KAAAA;KAAS;KAAA,IAAA,gBAAA;MAAA,OAC1Cd,EAAe,MAAM,WAAW,KAAKc,KAAAA;KAAS;KAAA,IAAA,cAAA;MAAA,OAChDtB,EAAQO,EAAIuB,UAAU,CAAC;KAAC;KAAA,IAAA,eAAA;MAAA,OACvB/B,EAAaQ,EAAIuB,UAAU,CAAC,KAAK;KAAQ;KAAA,IACrDE,QAAK;MAAA,OAAE;OACL,oBAAoB9B,EAA0BK,EAAIuB,UAAU,CAAC;OAC7D,GAAI,OAAOrB,EAAMuB,SAAU,WAAWvB,EAAMuB,QAAQV,KAAAA;MACtD;KAAC;KAAA,IAAA,QAAA;MAAA,OACMxB,EACL,+KACA,+JACA,iEACA,0EACAW,EAAMwB,KACR;KAAC;IAAA,GACGvB,CAAI,GAAA,IAAA,EAAA,GAAAwB,EAAAjB,SAEPR,EAAMK,QAAQ,GAAAqB,GAAAC,MAAA;KAAA,IAAAC,IA5BD9B,EAAIuB,UAAU,GAACQ,IACxB;MACL,GAAG/B,EAAIgC,eAAe;MAEtBC,SAASjC,KAAIkC,aAAa;KAC5B;KAAC,OAAAJ,MAAAD,EAAAM,KAAAC,EAAA5B,GAAA,kBAAAqB,EAAAM,IAAAL,CAAA,GAAAD,EAAAQ,IAAAC,EAAA9B,GAAAuB,GAAAF,EAAAQ,CAAA,GAAAR;IAAA,GAAA;KAAAM,GAAApB,KAAAA;KAAAsB,GAAAtB,KAAAA;IAAA,CAAA,GAAAP;GAAA,EAAA,CAAA;EAAA;CAAA,CAAA;AA6BX"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ParentProps } from 'solid-js';
|
|
2
|
+
import { Alignment, Side } from '../../../lib';
|
|
3
|
+
import { BaseProps } from '../../../types';
|
|
4
|
+
export type PopoverSide = Side | "inline-start" | "inline-end";
|
|
5
|
+
export interface PopoverContentProps extends BaseProps, ParentProps {
|
|
6
|
+
/** 贴 trigger 的哪一侧,默认 'bottom'。额外支持 Base UI 的 logical side。 */
|
|
7
|
+
side?: PopoverSide;
|
|
8
|
+
/** 沿边对齐方式,默认 'center' */
|
|
9
|
+
align?: Alignment | "center";
|
|
10
|
+
/** 沿主轴(side 指向的方向)与 trigger 之间的间距(像素),默认 4 */
|
|
11
|
+
sideOffset?: number;
|
|
12
|
+
/** 沿交叉轴(对齐方向)的偏移(像素),默认 0 */
|
|
13
|
+
alignOffset?: number;
|
|
14
|
+
/** 距视口边缘的最小间距(像素),默认 8 */
|
|
15
|
+
collisionPadding?: number;
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Middleware, Placement } from '../../../lib';
|
|
2
|
+
import { PopoverSide } from './PopoverContent.types';
|
|
3
|
+
/**
|
|
4
|
+
* 把 shadcn/Base UI 风格的 side + align 拆分参数转换成核心库统一用的
|
|
5
|
+
* `Placement` 字符串。Base UI 额外支持 inline-start / inline-end 逻辑方向,
|
|
6
|
+
* 这里简单按 LTR 映射(inline-start -> left, inline-end -> right)。
|
|
7
|
+
*/
|
|
8
|
+
export declare function toPopoverPlacement(side: PopoverSide, align: "start" | "end" | "center"): Placement;
|
|
9
|
+
/** 根据最终生效的 placement 计算缩放动画的 transform-origin。 */
|
|
10
|
+
export declare function getPopoverTransformOrigin(placement: Placement): string;
|
|
11
|
+
export interface BuildPopoverMiddlewareOptions {
|
|
12
|
+
sideOffset: number;
|
|
13
|
+
alignOffset: number;
|
|
14
|
+
collisionPadding: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Popover 定位管线:offset → flip → shift → hide → containingBlockOffset。
|
|
18
|
+
* 和 Tooltip 相比只少了 arrow middleware,其余策略一致。
|
|
19
|
+
*/
|
|
20
|
+
export declare function createPopoverMiddleware(options: BuildPopoverMiddlewareOptions): Middleware[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getAlignment as e, getSide as t } from "../../../lib/positioner/core/placement.js";
|
|
2
|
+
import { offset as n } from "../../../lib/positioner/middleware/offset.js";
|
|
3
|
+
import { shift as r } from "../../../lib/positioner/middleware/shift.js";
|
|
4
|
+
import { flip as i } from "../../../lib/positioner/middleware/flip.js";
|
|
5
|
+
import { hide as a } from "../../../lib/positioner/middleware/hide.js";
|
|
6
|
+
import { containingBlockOffset as o } from "../../../lib/positioner/middleware/containing-block-offset.js";
|
|
7
|
+
//#region src/components/popover/PopoverContent/PopoverContent.utils.ts
|
|
8
|
+
function s(e, t) {
|
|
9
|
+
let n = e === "inline-start" ? "left" : e === "inline-end" ? "right" : e;
|
|
10
|
+
return t === "center" ? n : `${n}-${t}`;
|
|
11
|
+
}
|
|
12
|
+
function c(n) {
|
|
13
|
+
let r = t(n), i = e(n), a = i === "start" ? "0%" : i === "end" ? "100%" : "50%";
|
|
14
|
+
switch (r) {
|
|
15
|
+
case "top": return `${a} 100%`;
|
|
16
|
+
case "bottom": return `${a} 0%`;
|
|
17
|
+
case "left": return `100% ${a}`;
|
|
18
|
+
case "right": return `0% ${a}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function l(e) {
|
|
22
|
+
return [
|
|
23
|
+
n({
|
|
24
|
+
mainAxis: e.sideOffset,
|
|
25
|
+
crossAxis: e.alignOffset
|
|
26
|
+
}),
|
|
27
|
+
i(),
|
|
28
|
+
r({ padding: e.collisionPadding }),
|
|
29
|
+
a(),
|
|
30
|
+
o()
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { l as createPopoverMiddleware, c as getPopoverTransformOrigin, s as toPopoverPlacement };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=PopoverContent.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PopoverContent.utils.js","names":[],"sources":["../../../../src/components/popover/PopoverContent/PopoverContent.utils.ts"],"sourcesContent":["import {\n containingBlockOffset,\n flip,\n getAlignment,\n getSide,\n hide,\n offset,\n shift,\n type Middleware,\n type Placement,\n} from \"~/lib\";\nimport type { PopoverSide } from \"./PopoverContent.types\";\n\n/**\n * 把 shadcn/Base UI 风格的 side + align 拆分参数转换成核心库统一用的\n * `Placement` 字符串。Base UI 额外支持 inline-start / inline-end 逻辑方向,\n * 这里简单按 LTR 映射(inline-start -> left, inline-end -> right)。\n */\nexport function toPopoverPlacement(\n side: PopoverSide,\n align: \"start\" | \"end\" | \"center\",\n): Placement {\n const physical =\n side === \"inline-start\" ? \"left\" : side === \"inline-end\" ? \"right\" : side;\n return align === \"center\" ? physical : (`${physical}-${align}` as Placement);\n}\n\n/** 根据最终生效的 placement 计算缩放动画的 transform-origin。 */\nexport function getPopoverTransformOrigin(placement: Placement): string {\n const side = getSide(placement);\n const align = getAlignment(placement);\n const crossAxisOrigin =\n align === \"start\" ? \"0%\" : align === \"end\" ? \"100%\" : \"50%\";\n\n switch (side) {\n case \"top\":\n return `${crossAxisOrigin} 100%`;\n case \"bottom\":\n return `${crossAxisOrigin} 0%`;\n case \"left\":\n return `100% ${crossAxisOrigin}`;\n case \"right\":\n return `0% ${crossAxisOrigin}`;\n }\n}\n\nexport interface BuildPopoverMiddlewareOptions {\n sideOffset: number;\n alignOffset: number;\n collisionPadding: number;\n}\n\n/**\n * Popover 定位管线:offset → flip → shift → hide → containingBlockOffset。\n * 和 Tooltip 相比只少了 arrow middleware,其余策略一致。\n */\nexport function createPopoverMiddleware(\n options: BuildPopoverMiddlewareOptions,\n): Middleware[] {\n return [\n offset({ mainAxis: options.sideOffset, crossAxis: options.alignOffset }),\n flip(),\n shift({ padding: options.collisionPadding }),\n hide(),\n containingBlockOffset(),\n ];\n}\n"],"mappings":";;;;;;;AAkBA,SAAgB,EACd,GACA,GACW;CACX,IAAM,IACJ,MAAS,iBAAiB,SAAS,MAAS,eAAe,UAAU;CACvE,OAAO,MAAU,WAAW,IAAY,GAAG,EAAS,GAAG;AACzD;AAGA,SAAgB,EAA0B,GAA8B;CACtE,IAAM,IAAO,EAAQ,CAAS,GACxB,IAAQ,EAAa,CAAS,GAC9B,IACJ,MAAU,UAAU,OAAO,MAAU,QAAQ,SAAS;CAExD,QAAQ,GAAR;EACE,KAAK,OACH,OAAO,GAAG,EAAgB;EAC5B,KAAK,UACH,OAAO,GAAG,EAAgB;EAC5B,KAAK,QACH,OAAO,QAAQ;EACjB,KAAK,SACH,OAAO,MAAM;CACjB;AACF;AAYA,SAAgB,EACd,GACc;CACd,OAAO;EACL,EAAO;GAAE,UAAU,EAAQ;GAAY,WAAW,EAAQ;EAAY,CAAC;EACvE,EAAK;EACL,EAAM,EAAE,SAAS,EAAQ,iBAAiB,CAAC;EAC3C,EAAK;EACL,EAAsB;CACxB;AACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { PopoverContent } from './PopoverContent';
|
|
2
|
+
export type { PopoverContentProps, PopoverSide } from './PopoverContent.types';
|
|
3
|
+
export { createPopoverMiddleware, toPopoverPlacement, } from './PopoverContent.utils';
|
|
4
|
+
export type { BuildPopoverMiddlewareOptions } from './PopoverContent.utils';
|
|
5
|
+
export { usePopoverContent } from './usePopoverContent';
|
|
6
|
+
export type { UsePopoverContentResult } from './usePopoverContent';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Positioner } from '../../../lib';
|
|
2
|
+
import { usePopoverContext } from '../Popover/Popover.context';
|
|
3
|
+
import { PopoverContentProps } from './PopoverContent.types';
|
|
4
|
+
export interface UsePopoverContentResult {
|
|
5
|
+
ctx: ReturnType<typeof usePopoverContext>;
|
|
6
|
+
pos: Positioner;
|
|
7
|
+
isVisible: () => boolean;
|
|
8
|
+
/** 驱动 data-open/data-closed 的动画状态;打开时比 isVisible 晚一帧。 */
|
|
9
|
+
animationState: () => "open" | "closed";
|
|
10
|
+
}
|
|
11
|
+
export declare function usePopoverContent(props: () => PopoverContentProps): UsePopoverContentResult;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createPositioner as e } from "../../../lib/positioner/create-positioner.js";
|
|
2
|
+
import { usePopoverContext as t } from "../Popover/Popover.context.js";
|
|
3
|
+
import { createPopoverMiddleware as n, toPopoverPlacement as r } from "./PopoverContent.utils.js";
|
|
4
|
+
import { createEffect as i, createMemo as a, createSignal as o, onCleanup as s } from "solid-js";
|
|
5
|
+
//#region src/components/popover/PopoverContent/usePopoverContent.ts
|
|
6
|
+
function c(c) {
|
|
7
|
+
let l = t("PopoverContent"), u = e(l.reference, l.floating, {
|
|
8
|
+
placement: () => r(c().side ?? "bottom", c().align ?? "center"),
|
|
9
|
+
strategy: "fixed",
|
|
10
|
+
middleware: () => n({
|
|
11
|
+
sideOffset: c().sideOffset ?? 4,
|
|
12
|
+
alignOffset: c().alignOffset ?? 0,
|
|
13
|
+
collisionPadding: c().collisionPadding ?? 8
|
|
14
|
+
})
|
|
15
|
+
}), d = a(() => l.open() && !u.middlewareData().hide?.referenceHidden), [f, p] = o("closed");
|
|
16
|
+
return i(() => {
|
|
17
|
+
if (d()) {
|
|
18
|
+
let e = requestAnimationFrame(() => p("open"));
|
|
19
|
+
s(() => cancelAnimationFrame(e));
|
|
20
|
+
} else p("closed");
|
|
21
|
+
}), i(() => {
|
|
22
|
+
if (!l.open()) return;
|
|
23
|
+
let e = (e) => {
|
|
24
|
+
let t = e.target;
|
|
25
|
+
!(t instanceof Element ? t : t?.parentElement)?.closest("[data-slot=\"select-content\"]") && !l.reference()?.contains(t) && !l.floating()?.contains(t) && (l.closePopover(), e.stopPropagation());
|
|
26
|
+
}, t = (e) => {
|
|
27
|
+
e.key === "Escape" && (e.preventDefault(), l.closePopover());
|
|
28
|
+
};
|
|
29
|
+
document.addEventListener("pointerdown", e, { capture: !0 }), document.addEventListener("keydown", t), s(() => {
|
|
30
|
+
document.removeEventListener("pointerdown", e, { capture: !0 }), document.removeEventListener("keydown", t);
|
|
31
|
+
});
|
|
32
|
+
}), {
|
|
33
|
+
ctx: l,
|
|
34
|
+
pos: u,
|
|
35
|
+
isVisible: d,
|
|
36
|
+
animationState: f
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { c as usePopoverContent };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=usePopoverContent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePopoverContent.js","names":[],"sources":["../../../../src/components/popover/PopoverContent/usePopoverContent.ts"],"sourcesContent":["import { createSignal, createMemo, createEffect, onCleanup } from \"solid-js\";\nimport { createPositioner, type Positioner } from \"~/lib\";\nimport { usePopoverContext } from \"../Popover/Popover.context\";\nimport {\n createPopoverMiddleware,\n toPopoverPlacement,\n} from \"./PopoverContent.utils\";\nimport type { PopoverContentProps } from \"./PopoverContent.types\";\n\nexport interface UsePopoverContentResult {\n ctx: ReturnType<typeof usePopoverContext>;\n pos: Positioner;\n isVisible: () => boolean;\n /** 驱动 data-open/data-closed 的动画状态;打开时比 isVisible 晚一帧。 */\n animationState: () => \"open\" | \"closed\";\n}\n\nexport function usePopoverContent(\n props: () => PopoverContentProps,\n): UsePopoverContentResult {\n const ctx = usePopoverContext(\"PopoverContent\");\n\n const pos = createPositioner(ctx.reference, ctx.floating, {\n placement: () =>\n toPopoverPlacement(props().side ?? \"bottom\", props().align ?? \"center\"),\n strategy: \"fixed\",\n middleware: () =>\n createPopoverMiddleware({\n sideOffset: props().sideOffset ?? 4,\n alignOffset: props().alignOffset ?? 0,\n collisionPadding: props().collisionPadding ?? 8,\n }),\n });\n\n const isVisible = createMemo(\n () => ctx.open() && !pos.middlewareData().hide?.referenceHidden,\n );\n\n // 打开时延迟一帧再触发动画 class,给定位计算留出时间。\n const [animationState, setAnimationState] = createSignal<\"open\" | \"closed\">(\n \"closed\",\n );\n\n createEffect(() => {\n if (isVisible()) {\n const raf = requestAnimationFrame(() => setAnimationState(\"open\"));\n onCleanup(() => cancelAnimationFrame(raf));\n } else {\n setAnimationState(\"closed\");\n }\n });\n\n // 打开期间绑定 document 级监听:点击外部关闭 + Escape 关闭。\n createEffect(() => {\n if (!ctx.open()) return;\n\n const onPointerDown = (e: PointerEvent) => {\n const target = e.target as Node;\n const targetElement =\n target instanceof Element ? target : target?.parentElement;\n const insideNestedFloating = !!targetElement?.closest(\n '[data-slot=\"select-content\"]',\n );\n if (\n !insideNestedFloating &&\n !ctx.reference()?.contains(target) &&\n !ctx.floating()?.contains(target)\n ) {\n ctx.closePopover();\n e.stopPropagation();\n }\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n ctx.closePopover();\n }\n };\n\n document.addEventListener(\"pointerdown\", onPointerDown, { capture: true });\n document.addEventListener(\"keydown\", onKeyDown);\n onCleanup(() => {\n document.removeEventListener(\"pointerdown\", onPointerDown, {\n capture: true,\n });\n document.removeEventListener(\"keydown\", onKeyDown);\n });\n });\n\n return { ctx, pos, isVisible, animationState };\n}\n"],"mappings":";;;;;AAiBA,SAAgB,EACd,GACyB;CACzB,IAAM,IAAM,EAAkB,gBAAgB,GAExC,IAAM,EAAiB,EAAI,WAAW,EAAI,UAAU;EACxD,iBACE,EAAmB,EAAM,CAAC,CAAC,QAAQ,UAAU,EAAM,CAAC,CAAC,SAAS,QAAQ;EACxE,UAAU;EACV,kBACE,EAAwB;GACtB,YAAY,EAAM,CAAC,CAAC,cAAc;GAClC,aAAa,EAAM,CAAC,CAAC,eAAe;GACpC,kBAAkB,EAAM,CAAC,CAAC,oBAAoB;EAChD,CAAC;CACL,CAAC,GAEK,IAAY,QACV,EAAI,KAAK,KAAK,CAAC,EAAI,eAAe,CAAC,CAAC,MAAM,eAClD,GAGM,CAAC,GAAgB,KAAqB,EAC1C,QACF;CAiDA,OA/CA,QAAmB;EACjB,IAAI,EAAU,GAAG;GACf,IAAM,IAAM,4BAA4B,EAAkB,MAAM,CAAC;GACjE,QAAgB,qBAAqB,CAAG,CAAC;EAC3C,OACE,EAAkB,QAAQ;CAE9B,CAAC,GAGD,QAAmB;EACjB,IAAI,CAAC,EAAI,KAAK,GAAG;EAEjB,IAAM,KAAiB,MAAoB;GACzC,IAAM,IAAS,EAAE;GAMjB,AACE,EALA,aAAkB,UAAU,IAAS,GAAQ,cAAA,EACD,QAC5C,gCACF,KAGE,CAAC,EAAI,UAAU,CAAC,EAAE,SAAS,CAAM,KACjC,CAAC,EAAI,SAAS,CAAC,EAAE,SAAS,CAAM,MAEhC,EAAI,aAAa,GACjB,EAAE,gBAAgB;EAEtB,GAEM,KAAa,MAAqB;GACtC,AAAI,EAAE,QAAQ,aACZ,EAAE,eAAe,GACjB,EAAI,aAAa;EAErB;EAIA,AAFA,SAAS,iBAAiB,eAAe,GAAe,EAAE,SAAS,GAAK,CAAC,GACzE,SAAS,iBAAiB,WAAW,CAAS,GAC9C,QAAgB;GAId,AAHA,SAAS,oBAAoB,eAAe,GAAe,EACzD,SAAS,GACX,CAAC,GACD,SAAS,oBAAoB,WAAW,CAAS;EACnD,CAAC;CACH,CAAC,GAEM;EAAE;EAAK;EAAK;EAAW;CAAe;AAC/C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { clsx as e } from "../../../utils/clsx.js";
|
|
2
|
+
import { mergeProps as t, spread as n, template as r } from "solid-js/web";
|
|
3
|
+
import { splitProps as i } from "solid-js";
|
|
4
|
+
//#region src/components/popover/PopoverDescription/PopoverDescription.tsx
|
|
5
|
+
var a = /*#__PURE__*/ r("<div data-slot=popover-description>");
|
|
6
|
+
function o(r) {
|
|
7
|
+
let [o, s] = i(r, ["class"]);
|
|
8
|
+
return (() => {
|
|
9
|
+
var r = a();
|
|
10
|
+
return n(r, t({ get class() {
|
|
11
|
+
return e("text-muted-foreground", o.class);
|
|
12
|
+
} }, s), !1, !1), r;
|
|
13
|
+
})();
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { o as PopoverDescription };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=PopoverDescription.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PopoverDescription.js","names":["splitProps","ComponentProps","clsx","PopoverDescription","props","local","rest","_el$","_tmpl$","_$spread","_$mergeProps","class"],"sources":["../../../../src/components/popover/PopoverDescription/PopoverDescription.tsx"],"sourcesContent":["import { splitProps } from \"solid-js\";\nimport type { ComponentProps } from \"solid-js\";\nimport { clsx } from \"~/utils\";\n\nexport function PopoverDescription(props: ComponentProps<\"div\">) {\n const [local, rest] = splitProps(props, [\"class\"]);\n return (\n <div\n data-slot=\"popover-description\"\n class={clsx(\"text-muted-foreground\", local.class)}\n {...rest}\n />\n );\n}\n"],"mappings":";;;;;AAIA,SAAgBG,EAAmBC,GAA8B;CAC/D,IAAM,CAACC,GAAOC,KAAQN,EAAWI,GAAO,CAAC,OAAO,CAAC;CACjD,cAAA;EAAA,IAAAG,IAAAC,EAAA;EAIY,OAJZC,EAAAF,GAAAG,EAAA,EAAA,IAAA,QAAA;GAAA,OAGWR,EAAK,yBAAyBG,EAAMM,KAAK;EAAC,EAAA,GAC7CL,CAAI,GAAA,IAAA,EAAA,GAAAC;CAAA,EAAA,CAAA;AAGd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PopoverDescription } from './PopoverDescription';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { clsx as e } from "../../../utils/clsx.js";
|
|
2
|
+
import { mergeProps as t, spread as n, template as r } from "solid-js/web";
|
|
3
|
+
import { splitProps as i } from "solid-js";
|
|
4
|
+
//#region src/components/popover/PopoverHeader/PopoverHeader.tsx
|
|
5
|
+
var a = /*#__PURE__*/ r("<div data-slot=popover-header>");
|
|
6
|
+
function o(r) {
|
|
7
|
+
let [o, s] = i(r, ["class"]);
|
|
8
|
+
return (() => {
|
|
9
|
+
var r = a();
|
|
10
|
+
return n(r, t({ get class() {
|
|
11
|
+
return e("flex flex-col gap-0.5 text-sm", o.class);
|
|
12
|
+
} }, s), !1, !1), r;
|
|
13
|
+
})();
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { o as PopoverHeader };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=PopoverHeader.js.map
|