@amaui/ui-react
Version:
UI for React
1,049 lines (1,027 loc) • 41.8 kB
JavaScript
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;