@webiny/admin-ui 6.4.11 → 6.6.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Accordion/Accordion.d.ts +7 -6
- package/Accordion/components/AccordionContent.js +4 -1
- package/Accordion/components/AccordionContent.js.map +1 -1
- package/Accordion/components/AccordionItem.d.ts +8 -6
- package/Accordion/components/AccordionItem.js.map +1 -1
- package/Accordion/components/AccordionItemAction.d.ts +7 -6
- package/Accordion/components/AccordionItemDragHandle.d.ts +2 -1
- package/Accordion/components/AccordionItemDragHandle.js +2 -1
- package/Accordion/components/AccordionItemDragHandle.js.map +1 -1
- package/Accordion/components/AccordionItemIcon.d.ts +7 -6
- package/Accordion/components/AccordionItemSeparator.d.ts +7 -6
- package/Accordion/components/AccordionTrigger.js +4 -2
- package/Accordion/components/AccordionTrigger.js.map +1 -1
- package/Alert/Alert.d.ts +21 -19
- package/AutoComplete/AutoComplete.d.ts +7 -6
- package/AutoComplete/primitives/AutoCompletePrimitive.d.ts +7 -6
- package/Avatar/Avatar.d.ts +9 -8
- package/Avatar/components/AvatarFallback.d.ts +7 -6
- package/Avatar/components/AvatarImage.d.ts +7 -6
- package/BetaBadge/BetaBadge.d.ts +6 -0
- package/BetaBadge/BetaBadge.js +7 -0
- package/BetaBadge/BetaBadge.js.map +1 -0
- package/Breadcrumbs/Breadcrumbs.d.ts +54 -0
- package/Breadcrumbs/Breadcrumbs.js +66 -0
- package/Breadcrumbs/Breadcrumbs.js.map +1 -0
- package/Breadcrumbs/Breadcrumbs.stories.d.ts +9 -0
- package/Breadcrumbs/Breadcrumbs.stories.js +71 -0
- package/Breadcrumbs/Breadcrumbs.stories.js.map +1 -0
- package/Breadcrumbs/index.d.ts +1 -0
- package/Breadcrumbs/index.js +1 -0
- package/Button/Button.d.ts +10 -9
- package/Button/CopyButton.d.ts +7 -6
- package/Button/IconButton.d.ts +10 -9
- package/Calendar/Calendar.d.ts +7 -6
- package/Calendar/calendarClassNames.js +1 -1
- package/Calendar/calendarClassNames.js.map +1 -1
- package/Card/Card.d.ts +8 -22
- package/Card/components/CancelAction.d.ts +8 -6
- package/Card/components/CardContent.d.ts +6 -6
- package/Card/components/CardTitle.d.ts +2 -2
- package/Card/components/ConfirmAction.d.ts +8 -6
- package/Card/components/Icon.d.ts +7 -6
- package/Checkbox/Checkbox.d.ts +7 -6
- package/Checkbox/primitives/CheckboxPrimitive.d.ts +17 -12
- package/CheckboxGroup/CheckboxGroup.d.ts +7 -6
- package/CheckboxGroup/primitives/CheckboxGroupPrimitive.d.ts +20 -12
- package/CodeEditor/CodeEditor.d.ts +7 -6
- package/CodeEditor/CodeEditorPrimitive.d.ts +7 -6
- package/CodeEditor/CodeEditorPrimitive.js +3 -1
- package/CodeEditor/CodeEditorPrimitive.js.map +1 -1
- package/ColorPicker/ColorPicker.d.ts +7 -6
- package/ColorPicker/primitives/ColorPickerPrimitive.d.ts +7 -6
- package/Command/Command.d.ts +10 -8
- package/DataList/DataListModal.d.ts +6 -3
- package/DataTable/DataTable.d.ts +23 -12
- package/DataTable/DataTable.js +12 -4
- package/DataTable/DataTable.js.map +1 -1
- package/DataTable/components/ColumnsVisibility.d.ts +5 -4
- package/DataTable/components/ColumnsVisibility.js +6 -3
- package/DataTable/components/ColumnsVisibility.js.map +1 -1
- package/DatePicker/DatePicker.d.ts +7 -6
- package/DatePicker/primitives/DatePickerPrimitive.d.ts +7 -6
- package/DatePicker/primitives/DateTimePicker.d.ts +1 -1
- package/DatePicker/primitives/DateTimePicker.js +15 -3
- package/DatePicker/primitives/DateTimePicker.js.map +1 -1
- package/DatePicker/primitives/components/DatePickerTrigger.js +1 -1
- package/DatePicker/primitives/components/DatePickerTrigger.js.map +1 -1
- package/DatePicker/utils/types.d.ts +2 -0
- package/Dialog/Dialog.d.ts +8 -22
- package/Dialog/components/CancelAction.d.ts +8 -6
- package/Dialog/components/ConfirmAction.d.ts +8 -6
- package/Dialog/components/DialogContent.d.ts +1 -1
- package/Dialog/components/DialogFooter.d.ts +1 -1
- package/Dialog/components/DialogTitle.d.ts +1 -1
- package/Dialog/components/Icon.d.ts +7 -6
- package/Drawer/Drawer.d.ts +8 -22
- package/Drawer/Drawer.stories.js +1 -0
- package/Drawer/Drawer.stories.js.map +1 -1
- package/Drawer/components/CancelButton.d.ts +8 -6
- package/Drawer/components/ConfirmButton.d.ts +8 -6
- package/Drawer/components/DrawerContent.d.ts +1 -1
- package/Drawer/components/Icon.d.ts +7 -6
- package/DropdownMenu/components/DropdownMenuItem.d.ts +3 -2
- package/DropdownMenu/components/DropdownMenuItem.js +9 -2
- package/DropdownMenu/components/DropdownMenuItem.js.map +1 -1
- package/DropdownMenu/components/DropdownMenuLink.d.ts +9 -8
- package/DropdownMenu/components/DropdownMenuSeparator.d.ts +7 -6
- package/EditableTitle/EditableTitle.d.ts +7 -6
- package/EmptyState/EmptyState.d.ts +43 -0
- package/EmptyState/EmptyState.js +93 -0
- package/EmptyState/EmptyState.js.map +1 -0
- package/EmptyState/EmptyState.stories.d.ts +13 -0
- package/EmptyState/EmptyState.stories.js +136 -0
- package/EmptyState/EmptyState.stories.js.map +1 -0
- package/EmptyState/illustrations/ContentIllustration.d.ts +2 -0
- package/EmptyState/illustrations/ContentIllustration.js +100 -0
- package/EmptyState/illustrations/ContentIllustration.js.map +1 -0
- package/EmptyState/illustrations/LayoutIllustration.d.ts +2 -0
- package/EmptyState/illustrations/LayoutIllustration.js +93 -0
- package/EmptyState/illustrations/LayoutIllustration.js.map +1 -0
- package/EmptyState/illustrations/ListingIllustration.d.ts +2 -0
- package/EmptyState/illustrations/ListingIllustration.js +92 -0
- package/EmptyState/illustrations/ListingIllustration.js.map +1 -0
- package/EmptyState/illustrations/SelectIllustration.d.ts +2 -0
- package/EmptyState/illustrations/SelectIllustration.js +100 -0
- package/EmptyState/illustrations/SelectIllustration.js.map +1 -0
- package/EmptyState/illustrations/TableIllustration.d.ts +2 -0
- package/EmptyState/illustrations/TableIllustration.js +233 -0
- package/EmptyState/illustrations/TableIllustration.js.map +1 -0
- package/EmptyState/illustrations/UploadIllustration.d.ts +2 -0
- package/EmptyState/illustrations/UploadIllustration.js +77 -0
- package/EmptyState/illustrations/UploadIllustration.js.map +1 -0
- package/EmptyState/illustrations/index.d.ts +6 -0
- package/EmptyState/illustrations/index.js +6 -0
- package/EmptyState/index.d.ts +1 -0
- package/EmptyState/index.js +1 -0
- package/FilePicker/FilePicker.d.ts +19 -18
- package/FilePicker/FilePicker.stories.d.ts +0 -6
- package/FilePicker/FilePicker.stories.js +1 -24
- package/FilePicker/FilePicker.stories.js.map +1 -1
- package/FilePicker/primitives/FilePickerPrimitive.d.ts +20 -19
- package/FilePicker/primitives/components/Trigger.d.ts +1 -1
- package/FilePicker/primitives/components/previews/ImagePreview/ImagePreview.d.ts +19 -7
- package/FilePicker/primitives/components/previews/ImagePreview/ImagePreview.js +15 -6
- package/FilePicker/primitives/components/previews/ImagePreview/ImagePreview.js.map +1 -1
- package/FilePicker/primitives/components/previews/ItemActions.js +1 -1
- package/FilePicker/primitives/components/previews/ItemActions.js.map +1 -1
- package/FilePicker/primitives/components/previews/ItemDescription.js +1 -1
- package/FilePicker/primitives/components/previews/ItemDescription.js.map +1 -1
- package/FilePicker/primitives/components/previews/RichItemPreview/RichItemPreview.d.ts +12 -6
- package/FilePicker/primitives/components/previews/RichItemPreview/RichItemPreview.js +13 -52
- package/FilePicker/primitives/components/previews/RichItemPreview/RichItemPreview.js.map +1 -1
- package/FilePicker/primitives/components/previews/RichItemPreview/RichItemThumbnail.d.ts +8 -4
- package/FilePicker/primitives/components/previews/RichItemPreview/RichItemThumbnail.js +66 -8
- package/FilePicker/primitives/components/previews/RichItemPreview/RichItemThumbnail.js.map +1 -1
- package/FilePicker/primitives/components/previews/TextOnlyPreview/TextOnlyPreview.d.ts +7 -6
- package/FilePicker/primitives/components/previews/index.d.ts +0 -1
- package/FilePicker/primitives/components/previews/index.js +0 -1
- package/FilePicker/primitives/components/previews/variants.d.ts +1 -1
- package/FillViewport/FillViewport.d.ts +21 -18
- package/FormComponent/Description.d.ts +7 -6
- package/FormComponent/ErrorMessage.d.ts +7 -6
- package/FormComponent/Label.d.ts +7 -6
- package/FormComponent/Note.d.ts +7 -6
- package/Grid/Grid.d.ts +24 -22
- package/HeaderBar/HeaderBar.d.ts +7 -6
- package/Heading/Heading.d.ts +8 -7
- package/Icon/Icon.d.ts +9 -8
- package/IconPicker/IconPicker.d.ts +7 -6
- package/IconPicker/primitives/IconPickerPrimitive.d.ts +1 -1
- package/IconPicker/primitives/components/IconPickerTrigger.d.ts +1 -1
- package/ImageEditor/AspectRatioPreview.d.ts +16 -0
- package/ImageEditor/AspectRatioPreview.js +26 -0
- package/ImageEditor/AspectRatioPreview.js.map +1 -0
- package/ImageEditor/CropHotspotEditor.d.ts +22 -0
- package/ImageEditor/CropHotspotEditor.js +402 -0
- package/ImageEditor/CropHotspotEditor.js.map +1 -0
- package/ImageEditor/ImageEditor.d.ts +18 -0
- package/ImageEditor/ImageEditor.js +151 -0
- package/ImageEditor/ImageEditor.js.map +1 -0
- package/ImageEditor/ImageEditor.stories.d.ts +6 -0
- package/ImageEditor/ImageEditor.stories.js +42 -0
- package/ImageEditor/ImageEditor.stories.js.map +1 -0
- package/ImageEditor/MetaFields.d.ts +12 -0
- package/ImageEditor/MetaFields.js +20 -0
- package/ImageEditor/MetaFields.js.map +1 -0
- package/ImageEditor/SectionLabel.d.ts +8 -0
- package/ImageEditor/SectionLabel.js +7 -0
- package/ImageEditor/SectionLabel.js.map +1 -0
- package/ImageEditor/geometry.d.ts +46 -0
- package/ImageEditor/geometry.js +126 -0
- package/ImageEditor/geometry.js.map +1 -0
- package/ImageEditor/index.d.ts +3 -0
- package/ImageEditor/index.js +3 -0
- package/ImageEditor/types.d.ts +52 -0
- package/ImageEditor/types.js +35 -0
- package/ImageEditor/types.js.map +1 -0
- package/Input/Input.d.ts +7 -6
- package/Input/InputPrimitive.d.ts +9 -8
- package/Label/Label.d.ts +8 -7
- package/Label/components/LabelValue.d.ts +1 -1
- package/Link/Link.d.ts +3 -3
- package/Link/Link.js +1 -1
- package/Link/Link.js.map +1 -1
- package/List/List.d.ts +8 -7
- package/List/components/ListItem.d.ts +7 -6
- package/List/components/ListItemAction.d.ts +7 -6
- package/List/components/ListItemHandle.d.ts +7 -6
- package/List/components/ListItemIcon.d.ts +7 -6
- package/List/components/ListItemSeparator.d.ts +7 -6
- package/Loader/Loader.d.ts +9 -8
- package/Loader/OverlayLoader.d.ts +7 -6
- package/Markdown/Markdown.d.ts +47 -0
- package/Markdown/Markdown.js +17 -0
- package/Markdown/Markdown.js.map +1 -0
- package/Markdown/index.d.ts +1 -0
- package/Markdown/index.js +1 -0
- package/MultiAutoComplete/MultiAutoComplete.d.ts +7 -6
- package/MultiAutoComplete/primitives/MultiAutoCompletePrimitive.d.ts +7 -6
- package/MultiAutoComplete/primitives/presenters/MultiAutoCompletePresenterWithFreeInput.d.ts +3 -3
- package/MultiAutoComplete/primitives/useMultiAutoComplete.d.ts +3 -3
- package/MultiFilePicker/MultiFilePicker.d.ts +19 -18
- package/MultiFilePicker/primitives/MultiFilePickerPrimitive.d.ts +19 -18
- package/MultiSelect/MultiSelect.d.ts +7 -6
- package/MultiSelect/primitives/MultiSelectPrimitive.d.ts +10 -6
- package/MultiSelect/primitives/MultiSelectPrimitive.js +1 -1
- package/MultiSelect/primitives/MultiSelectPrimitive.js.map +1 -1
- package/Popover/Popover.d.ts +7 -6
- package/Popover/primitives/PopoverPrimitive.d.ts +7 -7
- package/ProgressBar/ProgressBar.d.ts +7 -6
- package/RadioGroup/RadioGroup.d.ts +7 -6
- package/RadioGroup/primitives/Radio.d.ts +7 -6
- package/RadioGroup/primitives/RadioGroupPrimitive.d.ts +5 -1
- package/RangeSlider/RangeSlider.d.ts +7 -6
- package/SegmentedControl/SegmentedControl.d.ts +8 -7
- package/SegmentedControl/SegmentedControlTabs.d.ts +5 -2
- package/SegmentedControl/primitives/SegmentedControlPrimitive.d.ts +1 -1
- package/Select/Select.d.ts +7 -6
- package/Select/primitives/components/SelectContent.js +1 -1
- package/Select/primitives/components/SelectContent.js.map +1 -1
- package/Select/primitives/components/SelectTrigger.d.ts +2 -2
- package/Separator/Separator.d.ts +9 -8
- package/Sidebar/Sidebar.d.ts +7 -6
- package/Sidebar/components/SidebarContent.js +1 -1
- package/Sidebar/components/SidebarContent.js.map +1 -1
- package/Sidebar/components/SidebarIcon.d.ts +7 -6
- package/Sidebar/components/SidebarProvider.d.ts +4 -4
- package/Sidebar/components/SidebarRoot.js +1 -1
- package/Sidebar/components/SidebarRoot.js.map +1 -1
- package/Sidebar/components/items/SidebarMenuGroup.d.ts +9 -8
- package/Sidebar/components/items/SidebarMenuItem.d.ts +11 -10
- package/Sidebar/components/items/SidebarMenuItemIcon.d.ts +7 -6
- package/Sidebar/components/items/SidebarMenuLink.d.ts +11 -10
- package/Sidebar/components/items/SidebarMenuProvider.d.ts +4 -4
- package/Sidebar/components/items/SidebarMenuRootItem.d.ts +9 -7
- package/Sidebar/components/items/SidebarMenuSubButton.js +5 -8
- package/Sidebar/components/items/SidebarMenuSubButton.js.map +1 -1
- package/Sidebar/components/items/SidebarMenuSubItem.js +3 -3
- package/Sidebar/components/items/SidebarMenuSubItem.js.map +1 -1
- package/Skeleton/Skeleton.d.ts +9 -7
- package/Skeleton/Skeleton.js +10 -4
- package/Skeleton/Skeleton.js.map +1 -1
- package/Skeleton/Skeleton.stories.d.ts +2 -0
- package/Skeleton/Skeleton.stories.js +28 -2
- package/Skeleton/Skeleton.stories.js.map +1 -1
- package/Slider/Slider.d.ts +7 -6
- package/SteppedProgress/SteppedProgress.d.ts +7 -6
- package/SteppedProgress/SteppedProgressItem.d.ts +7 -6
- package/Switch/Switch.d.ts +7 -6
- package/Switch/primitives/SwitchPrimitive.d.ts +10 -6
- package/Table/Table.d.ts +12 -10
- package/Table/components/Direction.d.ts +1 -1
- package/Tabs/Tabs.d.ts +8 -6
- package/Tabs/Tabs.js +5 -2
- package/Tabs/Tabs.js.map +1 -1
- package/Tabs/components/Content.d.ts +1 -1
- package/Tabs/components/List.d.ts +2 -2
- package/Tabs/components/Tab.d.ts +7 -6
- package/Tabs/components/Trigger.d.ts +3 -2
- package/Tabs/components/Trigger.js +8 -3
- package/Tabs/components/Trigger.js.map +1 -1
- package/Tag/Tag.d.ts +8 -7
- package/Tags/Tags.d.ts +7 -6
- package/Tags/primitives/TagsPrimitive.d.ts +7 -6
- package/Text/Text.d.ts +8 -7
- package/Textarea/Textarea.d.ts +7 -6
- package/Textarea/TextareaPrimitive.d.ts +9 -8
- package/Toast/Toast.d.ts +7 -6
- package/Toast/components/ToastActions.d.ts +7 -6
- package/Toast/components/ToastDescription.d.ts +7 -6
- package/Toast/components/ToastTitle.d.ts +7 -6
- package/Toast/useToast.stories.js.map +1 -1
- package/Toggle/Toggle.d.ts +7 -6
- package/Toggle/primitives/TogglePrimitive.d.ts +13 -9
- package/ToggleGroup/ToggleGroup.d.ts +7 -6
- package/ToggleGroup/primitives/ToggleGroupPrimitive.d.ts +13 -9
- package/Tooltip/Tooltip.d.ts +7 -6
- package/Tree/Tree.d.ts +7 -6
- package/Tree/components/Item.d.ts +7 -6
- package/Tree/components/ItemCollapseTrigger.d.ts +7 -6
- package/Tree/components/ItemContent.d.ts +8 -6
- package/Tree/components/ItemDragHandle.d.ts +7 -6
- package/Tree/components/ItemIcon.d.ts +7 -6
- package/Tree/components/ItemPlaceholder.d.ts +7 -6
- package/Tree/components/ItemSubIndentation.d.ts +7 -6
- package/Tree/useTree.js +2 -6
- package/Tree/useTree.js.map +1 -1
- package/Widget/Widget.d.ts +8 -22
- package/Widget/components/Icon.d.ts +7 -6
- package/Widget/components/WidgetAction.d.ts +8 -6
- package/Widget/components/WidgetContent.d.ts +5 -5
- package/exports/admin/ui.d.ts +2 -0
- package/exports/admin/ui.js +2 -0
- package/index.d.ts +5 -0
- package/index.js +5 -0
- package/package.json +29 -29
- package/theme.css +22 -1
- package/utils.js +52 -34
- package/utils.js.map +1 -1
- package/FilePicker/primitives/components/previews/RichItemPreview/FileType.d.ts +0 -9
- package/FilePicker/primitives/components/previews/RichItemPreview/FileType.js +0 -45
- package/FilePicker/primitives/components/previews/RichItemPreview/FileType.js.map +0 -1
- package/FilePicker/primitives/components/previews/RichItemPreview/Placeholder.d.ts +0 -8
- package/FilePicker/primitives/components/previews/RichItemPreview/Placeholder.js +0 -14
- package/FilePicker/primitives/components/previews/RichItemPreview/Placeholder.js.map +0 -1
- package/FilePicker/primitives/components/previews/RichItemPreview/Thumbnail.d.ts +0 -11
- package/FilePicker/primitives/components/previews/RichItemPreview/Thumbnail.js +0 -20
- package/FilePicker/primitives/components/previews/RichItemPreview/Thumbnail.js.map +0 -1
- package/FilePicker/primitives/components/previews/RichItemPreview/ThumbnailActions.d.ts +0 -15
- package/FilePicker/primitives/components/previews/RichItemPreview/ThumbnailActions.js +0 -46
- package/FilePicker/primitives/components/previews/RichItemPreview/ThumbnailActions.js.map +0 -1
- package/FilePicker/primitives/components/previews/TruncatedFileName.d.ts +0 -11
- package/FilePicker/primitives/components/previews/TruncatedFileName.js +0 -20
- package/FilePicker/primitives/components/previews/TruncatedFileName.js.map +0 -1
- package/FilePicker/primitives/components/previews/fileName.d.ts +0 -12
- package/FilePicker/primitives/components/previews/fileName.js +0 -26
- package/FilePicker/primitives/components/previews/fileName.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageEditor/ImageEditor.js","sources":["../../src/ImageEditor/ImageEditor.tsx"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { ReactComponent as ArrowDropDownIcon } from \"@webiny/icons/arrow_drop_down.svg\";\nimport { Dialog } from \"~/Dialog/index.js\";\nimport { Button } from \"~/Button/index.js\";\nimport { DropdownMenu } from \"~/DropdownMenu/index.js\";\nimport { CropHotspotEditor, FREE, inferAspectId } from \"./CropHotspotEditor.js\";\nimport { AspectRatioPreview } from \"./AspectRatioPreview.js\";\nimport { MetaFields } from \"./MetaFields.js\";\nimport { SectionLabel } from \"./SectionLabel.js\";\nimport {\n DEFAULT_ASPECT_RATIOS,\n DEFAULT_PREVIEW_RATIO_IDS,\n type ImageEditorAspectRatio,\n type ImageEditorCrop,\n type ImageEditorHotspot,\n type ImageEditorImage,\n type ImageEditorValue\n} from \"./types.js\";\n\nexport interface ImageEditorProps {\n open: boolean;\n onClose: () => void;\n /** The source image to edit. */\n image: ImageEditorImage;\n /** The current edit (crop/hotspot/alt/caption), if any. */\n value?: ImageEditorValue;\n /** Called with the new edit when the user saves. */\n onSave: (value: ImageEditorValue) => void;\n /** Preview ratios shown in the strip. Defaults to square / 4:3 / 16:9. */\n aspectRatios?: ImageEditorAspectRatio[];\n showAlt?: boolean;\n showCaption?: boolean;\n title?: React.ReactNode;\n}\n\nconst isFullCrop = (crop: ImageEditorCrop | undefined): boolean => {\n if (!crop) {\n return true;\n }\n return crop.top === 0 && crop.left === 0 && crop.bottom === 0 && crop.right === 0;\n};\n\nconst isCenteredHotspot = (hotspot: ImageEditorHotspot | undefined): boolean => {\n return !hotspot || (hotspot.x === 0.5 && hotspot.y === 0.5);\n};\n\nexport const ImageEditor = ({\n open,\n onClose,\n image,\n value,\n onSave,\n aspectRatios = DEFAULT_ASPECT_RATIOS,\n showAlt = true,\n showCaption = true,\n title = \"Edit image\"\n}: ImageEditorProps) => {\n const [crop, setCrop] = useState<ImageEditorCrop | undefined>(value?.crop);\n const [hotspot, setHotspot] = useState<ImageEditorHotspot | undefined>(value?.hotspot);\n const [alt, setAlt] = useState(value?.alt ?? \"\");\n const [caption, setCaption] = useState(value?.caption ?? \"\");\n // Selected crop shape. Inferred from the saved crop on open so the selector\n // reflects the shape the crop was made with (rather than always \"free\").\n const [aspectId, setAspectId] = useState<string>(FREE);\n const [selectedRatioIds, setSelectedRatioIds] = useState<string[]>(() => {\n const defaults = aspectRatios\n .filter(ar => DEFAULT_PREVIEW_RATIO_IDS.includes(ar.id))\n .map(ar => ar.id);\n return defaults.length > 0 ? defaults : aspectRatios.map(ar => ar.id);\n });\n\n const toggleRatio = (id: string) =>\n setSelectedRatioIds(prev =>\n prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]\n );\n\n const visibleRatios = aspectRatios.filter(ar => selectedRatioIds.includes(ar.id));\n\n // Fall back to the image's natural dimensions when the caller didn't provide\n // them (e.g. missing metadata). Without real dimensions the canvas and previews\n // would assume a square and distort the image / mis-map the crop coordinates.\n const [naturalSize, setNaturalSize] = useState<{ width: number; height: number } | null>(null);\n\n useEffect(() => {\n if (!open || !image.src || (image.width > 0 && image.height > 0)) {\n return;\n }\n if (typeof document === \"undefined\") {\n return;\n }\n const probe = document.createElement(\"img\");\n probe.onload = () => {\n return setNaturalSize({ width: probe.naturalWidth, height: probe.naturalHeight });\n };\n probe.src = image.src;\n return () => {\n probe.onload = null;\n };\n }, [open, image.src, image.width, image.height]);\n\n const effectiveImage: ImageEditorImage = {\n src: image.src,\n width: image.width > 0 ? image.width : (naturalSize?.width ?? 0),\n height: image.height > 0 ? image.height : (naturalSize?.height ?? 0)\n };\n\n // Re-seed local state whenever the dialog is (re)opened for a given value.\n useEffect(() => {\n if (open) {\n setCrop(value?.crop);\n setHotspot(value?.hotspot);\n setAlt(value?.alt ?? \"\");\n setCaption(value?.caption ?? \"\");\n }\n }, [open, value]);\n\n // Recover the crop shape from the saved crop on open (and once the intrinsic\n // dimensions resolve). Keyed on `value`, not the live `crop`, so it never snaps\n // the selector while the user is dragging a free-form crop.\n useEffect(() => {\n if (open) {\n setAspectId(inferAspectId(value?.crop, effectiveImage.width, effectiveImage.height));\n }\n }, [open, value, effectiveImage.width, effectiveImage.height]);\n\n const handleSave = () => {\n const next: ImageEditorValue = {};\n if (!isFullCrop(crop)) {\n next.crop = crop;\n }\n if (!isCenteredHotspot(hotspot)) {\n next.hotspot = hotspot;\n }\n if (showAlt && alt.trim()) {\n next.alt = alt.trim();\n }\n if (showCaption && caption.trim()) {\n next.caption = caption.trim();\n }\n onSave(next);\n onClose();\n };\n\n return (\n <Dialog\n open={open}\n onClose={onClose}\n title={title}\n size={\"lg\"}\n actions={\n <div className={\"flex w-full items-center justify-end gap-sm\"}>\n <Button variant={\"secondary\"} text={\"Cancel\"} onClick={onClose} />\n <Button variant={\"primary\"} text={\"Save\"} onClick={handleSave} />\n </div>\n }\n >\n <div className={\"flex flex-col gap-lg\"}>\n <CropHotspotEditor\n image={effectiveImage}\n crop={crop}\n hotspot={hotspot}\n aspectId={aspectId}\n onChangeAspect={setAspectId}\n onChangeCrop={setCrop}\n onChangeHotspot={setHotspot}\n />\n\n <div className={\"flex flex-col gap-sm\"}>\n <div className={\"flex items-center justify-between\"}>\n <SectionLabel>Preview</SectionLabel>\n <DropdownMenu\n trigger={\n <Button\n variant={\"secondary\"}\n text={`Preview at (${visibleRatios.length})`}\n icon={<ArrowDropDownIcon />}\n iconPosition={\"end\"}\n />\n }\n >\n {aspectRatios.map(ar => (\n <DropdownMenu.CheckboxItem\n key={ar.id}\n text={ar.label}\n checked={selectedRatioIds.includes(ar.id)}\n onCheckedChange={() => toggleRatio(ar.id)}\n onSelect={e => e.preventDefault()}\n />\n ))}\n </DropdownMenu>\n </div>\n {visibleRatios.length > 0 ? (\n <div className={\"flex flex-wrap items-start gap-md\"}>\n {visibleRatios.map(ar => (\n <AspectRatioPreview\n key={ar.id}\n src={effectiveImage.src}\n imageWidth={effectiveImage.width}\n imageHeight={effectiveImage.height}\n crop={crop}\n hotspot={hotspot}\n aspectRatio={ar}\n />\n ))}\n </div>\n ) : (\n <div className={\"text-sm text-neutral-strong\"}>\n Select at least one shape to preview.\n </div>\n )}\n </div>\n\n {showAlt || showCaption ? (\n <div className={\"flex flex-col gap-sm\"}>\n <SectionLabel>Details</SectionLabel>\n <MetaFields\n alt={alt}\n caption={caption}\n showAlt={showAlt}\n showCaption={showCaption}\n onChangeAlt={setAlt}\n onChangeCaption={setCaption}\n />\n </div>\n ) : null}\n </div>\n </Dialog>\n );\n};\n"],"names":["isFullCrop","crop","isCenteredHotspot","hotspot","ImageEditor","open","onClose","image","value","onSave","aspectRatios","DEFAULT_ASPECT_RATIOS","showAlt","showCaption","title","setCrop","useState","setHotspot","alt","setAlt","caption","setCaption","aspectId","setAspectId","FREE","selectedRatioIds","setSelectedRatioIds","defaults","ar","DEFAULT_PREVIEW_RATIO_IDS","toggleRatio","id","prev","x","visibleRatios","naturalSize","setNaturalSize","useEffect","document","probe","effectiveImage","inferAspectId","handleSave","next","Dialog","Button","CropHotspotEditor","SectionLabel","DropdownMenu","ArrowDropDownIcon","e","AspectRatioPreview","MetaFields"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import react, { useState } from "react";
|
|
2
|
+
import { Button } from "../Button/index.js";
|
|
3
|
+
import { ImageEditor } from "./index.js";
|
|
4
|
+
const meta = {
|
|
5
|
+
title: "Components/ImageEditor",
|
|
6
|
+
component: ImageEditor,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: "fullscreen"
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const ImageEditor_stories = meta;
|
|
12
|
+
const DemoImage = {
|
|
13
|
+
src: "https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?w=1600",
|
|
14
|
+
width: 1600,
|
|
15
|
+
height: 1067
|
|
16
|
+
};
|
|
17
|
+
const Demo = ()=>{
|
|
18
|
+
const [open, setOpen] = useState(false);
|
|
19
|
+
const [value, setValue] = useState(void 0);
|
|
20
|
+
return /*#__PURE__*/ react.createElement("div", {
|
|
21
|
+
className: "p-lg"
|
|
22
|
+
}, /*#__PURE__*/ react.createElement(Button, {
|
|
23
|
+
variant: "primary",
|
|
24
|
+
text: "Edit image",
|
|
25
|
+
onClick: ()=>setOpen(true)
|
|
26
|
+
}), /*#__PURE__*/ react.createElement("pre", {
|
|
27
|
+
className: "mt-md text-sm"
|
|
28
|
+
}, JSON.stringify(value, null, 2)), /*#__PURE__*/ react.createElement(ImageEditor, {
|
|
29
|
+
open: open,
|
|
30
|
+
onClose: ()=>setOpen(false),
|
|
31
|
+
image: DemoImage,
|
|
32
|
+
value: value,
|
|
33
|
+
onSave: setValue
|
|
34
|
+
}));
|
|
35
|
+
};
|
|
36
|
+
const Default = {
|
|
37
|
+
render: ()=>/*#__PURE__*/ react.createElement(Demo, null)
|
|
38
|
+
};
|
|
39
|
+
export default ImageEditor_stories;
|
|
40
|
+
export { Default };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=ImageEditor.stories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageEditor/ImageEditor.stories.js","sources":["../../src/ImageEditor/ImageEditor.stories.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport type { Meta, StoryObj } from \"@storybook/react\";\nimport { Button } from \"~/Button/index.js\";\nimport { ImageEditor, type ImageEditorValue } from \"./index.js\";\n\nconst meta: Meta<typeof ImageEditor> = {\n title: \"Components/ImageEditor\",\n component: ImageEditor,\n parameters: {\n layout: \"fullscreen\"\n }\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof ImageEditor>;\n\nconst DemoImage = {\n src: \"https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?w=1600\",\n width: 1600,\n height: 1067\n};\n\nconst Demo = () => {\n const [open, setOpen] = useState(false);\n const [value, setValue] = useState<ImageEditorValue | undefined>(undefined);\n\n return (\n <div className={\"p-lg\"}>\n <Button variant={\"primary\"} text={\"Edit image\"} onClick={() => setOpen(true)} />\n <pre className={\"mt-md text-sm\"}>{JSON.stringify(value, null, 2)}</pre>\n <ImageEditor\n open={open}\n onClose={() => setOpen(false)}\n image={DemoImage}\n value={value}\n onSave={setValue}\n />\n </div>\n );\n};\n\nexport const Default: Story = {\n render: () => <Demo />\n};\n"],"names":["meta","ImageEditor","DemoImage","Demo","open","setOpen","useState","value","setValue","undefined","Button","JSON","Default"],"mappings":";;;AAKA,MAAMA,OAAiC;IACnC,OAAO;IACP,WAAWC;IACX,YAAY;QACR,QAAQ;IACZ;AACJ;AAEA,4BAAeD;AAIf,MAAME,YAAY;IACd,KAAK;IACL,OAAO;IACP,QAAQ;AACZ;AAEA,MAAMC,OAAO;IACT,MAAM,CAACC,MAAMC,QAAQ,GAAGC,SAAS;IACjC,MAAM,CAACC,OAAOC,SAAS,GAAGF,SAAuCG;IAEjE,OAAO,WAAP,GACI,oBAAC;QAAI,WAAW;qBACZ,oBAACC,QAAMA;QAAC,SAAS;QAAW,MAAM;QAAc,SAAS,IAAML,QAAQ;sBACvE,oBAAC;QAAI,WAAW;OAAkBM,KAAK,SAAS,CAACJ,OAAO,MAAM,mBAC9D,oBAACN,aAAWA;QACR,MAAMG;QACN,SAAS,IAAMC,QAAQ;QACvB,OAAOH;QACP,OAAOK;QACP,QAAQC;;AAIxB;AAEO,MAAMI,UAAiB;IAC1B,QAAQ,kBAAM,oBAACT,MAAIA;AACvB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface MetaFieldsProps {
|
|
3
|
+
alt: string;
|
|
4
|
+
caption: string;
|
|
5
|
+
showAlt: boolean;
|
|
6
|
+
showCaption: boolean;
|
|
7
|
+
onChangeAlt: (value: string) => void;
|
|
8
|
+
onChangeCaption: (value: string) => void;
|
|
9
|
+
}
|
|
10
|
+
/** Alt text + optional caption, captured alongside the crop/hotspot. */
|
|
11
|
+
export declare const MetaFields: ({ alt, caption, showAlt, showCaption, onChangeAlt, onChangeCaption }: MetaFieldsProps) => React.JSX.Element | null;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import react from "react";
|
|
2
|
+
import { Input } from "../Input/index.js";
|
|
3
|
+
const MetaFields = ({ alt, caption, showAlt, showCaption, onChangeAlt, onChangeCaption })=>{
|
|
4
|
+
if (!showAlt && !showCaption) return null;
|
|
5
|
+
return /*#__PURE__*/ react.createElement("div", {
|
|
6
|
+
className: "flex flex-col gap-md"
|
|
7
|
+
}, showAlt ? /*#__PURE__*/ react.createElement(Input, {
|
|
8
|
+
label: "Alternative text",
|
|
9
|
+
description: "Describe the image for screen readers and search engines.",
|
|
10
|
+
value: alt,
|
|
11
|
+
onChange: onChangeAlt
|
|
12
|
+
}) : null, showCaption ? /*#__PURE__*/ react.createElement(Input, {
|
|
13
|
+
label: "Caption",
|
|
14
|
+
value: caption,
|
|
15
|
+
onChange: onChangeCaption
|
|
16
|
+
}) : null);
|
|
17
|
+
};
|
|
18
|
+
export { MetaFields };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=MetaFields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageEditor/MetaFields.js","sources":["../../src/ImageEditor/MetaFields.tsx"],"sourcesContent":["import React from \"react\";\nimport { Input } from \"~/Input/index.js\";\n\ninterface MetaFieldsProps {\n alt: string;\n caption: string;\n showAlt: boolean;\n showCaption: boolean;\n onChangeAlt: (value: string) => void;\n onChangeCaption: (value: string) => void;\n}\n\n/** Alt text + optional caption, captured alongside the crop/hotspot. */\nexport const MetaFields = ({\n alt,\n caption,\n showAlt,\n showCaption,\n onChangeAlt,\n onChangeCaption\n}: MetaFieldsProps) => {\n if (!showAlt && !showCaption) {\n return null;\n }\n\n return (\n <div className={\"flex flex-col gap-md\"}>\n {showAlt ? (\n <Input\n label={\"Alternative text\"}\n description={\"Describe the image for screen readers and search engines.\"}\n value={alt}\n onChange={onChangeAlt}\n />\n ) : null}\n {showCaption ? (\n <Input label={\"Caption\"} value={caption} onChange={onChangeCaption} />\n ) : null}\n </div>\n );\n};\n"],"names":["MetaFields","alt","caption","showAlt","showCaption","onChangeAlt","onChangeCaption","Input"],"mappings":";;AAaO,MAAMA,aAAa,CAAC,EACvBC,GAAG,EACHC,OAAO,EACPC,OAAO,EACPC,WAAW,EACXC,WAAW,EACXC,eAAe,EACD;IACd,IAAI,CAACH,WAAW,CAACC,aACb,OAAO;IAGX,OAAO,WAAP,GACI,oBAAC;QAAI,WAAW;OACXD,UAAU,WAAVA,GACG,oBAACI,OAAKA;QACF,OAAO;QACP,aAAa;QACb,OAAON;QACP,UAAUI;SAEd,MACHD,cAAc,WAAdA,GACG,oBAACG,OAAKA;QAAC,OAAO;QAAW,OAAOL;QAAS,UAAUI;SACnD;AAGhB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Consistent section heading for the image editor. Uses the primary (darkest)
|
|
4
|
+
* text token so it reads as a heading, distinct from the muted body/caption text.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SectionLabel: ({ children }: {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}) => React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageEditor/SectionLabel.js","sources":["../../src/ImageEditor/SectionLabel.tsx"],"sourcesContent":["import React from \"react\";\n\n/**\n * Consistent section heading for the image editor. Uses the primary (darkest)\n * text token so it reads as a heading, distinct from the muted body/caption text.\n */\nexport const SectionLabel = ({ children }: { children: React.ReactNode }) => {\n return <div className={\"text-sm font-semibold text-neutral-primary\"}>{children}</div>;\n};\n"],"names":["SectionLabel","children"],"mappings":";AAMO,MAAMA,eAAe,CAAC,EAAEC,QAAQ,EAAiC,GAC7D,WAAP,GAAO,oBAAC;QAAI,WAAW;OAA+CA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preview geometry for the image editor.
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: this is a deliberate, minimal mirror of the canonical geometry core
|
|
5
|
+
* in `@webiny/website-builder-sdk` (`src/image/geometry.ts`). The SDK copy is the
|
|
6
|
+
* source of truth used for live frontend rendering; this copy exists only so the
|
|
7
|
+
* design-system layer stays free of an SDK dependency. Keep the two in sync — the
|
|
8
|
+
* whole point is that the editor preview matches what the site renders.
|
|
9
|
+
*/
|
|
10
|
+
import type { ImageEditorCrop, ImageEditorHotspot } from "./types.js";
|
|
11
|
+
export interface PreviewStyles {
|
|
12
|
+
container: React.CSSProperties;
|
|
13
|
+
image: React.CSSProperties;
|
|
14
|
+
}
|
|
15
|
+
interface Rect {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The largest rectangle of `ratio` (w/h) that fits inside the crop, centered on
|
|
23
|
+
* the hotspot and clamped to the crop bounds.
|
|
24
|
+
*/
|
|
25
|
+
export declare const getVisibleRect: (imageWidth: number, imageHeight: number, crop: ImageEditorCrop | undefined, hotspot: ImageEditorHotspot | undefined, ratio: number) => Rect;
|
|
26
|
+
/**
|
|
27
|
+
* CSS for an overflow-clipped container + absolutely positioned image that shows
|
|
28
|
+
* exactly the visible rect for a given aspect ratio.
|
|
29
|
+
*/
|
|
30
|
+
export declare const getPreviewStyles: (imageWidth: number, imageHeight: number, crop: ImageEditorCrop | undefined, hotspot: ImageEditorHotspot | undefined, ratio: number) => PreviewStyles;
|
|
31
|
+
export interface CroppedImageRenderStyles {
|
|
32
|
+
wrapper: React.CSSProperties;
|
|
33
|
+
image: React.CSSProperties;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Styles to render an already-cropped image inside a measured box, honoring the
|
|
37
|
+
* crop (and, for `cover`, the hotspot). Use when you know the box's pixel size:
|
|
38
|
+
* - `cover`: fills the box, cover-cropping the crop region toward the hotspot;
|
|
39
|
+
* - `contain`: fits the whole crop region inside the box (centered by the parent).
|
|
40
|
+
*/
|
|
41
|
+
export declare const getCroppedImageRenderStyles: (imageWidth: number, imageHeight: number, crop: ImageEditorCrop | undefined, hotspot: ImageEditorHotspot | undefined, opts: {
|
|
42
|
+
boxWidth: number;
|
|
43
|
+
boxHeight: number;
|
|
44
|
+
fit: "cover" | "contain";
|
|
45
|
+
}) => CroppedImageRenderStyles;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const clamp = (value, min = 0, max = 1)=>{
|
|
2
|
+
if (Number.isNaN(value)) return min;
|
|
3
|
+
return Math.min(max, Math.max(min, value));
|
|
4
|
+
};
|
|
5
|
+
const round = (n)=>Math.round(1000 * n) / 1000;
|
|
6
|
+
const getCropRect = (crop)=>{
|
|
7
|
+
const top = clamp(crop?.top ?? 0);
|
|
8
|
+
const left = clamp(crop?.left ?? 0);
|
|
9
|
+
const bottom = clamp(crop?.bottom ?? 0);
|
|
10
|
+
const right = clamp(crop?.right ?? 0);
|
|
11
|
+
return {
|
|
12
|
+
x: left,
|
|
13
|
+
y: top,
|
|
14
|
+
width: Math.max(0, 1 - left - right),
|
|
15
|
+
height: Math.max(0, 1 - top - bottom)
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
const getVisibleRect = (imageWidth, imageHeight, crop, hotspot, ratio)=>{
|
|
19
|
+
const cropRect = getCropRect(crop);
|
|
20
|
+
if (cropRect.width <= 0 || cropRect.height <= 0) return cropRect;
|
|
21
|
+
const iw = imageWidth > 0 ? imageWidth : 1;
|
|
22
|
+
const ih = imageHeight > 0 ? imageHeight : 1;
|
|
23
|
+
const targetAR = ratio > 0 ? ratio : 1;
|
|
24
|
+
const cropWpx = cropRect.width * iw;
|
|
25
|
+
const cropHpx = cropRect.height * ih;
|
|
26
|
+
const cropAR = cropWpx / cropHpx;
|
|
27
|
+
let finalWpx;
|
|
28
|
+
let finalHpx;
|
|
29
|
+
if (targetAR > cropAR) {
|
|
30
|
+
finalWpx = cropWpx;
|
|
31
|
+
finalHpx = cropWpx / targetAR;
|
|
32
|
+
} else {
|
|
33
|
+
finalHpx = cropHpx;
|
|
34
|
+
finalWpx = cropHpx * targetAR;
|
|
35
|
+
}
|
|
36
|
+
const finalW = finalWpx / iw;
|
|
37
|
+
const finalH = finalHpx / ih;
|
|
38
|
+
const hx = clamp(hotspot?.x ?? 0.5);
|
|
39
|
+
const hy = clamp(hotspot?.y ?? 0.5);
|
|
40
|
+
const maxX = cropRect.x + cropRect.width - finalW;
|
|
41
|
+
const maxY = cropRect.y + cropRect.height - finalH;
|
|
42
|
+
const x = clamp(hx - finalW / 2, cropRect.x, Math.max(cropRect.x, maxX));
|
|
43
|
+
const y = clamp(hy - finalH / 2, cropRect.y, Math.max(cropRect.y, maxY));
|
|
44
|
+
return {
|
|
45
|
+
x,
|
|
46
|
+
y,
|
|
47
|
+
width: finalW,
|
|
48
|
+
height: finalH
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const getPreviewStyles = (imageWidth, imageHeight, crop, hotspot, ratio)=>{
|
|
52
|
+
const rect = getVisibleRect(imageWidth, imageHeight, crop, hotspot, ratio);
|
|
53
|
+
const safeW = rect.width > 0 ? rect.width : 1;
|
|
54
|
+
const safeH = rect.height > 0 ? rect.height : 1;
|
|
55
|
+
return {
|
|
56
|
+
container: {
|
|
57
|
+
position: "relative",
|
|
58
|
+
width: "100%",
|
|
59
|
+
aspectRatio: `${round(ratio > 0 ? ratio : 1)}`,
|
|
60
|
+
overflow: "hidden"
|
|
61
|
+
},
|
|
62
|
+
image: {
|
|
63
|
+
position: "absolute",
|
|
64
|
+
width: `${round(100 / safeW)}%`,
|
|
65
|
+
height: `${round(100 / safeH)}%`,
|
|
66
|
+
left: `${round(100 * -(rect.x / safeW))}%`,
|
|
67
|
+
top: `${round(100 * -(rect.y / safeH))}%`,
|
|
68
|
+
maxWidth: "none",
|
|
69
|
+
objectFit: "cover",
|
|
70
|
+
objectPosition: `${round(100 * clamp(hotspot?.x ?? 0.5))}% ${round(100 * clamp(hotspot?.y ?? 0.5))}%`
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
const getCroppedImageRenderStyles = (imageWidth, imageHeight, crop, hotspot, opts)=>{
|
|
75
|
+
const imageStyle = (rect)=>{
|
|
76
|
+
const safeW = rect.width > 0 ? rect.width : 1;
|
|
77
|
+
const safeH = rect.height > 0 ? rect.height : 1;
|
|
78
|
+
return {
|
|
79
|
+
position: "absolute",
|
|
80
|
+
width: `${round(100 / safeW)}%`,
|
|
81
|
+
height: `${round(100 / safeH)}%`,
|
|
82
|
+
left: `${round(100 * -(rect.x / safeW))}%`,
|
|
83
|
+
top: `${round(100 * -(rect.y / safeH))}%`,
|
|
84
|
+
maxWidth: "none",
|
|
85
|
+
objectFit: "cover",
|
|
86
|
+
objectPosition: `${round(100 * clamp(hotspot?.x ?? 0.5))}% ${round(100 * clamp(hotspot?.y ?? 0.5))}%`
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
if ("cover" === opts.fit) {
|
|
90
|
+
const targetAspect = opts.boxHeight > 0 ? opts.boxWidth / opts.boxHeight : 1;
|
|
91
|
+
const rect = getVisibleRect(imageWidth, imageHeight, crop, hotspot, targetAspect);
|
|
92
|
+
return {
|
|
93
|
+
wrapper: {
|
|
94
|
+
position: "relative",
|
|
95
|
+
width: "100%",
|
|
96
|
+
height: "100%",
|
|
97
|
+
overflow: "hidden"
|
|
98
|
+
},
|
|
99
|
+
image: imageStyle(rect)
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const cropRect = getCropRect(crop);
|
|
103
|
+
const iw = imageWidth > 0 ? imageWidth : 1;
|
|
104
|
+
const ih = imageHeight > 0 ? imageHeight : 1;
|
|
105
|
+
const cropWpx = (cropRect.width > 0 ? cropRect.width : 1) * iw;
|
|
106
|
+
const cropHpx = (cropRect.height > 0 ? cropRect.height : 1) * ih;
|
|
107
|
+
const cropAspect = cropWpx / cropHpx;
|
|
108
|
+
let width = opts.boxWidth;
|
|
109
|
+
let height = opts.boxWidth / cropAspect;
|
|
110
|
+
if (height > opts.boxHeight) {
|
|
111
|
+
height = opts.boxHeight;
|
|
112
|
+
width = opts.boxHeight * cropAspect;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
wrapper: {
|
|
116
|
+
position: "relative",
|
|
117
|
+
width: `${round(width)}px`,
|
|
118
|
+
height: `${round(height)}px`,
|
|
119
|
+
overflow: "hidden"
|
|
120
|
+
},
|
|
121
|
+
image: imageStyle(cropRect)
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
export { getCroppedImageRenderStyles, getPreviewStyles, getVisibleRect };
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageEditor/geometry.js","sources":["../../src/ImageEditor/geometry.ts"],"sourcesContent":["/**\n * Preview geometry for the image editor.\n *\n * IMPORTANT: this is a deliberate, minimal mirror of the canonical geometry core\n * in `@webiny/website-builder-sdk` (`src/image/geometry.ts`). The SDK copy is the\n * source of truth used for live frontend rendering; this copy exists only so the\n * design-system layer stays free of an SDK dependency. Keep the two in sync — the\n * whole point is that the editor preview matches what the site renders.\n */\nimport type { ImageEditorCrop, ImageEditorHotspot } from \"./types.js\";\n\nexport interface PreviewStyles {\n container: React.CSSProperties;\n image: React.CSSProperties;\n}\n\nconst clamp = (value: number, min = 0, max = 1): number => {\n if (Number.isNaN(value)) {\n return min;\n }\n return Math.min(max, Math.max(min, value));\n};\n\nconst round = (n: number): number => Math.round(n * 1000) / 1000;\n\ninterface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nconst getCropRect = (crop?: ImageEditorCrop | null): Rect => {\n const top = clamp(crop?.top ?? 0);\n const left = clamp(crop?.left ?? 0);\n const bottom = clamp(crop?.bottom ?? 0);\n const right = clamp(crop?.right ?? 0);\n return {\n x: left,\n y: top,\n width: Math.max(0, 1 - left - right),\n height: Math.max(0, 1 - top - bottom)\n };\n};\n\n/**\n * The largest rectangle of `ratio` (w/h) that fits inside the crop, centered on\n * the hotspot and clamped to the crop bounds.\n */\nexport const getVisibleRect = (\n imageWidth: number,\n imageHeight: number,\n crop: ImageEditorCrop | undefined,\n hotspot: ImageEditorHotspot | undefined,\n ratio: number\n): Rect => {\n const cropRect = getCropRect(crop);\n if (cropRect.width <= 0 || cropRect.height <= 0) {\n return cropRect;\n }\n\n const iw = imageWidth > 0 ? imageWidth : 1;\n const ih = imageHeight > 0 ? imageHeight : 1;\n const targetAR = ratio > 0 ? ratio : 1;\n\n const cropWpx = cropRect.width * iw;\n const cropHpx = cropRect.height * ih;\n const cropAR = cropWpx / cropHpx;\n\n let finalWpx: number;\n let finalHpx: number;\n if (targetAR > cropAR) {\n finalWpx = cropWpx;\n finalHpx = cropWpx / targetAR;\n } else {\n finalHpx = cropHpx;\n finalWpx = cropHpx * targetAR;\n }\n\n const finalW = finalWpx / iw;\n const finalH = finalHpx / ih;\n\n const hx = clamp(hotspot?.x ?? 0.5);\n const hy = clamp(hotspot?.y ?? 0.5);\n const maxX = cropRect.x + cropRect.width - finalW;\n const maxY = cropRect.y + cropRect.height - finalH;\n const x = clamp(hx - finalW / 2, cropRect.x, Math.max(cropRect.x, maxX));\n const y = clamp(hy - finalH / 2, cropRect.y, Math.max(cropRect.y, maxY));\n\n return { x, y, width: finalW, height: finalH };\n};\n\n/**\n * CSS for an overflow-clipped container + absolutely positioned image that shows\n * exactly the visible rect for a given aspect ratio.\n */\nexport const getPreviewStyles = (\n imageWidth: number,\n imageHeight: number,\n crop: ImageEditorCrop | undefined,\n hotspot: ImageEditorHotspot | undefined,\n ratio: number\n): PreviewStyles => {\n const rect = getVisibleRect(imageWidth, imageHeight, crop, hotspot, ratio);\n const safeW = rect.width > 0 ? rect.width : 1;\n const safeH = rect.height > 0 ? rect.height : 1;\n\n return {\n container: {\n position: \"relative\",\n width: \"100%\",\n aspectRatio: `${round(ratio > 0 ? ratio : 1)}`,\n overflow: \"hidden\"\n },\n image: {\n position: \"absolute\",\n width: `${round(100 / safeW)}%`,\n height: `${round(100 / safeH)}%`,\n left: `${round(-(rect.x / safeW) * 100)}%`,\n top: `${round(-(rect.y / safeH) * 100)}%`,\n maxWidth: \"none\",\n // Safety net: when the intrinsic dimensions match the image, the box\n // already has the image's aspect ratio so `cover` is a no-op. If the\n // dimensions are wrong/missing, this crops toward the focal point\n // instead of hard-stretching the image.\n objectFit: \"cover\",\n objectPosition: `${round(clamp(hotspot?.x ?? 0.5) * 100)}% ${round(clamp(hotspot?.y ?? 0.5) * 100)}%`\n }\n };\n};\n\nexport interface CroppedImageRenderStyles {\n wrapper: React.CSSProperties;\n image: React.CSSProperties;\n}\n\n/**\n * Styles to render an already-cropped image inside a measured box, honoring the\n * crop (and, for `cover`, the hotspot). Use when you know the box's pixel size:\n * - `cover`: fills the box, cover-cropping the crop region toward the hotspot;\n * - `contain`: fits the whole crop region inside the box (centered by the parent).\n */\nexport const getCroppedImageRenderStyles = (\n imageWidth: number,\n imageHeight: number,\n crop: ImageEditorCrop | undefined,\n hotspot: ImageEditorHotspot | undefined,\n opts: { boxWidth: number; boxHeight: number; fit: \"cover\" | \"contain\" }\n): CroppedImageRenderStyles => {\n const imageStyle = (rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n }): React.CSSProperties => {\n const safeW = rect.width > 0 ? rect.width : 1;\n const safeH = rect.height > 0 ? rect.height : 1;\n return {\n position: \"absolute\",\n width: `${round(100 / safeW)}%`,\n height: `${round(100 / safeH)}%`,\n left: `${round(-(rect.x / safeW) * 100)}%`,\n top: `${round(-(rect.y / safeH) * 100)}%`,\n maxWidth: \"none\",\n // See getPreviewStyles: no-op when dimensions are correct, graceful\n // crop toward the focal point when they aren't (instead of stretching).\n objectFit: \"cover\",\n objectPosition: `${round(clamp(hotspot?.x ?? 0.5) * 100)}% ${round(clamp(hotspot?.y ?? 0.5) * 100)}%`\n };\n };\n\n if (opts.fit === \"cover\") {\n const targetAspect = opts.boxHeight > 0 ? opts.boxWidth / opts.boxHeight : 1;\n const rect = getVisibleRect(imageWidth, imageHeight, crop, hotspot, targetAspect);\n return {\n wrapper: { position: \"relative\", width: \"100%\", height: \"100%\", overflow: \"hidden\" },\n image: imageStyle(rect)\n };\n }\n\n // contain: fit the whole crop region within the box, preserving its aspect.\n const cropRect = getCropRect(crop);\n const iw = imageWidth > 0 ? imageWidth : 1;\n const ih = imageHeight > 0 ? imageHeight : 1;\n const cropWpx = (cropRect.width > 0 ? cropRect.width : 1) * iw;\n const cropHpx = (cropRect.height > 0 ? cropRect.height : 1) * ih;\n const cropAspect = cropWpx / cropHpx;\n\n let width = opts.boxWidth;\n let height = opts.boxWidth / cropAspect;\n if (height > opts.boxHeight) {\n height = opts.boxHeight;\n width = opts.boxHeight * cropAspect;\n }\n\n return {\n wrapper: {\n position: \"relative\",\n width: `${round(width)}px`,\n height: `${round(height)}px`,\n overflow: \"hidden\"\n },\n image: imageStyle(cropRect)\n };\n};\n"],"names":["clamp","value","min","max","Number","Math","round","n","getCropRect","crop","top","left","bottom","right","getVisibleRect","imageWidth","imageHeight","hotspot","ratio","cropRect","iw","ih","targetAR","cropWpx","cropHpx","cropAR","finalWpx","finalHpx","finalW","finalH","hx","hy","maxX","maxY","x","y","getPreviewStyles","rect","safeW","safeH","getCroppedImageRenderStyles","opts","imageStyle","targetAspect","cropAspect","width","height"],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic, self-contained types for the reusable image editor dialog.
|
|
3
|
+
*
|
|
4
|
+
* These are intentionally NOT imported from `@webiny/website-builder-sdk`:
|
|
5
|
+
* `@webiny/admin-ui` is the low-level design-system layer and must not depend on
|
|
6
|
+
* higher-level SDKs. The shapes are structurally identical to the SDK's
|
|
7
|
+
* `WebinyImageEdit`/`WebinyImageValue`, so consumers (File Manager, Website
|
|
8
|
+
* Builder) can pass values across the boundary without any mapping.
|
|
9
|
+
*/
|
|
10
|
+
/** Minimal information the editor needs about the source image. */
|
|
11
|
+
export interface ImageEditorImage {
|
|
12
|
+
src: string;
|
|
13
|
+
/** Intrinsic (original) pixel width. */
|
|
14
|
+
width: number;
|
|
15
|
+
/** Intrinsic (original) pixel height. */
|
|
16
|
+
height: number;
|
|
17
|
+
}
|
|
18
|
+
/** Crop stored as the fraction (0..1) cut off from each edge of the image. */
|
|
19
|
+
export interface ImageEditorCrop {
|
|
20
|
+
top: number;
|
|
21
|
+
left: number;
|
|
22
|
+
bottom: number;
|
|
23
|
+
right: number;
|
|
24
|
+
}
|
|
25
|
+
/** Focal region in normalized (0..1) coordinates of the original image. */
|
|
26
|
+
export interface ImageEditorHotspot {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
}
|
|
32
|
+
/** The complete non-destructive edit produced by the dialog. */
|
|
33
|
+
export interface ImageEditorValue {
|
|
34
|
+
crop?: ImageEditorCrop;
|
|
35
|
+
hotspot?: ImageEditorHotspot;
|
|
36
|
+
alt?: string;
|
|
37
|
+
caption?: string;
|
|
38
|
+
}
|
|
39
|
+
/** A single aspect ratio used both for the crop selector and the preview strip. */
|
|
40
|
+
export interface ImageEditorAspectRatio {
|
|
41
|
+
id: string;
|
|
42
|
+
label: string;
|
|
43
|
+
/** `width / height`. */
|
|
44
|
+
ratio: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The single source of truth for selectable aspect ratios, shared by the crop
|
|
48
|
+
* shape selector and the preview-shapes dropdown so their labels stay identical.
|
|
49
|
+
*/
|
|
50
|
+
export declare const DEFAULT_ASPECT_RATIOS: ImageEditorAspectRatio[];
|
|
51
|
+
/** Preview shapes selected by default (the originally specified square / 4:3 / 16:9). */
|
|
52
|
+
export declare const DEFAULT_PREVIEW_RATIO_IDS: string[];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const DEFAULT_ASPECT_RATIOS = [
|
|
2
|
+
{
|
|
3
|
+
id: "1:1",
|
|
4
|
+
label: "Square (1:1)",
|
|
5
|
+
ratio: 1
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
id: "4:3",
|
|
9
|
+
label: "Landscape (4:3)",
|
|
10
|
+
ratio: 4 / 3
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: "16:9",
|
|
14
|
+
label: "Widescreen (16:9)",
|
|
15
|
+
ratio: 16 / 9
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: "3:4",
|
|
19
|
+
label: "Portrait (3:4)",
|
|
20
|
+
ratio: 0.75
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "9:16",
|
|
24
|
+
label: "Tall (9:16)",
|
|
25
|
+
ratio: 9 / 16
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
const DEFAULT_PREVIEW_RATIO_IDS = [
|
|
29
|
+
"1:1",
|
|
30
|
+
"4:3",
|
|
31
|
+
"16:9"
|
|
32
|
+
];
|
|
33
|
+
export { DEFAULT_ASPECT_RATIOS, DEFAULT_PREVIEW_RATIO_IDS };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageEditor/types.js","sources":["../../src/ImageEditor/types.ts"],"sourcesContent":["/**\n * Generic, self-contained types for the reusable image editor dialog.\n *\n * These are intentionally NOT imported from `@webiny/website-builder-sdk`:\n * `@webiny/admin-ui` is the low-level design-system layer and must not depend on\n * higher-level SDKs. The shapes are structurally identical to the SDK's\n * `WebinyImageEdit`/`WebinyImageValue`, so consumers (File Manager, Website\n * Builder) can pass values across the boundary without any mapping.\n */\n\n/** Minimal information the editor needs about the source image. */\nexport interface ImageEditorImage {\n src: string;\n /** Intrinsic (original) pixel width. */\n width: number;\n /** Intrinsic (original) pixel height. */\n height: number;\n}\n\n/** Crop stored as the fraction (0..1) cut off from each edge of the image. */\nexport interface ImageEditorCrop {\n top: number;\n left: number;\n bottom: number;\n right: number;\n}\n\n/** Focal region in normalized (0..1) coordinates of the original image. */\nexport interface ImageEditorHotspot {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** The complete non-destructive edit produced by the dialog. */\nexport interface ImageEditorValue {\n crop?: ImageEditorCrop;\n hotspot?: ImageEditorHotspot;\n alt?: string;\n caption?: string;\n}\n\n/** A single aspect ratio used both for the crop selector and the preview strip. */\nexport interface ImageEditorAspectRatio {\n id: string;\n label: string;\n /** `width / height`. */\n ratio: number;\n}\n\n/**\n * The single source of truth for selectable aspect ratios, shared by the crop\n * shape selector and the preview-shapes dropdown so their labels stay identical.\n */\nexport const DEFAULT_ASPECT_RATIOS: ImageEditorAspectRatio[] = [\n { id: \"1:1\", label: \"Square (1:1)\", ratio: 1 },\n { id: \"4:3\", label: \"Landscape (4:3)\", ratio: 4 / 3 },\n { id: \"16:9\", label: \"Widescreen (16:9)\", ratio: 16 / 9 },\n { id: \"3:4\", label: \"Portrait (3:4)\", ratio: 3 / 4 },\n { id: \"9:16\", label: \"Tall (9:16)\", ratio: 9 / 16 }\n];\n\n/** Preview shapes selected by default (the originally specified square / 4:3 / 16:9). */\nexport const DEFAULT_PREVIEW_RATIO_IDS = [\"1:1\", \"4:3\", \"16:9\"];\n"],"names":["DEFAULT_ASPECT_RATIOS","DEFAULT_PREVIEW_RATIO_IDS"],"mappings":"AAuDO,MAAMA,wBAAkD;IAC3D;QAAE,IAAI;QAAO,OAAO;QAAgB,OAAO;IAAE;IAC7C;QAAE,IAAI;QAAO,OAAO;QAAmB,OAAO,IAAI;IAAE;IACpD;QAAE,IAAI;QAAQ,OAAO;QAAqB,OAAO,KAAK;IAAE;IACxD;QAAE,IAAI;QAAO,OAAO;QAAkB,OAAO;IAAM;IACnD;QAAE,IAAI;QAAQ,OAAO;QAAe,OAAO,IAAI;IAAG;CACrD;AAGM,MAAMC,4BAA4B;IAAC;IAAO;IAAO;CAAO"}
|
package/Input/Input.d.ts
CHANGED
|
@@ -2,21 +2,22 @@ import React from "react";
|
|
|
2
2
|
import { type InputPrimitiveProps } from "./InputPrimitive.js";
|
|
3
3
|
import { type FormComponentProps } from "../FormComponent/index.js";
|
|
4
4
|
type InputProps = InputPrimitiveProps & FormComponentProps;
|
|
5
|
-
declare const
|
|
6
|
-
|
|
5
|
+
declare const DecoratableInput: ({ label, description, hint, note, required, disabled, validation, validate, onBlur: originalOnBlur, ...props }: InputProps) => React.JSX.Element;
|
|
6
|
+
declare const Input: typeof DecoratableInput & {
|
|
7
|
+
original: typeof DecoratableInput;
|
|
7
8
|
originalName: string;
|
|
8
9
|
displayName: string;
|
|
9
10
|
} & {
|
|
10
|
-
original:
|
|
11
|
-
original:
|
|
11
|
+
original: typeof DecoratableInput & {
|
|
12
|
+
original: typeof DecoratableInput;
|
|
12
13
|
originalName: string;
|
|
13
14
|
displayName: string;
|
|
14
15
|
};
|
|
15
16
|
originalName: string;
|
|
16
17
|
displayName: string;
|
|
17
18
|
} & {
|
|
18
|
-
createDecorator: (decorator: import("@webiny/react-composition/types.js").ComponentDecorator<
|
|
19
|
-
original:
|
|
19
|
+
createDecorator: (decorator: import("@webiny/react-composition/types.js").ComponentDecorator<typeof DecoratableInput & {
|
|
20
|
+
original: typeof DecoratableInput;
|
|
20
21
|
originalName: string;
|
|
21
22
|
displayName: string;
|
|
22
23
|
}>) => (props: unknown) => React.JSX.Element;
|
|
@@ -14,8 +14,8 @@ declare const InputIcon: ({ icon, inputSize, className }: InputIconProps) => Rea
|
|
|
14
14
|
* where the `inputVariants` is used to style a div that wraps multiple elements (input, Tags, icons, etc.)
|
|
15
15
|
*/
|
|
16
16
|
declare const inputVariants: (props?: ({
|
|
17
|
-
size?: "
|
|
18
|
-
variant?: "
|
|
17
|
+
size?: "lg" | "md" | "xl" | null | undefined;
|
|
18
|
+
variant?: "ghost" | "ghost-negative" | "primary" | "secondary" | null | undefined;
|
|
19
19
|
invalid?: boolean | null | undefined;
|
|
20
20
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
21
21
|
type InputPrimitiveProps<TValue = any> = Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "onChange"> & VariantProps<typeof inputVariants> & {
|
|
@@ -56,21 +56,22 @@ type InputPrimitiveProps<TValue = any> = Omit<React.InputHTMLAttributes<HTMLInpu
|
|
|
56
56
|
*/
|
|
57
57
|
autoSelect?: boolean;
|
|
58
58
|
};
|
|
59
|
-
declare const
|
|
60
|
-
|
|
59
|
+
declare const DecoratableInputPrimitive: ({ autoSelect, className, disabled, endIcon, forwardEventOnChange, inputRef, invalid, maxLength, onChange: originalOnChange, onEnter, onEscape, onKeyDown: originalOnKeyDown, onFocus: originalOnFocus, size, startIcon, value, variant, ...props }: InputPrimitiveProps) => React.JSX.Element;
|
|
60
|
+
declare const InputPrimitive: typeof DecoratableInputPrimitive & {
|
|
61
|
+
original: typeof DecoratableInputPrimitive;
|
|
61
62
|
originalName: string;
|
|
62
63
|
displayName: string;
|
|
63
64
|
} & {
|
|
64
|
-
original:
|
|
65
|
-
original:
|
|
65
|
+
original: typeof DecoratableInputPrimitive & {
|
|
66
|
+
original: typeof DecoratableInputPrimitive;
|
|
66
67
|
originalName: string;
|
|
67
68
|
displayName: string;
|
|
68
69
|
};
|
|
69
70
|
originalName: string;
|
|
70
71
|
displayName: string;
|
|
71
72
|
} & {
|
|
72
|
-
createDecorator: (decorator: import("@webiny/react-composition/types").ComponentDecorator<
|
|
73
|
-
original:
|
|
73
|
+
createDecorator: (decorator: import("@webiny/react-composition/types").ComponentDecorator<typeof DecoratableInputPrimitive & {
|
|
74
|
+
original: typeof DecoratableInputPrimitive;
|
|
74
75
|
originalName: string;
|
|
75
76
|
displayName: string;
|
|
76
77
|
}>) => (props: unknown) => React.JSX.Element;
|
package/Label/Label.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { Label as LabelPrimitive } from "radix-ui";
|
|
3
3
|
import { type VariantProps } from "../utils.js";
|
|
4
4
|
declare const labelVariants: (props?: ({
|
|
5
|
-
weight?: "
|
|
5
|
+
weight?: "light" | "strong" | null | undefined;
|
|
6
6
|
disabled?: boolean | null | undefined;
|
|
7
7
|
invalid?: boolean | null | undefined;
|
|
8
8
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
@@ -14,21 +14,22 @@ interface LabelProps extends Omit<React.ComponentPropsWithoutRef<typeof LabelPri
|
|
|
14
14
|
required?: boolean;
|
|
15
15
|
disabled?: boolean;
|
|
16
16
|
}
|
|
17
|
-
declare const
|
|
18
|
-
|
|
17
|
+
declare const LabelBase: ({ className, disabled, description, hint, required, value, text, weight, invalid, ...props }: LabelProps) => React.JSX.Element | null;
|
|
18
|
+
declare const Label: typeof LabelBase & {
|
|
19
|
+
original: typeof LabelBase;
|
|
19
20
|
originalName: string;
|
|
20
21
|
displayName: string;
|
|
21
22
|
} & {
|
|
22
|
-
original:
|
|
23
|
-
original:
|
|
23
|
+
original: typeof LabelBase & {
|
|
24
|
+
original: typeof LabelBase;
|
|
24
25
|
originalName: string;
|
|
25
26
|
displayName: string;
|
|
26
27
|
};
|
|
27
28
|
originalName: string;
|
|
28
29
|
displayName: string;
|
|
29
30
|
} & {
|
|
30
|
-
createDecorator: (decorator: import("@webiny/react-composition/types.js").ComponentDecorator<
|
|
31
|
-
original:
|
|
31
|
+
createDecorator: (decorator: import("@webiny/react-composition/types.js").ComponentDecorator<typeof LabelBase & {
|
|
32
|
+
original: typeof LabelBase;
|
|
32
33
|
originalName: string;
|
|
33
34
|
displayName: string;
|
|
34
35
|
}>) => (props: unknown) => React.JSX.Element;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "../../utils.js";
|
|
3
3
|
declare const labelValueVariants: (props?: ({
|
|
4
|
-
weight?: "
|
|
4
|
+
weight?: "light" | "strong" | null | undefined;
|
|
5
5
|
disabled?: boolean | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
interface LabelValueProps extends VariantProps<typeof labelValueVariants> {
|
package/Link/Link.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { type VariantProps } from "../utils.js";
|
|
3
3
|
import { LinkComponentProps } from "./LinkComponent.js";
|
|
4
|
-
|
|
5
|
-
size?: "
|
|
6
|
-
variant?: "primary" | "
|
|
4
|
+
declare const linkVariants: (props?: ({
|
|
5
|
+
size?: "inherit" | "lg" | "md" | "sm" | "xl" | null | undefined;
|
|
6
|
+
variant?: "primary" | "primary-negative" | "secondary" | "secondary-negative" | null | undefined;
|
|
7
7
|
underline?: boolean | null | undefined;
|
|
8
8
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
9
9
|
export type LinkProps = LinkComponentProps & VariantProps<typeof linkVariants> & {
|
package/Link/Link.js
CHANGED