├── .editorconfig
├── .env.example
├── .eslintrc.js
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .prettierrc
├── CHANGELOG.md
├── DEVELOPMENT.md
├── LICENSE
├── README.md
├── babel.config.json
├── bin
└── deploy-js-bundle-to-filerobot.js
├── index.html
├── jsconfig.json
├── lerna.json
├── package.json
├── packages
├── filerobot-image-editor
│ ├── LICENSE
│ ├── README.md
│ ├── package.json
│ └── src
│ │ ├── index.d.ts
│ │ └── index.js
└── react-filerobot-image-editor
│ ├── LICENSE
│ ├── README.md
│ ├── package.json
│ └── src
│ ├── actions
│ ├── addFilter.js
│ ├── changePointerIcon.js
│ ├── changeRotation.js
│ ├── clearAnnotationsSelections.js
│ ├── duplicateAnnotations.js
│ ├── enableTextContentEdit.js
│ ├── hideLoader.js
│ ├── index.js
│ ├── redo.js
│ ├── removeAnnotations.js
│ ├── reset.js
│ ├── selectAnnotation.js
│ ├── selectTab.js
│ ├── selectTool.js
│ ├── setAnnotation.js
│ ├── setCanvasSize.js
│ ├── setCrop.js
│ ├── setFeedback.js
│ ├── setFinetune.js
│ ├── setLatestColor.js
│ ├── setOriginalImage.js
│ ├── setResize.js
│ ├── setSaved.js
│ ├── setSaving.js
│ ├── setShowTabsMenu.js
│ ├── setShownImageDimensions.js
│ ├── showLoader.js
│ ├── toggleFlip.js
│ ├── toggleOriginalImageDisplay.js
│ ├── undo.js
│ ├── updateState.js
│ └── zoomCanvas.js
│ ├── components
│ ├── App
│ │ ├── App.styled.js
│ │ └── index.jsx
│ ├── AssemblyPoint
│ │ ├── globalStyles.js
│ │ └── index.jsx
│ ├── FeedbackPopup
│ │ └── index.jsx
│ ├── Layers
│ │ ├── DesignLayer
│ │ │ ├── AnnotationNodes
│ │ │ │ ├── AnnotationNodes.constants.js
│ │ │ │ ├── ArrowNode.jsx
│ │ │ │ ├── EllipseNode.jsx
│ │ │ │ ├── ImageNode.jsx
│ │ │ │ ├── LineNode.jsx
│ │ │ │ ├── MemoizedAnnotation.jsx
│ │ │ │ ├── PolygonNode.jsx
│ │ │ │ ├── RectNode.jsx
│ │ │ │ ├── TextNode.jsx
│ │ │ │ └── index.jsx
│ │ │ ├── PreviewGroup.jsx
│ │ │ ├── index.jsx
│ │ │ └── nodesCommonPropTypes.js
│ │ ├── TransformersLayer
│ │ │ ├── CropTransformer.jsx
│ │ │ ├── NodesTransformer.jsx
│ │ │ ├── TransformersLayer.utils.js
│ │ │ └── index.jsx
│ │ └── index.js
│ ├── MainCanvas
│ │ ├── CanvasNode.jsx
│ │ ├── MainCanvas.styled.js
│ │ ├── index.jsx
│ │ └── touchZoomingEvents.js
│ ├── NodeControls
│ │ ├── NodeControls.styled.js
│ │ └── index.jsx
│ ├── Tabs
│ │ ├── TabItem.jsx
│ │ ├── Tabs.constants.js
│ │ ├── Tabs.styled.js
│ │ └── index.jsx
│ ├── TabsDrawer
│ │ └── index.jsx
│ ├── ToolsBar
│ │ ├── ToolsBar.styled.js
│ │ ├── ToolsBarItemButton.jsx
│ │ ├── ToolsBarItemOptionsWrapper.jsx
│ │ └── index.jsx
│ ├── Topbar
│ │ ├── BackButton.jsx
│ │ ├── CanvasZooming.jsx
│ │ ├── CloseButton.jsx
│ │ ├── ConfirmationModal.jsx
│ │ ├── ImageDimensionsAndDisplayToggle.jsx
│ │ ├── RedoButton.jsx
│ │ ├── ResetButton.jsx
│ │ ├── SaveButton.jsx
│ │ ├── Topbar.constants.js
│ │ ├── Topbar.styled.js
│ │ ├── UndoButton.jsx
│ │ └── index.jsx
│ ├── common
│ │ ├── AnnotationOptions
│ │ │ ├── AnnotationOptions.constants.js
│ │ │ ├── AnnotationOptions.styled.js
│ │ │ ├── OpacityField.jsx
│ │ │ ├── PositionFields.jsx
│ │ │ ├── ShadowFields.jsx
│ │ │ ├── StrokeFields.jsx
│ │ │ └── index.jsx
│ │ ├── ButtonWithMenu
│ │ │ ├── ButtonWithMenu.styled.js
│ │ │ └── index.jsx
│ │ ├── Carousel
│ │ │ ├── Carousel.styled.js
│ │ │ └── index.jsx
│ │ ├── ColorInput
│ │ │ ├── ColorInput.styled.js
│ │ │ └── index.jsx
│ │ ├── ColorPickerModal
│ │ │ ├── ColorPickerModal.styled.js
│ │ │ └── index.jsx
│ │ ├── HiddenUploadInput
│ │ │ ├── HiddenUploadInput.styled.js
│ │ │ └── index.jsx
│ │ ├── Modal
│ │ │ ├── Modal.styled.js
│ │ │ └── index.jsx
│ │ ├── Separator
│ │ │ ├── Separator.styled.js
│ │ │ └── index.jsx
│ │ ├── Slider
│ │ │ ├── Slider.styled.js
│ │ │ └── index.jsx
│ │ └── Spinner
│ │ │ ├── Spinner.styled.js
│ │ │ └── index.jsx
│ └── tools
│ │ ├── Arrow
│ │ ├── ArrowButton.jsx
│ │ ├── ArrowOptions.jsx
│ │ └── index.js
│ │ ├── Blur
│ │ ├── Blur.jsx
│ │ ├── BlurOptions.jsx
│ │ └── index.js
│ │ ├── Brightness
│ │ ├── Brightness.jsx
│ │ ├── BrightnessOptions.jsx
│ │ └── index.js
│ │ ├── Contrast
│ │ ├── Contrast.jsx
│ │ ├── ContrastOptions.jsx
│ │ └── index.js
│ │ ├── Crop
│ │ ├── Crop.constants.js
│ │ ├── Crop.jsx
│ │ ├── Crop.styled.js
│ │ ├── CropPresetGroup.jsx
│ │ ├── CropPresetGroupsFolder.jsx
│ │ ├── CropPresetItem.jsx
│ │ ├── CropPresetsOption.jsx
│ │ └── index.js
│ │ ├── Ellipse
│ │ ├── EllipseButton.jsx
│ │ ├── EllipseOptions.jsx
│ │ └── index.js
│ │ ├── Filters
│ │ ├── FilterItem.jsx
│ │ ├── Filters.constants.js
│ │ ├── Filters.jsx
│ │ ├── Filters.styled.js
│ │ └── index.js
│ │ ├── Flip
│ │ ├── FlipX.jsx
│ │ ├── FlipY.jsx
│ │ └── index.js
│ │ ├── HSV
│ │ ├── HSV.jsx
│ │ ├── HSVOptions.jsx
│ │ └── index.js
│ │ ├── Image
│ │ ├── Image.styled.js
│ │ ├── ImageButton.jsx
│ │ ├── ImageControls.jsx
│ │ ├── ImageOptions.jsx
│ │ ├── ImagesGallery.jsx
│ │ └── index.js
│ │ ├── Line
│ │ ├── LineButton.jsx
│ │ ├── LineOptions.jsx
│ │ └── index.js
│ │ ├── Pen
│ │ ├── PenButton.jsx
│ │ ├── PenOptions.jsx
│ │ └── index.js
│ │ ├── Polygon
│ │ ├── Polygon.constants.js
│ │ ├── PolygonButton.jsx
│ │ ├── PolygonOptions.jsx
│ │ ├── PolygonSidesField.jsx
│ │ └── index.js
│ │ ├── Rect
│ │ ├── Rect.constants.js
│ │ ├── RectButton.jsx
│ │ ├── RectCornerField.jsx
│ │ ├── RectOptions.jsx
│ │ └── index.js
│ │ ├── Resize
│ │ ├── Resize.jsx
│ │ ├── Resize.styled.js
│ │ └── index.js
│ │ ├── Rotate
│ │ ├── Rotate.styled.js
│ │ ├── RotateButton.jsx
│ │ ├── RotateOptions.jsx
│ │ └── index.js
│ │ ├── Text
│ │ ├── TextButton.jsx
│ │ ├── TextOptions
│ │ │ ├── TextAlignmentFields.jsx
│ │ │ ├── TextControls.jsx
│ │ │ ├── TextOptions.constants.js
│ │ │ ├── TextOptions.styled.js
│ │ │ ├── TextSpacingsFields.jsx
│ │ │ ├── handleTextChangeArea.js
│ │ │ └── index.jsx
│ │ └── index.js
│ │ ├── Warmth
│ │ ├── Warmth.jsx
│ │ ├── WarmthOptions.jsx
│ │ └── index.js
│ │ ├── Watermark
│ │ ├── Watermark.jsx
│ │ ├── Watermark.styled.js
│ │ ├── WatermarkPadding.jsx
│ │ ├── WatermarksGallery.jsx
│ │ └── index.jsx
│ │ ├── tools.constants.js
│ │ └── tools.styled.js
│ ├── context
│ ├── AppContext.js
│ ├── AppProvider.jsx
│ ├── AppProviderOverridenValue.jsx
│ ├── appReducer.js
│ ├── defaultConfig.js
│ ├── defaultTranslations.js
│ ├── getInitialAppState.js
│ └── index.js
│ ├── custom
│ ├── filters
│ │ ├── Aden.js
│ │ ├── Amaro.js
│ │ ├── Ashby.js
│ │ ├── BaseFilters.js
│ │ ├── BlackAndWhite.js
│ │ ├── Brannan.js
│ │ ├── Brooklyn.js
│ │ ├── Charmes.js
│ │ ├── Clarendon.js
│ │ ├── Crema.js
│ │ ├── Dogpatch.js
│ │ ├── Earlybird.js
│ │ ├── Gingham.js
│ │ ├── Ginza.js
│ │ ├── Hefe.js
│ │ ├── Helena.js
│ │ ├── Hudson.js
│ │ ├── Juno.js
│ │ ├── Kelvin.js
│ │ ├── Lark.js
│ │ ├── LoFi.js
│ │ ├── Ludwig.js
│ │ ├── Maven.js
│ │ ├── Mayfair.js
│ │ ├── Moon.js
│ │ ├── Nashville.js
│ │ ├── NinteenSeventySeven.js
│ │ ├── Perpetua.js
│ │ ├── Reyes.js
│ │ ├── Rise.js
│ │ ├── Sierra.js
│ │ ├── Skyline.js
│ │ ├── Slumber.js
│ │ ├── Stinson.js
│ │ ├── Sutro.js
│ │ ├── Toaster.js
│ │ ├── Valencia.js
│ │ ├── Vesper.js
│ │ ├── Walden.js
│ │ ├── Willow.js
│ │ ├── XPro2.js
│ │ └── index.js
│ └── finetunes
│ │ ├── CustomThreshold.js
│ │ ├── Warmth.js
│ │ └── index.js
│ ├── hooks
│ ├── index.js
│ ├── useAnnotation
│ │ ├── getBoundingRectUnScaled.js
│ │ ├── getNewAnnotationPreview.js
│ │ ├── index.js
│ │ └── previewThenCallAnnotationAdding.js
│ ├── useAnnotationEvents.js
│ ├── useAppReducer.js
│ ├── useDebouncedCallback.js
│ ├── useDrag.js
│ ├── useFilter.js
│ ├── useFinetune.js
│ ├── usePhoneScreen.js
│ ├── useResizeObserver.js
│ ├── useStore.js
│ ├── useTransformedImgData.js
│ └── useUpdateEffect.js
│ ├── index.d.ts
│ ├── index.js
│ └── utils
│ ├── assignFinetuneNamesToKonva.js
│ ├── calculateZoomData.js
│ ├── cloudimageQueryToDesignState.js
│ ├── compareRatios.js
│ ├── constants.js
│ ├── cropImage.js
│ ├── debounce.js
│ ├── deepMerge.js
│ ├── extractCurrentDesignState.js
│ ├── extractNameFromUrl.js
│ ├── filterStrToClass.js
│ ├── finetunesStrsToClasses.js
│ ├── getCenterRotatedPoint.js
│ ├── getDefaultSaveQuality.js
│ ├── getDimensionsMinimalRatio.js
│ ├── getElemDocumentCoords.js
│ ├── getFileFullName.js
│ ├── getImageSealingParams.js
│ ├── getPointerOffsetPositionBoundedToObject.js
│ ├── getProperDimensions.js
│ ├── getProperImageToCanvasSpacing.js
│ ├── getScrollOffset.js
│ ├── getSizeAfterRotation.js
│ ├── getZoomFitFactor.js
│ ├── imageToBase64.js
│ ├── isDefaultZeroValuesOnly.js
│ ├── isSameImage.js
│ ├── loadImage.js
│ ├── mapCropBox.js
│ ├── mapNumber.js
│ ├── mapPositionStringToPoint.js
│ ├── operationsToCloudimageUrl.js
│ ├── randomId.js
│ ├── restrictNumber.js
│ ├── rgbaToHexa.js
│ ├── sha1.js
│ ├── toPrecisedFloat.js
│ └── translator.js
├── public
├── assets
│ ├── Ellipse 3.png
│ ├── Hollow-Ellipse 3.png
│ ├── add-annotation.svg
│ ├── adding-icon.png
│ ├── arrow-icon.png
│ ├── arrow.png
│ ├── check-icon.png
│ ├── copy-icon.png
│ ├── down-arrow-icon.png
│ ├── git-stars.svg
│ ├── github-logo.svg
│ ├── half-circle.png
│ ├── image-resize-mode.svg
│ ├── loading.svg
│ ├── scaleflex-logo.svg
│ └── watermark-img.svg
├── demo-config.js
├── init.js
└── style.css
├── vite.config.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 |
6 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | # This env. variables are used in deployment to filerobot CDN.
2 | # Copy the variables and paste them into .env file and replace with proper values
3 | UPLOAD_SECURITY_TEMPLATE_ID=FILEROBOT_KEY_USED_IN_UPLOADING_JS_BUNDLE
4 | PLUGINS_CONTAINER=FILEROBOT_CONTAINER_OF_PLUGINS_FOLDER
5 | PLUGIN_FOLDER=FILEROBOT_PLUGINS_FOLDER
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | es2021: true,
5 | },
6 | extends: [
7 | 'airbnb',
8 | 'plugin:react/recommended',
9 | 'plugin:prettier/recommended',
10 | ],
11 | parserOptions: {
12 | ecmaFeatures: {
13 | jsx: true,
14 | },
15 | ecmaVersion: 12,
16 | sourceType: 'module',
17 | },
18 | plugins: ['react', 'prettier'],
19 | rules: {
20 | 'no-unused-vars': 'warn',
21 | 'import/no-cycle': 'off',
22 | 'import/no-extraneous-dependencies': [
23 | 'error',
24 | {
25 | devDependencies: true,
26 | peerDependencies: true,
27 | },
28 | ],
29 | 'import/prefer-default-export': 'off',
30 | 'react/prop-types': 'warn',
31 | 'react/jsx-props-no-spreading': 'off',
32 | 'react/jsx-filename-extension': 'error',
33 | 'react/no-array-index-key': 'error',
34 | 'react/prefer-read-only-props': 'error',
35 | 'react/jsx-key': ['error', { checkKeyMustBeforeSpread: true }],
36 | 'react/react-in-jsx-scope': 'off',
37 | 'react/function-component-definition': [
38 | 2,
39 | { namedComponents: 'arrow-function' },
40 | ],
41 | },
42 | settings: {
43 | 'import/resolver': {
44 | node: {
45 | moduleDirectory: [
46 | 'node_modules',
47 | 'packages/react-filerobot-image-editor/src',
48 | ],
49 | },
50 | },
51 | },
52 | };
53 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: unseen
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug (required)**
11 | A clear and concise description of what the bug is.
12 |
13 | **Codesandbox demo (required)**
14 | Provide an example link that produces the issue on any instant cloud development (ex. codesandbox).
15 |
16 | **To Reproduce (required)**
17 | Steps to reproduce the behavior:
18 | 1. Go to '...'
19 | 2. Click on '....'
20 | 3. Scroll down to '....'
21 | 4. See error
22 |
23 | **Expected behavior**
24 | A clear and concise description of what you expected to happen.
25 |
26 | **Videos/Screenshots**
27 | If applicable, add screenshots to help explain your problem.
28 |
29 | **Desktop (please complete the following information):**
30 | - OS: [e.g. iOS]
31 | - Browser [e.g. chrome, safari]
32 | - Version [e.g. 22]
33 |
34 | **Smartphone (please complete the following information):**
35 | - Device: [e.g. iPhone6]
36 | - OS: [e.g. iOS8.1]
37 | - Browser [e.g. stock browser, safari]
38 | - Version [e.g. 22]
39 |
40 | **Additional context**
41 | Add any other context about the problem here.
42 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: unseen
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | node_modules
3 | yarn.lock
4 | package-lock.json
5 |
6 | # Editor folders
7 | .cache
8 | .eslintCache
9 | .vscode
10 | .idea
11 |
12 | # production
13 | dist
14 | lib
15 | build
16 | demo-dist
17 |
18 | # misc
19 | .DS_Store
20 | .env
21 | .env.local
22 | .env.development.local
23 | .env.test.local
24 | .env.production.local
25 | .vite
26 |
27 | # Logs
28 | logs
29 | *.log
30 | npm-debug.log*
31 | yarn-debug.log*
32 | yarn-error.log*
33 | lerna-debug.log*
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "jsxSingleQuote": false,
5 | "endOfLine": "lf",
6 | "semi": true
7 | }
--------------------------------------------------------------------------------
/DEVELOPMENT.md:
--------------------------------------------------------------------------------
1 | # Dev. notes for developers in-case of contribution
2 |
3 | #### Glossary
4 | - $reactPackage === packages/react-filerobot-image-editor/
5 | -
6 |
7 | #### Adding a new property
8 |
9 | - Doing a global search for any property at least should exist 1 time occurrence in each of these 5 files (README.md, $reactPackage/index.d.ts, defaultConfig.js, demo-config.js & -- feature's implementation file --).
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 scaleflex
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/babel.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "modules": false
7 | }
8 | ],
9 | "@babel/preset-react",
10 | [
11 | "minify",
12 | {
13 | "builtIns": false
14 | }
15 | ]
16 | ],
17 | "comments": false,
18 | "plugins": [
19 | [
20 | "module-resolver",
21 | {
22 | "root": [
23 | "./src"
24 | ],
25 | "alias": {
26 | "react-filerobot-image-editor/src/": "react-filerobot-image-editor",
27 | "react-filerobot-image-editor/src/utils/deepMerge": "react-filerobot-image-editor/lib/utils/deepMerge",
28 | }
29 | }
30 | ],
31 | [
32 | "babel-plugin-styled-components"
33 | ],
34 | [
35 | "@babel/plugin-transform-runtime"
36 | ]
37 | ],
38 | "env": {
39 | "production": {
40 | "plugins": [
41 | [
42 | "babel-plugin-styled-components",
43 | {
44 | "pure": true,
45 | "displayName": false
46 | }
47 | ],
48 | [
49 | "transform-react-remove-prop-types",
50 | {
51 | "removeImport": true
52 | }
53 | ]
54 | ]
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "packages/react-filerobot-image-editor/src",
4 | "jsx": "preserve"
5 | },
6 | "include": [
7 | "packages/react-filerobot-image-editor/src"
8 | ]
9 | }
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "npmClient": "yarn",
3 | "useWorkspaces": true,
4 | "packages": ["packages/*"],
5 | "version": "4.9.1",
6 | "command": {
7 | "version": {
8 | "message": "Chore(Release): publish new version %s🔥🚀"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/filerobot-image-editor/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 scaleflex
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/packages/filerobot-image-editor/README.md:
--------------------------------------------------------------------------------
1 | # filerobot-image-editor
2 |
3 | Vanilla Javascript bridged version of filerobot image editor (FIE).
4 |
5 | Visit [main README.md](https://github.com/scaleflex/filerobot-image-editor#readme) for docs.
--------------------------------------------------------------------------------
/packages/filerobot-image-editor/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "filerobot-image-editor",
3 | "version": "4.8.1",
4 | "license": "MIT",
5 | "author": "Scaleflex",
6 | "homepage": "https://github.com/scaleflex/filerobot-image-editor#readme",
7 | "main": "lib/index.js",
8 | "types": "lib/index.d.ts",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/scaleflex/filerobot-image-editor#readme"
12 | },
13 | "keywords": [
14 | "Image editing javascript library",
15 | "Javascript image editor library",
16 | "image editor",
17 | "filerobot image editor",
18 | "edit image",
19 | "modify image",
20 | "update image",
21 | "finetune",
22 | "filters",
23 | "weatermark",
24 | "resize",
25 | "annotate"
26 | ],
27 | "files": [
28 | "lib"
29 | ],
30 | "dependencies": {
31 | "@babel/runtime": "^7.17.2",
32 | "react": "^18.2.0",
33 | "react-dom": "^18.2.0",
34 | "react-konva": "^18.2.10",
35 | "styled-components": "^5.3.5"
36 | },
37 | "peerDependencies": {
38 | "react-filerobot-image-editor": "^4.7.0"
39 | },
40 | "scripts": {
41 | "build:lib": "rimraf lib && cross-env BABEL_ENV=production NODE_ENV=production babel src -d lib --config-file ../../babel.config.json -D"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/packages/filerobot-image-editor/src/index.d.ts:
--------------------------------------------------------------------------------
1 | import { FilerobotImageEditorConfig, TABS, TOOLS, getCurrentImgDataFunction } from 'react-filerobot-image-editor';
2 |
3 | declare class FilerobotImageEditor {
4 | TABS: typeof TABS;
5 | TOOLS: typeof TOOLS;
6 | constructor(container: HTMLElement, config: FilerobotImageEditorConfig);
7 | render(additionalConfig?: FilerobotImageEditorConfig): void;
8 | terminate(): void;
9 | getCurrentImgData: getCurrentImgDataFunction;
10 | updateState: (newStatePart: {} | ((currentState: {}) => void)) => void;
11 | }
12 |
13 | export default FilerobotImageEditor;
14 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 scaleflex
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/README.md:
--------------------------------------------------------------------------------
1 | # react-filerobot-image-editor
2 |
3 | React component version of filerobot image editor (FIE).
4 |
5 | Visit [main README.md](https://github.com/scaleflex/filerobot-image-editor#readme) for docs.
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-filerobot-image-editor",
3 | "version": "4.9.1",
4 | "license": "MIT",
5 | "author": "Scaleflex",
6 | "homepage": "https://github.com/scaleflex/filerobot-image-editor#readme",
7 | "main": "./lib/index.js",
8 | "types": "./lib/index.d.ts",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/scaleflex/filerobot-image-editor#readme"
12 | },
13 | "keywords": [
14 | "Image editing react component",
15 | "React Image Editor",
16 | "image editor",
17 | "filerobot image editor",
18 | "edit image",
19 | "modify image",
20 | "update image",
21 | "finetune",
22 | "filters",
23 | "weatermark",
24 | "resize",
25 | "annotate"
26 | ],
27 | "files": [
28 | "lib"
29 | ],
30 | "dependencies": {
31 | "@babel/runtime": "^7.17.2",
32 | "@scaleflex/icons": "2.10.27",
33 | "@scaleflex/ui": "2.10.27",
34 | "konva": "9.3.6",
35 | "prop-types": "15.7.2"
36 | },
37 | "peerDependencies": {
38 | "react": ">=17.0.0",
39 | "react-dom": ">=17.0.0",
40 | "react-konva": ">=17.0.0",
41 | "styled-components": ">=5.3.5"
42 | },
43 | "scripts": {
44 | "build:lib": "rimraf lib && cross-env BABEL_ENV=production NODE_ENV=production babel src -d lib --config-file ../../babel.config.json -D"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/addFilter.js:
--------------------------------------------------------------------------------
1 | export const ADD_FILTER = 'ADD_FILTER';
2 |
3 | const addFilter = (state, payload) => ({
4 | ...state,
5 | isDesignState: !payload.dismissHistory, // not stored in state, used in reducer to consider in undo/redo stacks
6 | filter: payload.filter || null,
7 | });
8 |
9 | export default addFilter;
10 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/changePointerIcon.js:
--------------------------------------------------------------------------------
1 | export const CHANGE_POINTER_ICON = 'CHANGE_POINTER_ICON';
2 |
3 | const changingPointerIcon = (state, payload) =>
4 | state.pointerCssIcon !== payload.pointerCssIcon
5 | ? {
6 | ...state,
7 | pointerCssIcon: payload.pointerCssIcon,
8 | }
9 | : state;
10 |
11 | export default changingPointerIcon;
12 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/changeRotation.js:
--------------------------------------------------------------------------------
1 | export const CHANGE_ROTATION = 'CHANGE_ROTATION';
2 |
3 | const changeRotation = (state, payload) =>
4 | state.adjustments.rotation !== payload.rotation
5 | ? {
6 | ...state,
7 | isDesignState: !payload.dismissHistory,
8 | adjustments: {
9 | ...state.adjustments,
10 | rotation: payload.rotation,
11 | },
12 | }
13 | : state;
14 |
15 | export default changeRotation;
16 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/clearAnnotationsSelections.js:
--------------------------------------------------------------------------------
1 | export const CLEAR_ANNOTATIONS_SELECTIONS = 'CLEAR_ANNOTATIONS_SELECTIONS';
2 |
3 | const clearAnnotationsSelections = (state) =>
4 | state.selectionsIds.length === 0
5 | ? state
6 | : {
7 | ...state,
8 | selectionsIds: [],
9 | };
10 |
11 | export default clearAnnotationsSelections;
12 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/duplicateAnnotations.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import randomId from 'utils/randomId';
3 |
4 | export const DUPLICATE_ANNOTATIONS = 'DUPLICATE_ANNOTATIONS';
5 |
6 | const duplicateAnnotations = (state, payload) => {
7 | const { annotations } = state;
8 | const duplicatedAnnotations = {};
9 | payload.annotationsIds.forEach((id) => {
10 | const annotation = annotations[id];
11 | if (annotation) {
12 | const clonedAnnotationId = randomId(annotation.name);
13 | duplicatedAnnotations[clonedAnnotationId] = {
14 | ...annotation,
15 | id: clonedAnnotationId,
16 | x: annotation.x + 20,
17 | y: annotation.y + 20,
18 | };
19 | }
20 | });
21 |
22 | return {
23 | ...state,
24 | // not stored in state, used in reducer to consider in undo/redo stacks
25 | isDesignState: !payload.dismissHistory,
26 | annotations: {
27 | ...annotations,
28 | ...duplicatedAnnotations,
29 | },
30 | };
31 | };
32 |
33 | export default duplicateAnnotations;
34 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/enableTextContentEdit.js:
--------------------------------------------------------------------------------
1 | export const ENABLE_TEXT_CONTENT_EDIT = 'ENABLE_TEXT_CONTENT_EDIT';
2 |
3 | const enableTextContentEdit = (state, payload) => ({
4 | ...state,
5 | textIdOfEditableContent: payload.textIdOfEditableContent || null,
6 | });
7 |
8 | export default enableTextContentEdit;
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/hideLoader.js:
--------------------------------------------------------------------------------
1 | export const HIDE_LOADER = 'HIDE_LOADER';
2 |
3 | const hideLoader = (state) => ({
4 | ...state,
5 | isLoadingGlobally: false,
6 | });
7 |
8 | export default hideLoader;
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/redo.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import extractCurrentDesignState from 'utils/extractCurrentDesignState';
3 |
4 | export const REDO = 'REDO';
5 |
6 | const redo = (state) => {
7 | if (state.futureDesignStates && state.futureDesignStates.length > 0) {
8 | const currentDesignState = extractCurrentDesignState(state);
9 | const [presentDesignState, ...newFutureDesignStates] =
10 | state.futureDesignStates;
11 | const newPastDesignStates = [
12 | currentDesignState,
13 | ...(state.pastDesignStates || []),
14 | ];
15 |
16 | return {
17 | ...state,
18 | ...presentDesignState,
19 | selectionsIds: [],
20 | pastDesignStates: newPastDesignStates,
21 | futureDesignStates: newFutureDesignStates,
22 | hasUndo: true,
23 | hasRedo: newFutureDesignStates.length > 0,
24 | haveNotSavedChanges: true,
25 | };
26 | }
27 |
28 | return state;
29 | };
30 |
31 | export default redo;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/removeAnnotations.js:
--------------------------------------------------------------------------------
1 | export const REMOVE_ANNOTATIONS = 'REMOVE_ANNOTATIONS';
2 |
3 | const removeAnnotations = (state, payload) => {
4 | const { annotations } = state;
5 | let newSelectionsIds = state.selectionsIds;
6 |
7 | payload.annotationsIds.forEach((id) => {
8 | newSelectionsIds = newSelectionsIds.filter(
9 | (selectionId) => selectionId !== id,
10 | );
11 |
12 | if (state.designLayer && annotations[id]) {
13 | const annotationNode = state.designLayer.findOne(`#${id}`);
14 | if (annotationNode) {
15 | annotationNode.destroy();
16 | }
17 | delete annotations[id];
18 | }
19 | });
20 |
21 | return {
22 | ...state,
23 | // not stored in state, used in reducer to consider in undo/redo stacks
24 | isDesignState: payload.isDesignState || true,
25 | annotations,
26 | selectionsIds: [],
27 | };
28 | };
29 |
30 | export default removeAnnotations;
31 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/reset.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import { DEFAULT_ZOOM_FACTOR } from 'utils/constants';
3 | import extractCurrentDesignState from 'utils/extractCurrentDesignState';
4 |
5 | export const RESET = 'RESET';
6 |
7 | const reset = (state, payload) => {
8 | const resettedDesignState = extractCurrentDesignState(
9 | {
10 | ...payload.config,
11 | imgSrc: state.imgSrc,
12 | },
13 | true,
14 | );
15 |
16 | return {
17 | ...state,
18 | ...resettedDesignState,
19 | zoom: {
20 | factor: DEFAULT_ZOOM_FACTOR,
21 | x: null,
22 | y: null,
23 | },
24 | selectionsIds: [],
25 | isResetted: true,
26 | pastDesignStates: [],
27 | futureDesignStates: [],
28 | hasUndo: false,
29 | hasRedo: false,
30 | haveNotSavedChanges: false,
31 | };
32 | };
33 |
34 | export default reset;
35 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/selectAnnotation.js:
--------------------------------------------------------------------------------
1 | export const SELECT_ANNOTATION = 'SELECT_ANNOTATION';
2 |
3 | const selectAnnotation = (state, payload) => {
4 | if (
5 | state.selectionsIds.length === 1 &&
6 | state.selectionsIds[0] === payload.annotationId
7 | ) {
8 | return state;
9 | }
10 |
11 | let newSelectionsIds;
12 | if (payload.multiple) {
13 | newSelectionsIds = state.selectionsIds.filter(
14 | (id) => id !== payload.annotationId,
15 | );
16 |
17 | const wasAnnotationAlreadySelected =
18 | newSelectionsIds.length !== state.selectionsIds.length;
19 | if (!wasAnnotationAlreadySelected) {
20 | newSelectionsIds.push(payload.annotationId);
21 | }
22 | } else {
23 | newSelectionsIds = [payload.annotationId];
24 | }
25 |
26 | return {
27 | ...state,
28 | selectionsIds: newSelectionsIds,
29 | };
30 | };
31 |
32 | export default selectAnnotation;
33 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/selectTab.js:
--------------------------------------------------------------------------------
1 | import { TABS_TOOLS } from 'components/tools/tools.constants';
2 | import { POINTER_ICONS, TABS_IDS } from 'utils/constants';
3 |
4 | export const SELECT_TAB = 'SELECT_TAB';
5 |
6 | const selectTab = (state, payload) =>
7 | payload.tabId === state.tabId
8 | ? state
9 | : {
10 | ...state,
11 | tabId: payload.tabId,
12 | toolId: TABS_TOOLS[payload.tabId][0],
13 | selectionsIds: [],
14 | pointerCssIcon:
15 | payload.tabId === TABS_IDS.ANNOTATE
16 | ? POINTER_ICONS.DRAW
17 | : POINTER_ICONS.DEFAULT,
18 | };
19 |
20 | export default selectTab;
21 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/selectTool.js:
--------------------------------------------------------------------------------
1 | export const SELECT_TOOL = 'SELECT_TOOL';
2 |
3 | const selectTool = (state, payload) =>
4 | state.toolId === payload.toolId
5 | ? state
6 | : {
7 | ...state,
8 | toolId: payload.toolId,
9 | selectionsIds: payload.keepSelections ? state.selectionsIds : [],
10 | };
11 |
12 | export default selectTool;
13 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setAnnotation.js:
--------------------------------------------------------------------------------
1 | import randomId from 'utils/randomId';
2 |
3 | export const SET_ANNOTATION = 'SET_ANNOTATION';
4 |
5 | const setAnnotation = (state, payload = {}) => {
6 | // dismissHistory is used to prevent considering this change in history (undo/redo).
7 | const {
8 | dismissHistory = false,
9 | replaceCurrent = false,
10 | ...newAnnotation
11 | } = payload;
12 | const annotationId = newAnnotation.id ?? randomId(newAnnotation.name);
13 |
14 | const existedAnnotation = state.annotations[annotationId];
15 | // If annotation not changed don't update it.
16 | if (
17 | existedAnnotation &&
18 | !Object.keys(newAnnotation).some(
19 | (key) =>
20 | (newAnnotation[key] || newAnnotation[key] === 0) &&
21 | newAnnotation[key] !== existedAnnotation[key],
22 | )
23 | ) {
24 | return state;
25 | }
26 |
27 | return {
28 | ...state,
29 | isDesignState: !dismissHistory, // not stored in state, used in reducer to consider in undo/redo stacks
30 | annotations: {
31 | ...state.annotations,
32 | [annotationId]: {
33 | ...(replaceCurrent ? {} : existedAnnotation),
34 | ...newAnnotation,
35 | },
36 | },
37 | };
38 | };
39 |
40 | export default setAnnotation;
41 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setFeedback.js:
--------------------------------------------------------------------------------
1 | export const SET_FEEDBACK = 'SET_FEEDBACK';
2 |
3 | const setFeedback = (state, payload) => ({
4 | ...state,
5 | isLoadingGlobally: false,
6 | feedback: payload.feedback || {},
7 | });
8 |
9 | export default setFeedback;
10 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setFinetune.js:
--------------------------------------------------------------------------------
1 | export const SET_FINETUNE = 'SET_FINETUNE';
2 |
3 | const setFinetune = (state, payload) => ({
4 | ...state,
5 | isDesignState: !payload.dismissHistory, // not stored in state, used in reducer to consider in undo/redo stacks
6 | finetunes:
7 | !payload.finetune || state.finetunes.includes(payload.finetune)
8 | ? state.finetunes
9 | : [...state.finetunes, payload.finetune],
10 | finetunesProps: {
11 | ...state.finetunesProps,
12 | ...payload.finetuneProps,
13 | },
14 | });
15 |
16 | export default setFinetune;
17 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setLatestColor.js:
--------------------------------------------------------------------------------
1 | export const SET_LATEST_COLOR = 'SET_LATEST_COLOR';
2 |
3 | const setLatestColor = (state, payload) => ({
4 | ...state,
5 | latestColors: {
6 | ...state.latestColors,
7 | ...payload.latestColors,
8 | },
9 | });
10 |
11 | export default setLatestColor;
12 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setOriginalImage.js:
--------------------------------------------------------------------------------
1 | export const SET_ORIGINAL_IMAGE = 'SET_ORIGINAL_IMAGE';
2 |
3 | const setOriginalImage = (state, payload) => ({
4 | ...state,
5 | feedback: {},
6 | originalImage: payload.originalImage,
7 | imgSrc: payload.originalImage.src,
8 | });
9 |
10 | export default setOriginalImage;
11 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setResize.js:
--------------------------------------------------------------------------------
1 | export const SET_RESIZE = 'SET_RESIZE';
2 |
3 | const setResize = (state, payload) => ({
4 | ...state,
5 | isDesignState: !payload.dismissHistory,
6 | resize: {
7 | ...state.resize,
8 | // width, height, manualChangeDisabled (false by default), ratioUnlocked (locked by default).
9 | ...payload,
10 | manualChangeDisabled: payload.manualChangeDisabled ?? false,
11 | },
12 | });
13 |
14 | export default setResize;
15 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setSaved.js:
--------------------------------------------------------------------------------
1 | export const SET_SAVED = 'SET_SAVED';
2 |
3 | const setSaved = (state) =>
4 | !state.haveNotSavedChanges ? state : { ...state, haveNotSavedChanges: false };
5 |
6 | export default setSaved;
7 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setSaving.js:
--------------------------------------------------------------------------------
1 | export const SET_SAVING = 'SET_SAVING';
2 |
3 | const setSaving = (state, payload) => ({
4 | ...state,
5 | isSaving: payload.isSaving,
6 | isLoadingGlobally: payload.isSaving,
7 | });
8 |
9 | export default setSaving;
10 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setShowTabsMenu.js:
--------------------------------------------------------------------------------
1 | export const SET_SHOWN_TABS_MENU = 'SET_SHOWN_TABS_MENU';
2 |
3 | const setShowTabsMenu = (state, payload) => ({
4 | ...state,
5 | showTabsMenu: payload.opened,
6 | });
7 |
8 | export default setShowTabsMenu;
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/setShownImageDimensions.js:
--------------------------------------------------------------------------------
1 | export const SET_SHOWN_IMAGE_DIMENSIONS = 'SET_SHOWN_IMAGE_DIMENSIONS';
2 |
3 | const setShownImageDimensions = (state, payload) => ({
4 | ...state,
5 | shownImageDimensions: {
6 | ...state.shownImageDimensions,
7 | ...payload.shownImageDimensions,
8 | },
9 | designLayer: payload.designLayer || state.designLayer,
10 | previewGroup: payload.previewGroup || state.previewGroup,
11 | });
12 |
13 | export default setShownImageDimensions;
14 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/showLoader.js:
--------------------------------------------------------------------------------
1 | export const SHOW_LOADER = 'SHOW_LOADER';
2 |
3 | const showLoader = (state) => ({
4 | ...state,
5 | isLoadingGlobally: true,
6 | });
7 |
8 | export default showLoader;
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/toggleFlip.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import { FLIP_DIRECTIONS } from 'utils/constants';
3 |
4 | export const TOGGLE_FLIP = 'TOGGLE_FLIP';
5 |
6 | const toggleFlip = (state, payload) => {
7 | const flipProperty = `isFlipped${
8 | payload.direction === FLIP_DIRECTIONS.X ? 'X' : 'Y'
9 | }`;
10 |
11 | return {
12 | ...state,
13 | isDesignState: !payload.dismissHistory,
14 | adjustments: {
15 | ...state.adjustments,
16 | [flipProperty]: !state.adjustments[flipProperty],
17 | },
18 | };
19 | };
20 |
21 | export default toggleFlip;
22 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/toggleOriginalImageDisplay.js:
--------------------------------------------------------------------------------
1 | export const TOGGLE_ORIGINAL_IMAGE_DISPLAY = 'TOGGLE_ORIGINAL_IMAGE_DISPLAY';
2 |
3 | const toggleOriginalImageDisplay = (state, payload) => ({
4 | ...state,
5 | isShowOriginalImage: payload.isShow,
6 | });
7 |
8 | export default toggleOriginalImageDisplay;
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/undo.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import extractCurrentDesignState from 'utils/extractCurrentDesignState';
3 |
4 | export const UNDO = 'UNDO';
5 |
6 | const undo = (state) => {
7 | if (state.pastDesignStates && state.pastDesignStates.length > 0) {
8 | const currentDesignState = extractCurrentDesignState(state);
9 | const [presentDesignState, ...newPastDesignStates] = state.pastDesignStates;
10 | const newFutureDesignStates = [
11 | currentDesignState,
12 | ...(state.futureDesignStates || []),
13 | ];
14 |
15 | return {
16 | ...state,
17 | ...presentDesignState,
18 | selectionsIds: [],
19 | pastDesignStates: newPastDesignStates,
20 | futureDesignStates: newFutureDesignStates,
21 | hasUndo: newPastDesignStates.length > 0,
22 | hasRedo: true,
23 | haveNotSavedChanges: newPastDesignStates.length > 0,
24 | };
25 | }
26 |
27 | return state;
28 | };
29 |
30 | export default undo;
31 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/updateState.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import deepMerge from 'utils/deepMerge';
3 |
4 | export const UPDATE_STATE = 'UPDATE_STATE';
5 |
6 | const updateState = (state, payloadObjOrFn) => {
7 | const payload =
8 | payloadObjOrFn && typeof payloadObjOrFn === 'function'
9 | ? payloadObjOrFn(state)
10 | : payloadObjOrFn;
11 | return payload ? deepMerge(state, payload) : state;
12 | };
13 |
14 | export default updateState;
15 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/actions/zoomCanvas.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import calculateZoomData from 'utils/calculateZoomData';
3 | import { DEFAULT_ZOOM_FACTOR } from 'utils/constants';
4 | import restrictNumber from 'utils/restrictNumber';
5 |
6 | export const ZOOM_CANVAS = 'ZOOM_CANVAS';
7 |
8 | const MIN_ZOOM_FACTOR = 0.03;
9 | const MAX_ZOOM_FACTOR = 60;
10 |
11 | const zoomCanvas = (state, payload) => {
12 | const newZoomFactor = restrictNumber(
13 | parseFloat(payload.factor).toFixed(2),
14 | MIN_ZOOM_FACTOR,
15 | MAX_ZOOM_FACTOR,
16 | );
17 |
18 | let newZoomData;
19 |
20 | if (payload.preparedDimensions) {
21 | const { preparedDimensions, ...zoomProps } = payload;
22 | newZoomData = zoomProps;
23 | } else {
24 | const newZoomPoint = {
25 | x:
26 | !payload.x && payload.x !== 0
27 | ? state.canvasWidth / 2
28 | : payload.x ?? state.zoom.x,
29 | y:
30 | !payload.y && payload.y !== 0
31 | ? state.canvasHeight / 2
32 | : payload.y ?? state.zoom.y,
33 | };
34 |
35 | newZoomData = calculateZoomData(
36 | { ...newZoomPoint, factor: newZoomFactor },
37 | // `isAbsoluteZoom` means we don't depend on the old zoom, and we are going to zoom & pan assuming it's happening for firsst time.
38 | payload.isAbsoluteZoom
39 | ? { factor: DEFAULT_ZOOM_FACTOR, x: null, y: null }
40 | : state.zoom,
41 | state.canvasWidth,
42 | state.canvasHeight,
43 | );
44 | }
45 |
46 | return newZoomData.factor === state.zoom.factor &&
47 | newZoomData.x === state.zoom.x &&
48 | newZoomData.y === state.zoom.y
49 | ? state
50 | : {
51 | ...state,
52 | zoom: { ...state.zoom, ...newZoomData },
53 | };
54 | };
55 |
56 | export default zoomCanvas;
57 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/AssemblyPoint/globalStyles.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { createGlobalStyle } from 'styled-components';
3 |
4 | /** Internal Dependencies */
5 | import { ROOT_CONTAINER_CLASS_NAME } from 'utils/constants';
6 |
7 | const FontsFaces = createGlobalStyle`
8 | .${ROOT_CONTAINER_CLASS_NAME} {
9 | font-family: ${({ theme = {} }) => theme.typography?.fontFamily || 'Arial'};
10 | }
11 |
12 | .SfxModal-Wrapper * {
13 | font-family: ${({ theme = {} }) => theme.typography?.fontFamily || 'Arial'};
14 | }
15 | `;
16 |
17 | const OverrideDefaultStyles = createGlobalStyle`
18 | .Menu-open {
19 | overflow: visible !important;
20 | }
21 |
22 | .${ROOT_CONTAINER_CLASS_NAME}, #SfxPopper {
23 | box-sizing: border-box;
24 |
25 | .SfxPopper-root .SfxMenu-root {
26 | overflow: visible;
27 | width: max-content;
28 |
29 | .SfxMenuItem-prefix {
30 | margin-right: 6px;
31 | }
32 | }
33 | }
34 | .${ROOT_CONTAINER_CLASS_NAME} *, #SfxPopper * {
35 | box-sizing: border-box;
36 | scrollbar-color: rgba(203, 211, 218, 1) rgba(203, 211, 218, 0.35);
37 |
38 | :not(button) > svg:not([color]) {
39 | color: ${({ theme }) => theme.palette['icons-primary']}
40 | }
41 |
42 | :disabled, [aria-disabled="true"] {
43 | cursor: not-allowed;
44 | }
45 |
46 | &::-webkit-scrollbar {
47 | width: 4px;
48 | height: 4px;
49 | }
50 |
51 | &::-webkit-scrollbar-track {
52 | background: rgba(203, 211, 218, 0.35);
53 | }
54 |
55 | &::-webkit-scrollbar-thumb {
56 | background: rgba(203, 211, 218, 1);
57 | border-radius: 10px;
58 | }
59 | }
60 | `;
61 |
62 | export { FontsFaces, OverrideDefaultStyles };
63 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/FeedbackPopup/index.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import Popup from '@scaleflex/ui/core/popup';
5 |
6 | /** Internal Dependencies */
7 | import { SET_FEEDBACK } from 'actions';
8 | import { useStore } from 'hooks';
9 | import { FEEDBACK_STATUSES } from 'utils/constants';
10 |
11 | const defaultAnchorOrigin = {
12 | horizontal: 'center',
13 | vertical: 'bottom',
14 | };
15 |
16 | const ERROR_TO_ROBOT_STATUS = {
17 | [FEEDBACK_STATUSES.ERROR]: 'error',
18 | [FEEDBACK_STATUSES.WARNING]: 'warning',
19 | };
20 |
21 | const FeedbackPopup = ({ anchorOrigin }) => {
22 | const { feedback = {}, dispatch } = useStore();
23 |
24 | if (!feedback.message) {
25 | return null;
26 | }
27 |
28 | const onClose = () => {
29 | dispatch({
30 | type: SET_FEEDBACK,
31 | payload: {
32 | feedback: {},
33 | },
34 | });
35 | };
36 |
37 | return (
38 |
47 | );
48 | };
49 |
50 | FeedbackPopup.defaultProps = {
51 | anchorOrigin: defaultAnchorOrigin,
52 | };
53 |
54 | FeedbackPopup.propTypes = {
55 | anchorOrigin: PropTypes.instanceOf(Object),
56 | };
57 |
58 | export default FeedbackPopup;
59 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/DesignLayer/AnnotationNodes/AnnotationNodes.constants.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import { TOOLS_IDS } from 'utils/constants';
3 | import RectNode from './RectNode';
4 | import EllipseNode from './EllipseNode';
5 | import PolygonNode from './PolygonNode';
6 | import TextNode from './TextNode';
7 | import ImageNode from './ImageNode';
8 | import LineNode from './LineNode';
9 | import ArrowNode from './ArrowNode';
10 |
11 | export const ANNOTATION_NAMES_TO_COMPONENT = {
12 | [TOOLS_IDS.RECT]: RectNode,
13 | [TOOLS_IDS.ELLIPSE]: EllipseNode,
14 | [TOOLS_IDS.POLYGON]: PolygonNode,
15 | [TOOLS_IDS.TEXT]: TextNode,
16 | [TOOLS_IDS.IMAGE]: ImageNode,
17 | [TOOLS_IDS.LINE]: LineNode,
18 | [TOOLS_IDS.ARROW]: ArrowNode,
19 | [TOOLS_IDS.PEN]: LineNode,
20 | };
21 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/DesignLayer/AnnotationNodes/EllipseNode.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Ellipse } from 'react-konva';
5 |
6 | /** Internal Dependencies */
7 | import nodesCommonPropTypes from '../nodesCommonPropTypes';
8 |
9 | const EllipseNode = ({
10 | id,
11 | name,
12 | fill,
13 | x,
14 | y,
15 | radiusX,
16 | radiusY,
17 | scaleX,
18 | scaleY,
19 | rotation,
20 | annotationEvents,
21 | stroke,
22 | strokeWidth,
23 | shadowOffsetX,
24 | shadowOffsetY,
25 | shadowBlur,
26 | shadowColor,
27 | shadowOpacity,
28 | opacity,
29 | ...otherProps
30 | }) => (
31 |
55 | );
56 |
57 | EllipseNode.defaultProps = {
58 | ...nodesCommonPropTypes.defaults,
59 | fill: '#000',
60 | radiusX: 0,
61 | radiusY: 0,
62 | };
63 |
64 | EllipseNode.propTypes = {
65 | ...nodesCommonPropTypes.definitions,
66 | x: PropTypes.number.isRequired,
67 | y: PropTypes.number.isRequired,
68 | annotationEvents: PropTypes.instanceOf(Object).isRequired,
69 | radiusX: PropTypes.number,
70 | radiusY: PropTypes.number,
71 | fill: PropTypes.string,
72 | };
73 |
74 | export default EllipseNode;
75 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/DesignLayer/AnnotationNodes/LineNode.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Line } from 'react-konva';
5 |
6 | /** Internal Dependencies */
7 | import nodesCommonPropTypes from '../nodesCommonPropTypes';
8 |
9 | const LineNode = ({
10 | id,
11 | name,
12 | scaleX,
13 | scaleY,
14 | rotation,
15 | annotationEvents,
16 | points,
17 | lineCap,
18 | stroke,
19 | strokeWidth,
20 | shadowOffsetX,
21 | shadowOffsetY,
22 | shadowBlur,
23 | shadowColor,
24 | shadowOpacity,
25 | tension,
26 | opacity,
27 | ...otherProps
28 | }) => (
29 |
52 | );
53 |
54 | LineNode.defaultProps = {
55 | ...nodesCommonPropTypes.defaults,
56 | stroke: '#000000',
57 | strokeWidth: 1,
58 | lineCap: 'butt', // butt/round/square
59 | annotationEvents: {},
60 | tension: undefined,
61 | };
62 |
63 | LineNode.propTypes = {
64 | ...nodesCommonPropTypes.definitions,
65 | points: PropTypes.instanceOf(Array).isRequired,
66 | annotationEvents: PropTypes.instanceOf(Object),
67 | lineCap: PropTypes.string,
68 | tension: PropTypes.number,
69 | };
70 |
71 | export default LineNode;
72 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/DesignLayer/AnnotationNodes/MemoizedAnnotation.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React, { memo } from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { ANNOTATION_NAMES_TO_COMPONENT } from './AnnotationNodes.constants';
7 |
8 | const MemoizedAnnotation = ({
9 | annotation,
10 | annotationEvents,
11 | selectionsIds,
12 | }) => {
13 | const AnnotationComponent = ANNOTATION_NAMES_TO_COMPONENT[annotation.name];
14 | if (!AnnotationComponent) return null;
15 |
16 | return (
17 |
23 | );
24 | };
25 |
26 | MemoizedAnnotation.propTypes = {
27 | annotation: PropTypes.instanceOf(Object).isRequired,
28 | annotationEvents: PropTypes.instanceOf(Object).isRequired,
29 | selectionsIds: PropTypes.instanceOf(Object).isRequired,
30 | };
31 |
32 | export default memo(MemoizedAnnotation);
33 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/DesignLayer/AnnotationNodes/PolygonNode.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { RegularPolygon } from 'react-konva';
5 |
6 | /** Internal Dependencies */
7 | import nodesCommonPropTypes from '../nodesCommonPropTypes';
8 |
9 | const PolygonNode = ({
10 | id,
11 | name,
12 | fill,
13 | x,
14 | y,
15 | radius,
16 | scaleX,
17 | scaleY,
18 | rotation,
19 | sides,
20 | annotationEvents,
21 | stroke,
22 | strokeWidth,
23 | shadowOffsetX,
24 | shadowOffsetY,
25 | shadowBlur,
26 | shadowColor,
27 | shadowOpacity,
28 | opacity,
29 | ...otherProps
30 | }) => (
31 |
55 | );
56 |
57 | PolygonNode.defaultProps = {
58 | ...nodesCommonPropTypes.defaults,
59 | fill: '#000',
60 | sides: 3,
61 | };
62 |
63 | PolygonNode.propTypes = {
64 | ...nodesCommonPropTypes.definitions,
65 | x: PropTypes.number.isRequired,
66 | y: PropTypes.number.isRequired,
67 | annotationEvents: PropTypes.instanceOf(Object).isRequired,
68 | radius: PropTypes.number.isRequired,
69 | fill: PropTypes.string,
70 | sides: PropTypes.number,
71 | };
72 |
73 | export default PolygonNode;
74 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/DesignLayer/AnnotationNodes/RectNode.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Rect } from 'react-konva';
5 |
6 | /** Internal Dependencies */
7 | import nodesCommonPropTypes from '../nodesCommonPropTypes';
8 |
9 | const RectNode = ({
10 | id,
11 | name,
12 | fill,
13 | x,
14 | y,
15 | width,
16 | height,
17 | scaleX,
18 | scaleY,
19 | rotation,
20 | annotationEvents,
21 | stroke,
22 | strokeWidth,
23 | shadowOffsetX,
24 | shadowOffsetY,
25 | shadowBlur,
26 | shadowColor,
27 | shadowOpacity,
28 | opacity,
29 | cornerRadius,
30 | ...otherProps
31 | }) => (
32 |
55 | );
56 |
57 | RectNode.defaultProps = {
58 | ...nodesCommonPropTypes.defaults,
59 | fill: '#000',
60 | cornerRadius: 0,
61 | width: 0,
62 | height: 0,
63 | };
64 |
65 | RectNode.propTypes = {
66 | ...nodesCommonPropTypes.definitions,
67 | x: PropTypes.number.isRequired,
68 | y: PropTypes.number.isRequired,
69 | annotationEvents: PropTypes.instanceOf(Object).isRequired,
70 | width: PropTypes.number,
71 | height: PropTypes.number,
72 | fill: PropTypes.string,
73 | cornerRadius: PropTypes.number,
74 | };
75 |
76 | export default RectNode;
77 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/DesignLayer/AnnotationNodes/index.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React, { useMemo } from 'react';
3 |
4 | /** Internal Dependencies */
5 | import { useAnnotationEvents, useStore } from 'hooks';
6 | import MemoizedAnnotation from './MemoizedAnnotation';
7 |
8 | const AnnotationNodes = () => {
9 | const { annotations = {}, selectionsIds = [] } = useStore();
10 | const annotationEvents = useAnnotationEvents();
11 |
12 | return useMemo(
13 | () =>
14 | Object.values(annotations).map((annotation) => (
15 |
21 | )),
22 | [annotations, annotationEvents, selectionsIds],
23 | );
24 | };
25 |
26 | export default AnnotationNodes;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/DesignLayer/PreviewGroup.jsx:
--------------------------------------------------------------------------------
1 | import React, { forwardRef } from 'react';
2 | import { Group } from 'react-konva';
3 |
4 | const PreviewGroup = (props, ref) => {
5 | return ;
6 | };
7 |
8 | export default forwardRef(PreviewGroup);
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/DesignLayer/nodesCommonPropTypes.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 |
3 | const nodesCommonPropTypes = {
4 | definitions: {
5 | id: PropTypes.string.isRequired,
6 | name: PropTypes.string.isRequired,
7 | rotation: PropTypes.number,
8 | scaleX: PropTypes.number,
9 | scaleY: PropTypes.number,
10 | stroke: PropTypes.string,
11 | strokeWidth: PropTypes.number,
12 | shadowOffsetX: PropTypes.number,
13 | shadowOffsetY: PropTypes.number,
14 | shadowBlur: PropTypes.number,
15 | shadowColor: PropTypes.string,
16 | shadowOpacity: PropTypes.number,
17 | opacity: PropTypes.number,
18 | },
19 | defaults: {
20 | rotation: 0,
21 | scaleX: 1,
22 | scaleY: 1,
23 | stroke: undefined,
24 | strokeWidth: undefined,
25 | shadowOffsetX: undefined,
26 | shadowOffsetY: undefined,
27 | shadowBlur: undefined,
28 | shadowColor: undefined,
29 | shadowOpacity: undefined,
30 | opacity: 1,
31 | },
32 | };
33 |
34 | export default nodesCommonPropTypes;
35 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/TransformersLayer/index.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import { Layer } from 'react-konva';
4 |
5 | /** Internal Dependencies */
6 | import { useStore } from 'hooks';
7 | import { TOOLS_IDS, TRANSFORMERS_LAYER_ID } from 'utils/constants';
8 | import CropTransformer from './CropTransformer';
9 | import NodesTransformer from './NodesTransformer';
10 |
11 | const TransformersLayer = () => {
12 | const { toolId, shownImageDimensions } = useStore();
13 |
14 | return (
15 |
20 |
21 | {toolId === TOOLS_IDS.CROP && }
22 |
23 | );
24 | };
25 |
26 | export default TransformersLayer;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Layers/index.js:
--------------------------------------------------------------------------------
1 | export { default as DesignLayer } from './DesignLayer';
2 |
3 | export { default as TransformersLayer } from './TransformersLayer';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/MainCanvas/MainCanvas.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { Stage } from 'react-konva';
3 | import styled from 'styled-components';
4 |
5 | const CanvasContainer = styled.div`
6 | width: 100%;
7 | position: relative;
8 | // backup for flex-grow, 94px, 12px = toolsbar's maxheight, app container padding.
9 | height: calc(100% - 112px - 16px);
10 | overflow: hidden;
11 | min-height: 250px;
12 | padding: 16px;
13 | flex-grow: 1;
14 | `;
15 |
16 | const StyledOrignalImage = styled.img`
17 | max-width: 98%;
18 | max-height: 98%;
19 | box-shadow: 0 0 0 5px rgba(0, 0, 0, 0.1);
20 | position: absolute;
21 | top: 50%;
22 | left: 50%;
23 | transform: translate(-50%, -50%);
24 | z-index: 2;
25 | `;
26 |
27 | const StyledCanvasNode = styled(Stage)`
28 | outline: none;
29 | background: ${({ theme }) => theme.palette['bg-hover']};
30 | `;
31 |
32 | export { CanvasContainer, StyledOrignalImage, StyledCanvasNode };
33 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/NodeControls/NodeControls.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 |
4 | const StyledNodeControls = styled.div(
5 | ({ theme, top, left }) => `
6 | position: absolute;
7 | z-index: 1;
8 | background: ${theme.palette['bg-secondary']};
9 | border-radius: 2px;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | box-shadow: 0px 1px 2px ${theme.palette['light-shadow']};
14 | top: ${(top || 0) + 8}px;
15 | left: ${(left || 0) + 4}px;
16 | transform: translateX(-50%);
17 | height: 32px;
18 | `,
19 | );
20 |
21 | export { StyledNodeControls };
22 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Tabs/TabItem.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React, { useCallback, memo } from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { StyledTabItem, StyledTabItemLabel } from './Tabs.styled';
7 |
8 | const TabItem = ({ id, label, Icon, isSelected, onClick }) => {
9 | const handleClick = useCallback(() => {
10 | if (typeof onClick === 'function') {
11 | onClick(id);
12 | }
13 | }, [id]);
14 |
15 | return (
16 |
21 |
22 | {label && (
23 |
24 | {label}
25 |
26 | )}
27 |
28 | );
29 | };
30 |
31 | TabItem.defaultProps = {
32 | isSelected: false,
33 | onClick: undefined,
34 | label: undefined,
35 | };
36 |
37 | TabItem.propTypes = {
38 | id: PropTypes.string.isRequired,
39 | label: PropTypes.string,
40 | Icon: PropTypes.oneOfType([
41 | PropTypes.node,
42 | PropTypes.func,
43 | PropTypes.instanceOf(Object),
44 | ]).isRequired,
45 | onClick: PropTypes.func,
46 | isSelected: PropTypes.bool,
47 | };
48 |
49 | export default memo(TabItem);
50 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Tabs/Tabs.constants.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import {
3 | FineTune,
4 | Annotate,
5 | CropFrame,
6 | ImageFilters,
7 | Watermark,
8 | Resize,
9 | } from '@scaleflex/icons';
10 |
11 | /** Internal Dependencies */
12 | import { TABS_IDS } from 'utils/constants';
13 |
14 | export const AVAILABLE_TABS = [
15 | {
16 | id: TABS_IDS.ADJUST,
17 | labelKey: 'adjustTab',
18 | icon: CropFrame,
19 | },
20 | {
21 | id: TABS_IDS.FINETUNE,
22 | labelKey: 'finetuneTab',
23 | icon: FineTune,
24 | },
25 | {
26 | id: TABS_IDS.FILTERS,
27 | labelKey: 'filtersTab',
28 | icon: ImageFilters,
29 | hideFn: ({ useCloudimage }) => useCloudimage,
30 | },
31 | {
32 | id: TABS_IDS.WATERMARK,
33 | labelKey: 'watermarkTab',
34 | icon: Watermark,
35 | },
36 | {
37 | id: TABS_IDS.ANNOTATE,
38 | labelKey: 'annotateTabLabel',
39 | icon: Annotate,
40 | hideFn: ({ useCloudimage }) => useCloudimage,
41 | },
42 | {
43 | id: TABS_IDS.RESIZE,
44 | labelKey: 'resizeTab',
45 | icon: Resize,
46 | },
47 | ];
48 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Tabs/Tabs.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 | import Label from '@scaleflex/ui/core/label';
4 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
5 | import { FontVariant as FV } from '@scaleflex/ui/utils/types/typography';
6 |
7 | const StyledTabItem = styled.div(
8 | ({ theme }) => `
9 | width: 72px;
10 | min-height: 66px;
11 | padding: 4px 2px;
12 | border-radius: 4px;
13 | display: flex;
14 | flex-direction: column;
15 | gap: 6px;
16 | background: ${theme.palette[PC.BackgroundStateless]};
17 | align-items: center;
18 | justify-content: center;
19 |
20 | [data-phone='true'] & {
21 | margin-bottom: 0;
22 | height: 50px;
23 | border-radius: 0;
24 | }
25 |
26 | svg {
27 | color: ${theme.palette[PC.IconsPrimary]};
28 | }
29 |
30 | &,
31 | * {
32 | cursor: pointer;
33 | }
34 |
35 | &:hover {
36 | background: ${theme.palette['bg-primary-active']};
37 | }
38 |
39 | &[aria-selected='true'] {
40 | background: ${theme.palette['bg-primary-active']};
41 |
42 | * {
43 | color: ${theme.palette['accent-primary-active']};
44 | }
45 | }
46 | `,
47 | );
48 |
49 | const StyledTabItemLabel = styled(Label)(
50 | ({ theme }) => `
51 | color: ${theme.palette[PC.TextPrimary]};
52 | ${theme.typography.font[FV.LabelSmall]};
53 | font-size: 12px;
54 | line-height: 14px;
55 |
56 | span {
57 | white-space: normal;
58 | }
59 |
60 | [data-phone='true'] & {
61 | font-size: 10px;
62 | }
63 | `,
64 | );
65 |
66 | export { StyledTabItem, StyledTabItemLabel };
67 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/TabsDrawer/index.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import {
5 | DrawerBody,
6 | DrawerHeader,
7 | DrawerList,
8 | } from '@scaleflex/ui/core/drawer';
9 | import { Menu } from '@scaleflex/icons';
10 | import { Button } from '@scaleflex/ui/core';
11 |
12 | /** Internal Dependencies */
13 | import { useStore } from 'hooks';
14 | import { StyledDrawer } from 'components/App/App.styled';
15 | import Tabs from 'components/Tabs';
16 |
17 | const TabsDrawer = ({ toggleMainMenu }) => {
18 | const { t, showTabsMenu } = useStore();
19 |
20 | return (
21 | toggleMainMenu(false)}
25 | disablePortal
26 | >
27 |
28 | }
31 | onClick={() => toggleMainMenu(false)}
32 | >
33 | {t('tabsMenu')}
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | );
43 | };
44 |
45 | TabsDrawer.defaultProps = {
46 | toggleMainMenu: () => {},
47 | };
48 |
49 | TabsDrawer.propTypes = {
50 | toggleMainMenu: PropTypes.func,
51 | };
52 |
53 | export default TabsDrawer;
54 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/ToolsBar/ToolsBarItemButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React, { memo } from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { usePhoneScreen } from 'hooks';
7 | import {
8 | StyledToolsBarItemButton,
9 | StyledToolsBarItemButtonLabel,
10 | } from './ToolsBar.styled';
11 |
12 | const ToolsBarItemButton = ({
13 | id,
14 | label,
15 | onClick,
16 | Icon,
17 | isSelected,
18 | children,
19 | className,
20 | }) => {
21 | const isPhoneScreen = usePhoneScreen(320);
22 |
23 | const handleClick = (e) => {
24 | onClick(id, e);
25 | };
26 |
27 | return (
28 |
34 |
35 | {label && (
36 |
37 | {label}
38 |
39 | )}
40 | {children}
41 |
42 | );
43 | };
44 |
45 | ToolsBarItemButton.defaultProps = {
46 | isSelected: false,
47 | id: undefined,
48 | children: null,
49 | label: '',
50 | };
51 |
52 | ToolsBarItemButton.propTypes = {
53 | children: PropTypes.node,
54 | id: PropTypes.string,
55 | label: PropTypes.string,
56 | onClick: PropTypes.func.isRequired,
57 | className: PropTypes.string.isRequired,
58 | isSelected: PropTypes.bool,
59 | Icon: PropTypes.oneOfType([
60 | PropTypes.node,
61 | PropTypes.func,
62 | PropTypes.instanceOf(Object),
63 | ]).isRequired,
64 | };
65 |
66 | export default memo(ToolsBarItemButton);
67 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/ToolsBar/ToolsBarItemOptionsWrapper.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { StyledToolsBarItemOptionsWrapper } from './ToolsBar.styled';
7 |
8 | const ToolsBarItemOptionsWrapper = ({ children, isPhoneScreen }) => (
9 |
14 | {children}
15 |
16 | );
17 |
18 | ToolsBarItemOptionsWrapper.defaultProps = {
19 | children: undefined,
20 | isPhoneScreen: false,
21 | };
22 |
23 | ToolsBarItemOptionsWrapper.propTypes = {
24 | children: PropTypes.node,
25 | isPhoneScreen: PropTypes.bool,
26 | };
27 |
28 | export default ToolsBarItemOptionsWrapper;
29 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Topbar/BackButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import { Button } from '@scaleflex/ui/core';
4 | import ArrowLeftOutline from '@scaleflex/icons/arrow-left-outline';
5 |
6 | /** Internal Dependencies */
7 | import { usePhoneScreen, useStore } from 'hooks';
8 | import { StyledBackButtonLabel } from './Topbar.styled';
9 | import ConfirmationModal from './ConfirmationModal';
10 |
11 | const BackButton = () => {
12 | const { t } = useStore();
13 | const isPhone = usePhoneScreen();
14 |
15 | return (
16 |
17 | }
22 | >
23 | {!isPhone && {t('back')}}
24 |
25 |
26 | );
27 | };
28 |
29 | export default BackButton;
30 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Topbar/CloseButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import CrossOutline from '@scaleflex/icons/cross-outline';
4 |
5 | /** Internal Dependencies */
6 | import { useStore } from 'hooks';
7 | import Separator from 'components/common/Separator';
8 | import { StyledCloseButton } from './Topbar.styled';
9 | import ConfirmationModal from './ConfirmationModal';
10 |
11 | const CloseButton = () => {
12 | const {
13 | config: { onClose },
14 | } = useStore();
15 |
16 | if (typeof onClose !== 'function') {
17 | return null;
18 | }
19 |
20 | return (
21 | <>
22 |
23 |
24 |
29 |
30 |
31 |
32 | >
33 | );
34 | };
35 |
36 | export default CloseButton;
37 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Topbar/RedoButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React, { useCallback } from 'react';
3 | import PropTypes from 'prop-types';
4 | import Redo from '@scaleflex/icons/redo';
5 |
6 | /** Internal Dependencies */
7 | import { REDO } from 'actions';
8 | import { useStore } from 'hooks';
9 | import { StyledHistoryButton } from './Topbar.styled';
10 |
11 | const RedoButton = ({ margin }) => {
12 | const { dispatch, hasRedo = false, t } = useStore();
13 | const dispatchRedo = useCallback(() => {
14 | dispatch({ type: REDO });
15 | }, []);
16 |
17 | return (
18 |
27 |
28 |
29 | );
30 | };
31 |
32 | RedoButton.defaultProps = {
33 | margin: undefined,
34 | };
35 |
36 | RedoButton.propTypes = {
37 | margin: PropTypes.string,
38 | };
39 |
40 | export default RedoButton;
41 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Topbar/ResetButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import Reset from '@scaleflex/icons/reset';
5 |
6 | /** Internal Dependencies */
7 | import { useStore } from 'hooks';
8 | import { StyledHistoryButton } from './Topbar.styled';
9 | import ConfirmationModal from './ConfirmationModal';
10 |
11 | const ResetButton = ({ margin }) => {
12 | const { isResetted = true, feedback, t } = useStore();
13 |
14 | const isBlockerError = feedback.duration === 0;
15 |
16 | return (
17 |
18 |
26 |
27 |
28 |
29 | );
30 | };
31 |
32 | ResetButton.defaultProps = {
33 | margin: undefined,
34 | };
35 |
36 | ResetButton.propTypes = {
37 | margin: PropTypes.string,
38 | };
39 |
40 | export default ResetButton;
41 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Topbar/Topbar.constants.js:
--------------------------------------------------------------------------------
1 | export const ZOOM_FACTORS_PRESETS = [
2 | {
3 | labelKey: 'fitSize',
4 | factor: 'fit',
5 | },
6 | {
7 | labelKey: 'actualSize',
8 | factor: 1,
9 | },
10 | {
11 | label: '25%',
12 | factor: 0.25,
13 | },
14 | {
15 | label: '50%',
16 | factor: 0.5,
17 | },
18 | {
19 | label: '75%',
20 | factor: 0.75,
21 | },
22 | {
23 | label: '125%',
24 | factor: 1.25,
25 | },
26 | {
27 | label: '170%',
28 | factor: 1.7,
29 | },
30 | {
31 | label: '300%',
32 | factor: 3,
33 | },
34 | {
35 | label: '500%',
36 | factor: 5,
37 | },
38 | {
39 | label: '1000%',
40 | factor: 10,
41 | },
42 | ];
43 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/Topbar/UndoButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React, { useCallback } from 'react';
3 | import PropTypes from 'prop-types';
4 | import Undo from '@scaleflex/icons/undo';
5 |
6 | /** Internal Dependencies */
7 | import { UNDO } from 'actions';
8 | import { useStore } from 'hooks';
9 | import { StyledHistoryButton } from './Topbar.styled';
10 |
11 | const UndoButton = ({ margin }) => {
12 | const { dispatch, hasUndo = false, t, feedback } = useStore();
13 | const isBlockerError = feedback.duration === 0;
14 | const dispatchUndo = useCallback(() => {
15 | dispatch({ type: UNDO });
16 | }, []);
17 |
18 | return (
19 |
28 |
29 |
30 | );
31 | };
32 |
33 | UndoButton.defaultProps = {
34 | margin: undefined,
35 | };
36 |
37 | UndoButton.propTypes = {
38 | margin: PropTypes.string,
39 | };
40 |
41 | export default UndoButton;
42 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/AnnotationOptions/AnnotationOptions.constants.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import { POSITIONS } from 'utils/constants';
3 |
4 | export const AVAILABLE_POSITIONS = Object.values(POSITIONS);
5 |
6 | export const posCssRotateDegFromRightSide = {
7 | [POSITIONS.TOP_LEFT]: -145,
8 | [POSITIONS.TOP_CENTER]: -90,
9 | [POSITIONS.TOP_RIGHT]: -45,
10 | [POSITIONS.MIDDLE_LEFT]: 180,
11 | [POSITIONS.MIDDLE_CENTER]: 0,
12 | [POSITIONS.MIDDLE_RIGHT]: 0,
13 | [POSITIONS.BOTTOM_LEFT]: 135,
14 | [POSITIONS.BOTTOM_CENTER]: 90,
15 | [POSITIONS.BOTTOM_RIGHT]: 45,
16 | };
17 |
18 | export const POPPABLE_OPTIONS = {
19 | OPACITY: 'opacity',
20 | STROKE: 'stroke',
21 | SHADOW: 'shadow',
22 | POSITION: 'position',
23 | };
24 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/AnnotationOptions/OpacityField.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import restrictNumber from 'utils/restrictNumber';
7 | import { Label } from '@scaleflex/ui/core';
8 | import {
9 | StyledSpacedOptionFields,
10 | StyledIconLabel,
11 | StyledOptionPopupContent,
12 | } from './AnnotationOptions.styled';
13 | import Slider from '../Slider';
14 |
15 | const MIN_PERCENTANGE = 0;
16 | const MAX_PERCENTANGE = 1;
17 |
18 | const OpacityField = ({ annotation, updateAnnotation, t }) => {
19 | const { opacity } = annotation;
20 | const opacityValue = Math.round(opacity * 100);
21 |
22 | const changeOpacity = (newOpactiy) => {
23 | updateAnnotation({
24 | opacity: restrictNumber(
25 | newOpactiy / 100,
26 | MIN_PERCENTANGE,
27 | MAX_PERCENTANGE,
28 | ),
29 | });
30 | };
31 |
32 | return (
33 |
34 |
35 |
36 |
42 | {`${opacityValue}%`}
43 |
44 |
45 | );
46 | };
47 |
48 | OpacityField.propTypes = {
49 | annotation: PropTypes.instanceOf(Object).isRequired,
50 | t: PropTypes.func.isRequired,
51 | updateAnnotation: PropTypes.func.isRequired,
52 | };
53 |
54 | export default OpacityField;
55 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/AnnotationOptions/StrokeFields.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import restrictNumber from 'utils/restrictNumber';
7 | import ColorInput from 'components/common/ColorInput';
8 | import { StyledSpacedOptionFields } from './AnnotationOptions.styled';
9 | import Slider from '../Slider';
10 |
11 | const MIN_PERCENTANGE = 0;
12 | const MAX_PERCENTANGE = 100;
13 |
14 | const StrokeFields = ({ annotation, updateAnnotation }) => {
15 | const { stroke, strokeWidth } = annotation;
16 |
17 | const changeStrokeWidth = (newStrokeWidth) => {
18 | updateAnnotation({
19 | strokeWidth: restrictNumber(
20 | newStrokeWidth,
21 | MIN_PERCENTANGE,
22 | MAX_PERCENTANGE,
23 | ),
24 | });
25 | };
26 |
27 | const changeStrokeColor = (newStrokeColor) => {
28 | updateAnnotation({ stroke: newStrokeColor });
29 | };
30 |
31 | return (
32 |
33 |
39 |
44 |
45 | );
46 | };
47 |
48 | StrokeFields.propTypes = {
49 | annotation: PropTypes.instanceOf(Object).isRequired,
50 | updateAnnotation: PropTypes.func.isRequired,
51 | };
52 |
53 | export default StrokeFields;
54 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/ButtonWithMenu/ButtonWithMenu.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 | import Button from '@scaleflex/ui/core/button';
4 | import { Color as PC } from '@scaleflex/ui/utils/types/palette/color';
5 | import { Menu, MenuItem, MenuItemIcon } from '@scaleflex/ui/core';
6 |
7 | const StyledButtonWrapper = styled.div`
8 | display: flex;
9 | align-items: center;
10 | margin-left: ${({ noMargin }) => (noMargin ? '0' : '12px')};
11 | flex-shrink: 0;
12 | `;
13 |
14 | const StyledMainButton = styled(Button)`
15 | flex-grow: 1;
16 | justify-content: center;
17 | align-items: center;
18 | `;
19 |
20 | const StyledMenu = styled(Menu)`
21 | padding: 8px;
22 | background-color: ${({ theme: { palette } }) =>
23 | palette[PC.BackgroundStateless]};
24 | `;
25 |
26 | const StyledMenuItem = styled(MenuItem)`
27 | border-radius: 4px;
28 | `;
29 |
30 | const StyledMenuIcon = styled(MenuItemIcon)`
31 | display: flex;
32 | align-items: center;
33 | `;
34 |
35 | export {
36 | StyledButtonWrapper,
37 | StyledMainButton,
38 | StyledMenu,
39 | StyledMenuItem,
40 | StyledMenuIcon,
41 | };
42 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/Carousel/Carousel.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled, { css } from 'styled-components';
3 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
4 |
5 | const StyledCarouselWrapper = styled.div`
6 | max-width: 680px;
7 | min-width: 150px;
8 | position: relative;
9 | overflow: hidden;
10 | touch-action: pan-y pinch-zoom;
11 | `;
12 |
13 | const StyledCarousel = styled.ul`
14 | padding: 0;
15 | margin: 0;
16 | white-space: nowrap;
17 | overflow: hidden;
18 | `;
19 |
20 | const StyledCarouselItem = styled.li`
21 | padding: 4px;
22 | display: inline-block;
23 | list-style-type: none;
24 | user-select: none;
25 | `;
26 |
27 | const arrowsCommonStyles = css`
28 | position: absolute;
29 | top: 0;
30 | height: 100%;
31 | width: 60px;
32 | cursor: pointer;
33 | display: flex;
34 | align-items: center;
35 | justify-content: center;
36 | z-index: 1;
37 |
38 | svg {
39 | color: ${({ theme: { palette } }) => palette[PC.IconsSecondary]};
40 | }
41 | `;
42 |
43 | const StyledPrevArrowWrapper = styled.div`
44 | ${arrowsCommonStyles}
45 | left: 0;
46 | justify-content: flex-start;
47 | background: linear-gradient(
48 | 90deg,
49 | #ffffff 1.56%,
50 | rgba(255, 255, 255, 0.89) 52.4%,
51 | rgba(255, 255, 255, 0.532165) 76.04%,
52 | rgba(255, 255, 255, 0) 100%
53 | );
54 | `;
55 |
56 | const StyledNextArrowWrapper = styled.div`
57 | ${arrowsCommonStyles}
58 | right: 0;
59 | justify-content: flex-end;
60 | background: linear-gradient(
61 | 270deg,
62 | #ffffff 1.56%,
63 | rgba(255, 255, 255, 0.89) 52.4%,
64 | rgba(255, 255, 255, 0.532165) 76.04%,
65 | rgba(255, 255, 255, 0) 100%
66 | );
67 | `;
68 |
69 | export {
70 | StyledCarouselWrapper,
71 | StyledCarousel,
72 | StyledCarouselItem,
73 | StyledPrevArrowWrapper,
74 | StyledNextArrowWrapper,
75 | };
76 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/ColorInput/ColorInput.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
4 |
5 | const StyledPickerTrigger = styled.div.attrs(({ $color }) => ({
6 | style: {
7 | background:
8 | $color === 'rgba(0,0,0,0)'
9 | ? 'repeating-conic-gradient(#5d6d7e 0% 25%, transparent 0% 50%) 50% / 8px 8px'
10 | : $color,
11 | },
12 | }))`
13 | background: ${({ theme }) => theme.palette['icons-primary']};
14 | border-radius: 4px;
15 | width: 32px;
16 | height: 32px;
17 | border: 1px solid ${({ theme }) => theme.palette[PC.BorderPrimaryStateless]};
18 | cursor: pointer;
19 | box-sizing: border-box;
20 | `;
21 |
22 | export { StyledPickerTrigger };
23 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/ColorPickerModal/ColorPickerModal.styled.js:
--------------------------------------------------------------------------------
1 | import { Modal, ModalActions as SfxModalActions } from '@scaleflex/ui/core';
2 | import styled from 'styled-components';
3 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
4 |
5 | const ColorPickerModal = styled(Modal)`
6 | max-width: 350px;
7 | `;
8 |
9 | const ColorPickerWrap = styled.div`
10 | .SfxColorPicker-root {
11 | max-width: 100%;
12 | padding: 0;
13 | box-shadow: none;
14 | border: none;
15 | ${({ hideModalTitle }) => hideModalTitle && 'padding-top: 12px;'}
16 | }
17 |
18 | .SfxColorPicker-action {
19 | display: flex;
20 | gap: 12px;
21 |
22 | .SfxColorPicker-select {
23 | width: 100px;
24 | }
25 | .SfxInput-root {
26 | width: 190px !important;
27 | }
28 | }
29 |
30 | .SfxColorPicker-icon {
31 | color: ${({ theme: { palette } }) => palette[PC.IconsPrimary]};
32 | }
33 |
34 | .SfxColorPicker-range-picker,
35 | .SfxColorPicker-bar-wrapper {
36 | width: 100%;
37 | }
38 | `;
39 |
40 | const ModalActions = styled(SfxModalActions)`
41 | gap: 12px;
42 | padding: 24px;
43 |
44 | .SfxButton-root {
45 | flex: 1;
46 | margin: 0;
47 | height: 40px;
48 | }
49 | `;
50 |
51 | const Styled = {
52 | ColorPickerModal,
53 | ColorPickerWrap,
54 | ModalActions,
55 | };
56 |
57 | export default Styled;
58 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/HiddenUploadInput/HiddenUploadInput.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 |
4 | const StyledHiddenUploadInput = styled.input`
5 | display: none;
6 | width: 1px;
7 | height: 1px;
8 | position: absolute;
9 | z-index: -1;
10 | `;
11 |
12 | export { StyledHiddenUploadInput };
13 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/HiddenUploadInput/index.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React, { forwardRef } from 'react';
3 |
4 | /** Internal Dependencies */
5 | import { StyledHiddenUploadInput } from './HiddenUploadInput.styled';
6 |
7 | const HiddenUploadInput = (props, ref) => {
8 | return ;
9 | };
10 |
11 | export default forwardRef(HiddenUploadInput);
12 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/Modal/Modal.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled, { css } from 'styled-components';
3 | import modalTitle from '@scaleflex/ui/core/modal-title';
4 | import { Modal, ModalActions } from '@scaleflex/ui/core';
5 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
6 | import { FontVariant as FV } from '@scaleflex/ui/utils/types/typography';
7 |
8 | const StyledModal = styled(Modal)`
9 | width: ${({ width }) => width || '300px'};
10 | max-width: unset;
11 | `;
12 |
13 | const StyledModalTitle = styled(modalTitle)(
14 | ({ theme, isWarning }) => css`
15 | padding-bottom: 0;
16 |
17 | .SfxModalTitle-Icon {
18 | background-color: ${isWarning && theme.palette[PC.Orange_0_1_Overlay]};
19 | }
20 |
21 | .SfxModalTitle-LabelPrimary {
22 | margin-bottom: 24px;
23 | ${theme.typography.font[FV.TitleH3]};
24 | }
25 |
26 | .SfxModalTitle-LabelSecondary {
27 | ${theme.typography.font[FV.TextLarge]};
28 | text-align: center;
29 | }
30 | `,
31 | );
32 |
33 | const StyledModalActions = styled(ModalActions)`
34 | gap: 12px;
35 | padding: 24px;
36 |
37 | .SfxButton-root {
38 | flex: 1;
39 | margin: 0;
40 | height: 40px;
41 | }
42 | `;
43 |
44 | export { StyledModal, StyledModalTitle, StyledModalActions };
45 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/Separator/Separator.styled.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
3 |
4 | const StyledSeparator = styled.div`
5 | display: inline-block;
6 | height: ${(props) => props.height};
7 | width: ${(props) => props.width};
8 | border-radius: 1px;
9 | background: ${({ theme: { palette } }) => palette[PC.BordersSecondary]};
10 | `;
11 |
12 | export { StyledSeparator };
13 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/Separator/index.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { StyledSeparator } from './Separator.styled';
7 |
8 | const Separator = ({ height, width }) => (
9 |
10 | );
11 |
12 | Separator.defaultProps = {
13 | height: '24px',
14 | width: '1px',
15 | };
16 |
17 | Separator.propTypes = {
18 | height: PropTypes.string,
19 | width: PropTypes.string,
20 | };
21 |
22 | export default Separator;
23 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/Slider/Slider.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 | import Slider from '@scaleflex/ui/core/slider';
4 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
5 |
6 | const StyledSlider = styled(Slider)`
7 | width: ${({ width }) => width || '104px'};
8 | max-width: ${({ width }) => width || '104px'};
9 | user-select: none;
10 | padding: 0;
11 | margin-bottom: ${({ noMargin }) => (noMargin ? '' : '16px')};
12 |
13 | .SfxSlider-thumb {
14 | background-color: ${({ theme: { palette } }) =>
15 | palette[PC.AccentStateless]};
16 | }
17 |
18 | .SfxSlider-Track {
19 | height: 2px;
20 | color: ${({ theme: { palette } }) => palette[PC.AccentStateless]};
21 | }
22 |
23 | .SfxSlider-rail {
24 | height: 2px;
25 | background-color: ${({ theme: { palette } }) => palette[PC.BordersItem]};
26 | }
27 | `;
28 |
29 | export { StyledSlider };
30 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/Slider/index.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { StyledSlider } from './Slider.styled';
7 |
8 | const Slider = ({ onChange, ...props }) => {
9 | return (
10 | (onChange ? onChange(val) : undefined)}
13 | hideAnnotation
14 | labelTooltip="auto"
15 | {...props}
16 | />
17 | );
18 | };
19 |
20 | Slider.propTypes = {
21 | onChange: PropTypes.func.isRequired,
22 | };
23 |
24 | export default Slider;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/Spinner/Spinner.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { Loading } from '@scaleflex/icons';
3 | import styled, { keyframes } from 'styled-components';
4 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
5 |
6 | const spin = keyframes`
7 | to { transform: rotate(360deg); }
8 | `;
9 |
10 | const StyledSpinnerWrapper = styled.div`
11 | background: ${({ theme: { palette } }) => palette[PC.BackgroundStateless]};
12 | display: flex;
13 | align-items: center;
14 | justify-content: center;
15 | position: absolute;
16 | z-index: 11111;
17 | top: 0;
18 | bottom: 0;
19 | right: 0;
20 | left: 0;
21 | flex-direction: column;
22 | user-select: none;
23 | `;
24 |
25 | const StyledSpinner = styled(Loading)`
26 | animation: ${spin} 1.2s infinite;
27 | `;
28 |
29 | export { StyledSpinnerWrapper, StyledSpinner };
30 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/common/Spinner/index.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
7 |
8 | import { StyledSpinnerWrapper, StyledSpinner } from './Spinner.styled';
9 |
10 | const Spinner = ({ theme }) => {
11 | return (
12 |
13 |
14 |
15 | );
16 | };
17 |
18 | Spinner.defaultProps = {
19 | theme: {},
20 | };
21 |
22 | Spinner.propTypes = {
23 | theme: PropTypes.instanceOf(Object),
24 | };
25 |
26 | export default Spinner;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Arrow/ArrowButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { ArrowTool as ArrowIcon } from '@scaleflex/icons/arrow-tool';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const ArrowButton = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | ArrowButton.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | ArrowButton.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default ArrowButton;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Arrow/ArrowOptions.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { useAnnotation } from 'hooks';
7 | import { TOOLS_IDS } from 'utils/constants';
8 | import AnnotationOptions from 'components/common/AnnotationOptions';
9 |
10 | const ArrowOptions = ({ t }) => {
11 | const [arrow, saveArrow] = useAnnotation({
12 | name: TOOLS_IDS.ARROW,
13 | });
14 |
15 | return (
16 |
24 | );
25 | };
26 |
27 | ArrowOptions.propTypes = {
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default ArrowOptions;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Arrow/index.js:
--------------------------------------------------------------------------------
1 | export { default as ArrowButton } from './ArrowButton';
2 |
3 | export { default as ArrowOptions } from './ArrowOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Blur/Blur.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Blur as BlurIcon } from '@scaleflex/icons/blur';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const Blur = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | Blur.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | Blur.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default Blur;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Blur/index.js:
--------------------------------------------------------------------------------
1 | export { default as Blur } from './Blur';
2 |
3 | export { default as BlurOptions } from './BlurOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Brightness/Brightness.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Brightness as BrightnessIcon } from '@scaleflex/icons/brightness';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const Brightness = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | Brightness.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | Brightness.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default Brightness;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Brightness/index.js:
--------------------------------------------------------------------------------
1 | export { default as Brightness } from './Brightness';
2 |
3 | export { default as BrightnessOptions } from './BrightnessOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Contrast/Contrast.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Contrast as ContrastIcon } from '@scaleflex/icons/contrast';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const Contrast = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | Contrast.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | Contrast.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default Contrast;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Contrast/index.js:
--------------------------------------------------------------------------------
1 | export { default as Contrast } from './Contrast';
2 |
3 | export { default as ContrastOptions } from './ContrastOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Crop/Crop.constants.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import Custom from '@scaleflex/icons/custom';
3 | import Ellipse from '@scaleflex/icons/ellipse';
4 | import Landscape from '@scaleflex/icons/landscape';
5 | import Portrait from '@scaleflex/icons/portrait';
6 | import ImageOutline from '@scaleflex/icons/image-outline';
7 |
8 | /** Internal Dependencies */
9 | import { CUSTOM_CROP, ELLIPSE_CROP, ORIGINAL_CROP } from 'utils/constants';
10 | import toPrecisedFloat from 'utils/toPrecisedFloat';
11 |
12 | export const DEFAULT_CROP_PRESETS = [
13 | {
14 | titleKey: 'custom',
15 | ratio: CUSTOM_CROP,
16 | icon: Custom,
17 | hide: ({ lockCropAreaAt } = {}) => lockCropAreaAt,
18 | },
19 | {
20 | titleKey: 'original',
21 | ratio: ORIGINAL_CROP,
22 | icon: ImageOutline,
23 | },
24 | {
25 | titleKey: 'landscape',
26 | descriptionKey: '16:9',
27 | ratio: toPrecisedFloat(16 / 9),
28 | icon: Landscape,
29 | },
30 | {
31 | titleKey: 'portrait',
32 | descriptionKey: '9:16',
33 | ratio: toPrecisedFloat(9 / 16),
34 | icon: Portrait,
35 | },
36 | {
37 | titleKey: 'ellipse',
38 | ratio: ELLIPSE_CROP,
39 | icon: Ellipse,
40 | },
41 | ];
42 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Crop/Crop.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React, { useState } from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Crop as CropIcon } from '@scaleflex/icons/crop';
5 |
6 | /** Internal Dependencies */
7 | import { useStore } from 'hooks';
8 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
9 | import { TOOLS_IDS } from 'utils/constants';
10 | import { StyledToolsBarItemButtonLabel } from 'components/ToolsBar/ToolsBar.styled';
11 | import CropPresetsOption from './CropPresetsOption';
12 |
13 | const Crop = ({ selectTool, isSelected }) => {
14 | const { config, t } = useStore();
15 | const [anchorEl, setAnchorEl] = useState();
16 |
17 | const selectToolAndShowPresets = (toolId, e) => {
18 | selectTool(toolId);
19 | setAnchorEl(e.currentTarget);
20 | };
21 |
22 | const closeCropPresets = () => {
23 | setAnchorEl(null);
24 | };
25 |
26 | return (
27 |
34 | {!config[TOOLS_IDS.CROP].noPresets ? (
35 |
36 | ) : (
37 |
38 | {t('cropTool')}
39 |
40 | )}
41 |
42 | );
43 | };
44 |
45 | Crop.defaultProps = {
46 | isSelected: false,
47 | };
48 |
49 | Crop.propTypes = {
50 | selectTool: PropTypes.func.isRequired,
51 | isSelected: PropTypes.bool,
52 | };
53 |
54 | export default Crop;
55 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Crop/index.js:
--------------------------------------------------------------------------------
1 | export { default as Crop } from './Crop';
2 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Ellipse/EllipseButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Ellipse as EllipseIcon } from '@scaleflex/icons/ellipse';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const EllipseButton = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | EllipseButton.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | EllipseButton.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default EllipseButton;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Ellipse/EllipseOptions.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { useAnnotation } from 'hooks';
7 | import { TOOLS_IDS } from 'utils/constants';
8 | import AnnotationOptions from 'components/common/AnnotationOptions';
9 |
10 | const EllipseOptions = ({ t }) => {
11 | const [ellipse, saveEllipse] = useAnnotation({
12 | name: TOOLS_IDS.ELLIPSE,
13 | });
14 |
15 | return (
16 |
22 | );
23 | };
24 |
25 | EllipseOptions.propTypes = {
26 | t: PropTypes.func.isRequired,
27 | };
28 | export default EllipseOptions;
29 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Ellipse/index.js:
--------------------------------------------------------------------------------
1 | export { default as EllipseButton } from './EllipseButton';
2 |
3 | export { default as EllipseOptions } from './EllipseOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Filters/Filters.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 |
4 | /** Internal Dependencies */
5 | import { useFilter, useStore } from 'hooks';
6 | import Carousel from 'components/common/Carousel';
7 | import FilterItem from './FilterItem';
8 | import { AVAILABLE_FILTERS } from './Filters.constants';
9 |
10 | const style = { maxWidth: '100%', width: '100%' };
11 |
12 | const Filters = () => {
13 | const { originalImage } = useStore();
14 | const [appliedFilter, applyFilter] = useFilter();
15 |
16 | return (
17 |
18 | {AVAILABLE_FILTERS.map((filter) => (
19 |
27 | ))}
28 |
29 | );
30 | };
31 | export default Filters;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Filters/Filters.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import Label from '@scaleflex/ui/core/label';
3 | import { FontVariant as FV } from '@scaleflex/ui/utils/types/typography';
4 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
5 | import { Stage } from 'react-konva';
6 | import styled, { css } from 'styled-components';
7 |
8 | const StyledFilterItem = styled.div`
9 | display: inline-flex;
10 | flex-direction: column;
11 | align-items: center;
12 | justify-content: center;
13 | padding: 0px 2px;
14 | gap: 6px;
15 | cursor: pointer;
16 | border-radius: 2px;
17 |
18 | canvas {
19 | border-radius: 2px;
20 | }
21 | `;
22 |
23 | const FilterItemPreview = styled(Stage)`
24 | [aria-selected='true'] & {
25 | padding: 1px;
26 | border: 1px solid ${({ theme }) => theme.palette['accent-primary-active']};
27 | border-radius: 2px;
28 | }
29 | `;
30 |
31 | const FilterItemLabel = styled(Label)(
32 | ({ theme }) => css`
33 | color: ${theme.palette[PC.TextPrimary]};
34 | ${theme.typography.font[FV.LabelExtraSmallUp]};
35 |
36 | [aria-selected='true'] & {
37 | color: ${theme.palette['accent-primary-active']};
38 | }
39 | `,
40 | );
41 |
42 | export { StyledFilterItem, FilterItemPreview, FilterItemLabel };
43 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Filters/index.js:
--------------------------------------------------------------------------------
1 | export { default as Filters } from './Filters';
2 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Flip/index.js:
--------------------------------------------------------------------------------
1 | export { default as FlipX } from './FlipX';
2 |
3 | export { default as FlipY } from './FlipY';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/HSV/HSV.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Saturation as SaturationIcon } from '@scaleflex/icons/saturation';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const HSV = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | HSV.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | HSV.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default HSV;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/HSV/index.js:
--------------------------------------------------------------------------------
1 | export { default as HSV } from './HSV';
2 |
3 | export { default as HSVOptions } from './HSVOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Image/Image.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 |
4 | const StyledImagesGallery = styled.div`
5 | background: ${({ theme }) => theme.palette['bg-secondary']};
6 | box-shadow: 0px 1px 2px ${({ theme }) => theme.palette['light-shadow']};
7 | border-radius: 4px;
8 | padding: 8px;
9 | overflow-y: auto;
10 | max-height: 350px;
11 | max-width: 300px;
12 | `;
13 |
14 | const StyledImageWrapper = styled.div`
15 | display: inline-flex;
16 | align-items: center;
17 | justify-content: center;
18 | width: 60px;
19 | height: 60px;
20 | margin: 4px;
21 | padding: 4px;
22 | cursor: pointer;
23 | border-radius: 4px;
24 | border: 2px solid ${({ theme }) => theme.palette['bg-primary-active']};
25 | user-select: none;
26 |
27 | :hover {
28 | border-color: ${({ theme }) => theme.palette['accent-primary-active']};
29 | }
30 |
31 | img {
32 | width: 100%;
33 | height: 100%;
34 | object-fit: contain;
35 | }
36 | `;
37 |
38 | export { StyledImagesGallery, StyledImageWrapper };
39 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Image/ImageButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { ImageOutline as ImageIcon } from '@scaleflex/icons/image-outline';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const ImageButton = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | ImageButton.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | ImageButton.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default ImageButton;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Image/ImageControls.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import AnnotationOptions from 'components/common/AnnotationOptions';
7 |
8 | const ImageControls = ({ image, saveImage, children, t }) => (
9 |
16 | {children}
17 |
18 | );
19 |
20 | ImageControls.defaultProps = {
21 | children: null,
22 | };
23 |
24 | ImageControls.propTypes = {
25 | image: PropTypes.instanceOf(Object).isRequired,
26 | saveImage: PropTypes.func.isRequired,
27 | children: PropTypes.node,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default ImageControls;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Image/ImagesGallery.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import Popper from '@scaleflex/ui/core/popper';
5 |
6 | /** Internal Dependencies */
7 | import { StyledImagesGallery, StyledImageWrapper } from './Image.styled';
8 |
9 | const ImagesGallery = ({ gallery, anchorEl, onClose, onSelect }) => (
10 |
18 |
19 | {gallery.map(({ originalUrl, previewUrl }) => (
20 | onSelect(originalUrl)}
23 | >
24 |
30 |
31 | ))}
32 |
33 |
34 | );
35 | ImagesGallery.defaultProps = {
36 | gallery: [],
37 | anchorEl: null,
38 | };
39 |
40 | ImagesGallery.propTypes = {
41 | onClose: PropTypes.func.isRequired,
42 | onSelect: PropTypes.func.isRequired,
43 | gallery: PropTypes.arrayOf(Object),
44 | anchorEl: PropTypes.instanceOf(Object),
45 | };
46 |
47 | export default ImagesGallery;
48 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Image/index.js:
--------------------------------------------------------------------------------
1 | export { default as ImageButton } from './ImageButton';
2 |
3 | export { default as ImageOptions } from './ImageOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Line/LineButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import Line from '@scaleflex/icons/line';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const LineButton = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | LineButton.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | LineButton.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default LineButton;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Line/LineOptions.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { useAnnotation } from 'hooks';
7 | import { TOOLS_IDS } from 'utils/constants';
8 | import AnnotationOptions from 'components/common/AnnotationOptions';
9 |
10 | const LineOptions = ({ t }) => {
11 | const [line, saveLine] = useAnnotation({
12 | name: TOOLS_IDS.LINE,
13 | });
14 |
15 | return (
16 |
24 | );
25 | };
26 |
27 | LineOptions.propTypes = {
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default LineOptions;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Line/index.js:
--------------------------------------------------------------------------------
1 | export { default as LineButton } from './LineButton';
2 |
3 | export { default as LineOptions } from './LineOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Pen/PenButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Annotation as PenIcon } from '@scaleflex/icons/annotation';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const PenButton = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | PenButton.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | PenButton.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default PenButton;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Pen/index.js:
--------------------------------------------------------------------------------
1 | export { default as PenButton } from './PenButton';
2 |
3 | export { default as PenOptions } from './PenOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Polygon/Polygon.constants.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import PolygonSides from '@scaleflex/icons/polygon-sides';
3 |
4 | /** Internal Dependencies */
5 | import PolygonSidesField from './PolygonSidesField';
6 |
7 | export const SIDES_NUMBER = 'sides-number';
8 |
9 | export const POLYGON_POPPABLE_OPTIONS = [
10 | {
11 | titleKey: 'sides',
12 | name: SIDES_NUMBER,
13 | Icon: PolygonSides,
14 | },
15 | ];
16 |
17 | export const polygonOptionsPopupComponents = {
18 | [SIDES_NUMBER]: PolygonSidesField,
19 | };
20 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Polygon/PolygonButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Polygon as PolygonIcon } from '@scaleflex/icons/polygon';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const PolygonButton = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | PolygonButton.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | PolygonButton.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default PolygonButton;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Polygon/PolygonOptions.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { useAnnotation } from 'hooks';
7 | import { TOOLS_IDS } from 'utils/constants';
8 | import AnnotationOptions from 'components/common/AnnotationOptions';
9 | import {
10 | polygonOptionsPopupComponents,
11 | POLYGON_POPPABLE_OPTIONS,
12 | } from './Polygon.constants';
13 |
14 | const PolygonOptions = ({ t }) => {
15 | const [polygon, savePolygon] = useAnnotation({
16 | name: TOOLS_IDS.POLYGON,
17 | });
18 |
19 | return (
20 |
29 | );
30 | };
31 |
32 | PolygonOptions.propTypes = {
33 | t: PropTypes.func.isRequired,
34 | };
35 |
36 | export default PolygonOptions;
37 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Polygon/PolygonSidesField.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import Label from '@scaleflex/ui/core/label';
5 |
6 | /** InternalDependencies */
7 | import { StyledSpacedOptionFields } from 'components/common/AnnotationOptions/AnnotationOptions.styled';
8 | import restrictNumber from 'utils/restrictNumber';
9 | import Slider from 'components/common/Slider';
10 |
11 | const MIN_VALUE = 3;
12 | const MAX_VALUE = 25;
13 |
14 | const PolygonSidesField = ({
15 | annotation: polygon,
16 | updateAnnotation: updatePolygon,
17 | t,
18 | }) => {
19 | const { sides } = polygon;
20 |
21 | const updateSidesNumber = (newSidesNumber) => {
22 | updatePolygon({
23 | sides: restrictNumber(newSidesNumber, MIN_VALUE, MAX_VALUE),
24 | });
25 | };
26 |
27 | return (
28 |
29 |
30 |
38 |
39 | );
40 | };
41 |
42 | PolygonSidesField.propTypes = {
43 | annotation: PropTypes.instanceOf(Object).isRequired,
44 | updateAnnotation: PropTypes.func.isRequired,
45 | t: PropTypes.func.isRequired,
46 | };
47 |
48 | export default PolygonSidesField;
49 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Polygon/index.js:
--------------------------------------------------------------------------------
1 | export { default as PolygonButton } from './PolygonButton';
2 |
3 | export { default as PolygonOptions } from './PolygonOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Rect/Rect.constants.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import RadiusCorner from '@scaleflex/icons/radius-corner';
3 |
4 | /** Internal Dependencies */
5 | import RectCornerField from './RectCornerField';
6 |
7 | export const CORNER_RADIUS = 'corner-radius';
8 |
9 | export const RECT_POPPABLE_OPTIONS = [
10 | {
11 | titleKey: 'cornerRadius',
12 | name: CORNER_RADIUS,
13 | Icon: RadiusCorner,
14 | },
15 | ];
16 |
17 | export const rectOptionsPopupComponents = {
18 | [CORNER_RADIUS]: RectCornerField,
19 | };
20 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Rect/RectButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { CropLandscape as RectIcon } from '@scaleflex/icons/crop-landscape';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const RectButton = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | RectButton.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | RectButton.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default RectButton;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Rect/RectCornerField.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import Label from '@scaleflex/ui/core/label';
5 |
6 | /** InternalDependencies */
7 | import { StyledSpacedOptionFields } from 'components/common/AnnotationOptions/AnnotationOptions.styled';
8 | import restrictNumber from 'utils/restrictNumber';
9 | import Slider from 'components/common/Slider';
10 |
11 | const MIN_VALUE = 0;
12 | const MAX_VALUE = 150;
13 |
14 | const RectCornerField = ({
15 | annotation: rect,
16 | updateAnnotation: updateRect,
17 | t,
18 | }) => {
19 | const { cornerRadius } = rect;
20 |
21 | const updateCornerRadius = (newCornerRadius) => {
22 | updateRect({
23 | cornerRadius: restrictNumber(newCornerRadius, MIN_VALUE, MAX_VALUE),
24 | });
25 | };
26 |
27 | return (
28 |
29 |
30 |
38 |
39 | );
40 | };
41 |
42 | RectCornerField.propTypes = {
43 | annotation: PropTypes.instanceOf(Object).isRequired,
44 | updateAnnotation: PropTypes.func.isRequired,
45 | t: PropTypes.func.isRequired,
46 | };
47 |
48 | export default RectCornerField;
49 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Rect/RectOptions.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { useAnnotation } from 'hooks';
7 | import { TOOLS_IDS } from 'utils/constants';
8 | import AnnotationOptions from 'components/common/AnnotationOptions';
9 | import {
10 | rectOptionsPopupComponents,
11 | RECT_POPPABLE_OPTIONS,
12 | } from './Rect.constants';
13 |
14 | const RectOptions = ({ t }) => {
15 | const [rect, saveRect] = useAnnotation({
16 | name: TOOLS_IDS.RECT,
17 | });
18 |
19 | return (
20 |
28 | );
29 | };
30 |
31 | RectOptions.propTypes = {
32 | t: PropTypes.func.isRequired,
33 | };
34 |
35 | export default RectOptions;
36 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Rect/index.js:
--------------------------------------------------------------------------------
1 | export { default as RectButton } from './RectButton';
2 |
3 | export { default as RectOptions } from './RectOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Resize/Resize.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled, { css } from 'styled-components';
3 | import IconButton from '@scaleflex/ui/core/icon-button';
4 | import InputGroup from '@scaleflex/ui/core/input-group';
5 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
6 | import { FontVariant as FV } from '@scaleflex/ui/utils/types/typography';
7 |
8 | const StyledResizeWrapper = styled.div`
9 | display: flex;
10 | justify-content: ${({ alignment }) => alignment || 'center'};
11 | align-items: flex-end;
12 | gap: 3px;
13 | flex-wrap: wrap;
14 | `;
15 |
16 | const StyledResizeInput = styled(InputGroup)(
17 | ({ theme }) => css`
18 | width: 106px;
19 | max-width: 106px;
20 | margin-top: 4px;
21 |
22 | .SfxInput-Base {
23 | width: 100%;
24 | min-width: 100%;
25 | max-width: 100%;
26 | }
27 |
28 | span {
29 | color: ${theme.palette[PC.TextSecondary]};
30 | ${theme.typography.font[FV.LabelMedium]};
31 | }
32 | `,
33 | );
34 |
35 | const StyledRatioLockIcon = styled(IconButton)`
36 | svg {
37 | margin-bottom: 1px;
38 | }
39 | `;
40 |
41 | const StyledResetButton = styled(IconButton)`
42 | margin-left: 12px;
43 | `;
44 |
45 | export {
46 | StyledResizeWrapper,
47 | StyledResizeInput,
48 | StyledRatioLockIcon,
49 | StyledResetButton,
50 | };
51 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Resize/index.js:
--------------------------------------------------------------------------------
1 | export { default as Resize } from './Resize';
2 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Rotate/Rotate.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 | import { IconButton, RotationSlider } from '@scaleflex/ui/core';
4 | import { Color as PC } from '@scaleflex/ui/utils/types/palette';
5 |
6 | const StyledRotationOptions = styled.div`
7 | display: flex;
8 | align-items: center;
9 | gap: 16px;
10 | `;
11 |
12 | const StyledRotationSlider = styled(RotationSlider)`
13 | .SfxRotationSlider-control {
14 | width: 1px;
15 | height: 10px;
16 | background-color: ${({ theme: { palette } }) => palette[PC.IconsSecondary]};
17 |
18 | &:before {
19 | box-shadow: unset;
20 | }
21 | }
22 |
23 | .SfxRotationSlider-mark,
24 | .SfxRotationSlider-small-dot-wrapper {
25 | padding: 0;
26 |
27 | .SfxRotationSlider-mark-text {
28 | top: 10px;
29 | }
30 |
31 | .SfxRotationSlider-big-dot {
32 | width: 4px;
33 | height: 4px;
34 | }
35 |
36 | .SfxRotationSlider-small-dot {
37 | width: 1px;
38 | height: 1px;
39 | }
40 | }
41 |
42 | .SfxRotationSlider-list {
43 | gap: 4px;
44 | }
45 | `;
46 |
47 | const StyledRotateButton = styled(IconButton)``;
48 |
49 | export { StyledRotationOptions, StyledRotationSlider, StyledRotateButton };
50 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Rotate/RotateButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { RotationLeft as RotateIcon } from '@scaleflex/icons/rotation-left';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const RotateButton = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | RotateButton.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | RotateButton.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default RotateButton;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Rotate/index.js:
--------------------------------------------------------------------------------
1 | export { default as RotateButton } from './RotateButton';
2 |
3 | export { default as RotateOptions } from './RotateOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Text/TextButton.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Text as TextIcon } from '@scaleflex/icons/text';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const TextButton = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | TextButton.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | TextButton.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default TextButton;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Text/TextOptions/TextAlignmentFields.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import {
7 | StyledSpacedOptionFields,
8 | StyledIconWrapper,
9 | } from 'components/common/AnnotationOptions/AnnotationOptions.styled';
10 | import { TextAlignCenter, TextAlignLeft } from '@scaleflex/icons';
11 |
12 | const rightAlignmentCssTransform = { transform: 'scaleX(-1)' };
13 |
14 | const TextAlignmentFields = ({
15 | annotation: text,
16 | updateAnnotation: updateText,
17 | }) => {
18 | const { align } = text;
19 |
20 | const changeHorizontalAlignment = (newHorizonalAlignment) => {
21 | updateText({ align: newHorizonalAlignment });
22 | };
23 |
24 | return (
25 |
26 | changeHorizontalAlignment('left')}
28 | active={align === 'left'}
29 | >
30 |
31 |
32 | changeHorizontalAlignment('center')}
34 | active={align === 'center'}
35 | >
36 |
37 |
38 | changeHorizontalAlignment('right')}
40 | active={align === 'right'}
41 | >
42 |
43 |
44 |
45 | );
46 | };
47 |
48 | TextAlignmentFields.propTypes = {
49 | annotation: PropTypes.instanceOf(Object).isRequired,
50 | updateAnnotation: PropTypes.func.isRequired,
51 | };
52 |
53 | export default TextAlignmentFields;
54 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Text/TextOptions/TextOptions.constants.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { TextAlignCenter } from '@scaleflex/icons';
3 | import Spacing from '@scaleflex/icons/spacing';
4 |
5 | /** Internal Dependencies */
6 | import TextSpacingsFields from './TextSpacingsFields';
7 | import TextAlignmentFields from './TextAlignmentFields';
8 |
9 | export const TEXT_ALIGNMENT = 'text-alignment';
10 | export const TEXT_SPACINGS = 'text-spacings';
11 |
12 | export const TEXT_POPPABLE_OPTIONS = [
13 | {
14 | titleKey: 'textAlignment',
15 | name: TEXT_ALIGNMENT,
16 | Icon: TextAlignCenter,
17 | },
18 | {
19 | titleKey: 'textSpacings',
20 | name: TEXT_SPACINGS,
21 | Icon: Spacing,
22 | },
23 | ];
24 |
25 | export const textOptionsPopupComponents = {
26 | [TEXT_ALIGNMENT]: TextAlignmentFields,
27 | [TEXT_SPACINGS]: TextSpacingsFields,
28 | };
29 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Text/TextOptions/TextOptions.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 | import Input from '@scaleflex/ui/core/input';
4 | import Select from '@scaleflex/ui/core/select';
5 |
6 | const StyledFontFamilySelect = styled(Select)`
7 | width: 160px;
8 | `;
9 |
10 | const StyledFontSizeInput = styled(Input)`
11 | width: 72px;
12 | `;
13 |
14 | const StyledToolsWrapper = styled.div`
15 | display: flex;
16 | `;
17 |
18 | export { StyledFontFamilySelect, StyledFontSizeInput, StyledToolsWrapper };
19 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Text/TextOptions/TextSpacingsFields.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import Label from '@scaleflex/ui/core/label';
5 |
6 | /** Internal Dependencies */
7 | import restrictNumber from 'utils/restrictNumber';
8 | import { StyledSpacedOptionFields } from 'components/common/AnnotationOptions/AnnotationOptions.styled';
9 | import Slider from 'components/common/Slider';
10 |
11 | const MIN_VALUE = 0;
12 | const MAX_VALUE = 100;
13 | const SLIDER_STEP = 1;
14 |
15 | const TextSpacingsFields = ({
16 | annotation: text,
17 | updateAnnotation: updateText,
18 | t,
19 | }) => {
20 | const { letterSpacing, lineHeight } = text;
21 |
22 | const updateValue = (prop, val) => {
23 | updateText({ [prop]: restrictNumber(val, MIN_VALUE, MAX_VALUE) });
24 | };
25 |
26 | return (
27 |
28 |
29 | updateValue('letterSpacing', val)}
33 | value={letterSpacing}
34 | step={SLIDER_STEP}
35 | />
36 |
37 | updateValue('lineHeight', val)}
41 | value={lineHeight}
42 | step={SLIDER_STEP}
43 | />
44 |
45 | );
46 | };
47 |
48 | TextSpacingsFields.propTypes = {
49 | annotation: PropTypes.instanceOf(Object).isRequired,
50 | updateAnnotation: PropTypes.func.isRequired,
51 | t: PropTypes.func.isRequired,
52 | };
53 |
54 | export default TextSpacingsFields;
55 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Text/TextOptions/index.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import { useAnnotation } from 'hooks';
7 | import { TOOLS_IDS } from 'utils/constants';
8 | import TextControls from './TextControls';
9 |
10 | const TextOptions = ({ t }) => {
11 | const [text, saveText] = useAnnotation({ name: TOOLS_IDS.TEXT });
12 |
13 | return ;
14 | };
15 |
16 | TextOptions.propTypes = {
17 | t: PropTypes.func.isRequired,
18 | };
19 |
20 | export default TextOptions;
21 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Text/index.js:
--------------------------------------------------------------------------------
1 | export { default as TextButton } from './TextButton';
2 |
3 | export { default as TextOptions } from './TextOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Warmth/Warmth.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import { Temprature as WarmthIcon } from '@scaleflex/icons/tempreture';
5 |
6 | /** Internal Dependencies */
7 | import ToolsBarItemButton from 'components/ToolsBar/ToolsBarItemButton';
8 | import { TOOLS_IDS } from 'utils/constants';
9 |
10 | const Warmth = ({ selectTool, isSelected, t }) => (
11 |
19 | );
20 |
21 | Warmth.defaultProps = {
22 | isSelected: false,
23 | };
24 |
25 | Warmth.propTypes = {
26 | selectTool: PropTypes.func.isRequired,
27 | isSelected: PropTypes.bool,
28 | t: PropTypes.func.isRequired,
29 | };
30 |
31 | export default Warmth;
32 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Warmth/index.js:
--------------------------------------------------------------------------------
1 | export { default as Warmth } from './Warmth';
2 |
3 | export { default as WarmthOptions } from './WarmthOptions';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Watermark/Watermark.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import styled from 'styled-components';
3 |
4 | const StyledWatermarkWrapper = styled.div`
5 | display: flex;
6 | align-items: center;
7 | justify-content: center;
8 | flex-wrap: wrap;
9 | gap: 8px;
10 | overflow: hidden;
11 |
12 | ${({ noWrap }) => (noWrap ? 'flex-wrap: nowrap;' : '')};
13 | `;
14 |
15 | const StyledControlsWrapper = styled.div`
16 | margin-bottom: 8px;
17 | `;
18 |
19 | const StyledWatermarkGalleryItem = styled.div(
20 | ({ theme }) => `
21 | padding: 6px 4px;
22 | border: 1px solid ${theme.palette['borders-secondary']};
23 | width: fit-content;
24 | height: 32px;
25 | border-radius: 2px;
26 | overflow: hidden;
27 | cursor: pointer;
28 | border-radius: 4px;
29 |
30 | :hover {
31 | background: ${theme.palette['bg-primary-active']};
32 | }
33 |
34 | &[aria-selected='true'] {
35 | background: ${theme.palette['bg-primary-active']};
36 | border-color: ${theme.palette['accent-primary-active']};
37 | }
38 |
39 | img {
40 | max-width: 100%;
41 | max-height: 100%;
42 | }
43 | `,
44 | );
45 |
46 | export {
47 | StyledWatermarkWrapper,
48 | StyledControlsWrapper,
49 | StyledWatermarkGalleryItem,
50 | };
51 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/Watermark/index.jsx:
--------------------------------------------------------------------------------
1 | export { default as Watermark } from './Watermark';
2 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/components/tools/tools.styled.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { Input, Label } from '@scaleflex/ui/core';
3 | import styled from 'styled-components';
4 | import { FontVariant as FV } from '@scaleflex/ui/utils/types/typography';
5 |
6 | const StyledHSVOptions = styled.div`
7 | display: flex;
8 | width: 100%;
9 | justify-content: space-between;
10 | gap: 10px;
11 |
12 | .SfxSlider-root {
13 | min-width: 100px;
14 | }
15 |
16 | ${({ isPhoneScreen }) =>
17 | isPhoneScreen &&
18 | `
19 | flex-direction: column;
20 |
21 | .SfxSlider-root {
22 | min-width: 230px;
23 | }
24 | `}
25 | `;
26 |
27 | const StyledSliderContainer = styled.div`
28 | display: flex;
29 | flex-direction: column;
30 | `;
31 |
32 | const StyledSliderLabel = styled(Label)`
33 | ${({ theme }) => theme.typography.font[FV.LabelExtraSmallUp]};
34 | `;
35 |
36 | const StyledSliderWrapper = styled.div`
37 | display: flex;
38 | align-items: center;
39 | `;
40 |
41 | const StyledSliderInput = styled(Input)`
42 | display: inline-block;
43 | width: 40px;
44 | height: 28px;
45 | padding: 6px 2px;
46 | margin-left: 10px;
47 | border: none;
48 |
49 | .SfxInput-Base {
50 | text-align: center;
51 | width: 100%;
52 | min-width: 100%;
53 | max-width: 100%;
54 | }
55 | `;
56 |
57 | export {
58 | StyledHSVOptions,
59 | StyledSliderContainer,
60 | StyledSliderLabel,
61 | StyledSliderWrapper,
62 | StyledSliderInput,
63 | };
64 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/context/AppContext.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { createContext } from 'react';
3 |
4 | const AppContext = createContext({});
5 |
6 | export default AppContext;
7 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/context/AppProvider.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React, { useCallback, useEffect, useMemo } from 'react';
3 | import PropTypes from 'prop-types';
4 | import { useTheme } from '@scaleflex/ui/theme/hooks';
5 |
6 | /** Internal Dependencies */
7 | import { useAppReducer } from 'hooks';
8 | import { translate, updateTranslations } from 'utils/translator';
9 | import appReducer from './appReducer';
10 | import AppContext from './AppContext';
11 | import getInitialAppState from './getInitialAppState';
12 |
13 | let isFieMounted = true;
14 |
15 | const AppProvider = ({ children, config = {} }) => {
16 | const [state, _dispatch] = useAppReducer(
17 | appReducer,
18 | getInitialAppState(config),
19 | config,
20 | );
21 |
22 | useEffect(() => {
23 | isFieMounted = true;
24 |
25 | return () => {
26 | isFieMounted = false;
27 | };
28 | }, []);
29 |
30 | const dispatch = useCallback(
31 | (...args) => {
32 | if (isFieMounted) {
33 | _dispatch(...args);
34 | }
35 | },
36 | [_dispatch],
37 | );
38 |
39 | useEffect(() => {
40 | updateTranslations(config.translations, config.language);
41 | }, [config.useBackendTranslations, config.language, config.translations]);
42 |
43 | const theme = useTheme();
44 | const providedValue = useMemo(
45 | () => ({
46 | ...state,
47 | config,
48 | theme,
49 | dispatch,
50 | t: translate,
51 | }),
52 | [config, state],
53 | );
54 |
55 | return (
56 | {children}
57 | );
58 | };
59 |
60 | AppProvider.defaultProps = {
61 | config: {},
62 | };
63 |
64 | AppProvider.propTypes = {
65 | children: PropTypes.node.isRequired,
66 | config: PropTypes.instanceOf(Object),
67 | };
68 |
69 | export default AppProvider;
70 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/context/AppProviderOverridenValue.jsx:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | /** Internal Dependencies */
6 | import AppContext from './AppContext';
7 |
8 | // This component is used in repassing the state to react-konva's modules
9 | // As it has issue in context bridging.
10 | const AppProviderOverridenValue = ({ children, overridingValue }) => (
11 | {children}
12 | );
13 |
14 | AppProviderOverridenValue.propTypes = {
15 | children: PropTypes.node.isRequired,
16 | overridingValue: PropTypes.instanceOf(Object).isRequired,
17 | };
18 |
19 | export default AppProviderOverridenValue;
20 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/context/appReducer.js:
--------------------------------------------------------------------------------
1 | import actions from 'actions';
2 |
3 | const appReducer = (state, action) =>
4 | actions[action.type]
5 | ? actions[action.type](state, action.payload) || state
6 | : state;
7 |
8 | export default appReducer;
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/context/index.js:
--------------------------------------------------------------------------------
1 | import AppContext from './AppContext';
2 |
3 | export default AppContext;
4 |
5 | export { default as AppProvider } from './AppProvider';
6 |
7 | export { default as AppProviderOverridenValue } from './AppProviderOverridenValue';
8 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Aden.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [228, 130, 225, 0.13];
4 | const SATURATION_CONST = -0.2;
5 |
6 | /**
7 | * Aden Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Aden]);
13 | */
14 | function Aden(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | Aden.filterName = 'Aden'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Aden;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Amaro.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const SATURATION_CONST = 0.3;
4 | const BRIGHTNESS_CONST = 0.15;
5 |
6 | /**
7 | * Amaro Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Amaro]);
13 | */
14 | function Amaro(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.saturation(SATURATION_CONST),
18 | BaseFilters.brightness(BRIGHTNESS_CONST),
19 | );
20 | }
21 |
22 | Amaro.filterName = 'Amaro'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Amaro;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Ashby.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [255, 160, 25, 0.1];
4 | const BRIGHTNESS_CONST = 0.1;
5 |
6 | /**
7 | * Ashby Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Ashby]);
13 | */
14 | function Ashby(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
18 | BaseFilters.brightness(BRIGHTNESS_CONST),
19 | );
20 | }
21 |
22 | Ashby.filterName = 'Ashby'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Ashby;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/BlackAndWhite.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from "./BaseFilters";
2 |
3 | /**
4 | * BlackAndWhite Filter.
5 | * @function
6 | * @param {Object} imageData
7 | * @example
8 | * node.cache();
9 | * node.filters([BlackAndWhite]);
10 | */
11 | function BlackAndWhite(imageData) {
12 | const thresholdValue = 100;
13 | BaseFilters.apply(
14 | imageData,
15 | (pixels) => {
16 | const isWhite =
17 | (pixels[0] + pixels[1] + pixels[2]) / 3 > thresholdValue;
18 | const val = isWhite ? 255 : 0;
19 | return [val, val, val];
20 | },
21 | );
22 | }
23 |
24 | BlackAndWhite.filterName = 'BlackAndWhite'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default BlackAndWhite;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Brannan.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const CONTRAST_CONST = 0.2;
4 | const COLOR_FILTER_CONST = [140, 10, 185, 0.1];
5 |
6 | /**
7 | * Brannan Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Brannan]);
13 | */
14 | function Brannan(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.contrast(CONTRAST_CONST),
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | );
20 | }
21 |
22 | Brannan.filterName = 'Brannan'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Brannan;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Brooklyn.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [25, 240, 252, 0.05];
4 | const SEPIA_CONST = 0.3;
5 |
6 | /**
7 | * Brooklyn Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Brooklyn]);
13 | */
14 | function Brooklyn(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
18 | BaseFilters.sepia(SEPIA_CONST),
19 | );
20 | }
21 |
22 | Brooklyn.filterName = 'Brooklyn'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Brooklyn;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Charmes.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [255, 50, 80, 0.12];
4 | const CONTRAST_CONST = 0.05;
5 |
6 | /**
7 | * Charmes Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Charmes]);
13 | */
14 | function Charmes(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
18 | BaseFilters.contrast(CONTRAST_CONST),
19 | );
20 | }
21 |
22 | Charmes.filterName = 'Charmes'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Charmes;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Clarendon.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const BRIGHTNESS_CONST = 0.1;
4 | const CONTRAST_CONST = 0.1;
5 | const SATURATION_CONST = 0.15;
6 |
7 | /**
8 | * Clarendon Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([Clarendon]);
14 | */
15 | function Clarendon(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.brightness(BRIGHTNESS_CONST),
19 | BaseFilters.contrast(CONTRAST_CONST),
20 | BaseFilters.saturation(SATURATION_CONST),
21 | );
22 | }
23 |
24 | Clarendon.filterName = 'Clarendon'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Clarendon;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Crema.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const ADJUST_RGB_CONST = [1.04, 1, 1.02];
4 | const SATURATION_CONST = -0.05;
5 |
6 | /**
7 | * Crema Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Crema]);
13 | */
14 | function Crema(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.adjustRGB(ADJUST_RGB_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | Crema.filterName = 'Crema'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Crema;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Dogpatch.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const CONTRAST_CONST = 0.15;
4 | const BRIGHTNESS_CONST = 0.1;
5 |
6 | /**
7 | * Dogpatch Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Dogpatch]);
13 | */
14 | function Dogpatch(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.contrast(CONTRAST_CONST),
18 | BaseFilters.brightness(BRIGHTNESS_CONST),
19 | );
20 | }
21 |
22 | Dogpatch.filterName = 'Dogpatch'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Dogpatch;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Earlybird.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [255, 165, 40, 0.2];
4 |
5 | /**
6 | * Earlybird Filter.
7 | * @function
8 | * @param {Object} imageData
9 | * @example
10 | * node.cache();
11 | * node.filters([Earlybird]);
12 | */
13 | function Earlybird(imageData) {
14 | BaseFilters.apply(
15 | imageData,
16 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
17 | );
18 | }
19 |
20 | Earlybird.filterName = 'Earlybird'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
21 |
22 | export default Earlybird;
23 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Gingham.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const SEPIA_CONST = 0.04;
4 | const CONTRAST_CONST = -0.15;
5 |
6 | /**
7 | * Gingham Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Gingham]);
13 | */
14 | function Gingham(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.sepia(SEPIA_CONST),
18 | BaseFilters.contrast(CONTRAST_CONST),
19 | );
20 | }
21 |
22 | Gingham.filterName = 'Gingham'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Gingham;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Ginza.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const SEPIA_CONST = 0.06;
4 | const BRIGHTNESS_CONST = 0.1;
5 |
6 | /**
7 | * Ginza Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Ginza]);
13 | */
14 | function Ginza(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.sepia(SEPIA_CONST),
18 | BaseFilters.brightness(BRIGHTNESS_CONST),
19 | );
20 | }
21 |
22 | Ginza.filterName = 'Ginza'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Ginza;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Hefe.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const CONTRAST_CONST = 0.1;
4 | const SATURATION_CONST = 0.15;
5 |
6 | /**
7 | * Hefe Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Hefe]);
13 | */
14 | function Hefe(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.contrast(CONTRAST_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | Hefe.filterName = 'Hefe'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Hefe;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Helena.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [208, 208, 86, 0.2];
4 | const CONTRAST_CONST = 0.15;
5 |
6 | /**
7 | * Helena Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Helena]);
13 | */
14 | function Helena(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
18 | BaseFilters.contrast(CONTRAST_CONST),
19 | );
20 | }
21 |
22 | Helena.filterName = 'Helena'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Helena;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Hudson.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const ADJUST_RGB_CONST = [1, 1, 1.25];
4 | const CONTRAST_CONST = 0.1;
5 | const BRIGHTNESS_CONST = 0.15;
6 |
7 | /**
8 | * Hudson Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([Hudson]);
14 | */
15 | function Hudson(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.adjustRGB(ADJUST_RGB_CONST),
19 | BaseFilters.contrast(CONTRAST_CONST),
20 | BaseFilters.brightness(BRIGHTNESS_CONST),
21 | );
22 | }
23 |
24 | Hudson.filterName = 'Hudson'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Hudson;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Juno.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const ADJUST_RGB_CONST = [1.01, 1.04, 1];
4 | const SATURATION_CONST = 0.3;
5 |
6 | /**
7 | * Juno Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Juno]);
13 | */
14 | function Juno(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.adjustRGB(ADJUST_RGB_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | Juno.filterName = 'Juno'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Juno;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Kelvin.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [255, 140, 0, 0.1];
4 | const ADJUST_RGB_CONST = [1.15, 1.05, 1];
5 | const SATURATION_CONST = 0.35;
6 |
7 | /**
8 | * Kelvin Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([Kelvin]);
14 | */
15 | function Kelvin(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | BaseFilters.adjustRGB(ADJUST_RGB_CONST),
20 | BaseFilters.saturation(SATURATION_CONST),
21 | );
22 | }
23 |
24 | Kelvin.filterName = 'Kelvin'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Kelvin;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Lark.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const BRIGHTNESS_CONST = 0.08;
4 | const ADJUST_RGB_CONST = [1, 1.03, 1.05];
5 | const SATURATION_CONST = 0.12;
6 |
7 | /**
8 | * Lark Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([Lark]);
14 | */
15 | function Lark(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.brightness(BRIGHTNESS_CONST),
19 | BaseFilters.adjustRGB(ADJUST_RGB_CONST),
20 | BaseFilters.saturation(SATURATION_CONST),
21 | );
22 | }
23 |
24 | Lark.filterName = 'Lark'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Lark;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/LoFi.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const CONTRAST_CONST = 0.15;
4 | const SATURATION_CONST = 0.2;
5 |
6 | /**
7 | * LoFi Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([LoFi]);
13 | */
14 | function LoFi(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.contrast(CONTRAST_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | LoFi.filterName = 'LoFi'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default LoFi;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Ludwig.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const BRIGHTNESS_CONST = 0.05;
4 | const SATURATION_CONST = -0.03;
5 |
6 | /**
7 | * Ludwig Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Ludwig]);
13 | */
14 | function Ludwig(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.brightness(BRIGHTNESS_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | Ludwig.filterName = 'Ludwig'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Ludwig;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Maven.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [225, 240, 0, 0.1];
4 | const SATURATION_CONST = 0.25;
5 | const CONTRAST_CONST = 0.05;
6 |
7 | /**
8 | * Maven Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([Maven]);
14 | */
15 | function Maven(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | BaseFilters.saturation(SATURATION_CONST),
20 | BaseFilters.contrast(CONTRAST_CONST),
21 | );
22 | }
23 |
24 | Maven.filterName = 'Maven'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Maven;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Mayfair.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [230, 115, 108, 0.05];
4 | const SATURATION_CONST = 0.15;
5 |
6 | /**
7 | * Mayfair Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Mayfair]);
13 | */
14 | function Mayfair(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | Mayfair.filterName = 'Mayfair'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Mayfair;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Moon.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const BRIGHTNESS_CONST = 0.1;
4 |
5 | /**
6 | * Moon Filter.
7 | * @function
8 | * @param {Object} imageData
9 | * @example
10 | * node.cache();
11 | * node.filters([Moon]);
12 | */
13 | function Moon(imageData) {
14 | BaseFilters.apply(
15 | imageData,
16 | BaseFilters.grayscale(),
17 | BaseFilters.brightness(BRIGHTNESS_CONST),
18 | );
19 |
20 | const pixels = imageData.data; // [0, 1, 2, 3,...] => [r, g, b, a, ...]
21 | const len = pixels.length;
22 | }
23 |
24 | Moon.filterName = 'Moon'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Moon;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Nashville.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [220, 115, 188, 0.12];
4 | const CONTRAST_CONST = -0.05;
5 |
6 | /**
7 | * Nashville Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Nashville]);
13 | */
14 | function Nashville(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
18 | BaseFilters.contrast(CONTRAST_CONST),
19 | );
20 | }
21 |
22 | Nashville.filterName = 'Nashville'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Nashville;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/NinteenSeventySeven.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [255, 25, 0, 0.15];
4 | const BRIGHTNESS_CONST = 0.1;
5 |
6 | /**
7 | * NinteenSeventySeven Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([NinteenSeventySeven]);
13 | */
14 | function NinteenSeventySeven(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
18 | BaseFilters.brightness(BRIGHTNESS_CONST),
19 | );
20 | }
21 |
22 | NinteenSeventySeven.filterName = 'NinteenSeventySeven'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default NinteenSeventySeven;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Perpetua.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const ADJUST_RGB_CONST = [1.05, 1.1, 1];
4 |
5 | /**
6 | * Perpetua Filter.
7 | * @function
8 | * @param {Object} imageData
9 | * @example
10 | * node.cache();
11 | * node.filters([Perpetua]);
12 | */
13 | function Perpetua(imageData) {
14 | BaseFilters.apply(
15 | imageData,
16 | BaseFilters.adjustRGB(ADJUST_RGB_CONST),
17 | );
18 | }
19 |
20 | Perpetua.filterName = 'Perpetua'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
21 |
22 | export default Perpetua;
23 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Reyes.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const SEPIA_CONST = 0.4;
4 | const BRIGHTNESS_CONST = 0.13;
5 | const CONTRAST_CONST = -0.05;
6 |
7 | /**
8 | * Reyes Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([Reyes]);
14 | */
15 | function Reyes(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.sepia(SEPIA_CONST),
19 | BaseFilters.brightness(BRIGHTNESS_CONST),
20 | BaseFilters.contrast(CONTRAST_CONST),
21 | );
22 | }
23 |
24 | Reyes.filterName = 'Reyes'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Reyes;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Rise.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [255, 170, 0, 0.1];
4 | const BRIGHTNESS_CONST = 0.09;
5 | const SATURATION_CONST = 0.1;
6 |
7 | /**
8 | * Rise Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([Rise]);
14 | */
15 | function Rise(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | BaseFilters.brightness(BRIGHTNESS_CONST),
20 | BaseFilters.saturation(SATURATION_CONST),
21 | );
22 | }
23 |
24 | Rise.filterName = 'Rise'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Rise;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Sierra.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const CONTRAST_CONST = -0.15;
4 | const SATURATION_CONST = 0.1;
5 |
6 | /**
7 | * Sierra Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Sierra]);
13 | */
14 | function Sierra(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.contrast(CONTRAST_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | Sierra.filterName = 'Sierra'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Sierra;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Skyline.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const SATURATION_CONST = 0.35;
4 | const BRIGHTNESS_CONST = 0.1;
5 |
6 | /**
7 | * Skyline Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Skyline]);
13 | */
14 | function Skyline(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.saturation(SATURATION_CONST),
18 | BaseFilters.brightness(BRIGHTNESS_CONST),
19 | );
20 | }
21 |
22 | Skyline.filterName = 'Skyline'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Skyline;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Slumber.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const BRIGHTNESS_CONST = 0.1;
4 | const SATURATION_CONST = -0.5;
5 |
6 | /**
7 | * Slumber Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Slumber]);
13 | */
14 | function Slumber(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.brightness(BRIGHTNESS_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | Slumber.filterName = 'Slumber'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Slumber;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Stinson.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const BRIGHTNESS_CONST = 0.1;
4 | const SEPIA_CONST = 0.3;
5 |
6 | /**
7 | * Stinson Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Stinson]);
13 | */
14 | function Stinson(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.brightness(BRIGHTNESS_CONST),
18 | BaseFilters.sepia(SEPIA_CONST),
19 | );
20 | }
21 |
22 | Stinson.filterName = 'Stinson'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Stinson;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Sutro.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const BRIGHTNESS_CONST = -0.1;
4 | const SATURATION_CONST = -0.1;
5 |
6 | /**
7 | * Sutro Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Sutro]);
13 | */
14 | function Sutro(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.brightness(BRIGHTNESS_CONST),
18 | BaseFilters.saturation(SATURATION_CONST),
19 | );
20 | }
21 |
22 | Sutro.filterName = 'Sutro'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Sutro;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Toaster.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const SEPIA_CONST = 0.1;
4 | const COLOR_FILTER_CONST = [255, 145, 0, 0.2];
5 |
6 | /**
7 | * Toaster Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Toaster]);
13 | */
14 | function Toaster(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.sepia(SEPIA_CONST),
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | );
20 | }
21 |
22 | Toaster.filterName = 'Toaster'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Toaster;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Valencia.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [255, 225, 80, 0.08];
4 | const SATURATION_CONST = 0.1;
5 | const CONTRAST_CONST = 0.05;
6 |
7 | /**
8 | * Valencia Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([Valencia]);
14 | */
15 | function Valencia(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | BaseFilters.saturation(SATURATION_CONST),
20 | BaseFilters.contrast(CONTRAST_CONST),
21 | );
22 | }
23 |
24 | Valencia.filterName = 'Valencia'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Valencia;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Vesper.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [255, 225, 0, 0.05];
4 | const BRIGHTNESS_CONST = 0.06;
5 | const CONTRAST_CONST = 0.06;
6 |
7 | /**
8 | * Vesper Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([Vesper]);
14 | */
15 | function Vesper(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | BaseFilters.brightness(BRIGHTNESS_CONST),
20 | BaseFilters.contrast(CONTRAST_CONST),
21 | );
22 | }
23 |
24 | Vesper.filterName = 'Vesper'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default Vesper;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Walden.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const BRIGHTNESS_CONST = 0.1;
4 | const COLOR_FILTER_CONST = [255, 255, 0, 0.2];
5 |
6 | /**
7 | * Walden Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Walden]);
13 | */
14 | function Walden(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.brightness(BRIGHTNESS_CONST),
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | );
20 | }
21 |
22 | Walden.filterName = 'Walden'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
23 |
24 | export default Walden;
25 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/Willow.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [100, 28, 210, 0.03];
4 | const BRIGHTNESS_CONST = 0.1;
5 |
6 | /**
7 | * Willow Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Willow]);
13 | */
14 | function Willow(imageData) {
15 | BaseFilters.apply(
16 | imageData,
17 | BaseFilters.grayscale(),
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | BaseFilters.brightness(BRIGHTNESS_CONST),
20 | );
21 | }
22 |
23 | Willow.filterName = 'Willow'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
24 |
25 | export default Willow;
26 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/filters/XPro2.js:
--------------------------------------------------------------------------------
1 | import BaseFilters from './BaseFilters';
2 |
3 | const COLOR_FILTER_CONST = [255, 255, 0, 0.07];
4 | const SATURATION_CONST = 0.2;
5 | const CONTRAST_CONST = 0.15;
6 |
7 | /**
8 | * XPro2 Filter.
9 | * @function
10 | * @param {Object} imageData
11 | * @example
12 | * node.cache();
13 | * node.filters([XPro2]);
14 | */
15 | function XPro2(imageData) {
16 | BaseFilters.apply(
17 | imageData,
18 | BaseFilters.colorFilter(COLOR_FILTER_CONST),
19 | BaseFilters.saturation(SATURATION_CONST),
20 | BaseFilters.contrast(CONTRAST_CONST),
21 | );
22 | }
23 |
24 | XPro2.filterName = 'XPro2'; // We assign the filter name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
25 |
26 | export default XPro2;
27 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/finetunes/CustomThreshold.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import Konva from 'konva';
3 | import { Factory as KonvaFactory } from 'konva/lib/Factory';
4 | import { getNumberValidator as konvaGetNumberValidator } from 'konva/lib/Validators';
5 |
6 | /**
7 | * CustomThreshold Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([CustomThreshold]);
13 | * node.threshold(100);
14 | */
15 | function CustomThreshold(imageData) {
16 | const thresholdValue = this.threshold();
17 | const isZeroThreshold = thresholdValue === 0;
18 | const pixels = imageData.data; // [0, 1, 2, 3,...] => [r, g, b, a, ...]
19 | const len = pixels.length;
20 |
21 | for (let i = 0; i < len; i += 4) {
22 | if (!isZeroThreshold) {
23 | pixels[i] = pixels[i] >= thresholdValue ? 255 : 0;
24 | pixels[i + 1] = pixels[i + 1] >= thresholdValue ? 255 : 0;
25 | pixels[i + 2] = pixels[i + 2] >= thresholdValue ? 255 : 0;
26 | }
27 | }
28 | }
29 |
30 | CustomThreshold.finetuneName = 'CustomThreshold'; // We assign the finetune name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
31 |
32 | export default CustomThreshold;
33 |
34 | /**
35 | * adds threshold parameter (0 - 255), 0 means no value... 255 max value.
36 | */
37 | KonvaFactory.addGetterSetter(
38 | Konva.Image,
39 | 'threshold',
40 | 0,
41 | konvaGetNumberValidator,
42 | KonvaFactory.afterSetFilter,
43 | );
44 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/finetunes/Warmth.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import Konva from 'konva';
3 | import { Factory as KonvaFactory } from 'konva/lib/Factory';
4 | import { getNumberValidator as konvaGetNumberValidator } from 'konva/lib/Validators';
5 |
6 | /**
7 | * Warmth Filter.
8 | * @function
9 | * @param {Object} imageData
10 | * @example
11 | * node.cache();
12 | * node.filters([Warmth]);
13 | * node.warmth(100);
14 | * Red (r) > Blue (b) means warmer effect
15 | * Red (r) < Blue (b) means cooler effect
16 | */
17 | function Warmth(imageData) {
18 | const warmthValue = this.warmth();
19 | const pixels = imageData.data; // [0, 1, 2, 3,...] => [r, g, b, a, ...]
20 | const len = pixels.length;
21 |
22 | for (let i = 0; i < len; i += 4) {
23 | // red
24 | pixels[i] += warmthValue;
25 | // blue
26 | pixels[i + 2] -= warmthValue;
27 | }
28 | }
29 |
30 | Warmth.finetuneName = 'Warmth'; // We assign the finetune name here instead of using the fn. name as on prod. code the fn. name is optimized that might cause bug in that case.
31 |
32 | export default Warmth;
33 |
34 | /**
35 | * adds warmth parameter (0 - 200), 0 means no value... 200 max value.
36 | */
37 | KonvaFactory.addGetterSetter(
38 | Konva.Image,
39 | 'warmth',
40 | 0,
41 | konvaGetNumberValidator(),
42 | KonvaFactory.afterSetFilter,
43 | );
44 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/custom/finetunes/index.js:
--------------------------------------------------------------------------------
1 | export { default as Warmth } from './Warmth';
2 |
3 | export { default as CustomThreshold } from './CustomThreshold';
4 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/hooks/index.js:
--------------------------------------------------------------------------------
1 | export { default as useFinetune } from './useFinetune';
2 |
3 | export { default as useFilter } from './useFilter';
4 |
5 | export { default as useAnnotation } from './useAnnotation';
6 |
7 | export { default as useAppReducer } from './useAppReducer';
8 |
9 | export { default as useAnnotationEvents } from './useAnnotationEvents';
10 |
11 | export { default as useResizeObserver } from './useResizeObserver';
12 |
13 | export { default as useDebouncedCallback } from './useDebouncedCallback';
14 |
15 | export { default as useStore } from './useStore';
16 |
17 | export { default as useDrag } from './useDrag';
18 |
19 | export { default as usePhoneScreen } from './usePhoneScreen';
20 |
21 | export { default as useTransformedImgData } from './useTransformedImgData';
22 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/hooks/useAnnotation/getBoundingRectUnScaled.js:
--------------------------------------------------------------------------------
1 | const getBoundingRectUnScaled = (
2 | pointerOffsets = {},
3 | pointerDown = {},
4 | previewGroup,
5 | ) => {
6 | const boundingRect = {};
7 | const parentAttrs = previewGroup.parent.attrs;
8 | boundingRect.x =
9 | Math.min(pointerOffsets.offsetX, pointerDown.startedX) -
10 | parentAttrs.xPadding || 0;
11 | boundingRect.y =
12 | Math.min(pointerOffsets.offsetY, pointerDown.startedY) -
13 | parentAttrs.yPadding || 0;
14 | boundingRect.width = pointerOffsets.offsetX - pointerDown.startedX;
15 | boundingRect.height = pointerOffsets.offsetY - pointerDown.startedY;
16 | boundingRect.startedX = pointerDown.startedX - parentAttrs.xPadding || 0;
17 | boundingRect.startedY = pointerDown.startedY - parentAttrs.yPadding || 0;
18 |
19 | return boundingRect;
20 | };
21 |
22 | export default getBoundingRectUnScaled;
23 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/hooks/useDebouncedCallback.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { useCallback } from 'react';
3 |
4 | /** Internal Dependencies */
5 | import debounce from 'utils/debounce';
6 |
7 | const useDebouncedCallback = (func, timeout, dependencies = []) =>
8 | useCallback(debounce(func, timeout), dependencies);
9 |
10 | export default useDebouncedCallback;
11 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/hooks/useDrag.js:
--------------------------------------------------------------------------------
1 | const useDrag = (onMove, onStart, onEnd) => {
2 | const onDragging = (e) => {
3 | if (typeof onMove === 'function') {
4 | onMove(e.touches?.[0] || e);
5 | }
6 | };
7 |
8 | const disableSliding = (e) => {
9 | document.removeEventListener('mousemove', onDragging);
10 | document.removeEventListener('mouseup', disableSliding);
11 | document.removeEventListener('mouseleave', disableSliding);
12 | document.removeEventListener('touchmove', onDragging);
13 | document.removeEventListener('touchend', disableSliding);
14 | document.removeEventListener('touchcancel', disableSliding);
15 |
16 | if (typeof onEnd === 'function') {
17 | onEnd(e.touches?.[0] || e);
18 | }
19 | };
20 |
21 | const enableDrag = (e) => {
22 | document.addEventListener('mousemove', onDragging);
23 | document.addEventListener('mouseup', disableSliding);
24 | document.addEventListener('mouseleave', disableSliding);
25 | document.addEventListener('touchmove', onDragging);
26 | document.addEventListener('touchend', disableSliding);
27 | document.addEventListener('touchcancel', disableSliding);
28 |
29 | if (typeof onStart === 'function') {
30 | onStart(e.touches?.[0] || e);
31 | }
32 | };
33 |
34 | return {
35 | onMouseDown: enableDrag,
36 | onTouchStart: enableDrag,
37 | };
38 | };
39 |
40 | export default useDrag;
41 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/hooks/useFilter.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { useCallback, useMemo } from 'react';
3 |
4 | /** Internal Dependencies */
5 | import { ADD_FILTER } from 'actions';
6 | import useStore from './useStore';
7 |
8 | const useFilter = () => {
9 | const { dispatch, filter } = useStore();
10 |
11 | const setFilter = useCallback((filterToApply) => {
12 | dispatch({
13 | type: ADD_FILTER,
14 | payload: {
15 | filter: filterToApply,
16 | },
17 | });
18 | }, []);
19 |
20 | return useMemo(() => [filter, setFilter], [filter]);
21 | };
22 |
23 | export default useFilter;
24 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/hooks/useFinetune.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { useCallback, useEffect, useMemo } from 'react';
3 |
4 | /** Internal Dependencies */
5 | import { SET_FINETUNE } from 'actions';
6 | import isDefaultZeroValuesOnly from 'utils/isDefaultZeroValuesOnly';
7 | import useStore from './useStore';
8 |
9 | const useFinetune = (finetune, initialProps) => {
10 | const { dispatch, finetunes, finetunesProps } = useStore();
11 |
12 | const setFinetuneWithProps = useCallback((newFinetuneProps) => {
13 | dispatch({
14 | type: SET_FINETUNE,
15 | payload: {
16 | finetune,
17 | finetuneProps: newFinetuneProps,
18 | },
19 | });
20 | }, []);
21 |
22 | useEffect(() => {
23 | if (!finetunes.includes(finetune) && !isDefaultZeroValuesOnly(initialProps, finetunesProps)) {
24 | // initialProps first if we've any similar prop set before w/ diff. val don't override.
25 | setFinetuneWithProps({
26 | ...initialProps,
27 | ...finetunesProps,
28 | });
29 | }
30 | }, []);
31 |
32 | return useMemo(
33 | () => [finetunesProps, setFinetuneWithProps],
34 | [finetunesProps],
35 | );
36 | };
37 |
38 | export default useFinetune;
39 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/hooks/usePhoneScreen.js:
--------------------------------------------------------------------------------
1 | const usePhoneScreen = (screenWidth = 438) =>
2 | window.matchMedia(`(max-width: ${screenWidth}px)`).matches;
3 |
4 | export default usePhoneScreen;
5 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/hooks/useStore.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { useContext } from 'react';
3 |
4 | /** Internal Dependencies */
5 | import AppContext from 'context';
6 |
7 | const useStore = () => useContext(AppContext);
8 | export default useStore;
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/hooks/useUpdateEffect.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import { useEffect, useRef } from 'react';
3 |
4 | const useUpdateEffect = (effectCallback, dependencies) => {
5 | const isFirstRender = useRef(true);
6 |
7 | useEffect(
8 | () => () => {
9 | isFirstRender.current = true;
10 | },
11 | [],
12 | );
13 |
14 | useEffect(() => {
15 | if (isFirstRender.current) {
16 | isFirstRender.current = false;
17 | } else if (typeof effectCallback === 'function') {
18 | return effectCallback();
19 | }
20 |
21 | return undefined;
22 | }, dependencies);
23 | };
24 |
25 | export default useUpdateEffect;
26 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/index.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import FilerobotImageEditor from 'components/AssemblyPoint';
3 | import { TABS_IDS, TOOLS_IDS } from 'utils/constants';
4 |
5 | export { TABS_IDS as TABS, TOOLS_IDS as TOOLS };
6 |
7 | export default FilerobotImageEditor;
8 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/assignFinetuneNamesToKonva.js:
--------------------------------------------------------------------------------
1 | const assignFinetuneNamesToKonva = () => {
2 | Object.keys(Konva.Filters).forEach((key) => Konva.Filters[key].finetuneName = key)
3 | }
4 |
5 | export default assignFinetuneNamesToKonva;
6 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/calculateZoomData.js:
--------------------------------------------------------------------------------
1 | import { DEFAULT_ZOOM_FACTOR } from './constants';
2 |
3 | const calculateZoomData = (newZoom, oldZoom, canvasWidth, canvasHeight) => {
4 | if (newZoom.factor === DEFAULT_ZOOM_FACTOR) {
5 | return {
6 | x: 0,
7 | y: 0,
8 | factor: DEFAULT_ZOOM_FACTOR,
9 | };
10 | }
11 |
12 | const isZoomIn = newZoom.factor > oldZoom.factor;
13 | const mousePointTo = {
14 | x: (newZoom.x - oldZoom.x || 0) / oldZoom.factor,
15 | y: (newZoom.y - oldZoom.y || 0) / oldZoom.factor,
16 | };
17 |
18 | const newPos = {
19 | x: newZoom.x - mousePointTo.x * newZoom.factor,
20 | y: newZoom.y - mousePointTo.y * newZoom.factor,
21 | };
22 | if (!isZoomIn || oldZoom.factor !== 1) {
23 | newPos.x = Math.min(
24 | 0,
25 | Math.max(newPos.x, canvasWidth * (1 - oldZoom.factor)),
26 | );
27 | newPos.y = Math.min(
28 | 0,
29 | Math.max(newPos.y, canvasHeight * (1 - oldZoom.factor)),
30 | );
31 | }
32 |
33 | if (newZoom.factor < 1) {
34 | const initialAndScaledWidthDiff =
35 | canvasWidth - canvasWidth * newZoom.factor;
36 | const initialAndScaledHeightDiff =
37 | canvasHeight - canvasHeight * newZoom.factor;
38 | newPos.x += initialAndScaledWidthDiff / 2;
39 | newPos.y += initialAndScaledHeightDiff / 2;
40 | }
41 |
42 | return {
43 | ...newPos,
44 | factor: newZoom.factor,
45 | };
46 | };
47 |
48 | export default calculateZoomData;
49 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/compareRatios.js:
--------------------------------------------------------------------------------
1 | import toPrecisedFloat from './toPrecisedFloat';
2 |
3 | const compareRatios = (ratio1, ratio2) =>
4 | toPrecisedFloat(ratio1) === toPrecisedFloat(ratio2);
5 |
6 | export default compareRatios;
7 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/cropImage.js:
--------------------------------------------------------------------------------
1 | import { ELLIPSE_CROP } from './constants';
2 |
3 | const cropImage = (context, cropBox, noEllipticalCrop = false) => {
4 | if (cropBox.ratio === ELLIPSE_CROP && !noEllipticalCrop) {
5 | context.ellipse(
6 | cropBox.x + cropBox.width / 2,
7 | cropBox.y + cropBox.height / 2,
8 | cropBox.width / 2,
9 | cropBox.height / 2,
10 | 0,
11 | 0,
12 | 2 * Math.PI,
13 | );
14 | } else {
15 | context.rect(cropBox.x, cropBox.y, cropBox.width, cropBox.height);
16 | }
17 | };
18 |
19 | export default cropImage;
20 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/debounce.js:
--------------------------------------------------------------------------------
1 | const debounce = (func, timeout = 300) => {
2 | let timer;
3 |
4 | return (...args) => {
5 | clearTimeout(timer);
6 | const [firstArg, ...otherArgs] = args;
7 | timer = setTimeout(
8 | func.bind(null, firstArg?.target?.value ?? firstArg, ...otherArgs),
9 | timeout,
10 | );
11 | };
12 | };
13 |
14 | export default debounce;
15 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/deepMerge.js:
--------------------------------------------------------------------------------
1 | const deepMerge = (source, object = {}, considerArray = false) => {
2 | const mergedObject = { ...source };
3 | const keys = Object.keys(object);
4 | keys.forEach((k) => {
5 | // considers null in the values.
6 | const val = object[k];
7 | if (val !== undefined) {
8 | const valType = typeof val;
9 | if (
10 | valType !== 'object' ||
11 | val instanceof HTMLElement ||
12 | val === null ||
13 | Array.isArray(val) ||
14 | !source[k] ||
15 | typeof source[k] !== 'object'
16 | ) {
17 | mergedObject[k] =
18 | considerArray && Array.isArray(mergedObject[k]) && Array.isArray(val)
19 | ? [...mergedObject[k], ...val]
20 | : val;
21 | return;
22 | }
23 |
24 | // After the above condition we now have both of them in type objects.
25 | mergedObject[k] = deepMerge(source[k], val);
26 | }
27 | });
28 |
29 | return mergedObject;
30 | };
31 |
32 | export default deepMerge;
33 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/extractCurrentDesignState.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import defaultConfig from 'context/defaultConfig';
3 | import getInitialAppState from 'context/getInitialAppState';
4 |
5 | /**
6 | * Extracts the needed properties/state that are used in canvas's design from the global state.
7 | *
8 | * @param {Object} state The global state.
9 | * @param {Object} defaultValue Value assigned to any undefined/null property in returned object.
10 | * @returns {Object} The extracted design state.
11 | */
12 | const extractCurrentDesignState = (state, useStateAsConfig) => {
13 | const initialAppState = getInitialAppState(
14 | useStateAsConfig ? state : defaultConfig,
15 | );
16 |
17 | return {
18 | imgSrc: state.imgSrc || initialAppState.imgSrc,
19 | finetunes: state.finetunes || initialAppState.finetunes,
20 | finetunesProps: state.finetunesProps || initialAppState.finetunesProps,
21 | filter: state.filter || initialAppState.filter,
22 | adjustments: state.adjustments || initialAppState.adjustments,
23 | annotations: state.annotations || initialAppState.annotations,
24 | resize: state.resize || initialAppState.resize,
25 | };
26 | };
27 |
28 | export default extractCurrentDesignState;
29 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/extractNameFromUrl.js:
--------------------------------------------------------------------------------
1 | const extractNameFromUrl = (url) => {
2 | const urlParts = url.split('/');
3 | return urlParts[urlParts.length - 1].split('?')[0];
4 | };
5 |
6 | export default extractNameFromUrl;
7 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/filterStrToClass.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import Konva from 'konva';
3 |
4 | /** Internal Dependencies */
5 | import * as CustomFilters from 'custom/filters';
6 |
7 | const filterStrToClass = (filterString) => {
8 | if (filterString) {
9 | return CustomFilters[filterString] || Konva.Filters[filterString];
10 | }
11 |
12 | return null;
13 | };
14 |
15 | export default filterStrToClass;
16 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/finetunesStrsToClasses.js:
--------------------------------------------------------------------------------
1 | /** External Dependencies */
2 | import Konva from 'konva';
3 |
4 | /** Internal Dependencies */
5 | import * as CustomFinetunes from 'custom/finetunes';
6 |
7 | const finetunesStrsToClasses = (finetunesStrings) => {
8 | if (Array.isArray(finetunesStrings) && finetunesStrings.length > 0) {
9 | return finetunesStrings.map(
10 | (finetuneClassName) =>
11 | Konva.Filters[finetuneClassName] || CustomFinetunes[finetuneClassName],
12 | );
13 | }
14 |
15 | return [];
16 | };
17 |
18 | export default finetunesStrsToClasses;
19 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getCenterRotatedPoint.js:
--------------------------------------------------------------------------------
1 | const getRotatedPoint = ({ x, y }, angleDegree) => {
2 | const radianAngle = (angleDegree * Math.PI) / 180;
3 | const rcos = Math.cos(radianAngle);
4 | const rsin = Math.sin(radianAngle);
5 | return { x: x * rcos - y * rsin, y: y * rcos + x * rsin };
6 | };
7 |
8 | const getCenterRotatedPoint = (width, height, newRotationAngleDegree) => {
9 | if (
10 | !width ||
11 | !height ||
12 | (!newRotationAngleDegree && newRotationAngleDegree !== 0)
13 | ) {
14 | return {
15 | x: 0,
16 | y: 0,
17 | rotation: newRotationAngleDegree,
18 | };
19 | }
20 | const topLeft = { x: -width / 2, y: -height / 2 };
21 | const current = getRotatedPoint(topLeft, 0);
22 | const rotated = getRotatedPoint(topLeft, newRotationAngleDegree);
23 | const dx = rotated.x - current.x;
24 | const dy = rotated.y - current.y;
25 |
26 | return { x: dx, y: dy, rotation: newRotationAngleDegree };
27 | };
28 |
29 | export default getCenterRotatedPoint;
30 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getDefaultSaveQuality.js:
--------------------------------------------------------------------------------
1 | import { DEFAULT_SAVE_QUALITY } from './constants';
2 |
3 | const getDefaultSaveQuality = (providedDefaultQuality) =>
4 | providedDefaultQuality <= 0 || providedDefaultQuality > 1
5 | ? DEFAULT_SAVE_QUALITY
6 | : providedDefaultQuality;
7 |
8 | export default getDefaultSaveQuality;
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getDimensionsMinimalRatio.js:
--------------------------------------------------------------------------------
1 | const getDimensionsMinimalRatio = (
2 | firstWidth,
3 | firstHeight,
4 | secondWidth,
5 | secondHeight,
6 | ) => {
7 | const widthScale = firstWidth / secondWidth;
8 | const heightScale = firstHeight / secondHeight;
9 |
10 | return Math.min(widthScale, heightScale) || 1;
11 | };
12 |
13 | export default getDimensionsMinimalRatio;
14 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getElemDocumentCoords.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import getScrollOffset from './getScrollOffset';
3 |
4 | const getElemDocumentCoords = (elem) => {
5 | if (!elem) {
6 | return null;
7 | }
8 | const box = elem.getBoundingClientRect();
9 |
10 | const { body } = document;
11 | const { topOffset, leftOffset } = getScrollOffset();
12 |
13 | const docEl = document.documentElement;
14 | const clientTop = docEl.clientTop || body.clientTop || 0;
15 | const clientLeft = docEl.clientLeft || body.clientLeft || 0;
16 |
17 | const top = box.top + topOffset - clientTop;
18 | const left = box.left + leftOffset - clientLeft;
19 |
20 | return {
21 | top: Math.round(top),
22 | left: Math.round(left),
23 | width: box.width,
24 | height: box.height,
25 | };
26 | };
27 |
28 | export default getElemDocumentCoords;
29 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getFileFullName.js:
--------------------------------------------------------------------------------
1 | import {
2 | DEFAULT_IMAGE_TYPE,
3 | POSSIBLE_IMAGE_TYPES,
4 | SUPPORTED_IMAGE_TYPES,
5 | } from './constants';
6 |
7 | const getFileFullName = (fileName = '', appendedExtension) => {
8 | let finalExtension = appendedExtension;
9 | let finalFileName = fileName;
10 | if (
11 | !finalExtension &&
12 | POSSIBLE_IMAGE_TYPES.some(
13 | (extension) =>
14 | fileName.lastIndexOf(`.${extension}`) ===
15 | fileName.length - `.${extension}`.length,
16 | )
17 | ) {
18 | const currentExtension = fileName
19 | .slice(fileName.lastIndexOf('.') + 1)
20 | ?.toLowerCase();
21 | finalExtension =
22 | currentExtension && SUPPORTED_IMAGE_TYPES.includes(currentExtension)
23 | ? currentExtension
24 | : DEFAULT_IMAGE_TYPE;
25 | finalFileName = fileName.slice(0, fileName.lastIndexOf('.'));
26 | }
27 |
28 | finalExtension = finalExtension || DEFAULT_IMAGE_TYPE;
29 |
30 | return {
31 | fullName: `${finalFileName}.${finalExtension}`,
32 | name: finalFileName,
33 | extension: finalExtension,
34 | };
35 | };
36 |
37 | export default getFileFullName;
38 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getImageSealingParams.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import sha1 from './sha1';
3 |
4 | const encodeBase64 = (str) => {
5 | return btoa(str).replace(/=*$/g, '');
6 | };
7 |
8 | const getSha1 = (str, length) => {
9 | return sha1(str).slice(0, length);
10 | };
11 |
12 | const getSealingParams = (paramsStr, originalUrl, salt, charCount) => {
13 | const base64String = encodeBase64(paramsStr);
14 | const calcHash = getSha1(originalUrl + base64String + salt, charCount);
15 |
16 | return [
17 | calcHash ? `ci_seal=${calcHash}` : '',
18 | base64String ? `ci_eqs=${base64String}` : '',
19 | ]
20 | .filter((i) => i)
21 | .join('&');
22 | };
23 |
24 | const getImageSealingParams = (paramsStr, imageSealing, originalUrl) => {
25 | const { salt, charCount, includeParams = [] } = imageSealing || {};
26 | const isIncludeParamsEmpty = !includeParams || includeParams?.length === 0;
27 |
28 | let sealingParamsStr = '';
29 | let restParamsStr = '';
30 |
31 | const sealingParams = [];
32 | const restParams = [];
33 |
34 | paramsStr.split('&').forEach((item) => {
35 | const [paramName] = item.split('=');
36 |
37 | if (includeParams?.indexOf(paramName) > -1 || isIncludeParamsEmpty) {
38 | sealingParams.push(item);
39 | } else {
40 | restParams.push(item);
41 | }
42 | });
43 |
44 | if (restParams.length > 0) {
45 | restParamsStr = restParams.join('&');
46 | }
47 |
48 | // We need to add sealing always, even if sealingParams is empty.
49 | // In case with empty params sealing will be like: ci_seal=10613a92e5
50 | sealingParamsStr = getSealingParams(
51 | sealingParams.join('&'),
52 | originalUrl,
53 | salt,
54 | charCount,
55 | );
56 |
57 | return [sealingParamsStr, restParamsStr].filter((p) => p).join('&');
58 | };
59 |
60 | export default getImageSealingParams;
61 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getPointerOffsetPositionBoundedToObject.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import restrictNumber from './restrictNumber';
3 |
4 | /**
5 | * Gets the touch/mouse position relative to the passed object to be considred as offset X/Y.
6 | *
7 | * @param {Object} previewGroup - The preview group that is a direct child of the design layer
8 | * @param {Object} relativeToObject - The object to be considered as parent element
9 | * contains left, top, width & height relative to the document.
10 | * @returns {Object} both X & Y offset values.
11 | */
12 | const getPointerOffsetPositionBoundedToObject = (
13 | previewGroup = {},
14 | relativeToObject = {},
15 | ) => {
16 | const designLayer = previewGroup.parent;
17 | const canvas = designLayer.getStage();
18 | const canvasZoomFactor = canvas.attrs.zoomFactor;
19 | const pos = designLayer.getRelativePointerPosition();
20 |
21 | return {
22 | offsetX:
23 | restrictNumber(
24 | pos.x,
25 | 0,
26 | relativeToObject.width / (canvas.scaleX() / canvasZoomFactor),
27 | ) + designLayer.attrs.xPadding,
28 | offsetY:
29 | restrictNumber(
30 | pos.y,
31 | 0,
32 | relativeToObject.height / (canvas.scaleY() / canvasZoomFactor),
33 | ) + designLayer.attrs.yPadding,
34 | };
35 | };
36 |
37 | export default getPointerOffsetPositionBoundedToObject;
38 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getProperDimensions.js:
--------------------------------------------------------------------------------
1 | /** Internal Dependencies */
2 | import getSizeAfterRotation from './getSizeAfterRotation';
3 | import mapCropBox from './mapCropBox';
4 |
5 | const getProperDimensions = (
6 | resizeDimensions,
7 | cropDimensions,
8 | shownImageDimensions,
9 | originalDimensions,
10 | rotationAngle = 0,
11 | ) => {
12 | if (resizeDimensions.width && resizeDimensions.height) {
13 | return resizeDimensions;
14 | }
15 |
16 | const mappedCropArea = mapCropBox(
17 | cropDimensions,
18 | shownImageDimensions,
19 | originalDimensions,
20 | );
21 | const croppedRotatedArea = getSizeAfterRotation(
22 | mappedCropArea.width,
23 | mappedCropArea.height,
24 | rotationAngle,
25 | );
26 | if (resizeDimensions.width || resizeDimensions.height) {
27 | return {
28 | width: resizeDimensions.width || croppedRotatedArea.width,
29 | height: resizeDimensions.height || croppedRotatedArea.height,
30 | };
31 | }
32 |
33 | return (
34 | (croppedRotatedArea.width &&
35 | croppedRotatedArea.height &&
36 | croppedRotatedArea) || {
37 | ...originalDimensions,
38 | ...getSizeAfterRotation(
39 | originalDimensions.width,
40 | originalDimensions.height,
41 | rotationAngle,
42 | ),
43 | }
44 | );
45 | };
46 |
47 | export default getProperDimensions;
48 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getProperImageToCanvasSpacing.js:
--------------------------------------------------------------------------------
1 | const SPACING_PERCENTAGE = 0.05;
2 | const DEFAULT_SPACING = 12;
3 |
4 | const getProperImageToCanvasSpacing = () =>
5 | (window
6 | ? Math.min(window.innerHeight, window.innerWidth) * SPACING_PERCENTAGE
7 | : DEFAULT_SPACING) * 2;
8 |
9 | export default getProperImageToCanvasSpacing;
10 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getScrollOffset.js:
--------------------------------------------------------------------------------
1 | const getScrollOffset = () => {
2 | const { body } = document;
3 | const docEl = document.documentElement;
4 |
5 | const scrollTop = window?.pageYOffset || docEl.scrollTop || body.scrollTop;
6 | const scrollLeft = window?.pageXOffset || docEl.scrollLeft || body.scrollLeft;
7 |
8 | return {
9 | topOffset: scrollTop,
10 | leftOffset: scrollLeft,
11 | };
12 | };
13 |
14 | export default getScrollOffset;
15 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getSizeAfterRotation.js:
--------------------------------------------------------------------------------
1 | const getSizeAfterRotation = (width, height, rotationAngleInDegree = 0) => {
2 | const absRotationAngleInDegree = Math.abs(rotationAngleInDegree);
3 | const roundedDegree = Math.round(rotationAngleInDegree);
4 | const isGreaterThan90Degree = absRotationAngleInDegree > 90;
5 | const currentAbsRotationAngleInDegree = isGreaterThan90Degree
6 | ? absRotationAngleInDegree - 90
7 | : absRotationAngleInDegree;
8 | const currentWidth = isGreaterThan90Degree ? height : width;
9 | const currentHeight = isGreaterThan90Degree ? width : height;
10 | const radianAngle = (currentAbsRotationAngleInDegree * Math.PI) / 180;
11 | const sin = Math.abs(Math.sin(radianAngle));
12 | const cos = Math.abs(Math.cos(radianAngle));
13 | const getLeftOffset = () =>
14 | roundedDegree > 90
15 | ? currentWidth * cos + currentHeight * sin
16 | : currentHeight * sin;
17 | const getTopOffset = () => {
18 | if (roundedDegree < 0 && roundedDegree > -90) {
19 | return currentWidth * sin;
20 | }
21 | if (roundedDegree > 90) {
22 | return currentWidth * sin;
23 | }
24 | return currentHeight * cos + currentWidth * sin;
25 | };
26 |
27 | return {
28 | width: Math.round(currentWidth * cos) + Math.round(currentHeight * sin),
29 | height: Math.round(currentWidth * sin) + Math.round(currentHeight * cos),
30 | offsetTop: roundedDegree >= 0 && roundedDegree <= 90 ? 0 : getTopOffset(),
31 | offsetLeft:
32 | roundedDegree <= 0 && roundedDegree >= -90 ? 0 : getLeftOffset(),
33 | };
34 | };
35 |
36 | export default getSizeAfterRotation;
37 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/getZoomFitFactor.js:
--------------------------------------------------------------------------------
1 | import { DEFAULT_ZOOM_FACTOR } from './constants';
2 |
3 | const getZoomFitFactor = (previewDimens, originalDimens) =>
4 | Math.min(
5 | previewDimens.width / originalDimens.width,
6 | previewDimens.height / originalDimens.height,
7 | ) || DEFAULT_ZOOM_FACTOR;
8 |
9 | export default getZoomFitFactor;
10 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/imageToBase64.js:
--------------------------------------------------------------------------------
1 | const imageToBase64 = (image) => {
2 | if (image instanceof HTMLImageElement) {
3 | const canvas = document.createElement('canvas');
4 | const ctx = canvas.getContext('2d');
5 | canvas.width = image.width;
6 | canvas.height = image.height;
7 | ctx.drawImage(image, 0, 0);
8 | return canvas.toDataURL();
9 | }
10 |
11 | return '';
12 | };
13 |
14 | export default imageToBase64;
15 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/isDefaultZeroValuesOnly.js:
--------------------------------------------------------------------------------
1 | const isDefaultZeroValuesOnly = (initialProps, newProps) => (
2 | initialProps &&
3 | Object.keys(initialProps || {}).every((key) => initialProps[key] === 0) &&
4 | newProps &&
5 | Object.keys(newProps || {}).length === 0
6 | )
7 |
8 | export default isDefaultZeroValuesOnly;
9 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/isSameImage.js:
--------------------------------------------------------------------------------
1 | const isSameImage = (img1, img2HtmlElement) =>
2 | img1 &&
3 | img2HtmlElement &&
4 | ((img1 instanceof HTMLImageElement &&
5 | img1.src === img2HtmlElement.src &&
6 | img1.width === img2HtmlElement.width &&
7 | img1.height === img2HtmlElement.height) ||
8 | (img1?.src || img1) === img2HtmlElement.src);
9 |
10 | export default isSameImage;
11 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/loadImage.js:
--------------------------------------------------------------------------------
1 | import extractNameFromUrl from './extractNameFromUrl';
2 |
3 | const loadImage = (imageSrc, imageFileName, noCrossOrigin = false) =>
4 | new Promise((resolve, reject) => {
5 | const imageElement = new Image();
6 | if (!noCrossOrigin) {
7 | imageElement.crossOrigin = 'Anonymous';
8 | }
9 | imageElement.src = imageSrc;
10 | imageElement.name = imageFileName ?? extractNameFromUrl(imageSrc);
11 | imageElement.onload = () => {
12 | resolve(imageElement);
13 | };
14 | imageElement.onerror = () => {
15 | reject(
16 | new Error(
17 | `Error in loading the image with the provided url: ${imageSrc}`,
18 | ),
19 | );
20 | };
21 | });
22 |
23 | export default loadImage;
24 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/mapCropBox.js:
--------------------------------------------------------------------------------
1 | import mapNumber from './mapNumber';
2 |
3 | const mapCropBox = (crop, shownImageDimensions, toDimensions) => ({
4 | ...(crop.x || crop.x === 0
5 | ? {
6 | x: Math.round(
7 | mapNumber(
8 | crop.x,
9 | 0,
10 | shownImageDimensions.width, // could replace with image node's dimensions from designLayer as they're same
11 | 0,
12 | toDimensions.width,
13 | ),
14 | ),
15 | }
16 | : {}),
17 | ...(crop.y || crop.y === 0
18 | ? {
19 | y: Math.round(
20 | mapNumber(
21 | crop.y,
22 | 0,
23 | shownImageDimensions.height,
24 | 0,
25 | toDimensions.height,
26 | ),
27 | ),
28 | }
29 | : {}),
30 | width: Math.round(
31 | mapNumber(
32 | crop.width ?? shownImageDimensions.width,
33 | 0,
34 | shownImageDimensions.width,
35 | 0,
36 | toDimensions.width,
37 | ),
38 | ),
39 | height: Math.round(
40 | mapNumber(
41 | crop.height ?? shownImageDimensions.height,
42 | 0,
43 | shownImageDimensions.height,
44 | 0,
45 | toDimensions.height,
46 | ),
47 | ),
48 | });
49 |
50 | export default mapCropBox;
51 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/mapNumber.js:
--------------------------------------------------------------------------------
1 | const mapNumber = (number, oldMin, oldMax, newMin, newMax) =>
2 | ((number - oldMin) * (newMax - newMin)) / (oldMax - oldMin) + newMin;
3 |
4 | export default mapNumber;
5 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/randomId.js:
--------------------------------------------------------------------------------
1 | const randomId = (prefixString = '') =>
2 | `${prefixString}${prefixString ? '-' : ''}${parseInt(
3 | Date.now() * Math.random(),
4 | 10,
5 | )}`;
6 |
7 | export default randomId;
8 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/restrictNumber.js:
--------------------------------------------------------------------------------
1 | const restrictNumber = (number, min = 0, max) => {
2 | // we are not assigning default value for it as if max was null it will override the default value.
3 | const currentMax = max || 1000000;
4 | const convertedNumber = +number;
5 |
6 | return Math.min(Math.max(min, convertedNumber), currentMax);
7 | };
8 |
9 | export default restrictNumber;
10 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/rgbaToHexa.js:
--------------------------------------------------------------------------------
1 | const rgbaToHexWithOpacity = (rgba = '') => {
2 | const defaultHexColor = { hex: '000000', opacity: 1 };
3 | if (!rgba) {
4 | return defaultHexColor;
5 | }
6 | if (rgba.startsWith('#')) {
7 | return { hex: rgba.replace('#', ''), opacity: 1 };
8 | }
9 |
10 | let [r, g, b, opacity] = rgba.split(',');
11 | if (!r || !g || !b) {
12 | return defaultHexColor;
13 | }
14 | r = parseFloat(r.replace(/rgba?\(/, '').trim()).toString(16);
15 | g = parseFloat(g.trim()).toString(16);
16 | b = parseFloat(b.trim()).toString(16);
17 | opacity = opacity ? parseFloat(opacity.trim() ?? 1) : undefined;
18 |
19 | if (r.length === 1) r = `0${r}`;
20 | if (g.length === 1) g = `0${g}`;
21 | if (b.length === 1) b = `0${b}`;
22 |
23 | return {
24 | hex: `${r}${g}${b}`,
25 | opacity,
26 | };
27 | };
28 |
29 | export default rgbaToHexWithOpacity;
30 |
--------------------------------------------------------------------------------
/packages/react-filerobot-image-editor/src/utils/toPrecisedFloat.js:
--------------------------------------------------------------------------------
1 | const toPrecisedFloat = (number, precision = 5) =>
2 | number && +parseFloat(number).toFixed(precision);
3 |
4 | export default toPrecisedFloat;
5 |
--------------------------------------------------------------------------------
/public/assets/Ellipse 3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scaleflex/filerobot-image-editor/3d198dd662b4f0ec004bb97d52c0a45048539334/public/assets/Ellipse 3.png
--------------------------------------------------------------------------------
/public/assets/Hollow-Ellipse 3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scaleflex/filerobot-image-editor/3d198dd662b4f0ec004bb97d52c0a45048539334/public/assets/Hollow-Ellipse 3.png
--------------------------------------------------------------------------------
/public/assets/adding-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scaleflex/filerobot-image-editor/3d198dd662b4f0ec004bb97d52c0a45048539334/public/assets/adding-icon.png
--------------------------------------------------------------------------------
/public/assets/arrow-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scaleflex/filerobot-image-editor/3d198dd662b4f0ec004bb97d52c0a45048539334/public/assets/arrow-icon.png
--------------------------------------------------------------------------------
/public/assets/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scaleflex/filerobot-image-editor/3d198dd662b4f0ec004bb97d52c0a45048539334/public/assets/arrow.png
--------------------------------------------------------------------------------
/public/assets/check-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scaleflex/filerobot-image-editor/3d198dd662b4f0ec004bb97d52c0a45048539334/public/assets/check-icon.png
--------------------------------------------------------------------------------
/public/assets/copy-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scaleflex/filerobot-image-editor/3d198dd662b4f0ec004bb97d52c0a45048539334/public/assets/copy-icon.png
--------------------------------------------------------------------------------
/public/assets/down-arrow-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scaleflex/filerobot-image-editor/3d198dd662b4f0ec004bb97d52c0a45048539334/public/assets/down-arrow-icon.png
--------------------------------------------------------------------------------
/public/assets/git-stars.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/github-logo.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/half-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scaleflex/filerobot-image-editor/3d198dd662b4f0ec004bb97d52c0a45048539334/public/assets/half-circle.png
--------------------------------------------------------------------------------