UNPKG

@amaui/ui-react

Version:
1,049 lines (1,027 loc) 41.8 kB
import _extends from "@babel/runtime/helpers/extends"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; const _excluded = ["tonal", "color", "image", "name", "type", "openDefault", "openedOptionDefault", "valueDefault", "value", "valueCopyDefault", "valueCopy", "onChange", "onChangeCopy", "onlyFilters", "filters", "meta", "filtersOption", "cropOption", "resizeOption", "qualityOption", "downloadOption", "resizeAspectRatio", "renderOption", "renderOptionClear", "renderSave", "renderCancel", "renderSlider", "renderDownload", "renderInput", "IconBrightness", "IconContrast", "IconSaturation", "IconFade", "IconInvert", "IconOldPhoto", "IconSave", "IconCancel", "IconClear", "IconCrop", "IconFilters", "IconResize", "IconQuality", "IconDownload", "ChipProps", "SliderProps", "TooltipProps", "ImageCropProps", "IconButtonProps", "className", "children"]; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } import React from 'react'; import { is, to, clamp, debounce, canvasCrop, download as downloadMethod, isEnvironment } from '@amaui/utils'; import { classNames, style as styleMethod, useAmauiTheme } from '@amaui/style-react'; import IconMaterialDone from '@amaui/icons-material-rounded-react/IconMaterialDoneW100'; import IconMaterialClose from '@amaui/icons-material-rounded-react/IconMaterialCloseW100'; import IconMaterialTune from '@amaui/icons-material-rounded-react/IconMaterialTuneW100'; import IconMaterialCrop from '@amaui/icons-material-rounded-react/IconMaterialCropW100'; import IconMaterialAspectRatio from '@amaui/icons-material-rounded-react/IconMaterialAspectRatioW100'; import IconMaterialHighQuality from '@amaui/icons-material-rounded-react/IconMaterialHighQualityW100'; import IconMaterialClearAll from '@amaui/icons-material-rounded-react/IconMaterialClearAllW100'; import IconMaterialDownload from '@amaui/icons-material-rounded-react/IconMaterialDownloadW100'; import IconMaterialCloud from '@amaui/icons-material-rounded-react/IconMaterialCloudW100'; import IconMaterialWaterDrop from '@amaui/icons-material-rounded-react/IconMaterialWaterDropW100'; import IconMaterialFlaky from '@amaui/icons-material-rounded-react/IconMaterialFlakyW100'; import IconMaterialWbSunny from '@amaui/icons-material-rounded-react/IconMaterialWbSunnyW100'; import IconMaterialTonality from '@amaui/icons-material-rounded-react/IconMaterialTonalityW100'; import IconMaterialNightlight from '@amaui/icons-material-rounded-react/IconMaterialNightlightW100'; import TypeElement from '../Type'; import SurfaceElement from '../Surface'; import TooltipElement from '../Tooltip'; import IconButtonElement from '../IconButton'; import ExpandElement from '../Expand'; import DividerElement from '../Divider'; import SliderElement from '../Slider'; import NumericTextFieldElement from '../NumericTextField'; import ImageCropElement from '../ImageCrop'; import ChipElement from '../Chip'; import LineElement from '../Line'; import { canvasBrightness, staticClassName, image as imageMethod, canvasContrast, canvasSaturation, canvasFade, canvasInvert, canvasOldPhoto } from '../utils'; const useStyle = styleMethod(theme => ({ root: {}, option: { width: '100%', padding: `${theme.methods.space.value(2, 'px')} ${theme.methods.space.value(3, 'px')}` }, options: { width: '100%', overflowX: 'auto', padding: `${theme.methods.space.value(2, 'px')} ${theme.methods.space.value(3, 'px')}` }, canvas: { width: '100%', height: 'auto', zIndex: '1' }, inputs: { width: '100%' }, divider: { '&.amaui-Divider-root': { margin: '0px' } }, imageWrapper: { position: 'relative', height: '400px', width: '100%', '&::before': { content: '""', position: 'absolute', inset: '0', width: '100%', height: '100%', background: 'currentColor', zIndex: '0', opacity: '0.94' } }, canvasWrapper: { position: 'relative', lineHeight: '0' }, image: { width: '100%', height: 'auto' }, imageCopy: { width: '100%', height: 'auto' }, imageCrop: { position: 'absolute', inset: '0', width: '100% !important', height: '100% !important' }, meta: { width: '100%', padding: `${theme.methods.space.value(1.5, 'px')} ${theme.methods.space.value(3, 'px')}` }, optionInput: { '& .amaui-TextField-input-wrapper': { padding: '0px', height: 'auto' }, '& .amaui-TextField-input': { textAlign: 'center' } }, filters: { width: '100%', overflowX: 'auto', '& > *': { flex: '0 0 auto' } }, action: { width: '100%', paddingTop: theme.methods.space.value(2, 'px') }, slider: { width: '100%' } }), { name: 'amaui-ImageEdit' }); const ImageEdit = /*#__PURE__*/React.forwardRef((props_, ref) => { const theme = useAmauiTheme(); const props = React.useMemo(() => _objectSpread(_objectSpread(_objectSpread({}, theme?.ui?.elements?.all?.props?.default), theme?.ui?.elements?.amauiImageEdit?.props?.default), props_), [props_]); const Line = React.useMemo(() => theme?.elements?.Line || LineElement, [theme]); const Type = React.useMemo(() => theme?.elements?.Type || TypeElement, [theme]); const Surface = React.useMemo(() => theme?.elements?.Surface || SurfaceElement, [theme]); const IconButton = React.useMemo(() => theme?.elements?.IconButton || IconButtonElement, [theme]); const Tooltip = React.useMemo(() => theme?.elements?.Tooltip || TooltipElement, [theme]); const Expand = React.useMemo(() => theme?.elements?.Expand || ExpandElement, [theme]); const Divider = React.useMemo(() => theme?.elements?.Divider || DividerElement, [theme]); const Slider = React.useMemo(() => theme?.elements?.Slider || SliderElement, [theme]); const NumericTextField = React.useMemo(() => theme?.elements?.NumericTextField || NumericTextFieldElement, [theme]); const ImageCrop = React.useMemo(() => theme?.elements?.ImageCrop || ImageCropElement, [theme]); const Chip = React.useMemo(() => theme?.elements?.Chip || ChipElement, [theme]); const { tonal = true, color = 'primary', image, name = 'amaui-image.jpg', type = 'image/jpeg', openDefault, openedOptionDefault, valueDefault, value: value_, valueCopyDefault, valueCopy: valueCopy_, onChange: onChange_, onChangeCopy: onChangeCopy_, onlyFilters, filters: filters_, meta = true, filtersOption = true, cropOption = true, resizeOption = true, qualityOption = true, downloadOption = true, resizeAspectRatio = true, renderOption, renderOptionClear, renderSave, renderCancel, renderSlider, renderDownload, renderInput, IconBrightness = IconMaterialWbSunny, IconContrast = IconMaterialFlaky, IconSaturation = IconMaterialWaterDrop, IconFade = IconMaterialCloud, IconInvert = IconMaterialTonality, IconOldPhoto = IconMaterialNightlight, IconSave = IconMaterialDone, IconCancel = IconMaterialClose, IconClear = IconMaterialClearAll, IconCrop = IconMaterialCrop, IconFilters = IconMaterialTune, IconResize = IconMaterialAspectRatio, IconQuality = IconMaterialHighQuality, IconDownload = IconMaterialDownload, ChipProps: ChipProps_, SliderProps: SliderProps_, TooltipProps: TooltipProps_, ImageCropProps: ImageCropProps_, IconButtonProps: IconButtonProps_, className, children } = props, other = _objectWithoutProperties(props, _excluded); const [init, setInit] = React.useState(false); const [value, setValue] = React.useState(valueDefault !== undefined ? valueDefault : value_); const [valueCopy, setValueCopy] = React.useState(valueCopyDefault !== undefined ? valueCopyDefault : valueCopy_); const [open, setOpen] = React.useState(openDefault); const [openedOption, setOpenedOption] = React.useState(openedOptionDefault); const [quality, setQuality] = React.useState(100); const [filterValues, setFilterValues] = React.useState({}); const [filterValuesCopy, setFilterValuesCopy] = React.useState({}); const [filter, setFilter] = React.useState(); const [resize, setResize] = React.useState(); const [selection, setSelection] = React.useState(); const [aspectRatio, setAspectRatio] = React.useState(); const [aspectRatioCustom, setAspectRatioCustom] = React.useState([1, 1]); const [size, setSize] = React.useState(''); const { classes } = useStyle(); const refs = { root: React.useRef(undefined), option: React.useRef(undefined), value: React.useRef(undefined), valueCopy: React.useRef(undefined), canvasMain: React.useRef(), open: React.useRef(), resizeAspectRatio: React.useRef(undefined), filterValues: React.useRef(undefined), filterValuesCopy: React.useRef(undefined) }; refs.value.current = value; refs.valueCopy.current = valueCopy; refs.open.current = open; refs.resizeAspectRatio.current = resizeAspectRatio; refs.filterValues.current = filterValues; refs.filterValuesCopy.current = filterValuesCopy; const updateSize = function () { let valueNew = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : refs.canvasMain.current; const uri = valueNew.toDataURL(type); // Update size setSize(to(to(uri, 'byte-size'), 'size-format')); }; React.useEffect(() => { const method = event => { if (['Escape'].includes(event.key) || ['s', 'S'].includes(event.key) && event.metaKey || ['f', 'F'].includes(event.key) && event.metaKey && event.shiftKey || ['c', 'C'].includes(event.key) && event.metaKey && event.shiftKey || ['d', 'D'].includes(event.key) && (event.metaKey || event.shiftKey) || ['r', 'R'].includes(event.key) && (event.metaKey || event.shiftKey) || ['q', 'Q'].includes(event.key) && event.metaKey && event.shiftKey) { event.preventDefault(); } switch (event.key) { case 's': case 'S': if (refs.open.current && event.metaKey) onSave(); return; case 'f': case 'F': if (event.metaKey && event.shiftKey) openOption('filters'); return; case 'c': case 'C': if (event.metaKey && event.shiftKey) openOption('crop'); return; case 'd': case 'D': if (event.metaKey && event.shiftKey) onDownload(); return; case 'r': case 'R': if (event.metaKey && !event.shiftKey) onReset(); if (event.metaKey && event.shiftKey) openOption('resize'); return; case 'q': case 'Q': if (event.metaKey && event.shiftKey) openOption('quality'); return; case 'Escape': if (refs.open.current) onCancel(); return; default: break; } }; if (!refs.value.current) { if (image instanceof HTMLCanvasElement) onChange(image);else if (is('string', image)) makeImage(image); } const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined; rootDocument.addEventListener('keydown', method); setInit(true); return () => { // Clean up rootDocument.removeEventListener('keydown', method); }; }, []); React.useEffect(() => { if (image instanceof HTMLCanvasElement) onChange(image);else if (is('string', image)) makeImage(image); }, [image]); React.useEffect(() => { const valueToUse = !open ? refs.value.current : refs.valueCopy.current; if (valueToUse) { refs.canvasMain.current.width = valueToUse.width; refs.canvasMain.current.height = valueToUse.height; refs.canvasMain.current?.getContext('2d').drawImage(valueToUse, 0, 0, valueToUse.width, valueToUse.height); updateSize(); } }, [value, valueCopy, open]); React.useEffect(() => { if (init) { if (value_ !== value) onChange(value_); } }, [value_]); React.useEffect(() => { if (init) { if (valueCopy_ !== valueCopy) onChangeCopy(valueCopy_); } }, [valueCopy_]); const applyAllFilters = canvas => { let valueCopy__ = refs.valueCopy.current; // Update filters Object.keys(refs.filterValuesCopy.current).forEach(item => { const filterValue_ = filters.find(item_ => item_.value === item); if (filterValue_) { const { method } = filterValue_; if (is('function', method) && refs.filterValuesCopy.current[item] !== undefined) valueCopy__ = method(refs.filterValuesCopy.current[item], canvas, valueCopy__); } }); }; const applyAllFiltersDebounced = React.useCallback(debounce(applyAllFilters, 140), []); React.useEffect(() => { applyAllFiltersDebounced(refs.canvasMain.current); }, [filterValuesCopy]); const makeImage = async function () { let valueNew = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : refs.value.current; const img = await imageMethod(valueNew); const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined; const canvas = rootDocument.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height); // Image onChange(canvas); // Image copy const copy = rootDocument.createElement('canvas'); copy.width = canvas.width; copy.height = canvas.height; copy.getContext('2d').drawImage(canvas, 0, 0, canvas.width, canvas.height); onChangeCopy(copy); }; const updateResize = debounce(async (width, height) => { const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined; // Update value copy const canvas = rootDocument.createElement('canvas'); if (width > 1 && height > 1) { canvas.width = width; canvas.height = height; canvas.getContext('2d').drawImage(refs.value.current, 0, 0, width, height); // Value copy onChangeCopy(canvas); // Update the canvas value refs.canvasMain.current.width = width; refs.canvasMain.current.height = height; refs.canvasMain.current.getContext('2d').drawImage(value, 0, 0, width, height); // Update size updateSize(); } }, 140); const onFilterSliderChange = (valueNew, valueFilter) => { setFilterValuesCopy(values_ => _objectSpread(_objectSpread({}, values_), {}, { [valueFilter]: valueNew })); }; const onChangeFilter = valueNew => { // If moving to another filter or closing current one // clean up previous one filter for mainCanvas if (filter === valueNew) setFilter('');else setFilter(valueNew); }; const onChangeAspectRatioCustom = function (valueNew_) { let left_ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; const valueNew = !valueNew_ ? 1 : valueNew_; let left = aspectRatioCustom?.[0] || 1; let right = aspectRatioCustom?.[1] || 1; left_ ? left = valueNew : right = valueNew; setAspectRatioCustom([left, right]); onChangeAspectRatio(left / right); }; const onChangeAspectRatio = valueNew => { if (aspectRatio === valueNew) setAspectRatio('');else setAspectRatio(valueNew); }; const onChangeResize = async function (valueNew) { let width_ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; let width; let height; if (!refs.resizeAspectRatio.current) { if (width_) { width = +valueNew; height = resize?.[1]; } else { width = resize?.[0]; height = +valueNew; } } else { const aspectRatio_ = value?.width / value?.height; if (width_) { width = +valueNew; height = valueNew / aspectRatio_; } else { height = +valueNew; width = height * aspectRatio_; } } width = clamp(width, 0); height = clamp(height, 0); setResize([width, height]); await updateResize(width, height); }; const updateQuality = debounce(async valueNew => { const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined; // Update copy value const uri = value.toDataURL('image/jpeg', valueNew / 100); const img = await imageMethod(uri); const canvas = rootDocument.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height); onChangeCopy(canvas); // Update the canvas value refs.canvasMain.current.width = canvas.width; refs.canvasMain.current.height = canvas.height; refs.canvasMain.current?.getContext('2d').drawImage(canvas, 0, 0, canvas.width, canvas.height); // Update size updateSize(); }, 40); const onChangeQuality = async valueNew => { setQuality(valueNew); await updateQuality(valueNew); }; const onChange = valueNew => { // Update inner or controlled if (!props.hasOwnProperty('value')) setValue(valueNew); if (is('function', onChange_)) onChange_(valueNew); }; const onChangeCopy = valueNew => { // Update inner or controlled if (!props.hasOwnProperty('valueCopy')) setValueCopy(valueNew); if (is('function', onChangeCopy_)) onChangeCopy_(valueNew); }; const onReset = function () { let imageReset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; let valueCopyReset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; let resizeReset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined; setOpen(false); setQuality(100); setAspectRatio(''); setAspectRatioCustom([1, 1]); setSelection(''); setFilter(''); setFilterValuesCopy(_objectSpread({}, filterValues)); if (resizeReset) setResize([value?.width, value?.height]); if (valueCopyReset) { const canvas = rootDocument.createElement('canvas'); canvas.width = refs.value.current.width; canvas.height = refs.value.current.height; canvas.getContext('2d').drawImage(refs.value.current, 0, 0, refs.value.current.width, refs.value.current.height); onChangeCopy(canvas); } if (imageReset) { setFilterValues({}); setFilterValuesCopy({}); makeImage(image); } }; const openOption = valueNew => { setOpenedOption(valueNew); if (open && openedOption === valueNew) { setOpen(false); onReset(false); } else if (!open) setOpen(true); }; const onSave = () => { const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined; // Make value copy into value let canvas = rootDocument.createElement('canvas'); canvas.width = refs.valueCopy.current.width; canvas.height = refs.valueCopy.current.height; canvas.getContext('2d').drawImage(refs.valueCopy.current, 0, 0, refs.valueCopy.current.width, refs.valueCopy.current.height); // Update crop if (openedOption === 'crop' && selection) { // Crop the canvas canvas.width = selection.width; canvas.height = selection.height; canvas = canvasCrop(refs.valueCopy.current, selection.left, selection.top, selection.width, selection.height); } // Update filters setFilterValues(_objectSpread({}, filterValuesCopy)); applyAllFilters(canvas); // Update the main canvas value refs.canvasMain.current.width = canvas.width; refs.canvasMain.current.height = canvas.height; refs.canvasMain.current?.getContext('2d').drawImage(canvas, 0, 0, canvas.width, canvas.height); // Update value onChange(canvas); const canvasCopy = rootDocument.createElement('canvas'); canvasCopy.width = canvas.width; canvasCopy.height = canvas.height; canvasCopy.getContext('2d').drawImage(canvas, 0, 0, canvasCopy.width, canvasCopy.height); // Update value copy onChangeCopy(canvasCopy); // Reset onReset(false, false, false); }; const onDownload = () => { // Download the image from canvas datauri // of the image type and quality, name const uri = refs.value.current.toDataURL(type); downloadMethod(name, uri, type); }; const onCancel = () => { const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined; // Reset to unopen onReset(false); // Make value copy into value const canvas = rootDocument.createElement('canvas'); canvas.width = refs.value.current.width; canvas.height = refs.value.current.height; canvas.getContext('2d').drawImage(refs.value.current, 0, 0, refs.value.current.width, refs.value.current.height); onChangeCopy(canvas); // Update the main canvas value refs.canvasMain.current.width = refs.value.current?.width; refs.canvasMain.current.height = refs.value.current?.height; refs.canvasMain.current?.getContext('2d').drawImage(refs.value.current, 0, 0, refs.value.current.width, refs.value.current.height); }; let filters = React.useMemo(() => [{ label: 'Brightness', Icon: IconBrightness, value: 'brightness', method: canvasBrightness, renderIconButton: (value__, selected_, onChangeFilter_) => /*#__PURE__*/React.createElement(Tooltip, _extends({ key: value__, label: "Brightness" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "outlined", selected: selected_, onClick: () => onChangeFilter_(value__) }, IconButtonProps), /*#__PURE__*/React.createElement(IconBrightness, null))), renderSlider: (value__, filterValuesCopy_, onFilterSliderChange_) => /*#__PURE__*/React.createElement(Slider, _extends({ key: value__, valueDefault: filterValuesCopy_?.[value__] || 0, value: filterValuesCopy_?.[value__] || 0, min: -100, max: 100, precision: 1, marks: [{ value: -100, label: '-100' }, { value: 0, label: '0' }, { value: 100, label: '100' }], labels: true, tooltip: true, onChange: valueNew => { if (is('function', onFilterSliderChange_)) onFilterSliderChange_(valueNew, value__); } }, SliderProps, { className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-slider'], SliderProps.className, classes.slider]) })) }, { label: 'Contrast', Icon: IconContrast, value: 'contrast', method: canvasContrast, renderIconButton: (value__, selected_, onChangeFilter_) => /*#__PURE__*/React.createElement(Tooltip, _extends({ key: value__, label: "Contrast" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "outlined", selected: selected_, onClick: () => onChangeFilter_(value__) }, IconButtonProps), /*#__PURE__*/React.createElement(IconContrast, null))), renderSlider: (value__, filterValuesCopy_, onFilterSliderChange_) => /*#__PURE__*/React.createElement(Slider, _extends({ key: value__, valueDefault: filterValuesCopy_?.[value__] || 0, value: filterValuesCopy_?.[value__] || 0, min: -100, max: 100, precision: 1, marks: [{ value: -100, label: '-100' }, { value: 0, label: '0' }, { value: 100, label: '100' }], labels: true, tooltip: true, onChange: valueNew => { if (is('function', onFilterSliderChange_)) onFilterSliderChange_(valueNew, value__); } }, SliderProps, { className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-slider'], SliderProps.className, classes.slider]) })) }, { label: 'Saturation', Icon: IconSaturation, value: 'saturation', method: canvasSaturation, renderIconButton: (value__, selected_, onChangeFilter_) => /*#__PURE__*/React.createElement(Tooltip, _extends({ key: value__, label: "Saturation" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "outlined", selected: selected_, onClick: () => onChangeFilter_(value__) }, IconButtonProps), /*#__PURE__*/React.createElement(IconSaturation, null))), renderSlider: (value__, filterValuesCopy_, onFilterSliderChange_) => /*#__PURE__*/React.createElement(Slider, _extends({ key: value__, valueDefault: filterValuesCopy_?.[value__] || 0, value: filterValuesCopy_?.[value__] || 0, min: -100, max: 100, precision: 1, marks: [{ value: -100, label: '-100' }, { value: 0, label: '0' }, { value: 100, label: '100' }], labels: true, tooltip: true, onChange: valueNew => { if (is('function', onFilterSliderChange_)) onFilterSliderChange_(valueNew, value__); } }, SliderProps, { className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-slider'], SliderProps.className, classes.slider]) })) }, { label: 'Fade', Icon: IconFade, value: 'fade', method: canvasFade, renderIconButton: (value__, selected_, onChangeFilter_) => /*#__PURE__*/React.createElement(Tooltip, _extends({ key: value__, label: "Fade" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "outlined", selected: selected_, onClick: () => onChangeFilter_(value__) }, IconButtonProps), /*#__PURE__*/React.createElement(IconFade, null))), renderSlider: (value__, filterValuesCopy_, onFilterSliderChange_) => /*#__PURE__*/React.createElement(Slider, _extends({ key: value__, valueDefault: filterValuesCopy_?.[value__] || 0, value: filterValuesCopy_?.[value__] || 0, min: 0, max: 100, precision: 1, marks: [{ value: 0, label: '0' }, { value: 100, label: '100' }], labels: true, tooltip: true, onChange: valueNew => { if (is('function', onFilterSliderChange_)) onFilterSliderChange_(valueNew, value__); } }, SliderProps, { className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-slider'], SliderProps.className, classes.slider]) })) }, { label: 'Invert', Icon: IconInvert, value: 'invert', method: canvasInvert, renderIconButton: (value__, selected_, onChangeFilter_) => /*#__PURE__*/React.createElement(Tooltip, _extends({ key: value__, label: "Invert" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "outlined", selected: selected_, onClick: () => onChangeFilter_(value__) }, IconButtonProps), /*#__PURE__*/React.createElement(IconInvert, null))), renderSlider: (value__, filterValuesCopy_, onFilterSliderChange_) => /*#__PURE__*/React.createElement(Slider, _extends({ key: value__, valueDefault: filterValuesCopy_?.[value__] || 0, value: filterValuesCopy_?.[value__] || 0, min: 0, max: 1, precision: 1, marks: [{ value: 0, label: 'Not inverted' }, { value: 1, label: 'Inverted' }], labels: true, tooltip: true, onChange: valueNew => { if (is('function', onFilterSliderChange_)) onFilterSliderChange_(valueNew, value__); } }, SliderProps, { className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-slider'], SliderProps.className, classes.slider]) })) }, { label: 'Old photo', Icon: IconOldPhoto, value: 'old_photo', method: canvasOldPhoto, renderIconButton: (value__, selected_, onChangeFilter_) => /*#__PURE__*/React.createElement(Tooltip, _extends({ key: value__, label: "Old photo" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "outlined", selected: selected_, onClick: () => onChangeFilter_(value__) }, IconButtonProps), /*#__PURE__*/React.createElement(IconOldPhoto, null))), renderSlider: (value__, filterValuesCopy_, onFilterSliderChange_) => /*#__PURE__*/React.createElement(Slider, _extends({ key: value__, valueDefault: filterValuesCopy_?.[value__] || 0, value: filterValuesCopy_?.[value__] || 0, min: -40, max: 40, precision: 1, marks: [{ value: -40, label: '-40' }, { value: 0, label: 'No filter' }, { value: 40, label: '40' }], labels: true, tooltip: true, onChange: valueNew => { if (is('function', onFilterSliderChange_)) onFilterSliderChange_(valueNew, value__); } }, SliderProps, { className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-slider'], SliderProps.className, classes.slider]) })) }, ...(filters_ || [])], [filters_]); // Only filters if (is('array', onlyFilters)) filters = filters.filter(item => onlyFilters.includes(item.value)); const ImageCropProps = _objectSpread({ gridLines: true }, ImageCropProps_); const TooltipProps = _objectSpread({ position: 'bottom', interactive: false }, TooltipProps_); const IconButtonProps = _objectSpread({ tonal, color: 'inherit' }, IconButtonProps_); const SliderProps = _objectSpread({ tonal: false, color: 'default' }, SliderProps_); const ChipProps = _objectSpread({ size: 'small' }, ChipProps_); const chips = [{ label: '1:1', value: 1 / 1 }, { label: '4:3', value: 4 / 3 }, { label: '16:9', value: 16 / 9 }]; const options = [filtersOption && { label: 'Filters', value: 'filters', Icon: IconFilters }, cropOption && { label: 'Crop', value: 'crop', Icon: IconCrop }, resizeOption && { label: 'Resize', value: 'resize', Icon: IconResize }, qualityOption && { label: 'Quality', value: 'quality', Icon: IconQuality }].filter(Boolean); const MetaTypeProps = { version: 'b3' }; const filterValue = filters.find(item_ => item_.value === filter); return /*#__PURE__*/React.createElement(Line, _extends({ ref: item => { if (ref) { if (is('function', ref)) ref(item);else if (ref?.current) ref.current = item; } refs.root.current = item; }, tonal: tonal, color: color, gap: 0, direction: "column", Component: Surface, className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-root', `amaui-ImageEdit-size-${size}`], className, classes.root]) }, other), /*#__PURE__*/React.createElement(Line, { gap: 0, direction: "column", align: "center", justify: "center", className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-image-wrapper'], classes.imageWrapper]) }, /*#__PURE__*/React.createElement("div", { className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-canvas-wrapper'], classes.canvasWrapper]) }, /*#__PURE__*/React.createElement("canvas", { ref: refs.canvasMain, className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-canvas', 'amaui-ImageEdit-canvas-main'], classes.canvas, classes.canvas_main]) }), open && openedOption === 'crop' && /*#__PURE__*/React.createElement(ImageCrop, _extends({ image: valueCopy, aspectRatio: aspectRatio ? aspectRatio : undefined, onSelectorChange: selector => setSelection(selector) }, ImageCropProps, { className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-image-crop'], ImageCropProps.className, classes.imageCrop]), style: { width: valueCopy?.width, height: valueCopy?.height } })))), (filtersOption || cropOption || resizeOption || qualityOption) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Expand, { in: !!open, parent: refs.root.current, style: { width: '100%' } }, /*#__PURE__*/React.createElement(Line, { gap: 0, ref: refs.option, direction: "column", className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-option'], classes.option]) }, openedOption === 'filters' && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Expand, { in: !!filterValue, parent: refs.option.current, style: { width: '100%' } }, /*#__PURE__*/React.createElement("div", { style: { paddingInline: theme.methods.space.value(5, 'px'), paddingBottom: theme.methods.space.value(5, 'px') } }, is('function', filterValue?.renderSlider) && filterValue?.renderSlider(filterValue.value, refs.filterValuesCopy.current, onFilterSliderChange))), /*#__PURE__*/React.createElement(Line, { gap: 1, direction: "row", align: "center", justify: "flex-start", className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-filters'], classes.filters]) }, filters.map(item => is('function', item.renderIconButton) && item.renderIconButton(item.value, item.value === filter, onChangeFilter)))), openedOption === 'crop' && /*#__PURE__*/React.createElement(Line, { gap: 1, direction: "row", align: "center", justify: "center", style: { width: '100%' } }, chips.map((item, index) => /*#__PURE__*/React.createElement(Chip, _extends({ key: index, selected: aspectRatio === item.value, onClick: () => onChangeAspectRatio(item.value) }, ChipProps), item.label)), /*#__PURE__*/React.createElement(Line, { gap: 0, direction: "row", align: "center", justify: "center" }, is('function', renderInput) ? renderInput(value, valueCopy, aspectRatioCustom, onChangeAspectRatioCustom, 'left') : /*#__PURE__*/React.createElement(NumericTextField, { tonal: tonal, color: "default", version: "text", size: "small", min: 1, value: aspectRatioCustom?.[0], onChange: valueNew => onChangeAspectRatioCustom(+valueNew), increment: false, decrement: false, className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-option-input'], classes.optionInput]), style: { width: 24 } }), /*#__PURE__*/React.createElement(Type, null, ":"), is('function', renderInput) ? renderInput(value, valueCopy, aspectRatioCustom, onChangeAspectRatioCustom, 'right') : /*#__PURE__*/React.createElement(NumericTextField, { tonal: tonal, color: "default", version: "text", size: "small", min: 1, value: aspectRatioCustom?.[1], onChange: valueNew => onChangeAspectRatioCustom(+valueNew, false), increment: false, decrement: false, className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-option-input'], classes.optionInput]), style: { width: 24 } }))), openedOption === 'resize' && /*#__PURE__*/React.createElement(Line, { direction: "row", align: "center", justify: "center", className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-inputs'], classes.inputs]) }, is('function', renderInput) ? renderInput(value, valueCopy, resize, onChangeResize, 'width') : /*#__PURE__*/React.createElement(NumericTextField, { tonal: tonal, label: "Width", color: "default", version: "text", size: "small", min: 1, max: value?.width, valueDefault: value?.width, value: resize?.[0], onChange: valueNew => onChangeResize(valueNew) }), is('function', renderInput) ? renderInput(value, valueCopy, resize, onChangeResize, 'height') : /*#__PURE__*/React.createElement(NumericTextField, { tonal: tonal, label: "Height", color: "default", version: "text", size: "small", min: 1, max: value?.height, valueDefault: value?.height, value: resize?.[1], onChange: valueNew => onChangeResize(valueNew, false) })), openedOption === 'quality' && /*#__PURE__*/React.createElement(Line, { gap: 3, direction: "row", align: "center", style: { width: '100%' } }, /*#__PURE__*/React.createElement(Slider, _extends({ valueDefault: quality, value: quality, min: 1, max: 100, precision: 1, marks: [{ value: 1 }, { value: 50 }, { value: 100 }], tooltip: true, onChange: onChangeQuality }, SliderProps, { className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-slider'], SliderProps.className, classes.slider]) })), /*#__PURE__*/React.createElement(NumericTextField, { tonal: tonal, color: "default", version: "text", size: "small", min: 1, max: 100, value: quality, increment: false, decrement: false, onChange: valueNew => onChangeQuality(+valueNew), className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-option-input'], classes.optionInput]), style: { width: 34 } })), /*#__PURE__*/React.createElement(Line, { gap: 1, direction: "row", align: "center", justify: "center", className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-action'], classes.action]) }, is('function', renderSave) ? renderSave(onSave) : /*#__PURE__*/React.createElement(Tooltip, _extends({ label: "Save" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "outlined", onClick: onSave }, IconButtonProps), /*#__PURE__*/React.createElement(IconSave, null))), is('function', renderCancel) ? renderCancel(onSave) : /*#__PURE__*/React.createElement(Tooltip, _extends({ label: "Cancel" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "outlined", onClick: onCancel }, IconButtonProps), /*#__PURE__*/React.createElement(IconCancel, null))))), /*#__PURE__*/React.createElement(Divider, { color: "inherit", className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-divider'], classes.divider]) })), /*#__PURE__*/React.createElement(Line, { direction: "column", align: "center", justify: "center", className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-options'], classes.options]) }, /*#__PURE__*/React.createElement(Line, { gap: 1, direction: "row", justify: "flex-start" }, options.map((item, index) => is('function', renderOption) ? renderOption(item, open && openOption === item.value, openOption) : /*#__PURE__*/React.createElement(Tooltip, _extends({ key: index, label: item.label }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "outlined", selected: open && openedOption === item.value, onClick: () => openOption(item.value) }, IconButtonProps), /*#__PURE__*/React.createElement(item.Icon, null)))), /*#__PURE__*/React.createElement(Line, { gap: 0, direction: "row", align: "center" }, downloadOption && is('function', renderDownload) ? renderDownload(onDownload) : /*#__PURE__*/React.createElement(Tooltip, _extends({ label: "Download" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "text", onClick: onDownload }, IconButtonProps), /*#__PURE__*/React.createElement(IconDownload, null))), is('function', renderOptionClear) ? renderOptionClear(onReset) : /*#__PURE__*/React.createElement(Tooltip, _extends({ label: "Reset" }, TooltipProps), /*#__PURE__*/React.createElement(IconButton, _extends({ version: "text", onClick: onReset }, IconButtonProps), /*#__PURE__*/React.createElement(IconClear, null))))))), children, meta && value && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, { color: "inherit", className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-divider'], classes.divider]) }), /*#__PURE__*/React.createElement(Line, { gap: 1, direction: "row", align: "center", justify: "center", className: classNames([staticClassName('ImageEdit', theme) && ['amaui-ImageEdit-meta'], classes.meta]) }, /*#__PURE__*/React.createElement(Type, MetaTypeProps, "Dimensions: ", (!open ? value : valueCopy)?.width, "x", (!open ? value : valueCopy)?.height), /*#__PURE__*/React.createElement(Type, MetaTypeProps, "\xB7"), /*#__PURE__*/React.createElement(Type, MetaTypeProps, "Size: ", size)))); }); ImageEdit.displayName = 'amaui-ImageEdit'; export default ImageEdit;