The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github
    ├── ISSUE_TEMPLATE
    │   ├── bug-report.md
    │   └── feature_request.md
    ├── PULL_REQUEST_TEMPLATE.md
    ├── stale.yml
    └── workflows
    │   └── release.yaml
├── .gitignore
├── .prettierrc
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── UPGRADE.md
├── babel.config.js
├── config
    ├── jestTestSetup.js
    ├── postcss.colors.js
    ├── postcss.config.js
    └── tsconfig.test.json
├── docs-images
    ├── background_plugin.png
    ├── basic.png
    ├── image-plugin.gif
    ├── image_upload.png
    ├── json-example-1.png
    ├── json-example-2.png
    ├── quick-example.gif
    ├── react-example-app.png
    ├── spacer-plugin.gif
    ├── text-editing-plugin.gif
    └── video-plugin.gif
├── docs
    ├── .nojekyll
    ├── CONTRIBUTING.md
    ├── README.md
    ├── _sidebar.md
    ├── builtin_plugins.md
    ├── bundle-size.md
    ├── custom-cell-plugins.md
    ├── docs-images
    ├── editor.md
    ├── examples
    │   ├── pages
    │   ├── plugins
    │   └── slate-plugin-src
    ├── ie11.md
    ├── index.html
    ├── integration-react-admin.md
    ├── quick-start.md
    ├── recipes.md
    ├── server-side-rendering.md
    ├── slate.md
    └── utils.md
├── examples
    ├── .gitignore
    ├── README.md
    ├── components
    │   ├── CodeSnippet.tsx
    │   ├── ContactFormExample.tsx
    │   ├── ExampleCustomBottomToolbar
    │   │   ├── CollapseButton.tsx
    │   │   └── index.tsx
    │   ├── Navigation.tsx
    │   └── PageLayout.tsx
    ├── next-env.d.ts
    ├── next.config.js
    ├── package.json
    ├── pages
    │   ├── _app.tsx
    │   ├── _document.tsx
    │   ├── debug_no_content.tsx
    │   ├── empty.tsx
    │   ├── examples
    │   │   ├── bare.tsx
    │   │   ├── cellSpacing.tsx
    │   │   ├── conditionalForm.tsx
    │   │   ├── constraints.tsx
    │   │   ├── contactform.tsx
    │   │   ├── customEditorChildren.tsx
    │   │   ├── customListInSlate.tsx
    │   │   ├── customMissingPlugin.tsx
    │   │   ├── customToolbar.tsx
    │   │   ├── customformlayout.tsx
    │   │   ├── customuniformsexperiments.tsx
    │   │   ├── dark-editor.tsx
    │   │   ├── dark-full.tsx
    │   │   ├── decorateplugins.tsx
    │   │   ├── extractTextContents.tsx
    │   │   ├── formFieldInText.tsx
    │   │   ├── i18n.tsx
    │   │   ├── languageSwitch.tsx
    │   │   ├── multicontrols.tsx
    │   │   ├── multipleEditors.tsx
    │   │   ├── nestedPlugins.tsx
    │   │   ├── reactadmin.tsx
    │   │   ├── readonly.tsx
    │   │   ├── sidebarPosition.tsx
    │   │   ├── simple.tsx
    │   │   ├── stretchCells.tsx
    │   │   └── switchValueTest.tsx
    │   ├── index.tsx
    │   ├── old
    │   │   ├── demo.tsx
    │   │   └── fromhtml.tsx
    │   ├── readonly-bare-empty.tsx
    │   ├── readonly-bare.tsx
    │   └── readonly.tsx
    ├── plugins
    │   ├── cellPlugins.ts
    │   ├── codeSnippet.tsx
    │   ├── contactForm.tsx
    │   ├── customContentPlugin.tsx
    │   ├── customContentPluginTwitter.tsx
    │   ├── customContentPluginWithListField.tsx
    │   ├── customLayoutPlugin.tsx
    │   ├── customLayoutPluginWithCellSpacing.tsx
    │   ├── customLayoutPluginWithInitialState.tsx
    │   ├── customSlatePlugin.tsx
    │   ├── katexSlatePlugin.tsx
    │   ├── react-katex.d.ts
    │   └── slate.tsx
    ├── public
    │   ├── docs
    │   └── images
    │   │   ├── app-preview.mp4
    │   │   ├── callisto-preview.mp4
    │   │   ├── clarke-preview.mp4
    │   │   ├── create-content.png
    │   │   ├── front.png
    │   │   ├── grass-header.jpg
    │   │   ├── khorana-preview.mp4
    │   │   ├── layouts.png
    │   │   ├── mountain.jpg
    │   │   ├── react.png
    │   │   ├── responsive.png
    │   │   ├── sane-markup.png
    │   │   ├── sea-bg.jpg
    │   │   └── sites-demo.mp4
    ├── sampleContents
    │   ├── cellSpacing.tsx
    │   ├── demo.tsx
    │   ├── demoSimpleReadOnly.tsx
    │   ├── raAboutUs.tsx
    │   └── v0.ts
    ├── styles
    │   ├── elements.css
    │   ├── styles.css
    │   └── typography.css
    ├── tsconfig.json
    └── utils
    │   └── createEmotionCache.ts
├── lerna.json
├── package.json
├── packages
    ├── editor
    │   ├── .DS_Store
    │   ├── .npmignore
    │   ├── README.md
    │   ├── babel.config.js
    │   ├── package.json
    │   ├── src
    │   │   ├── core
    │   │   │   ├── EditorStore.ts
    │   │   │   ├── Provider
    │   │   │   │   ├── CallbacksProvider.tsx
    │   │   │   │   ├── DndProvider.tsx
    │   │   │   │   ├── EditorStoreProvider.tsx
    │   │   │   │   ├── OptionsProvider.tsx
    │   │   │   │   ├── RenderOptionsProvider.tsx
    │   │   │   │   └── index.tsx
    │   │   │   ├── actions
    │   │   │   │   ├── cell
    │   │   │   │   │   ├── core.ts
    │   │   │   │   │   ├── drag.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── insert.ts
    │   │   │   │   ├── display.ts
    │   │   │   │   ├── helpers.ts
    │   │   │   │   ├── setting.ts
    │   │   │   │   ├── undo.ts
    │   │   │   │   └── value.ts
    │   │   │   ├── components
    │   │   │   │   ├── BlurGate.tsx
    │   │   │   │   ├── Cell
    │   │   │   │   │   ├── CellErrorGate.tsx
    │   │   │   │   │   ├── Draggable
    │   │   │   │   │   │   ├── index.css
    │   │   │   │   │   │   ├── index.tsx
    │   │   │   │   │   │   └── useDragHandle.tsx
    │   │   │   │   │   ├── Droppable
    │   │   │   │   │   │   ├── helper
    │   │   │   │   │   │   │   └── dnd.ts
    │   │   │   │   │   │   ├── index.css
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── ErrorCell
    │   │   │   │   │   │   ├── index.css
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── Handle
    │   │   │   │   │   │   ├── index.css
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── Inner
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── InsertNew.tsx
    │   │   │   │   │   ├── MoveActions
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── NoopProvider.tsx
    │   │   │   │   │   ├── PluginComponent
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── PluginControls
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── PluginMissing.tsx
    │   │   │   │   │   ├── Rows
    │   │   │   │   │   │   ├── __tests__
    │   │   │   │   │   │   │   └── index.test.tsx
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── index.css
    │   │   │   │   │   ├── index.tsx
    │   │   │   │   │   └── utils
    │   │   │   │   │   │   └── scrollIntoViewWithOffset.ts
    │   │   │   │   ├── Editable
    │   │   │   │   │   ├── FallbackDropArea.tsx
    │   │   │   │   │   ├── Inner
    │   │   │   │   │   │   ├── Rows.tsx
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── hooks
    │   │   │   │   │   │   └── useKeepScrollPosition.ts
    │   │   │   │   │   ├── index.css
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── HotKey
    │   │   │   │   │   └── GlobalHotKeys.tsx
    │   │   │   │   ├── Row
    │   │   │   │   │   ├── Droppable
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── ResizableRowCell.tsx
    │   │   │   │   │   ├── index.css
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── hooks
    │   │   │   │   │   ├── __tests__
    │   │   │   │   │   │   ├── nodeMove.test.tsx
    │   │   │   │   │   │   └── useDebouncedCellData.test.tsx
    │   │   │   │   │   ├── actions.ts
    │   │   │   │   │   ├── callbacks.ts
    │   │   │   │   │   ├── debug
    │   │   │   │   │   │   └── useWhyDidYouUpdate.ts
    │   │   │   │   │   ├── display.ts
    │   │   │   │   │   ├── displayMode.ts
    │   │   │   │   │   ├── dragDropActions.ts
    │   │   │   │   │   ├── focus.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── node.ts
    │   │   │   │   │   ├── nodeActions.ts
    │   │   │   │   │   ├── nodeMove.ts
    │   │   │   │   │   ├── options.ts
    │   │   │   │   │   ├── renderOptions.ts
    │   │   │   │   │   ├── screen.tsx
    │   │   │   │   │   ├── utils
    │   │   │   │   │   │   ├── findSiblingRow.test.ts
    │   │   │   │   │   │   └── findSiblingRow.ts
    │   │   │   │   │   └── value.ts
    │   │   │   │   └── index.css
    │   │   │   ├── const.ts
    │   │   │   ├── defaultOptions.ts
    │   │   │   ├── grid.css
    │   │   │   ├── helper
    │   │   │   │   ├── lazyLoad
    │   │   │   │   │   └── index.tsx
    │   │   │   │   └── throttle
    │   │   │   │   │   └── index.ts
    │   │   │   ├── index.css
    │   │   │   ├── migrations
    │   │   │   │   ├── EDITABLE_MIGRATIONS
    │   │   │   │   │   ├── from0to1.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── Migration.ts
    │   │   │   │   ├── __tests__
    │   │   │   │   │   ├── migrate.test.ts
    │   │   │   │   │   └── migrateValue.test.ts
    │   │   │   │   ├── migrate.ts
    │   │   │   │   └── serialzeValue.ts
    │   │   │   ├── reducer
    │   │   │   │   ├── display
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── focus
    │   │   │   │   │   ├── __tests__
    │   │   │   │   │   │   └── index.test.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── hover
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── settings
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── value
    │   │   │   │   │   ├── __tests__
    │   │   │   │   │   │   ├── initialReduced.test.ts
    │   │   │   │   │   │   ├── removeCell.test.ts
    │   │   │   │   │   │   ├── resizeCell.test.ts
    │   │   │   │   │   │   └── updateCellContent.test.ts
    │   │   │   │   │   ├── helper
    │   │   │   │   │   │   ├── __tests__
    │   │   │   │   │   │   │   ├── optimize.test.ts
    │   │   │   │   │   │   │   └── sizing.test.ts
    │   │   │   │   │   │   ├── empty.ts
    │   │   │   │   │   │   ├── optimize.ts
    │   │   │   │   │   │   ├── setAllSizesAndOptimize.ts
    │   │   │   │   │   │   └── sizing.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── testUtils.ts
    │   │   │   │   │   └── tree.ts
    │   │   │   │   └── values
    │   │   │   │   │   └── index.ts
    │   │   │   ├── reduxConnect.tsx
    │   │   │   ├── selector
    │   │   │   │   ├── display
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── editable
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── focus.ts
    │   │   │   │   └── setting.ts
    │   │   │   ├── service
    │   │   │   │   ├── hover
    │   │   │   │   │   ├── __tests__
    │   │   │   │   │   │   └── index.test.ts
    │   │   │   │   │   ├── computeHover.ts
    │   │   │   │   │   └── input.ts
    │   │   │   │   └── logger
    │   │   │   │   │   └── index.ts
    │   │   │   ├── store.ts
    │   │   │   ├── types
    │   │   │   │   ├── callbacks.ts
    │   │   │   │   ├── components.ts
    │   │   │   │   ├── constraints.ts
    │   │   │   │   ├── display.ts
    │   │   │   │   ├── hover.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── jsonSchema.ts
    │   │   │   │   ├── node.ts
    │   │   │   │   ├── options.ts
    │   │   │   │   ├── plugins.ts
    │   │   │   │   ├── renderOptions.ts
    │   │   │   │   └── state.ts
    │   │   │   └── utils
    │   │   │   │   ├── ancestorTree.ts
    │   │   │   │   ├── cloneWithNewIds.ts
    │   │   │   │   ├── createId.ts
    │   │   │   │   ├── createValue.ts
    │   │   │   │   ├── deepEquals.ts
    │   │   │   │   ├── getAvailablePlugins.ts
    │   │   │   │   ├── getCellData.ts
    │   │   │   │   ├── getCellSpacing.ts
    │   │   │   │   ├── getCellStylingProps.ts
    │   │   │   │   ├── getDropLevels.ts
    │   │   │   │   ├── getTextContents.test.ts
    │   │   │   │   ├── getTextContents.ts
    │   │   │   │   ├── mapNode.test.ts
    │   │   │   │   ├── mapNode.ts
    │   │   │   │   ├── objIsNode.ts
    │   │   │   │   ├── removeUndefinedProps.test.ts
    │   │   │   │   └── removeUndefinedProps.ts
    │   │   ├── editor
    │   │   │   ├── EditableEditor.tsx
    │   │   │   ├── Editor.tsx
    │   │   │   └── StickyWrapper.tsx
    │   │   ├── index.css
    │   │   ├── index.tsx
    │   │   ├── renderer
    │   │   │   ├── HTMLRenderer.tsx
    │   │   │   └── __tests__
    │   │   │   │   └── index.test.tsx
    │   │   ├── types.d.ts
    │   │   ├── ui
    │   │   │   ├── AutoformControls
    │   │   │   │   ├── AutoField.tsx
    │   │   │   │   ├── AutoFieldContext.tsx
    │   │   │   │   ├── AutoFields.tsx
    │   │   │   │   ├── AutoForm.tsx
    │   │   │   │   ├── index.tsx
    │   │   │   │   └── makeUniformsSchema.ts
    │   │   │   ├── BottomToolbar
    │   │   │   │   ├── Drawer.tsx
    │   │   │   │   ├── MoveActions.tsx
    │   │   │   │   ├── NodeTools.tsx
    │   │   │   │   ├── ScaleButton.tsx
    │   │   │   │   ├── Tools.tsx
    │   │   │   │   ├── index.tsx
    │   │   │   │   └── types.ts
    │   │   │   ├── ColorPicker
    │   │   │   │   ├── ColorPicker.tsx
    │   │   │   │   ├── ColorPickerField.tsx
    │   │   │   │   ├── colorToString.tsx
    │   │   │   │   ├── index.tsx
    │   │   │   │   └── types.ts
    │   │   │   ├── DraftSwitch
    │   │   │   │   └── index.tsx
    │   │   │   ├── DuplicateButton
    │   │   │   │   └── index.tsx
    │   │   │   ├── EditorUI
    │   │   │   │   └── index.tsx
    │   │   │   ├── I18nTools
    │   │   │   │   ├── I18nDialog.tsx
    │   │   │   │   ├── SelectLang.tsx
    │   │   │   │   └── index.tsx
    │   │   │   ├── ImageUpload
    │   │   │   │   ├── ImageUpload.tsx
    │   │   │   │   ├── defaultTranslations.tsx
    │   │   │   │   ├── index.tsx
    │   │   │   │   └── types.tsx
    │   │   │   ├── MultiNodesBottomToolbar
    │   │   │   │   ├── DeleteAll.tsx
    │   │   │   │   ├── DuplicateAll.tsx
    │   │   │   │   └── index.tsx
    │   │   │   ├── PluginDrawer
    │   │   │   │   ├── Draggable
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── Item
    │   │   │   │   │   ├── index.css
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── index.css
    │   │   │   │   └── index.tsx
    │   │   │   ├── SelectParentButton
    │   │   │   │   └── index.tsx
    │   │   │   ├── Sidebar
    │   │   │   │   ├── Button
    │   │   │   │   │   ├── index.css
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── ToggleEdit
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── ToggleInsert
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── ToggleLayout
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── TogglePreview
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── ToggleResize
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── UndoRedo
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── Zoom
    │   │   │   │   │   └── index.tsx
    │   │   │   │   ├── index.css
    │   │   │   │   └── index.tsx
    │   │   │   ├── Trash
    │   │   │   │   ├── index.css
    │   │   │   │   └── index.tsx
    │   │   │   ├── defaultTheme
    │   │   │   │   └── index.ts
    │   │   │   ├── index.css
    │   │   │   ├── index.tsx
    │   │   │   ├── moveButtons
    │   │   │   │   └── index.tsx
    │   │   │   └── uniform-mui
    │   │   │   │   ├── AutoField.tsx
    │   │   │   │   ├── AutoFields.tsx
    │   │   │   │   ├── BoolField.tsx
    │   │   │   │   ├── DateField.tsx
    │   │   │   │   ├── ErrorField.tsx
    │   │   │   │   ├── ErrorsField.tsx
    │   │   │   │   ├── HiddenField.tsx
    │   │   │   │   ├── ListAddField.tsx
    │   │   │   │   ├── ListDelField.tsx
    │   │   │   │   ├── ListField.tsx
    │   │   │   │   ├── ListItemField.tsx
    │   │   │   │   ├── ListSortField.tsx
    │   │   │   │   ├── LongTextField.tsx
    │   │   │   │   ├── NestField.tsx
    │   │   │   │   ├── NumField.tsx
    │   │   │   │   ├── README.md
    │   │   │   │   ├── RadioField.tsx
    │   │   │   │   ├── SelectField.tsx
    │   │   │   │   ├── SubmitField.tsx
    │   │   │   │   ├── TextField.tsx
    │   │   │   │   ├── index.ts
    │   │   │   │   └── wrapField.tsx
    │   │   ├── variables.css
    │   │   └── wdyr.ts
    │   ├── tsconfig-es.json
    │   └── tsconfig.json
    ├── index.d.ts
    ├── plugins
    │   ├── README.md
    │   ├── content
    │   │   ├── divider
    │   │   │   ├── .npmignore
    │   │   │   ├── babel.config.js
    │   │   │   ├── package.json
    │   │   │   ├── src
    │   │   │   │   ├── Renderer
    │   │   │   │   │   └── DividerHtmlRenderer.tsx
    │   │   │   │   ├── createPlugin.tsx
    │   │   │   │   ├── default
    │   │   │   │   │   └── settings.tsx
    │   │   │   │   ├── index.css
    │   │   │   │   ├── index.ts
    │   │   │   │   └── types
    │   │   │   │   │   ├── settings.ts
    │   │   │   │   │   └── translations.ts
    │   │   │   ├── tsconfig-es.json
    │   │   │   └── tsconfig.json
    │   │   ├── html5-video
    │   │   │   ├── .npmignore
    │   │   │   ├── babel.config.js
    │   │   │   ├── package.json
    │   │   │   ├── src
    │   │   │   │   ├── Renderer
    │   │   │   │   │   └── Html5VideoHtmlRenderer.tsx
    │   │   │   │   ├── createPlugin.tsx
    │   │   │   │   ├── default
    │   │   │   │   │   ├── settings.tsx
    │   │   │   │   │   └── state.ts
    │   │   │   │   ├── index.css
    │   │   │   │   ├── index.tsx
    │   │   │   │   └── types
    │   │   │   │   │   ├── settings.ts
    │   │   │   │   │   ├── state.ts
    │   │   │   │   │   └── translations.ts
    │   │   │   ├── tsconfig-es.json
    │   │   │   └── tsconfig.json
    │   │   ├── image
    │   │   │   ├── .npmignore
    │   │   │   ├── babel.config.js
    │   │   │   ├── package.json
    │   │   │   ├── src
    │   │   │   │   ├── Controls
    │   │   │   │   │   └── ImageControls.tsx
    │   │   │   │   ├── Renderer
    │   │   │   │   │   └── ImageHtmlRenderer.tsx
    │   │   │   │   ├── common
    │   │   │   │   │   └── styles.ts
    │   │   │   │   ├── createPlugin.tsx
    │   │   │   │   ├── default
    │   │   │   │   │   └── settings.tsx
    │   │   │   │   ├── index.css
    │   │   │   │   ├── index.tsx
    │   │   │   │   └── types
    │   │   │   │   │   ├── controls.ts
    │   │   │   │   │   ├── settings.ts
    │   │   │   │   │   ├── state.ts
    │   │   │   │   │   └── translations.ts
    │   │   │   ├── tsconfig-es.json
    │   │   │   └── tsconfig.json
    │   │   ├── slate
    │   │   │   ├── .npmignore
    │   │   │   ├── babel.config.js
    │   │   │   ├── package.json
    │   │   │   ├── src
    │   │   │   │   ├── __tests__
    │   │   │   │   │   ├── getTextContents.test.ts
    │   │   │   │   │   └── htmlToSlate.test.ts
    │   │   │   │   ├── components
    │   │   │   │   │   ├── ConditionalWrapper.tsx
    │   │   │   │   │   ├── Controls.tsx
    │   │   │   │   │   ├── DialogVisibleProvider.tsx
    │   │   │   │   │   ├── HoverButtons.tsx
    │   │   │   │   │   ├── PluginButton.tsx
    │   │   │   │   │   ├── PluginControls.tsx
    │   │   │   │   │   ├── ReadOnlySlate.tsx
    │   │   │   │   │   ├── SlateEditor.tsx
    │   │   │   │   │   ├── SlateProvider.tsx
    │   │   │   │   │   ├── ToolbarButton.tsx
    │   │   │   │   │   ├── VoidEditableElement.tsx
    │   │   │   │   │   ├── hotkeyHooks.ts
    │   │   │   │   │   ├── pluginHooks.ts
    │   │   │   │   │   └── renderHooks.tsx
    │   │   │   │   ├── default
    │   │   │   │   │   └── settings.ts
    │   │   │   │   ├── hooks
    │   │   │   │   │   ├── useAddPlugin.ts
    │   │   │   │   │   ├── useCurrentNodeDataWithPlugin.ts
    │   │   │   │   │   ├── useCurrentNodeWithPlugin.ts
    │   │   │   │   │   ├── useCurrentSelection.ts
    │   │   │   │   │   ├── usePluginIsActive.ts
    │   │   │   │   │   ├── usePluginIsDisabled.ts
    │   │   │   │   │   ├── useRemovePlugin.ts
    │   │   │   │   │   ├── useTextIsSelected.ts
    │   │   │   │   │   └── useWhyDidYouUpdate.ts
    │   │   │   │   ├── htmlToSlate
    │   │   │   │   │   ├── HtmlToSlate.tsx
    │   │   │   │   │   ├── index.tsx
    │   │   │   │   │   ├── parseHtml.browser.ts
    │   │   │   │   │   └── parseHtml.ts
    │   │   │   │   ├── index.css
    │   │   │   │   ├── index.tsx
    │   │   │   │   ├── migrations
    │   │   │   │   │   ├── deep-rename-keys.d.ts
    │   │   │   │   │   ├── v002.ts
    │   │   │   │   │   ├── v003.ts
    │   │   │   │   │   └── v004.ts
    │   │   │   │   ├── none.tsx
    │   │   │   │   ├── pluginFactories
    │   │   │   │   │   ├── components
    │   │   │   │   │   │   └── UniformsControls.tsx
    │   │   │   │   │   ├── createComponentPlugin.tsx
    │   │   │   │   │   ├── createDataPlugin.tsx
    │   │   │   │   │   ├── createHeadingsPlugin.tsx
    │   │   │   │   │   ├── createListIndentionPlugin.tsx
    │   │   │   │   │   ├── createListItemPlugin.tsx
    │   │   │   │   │   ├── createListPlugin.tsx
    │   │   │   │   │   ├── createMarkPlugin.tsx
    │   │   │   │   │   ├── createSimpleHtmlBlockPlugin.tsx
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── utils
    │   │   │   │   │   │   └── listUtils.ts
    │   │   │   │   ├── plugins
    │   │   │   │   │   ├── alignment.tsx
    │   │   │   │   │   ├── code
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── emphasize
    │   │   │   │   │   │   ├── em.tsx
    │   │   │   │   │   │   ├── index.tsx
    │   │   │   │   │   │   ├── strong.tsx
    │   │   │   │   │   │   └── underline.tsx
    │   │   │   │   │   ├── headings
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── links
    │   │   │   │   │   │   ├── anchor.tsx
    │   │   │   │   │   │   ├── index.tsx
    │   │   │   │   │   │   └── link.tsx
    │   │   │   │   │   ├── lists
    │   │   │   │   │   │   ├── constants.ts
    │   │   │   │   │   │   └── index.tsx
    │   │   │   │   │   ├── paragraphs
    │   │   │   │   │   │   ├── index.tsx
    │   │   │   │   │   │   └── node.css
    │   │   │   │   │   └── quotes.tsx
    │   │   │   │   ├── slateEnhancer
    │   │   │   │   │   ├── withInline.ts
    │   │   │   │   │   └── withPaste.ts
    │   │   │   │   ├── slateTypes.d.ts
    │   │   │   │   ├── types.ts
    │   │   │   │   ├── types
    │   │   │   │   │   ├── SlatePlugin.ts
    │   │   │   │   │   ├── component.ts
    │   │   │   │   │   ├── initialSlateState.ts
    │   │   │   │   │   ├── slatePluginDefinitions.ts
    │   │   │   │   │   ├── state.ts
    │   │   │   │   │   └── translations.ts
    │   │   │   │   └── utils
    │   │   │   │   │   ├── flattenDeep.ts
    │   │   │   │   │   ├── getCurrentData.ts
    │   │   │   │   │   ├── getTextContent.ts
    │   │   │   │   │   ├── makeSlatePluginsFromDef.ts
    │   │   │   │   │   ├── transformInitialSlateState.ts
    │   │   │   │   │   └── useSafeSetState.ts
    │   │   │   ├── tsconfig-es.json
    │   │   │   └── tsconfig.json
    │   │   ├── spacer
    │   │   │   ├── .npmignore
    │   │   │   ├── babel.config.js
    │   │   │   ├── package.json
    │   │   │   ├── src
    │   │   │   │   ├── Renderer
    │   │   │   │   │   ├── SpacerHtmlRenderer.tsx
    │   │   │   │   │   └── SpacerResizable.tsx
    │   │   │   │   ├── createPlugin.tsx
    │   │   │   │   ├── default
    │   │   │   │   │   └── settings.tsx
    │   │   │   │   ├── index.css
    │   │   │   │   ├── index.tsx
    │   │   │   │   └── types
    │   │   │   │   │   ├── settings.ts
    │   │   │   │   │   ├── state.ts
    │   │   │   │   │   └── translations.ts
    │   │   │   ├── tsconfig-es.json
    │   │   │   └── tsconfig.json
    │   │   └── video
    │   │   │   ├── .npmignore
    │   │   │   ├── babel.config.js
    │   │   │   ├── package.json
    │   │   │   ├── src
    │   │   │       ├── Renderer
    │   │   │       │   ├── VideoHtmlRenderer.tsx
    │   │   │       │   └── index.css
    │   │   │       ├── common
    │   │   │       │   └── styles.ts
    │   │   │       ├── createPlugin.tsx
    │   │   │       ├── default
    │   │   │       │   ├── settings.tsx
    │   │   │       │   └── state.ts
    │   │   │       ├── index.css
    │   │   │       ├── index.tsx
    │   │   │       └── types
    │   │   │       │   ├── api.ts
    │   │   │       │   ├── component.ts
    │   │   │       │   ├── controls.ts
    │   │   │       │   ├── renderer.ts
    │   │   │       │   ├── settings.ts
    │   │   │       │   ├── state.ts
    │   │   │       │   └── translations.ts
    │   │   │   ├── tsconfig-es.json
    │   │   │   └── tsconfig.json
    │   └── layout
    │   │   └── background
    │   │       ├── .npmignore
    │   │       ├── babel.config.js
    │   │       ├── package.json
    │   │       ├── src
    │   │           ├── Controls
    │   │           │   ├── Controls.tsx
    │   │           │   ├── Inner.tsx
    │   │           │   └── sub
    │   │           │   │   ├── Color.tsx
    │   │           │   │   ├── Image.tsx
    │   │           │   │   └── LinearGradient.tsx
    │   │           ├── Renderer
    │   │           │   └── BackgroundHtmlRenderer.tsx
    │   │           ├── const
    │   │           │   └── mode.ts
    │   │           ├── createPlugin.tsx
    │   │           ├── default
    │   │           │   └── settings.tsx
    │   │           ├── index.css
    │   │           ├── index.tsx
    │   │           └── types
    │   │           │   ├── ModeEnum.ts
    │   │           │   ├── api.ts
    │   │           │   ├── component.ts
    │   │           │   ├── controls.ts
    │   │           │   ├── gradient.ts
    │   │           │   ├── makeOptional.ts
    │   │           │   ├── omit.ts
    │   │           │   ├── renderer.ts
    │   │           │   ├── settings.ts
    │   │           │   ├── state.ts
    │   │           │   └── translations.ts
    │   │       ├── tsconfig-es.json
    │   │       └── tsconfig.json
    ├── react-admin
    │   ├── .npmignore
    │   ├── README.md
    │   ├── babel.config.js
    │   ├── package.json
    │   ├── src
    │   │   ├── RaReactPageInput.tsx
    │   │   ├── RaSelectReferenceInputField.tsx
    │   │   └── index.tsx
    │   ├── tsconfig-es.json
    │   └── tsconfig.json
    ├── tsconfig.json
    └── tsconfig.settings.json
└── yarn.lock


/.editorconfig:
--------------------------------------------------------------------------------
 1 | # EditorConfig is awesome: http://EditorConfig.org
 2 | root = true
 3 | 
 4 | [*]
 5 | indent_style = space
 6 | indent_size = 2
 7 | end_of_line = lf
 8 | charset = utf-8
 9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
11 | 
12 | [*.md]
13 | trim_trailing_whitespace = false
14 | 


--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | _book/**
2 | config/**
3 | coverage/**
4 | examples/build/**
5 | examples/src/contents.ts
6 | **/lib/**
7 | **/lib-es/**
8 | node_modules


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: Bug Report
 3 | about: Create a report to help us improve
 4 | title: ''
 5 | labels: bug
 6 | ---
 7 | 
 8 | **Describe the bug**
 9 | A clear and concise description of what the bug is.
10 | 
11 | **To Reproduce**
12 | Steps to reproduce the behavior:
13 | 1. Go to '...'
14 | 2. Click on '....'
15 | 3. Scroll down to '....'
16 | 4. See error
17 | 
18 | **Expected behavior**
19 | A clear and concise description of what you expected to happen.
20 | 
21 | **Screenshots**
22 | If applicable, add screenshots to help explain your problem.
23 | 
24 | **Desktop (please complete the following information):**
25 |  - OS: [e.g. iOS]
26 |  - Browser [e.g. chrome, safari]
27 |  - Version [e.g. 22]
28 | 
29 | **Smartphone (please complete the following information):**
30 |  - Device: [e.g. iPhone6]
31 |  - OS: [e.g. iOS8.1]
32 |  - Browser [e.g. stock browser, safari]
33 |  - Version [e.g. 22]
34 | 
35 | **Additional context**
36 | Add any other context about the problem here.
37 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: Feature request
 3 | about: Suggest an idea for this project
 4 | title: ''
 5 | labels: enhancement
 6 | ---
 7 | 
 8 | **Is your feature request related to a problem? Please describe.**
 9 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
10 | 
11 | **Describe the solution you'd like**
12 | A clear and concise description of what you want to happen.
13 | 
14 | **Describe alternatives you've considered**
15 | A clear and concise description of any alternative solutions or features you've considered.
16 | 
17 | **Additional context**
18 | Add any other context or screenshots about the feature request here.
19 | 


--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
 1 | # Number of days of inactivity before an issue becomes stale
 2 | daysUntilStale: 60
 3 | # Number of days of inactivity before a stale issue is closed
 4 | daysUntilClose: 14
 5 | # Issues with these labels will never be considered stale
 6 | exemptLabels:
 7 |   - pinned
 8 |   - security
 9 | # Label to use when marking an issue as stale
10 | staleLabel: wontfix
11 | # Comment to post when marking an issue as stale. Set to `false` to disable
12 | markComment: >
13 |   This issue has been automatically marked as stale because it has not had
14 |   recent activity 😏. It will be closed if no further activity occurs. Thank you
15 |   for your contributions! ❤️
16 | # Comment to post when closing a stale issue. Set to `false` to disable
17 | closeComment: false
18 | 


--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
 1 | name: Node.js CI
 2 | 
 3 | on:
 4 |   push:
 5 |     branches:
 6 |       - master
 7 |   pull_request:
 8 |     branches:
 9 |       - master
10 | 
11 | jobs:
12 |   build:
13 |     runs-on: ubuntu-latest
14 | 
15 |     steps:
16 |       - uses: actions/checkout@v3
17 |       - name: Use Node.js
18 |         uses: actions/setup-node@v3
19 |         with:
20 |           node-version: '14.x'
21 |           cache: 'yarn'
22 |       - run: yarn --frozen-lockfile
23 |       - run: yarn build:lib || yarn build:lib
24 |       #- run: yarn run lint
25 |       #- run: yarn run test
26 |       - name: semantic release
27 |         env:
28 |           GH_TOKEN_DOCS: ${{ secrets.GH_TOKEN_DOCS }}
29 |           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30 |           NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
31 |         run: 'echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc && yarn run semantic-release'
32 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | .idea
 2 | .vscode
 3 | logs
 4 | *.log
 5 | *.log.*
 6 | node_modules/
 7 | doc/
 8 | _book/
 9 | coverage/
10 | lib/
11 | lib-es/
12 | dist/
13 | examples/build
14 | *.tsbuildinfo
15 | .DS_store


--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 |   "semi": true,
3 |   "singleQuote": true,
4 |   "trailingComma": "es5",
5 |   "endOfLine": "auto"
6 | }
7 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | MIT License
 2 | 
 3 | Copyright (c) 2016-2019 Aeneas Rekkas
 4 | Copyright (c) 2020 react-page
 5 | 
 6 | 
 7 | Permission is hereby granted, free of charge, to any person obtaining a copy
 8 | of this software and associated documentation files (the "Software"), to deal
 9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 | 
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 | 
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 | 


--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 |   presets: ['@babel/preset-env', '@babel/preset-react'],
3 |   plugins: [
4 |     '@babel/plugin-transform-modules-commonjs',
5 |     '@babel/plugin-proposal-class-properties',
6 |   ],
7 | };
8 | 


--------------------------------------------------------------------------------
/config/jestTestSetup.js:
--------------------------------------------------------------------------------
 1 | const enzyme = require('enzyme');
 2 | const EnzymeAdapter = require('enzyme-adapter-react-16');
 3 | const enableHooks = require('jest-react-hooks-shallow').default;
 4 | 
 5 | import React from 'react';
 6 | React.useLayoutEffect = React.useEffect;
 7 | 
 8 | enzyme.configure({ adapter: new EnzymeAdapter() });
 9 | enableHooks(jest);
10 | 


--------------------------------------------------------------------------------
/config/postcss.config.js:
--------------------------------------------------------------------------------
 1 | module.exports = (ctx) => ({
 2 |   map: ctx.options.map,
 3 |   parser: ctx.options.parser,
 4 |   plugins: [
 5 |     require('postcss-nested'),
 6 |     require('postcss-import')({ root: ctx.file.dirname }),
 7 | 
 8 |     require('postcss-preset-env')({
 9 |       stage: 0,
10 |     }),
11 |   ],
12 | });
13 | 


--------------------------------------------------------------------------------
/config/tsconfig.test.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "compilerOptions": {
 3 |     "rootDirs": ["src"],
 4 |     "outDir": "lib",
 5 | 
 6 |     "moduleResolution": "node",
 7 |     "downlevelIteration": true,
 8 |     "target": "es5",
 9 |     "module": "commonjs",
10 |     "allowJs": true,
11 |     "jsx": "react",
12 |     "experimentalDecorators": true,
13 |     "esModuleInterop": true,
14 |     "sourceMap": true,
15 |     "skipLibCheck": true,
16 |     "skipDefaultLibCheck": true,
17 |     "noUnusedLocals": false,
18 |     "declaration": true,
19 |     "declarationMap": true,
20 |     "composite": true,
21 |     "lib": ["es7", "dom"],
22 |     "types": [
23 |       "node",
24 |       "jest",
25 |       "../packages/plugins/content/slate/src/slateTypes"
26 |     ],
27 |     "paths": {
28 |       "react": ["./node_modules/@types/react/index"],
29 |       "slate": ["./node_modules/@types/slate/index"]
30 |     }
31 |   }
32 | }
33 | 


--------------------------------------------------------------------------------
/docs-images/background_plugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/background_plugin.png


--------------------------------------------------------------------------------
/docs-images/basic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/basic.png


--------------------------------------------------------------------------------
/docs-images/image-plugin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/image-plugin.gif


--------------------------------------------------------------------------------
/docs-images/image_upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/image_upload.png


--------------------------------------------------------------------------------
/docs-images/json-example-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/json-example-1.png


--------------------------------------------------------------------------------
/docs-images/json-example-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/json-example-2.png


--------------------------------------------------------------------------------
/docs-images/quick-example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/quick-example.gif


--------------------------------------------------------------------------------
/docs-images/react-example-app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/react-example-app.png


--------------------------------------------------------------------------------
/docs-images/spacer-plugin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/spacer-plugin.gif


--------------------------------------------------------------------------------
/docs-images/text-editing-plugin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/text-editing-plugin.gif


--------------------------------------------------------------------------------
/docs-images/video-plugin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs-images/video-plugin.gif


--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/docs/.nojekyll


--------------------------------------------------------------------------------
/docs/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ../CONTRIBUTING.md


--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ../README.md


--------------------------------------------------------------------------------
/docs/_sidebar.md:
--------------------------------------------------------------------------------
 1 | <!-- docs/_sidebar.md -->
 2 | 
 3 | - [Readme](/)
 4 | - [Getting started](/quick-start.md)
 5 | - [Editor component](/editor.md)
 6 | - [Rich text editing](/slate.md)
 7 | - [Inbuilt Cell Plugins](/builtin_plugins.md)
 8 | - [Custom Cell plugins](/custom-cell-plugins.md)
 9 | - [Utils](/utils.md)
10 | - [Recipes](/recipes.md)
11 | - Integrations
12 |   - [React Admin](/integration-react-admin.md)
13 | - FAQ
14 |   - [SSR](/server-side-rendering.md)
15 |   - [Bundle size](/bundle-size.md)
16 |   - [IE11](/ie11.md)
17 | - [CONTRIBUTING](/CONTRIBUTING.md)
18 | 


--------------------------------------------------------------------------------
/docs/bundle-size.md:
--------------------------------------------------------------------------------
1 | We try to keep the initial bundle size low so that you can use this library also to render the content statically without edit functionality.
2 | 
3 | We achieve that by lazy-loading using `import()` functions. Most modern bundlers like webpack (e.g. in nextjs) support this kind of lazy loading. So the default editor-ui (based on material-ui) is only loaded if the editor is in editMode.
4 | 


--------------------------------------------------------------------------------
/docs/docs-images:
--------------------------------------------------------------------------------
1 | ../docs-images


--------------------------------------------------------------------------------
/docs/examples/pages:
--------------------------------------------------------------------------------
1 | ../../examples/pages


--------------------------------------------------------------------------------
/docs/examples/plugins:
--------------------------------------------------------------------------------
1 | ../../examples/plugins


--------------------------------------------------------------------------------
/docs/examples/slate-plugin-src:
--------------------------------------------------------------------------------
1 | ../../packages/plugins/content/slate/src


--------------------------------------------------------------------------------
/docs/server-side-rendering.md:
--------------------------------------------------------------------------------
1 | # Server side rendering
2 | 
3 | SSR should work out-of-the-box!
4 | 
5 | In fact the demo page is using nextjs and does server side rendering


--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
 2 | 
 3 | # dependencies
 4 | /node_modules
 5 | /.pnp
 6 | .pnp.js
 7 | 
 8 | # testing
 9 | /coverage
10 | 
11 | # next.js
12 | /.next/
13 | /out/
14 | 
15 | # production
16 | /build
17 | 
18 | # misc
19 | .DS_Store
20 | *.pem
21 | 
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | 
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 | 
33 | # vercel
34 | .vercel
35 | 


--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
 2 | 
 3 | ## Getting Started
 4 | 
 5 | First, run the development server:
 6 | 
 7 | ```bash
 8 | npm run dev
 9 | # or
10 | yarn dev
11 | ```
12 | 
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 | 
15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16 | 
17 | ## Learn More
18 | 
19 | To learn more about Next.js, take a look at the following resources:
20 | 
21 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
22 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
23 | 
24 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
25 | 
26 | ## Deploy on Vercel
27 | 
28 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
29 | 
30 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
31 | 


--------------------------------------------------------------------------------
/examples/components/CodeSnippet.tsx:
--------------------------------------------------------------------------------
 1 | // lazy load this file to keep initial bundle small
 2 | 
 3 | import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
 4 | import { vscDarkPlus as style } from 'react-syntax-highlighter/dist/cjs/styles/prism';
 5 | import React from 'react';
 6 | 
 7 | const CodeSnippet: React.FC<{
 8 |   code: string;
 9 |   language: string;
10 | }> = ({ code, language }) => (
11 |   <SyntaxHighlighter wrapLongLines language={language} style={style}>
12 |     {code}
13 |   </SyntaxHighlighter>
14 | );
15 | 
16 | export default CodeSnippet;
17 | 


--------------------------------------------------------------------------------
/examples/components/ExampleCustomBottomToolbar/CollapseButton.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import { IconButton, Tooltip } from '@mui/material';
 3 | import IconCollapse from '@mui/icons-material/KeyboardArrowDown';
 4 | import IconRestore from '@mui/icons-material/KeyboardArrowUp';
 5 | 
 6 | interface CollapseButtonProps {
 7 |   collapsed: boolean;
 8 |   setCollapsed: (c: boolean) => void;
 9 | }
10 | 
11 | const CollapseButton: React.FC<CollapseButtonProps> = ({
12 |   collapsed,
13 |   setCollapsed,
14 | }) => {
15 |   const toggleCollapsed = React.useCallback(() => {
16 |     setCollapsed(!collapsed);
17 |   }, [collapsed, setCollapsed]);
18 |   return (
19 |     <Tooltip title={collapsed ? 'Restore Panel' : 'Collapse Panel'}>
20 |       <IconButton onClick={toggleCollapsed} aria-label="delete" color="default">
21 |         {collapsed ? <IconRestore /> : <IconCollapse />}
22 |       </IconButton>
23 |     </Tooltip>
24 |   );
25 | };
26 | 
27 | export default React.memo(CollapseButton);
28 | 


--------------------------------------------------------------------------------
/examples/next-env.d.ts:
--------------------------------------------------------------------------------
1 | /// <reference types="next" />
2 | /// <reference types="next/image-types/global" />
3 | 
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 | 


--------------------------------------------------------------------------------
/examples/next.config.js:
--------------------------------------------------------------------------------
 1 | const withBundleAnalyzer = require('@next/bundle-analyzer')({
 2 |   enabled: process.env.ANALYZE === 'true',
 3 | });
 4 | const path = require('path');
 5 | module.exports = withBundleAnalyzer({
 6 |   basePath: process.env.RELEASE_CHANNEL
 7 |     ? !process.env.RELEASE_CHANNEL || process.env.RELEASE_CHANNEL === 'latest'
 8 |       ? '/'
 9 |       : '/' + process.env.RELEASE_CHANNEL
10 |     : undefined,
11 |   async rewrites() {
12 |     return [
13 |       {
14 |         source: '/docs',
15 |         destination: '/docs/index.html',
16 |       },
17 |     ];
18 |   },
19 |   productionBrowserSourceMaps: true,
20 |   compiler: {
21 |     // ssr and displayName are configured by default
22 |     styledComponents: true,
23 |   },
24 | });
25 | 


--------------------------------------------------------------------------------
/examples/pages/debug_no_content.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PageLayout from '../components/PageLayout';
3 | 
4 | export default function Empty() {
5 |   return <PageLayout>this is purposly empty</PageLayout>;
6 | }
7 | 


--------------------------------------------------------------------------------
/examples/pages/empty.tsx:
--------------------------------------------------------------------------------
 1 | import type { Value, Options } from '@react-page/editor';
 2 | import Editor from '@react-page/editor';
 3 | 
 4 | import React, { useState } from 'react';
 5 | import PageLayout from '../components/PageLayout';
 6 | import { cellPlugins } from '../plugins/cellPlugins';
 7 | 
 8 | const LANGUAGES = [
 9 |   {
10 |     lang: 'en',
11 |     label: 'English',
12 |   },
13 |   {
14 |     lang: 'de',
15 |     label: 'Deutsch',
16 |   },
17 | ];
18 | 
19 | export default function Empty() {
20 |   const [value, setValue] = useState<Value | null>(null);
21 | 
22 |   return (
23 |     <PageLayout>
24 |       <Editor
25 |         cellPlugins={cellPlugins}
26 |         value={value}
27 |         lang={LANGUAGES[0].lang}
28 |         onChange={setValue}
29 |         languages={LANGUAGES}
30 |       />
31 |     </PageLayout>
32 |   );
33 | }
34 | 


--------------------------------------------------------------------------------
/examples/pages/examples/bare.tsx:
--------------------------------------------------------------------------------
 1 | import React, { useState } from 'react';
 2 | import type { Value } from '@react-page/editor';
 3 | import Editor from '@react-page/editor';
 4 | import slate from '@react-page/plugins-slate';
 5 | import image from '@react-page/plugins-image';
 6 | 
 7 | const cellPlugins = [slate(), image];
 8 | 
 9 | // Bare without page layout for bundle size debugging
10 | const Bare = () => {
11 |   const [value] = useState<Value | null>(null);
12 | 
13 |   return (
14 |     <>
15 |       <Editor cellPlugins={cellPlugins} value={value} />
16 |     </>
17 |   );
18 | };
19 | export default Bare;
20 | 


--------------------------------------------------------------------------------
/examples/pages/examples/customListInSlate.tsx:
--------------------------------------------------------------------------------
 1 | // The editor core
 2 | import type { Value } from '@react-page/editor';
 3 | import Editor from '@react-page/editor';
 4 | import slate, { pluginFactories } from '@react-page/plugins-slate';
 5 | import React, { useState } from 'react';
 6 | import PageLayout from '../../components/PageLayout';
 7 | 
 8 | const cellPlugins = [
 9 |   slate((def) => ({
10 |     ...def,
11 |     plugins: {
12 |       ...def.plugins,
13 |       lists: {
14 |         alpha: pluginFactories.createListPlugin({
15 |           type: 'alpha',
16 |           icon: <>a)</>,
17 |           label: 'alphabetic List',
18 |           tagName: 'ol',
19 |           getStyle: () => ({ listStyleType: 'lower-alpha' }),
20 |         }),
21 |         ...def.plugins.lists,
22 |       },
23 |     },
24 |   })),
25 | ];
26 | export default function CustomFormLayout() {
27 |   const [value, setValue] = useState<Value>();
28 | 
29 |   return (
30 |     <PageLayout>
31 |       <Editor cellPlugins={cellPlugins} value={value} onChange={setValue} />
32 |     </PageLayout>
33 |   );
34 | }
35 | 


--------------------------------------------------------------------------------
/examples/pages/examples/dark-editor.tsx:
--------------------------------------------------------------------------------
 1 | import type { Value } from '@react-page/editor';
 2 | import Editor, { defaultThemeOptions } from '@react-page/editor';
 3 | import { demo } from '../../sampleContents/demo';
 4 | import React, { useState } from 'react';
 5 | import { cellPlugins } from '../../plugins/cellPlugins';
 6 | import PageLayout from '../../components/PageLayout';
 7 | import { Button, createTheme } from '@mui/material';
 8 | const LANGUAGES = [
 9 |   {
10 |     lang: 'en',
11 |     label: 'English',
12 |   },
13 |   {
14 |     lang: 'de',
15 |     label: 'Deutsch',
16 |   },
17 | ];
18 | 
19 | const darkTheme = createTheme({
20 |   ...defaultThemeOptions,
21 |   palette: { mode: 'dark' },
22 | });
23 | export default function Dark() {
24 |   const [value, setValue] = useState<Value>(demo);
25 |   const reset = () => setValue(demo);
26 | 
27 |   return (
28 |     <PageLayout>
29 |       <Editor
30 |         cellPlugins={cellPlugins}
31 |         value={value}
32 |         lang={LANGUAGES[0].lang}
33 |         onChange={setValue}
34 |         languages={LANGUAGES}
35 |         uiTheme={darkTheme}
36 |       />
37 |       <Button onClick={reset}>Reset</Button>
38 |     </PageLayout>
39 |   );
40 | }
41 | 


--------------------------------------------------------------------------------
/examples/pages/examples/dark-full.tsx:
--------------------------------------------------------------------------------
 1 | import type { Value } from '@react-page/editor';
 2 | import { defaultThemeOptions } from '@react-page/editor';
 3 | import Editor from '@react-page/editor';
 4 | import { demo } from '../../sampleContents/demo';
 5 | import React, { useState } from 'react';
 6 | import { cellPlugins } from '../../plugins/cellPlugins';
 7 | import PageLayout from '../../components/PageLayout';
 8 | import { Button, createTheme, ThemeProvider } from '@mui/material';
 9 | const LANGUAGES = [
10 |   {
11 |     lang: 'en',
12 |     label: 'English',
13 |   },
14 |   {
15 |     lang: 'de',
16 |     label: 'Deutsch',
17 |   },
18 | ];
19 | 
20 | const darkTheme = createTheme({
21 |   ...defaultThemeOptions,
22 |   palette: { mode: 'dark' },
23 | });
24 | export default function Dark() {
25 |   const [value, setValue] = useState<Value>(demo);
26 |   const reset = () => setValue(demo);
27 | 
28 |   return (
29 |     <ThemeProvider theme={darkTheme}>
30 |       <PageLayout>
31 |         <Editor
32 |           cellPlugins={cellPlugins}
33 |           value={value}
34 |           lang={LANGUAGES[0].lang}
35 |           onChange={setValue}
36 |           languages={LANGUAGES}
37 |           uiTheme={darkTheme}
38 |         />
39 |         <Button onClick={reset}>Reset</Button>
40 |       </PageLayout>
41 |     </ThemeProvider>
42 |   );
43 | }
44 | 


--------------------------------------------------------------------------------
/examples/pages/examples/extractTextContents.tsx:
--------------------------------------------------------------------------------
 1 | import Editor, { getTextContents } from '@react-page/editor';
 2 | import React, { useEffect, useState } from 'react';
 3 | import PageLayout from '../../components/PageLayout';
 4 | import { cellPlugins } from '../../plugins/cellPlugins';
 5 | import { demo } from '../../sampleContents/demo';
 6 | 
 7 | export default function ReadOnly() {
 8 |   const [value, setValue] = useState(demo);
 9 |   useEffect(() => {
10 |     console.log(
11 |       'raw text contents',
12 |       getTextContents(value, { cellPlugins, lang: 'en' })
13 |     );
14 |   });
15 |   return (
16 |     <PageLayout>
17 |       <Editor
18 |         cellPlugins={cellPlugins}
19 |         value={value}
20 |         lang="en"
21 |         onChange={setValue}
22 |       />
23 |     </PageLayout>
24 |   );
25 | }
26 | 


--------------------------------------------------------------------------------
/examples/pages/examples/readonly.tsx:
--------------------------------------------------------------------------------
 1 | // The editor core
 2 | import Editor from '@react-page/editor';
 3 | // image
 4 | import image from '@react-page/plugins-image';
 5 | // The rich text area plugin
 6 | import slate from '@react-page/plugins-slate';
 7 | import React from 'react';
 8 | import PageLayout from '../../components/PageLayout';
 9 | import { demoSimpleReadOnly } from '../../sampleContents/demoSimpleReadOnly';
10 | 
11 | // Stylesheets for the rich text area plugin
12 | // uncomment this
13 | //import '@react-page/plugins-slate/lib/index.css';
14 | 
15 | // Stylesheets for the imagea plugin
16 | //import '@react-page/plugins-image/lib/index.css';
17 | 
18 | // Define which plugins we want to use.
19 | const cellPlugins = [slate(), image];
20 | 
21 | export default function ReadOnlyExample() {
22 |   // you would usually load SAMPLE_CONTENT from some api / endpoint / database
23 |   return (
24 |     <PageLayout>
25 |       <Editor value={demoSimpleReadOnly} cellPlugins={cellPlugins} readOnly />
26 |     </PageLayout>
27 |   );
28 | }
29 | 


--------------------------------------------------------------------------------
/examples/pages/examples/simple.tsx:
--------------------------------------------------------------------------------
 1 | import React, { useState } from 'react';
 2 | 
 3 | // The editor core
 4 | import type { Value } from '@react-page/editor';
 5 | import Editor from '@react-page/editor';
 6 | 
 7 | // import the main css, uncomment this: (this is commented in the example because of https://github.com/vercel/next.js/issues/19717)
 8 | // import '@react-page/editor/lib/index.css';
 9 | 
10 | // The rich text area plugin
11 | import slate from '@react-page/plugins-slate';
12 | // image
13 | import image from '@react-page/plugins-image';
14 | import PageLayout from '../../components/PageLayout';
15 | 
16 | // Stylesheets for the rich text area plugin
17 | // uncomment this
18 | //import '@react-page/plugins-slate/lib/index.css';
19 | 
20 | // Stylesheets for the imagea plugin
21 | //import '@react-page/plugins-image/lib/index.css';
22 | 
23 | // Define which plugins we want to use.
24 | const cellPlugins = [slate(), image];
25 | 
26 | export default function SimpleExample() {
27 |   const [value, setValue] = useState<Value | null>(null);
28 | 
29 |   return (
30 |     <PageLayout>
31 |       <Editor cellPlugins={cellPlugins} value={value} onChange={setValue} />
32 |     </PageLayout>
33 |   );
34 | }
35 | 


--------------------------------------------------------------------------------
/examples/pages/index.tsx:
--------------------------------------------------------------------------------
 1 | import { Button } from '@mui/material';
 2 | import type { Value } from '@react-page/editor';
 3 | import Editor from '@react-page/editor';
 4 | import React, { useState } from 'react';
 5 | import PageLayout from '../components/PageLayout';
 6 | import { cellPlugins } from '../plugins/cellPlugins';
 7 | import { demo } from '../sampleContents/demo';
 8 | const LANGUAGES = [
 9 |   {
10 |     lang: 'en',
11 |     label: 'English',
12 |   },
13 |   {
14 |     lang: 'de',
15 |     label: 'Deutsch',
16 |   },
17 | ];
18 | 
19 | export default function Home() {
20 |   const [value, setValue] = useState<Value>(demo);
21 |   const reset = () => setValue(demo);
22 | 
23 |   return (
24 |     <PageLayout>
25 |       <Editor
26 |         cellPlugins={cellPlugins}
27 |         value={value}
28 |         lang={LANGUAGES[0].lang}
29 |         onChange={setValue}
30 |         languages={LANGUAGES}
31 |       />
32 |       <Button onClick={reset}>Reset</Button>
33 |     </PageLayout>
34 |   );
35 | }
36 | 


--------------------------------------------------------------------------------
/examples/pages/old/demo.tsx:
--------------------------------------------------------------------------------
 1 | import type { Options, Value, Value_v0 } from '@react-page/editor';
 2 | import Editor from '@react-page/editor';
 3 | 
 4 | import React, { useState } from 'react';
 5 | import PageLayout from '../../components/PageLayout';
 6 | import { cellPlugins } from '../../plugins/cellPlugins';
 7 | import contents from '../../sampleContents/v0';
 8 | const LANGUAGES = [
 9 |   {
10 |     lang: 'en',
11 |     label: 'English',
12 |   },
13 |   {
14 |     lang: 'de',
15 |     label: 'Deutsch',
16 |   },
17 | ];
18 | 
19 | export default function Home() {
20 |   const [value, setValue] = useState<Value_v0 | Value>(contents[0]);
21 | 
22 |   return (
23 |     <PageLayout>
24 |       <Editor
25 |         cellPlugins={cellPlugins}
26 |         value={value}
27 |         onChange={setValue}
28 |         languages={LANGUAGES}
29 |       />
30 |     </PageLayout>
31 |   );
32 | }
33 | 


--------------------------------------------------------------------------------
/examples/pages/readonly-bare-empty.tsx:
--------------------------------------------------------------------------------
1 | import Editor from '@react-page/editor';
2 | import React from 'react';
3 | 
4 | export default function ReadOnlyBareEmpty() {
5 |   return <Editor cellPlugins={[]} value={null} lang="en" readOnly />;
6 | }
7 | 


--------------------------------------------------------------------------------
/examples/pages/readonly-bare.tsx:
--------------------------------------------------------------------------------
1 | import Editor from '@react-page/editor';
2 | import React from 'react';
3 | import { cellPlugins } from '../plugins/cellPlugins';
4 | import { demo } from '../sampleContents/demo';
5 | 
6 | export default function ReadOnlyBare() {
7 |   return <Editor cellPlugins={cellPlugins} value={demo} lang="en" readOnly />;
8 | }
9 | 


--------------------------------------------------------------------------------
/examples/pages/readonly.tsx:
--------------------------------------------------------------------------------
 1 | import Editor from '@react-page/editor';
 2 | import React from 'react';
 3 | import PageLayout from '../components/PageLayout';
 4 | import { cellPlugins } from '../plugins/cellPlugins';
 5 | import { demo } from '../sampleContents/demo';
 6 | 
 7 | export default function ReadOnly() {
 8 |   return (
 9 |     <PageLayout>
10 |       <Editor cellPlugins={cellPlugins} value={demo} lang="en" readOnly />
11 |     </PageLayout>
12 |   );
13 | }
14 | 


--------------------------------------------------------------------------------
/examples/plugins/codeSnippet.tsx:
--------------------------------------------------------------------------------
 1 | import type { CellPlugin } from '@react-page/editor';
 2 | import dynamic from 'next/dynamic';
 3 | import React from 'react';
 4 | 
 5 | // lazy load to keep initial bundle small
 6 | const CodeSnippet = dynamic(() => import('../components/CodeSnippet'));
 7 | 
 8 | const codeSnippet: CellPlugin<{
 9 |   code: string;
10 |   language: string;
11 | }> = {
12 |   Renderer: ({ data }) =>
13 |     data?.code ? (
14 |       <CodeSnippet language={data.language} code={data.code} />
15 |     ) : null,
16 |   id: 'code-snippet',
17 |   title: 'Code snippet',
18 |   description: 'A code snippet',
19 |   version: 1,
20 |   controls: {
21 |     type: 'autoform',
22 |     schema: {
23 |       properties: {
24 |         language: {
25 |           type: 'string',
26 |         },
27 |         code: {
28 |           type: 'string',
29 |           uniforms: {
30 |             multiline: true,
31 |           },
32 |         },
33 |       },
34 |       required: ['code'],
35 |     },
36 |   },
37 | };
38 | export default codeSnippet;
39 | 


--------------------------------------------------------------------------------
/examples/plugins/customLayoutPlugin.tsx:
--------------------------------------------------------------------------------
 1 | import type { CellPlugin } from '@react-page/editor';
 2 | import React from 'react';
 3 | import { defaultSlate, customizedSlate } from './slate';
 4 | 
 5 | const customLayoutPlugin: CellPlugin<{
 6 |   backgroundColor: string;
 7 | }> = {
 8 |   Renderer: ({ children, data }) => (
 9 |     <div
10 |       style={{
11 |         border: '1px solid black',
12 |         backgroundColor: data.backgroundColor,
13 |       }}
14 |     >
15 |       {children}
16 |     </div>
17 |   ),
18 |   createInitialChildren: () => {
19 |     return [
20 |       [
21 |         {
22 |           plugin: defaultSlate,
23 |         },
24 |         {
25 |           plugin: defaultSlate,
26 |         },
27 |       ],
28 |       [
29 |         {
30 |           plugin: customizedSlate,
31 |         },
32 |         {
33 |           plugin: customizedSlate,
34 |         },
35 |       ],
36 |     ];
37 |   },
38 | 
39 |   id: 'custom-layout-plugin',
40 |   title: 'Custom layout plugin',
41 |   description: 'Some custom layout plugin',
42 |   version: 1,
43 |   controls: {
44 |     type: 'autoform',
45 |     schema: {
46 |       required: ['backgroundColor'],
47 |       properties: {
48 |         backgroundColor: { type: 'string' },
49 |       },
50 |     },
51 |   },
52 | };
53 | 
54 | export default customLayoutPlugin;
55 | 


--------------------------------------------------------------------------------
/examples/plugins/customSlatePlugin.tsx:
--------------------------------------------------------------------------------
 1 | import { ColorPickerField } from '@react-page/editor';
 2 | import { pluginFactories } from '@react-page/plugins-slate';
 3 | import React from 'react';
 4 | 
 5 | export default pluginFactories.createComponentPlugin<{
 6 |   color: string;
 7 | }>({
 8 |   addHoverButton: true, // whether to show it above the text when selected
 9 |   addToolbarButton: true, // whether to show it in the bottom toolbar
10 |   type: 'SetColor', // a well defined string, this is kind of the id of the plugin
11 |   object: 'mark', // mark is like a span, other options are inline and block
12 |   icon: <span>Color</span>, // an icon to show
13 |   label: 'Set Color',
14 |   Component: 'span', // the component to render
15 |   getStyle: ({ color }) => ({ color }),
16 |   controls: {
17 |     // identical to custom cell plugins
18 |     type: 'autoform',
19 |     schema: {
20 |       type: 'object',
21 |       required: ['color'],
22 |       properties: {
23 |         color: {
24 |           uniforms: {
25 |             component: ColorPickerField,
26 |           },
27 |           default: 'rgba(0,0,255,1)',
28 |           type: 'string',
29 |         },
30 |       },
31 |     },
32 |   },
33 | });
34 | 


--------------------------------------------------------------------------------
/examples/plugins/react-katex.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'react-katex' {
2 |   export const InlineMath: React.FC<{ math: string }>;
3 | }
4 | 


--------------------------------------------------------------------------------
/examples/public/docs:
--------------------------------------------------------------------------------
1 | ../../docs/


--------------------------------------------------------------------------------
/examples/public/images/app-preview.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/app-preview.mp4


--------------------------------------------------------------------------------
/examples/public/images/callisto-preview.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/callisto-preview.mp4


--------------------------------------------------------------------------------
/examples/public/images/clarke-preview.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/clarke-preview.mp4


--------------------------------------------------------------------------------
/examples/public/images/create-content.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/create-content.png


--------------------------------------------------------------------------------
/examples/public/images/front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/front.png


--------------------------------------------------------------------------------
/examples/public/images/grass-header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/grass-header.jpg


--------------------------------------------------------------------------------
/examples/public/images/khorana-preview.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/khorana-preview.mp4


--------------------------------------------------------------------------------
/examples/public/images/layouts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/layouts.png


--------------------------------------------------------------------------------
/examples/public/images/mountain.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/mountain.jpg


--------------------------------------------------------------------------------
/examples/public/images/react.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/react.png


--------------------------------------------------------------------------------
/examples/public/images/responsive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/responsive.png


--------------------------------------------------------------------------------
/examples/public/images/sane-markup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/sane-markup.png


--------------------------------------------------------------------------------
/examples/public/images/sea-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/sea-bg.jpg


--------------------------------------------------------------------------------
/examples/public/images/sites-demo.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/examples/public/images/sites-demo.mp4


--------------------------------------------------------------------------------
/examples/sampleContents/demoSimpleReadOnly.tsx:
--------------------------------------------------------------------------------
 1 | import type { Value } from '@react-page/editor';
 2 | export const demoSimpleReadOnly: Value = {
 3 |   id: '2390df',
 4 |   version: 1,
 5 |   rows: [
 6 |     {
 7 |       id: '4c7d90',
 8 |       cells: [
 9 |         {
10 |           id: '95d678',
11 |           size: 12,
12 |           plugin: { id: 'ory/editor/core/content/slate', version: 1 },
13 |           dataI18n: {
14 |             undefined: {
15 |               slate: [
16 |                 {
17 |                   children: [{ text: 'Next Level Content Editing' }],
18 |                   type: 'HEADINGS/HEADING-TWO',
19 |                   data: { align: 'center' },
20 |                 },
21 |                 {
22 |                   children: [{ text: 'ReactPage' }],
23 |                   type: 'HEADINGS/HEADING-ONE',
24 |                   data: { align: 'center' },
25 |                 },
26 |               ],
27 |             },
28 |           },
29 |           rows: [],
30 |           inline: null,
31 |         },
32 |       ],
33 |     },
34 |   ],
35 | };
36 | 


--------------------------------------------------------------------------------
/examples/styles/elements.css:
--------------------------------------------------------------------------------
 1 | .react-page-plugins-content-divider {
 2 |   background-color: #aaa;
 3 |   width: 100%;
 4 |   height: 2px;
 5 |   border: none;
 6 | }
 7 | 
 8 | .editable-area code,
 9 | .editable-area pre {
10 |   font-family: monospace;
11 |   border-radius: 0.3em;
12 |   padding: 0.4em;
13 | }
14 | 
15 | .editable-area code {
16 |   display: inline;
17 |   margin: 0 0.5em;
18 |   white-space: pre;
19 | }
20 | 
21 | .editable-area pre {
22 |   display: block;
23 |   margin: 1em;
24 | }
25 | 
26 | .editable-area ul,
27 | .editable-area ol {
28 |   margin: 1em 0;
29 |   list-style-type: inside;
30 | }
31 | 
32 | .editable-area li {
33 |   margin: 0.2em 0 0.2em 1em;
34 | }
35 | 
36 | .editable-area li p {
37 |   margin: 0;
38 | }
39 | 
40 | .editable-area ol {
41 |   list-style-type: decimal;
42 | }
43 | 
44 | .editable-area ul {
45 |   list-style-type: disc;
46 | }
47 | 


--------------------------------------------------------------------------------
/examples/styles/styles.css:
--------------------------------------------------------------------------------
 1 | 
 2 | @import './typography.css';
 3 | @import './elements.css';
 4 | 
 5 | body {
 6 |   margin: 0px;
 7 | 
 8 |   color: #333333;
 9 |   font-size: 18px;
10 |   line-height: 28px;
11 | 
12 |   font-family: 'Open Sans', serif;
13 | }
14 | 
15 | p {
16 |   margin: 0 0 28px;
17 | }
18 | 
19 | pre {
20 |   overflow-x: auto;
21 | }
22 | 
23 | a {
24 |   color: #c73036;
25 |   font-family: Georgia, serif;
26 |   text-decoration: underline;
27 | }
28 | 
29 | a:hover {
30 |   color: #333333;
31 |   text-decoration: underline;
32 | }
33 | 
34 | 
35 | .react-page-cell-inner-leaf {
36 |   padding: 20px;
37 | }
38 | 
39 | 
40 | 


--------------------------------------------------------------------------------
/examples/utils/createEmotionCache.ts:
--------------------------------------------------------------------------------
1 | import createCache from '@emotion/cache';
2 | 
3 | // prepend: true moves MUI styles to the top of the <head> so they're loaded first.
4 | // It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
5 | export default function createEmotionCache() {
6 |   return createCache({ key: 'css', prepend: true });
7 | }
8 | 


--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "lerna": "3.6.0",
 3 |   "npmClient": "yarn",
 4 |   "packages": [
 5 |     "packages/editor",
 6 |     "packages/plugins/content/*",
 7 |     "packages/plugins/layout/*",
 8 |     "packages/react-admin",
 9 |     "examples"
10 |   ],
11 |   "useWorkspaces": true,
12 |   "version": "0.0.0",
13 |   "verifyAccess": false
14 | }
15 | 


--------------------------------------------------------------------------------
/packages/editor/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/packages/editor/.DS_Store


--------------------------------------------------------------------------------
/packages/editor/.npmignore:
--------------------------------------------------------------------------------
1 | src/**/*


--------------------------------------------------------------------------------
/packages/editor/README.md:
--------------------------------------------------------------------------------
 1 | # React-Page Editor
 2 | 
 3 | This is ReactPage's main Component.
 4 | 
 5 | Read the full readme here https://github.com/react-page/react-page
 6 | 
 7 | Docs: https://react-page.github.io/docs
 8 | 
 9 | Demo: https://react-page.github.io/
10 | 


--------------------------------------------------------------------------------
/packages/editor/babel.config.js:
--------------------------------------------------------------------------------
1 | const vendor = require('../../babel.config.js');
2 | module.exports = Object.assign({}, vendor);
3 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/Provider/CallbacksProvider.tsx:
--------------------------------------------------------------------------------
 1 | import type { FC, PropsWithChildren } from 'react';
 2 | import React, { useRef } from 'react';
 3 | import deepEquals from '../utils/deepEquals';
 4 | import { CallbacksContext } from '../components/hooks';
 5 | 
 6 | import type { Callbacks } from '../types';
 7 | 
 8 | const CallbacksProvider: FC<PropsWithChildren<Callbacks>> = ({
 9 |   children,
10 |   ...callbacks
11 | }) => {
12 |   const lastCallbacks = useRef<Callbacks>();
13 | 
14 |   const isEqual = lastCallbacks.current
15 |     ? deepEquals(lastCallbacks.current, callbacks)
16 |     : false;
17 |   if (!isEqual) {
18 |     lastCallbacks.current = callbacks;
19 |   }
20 | 
21 |   return lastCallbacks.current ? (
22 |     <CallbacksContext.Provider value={lastCallbacks.current}>
23 |       {children}
24 |     </CallbacksContext.Provider>
25 |   ) : null;
26 | };
27 | 
28 | export default CallbacksProvider;
29 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/Provider/DndProvider.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import { DndProvider as DndProviderOrg } from 'react-dnd';
 3 | import { useOption } from '../components/hooks';
 4 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
 5 | const DndProvider = ({ children }: any) => {
 6 |   const dndBackend = useOption('dndBackend');
 7 |   return dndBackend ? (
 8 |     <DndProviderOrg backend={dndBackend}>{children}</DndProviderOrg>
 9 |   ) : (
10 |     <>{children}</>
11 |   );
12 | };
13 | 
14 | export default DndProvider;
15 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/Provider/OptionsProvider.tsx:
--------------------------------------------------------------------------------
 1 | import type { FC, PropsWithChildren } from 'react';
 2 | import React, { useRef } from 'react';
 3 | import deepEquals from '../utils/deepEquals';
 4 | import { OptionsContext } from '../components/hooks';
 5 | import { DEFAULT_OPTIONS } from '../defaultOptions';
 6 | import type { Options } from '../types';
 7 | /*
 8 | we memoize the options, so that if you access them, you won't get a fresh object every time.
 9 | */
10 | 
11 | const OptionsProvider: FC<PropsWithChildren<Options>> = ({
12 |   children,
13 |   ...options
14 | }) => {
15 |   const lastOptions = useRef<Required<Options>>();
16 |   const fullOptions = {
17 |     ...DEFAULT_OPTIONS,
18 |     ...options,
19 |   };
20 | 
21 |   const isEqual = lastOptions.current
22 |     ? deepEquals(lastOptions.current, fullOptions)
23 |     : false;
24 |   if (!isEqual) {
25 |     lastOptions.current = fullOptions;
26 |   }
27 | 
28 |   return lastOptions.current ? (
29 |     <OptionsContext.Provider value={lastOptions.current}>
30 |       {children}
31 |     </OptionsContext.Provider>
32 |   ) : null;
33 | };
34 | 
35 | export default OptionsProvider;
36 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/Provider/RenderOptionsProvider.tsx:
--------------------------------------------------------------------------------
 1 | import type { FC, PropsWithChildren } from 'react';
 2 | import React, { useRef } from 'react';
 3 | import deepEquals from '../utils/deepEquals';
 4 | import { RenderOptionsContext } from '../components/hooks';
 5 | import type { RenderOptions } from '../types';
 6 | import { DEFAULT_RENDER_OPTIONS } from '../defaultOptions';
 7 | /*
 8 | we memoize the RenderOptions, so that if you access them, you won't get a fresh object every time.
 9 | 
10 | */
11 | const RenderOptionsProvider: FC<PropsWithChildren<RenderOptions>> = ({
12 |   children,
13 |   ...renderOptions
14 | }) => {
15 |   const lastRenderOptions = useRef<Required<RenderOptions>>();
16 |   const fullRenderOptions = {
17 |     ...DEFAULT_RENDER_OPTIONS,
18 |     ...renderOptions,
19 |   };
20 | 
21 |   const isEqual = lastRenderOptions.current
22 |     ? deepEquals(lastRenderOptions.current, fullRenderOptions)
23 |     : false;
24 |   if (!isEqual) {
25 |     lastRenderOptions.current = fullRenderOptions;
26 |   }
27 | 
28 |   return lastRenderOptions.current ? (
29 |     <RenderOptionsContext.Provider value={lastRenderOptions.current}>
30 |       {children}
31 |     </RenderOptionsContext.Provider>
32 |   ) : null;
33 | };
34 | 
35 | export default RenderOptionsProvider;
36 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/actions/cell/index.ts:
--------------------------------------------------------------------------------
 1 | import type { CellHoverAction } from './drag';
 2 | import { dragActions } from './drag';
 3 | import type { InsertAction } from './insert';
 4 | import { insertActions } from './insert';
 5 | import type { CellCoreAction } from './core';
 6 | import { coreActions } from './core';
 7 | export const cellActions = { ...dragActions, ...insertActions, ...coreActions };
 8 | export * from './insert';
 9 | export * from './core';
10 | export * from './drag';
11 | 
12 | export type CellAction = CellCoreAction | CellHoverAction | InsertAction;
13 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/actions/helpers.ts:
--------------------------------------------------------------------------------
 1 | import type { NewIds } from '../types/node';
 2 | import { createId } from '../utils/createId';
 3 | 
 4 | export const generateIds = (): NewIds => {
 5 |   return {
 6 |     cell: createId(),
 7 |     item: createId(),
 8 |     others: [createId(), createId(), createId()],
 9 |   };
10 | };
11 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/actions/setting.ts:
--------------------------------------------------------------------------------
 1 | import type { Action } from 'redux';
 2 | 
 3 | export const SET_LANG = 'SET_LANG';
 4 | 
 5 | export interface SetLangAction extends Action {
 6 |   lang: string;
 7 | }
 8 | 
 9 | export const setLang = (lang: string): SetLangAction => ({
10 |   type: SET_LANG,
11 |   lang,
12 | });
13 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/actions/undo.ts:
--------------------------------------------------------------------------------
 1 | import type { Action } from 'redux';
 2 | import { ActionTypes } from 'redux-undo';
 3 | 
 4 | export const undo = (): Action => ({
 5 |   type: ActionTypes.UNDO,
 6 | });
 7 | 
 8 | export const redo = (): Action => ({
 9 |   type: ActionTypes.REDO,
10 | });
11 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/actions/value.ts:
--------------------------------------------------------------------------------
 1 | import type { Action } from 'redux';
 2 | import type { Value, NewIds } from '../types/node';
 3 | import { generateIds } from './helpers';
 4 | 
 5 | export const UPDATE_VALUE = 'UPDATE_VALUE';
 6 | 
 7 | export interface UpdateEditableAction extends Action {
 8 |   ts: Date;
 9 |   value: Value | null;
10 |   ids: NewIds;
11 | }
12 | 
13 | export const updateValue = (value: Value | null): UpdateEditableAction => ({
14 |   type: UPDATE_VALUE,
15 |   ts: new Date(),
16 |   value,
17 |   ids: generateIds(),
18 | });
19 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Cell/CellErrorGate.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import ErrorCell from './ErrorCell';
 3 | 
 4 | export const CellErrorGate = class extends React.Component<
 5 |   {
 6 |     children: React.ReactNode;
 7 |     nodeId: string;
 8 |     shouldShowError?: boolean;
 9 |   },
10 |   { error: Error | null }
11 | > {
12 |   state = {
13 |     error: null,
14 |   };
15 |   componentDidCatch(error: Error) {
16 |     this.setState({ error });
17 |     console.error(error);
18 |   }
19 | 
20 |   reset() {
21 |     this.setState({ error: null });
22 |   }
23 | 
24 |   render() {
25 |     if (this.state.error && this.props.shouldShowError) {
26 |       return (
27 |         <ErrorCell
28 |           nodeId={this.props.nodeId}
29 |           error={this.state.error}
30 |           resetError={this.reset.bind(this)}
31 |         />
32 |       );
33 |     }
34 |     return this.props.children;
35 |   }
36 | };
37 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Cell/ErrorCell/index.css:
--------------------------------------------------------------------------------
 1 | .react-page-cell-error {
 2 |   background-color: red;
 3 |   padding: 8px;
 4 |   margin: 2px;
 5 |   overflow: hidden;
 6 | }
 7 | 
 8 | .react-page-cell-error strong {
 9 |   margin: 0 auto;
10 | }
11 | 
12 | .react-page-cell-error code {
13 |   overflow: scroll;
14 | }
15 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Cell/ErrorCell/index.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import { useIsEditMode, useRemoveCell, useUiTranslator } from '../../hooks';
 3 | 
 4 | const ErrorCell: React.FC<{
 5 |   nodeId: string;
 6 |   error: Error;
 7 |   resetError?: () => void;
 8 | }> = ({ nodeId, error, resetError }) => {
 9 |   const isEditMode = useIsEditMode();
10 |   const removeCell = useRemoveCell(nodeId);
11 |   const { t } = useUiTranslator();
12 |   return (
13 |     <div className="react-page-cell-error">
14 |       <strong>{t('An error occurred!')}</strong>
15 |       <small>
16 |         <dl>
17 |           <dt>{t('Cause:')}</dt>
18 |           <dd>{error.message}</dd>
19 |           <dt>{t('Cell:')}</dt>
20 |           <dd>{nodeId}</dd>
21 |         </dl>
22 |       </small>
23 |       {isEditMode ? (
24 |         <>
25 |           {resetError ? (
26 |             <button onClick={() => resetError()}>{t('Reset')}</button>
27 |           ) : null}
28 |           <button onClick={() => removeCell()}>{t('Remove')}</button>
29 |         </>
30 |       ) : null}
31 |     </div>
32 |   );
33 | };
34 | 
35 | export default ErrorCell;
36 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Cell/Handle/index.css:
--------------------------------------------------------------------------------
 1 | .react-page-editable {
 2 |   .react-page-cell-handle {
 3 |     display: none;
 4 |   }
 5 |   &&-mode-edit,
 6 |   &&-mode-resizing,
 7 |   &&-mode-layout {
 8 |     .react-page-cell-handle {
 9 |       position: absolute;
10 |       top: 0px;
11 |       left: 50%;
12 |       transform: translateX(-50%) translateY(-100%);
13 |       transition: opacity ease 0.4s;
14 |       opacity: 0;
15 | 
16 |       color: rgba(0, 0, 0, 0.97);
17 | 
18 |       background: rgba(255, 255, 255, 0.95);
19 |       text-align: center;
20 |       color: rgba(0, 0, 0, 0.97);
21 | 
22 |       display: inline-block;
23 |       padding: 12px 24px;
24 |       margin: 0 auto;
25 |       border-radius: 12px 12px 0 0;
26 |       text-transform: uppercase;
27 |       font-size: 14px;
28 |       line-height: 1.4;
29 |       letter-spacing: 0.15em;
30 | 
31 |       box-shadow: 0 -5px 5px rgb(0 0 0 / 22%);
32 |       pointer-events: none;
33 |     }
34 | 
35 |     .react-page-cell-handle-drag-enabled {
36 |       cursor: move;
37 |     }
38 | 
39 |     .react-page-cell:hover > .react-page-cell-handle,
40 |     .react-page-cell.react-page-cell-focused > .react-page-cell-handle {
41 |       opacity: 1;
42 |       pointer-events: all;
43 |     }
44 |   }
45 | }
46 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Cell/NoopProvider.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, PropsWithChildren } from 'react';
2 | import React from 'react';
3 | 
4 | const NoopProvider: FC<PropsWithChildren> = ({ children }) => <>{children}</>;
5 | 
6 | export default NoopProvider;
7 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Cell/PluginMissing.tsx:
--------------------------------------------------------------------------------
 1 | import type { PropsWithChildren } from 'react';
 2 | import React from 'react';
 3 | 
 4 | import type { CellPluginMissingProps } from '../../types/plugins';
 5 | 
 6 | const PluginMissing: React.FC<PropsWithChildren<CellPluginMissingProps>> = ({
 7 |   children,
 8 |   ...props
 9 | }) => (
10 |   <div>
11 |     <div
12 |       style={{
13 |         backgroundColor: 'red',
14 |         padding: '8px',
15 |         border: '1px solid black',
16 |         margin: '2px',
17 |         overflowX: 'scroll',
18 |       }}
19 |     >
20 |       The requested plugin `{props.pluginId}` could not be found.
21 |       <button onClick={props.remove}>Delete Plugin</button>
22 |       <pre>{JSON.stringify(props, null, 2)}</pre>
23 |     </div>
24 |     {children}
25 |   </div>
26 | );
27 | 
28 | export default PluginMissing;
29 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Cell/Rows/__tests__/index.test.tsx:
--------------------------------------------------------------------------------
 1 | import { shallow } from 'enzyme';
 2 | import React from 'react';
 3 | 
 4 | import Component from '../index';
 5 | 
 6 | describe('components/Cell/Rows', () => {
 7 |   xit('renders a single div', () => {
 8 |     const wrapper = shallow(<Component nodeId="some-node-id" />);
 9 |     expect(wrapper.find('.react-page-cell-rows')).toHaveLength(1);
10 |   });
11 | });
12 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Cell/Rows/index.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import Row from '../../Row';
 3 | import { useNodeChildrenIds } from '../../hooks';
 4 | 
 5 | const Rows: React.FC<{
 6 |   nodeId: string;
 7 | }> = ({ nodeId }) => {
 8 |   const rowIds = useNodeChildrenIds(nodeId);
 9 | 
10 |   return (
11 |     <div className="react-page-cell-rows">
12 |       {rowIds.map((id) => (
13 |         <Row nodeId={id} key={id} />
14 |       ))}
15 |     </div>
16 |   );
17 | };
18 | 
19 | export default React.memo(Rows);
20 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Cell/utils/scrollIntoViewWithOffset.ts:
--------------------------------------------------------------------------------
 1 | export default (
 2 |   element: HTMLElement,
 3 |   offset = 0,
 4 |   behavior: ScrollBehavior = 'smooth'
 5 | ) => {
 6 |   if (!element) {
 7 |     return;
 8 |   }
 9 |   const bodyRect = document.body.getBoundingClientRect().top;
10 |   const elementRect = element.getBoundingClientRect().top;
11 |   const elementPosition = elementRect - bodyRect;
12 |   const offsetPosition = elementPosition - offset;
13 | 
14 |   window.scrollTo({
15 |     top: offsetPosition,
16 |     behavior,
17 |   });
18 | };
19 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Editable/Inner/Rows.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import InsertNew from '../../Cell/InsertNew';
 3 | import { useCellSpacing, useOption, useValueNode } from '../../hooks';
 4 | import Row from '../../Row';
 5 | 
 6 | const Rows: React.FC = () => {
 7 |   const { rowIds } = useValueNode((editable) => ({
 8 |     rowIds: editable?.rows?.map((c) => c.id) ?? [],
 9 |   }));
10 | 
11 |   const childConstraints = useOption('childConstraints');
12 |   const components = useOption('components');
13 | 
14 |   const { y: cellSpacingY } = useCellSpacing();
15 |   const insertAllowed = childConstraints?.maxChildren
16 |     ? childConstraints?.maxChildren > rowIds.length
17 |     : true;
18 | 
19 |   const InsertNewWithDefault = components?.InsertNew ?? InsertNew;
20 | 
21 |   return (
22 |     <>
23 |       {rowIds.length > 0 ? (
24 |         <div
25 |           style={
26 |             cellSpacingY !== 0
27 |               ? { margin: `${-cellSpacingY / 2}px 0` }
28 |               : undefined
29 |           }
30 |         >
31 |           {rowIds.map((id) => (
32 |             <Row nodeId={id} key={id} />
33 |           ))}
34 |         </div>
35 |       ) : null}
36 |       {insertAllowed ? <InsertNewWithDefault childrenIds={rowIds} /> : null}
37 |     </>
38 |   );
39 | };
40 | 
41 | export default React.memo(Rows);
42 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Editable/index.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import FallbackDropArea from './FallbackDropArea';
 3 | import Inner from './Inner';
 4 | 
 5 | const Editable: React.FC = () => {
 6 |   return (
 7 |     <FallbackDropArea>
 8 |       <Inner />
 9 |     </FallbackDropArea>
10 |   );
11 | };
12 | 
13 | export default React.memo(Editable);
14 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/Row/Droppable/index.tsx:
--------------------------------------------------------------------------------
 1 | import type { FC, PropsWithChildren } from 'react';
 2 | import React from 'react';
 3 | import { useCellDrop } from '../../Cell/Droppable';
 4 | import { useIsInsertMode, useIsLayoutMode } from '../../hooks';
 5 | 
 6 | const Droppable: FC<PropsWithChildren<{ nodeId: string }>> = ({
 7 |   children,
 8 |   nodeId,
 9 | }) => {
10 |   const isLayoutMode = useIsLayoutMode();
11 |   const isInsertMode = useIsInsertMode();
12 | 
13 |   const [ref, isAllowed] = useCellDrop(nodeId);
14 |   if (!(isLayoutMode || isInsertMode)) {
15 |     return <div className="react-page-row-droppable-container">{children}</div>;
16 |   }
17 |   return (
18 |     <div ref={ref} className="react-page-row-droppable">
19 |       {children}
20 |     </div>
21 |   );
22 | };
23 | 
24 | export default Droppable;
25 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/hooks/actions.ts:
--------------------------------------------------------------------------------
 1 | import { useCallback } from 'react';
 2 | import { redo, undo } from '../../actions/undo';
 3 | import { useDispatch, useSelector } from '../../reduxConnect';
 4 | 
 5 | /**
 6 |  * @returns function, that undos last change if called
 7 |  */
 8 | export const useUndo = () => {
 9 |   const dispatch = useDispatch();
10 |   return useCallback(() => dispatch(undo()), [dispatch]);
11 | };
12 | 
13 | /**
14 |  * @returns function, that redos last change if called
15 |  */
16 | export const useRedo = () => {
17 |   const dispatch = useDispatch();
18 |   return useCallback(() => dispatch(redo()), [dispatch]);
19 | };
20 | 
21 | /**
22 |  * @returns whether user can undo
23 |  */
24 | export const useCanUndo = () => {
25 |   return useSelector((s) => s.reactPage.values.past.length > 0);
26 | };
27 | /**
28 |  * @returns whether user can undo
29 |  */
30 | export const useCanRedo = () => {
31 |   return useSelector((s) => s.reactPage.values.future.length > 0);
32 | };
33 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/hooks/callbacks.ts:
--------------------------------------------------------------------------------
 1 | import { createContext, useContext, useRef } from 'react';
 2 | import type { Callbacks } from '../../types';
 3 | 
 4 | export const CallbacksContext = createContext<Callbacks>({});
 5 | 
 6 | /**
 7 |  * @returns the callbacks object of the current Editor.
 8 |  *
 9 |  * this object is memoized, alltough its better to use `usecallback` instead if you want to use a single callback
10 |  */
11 | export const useCallbackOptions = () => useContext(CallbacksContext);
12 | 
13 | /**
14 |  * get a single (memoized) callback
15 |  * @param key the callback key
16 |  * @returns the callback value
17 |  */
18 | export const useCallbackOption = <K extends keyof Callbacks>(key: K) => {
19 |   const callbacks = useCallbackOptions();
20 |   const callback = callbacks[key];
21 |   const lastcallback = useRef(callback);
22 |   if (lastcallback.current !== callback) {
23 |     lastcallback.current = callback;
24 |   }
25 |   return lastcallback.current;
26 | };
27 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/hooks/index.ts:
--------------------------------------------------------------------------------
 1 | export * from './value';
 2 | export * from './node';
 3 | export * from './focus';
 4 | export * from './options';
 5 | export * from './renderOptions';
 6 | export * from './callbacks';
 7 | export * from './actions';
 8 | export * from './nodeActions';
 9 | export * from './displayMode';
10 | export * from './dragDropActions';
11 | export * from './screen';
12 | export * from './display';
13 | export * from './nodeMove';
14 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/hooks/renderOptions.ts:
--------------------------------------------------------------------------------
 1 | import { createContext, useContext, useRef } from 'react';
 2 | import deepEquals from '../../utils/deepEquals';
 3 | import { DEFAULT_RENDER_OPTIONS } from '../../defaultOptions';
 4 | import type { RenderOptions } from '../../types';
 5 | 
 6 | export const RenderOptionsContext = createContext<RenderOptions>(
 7 |   DEFAULT_RENDER_OPTIONS
 8 | );
 9 | 
10 | /**
11 |  * @returns the options object of the current Editor.
12 |  *
13 |  * this object is memoized, alltough its better to use `useOption` instead if you want to use a single option
14 |  */
15 | export const useRenderOptions = () => useContext(RenderOptionsContext);
16 | 
17 | /**
18 |  * get a single (memoized) option value
19 |  * @param key the option key
20 |  * @returns the option value
21 |  */
22 | export const useRenderOption = <K extends keyof RenderOptions>(key: K) => {
23 |   const options = useRenderOptions();
24 |   const option = options[key];
25 |   const lastOption = useRef(option);
26 |   if (!deepEquals(lastOption.current, option)) {
27 |     lastOption.current = option;
28 |   }
29 |   return lastOption.current;
30 | };
31 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/hooks/screen.tsx:
--------------------------------------------------------------------------------
1 | import { useMediaQuery, useTheme } from '@mui/material';
2 | 
3 | export const useIsSmallScreen = () => {
4 |   const theme = useTheme();
5 |   return useMediaQuery(theme.breakpoints.down('sm'));
6 | };
7 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/hooks/value.ts:
--------------------------------------------------------------------------------
 1 | import { useSelector } from '../../reduxConnect';
 2 | 
 3 | import { currentValue } from '../../selector/editable';
 4 | import type { Value } from '../../types/node';
 5 | import deepEquals from '../../utils/deepEquals';
 6 | 
 7 | type ValueSelector<T> = (node: Value | null) => T;
 8 | /**
 9 |  *
10 |  * @param selector receives the current value node object and returns T
11 |  * @returns the selection T
12 |  */
13 | export const useValueNode = <T>(selector: ValueSelector<T>) => {
14 |   return useSelector((state) => selector(currentValue(state)), deepEquals);
15 | };
16 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/components/index.css:
--------------------------------------------------------------------------------
1 | @import './Row/index.css';
2 | @import './Editable/index.css';
3 | @import './Cell/index.css';
4 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/const.ts:
--------------------------------------------------------------------------------
 1 | /**
 2 |  * A list of positions in the layout space.
 3 |  */
 4 | export enum PositionEnum {
 5 |   LEFT_OF = 'left-of',
 6 |   RIGHT_OF = 'right-of',
 7 |   ABOVE = 'above',
 8 |   BELOW = 'below',
 9 |   INLINE_LEFT = 'inline-left',
10 |   INLINE_RIGHT = 'inline-right',
11 | }
12 | 
13 | /**
14 |  * Is true if built in production mode.
15 |  */
16 | export const isProduction = process.env.NODE_ENV === 'production';
17 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/defaultOptions.ts:
--------------------------------------------------------------------------------
 1 | import type { Options, RenderOptions } from './types';
 2 | 
 3 | import { HTML5Backend } from 'react-dnd-html5-backend';
 4 | import { DISPLAY_MODE_EDIT } from './actions/display';
 5 | import { defaultTheme } from '../ui';
 6 | 
 7 | export const DEFAULT_OPTIONS: Required<Options> = {
 8 |   allowMoveInEditMode: true,
 9 |   allowResizeInEditMode: true,
10 | 
11 |   childConstraints: {},
12 |   components: {},
13 |   languages: [],
14 |   uiTranslator: null,
15 |   zoomEnabled: true,
16 |   zoomFactors: [1, 0.75, 0.5, 0.25],
17 |   undoRedoEnabled: true,
18 |   editEnabled: true,
19 |   insertEnabled: true,
20 |   layoutEnabled: true,
21 |   resizeEnabled: true,
22 |   previewEnabled: true,
23 | 
24 |   dndBackend: HTML5Backend,
25 |   blurGateDefaultMode: DISPLAY_MODE_EDIT,
26 |   blurGateDisabled: false,
27 |   middleware: [],
28 |   store: null,
29 |   hideEditorSidebar: false,
30 |   showMoveButtonsInBottomToolbar: true,
31 |   showMoveButtonsInLayoutMode: true,
32 |   sidebarPosition: 'rightAbsolute',
33 |   customOptions: [],
34 |   uiTheme: defaultTheme,
35 |   shouldShowErrorInCells: false,
36 | };
37 | 
38 | export const DEFAULT_RENDER_OPTIONS: Required<RenderOptions> = {
39 |   cellPlugins: [],
40 |   cellSpacing: null,
41 | };
42 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/helper/throttle/index.ts:
--------------------------------------------------------------------------------
1 | import { isProduction } from '../../const';
2 | 
3 | export const delay = isProduction ? 40 : 60;
4 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/index.css:
--------------------------------------------------------------------------------
1 | @import 'grid.css';
2 | @import 'components/index.css';
3 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/migrations/EDITABLE_MIGRATIONS/index.ts:
--------------------------------------------------------------------------------
1 | import from0to1 from './from0to1';
2 | 
3 | export const CURRENT_EDITABLE_VERSION = 1;
4 | export default [from0to1];
5 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/migrations/serialzeValue.ts:
--------------------------------------------------------------------------------
 1 | import type { CellPluginList } from '../types/plugins';
 2 | import type { Cell, Value, Row } from '../types/node';
 3 | 
 4 | const serializeRow = (r: Row, cellPlugins: CellPluginList): Row => {
 5 |   return {
 6 |     ...r,
 7 |     cells: r.cells.map((c) => serializeCell(c, cellPlugins)),
 8 |   };
 9 | };
10 | const serializeCell = (c: Cell, cellPlugins: CellPluginList): Cell => {
11 |   const pluginDef = c.plugin;
12 |   const pluginFound = pluginDef
13 |     ? cellPlugins.find((p) => p.id === pluginDef.id)
14 |     : null;
15 | 
16 |   const transformData = (dataIn: unknown) => {
17 |     return pluginFound?.serialize ? pluginFound.serialize(dataIn) : dataIn;
18 |   };
19 |   const dataI18n = c.dataI18n
20 |     ? Object.keys(c.dataI18n).reduce(
21 |         (acc, lang) => ({
22 |           ...acc,
23 |           [lang]: transformData(c.dataI18n?.[lang]),
24 |         }),
25 |         {}
26 |       )
27 |     : null;
28 | 
29 |   return {
30 |     ...c,
31 |     rows: c.rows?.map((r) => serializeRow(r, cellPlugins)),
32 |     dataI18n: dataI18n ?? {},
33 |   };
34 | };
35 | 
36 | export const serialzeValue = (
37 |   { rows, ...rest }: Value,
38 |   plugins: CellPluginList
39 | ) => {
40 |   return {
41 |     ...rest,
42 |     rows: rows.map((c) => serializeRow(c, plugins)),
43 |   };
44 | };
45 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/reducer/hover/index.ts:
--------------------------------------------------------------------------------
 1 | import type { CellHoverAction, ClearHoverAction } from '../../actions/cell';
 2 | import { CELL_DRAG_HOVER, CLEAR_CLEAR_HOVER } from '../../actions/cell';
 3 | import type { PositionEnum } from '../../const';
 4 | 
 5 | export type Hover = {
 6 |   nodeId?: string;
 7 |   position: PositionEnum;
 8 | } | null;
 9 | 
10 | export const hover = (
11 |   state: Hover = null,
12 |   action: CellHoverAction | ClearHoverAction
13 | ): Hover => {
14 |   switch (action.type) {
15 |     case CELL_DRAG_HOVER: {
16 |       return {
17 |         nodeId: action.hoverId,
18 |         position: action.position,
19 |       };
20 |     }
21 |     case CLEAR_CLEAR_HOVER:
22 |       return null;
23 | 
24 |     default:
25 |       return state;
26 |   }
27 | };
28 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/reducer/index.ts:
--------------------------------------------------------------------------------
 1 | import { combineReducers } from 'redux';
 2 | import type { Value, RootState } from '../types';
 3 | 
 4 | import { values } from './values';
 5 | import { display } from './display';
 6 | import { focus } from './focus';
 7 | 
 8 | import { hover } from './hover';
 9 | import { settings } from './settings';
10 | 
11 | const reducer = combineReducers({
12 |   values,
13 |   display,
14 |   focus,
15 |   settings,
16 |   hover,
17 |   __nodeCache: () => null, // always empty __nodeCache
18 | });
19 | 
20 | export { reducer };
21 | 
22 | export default combineReducers({ reactPage: reducer });
23 | 
24 | export function initialState(value: Value | null, lang: string): RootState {
25 |   return {
26 |     reactPage: {
27 |       __nodeCache: {},
28 |       hover: null,
29 |       focus: null,
30 |       display: {
31 |         mode: 'edit',
32 |         zoom: 1,
33 |       },
34 |       settings: {
35 |         lang,
36 |       },
37 |       values: {
38 |         past: [],
39 |         present: value,
40 |         future: [],
41 |       },
42 |     },
43 |   };
44 | }
45 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/reducer/settings/index.ts:
--------------------------------------------------------------------------------
 1 | import { SET_LANG } from '../../actions/setting';
 2 | 
 3 | export const settings = (
 4 |   state = {
 5 |     lang: null,
 6 |   },
 7 |   action: {
 8 |     type: string;
 9 | 
10 |     [key: string]: unknown;
11 |   }
12 | ) => {
13 |   switch (action.type) {
14 |     case SET_LANG:
15 |       return {
16 |         ...state,
17 |         lang: action.lang,
18 |       };
19 |     default:
20 |       return state;
21 |   }
22 | };
23 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/reducer/value/helper/__tests__/sizing.test.ts:
--------------------------------------------------------------------------------
 1 | import expect from 'unexpected';
 2 | 
 3 | import { sumSizes, resizeCells } from '../sizing';
 4 | import type { Cell } from '../../../../types/node';
 5 | 
 6 | describe('sumSizes', () => {
 7 |   [
 8 |     {
 9 |       cells: [{ size: 6 } as Cell, { size: 6 } as Cell],
10 |       e: 12,
11 |     },
12 |     {
13 |       cells: [{ size: 6 } as Cell, { size: 2 } as Cell],
14 |       e: 8,
15 |     },
16 |     {
17 |       cells: [{ size: 6 } as Cell, { size: 6 } as Cell, { size: 3 } as Cell],
18 |       e: 15,
19 |     },
20 |   ].forEach((c, k) => {
21 |     it(`should pass test case ${k}`, () => {
22 |       expect(sumSizes(c.cells), 'to equal', c.e);
23 |     });
24 |   });
25 | });
26 | 
27 | describe('resizeCells', () => {
28 |   [
29 |     {
30 |       a: { id: '2', size: 6 } as Cell,
31 |       cells: [
32 |         { id: '1', size: 4 } as Cell,
33 |         { id: '2', size: 4 } as Cell,
34 |         { id: '3', size: 4 } as Cell,
35 |       ],
36 |       e: [
37 |         { id: '1', size: 4 },
38 |         { id: '2', size: 6 },
39 |         { id: '3', size: 2 },
40 |       ],
41 |     },
42 |   ].forEach((c, k) => {
43 |     it(`should pass test case ${k}`, () => {
44 |       expect(resizeCells(c.cells, c.a), 'to equal', c.e);
45 |     });
46 |   });
47 | });
48 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/reducer/value/helper/empty.ts:
--------------------------------------------------------------------------------
 1 | import type { Node } from '../../../types/node';
 2 | import { isRow } from '../../../types/node';
 3 | 
 4 | export const isEmpty = (node: Node): boolean => {
 5 |   if (!node) {
 6 |     return true;
 7 |   }
 8 |   if (isRow(node)) {
 9 |     return node.cells.length === 0;
10 |   }
11 |   if (node.rows && node.rows?.length > 0) {
12 |     return false;
13 |   }
14 |   return !node.plugin;
15 | };
16 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/reducer/value/helper/setAllSizesAndOptimize.ts:
--------------------------------------------------------------------------------
 1 | import { computeSizes, computeInlines } from './sizing';
 2 | import { optimizeRow, optimizeRows, optimizeCells } from './optimize';
 3 | import type { Row } from '../../../types/node';
 4 | 
 5 | export const setAllSizesAndOptimize = (rows: Array<Row> = []): Array<Row> =>
 6 |   optimizeRows(rows).map((r: Row): Row => {
 7 |     const optimized = optimizeRow(r);
 8 |     if (optimized.cells) {
 9 |       optimized.cells = computeInlines(
10 |         computeSizes(
11 |           optimizeCells(
12 |             optimized.cells.map((cell) => ({
13 |               ...cell,
14 |               rows: cell.rows ? setAllSizesAndOptimize(cell.rows) : undefined,
15 |             }))
16 |           )
17 |         )
18 |       );
19 |     }
20 |     return optimized;
21 |   });
22 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/reducer/value/index.ts:
--------------------------------------------------------------------------------
 1 | import type { AnyAction } from 'redux';
 2 | import type { Value } from '../../types/node';
 3 | 
 4 | import { setAllSizesAndOptimize } from './helper/setAllSizesAndOptimize';
 5 | import { rows } from './tree';
 6 | 
 7 | export const value = (state: Value | null | undefined, action: AnyAction) => {
 8 |   switch (action.type) {
 9 |     case 'UPDATE_VALUE': {
10 |       return action.value;
11 |     }
12 |   }
13 |   const newRows = state?.rows
14 |     ? setAllSizesAndOptimize(rows(state.rows, action, 0))
15 |     : [];
16 | 
17 |   return {
18 |     ...state,
19 |     rows: newRows,
20 |   };
21 | };
22 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/reducer/value/testUtils.ts:
--------------------------------------------------------------------------------
 1 | import type { Action } from 'redux';
 2 | import { applyMiddleware, combineReducers, createStore } from 'redux';
 3 | import thunk from 'redux-thunk';
 4 | import type { Value } from '../../types/node';
 5 | 
 6 | import { value } from './index';
 7 | 
 8 | export const simulateDispatch = (
 9 |   initialState: Value,
10 |   action?: Action
11 | ): Value => {
12 |   const reducer = combineReducers({ value });
13 |   const store = createStore(
14 |     reducer,
15 |     { value: initialState },
16 |     applyMiddleware(thunk)
17 |   );
18 |   if (action) store.dispatch(action);
19 | 
20 |   return store.getState().value;
21 | };
22 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/reduxConnect.tsx:
--------------------------------------------------------------------------------
 1 | /* eslint-disable @typescript-eslint/ban-types */
 2 | import type { Dispatch } from 'react';
 3 | import React from 'react';
 4 | import {
 5 |   createDispatchHook,
 6 |   createSelectorHook,
 7 |   createStoreHook,
 8 |   Provider,
 9 | } from 'react-redux';
10 | import type { RootState } from './types';
11 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
12 | export const ReduxContext = React.createContext<any>(null);
13 | 
14 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
15 | export const ReduxProvider = ({ store, ...props }: any) => (
16 |   <Provider store={store} context={ReduxContext} {...props} />
17 | );
18 | 
19 | export const useStore = createStoreHook<RootState>(ReduxContext);
20 | export const useDispatch = createDispatchHook(
21 |   ReduxContext
22 |   // eslint-disable-next-line @typescript-eslint/no-explicit-any
23 | ) as () => Dispatch<any>;
24 | export const useSelector = createSelectorHook<RootState>(ReduxContext);
25 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/selector/display/index.ts:
--------------------------------------------------------------------------------
 1 | import {
 2 |   DISPLAY_MODE_EDIT,
 3 |   DISPLAY_MODE_LAYOUT,
 4 |   DISPLAY_MODE_PREVIEW,
 5 |   DISPLAY_MODE_INSERT,
 6 |   DISPLAY_MODE_RESIZING,
 7 | } from '../../actions/display';
 8 | 
 9 | import type { RootState } from '../../types/state';
10 | 
11 | export const isPreviewMode = ({
12 |   reactPage: {
13 |     display: { mode },
14 |   },
15 | }: RootState): boolean => mode === DISPLAY_MODE_PREVIEW;
16 | export const isLayoutMode = ({
17 |   reactPage: {
18 |     display: { mode },
19 |   },
20 | }: RootState): boolean => mode === DISPLAY_MODE_LAYOUT;
21 | export const isEditMode = ({
22 |   reactPage: {
23 |     display: { mode },
24 |   },
25 | }: RootState): boolean => mode === DISPLAY_MODE_EDIT;
26 | export const isInsertMode = ({
27 |   reactPage: {
28 |     display: { mode },
29 |   },
30 | }: RootState): boolean => mode === DISPLAY_MODE_INSERT;
31 | export const isResizeMode = ({
32 |   reactPage: {
33 |     display: { mode },
34 |   },
35 | }: RootState): boolean => mode === DISPLAY_MODE_RESIZING;
36 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/selector/focus.ts:
--------------------------------------------------------------------------------
 1 | import type { RootState } from '../types/state';
 2 | import { findNodeInState } from './editable';
 3 | 
 4 | export const focus = (state: RootState) =>
 5 |   state && state.reactPage && state.reactPage.focus;
 6 | 
 7 | export const allFocusedNodeIds = (state: RootState) => {
 8 |   return (
 9 |     focus(state)?.nodeIds?.filter((n) => findNodeInState(state, n)?.node) ?? []
10 |   );
11 | };
12 | export const singleFocusedNode = (state: RootState) => {
13 |   const nodeIds = allFocusedNodeIds(state);
14 | 
15 |   if (nodeIds?.length === 1) return nodeIds[0];
16 |   return null;
17 | };
18 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/selector/setting.ts:
--------------------------------------------------------------------------------
1 | import type { RootState } from '../types/state';
2 | 
3 | export const getLang = ({ reactPage: { settings } }: RootState) =>
4 |   settings.lang ?? 'default';
5 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/store.ts:
--------------------------------------------------------------------------------
 1 | import type { Store, Middleware } from 'redux';
 2 | import { createStore, applyMiddleware, compose } from 'redux';
 3 | import thunk from 'redux-thunk';
 4 | import rootReducer from './reducer';
 5 | import type { RootState } from './types/state';
 6 | import { isProduction } from './const';
 7 | 
 8 | declare global {
 9 |   interface Window {
10 |     __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: (settings: unknown) => void;
11 |   }
12 | }
13 | 
14 | /**
15 |  * Returns a new redux store.
16 |  */
17 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
18 | export default (
19 |   initialState: Record<string, unknown>,
20 |   middleware: Middleware[] = []
21 | ): Store<RootState> => {
22 |   // eslint-disable-next-line @typescript-eslint/no-explicit-any
23 |   const v: any =
24 |     !isProduction &&
25 |     typeof window === 'object' &&
26 |     window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
27 |       ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
28 |       : compose;
29 | 
30 |   return createStore(
31 |     rootReducer,
32 |     initialState,
33 |     v(applyMiddleware(...middleware, thunk))
34 |   );
35 | };
36 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/types/callbacks.ts:
--------------------------------------------------------------------------------
 1 | import type { Value } from './node';
 2 | 
 3 | export type Callbacks = {
 4 |   /**
 5 |    * is called when the value has changed.
 6 |    * Use this to save the new value
 7 |    */
 8 |   onChange?: null | ((v: Value) => void);
 9 | 
10 |   /**
11 |    * is called when the language has changed
12 |    */
13 |   onChangeLang?: null | ((l: string) => void);
14 | };
15 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/types/components.ts:
--------------------------------------------------------------------------------
 1 | import type { BottomToolbarProps } from '../../ui/BottomToolbar/types';
 2 | import type { InsertNewProps } from '../components/Cell/InsertNew';
 3 | import type { CellPluginMissingProps } from './plugins';
 4 | 
 5 | /**
 6 |  * Internal component overrides for the editor.
 7 |  */
 8 | export type Components = {
 9 |   /**
10 |    * BottomToolbar used for rendering plugin controls.
11 |    */
12 |   BottomToolbar?: React.ComponentType<BottomToolbarProps>;
13 |   CellPluginMissing?: React.ComponentType<CellPluginMissingProps>;
14 |   EditModeResizeHandle?: React.ComponentType<{ onClick: () => void }>;
15 |   InsertNew?: React.ComponentType<InsertNewProps>;
16 | };
17 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/types/constraints.ts:
--------------------------------------------------------------------------------
 1 | export type ChildConstraints = {
 2 |   /**
 3 |    * EXPERIMENTAL
 4 |    *
 5 |    * how many direct children are allowed?
 6 |    *
 7 |    * currently only affects the "+" button
 8 |    */
 9 |   maxChildren?: number;
10 | };
11 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/types/display.ts:
--------------------------------------------------------------------------------
1 | import type { DisplayModes } from '../actions/display';
2 | 
3 | export type Display = {
4 |   mode: DisplayModes;
5 |   referenceNodeId?: string;
6 |   zoom: number;
7 | };
8 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/types/hover.ts:
--------------------------------------------------------------------------------
 1 | import type { InsertOptions } from '../actions/cell';
 2 | import type { HoverTarget } from '../service/hover/computeHover';
 3 | import type { PartialCell } from './node';
 4 | 
 5 | export type Room = {
 6 |   height: number;
 7 |   width: number;
 8 | };
 9 | 
10 | export type Vector = {
11 |   y: number;
12 |   x: number;
13 | };
14 | 
15 | export type MatrixIndex = {
16 |   row: number;
17 |   cell: number;
18 | };
19 | 
20 | export type HoverInsertActions = {
21 |   dragCell(id: string): void;
22 |   cancelCellDrag(): void;
23 |   clear(): void;
24 |   above(drag: PartialCell, hover: HoverTarget, options?: InsertOptions): void;
25 |   below(drag: PartialCell, hover: HoverTarget, options?: InsertOptions): void;
26 |   leftOf(drag: PartialCell, hover: HoverTarget, options?: InsertOptions): void;
27 |   rightOf(drag: PartialCell, hover: HoverTarget, options?: InsertOptions): void;
28 |   inlineLeft(drag: PartialCell, hover: HoverTarget): void;
29 |   inlineRight(drag: PartialCell, hover: HoverTarget): void;
30 | };
31 | 
32 | export type Matrix = Array<Array<number>>;
33 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/types/index.ts:
--------------------------------------------------------------------------------
 1 | import type { Value } from '../..';
 2 | import type { Value_v0 } from '../migrations/EDITABLE_MIGRATIONS/from0to1';
 3 | 
 4 | export * from './display';
 5 | export * from './node';
 6 | export * from './hover';
 7 | export * from './jsonSchema';
 8 | export * from './plugins';
 9 | export * from './state';
10 | export * from './constraints';
11 | export * from './options';
12 | export * from './renderOptions';
13 | export * from './callbacks';
14 | export type ValueWithLegacy = Value | Value_v0;
15 | export type { Value_v0 };
16 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/types/renderOptions.ts:
--------------------------------------------------------------------------------
 1 | import type { CellPluginList } from '.';
 2 | 
 3 | export type CellSpacing = {
 4 |   x: number;
 5 |   y: number;
 6 | };
 7 | export type RenderOptions = {
 8 |   /**
 9 |    * an array of cell plugins. These plugins can be added as cells and usually render a component and a control.
10 |    * @see CellPlugin
11 |    */
12 |   cellPlugins: CellPluginList;
13 | 
14 |   /**
15 |    * Sets the size of the cell grid gutters in pixels.
16 |    */
17 |   cellSpacing?: number | CellSpacing | null;
18 | };
19 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/types/state.ts:
--------------------------------------------------------------------------------
 1 | import type { NodeWithAncestors, ValueWithHistory } from './node';
 2 | import type { Display } from './display';
 3 | import type { Focus } from '../reducer/focus';
 4 | import type { Hover } from '../reducer/hover';
 5 | 
 6 | export type RootState = {
 7 |   reactPage: {
 8 |     values: ValueWithHistory;
 9 |     display: Display;
10 |     focus: Focus | null;
11 |     hover: Hover | null;
12 |     settings: {
13 |       lang?: string;
14 |     };
15 |     __nodeCache?: Record<string, NodeWithAncestors | null>;
16 |   };
17 | };
18 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/utils/cloneWithNewIds.ts:
--------------------------------------------------------------------------------
 1 | import type { Cell, Node } from '../types';
 2 | import { isRow } from '../types';
 3 | import { createId } from './createId';
 4 | import { mapNode } from './mapNode';
 5 | 
 6 | export const cloneWithNewIds = (node: Node): Node => {
 7 |   return mapNode(node, {
 8 |     mapCell: (n) => ({
 9 |       ...n,
10 |       // clone data as well
11 |       dataI18n: n?.dataI18n ? JSON.parse(JSON.stringify(n.dataI18n)) : {},
12 |       id: createId(),
13 |     }),
14 |     mapRow: (n) => ({
15 |       ...n,
16 |       id: createId(),
17 |     }),
18 |   }) as Node;
19 | };
20 | 
21 | export const cloneAsCell = (node: Node): Cell => {
22 |   const cell = isRow(node)
23 |     ? {
24 |         id: createId(),
25 |         rows: [node],
26 |       }
27 |     : node;
28 |   return cloneWithNewIds(cell) as Cell;
29 | };
30 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/utils/createId.ts:
--------------------------------------------------------------------------------
1 | // import ShortUniqueId from 'short-unique-id';
2 | // REMOVED BECAUSE OF https://github.com/jeanlescure/short-unique-id/issues/31
3 | 
4 | // we do not need cryptographic save unique ids, so this poor mans solution is probably ok:
5 | 
6 | const LENGTH = 6;
7 | export const createId = () => Math.random().toString(36).substr(2, LENGTH);
8 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/utils/createValue.ts:
--------------------------------------------------------------------------------
 1 | import type { PluginsAndLang } from '../actions/cell/insert';
 2 | import { createRow } from '../actions/cell/insert';
 3 | import { CURRENT_EDITABLE_VERSION } from '../migrations/EDITABLE_MIGRATIONS';
 4 | import type { Value, PartialRow } from '../types/node';
 5 | import { createId } from './createId';
 6 | 
 7 | type PartialValue = {
 8 |   id?: string;
 9 |   rows?: PartialRow[];
10 | };
11 | export const createValue = (
12 |   partial: PartialValue,
13 |   options: PluginsAndLang
14 | ): Value => {
15 |   return {
16 |     id: partial.id || createId(),
17 |     rows: partial.rows?.map((c) => createRow(c, options)) ?? [],
18 |     version: CURRENT_EDITABLE_VERSION,
19 |   };
20 | };
21 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/utils/deepEquals.ts:
--------------------------------------------------------------------------------
1 | import equals from 'fast-deep-equal';
2 | 
3 | export default equals as <T>(a: T, b: T) => boolean;
4 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/utils/getCellData.ts:
--------------------------------------------------------------------------------
 1 | import type { Cell } from '../types';
 2 | 
 3 | export const getCellData = (
 4 |   cell: null | Pick<Cell, 'dataI18n'>,
 5 |   lang: string
 6 | ) => {
 7 |   const dataI18n = cell?.dataI18n;
 8 | 
 9 |   return (
10 |     dataI18n?.[lang] ??
11 |     // find first non-empty
12 |     dataI18n?.[Object.keys(dataI18n).find((l) => dataI18n[l]) ?? 'default'] ??
13 |     {}
14 |   );
15 | };
16 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/utils/getCellSpacing.ts:
--------------------------------------------------------------------------------
 1 | import type { CellPlugin, CellSpacing, DataTType } from '../types';
 2 | 
 3 | export const getPluginCellSpacing = <DataT extends DataTType>(
 4 |   plugin: CellPlugin<DataT> | null,
 5 |   data: DataT
 6 | ): number | CellSpacing | null =>
 7 |   plugin?.cellSpacing
 8 |     ? typeof plugin?.cellSpacing === 'function'
 9 |       ? plugin?.cellSpacing(data)
10 |       : plugin?.cellSpacing
11 |     : null;
12 | 
13 | export const normalizeCellSpacing = (
14 |   cellSpacing: null | number | CellSpacing = 0
15 | ): CellSpacing => {
16 |   if (!cellSpacing) {
17 |     return { x: 0, y: 0 };
18 |   }
19 |   if (['number', 'string'].indexOf(typeof cellSpacing) !== -1) {
20 |     return { x: +cellSpacing || 0, y: +cellSpacing || 0 };
21 |   } else {
22 |     return {
23 |       x: +(cellSpacing as CellSpacing).x || 0,
24 |       y: +(cellSpacing as CellSpacing).y || 0,
25 |     };
26 |   }
27 | };
28 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/utils/objIsNode.ts:
--------------------------------------------------------------------------------
 1 | import type { Node } from '../types';
 2 | 
 3 | // poor check
 4 | export const objIsNode = (obj: Record<string, unknown>): obj is Node => {
 5 |   if (!obj) return false;
 6 |   if (!('id' in obj)) {
 7 |     return false;
 8 |   }
 9 |   return true;
10 | };
11 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/utils/removeUndefinedProps.test.ts:
--------------------------------------------------------------------------------
 1 | import { removeUndefinedProps } from './removeUndefinedProps';
 2 | 
 3 | describe('removeUndefinedProps', () => {
 4 |   it('should remove undefined and null properties from object', () => {
 5 |     const obj = {
 6 |       a: 'a',
 7 |       b: undefined,
 8 |       c: 'something',
 9 |       d: null,
10 |     };
11 |     expect(removeUndefinedProps(obj)).toEqual({
12 |       a: 'a',
13 |       c: 'something',
14 |     });
15 |   });
16 | 
17 |   it('does not touch nested stuff', () => {
18 |     const obj = {
19 |       a: 'a',
20 |       b: undefined,
21 |       c: 'something',
22 |       d: {
23 |         some: undefined,
24 |         bar: 'bar',
25 |       },
26 |     };
27 |     expect(removeUndefinedProps(obj)).toEqual({
28 |       a: 'a',
29 |       c: 'something',
30 |       d: {
31 |         some: undefined,
32 |         bar: 'bar',
33 |       },
34 |     });
35 |   });
36 | });
37 | 


--------------------------------------------------------------------------------
/packages/editor/src/core/utils/removeUndefinedProps.ts:
--------------------------------------------------------------------------------
 1 | export const removeUndefinedProps = <T extends { [key: string]: unknown }>(
 2 |   obj: T
 3 | ): T =>
 4 |   Object.keys(obj).reduce((acc, key) => {
 5 |     const value = obj[key];
 6 |     if (typeof value === 'undefined' || value == null) {
 7 |       return acc;
 8 |     }
 9 |     return {
10 |       ...acc,
11 |       [key]: value,
12 |     };
13 |   }, {} as T);
14 | 


--------------------------------------------------------------------------------
/packages/editor/src/index.css:
--------------------------------------------------------------------------------
1 | 
2 | @import "variables.css";
3 | @import "core/index.css";
4 | @import "ui/index.css";
5 | 
6 | 


--------------------------------------------------------------------------------
/packages/editor/src/index.tsx:
--------------------------------------------------------------------------------
 1 | //import './wdyr';
 2 | export * from './core/types';
 3 | export * from './core/components/hooks';
 4 | export * from './ui';
 5 | 
 6 | import lazyLoad from './core/helper/lazyLoad';
 7 | import { Migration } from './core/migrations/Migration';
 8 | 
 9 | import Editor, { EditorProps } from './editor/Editor';
10 | import makeUniformsSchema from './ui/AutoformControls/makeUniformsSchema';
11 | 
12 | import { migrateValue } from './core/migrations/migrate';
13 | import deepEquals from './core/utils/deepEquals';
14 | 
15 | import { createValue } from './core/utils/createValue';
16 | import { objIsNode } from './core/utils/objIsNode';
17 | import { getTextContents } from './core/utils/getTextContents';
18 | export { objIsNode };
19 | export { lazyLoad };
20 | export { EditorProps };
21 | export { Migration };
22 | export { makeUniformsSchema };
23 | export { createValue, getTextContents };
24 | export { migrateValue };
25 | 
26 | export { deepEquals };
27 | export default Editor;
28 | 
29 | export const VERSION = '###VERSION###';
30 | 


--------------------------------------------------------------------------------
/packages/editor/src/types.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'color-parse' {
2 |   function parse(color: string): {
3 |     space: 'hsl' | 'rgb';
4 |     values: [number, number, number];
5 |     alpha: number;
6 |   };
7 |   export default parse;
8 | }
9 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/AutoformControls/AutoField.tsx:
--------------------------------------------------------------------------------
1 | import { AutoField } from '../uniform-mui';
2 | 
3 | export default AutoField;
4 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/AutoformControls/AutoFieldContext.tsx:
--------------------------------------------------------------------------------
 1 | import type { FC, PropsWithChildren } from 'react';
 2 | import React from 'react';
 3 | import { AutoField } from '../uniform-mui';
 4 | 
 5 | const AutofieldContextProvider: FC<PropsWithChildren> = ({ children }) => (
 6 |   <AutoField.componentDetectorContext.Provider
 7 |     value={(props, uniforms) => {
 8 |       const show = props.showIf?.(uniforms.model) ?? true;
 9 |       if (!show) return () => null;
10 | 
11 |       // see https://github.com/react-page/react-page/issues/1187
12 |       // we remap props.component to props._customComponent to avoid the underlying issue in uniforms
13 |       if (props._customComponent) {
14 |         return props._customComponent;
15 |       }
16 |       return AutoField.defaultComponentDetector(props, uniforms);
17 |     }}
18 |   >
19 |     {children}
20 |   </AutoField.componentDetectorContext.Provider>
21 | );
22 | 
23 | export default AutofieldContextProvider;
24 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/AutoformControls/AutoFields.tsx:
--------------------------------------------------------------------------------
1 | import { AutoFields } from '../uniform-mui';
2 | 
3 | export default AutoFields;
4 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/AutoformControls/AutoForm.tsx:
--------------------------------------------------------------------------------
 1 | /* eslint-disable @typescript-eslint/no-explicit-any */
 2 | import type { PropsWithChildren, ReactNode } from 'react';
 3 | import React, { forwardRef } from 'react';
 4 | import type { AutoFormProps } from 'uniforms';
 5 | import { AutoForm } from 'uniforms';
 6 | import AutofieldContextProvider from './AutoFieldContext';
 7 | 
 8 | type OptionalFields =
 9 |   | 'autosaveDelay'
10 |   | 'error'
11 |   | 'label'
12 |   | 'noValidate'
13 |   | 'onValidate'
14 |   | 'validate'
15 |   | 'autosave';
16 | type Props = Omit<AutoFormProps<unknown>, OptionalFields> &
17 |   Partial<AutoFormProps<unknown>>;
18 | 
19 | export default forwardRef<any, PropsWithChildren<Props>>(
20 |   (props: Props, ref) => (
21 |     <AutofieldContextProvider>
22 |       <AutoForm {...props} ref={ref as any} />
23 |     </AutofieldContextProvider>
24 |   )
25 | );
26 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/BottomToolbar/MoveActions.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import { MoveLeft, MoveRight, MoveDown, MoveUp } from '../moveButtons';
 3 | const MoveActions: React.FC<{ nodeId: string }> = ({ nodeId }) => {
 4 |   return (
 5 |     <div style={{ transform: 'scale(0.8)' }}>
 6 |       <MoveLeft nodeId={nodeId} />
 7 |       <MoveUp nodeId={nodeId} />
 8 | 
 9 |       <MoveDown nodeId={nodeId} />
10 |       <MoveRight nodeId={nodeId} />
11 |     </div>
12 |   );
13 | };
14 | 
15 | export default MoveActions;
16 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/BottomToolbar/ScaleButton.tsx:
--------------------------------------------------------------------------------
 1 | import { IconButton, Tooltip } from '@mui/material';
 2 | import ScaleIcon from '@mui/icons-material/AspectRatio';
 3 | import React from 'react';
 4 | import { useUiTranslator } from '../../core/components/hooks';
 5 | const SCALING_FACTORS = [1, 0.8, 0.6, 1.2];
 6 | let lastScale = SCALING_FACTORS[0]; // poor mans redux
 7 | 
 8 | export const ScaleButton: React.FC<{
 9 |   scale: number;
10 |   setScale: (s: number) => void;
11 | }> = ({ scale, setScale }) => {
12 |   const { t } = useUiTranslator();
13 |   const toggleScale = React.useCallback(() => {
14 |     const newScalingFactor =
15 |       SCALING_FACTORS[
16 |         (SCALING_FACTORS.indexOf(lastScale ?? scale) + 1) %
17 |           SCALING_FACTORS.length
18 |       ];
19 |     setScale(newScalingFactor);
20 |     // poor man's redux
21 |     lastScale = newScalingFactor;
22 |   }, [scale, lastScale, setScale]);
23 |   return (
24 |     <Tooltip title={t('Change size of this window') ?? ''}>
25 |       <IconButton
26 |         onClick={toggleScale}
27 |         aria-label="Change size of this window"
28 |         color="primary"
29 |       >
30 |         <ScaleIcon />
31 |       </IconButton>
32 |     </Tooltip>
33 |   );
34 | };
35 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/BottomToolbar/types.ts:
--------------------------------------------------------------------------------
 1 | import type { ReactNode } from 'react';
 2 | export type BottomToolbarProps = {
 3 |   open?: boolean;
 4 |   style?: React.CSSProperties;
 5 |   children?: React.ReactNode;
 6 |   className?: string;
 7 | 
 8 |   anchor?: 'top' | 'bottom' | 'left' | 'right';
 9 |   pluginControls?: ReactNode;
10 |   actionsLeft?: ReactNode;
11 | } & BottomToolbarToolsProps;
12 | 
13 | export type BottomToolbarToolsProps = {
14 |   nodeId: string;
15 | };
16 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/ColorPicker/ColorPickerField.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import { connectField } from 'uniforms';
 3 | import ColorPicker from './ColorPicker';
 4 | import { colorToString, stringToColor } from './colorToString';
 5 | import { useUiTranslator } from '../../core/components/hooks';
 6 | 
 7 | const ColorPickerField = connectField<{
 8 |   value: string;
 9 |   label: string;
10 |   onChange: (v: string | void) => void;
11 | }>((props) => {
12 |   const { t } = useUiTranslator();
13 |   return (
14 |     <ColorPicker
15 |       style={{ marginBottom: 8 }}
16 |       color={stringToColor(props.value)}
17 |       buttonContent={t(props.label) ?? ''}
18 |       onChange={(v) => {
19 |         props.onChange(colorToString(v));
20 |       }}
21 |     />
22 |   );
23 | });
24 | 
25 | /**
26 |  * A component that can be used in autoforms (uniforms)
27 |  */
28 | export default ColorPickerField;
29 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/ColorPicker/colorToString.tsx:
--------------------------------------------------------------------------------
 1 | import type { RGBColor } from './types';
 2 | import parse from 'color-parse';
 3 | export const colorToString = (c?: RGBColor | null) =>
 4 |   c ? 'rgba(' + c.r + ', ' + c.g + ', ' + c.b + ', ' + c.a + ')' : undefined;
 5 | 
 6 | export const stringToColor = (c: string) => {
 7 |   const match = parse(c);
 8 | 
 9 |   if (!match || match.space !== 'rgb') return null;
10 |   return {
11 |     r: match.values[0],
12 |     g: match.values[1],
13 |     b: match.values[2],
14 |     a: match.alpha,
15 |   };
16 | };
17 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/ColorPicker/index.tsx:
--------------------------------------------------------------------------------
1 | import lazyLoad from '../../core/helper/lazyLoad';
2 | export const ColorPicker = lazyLoad(() => import('./ColorPicker'));
3 | export const ColorPickerField = lazyLoad(() => import('./ColorPickerField'));
4 | export * from './colorToString';
5 | export * from './types';
6 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/ColorPicker/types.ts:
--------------------------------------------------------------------------------
 1 | import { RGBColor } from 'react-color';
 2 | 
 3 | export interface ColorPickerProps {
 4 |   onChange: (color: RGBColor) => void;
 5 |   onChangeComplete: (color: RGBColor) => void;
 6 |   color?: RGBColor | null;
 7 |   buttonContent?: JSX.Element | string;
 8 |   icon?: JSX.Element | string;
 9 |   onDialogOpen?: () => void;
10 |   style?: React.CSSProperties;
11 | }
12 | 
13 | export type ColorPickerState = {
14 |   isColorPickerVisible: boolean;
15 | };
16 | 
17 | export { RGBColor };
18 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/DuplicateButton/index.tsx:
--------------------------------------------------------------------------------
 1 | import { IconButton, Tooltip } from '@mui/material';
 2 | import Icon from '@mui/icons-material/FileCopy';
 3 | import React from 'react';
 4 | import { useDuplicateCell, useUiTranslator } from '../../core/components/hooks';
 5 | 
 6 | export const DuplicateButton: React.FC<{ nodeId: string }> = React.memo(
 7 |   ({ nodeId }) => {
 8 |     const duplicateCell = useDuplicateCell(nodeId);
 9 |     const { t } = useUiTranslator();
10 |     return (
11 |       <Tooltip title={t('Duplicate Plugin') ?? ''}>
12 |         <IconButton onClick={duplicateCell} aria-label="delete" color="default">
13 |           <Icon />
14 |         </IconButton>
15 |       </Tooltip>
16 |     );
17 |   }
18 | );
19 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/EditorUI/index.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | 
 3 | import { PluginDrawer } from '../PluginDrawer';
 4 | import { Trash } from '../Trash';
 5 | import type { StickyNess } from '../Sidebar';
 6 | import { Sidebar } from '../Sidebar';
 7 | import { useOption } from '../../core/components/hooks';
 8 | import { MultiNodesBottomToolbar } from '../MultiNodesBottomToolbar';
 9 | 
10 | export default React.memo(
11 |   ({
12 |     stickyNess = {
13 |       shouldStickToTop: false,
14 |       shouldStickToBottom: false,
15 |       rightOffset: 0,
16 |       rightOffsetFixed: 0,
17 |     },
18 |   }: {
19 |     stickyNess?: StickyNess;
20 |   }) => {
21 |     const hideEditorSidebar = useOption('hideEditorSidebar');
22 |     return (
23 |       <>
24 |         <Trash />
25 |         {!hideEditorSidebar && <Sidebar stickyNess={stickyNess} />}
26 |         <PluginDrawer />
27 |         <MultiNodesBottomToolbar />
28 |       </>
29 |     );
30 |   }
31 | );
32 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/I18nTools/SelectLang.tsx:
--------------------------------------------------------------------------------
 1 | import { Select, MenuItem } from '@mui/material';
 2 | import React, { memo } from 'react';
 3 | import { useLang, useOption, useSetLang } from '../../core/components/hooks';
 4 | 
 5 | const SelectLang = () => {
 6 |   const languages = useOption('languages');
 7 |   const lang = useLang();
 8 |   const setLang = useSetLang();
 9 |   if (languages && languages?.length > 0) {
10 |     return (
11 |       <Select
12 |         variant="standard"
13 |         value={lang || ''}
14 |         onChange={(e) => setLang(e.target.value as string)}
15 |       >
16 |         {languages.map((l) => (
17 |           <MenuItem key={l.lang} value={l.lang}>
18 |             {l.label}
19 |           </MenuItem>
20 |         ))}
21 |       </Select>
22 |     );
23 |   }
24 |   return null;
25 | };
26 | 
27 | export default memo(SelectLang);
28 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/I18nTools/index.tsx:
--------------------------------------------------------------------------------
 1 | import { IconButton, Dialog } from '@mui/material';
 2 | import Translate from '@mui/icons-material/Translate';
 3 | 
 4 | import React, { useState } from 'react';
 5 | import SelectLang from './SelectLang';
 6 | import I18nDialog from './I18nDialog';
 7 | import { useOption } from '../../core/components/hooks';
 8 | 
 9 | export const I18nTools: React.FC<{
10 |   nodeId: string;
11 | }> = React.memo(({ nodeId }) => {
12 |   const languages = useOption('languages');
13 | 
14 |   const [showI18nDialog, setShowI18nDialog] = useState(false);
15 |   const hasI18n = languages && languages?.length > 0;
16 |   const onClose = () => setShowI18nDialog(false);
17 |   if (!hasI18n) {
18 |     return null;
19 |   }
20 | 
21 |   return (
22 |     <>
23 |       <Dialog open={showI18nDialog} onClose={onClose}>
24 |         <I18nDialog nodeId={nodeId} onClose={onClose} />
25 |       </Dialog>
26 | 
27 |       <div style={{ display: 'flex', alignItems: 'center' }}>
28 |         <IconButton
29 |           onClick={() => setShowI18nDialog(true)}
30 |           aria-label="i18n"
31 |           color="secondary"
32 |         >
33 |           <Translate />
34 |         </IconButton>
35 | 
36 |         <SelectLang />
37 |       </div>
38 |     </>
39 |   );
40 | });
41 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/ImageUpload/defaultTranslations.tsx:
--------------------------------------------------------------------------------
1 | export const defaultTranslations = {
2 |   buttonContent: 'Upload image',
3 |   noFileError: 'No file selected',
4 |   badExtensionError: 'Bad file type',
5 |   tooBigError: 'Too big',
6 |   uploadingError: 'Error while uploading',
7 |   unknownError: 'Unknown error',
8 | };
9 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/ImageUpload/index.tsx:
--------------------------------------------------------------------------------
1 | import lazyLoad from '../../core/helper/lazyLoad';
2 | 
3 | export * from './types';
4 | 
5 | export const ImageUpload = lazyLoad(() => import('./ImageUpload'));
6 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/ImageUpload/types.tsx:
--------------------------------------------------------------------------------
 1 | export type ImageLoaded = {
 2 |   file: File;
 3 |   dataUrl: string;
 4 | };
 5 | 
 6 | export type ImageUploaded = {
 7 |   url: string;
 8 | };
 9 | export type ImageUploadType = (
10 |   file: File,
11 |   reportProgress: (progress: number) => void
12 | ) => Promise<ImageUploaded>;
13 | 
14 | export type ImageUploadProps = {
15 |   imageLoaded?: (image: ImageLoaded) => void;
16 |   imageUpload: ImageUploadType;
17 |   imageUploadError?: (errorCode: number) => void;
18 |   imageUploaded: (resp: ImageUploaded) => void;
19 |   icon?: JSX.Element;
20 |   style?: React.CSSProperties;
21 |   maxFileSize?: number;
22 |   allowedExtensions?: string[];
23 |   translations?: { [key: string]: string };
24 | };
25 | 
26 | export type ImageUploadState = {
27 |   isUploading: boolean;
28 |   hasError: boolean;
29 |   errorText: string | null;
30 |   progress?: number;
31 | };
32 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/MultiNodesBottomToolbar/DeleteAll.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import { IconButton, Tooltip } from '@mui/material';
 3 | import Delete from '@mui/icons-material/Delete';
 4 | import {
 5 |   useAllFocusedNodeIds,
 6 |   useRemoveMultipleNodeIds,
 7 |   useUiTranslator,
 8 | } from '../../core/components/hooks';
 9 | 
10 | const DeleteAll: React.FC = () => {
11 |   const remove = useRemoveMultipleNodeIds();
12 |   const focused = useAllFocusedNodeIds();
13 |   const { t } = useUiTranslator();
14 |   return (
15 |     <Tooltip title={t('Remove all selected') ?? ''}>
16 |       <IconButton
17 |         onClick={() => remove(focused)}
18 |         aria-label="delete"
19 |         color="secondary"
20 |       >
21 |         <Delete />
22 |       </IconButton>
23 |     </Tooltip>
24 |   );
25 | };
26 | 
27 | export default DeleteAll;
28 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/MultiNodesBottomToolbar/DuplicateAll.tsx:
--------------------------------------------------------------------------------
 1 | import { IconButton, Tooltip } from '@mui/material';
 2 | import React from 'react';
 3 | import {
 4 |   useAllFocusedNodeIds,
 5 |   useDuplicateMultipleCells,
 6 |   useUiTranslator,
 7 | } from '../../core/components/hooks';
 8 | import Icon from '@mui/icons-material/FileCopy';
 9 | 
10 | const DuplicateAll: React.FC = () => {
11 |   const duplicate = useDuplicateMultipleCells();
12 |   const { t } = useUiTranslator();
13 |   const nodeIds = useAllFocusedNodeIds();
14 |   return (
15 |     <Tooltip title={t('Duplicate al') ?? ''}>
16 |       <IconButton
17 |         onClick={() => duplicate(nodeIds)}
18 |         aria-label="delete"
19 |         color="default"
20 |       >
21 |         <Icon />
22 |       </IconButton>
23 |     </Tooltip>
24 |   );
25 | };
26 | 
27 | export default DuplicateAll;
28 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/PluginDrawer/Item/index.css:
--------------------------------------------------------------------------------
 1 | .react-page-plugin-drawer-item {
 2 |   cursor: pointer;
 3 | 
 4 |   z-index: 1;
 5 | }
 6 | .react-page-plugin-drawer-item:hover {
 7 |   z-index: 2;
 8 |   box-shadow: 0 0 20px #ccc;
 9 | }
10 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/PluginDrawer/index.css:
--------------------------------------------------------------------------------
1 | @import 'Item/index.css';
2 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/SelectParentButton/index.tsx:
--------------------------------------------------------------------------------
 1 | import IconButton from '@mui/material/IconButton';
 2 | import VerticalAlignTopIcon from '@mui/icons-material/VerticalAlignTop';
 3 | 
 4 | import React from 'react';
 5 | import {
 6 |   useFocusCell,
 7 |   useParentCellId,
 8 |   useUiTranslator,
 9 | } from '../../core/components/hooks';
10 | 
11 | export const SelectParentButton: React.FC<{
12 |   nodeId: string;
13 | }> = React.memo(({ nodeId }) => {
14 |   const parentCellId = useParentCellId(nodeId);
15 |   const { t } = useUiTranslator();
16 |   const focusParent = useFocusCell(parentCellId);
17 | 
18 |   return parentCellId ? (
19 |     <IconButton
20 |       className="bottomToolbar__selectParentButton"
21 |       onClick={() => focusParent()}
22 |       color="default"
23 |       title={t('Select parent') ?? ''}
24 |     >
25 |       <VerticalAlignTopIcon />
26 |     </IconButton>
27 |   ) : null;
28 | });
29 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/Sidebar/Button/index.css:
--------------------------------------------------------------------------------
 1 | .react-page-controls-mode-toggle-button-inner {
 2 |   float: right;
 3 |   margin: 8px;
 4 | }
 5 | 
 6 | .react-page-controls-mode-toggle-button-description {
 7 |   font-family: Roboto, sans-serif;
 8 |   font-size: 16px;
 9 |   margin-top: 18px;
10 |   float: right;
11 |   background: transparent;
12 |   color: transparent;
13 |   border: 1px transparent solid;
14 |   padding: 2px 8px;
15 |   text-align: right;
16 |   display: none;
17 |   transition: all 200ms ease;
18 |   white-space: nowrap;
19 |   overflow: hidden;
20 | }
21 | 
22 | .react-page-controls-mode-toggle-button:hover
23 |   .react-page-controls-mode-toggle-button-description {
24 |   max-width: 999px;
25 |   background: var(--darkBlack);
26 |   color: var(--white);
27 |   display: block;
28 |   border: 1px solid var(--faintBlack);
29 | }
30 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/Sidebar/ToggleEdit/index.tsx:
--------------------------------------------------------------------------------
 1 | import Create from '@mui/icons-material/Create';
 2 | 
 3 | import React from 'react';
 4 | import { useIsEditMode, useSetEditMode } from '../../../core/components/hooks';
 5 | import Button from '../Button/index';
 6 | 
 7 | type Props = {
 8 |   label: string;
 9 | };
10 | 
11 | const ToggleEdit: React.FC<Props> = ({ label }) => {
12 |   const isEditMode = useIsEditMode();
13 |   const setEditMode = useSetEditMode();
14 |   return (
15 |     <Button
16 |       icon={<Create />}
17 |       description={label}
18 |       active={isEditMode}
19 |       onClick={setEditMode}
20 |     />
21 |   );
22 | };
23 | 
24 | export default React.memo(ToggleEdit);
25 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/Sidebar/ToggleInsert/index.tsx:
--------------------------------------------------------------------------------
 1 | import ContentAdd from '@mui/icons-material/Add';
 2 | import React from 'react';
 3 | import {
 4 |   useIsInsertMode,
 5 |   useSetInsertMode,
 6 | } from '../../../core/components/hooks';
 7 | import Button from '../Button/index';
 8 | 
 9 | type Props = {
10 |   label: string;
11 | };
12 | const ToggleInsert: React.FC<Props> = ({ label }) => {
13 |   const isInsertMode = useIsInsertMode();
14 |   const setInsertMode = useSetInsertMode();
15 |   return (
16 |     <Button
17 |       icon={<ContentAdd />}
18 |       description={label}
19 |       active={isInsertMode}
20 |       onClick={setInsertMode}
21 |     />
22 |   );
23 | };
24 | 
25 | export default React.memo(ToggleInsert);
26 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/Sidebar/ToggleLayout/index.tsx:
--------------------------------------------------------------------------------
 1 | import ViewQuilt from '@mui/icons-material/ViewQuilt';
 2 | import React from 'react';
 3 | import {
 4 |   useIsLayoutMode,
 5 |   useSetLayoutMode,
 6 | } from '../../../core/components/hooks';
 7 | import Button from '../Button';
 8 | type Props = {
 9 |   label: string;
10 | };
11 | 
12 | const ToggleLayout: React.FC<Props> = ({ label }) => {
13 |   const isLayoutMode = useIsLayoutMode();
14 |   const setLayoutMode = useSetLayoutMode();
15 |   return (
16 |     <Button
17 |       icon={<ViewQuilt />}
18 |       description={label}
19 |       active={isLayoutMode}
20 |       onClick={setLayoutMode}
21 |     />
22 |   );
23 | };
24 | 
25 | export default React.memo(ToggleLayout);
26 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/Sidebar/TogglePreview/index.tsx:
--------------------------------------------------------------------------------
 1 | import Devices from '@mui/icons-material/Devices';
 2 | import React from 'react';
 3 | import {
 4 |   useIsPreviewMode,
 5 |   useSetPreviewMode,
 6 | } from '../../../core/components/hooks';
 7 | import Button from '../Button/index';
 8 | 
 9 | type Props = {
10 |   label: string;
11 | };
12 | const TogglePreview: React.FC<Props> = ({ label }) => {
13 |   const isPreviewMode = useIsPreviewMode();
14 |   const setIsPreviewMode = useSetPreviewMode();
15 |   return (
16 |     <Button
17 |       icon={<Devices />}
18 |       description={label}
19 |       active={isPreviewMode}
20 |       onClick={setIsPreviewMode}
21 |     />
22 |   );
23 | };
24 | 
25 | export default React.memo(TogglePreview);
26 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/Sidebar/ToggleResize/index.tsx:
--------------------------------------------------------------------------------
 1 | import Resize from '@mui/icons-material/SettingsOverscan';
 2 | import React from 'react';
 3 | import {
 4 |   useIsResizeMode,
 5 |   useSetResizeMode,
 6 | } from '../../../core/components/hooks';
 7 | import Button from '../Button/index';
 8 | 
 9 | type Props = {
10 |   label: string;
11 | };
12 | 
13 | const ToggleResize: React.FC<Props> = (props) => {
14 |   const isResizeMode = useIsResizeMode();
15 |   const setResizeMode = useSetResizeMode();
16 |   return (
17 |     <Button
18 |       icon={<Resize />}
19 |       description={props.label}
20 |       active={isResizeMode}
21 |       onClick={setResizeMode}
22 |     />
23 |   );
24 | };
25 | 
26 | export default React.memo(ToggleResize);
27 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/Sidebar/index.css:
--------------------------------------------------------------------------------
 1 | @import 'Button/index.css';
 2 | 
 3 | .react-page-controls-mode-toggle-clearfix {
 4 |   clear: both;
 5 | }
 6 | 
 7 | @keyframes fadeIn {
 8 |   0% {
 9 |    opacity: 0;
10 |    transform: scale(0);
11 |   }
12 |   80% {
13 |     opacity: 1;
14 |     transform: scale(1.05);
15 |   }
16 |   100% {
17 |     opacity: 1;
18 |     transform: scale(1);
19 |   }
20 | }
21 | 
22 | .react-page-controls-mode-toggle-control {
23 |   z-index: 1;
24 |   animation: fadeIn 0.8s forwards;
25 |   opacity: 0;
26 | 
27 | }
28 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/Trash/index.css:
--------------------------------------------------------------------------------
 1 | .react-page-controls-trash {
 2 |   position: fixed;
 3 |   bottom: -64px;
 4 |   z-index: 500;
 5 |   left: 50%;
 6 |   transition: bottom 200ms ease;
 7 |   padding: 8px;
 8 | }
 9 | 
10 | .react-page-controls-trash.react-page-controls-trash-active {
11 |   bottom: 16px;
12 | }
13 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/Trash/index.tsx:
--------------------------------------------------------------------------------
 1 | import Fab from '@mui/material/Fab';
 2 | import Delete from '@mui/icons-material/Delete';
 3 | import classNames from 'classnames';
 4 | import React from 'react';
 5 | import { useIsLayoutMode, useTrashDrop } from '../../core/components/hooks';
 6 | 
 7 | export const Trash: React.FC = React.memo(() => {
 8 |   const isLayoutMode = useIsLayoutMode();
 9 |   const [{ isHovering }, ref] = useTrashDrop();
10 |   return (
11 |     <div
12 |       ref={ref}
13 |       className={classNames('react-page-controls-trash', {
14 |         'react-page-controls-trash-active': isLayoutMode,
15 |       })}
16 |     >
17 |       <Fab color="secondary" disabled={!isHovering}>
18 |         <Delete />
19 |       </Fab>
20 |     </div>
21 |   );
22 | });
23 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/defaultTheme/index.ts:
--------------------------------------------------------------------------------
 1 | import type { ThemeOptions } from '@mui/material';
 2 | import { createTheme } from '@mui/material';
 3 | 
 4 | export const defaultThemeOptions: ThemeOptions = {
 5 |   components: {
 6 |     MuiTextField: {
 7 |       defaultProps: {
 8 |         variant: 'standard',
 9 |       },
10 |     },
11 |   },
12 | };
13 | 
14 | export const defaultTheme = createTheme(defaultThemeOptions);
15 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/index.css:
--------------------------------------------------------------------------------
1 | @import 'Sidebar/index.css';
2 | @import 'PluginDrawer/index.css';
3 | @import 'Trash/index.css';
4 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/index.tsx:
--------------------------------------------------------------------------------
 1 | // re-exports for customization
 2 | // TODO: add more if required
 3 | export * from './BottomToolbar';
 4 | export * from './AutoformControls';
 5 | 
 6 | export * from './I18nTools';
 7 | export * from './DuplicateButton';
 8 | export * from './Trash';
 9 | export * from './ImageUpload';
10 | export * from './SelectParentButton';
11 | export * from './PluginDrawer';
12 | 
13 | export * from './ColorPicker';
14 | export * from './Sidebar';
15 | 
16 | export * from './defaultTheme';
17 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/AutoField.tsx:
--------------------------------------------------------------------------------
 1 | import invariant from 'invariant';
 2 | import { createAutoField } from 'uniforms';
 3 | export { AutoFieldProps } from 'uniforms';
 4 | 
 5 | import BoolField from './BoolField';
 6 | import DateField from './DateField';
 7 | import ListField from './ListField';
 8 | import NestField from './NestField';
 9 | import NumField from './NumField';
10 | import RadioField from './RadioField';
11 | import SelectField from './SelectField';
12 | import TextField from './TextField';
13 | 
14 | const AutoField = createAutoField((props) => {
15 |   if (props.allowedValues) {
16 |     return props.checkboxes && props.fieldType !== Array
17 |       ? RadioField
18 |       : SelectField;
19 |   }
20 | 
21 |   switch (props.fieldType) {
22 |     case Array:
23 |       return ListField;
24 |     case Boolean:
25 |       return BoolField;
26 |     case Date:
27 |       return DateField;
28 |     case Number:
29 |       return NumField;
30 |     case Object:
31 |       return NestField;
32 |     case String:
33 |       return TextField;
34 |   }
35 | 
36 |   return invariant(false, 'Unsupported field type: %s', props.fieldType);
37 | });
38 | 
39 | export default AutoField;
40 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/AutoFields.tsx:
--------------------------------------------------------------------------------
 1 | import type { ComponentType } from 'react';
 2 | import { createElement } from 'react';
 3 | import { useForm } from 'uniforms';
 4 | 
 5 | import AutoField from './AutoField';
 6 | 
 7 | export type AutoFieldsProps = {
 8 |   autoField?: ComponentType<{ name: string }>;
 9 |   element?: ComponentType | string;
10 |   fields?: string[];
11 |   omitFields?: string[];
12 |   showInlineError?: boolean;
13 | };
14 | 
15 | export default function AutoFields({
16 |   autoField = AutoField,
17 |   element = 'div',
18 |   fields,
19 |   omitFields = [],
20 |   showInlineError,
21 |   ...props
22 | }: AutoFieldsProps) {
23 |   const { schema } = useForm();
24 | 
25 |   return createElement(
26 |     element,
27 |     props,
28 |     (fields ?? schema.getSubfields())
29 |       .filter((field) => !omitFields.includes(field))
30 |       .map((field) =>
31 |         createElement(
32 |           autoField,
33 |           Object.assign(
34 |             { key: field, name: field },
35 |             showInlineError === undefined ? null : { showInlineError }
36 |           )
37 |         )
38 |       )
39 |   );
40 | }
41 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/ErrorField.tsx:
--------------------------------------------------------------------------------
 1 | import FormControl from '@mui/material/FormControl';
 2 | import type { FormHelperTextProps } from '@mui/material/FormHelperText';
 3 | import FormHelperText from '@mui/material/FormHelperText';
 4 | import React from 'react';
 5 | import type { Override } from 'uniforms';
 6 | import { connectField, filterDOMProps } from 'uniforms';
 7 | 
 8 | export type ErrorFieldProps = Override<
 9 |   FormHelperTextProps,
10 |   {
11 |     errorMessage?: string;
12 |     fullWidth?: boolean;
13 |     margin?: 'dense' | 'normal' | 'none';
14 |   }
15 | >;
16 | 
17 | function Error({
18 |   children,
19 |   error,
20 |   errorMessage,
21 |   fullWidth,
22 |   margin,
23 |   variant,
24 |   ...props
25 | }: ErrorFieldProps) {
26 |   return !error ? null : (
27 |     <FormControl
28 |       error={!!error}
29 |       fullWidth={!!fullWidth}
30 |       margin={margin === 'dense' ? margin : undefined}
31 |       variant={variant}
32 |     >
33 |       <FormHelperText {...filterDOMProps(props)}>
34 |         {children || errorMessage}
35 |       </FormHelperText>
36 |     </FormControl>
37 |   );
38 | }
39 | 
40 | export default connectField<ErrorFieldProps>(Error, {
41 |   initialValue: false,
42 |   kind: 'leaf',
43 | });
44 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/HiddenField.tsx:
--------------------------------------------------------------------------------
 1 | import type { HTMLProps, Ref } from 'react';
 2 | import React, { useEffect } from 'react';
 3 | import type { Override } from 'uniforms';
 4 | import { filterDOMProps, useField } from 'uniforms';
 5 | 
 6 | export type HiddenFieldProps = Override<
 7 |   HTMLProps<HTMLInputElement>,
 8 |   {
 9 |     inputRef?: Ref<HTMLInputElement>;
10 |     name: string;
11 |     noDOM?: boolean;
12 |     value?: any;
13 |   }
14 | >;
15 | 
16 | export default function HiddenField({ value, ...rawProps }: HiddenFieldProps) {
17 |   const props = useField(rawProps.name, rawProps, { initialValue: false })[0];
18 | 
19 |   useEffect(() => {
20 |     if (value !== undefined && value !== props.value) {
21 |       props.onChange(value);
22 |     }
23 |   });
24 | 
25 |   return props.noDOM ? null : (
26 |     <input
27 |       disabled={props.disabled}
28 |       name={props.name}
29 |       readOnly={props.readOnly}
30 |       ref={props.inputRef}
31 |       type="hidden"
32 |       value={value ?? props.value ?? ''}
33 |       {...filterDOMProps(props)}
34 |     />
35 |   );
36 | }
37 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/LongTextField.tsx:
--------------------------------------------------------------------------------
 1 | import type { TextFieldProps } from '@mui/material/TextField';
 2 | import TextField from '@mui/material/TextField';
 3 | import React from 'react';
 4 | import type { FieldProps } from 'uniforms';
 5 | import { connectField, filterDOMProps } from 'uniforms';
 6 | 
 7 | export type LongTextFieldProps = FieldProps<string, TextFieldProps>;
 8 | 
 9 | const LongText = ({
10 |   disabled,
11 |   error,
12 |   errorMessage,
13 |   helperText,
14 |   inputRef,
15 |   label,
16 |   name,
17 |   onChange,
18 |   placeholder,
19 |   readOnly,
20 |   showInlineError,
21 |   type = 'text',
22 |   value,
23 |   ...props
24 | }: LongTextFieldProps) => {
25 |   return (
26 |     <TextField
27 |       disabled={disabled}
28 |       error={!!error}
29 |       fullWidth
30 |       helperText={(error && showInlineError && errorMessage) || helperText}
31 |       inputProps={{ readOnly }}
32 |       label={label}
33 |       margin="dense"
34 |       multiline
35 |       name={name}
36 |       onChange={(event) => disabled || onChange(event.target.value)}
37 |       placeholder={placeholder}
38 |       ref={inputRef}
39 |       type={type}
40 |       value={value ?? ''}
41 |       {...filterDOMProps(props)}
42 |     />
43 |   );
44 | };
45 | 
46 | export default connectField<LongTextFieldProps>(LongText, { kind: 'leaf' });
47 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/NestField.tsx:
--------------------------------------------------------------------------------
 1 | import FormLabel from '@mui/material/FormLabel';
 2 | import React from 'react';
 3 | import type { HTMLFieldProps } from 'uniforms';
 4 | import { connectField } from 'uniforms';
 5 | 
 6 | import AutoField from './AutoField';
 7 | import wrapField from './wrapField';
 8 | 
 9 | // FIXME: wrapField is not typed correctly.
10 | export type NestFieldProps = HTMLFieldProps<
11 |   Record<string, any>,
12 |   HTMLDivElement,
13 |   {
14 |     helperText?: string;
15 |     itemProps?: Record<string, any>;
16 |     fullWidth?: boolean;
17 |     margin?: any;
18 |   }
19 | >;
20 | 
21 | function Nest({
22 |   children,
23 |   fields,
24 |   fullWidth = true,
25 |   itemProps,
26 |   label,
27 |   margin = 'dense',
28 |   ...props
29 | }: NestFieldProps) {
30 |   return wrapField(
31 |     {
32 |       fullWidth,
33 |       margin,
34 |       ...props,
35 |       component: undefined,
36 |     },
37 |     label && <FormLabel component="legend">{label}</FormLabel>,
38 |     children ||
39 |       fields.map((field) => (
40 |         <AutoField key={field} name={field} {...itemProps} />
41 |       ))
42 |   );
43 | }
44 | 
45 | export default connectField<NestFieldProps>(Nest);
46 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/README.md:
--------------------------------------------------------------------------------
1 | until https://github.com/vazco/uniforms/pull/1091 is merged
2 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/SubmitField.tsx:
--------------------------------------------------------------------------------
 1 | import type { ButtonProps } from '@mui/material/Button';
 2 | import Button from '@mui/material/Button';
 3 | import type { ReactNode, Ref } from 'react';
 4 | import React from 'react';
 5 | import type { Override } from 'uniforms';
 6 | import { filterDOMProps, useForm } from 'uniforms';
 7 | 
 8 | export type SubmitFieldProps = Override<
 9 |   ButtonProps,
10 |   // FIXME: What kind of `ref` is it?
11 |   { inputRef?: Ref<any>; label?: ReactNode }
12 | >;
13 | 
14 | function SubmitField({
15 |   children,
16 |   disabled,
17 |   inputRef,
18 |   label = 'Submit',
19 |   value,
20 |   ...props
21 | }: SubmitFieldProps) {
22 |   const { error, state } = useForm();
23 | 
24 |   return (
25 |     <Button
26 |       disabled={disabled === undefined ? !!(error || state.disabled) : disabled}
27 |       ref={inputRef}
28 |       type="submit"
29 |       value={value}
30 |       variant="contained"
31 |       {...filterDOMProps(props)}
32 |     >
33 |       {children || label}
34 |     </Button>
35 |   );
36 | }
37 | 
38 | export default SubmitField;
39 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/TextField.tsx:
--------------------------------------------------------------------------------
 1 | import type { TextFieldProps as MUITextFieldProps } from '@mui/material/TextField';
 2 | import TextField from '@mui/material/TextField';
 3 | import React from 'react';
 4 | import type { FieldProps } from 'uniforms';
 5 | import { connectField, filterDOMProps } from 'uniforms';
 6 | 
 7 | export type TextFieldProps = FieldProps<string, MUITextFieldProps>;
 8 | 
 9 | function Text({
10 |   disabled,
11 |   error,
12 |   errorMessage,
13 |   helperText,
14 |   inputRef,
15 |   label,
16 |   name,
17 |   onChange,
18 |   placeholder,
19 |   readOnly,
20 |   showInlineError,
21 |   type = 'text',
22 |   value = '',
23 |   ...props
24 | }: TextFieldProps) {
25 |   return (
26 |     <TextField
27 |       disabled={disabled}
28 |       error={!!error}
29 |       fullWidth
30 |       helperText={(error && showInlineError && errorMessage) || helperText}
31 |       inputProps={{ readOnly }}
32 |       label={label}
33 |       margin="dense"
34 |       name={name}
35 |       onChange={(event) => disabled || onChange(event.target.value)}
36 |       placeholder={placeholder}
37 |       ref={inputRef}
38 |       type={type}
39 |       value={value}
40 |       {...filterDOMProps(props)}
41 |     />
42 |   );
43 | }
44 | 
45 | export default connectField<TextFieldProps>(Text, { kind: 'leaf' });
46 | 


--------------------------------------------------------------------------------
/packages/editor/src/ui/uniform-mui/wrapField.tsx:
--------------------------------------------------------------------------------
 1 | import FormControl from '@mui/material/FormControl';
 2 | import FormHelperText from '@mui/material/FormHelperText';
 3 | import type { ReactNode } from 'react';
 4 | import React, { createElement } from 'react';
 5 | 
 6 | export default function wrapField(
 7 |   {
 8 |     component,
 9 |     disabled,
10 |     error,
11 |     errorMessage,
12 |     fullWidth,
13 |     helperText,
14 |     margin,
15 |     readOnly,
16 |     required,
17 |     showInlineError,
18 |     variant,
19 |   }: any,
20 |   ...children: ReactNode[]
21 | ) {
22 |   const formHelperText = showInlineError && error ? errorMessage : helperText;
23 |   const props = {
24 |     component,
25 |     disabled: !!disabled,
26 |     error: !!error,
27 |     fullWidth: !!fullWidth,
28 |     margin,
29 |     readOnly,
30 |     required,
31 |     variant,
32 |   };
33 | 
34 |   return createElement(
35 |     FormControl,
36 |     props,
37 |     ...children,
38 |     !!formHelperText && <FormHelperText>{formHelperText}</FormHelperText>
39 |   );
40 | }
41 | 


--------------------------------------------------------------------------------
/packages/editor/src/variables.css:
--------------------------------------------------------------------------------
 1 | :root {
 2 |     --black: #000000;
 3 |     --white: #ffffff;
 4 |     --transparent: rgba(0, 0, 0, 0);
 5 |     --fullBlack: rgba(0, 0, 0, 1);
 6 |     --darkBlack: rgba(0, 0, 0, 0.87);
 7 |     --lightBlack: rgba(0, 0, 0, 0.54);
 8 |     --minBlack: rgba(0, 0, 0, 0.26);
 9 |     --faintBlack: rgba(0, 0, 0, 0.12);
10 |     --fullWhite: rgba(255, 255, 255, 1);
11 |     --darkWhite: rgba(255, 255, 255, 0.87);
12 |     --lightWhite: rgba(255, 255, 255, 0.54);
13 |     --minWhite: rgba(255, 255, 255, 0.26);
14 |     --faintWhite: rgba(255, 255, 255, 0.12);
15 |     --grey300: #e0e0e0;
16 |     --grey900: #212121;
17 | }


--------------------------------------------------------------------------------
/packages/editor/src/wdyr.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | 
3 | if (process.env.NODE_ENV === 'development') {
4 |   const whyDidYouRender = require('@welldone-software/why-did-you-render');
5 |   whyDidYouRender(React, {
6 |     trackAllPureComponents: true,
7 |   });
8 | }
9 | 


--------------------------------------------------------------------------------
/packages/editor/tsconfig-es.json:
--------------------------------------------------------------------------------
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "lib-es",
5 |     "module": "esNext"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/editor/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "../tsconfig.settings.json",
 3 |   "compilerOptions": {
 4 |     "rootDir": "src",
 5 |     "outDir": "lib"
 6 |   },
 7 |   "include": ["src"],
 8 |   "exclude": ["lib", "node_modules", "src/**/__tests__/**/*.*"]
 9 | }
10 | 


--------------------------------------------------------------------------------
/packages/index.d.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/react-page/react-page/3bb72bd52ce0857a8f4a6ca1f15d4ce2242c89d5/packages/index.d.ts


--------------------------------------------------------------------------------
/packages/plugins/README.md:
--------------------------------------------------------------------------------
1 | # ORY Editor Plugins
2 | 
3 | This directory contains various plugins for the ORY Editor which are maintained by ORY.
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/.npmignore:
--------------------------------------------------------------------------------
1 | src/**/*


--------------------------------------------------------------------------------
/packages/plugins/content/divider/babel.config.js:
--------------------------------------------------------------------------------
1 | const vendor = require('../../../../babel.config.js');
2 | module.exports = Object.assign({}, vendor);
3 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/src/Renderer/DividerHtmlRenderer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | 
3 | const DividerHtmlRenderer: React.FC = () => {
4 |   return <hr className="react-page-plugins-content-divider" />;
5 | };
6 | 
7 | export default DividerHtmlRenderer;
8 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/src/createPlugin.tsx:
--------------------------------------------------------------------------------
 1 | import type { CellPlugin } from '@react-page/editor';
 2 | import { lazyLoad } from '@react-page/editor';
 3 | import React from 'react';
 4 | import { defaultSettings } from './default/settings';
 5 | import DividerHtmlRenderer from './Renderer/DividerHtmlRenderer';
 6 | 
 7 | import type { DividerSettings } from './types/settings';
 8 | 
 9 | const Remove = lazyLoad(() => import('@mui/icons-material/Remove'));
10 | 
11 | const createPlugin: (settings: DividerSettings) => CellPlugin = (settings) => {
12 |   const mergedSettings = { ...defaultSettings, ...settings };
13 |   return {
14 |     Renderer: settings.Renderer || DividerHtmlRenderer,
15 |     id: 'ory/editor/core/content/divider',
16 |     version: 1,
17 |     icon: <Remove />,
18 |     title: mergedSettings.translations?.pluginName,
19 |     description: mergedSettings.translations?.pluginDescription,
20 |   };
21 | };
22 | 
23 | export default createPlugin;
24 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/src/default/settings.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | 
 3 | export const defaultTranslations = {
 4 |   pluginName: 'Divider',
 5 |   pluginDescription: 'A horizontal divider',
 6 | };
 7 | 
 8 | export const defaultSettings = {
 9 |   translations: defaultTranslations,
10 |   Renderer: () => <>Renderer for this plugin was not provided</>,
11 | };
12 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/src/index.css:
--------------------------------------------------------------------------------
1 | .react-page-plugins-content-divider {
2 |   background-color: #eee;
3 |   width: 100%;
4 |   height: 2px;
5 |   border-color: #eee;
6 | }
7 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/src/index.ts:
--------------------------------------------------------------------------------
1 | import createPlugin from './createPlugin';
2 | import DividerHtmlRenderer from './Renderer/DividerHtmlRenderer';
3 | 
4 | const plugin = createPlugin({
5 |   Renderer: DividerHtmlRenderer,
6 | });
7 | 
8 | export default plugin;
9 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/src/types/settings.ts:
--------------------------------------------------------------------------------
1 | import type { CellPluginComponentProps } from '@react-page/editor';
2 | import type { Translations } from './translations';
3 | 
4 | export interface DividerSettings {
5 |   Renderer: React.ComponentType<CellPluginComponentProps>;
6 |   translations?: Translations;
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/src/types/translations.ts:
--------------------------------------------------------------------------------
1 | import type { defaultTranslations } from '../default/settings';
2 | 
3 | export type Translations = typeof defaultTranslations;
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/tsconfig-es.json:
--------------------------------------------------------------------------------
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "lib-es",
5 |     "module": "esnext"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/plugins/content/divider/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "../../../tsconfig.settings.json",
 3 |   "compilerOptions": {
 4 |     "rootDir": "src",
 5 |     "outDir": "lib"
 6 |   },
 7 |   "include": ["src"],
 8 |   "exclude": ["lib", "node_modules", "src/**/__tests__/**/*.*"],
 9 |   "references": [{ "path": "../../../editor" }]
10 | }
11 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/.npmignore:
--------------------------------------------------------------------------------
1 | src/**/*


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/babel.config.js:
--------------------------------------------------------------------------------
1 | const vendor = require('../../../../babel.config.js');
2 | module.exports = Object.assign({}, vendor);
3 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/src/Renderer/Html5VideoHtmlRenderer.tsx:
--------------------------------------------------------------------------------
 1 | import type { CellPluginComponentProps } from '@react-page/editor';
 2 | import React from 'react';
 3 | import { defaultHtml5VideoState } from '../default/state';
 4 | import type { Html5VideoState } from '../types/state';
 5 | 
 6 | const Html5VideoHtmlRenderer: React.FC<
 7 |   CellPluginComponentProps<Html5VideoState>
 8 | > = ({ data = defaultHtml5VideoState }) => {
 9 |   return (
10 |     <div className="react-page-content-plugin-html5-video">
11 |       <video
12 |         autoPlay={true}
13 |         controls={true}
14 |         loop={true}
15 |         muted={true}
16 |         width="100%"
17 |         key={data?.url}
18 |       >
19 |         <source src={data?.url} type={`video/${data?.url?.split('.').pop()}`} />
20 |       </video>
21 |     </div>
22 |   );
23 | };
24 | 
25 | export default Html5VideoHtmlRenderer;
26 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/src/default/settings.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import type { Html5VideoSettings } from '../types/settings';
 3 | import { lazyLoad } from '@react-page/editor';
 4 | 
 5 | const PlayArrow = lazyLoad(() => import('@mui/icons-material/PlayArrow'));
 6 | 
 7 | export const defaultTranslations = {
 8 |   pluginName: 'HTML 5 Video',
 9 |   pluginDescription: 'Add webm, ogg and other HTML5 video',
10 |   urlLabel: 'Video url',
11 |   urlPlaceholder: 'https://example.com/video.webm',
12 |   isInlineable: true,
13 | };
14 | 
15 | export const defaultSettings: Html5VideoSettings = {
16 |   Renderer: () => <>Renderer; for this plugin was not provided </>,
17 |   translations: defaultTranslations,
18 |   icon: <PlayArrow />,
19 | };
20 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/src/default/state.ts:
--------------------------------------------------------------------------------
1 | import type { Html5VideoState } from './../types/state';
2 | export const defaultHtml5VideoState: Html5VideoState = {
3 |   url: '',
4 | };
5 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/src/index.css:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/src/index.tsx:
--------------------------------------------------------------------------------
 1 | import createPlugin from './createPlugin';
 2 | 
 3 | import Html5VideoHtmlRenderer from './Renderer/Html5VideoHtmlRenderer';
 4 | 
 5 | const plugin = createPlugin({
 6 |   Renderer: Html5VideoHtmlRenderer,
 7 | });
 8 | 
 9 | export default plugin;
10 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/src/types/settings.ts:
--------------------------------------------------------------------------------
 1 | import type { CellPluginComponentProps } from '@react-page/editor';
 2 | 
 3 | import type { Html5VideoState } from './state';
 4 | import type { Translations } from './translations';
 5 | 
 6 | export interface Html5VideoSettings {
 7 |   Renderer: React.ComponentType<CellPluginComponentProps<Html5VideoState>>;
 8 | 
 9 |   translations?: Translations;
10 |   icon?: React.ReactNode;
11 |   isInlineable?: boolean;
12 | }
13 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/src/types/state.ts:
--------------------------------------------------------------------------------
1 | export type Html5VideoState = {
2 |   url: string;
3 | };
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/src/types/translations.ts:
--------------------------------------------------------------------------------
1 | import type { defaultTranslations } from '../default/settings';
2 | 
3 | export type Translations = typeof defaultTranslations;
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/tsconfig-es.json:
--------------------------------------------------------------------------------
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "lib-es",
5 |     "module": "esnext"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/plugins/content/html5-video/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "../../../tsconfig.settings.json",
 3 |   "compilerOptions": {
 4 |     "rootDir": "src",
 5 |     "outDir": "lib"
 6 |   },
 7 |   "include": ["src"],
 8 |   "exclude": ["lib", "node_modules", "src/**/__tests__/**/*.*"],
 9 |   "references": [{ "path": "../../../editor" }]
10 | }
11 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/.npmignore:
--------------------------------------------------------------------------------
1 | src/**/*


--------------------------------------------------------------------------------
/packages/plugins/content/image/babel.config.js:
--------------------------------------------------------------------------------
1 | const vendor = require('../../../../babel.config.js');
2 | module.exports = Object.assign({}, vendor);
3 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@react-page/plugins-image",
 3 |   "version": "0.0.0",
 4 |   "main": "./lib/index.js",
 5 |   "module": "./lib-es/index.js",
 6 |   "sideEffects": false,
 7 |   "typings": "./lib/index.d.ts",
 8 |   "author": "ORY GmbH",
 9 |   "license": "MIT",
10 |   "scripts": {
11 |     "build": "npm-run-all --parallel build:lib build:css",
12 |     "build:watch": "npm-run-all --parallel build:lib:watch build:css:watch",
13 |     "build:lib": "tsc -p ./tsconfig.json && tsc -p ./tsconfig-es.json",
14 |     "build:lib:watch": "yarn build:lib -- --watch",
15 |     "build:css": "postcss --config ../../../../config/postcss.config.js --dir lib/ src/index.css",
16 |     "build:css:watch": "npm-run-all build:css -- -w",
17 |     "docs": "documentation build ./lib/**/*.js --format md --github -o ../../../../docs/api/plugins/image.md",
18 |     "clean": "rimraf \"lib\" && rimraf \"lib-es\" && rm -f *.tsbuildinfo"
19 |   },
20 |   "peerDependencies": {
21 |     "@mui/material": "*",
22 |     "react": ">= 16.14",
23 |     "react-dom": ">= 16.14"
24 |   },
25 |   "dependencies": {
26 |     "@mui/icons-material": "^5.8.0",
27 |     "@react-page/editor": "0.0.0"
28 |   },
29 |   "publishConfig": {
30 |     "access": "public"
31 |   }
32 | }
33 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/src/common/styles.ts:
--------------------------------------------------------------------------------
 1 | // material icons isn't allowing us to override style properties with className/styleName
 2 | export const iconStyle: React.CSSProperties = {
 3 |   width: '100%',
 4 |   height: 'auto',
 5 |   padding: '0',
 6 |   color: '#aaa',
 7 |   textAlign: 'center',
 8 |   minWidth: 64,
 9 |   minHeight: 64,
10 |   maxHeight: 256,
11 | };
12 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/src/createPlugin.tsx:
--------------------------------------------------------------------------------
 1 | import type { CellPlugin } from '@react-page/editor';
 2 | import React from 'react';
 3 | import { defaultSettings } from './default/settings';
 4 | import type { ImageSettings } from './types/settings';
 5 | import type { ImageState } from './types/state';
 6 | 
 7 | const createPlugin = (settings?: ImageSettings): CellPlugin<ImageState> => {
 8 |   const mergedSettings = { ...defaultSettings, ...settings };
 9 |   const Controls = mergedSettings.Controls;
10 |   return {
11 |     controls: {
12 |       type: 'custom',
13 |       Component: (props) => (
14 |         <Controls
15 |           {...props}
16 |           translations={mergedSettings.translations}
17 |           imageUpload={mergedSettings.imageUpload}
18 |         />
19 |       ),
20 |     },
21 |     Renderer: mergedSettings.Renderer,
22 |     id: 'ory/editor/core/content/image',
23 |     version: 1,
24 |     icon: mergedSettings.icon,
25 |     title: mergedSettings.translations?.pluginName,
26 |     isInlineable: true,
27 |     description: mergedSettings.translations?.pluginDescription,
28 |   };
29 | };
30 | export default createPlugin;
31 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/src/default/settings.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import type { ImageSettings } from '../types/settings';
 3 | import { lazyLoad } from '@react-page/editor';
 4 | const Panorama = lazyLoad(() => import('@mui/icons-material/Panorama'));
 5 | 
 6 | export const defaultTranslations = {
 7 |   pluginName: 'Image',
 8 |   pluginDescription: 'Loads an image from an url.',
 9 |   or: 'OR',
10 |   haveUrl: 'Existing image URL',
11 |   imageUrl: 'Image URL',
12 |   hrefPlaceholder: 'http://example.com',
13 |   hrefLabel: 'Link to open upon image click',
14 |   altPlaceholder: "Image's description",
15 |   altLabel: "Image's alternative description",
16 |   openNewWindow: 'Open link in new window',
17 |   srcPlaceholder: 'http://example.com/image.png',
18 | 
19 |   // Strings used in ImageUpload
20 |   buttonContent: 'Choose for upload',
21 |   noFileError: 'No file selected',
22 |   badExtensionError: 'Wrong file type',
23 |   tooBigError: 'Image file > 5MB',
24 |   uploadingError: 'Error while uploading',
25 |   unknownError: 'Unknown error',
26 | };
27 | 
28 | export const defaultSettings: ImageSettings = {
29 |   Controls: () => <> Controls for this plugin were not provided</>,
30 |   Renderer: () => <>Renderer; for this plugin was not provided </>,
31 |   translations: defaultTranslations,
32 |   icon: <Panorama />,
33 | };
34 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/src/index.css:
--------------------------------------------------------------------------------
 1 | .react-page-plugins-content-image {
 2 |     width: 100%;
 3 |   }
 4 |   
 5 |   .react-page-plugins-content-image-placeholder {
 6 |     position: relative;
 7 |     width: 100%;
 8 |     text-align: center;
 9 |   }
10 |   


--------------------------------------------------------------------------------
/packages/plugins/content/image/src/index.tsx:
--------------------------------------------------------------------------------
 1 | import type { CellPlugin } from '@react-page/editor';
 2 | import { lazyLoad, ImageUploadType } from '@react-page/editor';
 3 | import createPlugin from './createPlugin';
 4 | import ImageHtmlRenderer from './Renderer/ImageHtmlRenderer';
 5 | import type { ImageSettings } from './types/settings';
 6 | import type { ImageState } from './types/state';
 7 | 
 8 | const ImageControls = lazyLoad(() => import('./Controls/ImageControls'));
 9 | 
10 | const imagePlugin: (
11 |   settings?: Partial<ImageSettings>
12 | ) => CellPlugin<ImageState> = (settings) =>
13 |   createPlugin({
14 |     Renderer: ImageHtmlRenderer,
15 |     Controls: ImageControls,
16 |     ...settings,
17 |   });
18 | 
19 | const image = imagePlugin();
20 | export default image;
21 | export { ImageUploadType };
22 | export { imagePlugin };
23 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/src/types/controls.ts:
--------------------------------------------------------------------------------
 1 | import type {
 2 |   CellPluginComponentProps,
 3 |   ImageUploadType,
 4 | } from '@react-page/editor';
 5 | 
 6 | import type { ImageState } from './state';
 7 | import type { Translations } from './translations';
 8 | 
 9 | export type ImageControlType = React.ComponentType<
10 |   CellPluginComponentProps<ImageState> & {
11 |     imageUpload?: ImageUploadType;
12 |     translations?: Translations;
13 |   }
14 | >;
15 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/src/types/settings.ts:
--------------------------------------------------------------------------------
 1 | import type { CellPluginRenderer, ImageUploadType } from '@react-page/editor';
 2 | import type { ImageControlType } from './controls';
 3 | import type { ImageState } from './state';
 4 | 
 5 | import type { Translations } from './translations';
 6 | 
 7 | export type ImageSettings = {
 8 |   imageUpload?: ImageUploadType;
 9 |   Renderer: CellPluginRenderer<ImageState>;
10 |   Controls: ImageControlType;
11 |   translations?: Translations;
12 |   icon?: React.ReactNode;
13 | };
14 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/src/types/state.ts:
--------------------------------------------------------------------------------
1 | export type ImageState = {
2 |   src: string;
3 |   href?: string;
4 |   alt?: string;
5 |   openInNewWindow?: boolean;
6 | };
7 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/src/types/translations.ts:
--------------------------------------------------------------------------------
1 | import type { defaultTranslations } from '../default/settings';
2 | 
3 | export type Translations = typeof defaultTranslations;
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/tsconfig-es.json:
--------------------------------------------------------------------------------
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "lib-es",
5 |     "module": "esnext"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/plugins/content/image/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "../../../tsconfig.settings.json",
 3 |   "compilerOptions": {
 4 |     "rootDir": "src",
 5 |     "outDir": "lib"
 6 |   },
 7 |   "include": ["src"],
 8 |   "exclude": ["lib", "node_modules", "src/**/__tests__/**/*.*"],
 9 |   "references": [{ "path": "../../../editor" }]
10 | }
11 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/.npmignore:
--------------------------------------------------------------------------------
1 | src/**/*


--------------------------------------------------------------------------------
/packages/plugins/content/slate/babel.config.js:
--------------------------------------------------------------------------------
1 | const vendor = require('../../../../babel.config.js');
2 | module.exports = Object.assign({}, vendor);
3 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/components/ConditionalWrapper.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | 
 3 | export const ConditionalWrapper: React.FC<{
 4 |   condition: boolean;
 5 |   children: React.ReactElement;
 6 |   wrapper: (children: React.ReactElement) => React.ReactElement;
 7 | }> = ({ condition, wrapper, children }) => (
 8 |   <>{condition ? wrapper(children) : children}</>
 9 | );
10 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/components/Controls.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import type { SlateProps } from '../types/component';
 3 | import PluginButton from './PluginButton';
 4 | import { useTheme } from '@mui/material';
 5 | const Controls = (props: Pick<SlateProps, 'translations' | 'plugins'>) => {
 6 |   const { plugins, translations } = props;
 7 |   const theme = useTheme();
 8 | 
 9 |   const dark = theme.palette.mode === 'dark';
10 | 
11 |   return (
12 |     <div>
13 |       {plugins &&
14 |         plugins.map((plugin, i: number) =>
15 |           plugin.addToolbarButton ? (
16 |             <PluginButton
17 |               key={i}
18 |               translations={translations}
19 |               plugin={plugin}
20 |               dark={dark}
21 |             />
22 |           ) : null
23 |         )}
24 |     </div>
25 |   );
26 | };
27 | 
28 | export default React.memo(Controls);
29 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/components/DialogVisibleProvider.tsx:
--------------------------------------------------------------------------------
 1 | import type { Dispatch, FC, PropsWithChildren, SetStateAction } from 'react';
 2 | import React, { useContext, useMemo, useState } from 'react';
 3 | 
 4 | const DialogContext = React.createContext<{
 5 |   visible?: boolean;
 6 |   setVisible?: Dispatch<SetStateAction<boolean>>;
 7 | }>({});
 8 | 
 9 | const DialogVisibleProvider: FC<PropsWithChildren> = ({ children }) => {
10 |   const [visible, setVisible] = useState(false);
11 |   const value = useMemo(() => ({ visible, setVisible }), [visible, setVisible]);
12 |   return (
13 |     <DialogContext.Provider value={value}>{children}</DialogContext.Provider>
14 |   );
15 | };
16 | export const useDialogIsVisible = () => {
17 |   return useContext(DialogContext)?.visible;
18 | };
19 | export const useSetDialogIsVisible = () => {
20 |   return useContext(DialogContext)?.setVisible;
21 | };
22 | export default DialogVisibleProvider;
23 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/components/ReadOnlySlate.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import { SlateReactPresentation } from 'slate-react-presentation';
 3 | import type { SlateProps } from '../types/component';
 4 | import { useRenderElement, useRenderLeave } from './renderHooks';
 5 | 
 6 | const ReadOnlySlate = (props: SlateProps) => {
 7 |   const { plugins, defaultPluginType } = props;
 8 | 
 9 |   const renderElement = useRenderElement(
10 |     {
11 |       plugins,
12 |       defaultPluginType,
13 |     },
14 |     []
15 |   );
16 |   const renderLeaf = useRenderLeave({ plugins, readOnly: true }, []);
17 |   // the div around is required to be consistent in styling with the default editor
18 |   return (
19 |     <div
20 |       style={{
21 |         position: 'relative',
22 |         outline: 'none',
23 |         whiteSpace: 'pre-wrap',
24 |         overflowWrap: 'break-word',
25 |       }}
26 |     >
27 |       <SlateReactPresentation
28 |         renderElement={renderElement}
29 |         renderLeaf={renderLeaf}
30 |         value={props.data.slate}
31 |         LeafWrapper={React.Fragment}
32 |       />
33 |     </div>
34 |   );
35 | };
36 | 
37 | export default React.memo(ReadOnlySlate);
38 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/components/pluginHooks.ts:
--------------------------------------------------------------------------------
 1 | import type { DependencyList } from 'react';
 2 | import { useMemo } from 'react';
 3 | import type { SlatePlugin } from '../types/SlatePlugin';
 4 | import type { SlateComponentPluginDefinition } from '../types/slatePluginDefinitions';
 5 | 
 6 | export const useComponentNodePlugins = (
 7 |   { plugins }: { plugins: SlatePlugin[] },
 8 |   deps: DependencyList
 9 | ) =>
10 |   useMemo(
11 |     () =>
12 |       plugins.filter(
13 |         (plugin) =>
14 |           plugin.pluginType === 'component' && plugin.object !== 'mark'
15 |         // eslint-disable-next-line @typescript-eslint/no-explicit-any
16 |       ) as SlateComponentPluginDefinition<any>[],
17 |     deps
18 |   );
19 | 
20 | export const useComponentMarkPlugins = (
21 |   { plugins }: { plugins: SlatePlugin[] },
22 |   deps: DependencyList
23 | ) =>
24 |   useMemo(
25 |     () =>
26 |       plugins.filter(
27 |         (plugin) =>
28 |           plugin.pluginType === 'component' && plugin.object === 'mark'
29 |         // eslint-disable-next-line @typescript-eslint/no-explicit-any
30 |       ) as SlateComponentPluginDefinition<any>[],
31 |     deps
32 |   );
33 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/default/settings.ts:
--------------------------------------------------------------------------------
 1 | export const defaultTranslations = {
 2 |   pluginName: 'Text',
 3 |   pluginDescription: 'An advanced rich text area.',
 4 |   placeholder: 'Write here...',
 5 |   linkPlugin: {
 6 |     cancel: 'Cancel',
 7 |     ok: 'Ok',
 8 |     createLink: 'Create a link',
 9 |     linkTitlePlaceholder: 'Link title',
10 |     linkHrefPlaceholder: 'http://example.com/my/link.html',
11 |     linkOpenInNewWindowLabel: 'Open in new window',
12 |   },
13 | };
14 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/hooks/useCurrentNodeDataWithPlugin.ts:
--------------------------------------------------------------------------------
 1 | import type { DataTType } from '@react-page/editor';
 2 | import type { Editor } from 'slate';
 3 | import { useSlate } from 'slate-react';
 4 | import type { SlatePluginDefinition } from '../types/slatePluginDefinitions';
 5 | import { getCurrentNodeWithPlugin } from './useCurrentNodeWithPlugin';
 6 | 
 7 | export const getCurrentNodeDataWithPlugin = <T extends DataTType>(
 8 |   editor: Editor,
 9 |   plugin: SlatePluginDefinition<T>
10 | ): T => {
11 |   const currentNodeEntry = getCurrentNodeWithPlugin(editor, plugin);
12 | 
13 |   if (currentNodeEntry) {
14 |     const currentNode = currentNodeEntry[0];
15 |     if (plugin.pluginType === 'component' && plugin.object === 'mark') {
16 |       return (currentNode as Record<string, unknown>)[plugin.type] as T;
17 |     }
18 | 
19 |     // eslint-disable-next-line @typescript-eslint/no-explicit-any
20 |     const { data } = currentNode as any;
21 |     return data as T;
22 |   } else if (plugin.getInitialData) {
23 |     return plugin.getInitialData();
24 |   } else {
25 |     return {} as T;
26 |   }
27 | };
28 | 
29 | export default <T extends DataTType>(plugin: SlatePluginDefinition<T>): T => {
30 |   const editor = useSlate();
31 |   return getCurrentNodeDataWithPlugin(editor, plugin);
32 | };
33 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/hooks/useCurrentSelection.ts:
--------------------------------------------------------------------------------
1 | import { useSlate } from 'slate-react';
2 | 
3 | export default () => {
4 |   const editor = useSlate();
5 |   return editor.selection;
6 | };
7 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/hooks/usePluginIsActive.ts:
--------------------------------------------------------------------------------
1 | import type { DataTType } from '@react-page/editor';
2 | import type { SlatePluginDefinition } from '../types/slatePluginDefinitions';
3 | import useCurrentNodeWithPlugin from './useCurrentNodeWithPlugin';
4 | 
5 | export default <T extends DataTType>(plugin: SlatePluginDefinition<T>) => {
6 |   const nodeEntry = useCurrentNodeWithPlugin<T>(plugin);
7 |   return Boolean(nodeEntry);
8 | };
9 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/hooks/usePluginIsDisabled.ts:
--------------------------------------------------------------------------------
 1 | import type { DataTType } from '@react-page/editor';
 2 | import { useEffect, useState } from 'react';
 3 | import { useSlate } from 'slate-react';
 4 | import type { SlatePluginDefinition } from '../types/slatePluginDefinitions';
 5 | 
 6 | export default <T extends DataTType>(
 7 |   plugin: SlatePluginDefinition<T>
 8 | ): boolean => {
 9 |   const editor = useSlate();
10 |   const [disabled, setDisabled] = useState(false);
11 | 
12 |   useEffect(() => {
13 |     if (plugin.isDisabled) {
14 |       try {
15 |         plugin.isDisabled(editor).then((d) => {
16 |           setDisabled(d);
17 |         });
18 |       } catch (e) {
19 |         // slate sometimes throws when dom node cant be found in undo
20 |       }
21 |     }
22 |   }, [editor.selection, plugin]);
23 |   if (!editor) {
24 |     return true;
25 |   }
26 |   return disabled;
27 | };
28 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/hooks/useTextIsSelected.ts:
--------------------------------------------------------------------------------
 1 | import { Editor } from 'slate';
 2 | import { useSlate } from 'slate-react';
 3 | 
 4 | const useTextIsSelected = () => {
 5 |   const editor = useSlate();
 6 |   try {
 7 |     return Boolean(
 8 |       editor.selection && Editor.string(editor, editor.selection) !== ''
 9 |     );
10 |   } catch (e) {
11 |     // can in some cases throw currently
12 |     return false;
13 |   }
14 | };
15 | 
16 | export default useTextIsSelected;
17 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/htmlToSlate/index.tsx:
--------------------------------------------------------------------------------
 1 | import type { SlatePlugin } from '../types/SlatePlugin';
 2 | 
 3 | export const HtmlToSlate = ({ plugins }: { plugins: SlatePlugin[] }) => {
 4 |   return async (htmlString: string) => {
 5 |     const impl = (await import('./HtmlToSlate')).default;
 6 | 
 7 |     return impl({ plugins })(htmlString);
 8 |   };
 9 | };
10 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/htmlToSlate/parseHtml.browser.ts:
--------------------------------------------------------------------------------
 1 | export default (html: string) => {
 2 |   if (typeof DOMParser === 'undefined') {
 3 |     throw new Error(
 4 |       'The native `DOMParser` global which the `Html` serializer uses by default is not present in this environment. You must supply the `options.parseHtml` function instead.'
 5 |     );
 6 |   }
 7 | 
 8 |   return new DOMParser().parseFromString(html, 'text/html');
 9 | };
10 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/htmlToSlate/parseHtml.ts:
--------------------------------------------------------------------------------
1 | import { DOMParser } from '@xmldom/xmldom';
2 | 
3 | export default (html: string) => {
4 |   return new DOMParser().parseFromString(html, 'text/html');
5 | };
6 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/index.css:
--------------------------------------------------------------------------------
 1 | @import 'plugins/paragraphs/node.css';
 2 | 
 3 | .react-page-plugins-content-slate-inline-toolbar {
 4 |   position: absolute;
 5 |   z-index: 10;
 6 |   top: -10000px;
 7 |   left: -10000px;
 8 |   margin-top: -6px;
 9 |   opacity: 0;
10 |   background-color: var(--grey900);
11 |   border-radius: 4px;
12 |   transition: opacity 0.75s;
13 | }
14 | 
15 | .react-page-plugins-content-slate-inline-toolbar--hidden {
16 |   opacity: 0 !important;
17 |   pointer-events: none;
18 | }
19 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/migrations/deep-rename-keys.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-explicit-any */
2 | declare module 'deep-rename-keys' {
3 |   function rename(obj: any, cb: (key: string) => string): any;
4 |   export default rename;
5 | }
6 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/migrations/v002.ts:
--------------------------------------------------------------------------------
 1 | import { Migration } from '@react-page/editor';
 2 | 
 3 | import rename from 'deep-rename-keys';
 4 | const migration = new Migration({
 5 |   toVersion: '0.0.2',
 6 |   fromVersionRange: '^0.0.1',
 7 |   migrate: (state) => {
 8 |     // wrap with document
 9 |     state = {
10 |       ...state,
11 |       ...(state.serialized
12 |         ? { serialized: { document: state.serialized } }
13 |         : {}),
14 |     };
15 |     // rename keys
16 |     state = rename(state, (key: string) => {
17 |       switch (key) {
18 |         case 'kind':
19 |           return 'object';
20 |         case 'ranges':
21 |           return 'leaves';
22 |         default:
23 |           return key;
24 |       }
25 |     });
26 | 
27 |     return state;
28 |   },
29 | });
30 | 
31 | export default migration;
32 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/none.tsx:
--------------------------------------------------------------------------------
1 | export default {};
2 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/pluginFactories/createComponentPlugin.tsx:
--------------------------------------------------------------------------------
 1 | /* eslint-disable @typescript-eslint/ban-types */
 2 | import type { SlatePlugin } from '../types/SlatePlugin';
 3 | import type { SlateComponentPluginDefinition } from '../types/slatePluginDefinitions';
 4 | 
 5 | function createComponentPlugin<T extends Record<string, unknown>>(
 6 |   def: SlateComponentPluginDefinition<T>
 7 | ) {
 8 |   const customizablePlugin = function <CT extends Record<string, unknown> = T>(
 9 |     customize: (
10 |       t: SlateComponentPluginDefinition<T>
11 |     ) => SlateComponentPluginDefinition<CT> = (d) =>
12 |       d as unknown as SlateComponentPluginDefinition<CT>
13 |   ) {
14 |     return createComponentPlugin(customize(def));
15 |   };
16 |   customizablePlugin.toPlugin = (): SlatePlugin => ({
17 |     ...def,
18 |     pluginType: 'component',
19 |   });
20 |   return customizablePlugin;
21 | }
22 | 
23 | export default createComponentPlugin;
24 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/pluginFactories/createDataPlugin.tsx:
--------------------------------------------------------------------------------
 1 | /* eslint-disable @typescript-eslint/ban-types */
 2 | import type { SlatePlugin } from '../types/SlatePlugin';
 3 | import type { SlateDataPluginDefinition } from '../types/slatePluginDefinitions';
 4 | 
 5 | function createDataPlugin<T extends Record<string, unknown>>(
 6 |   def: SlateDataPluginDefinition<T>
 7 | ) {
 8 |   const customizablePlugin = function <CT>(
 9 |     customize: (
10 |       t: SlateDataPluginDefinition<T>
11 |     ) => SlateDataPluginDefinition<T & CT> = (d) =>
12 |       d as unknown as SlateDataPluginDefinition<T & CT>
13 |   ) {
14 |     return createDataPlugin(customize(def));
15 |   };
16 |   customizablePlugin.toPlugin = (): SlatePlugin => ({
17 |     pluginType: 'data',
18 |     ...def,
19 |   });
20 |   return customizablePlugin;
21 | }
22 | 
23 | export default createDataPlugin;
24 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/pluginFactories/createHeadingsPlugin.tsx:
--------------------------------------------------------------------------------
 1 | import type { SlateComponentPluginDefinition } from '../types/slatePluginDefinitions';
 2 | import type { HtmlBlockData } from './createSimpleHtmlBlockPlugin';
 3 | import createSimpleHtmlBlockPlugin from './createSimpleHtmlBlockPlugin';
 4 | 
 5 | export type HeadingsDef<T> = {
 6 |   level: 1 | 2 | 3 | 4 | 5 | 6;
 7 | } & Pick<
 8 |   SlateComponentPluginDefinition<HtmlBlockData<T>>,
 9 |   'type' | 'getInitialData' | 'icon'
10 | >;
11 | // eslint-disable-next-line @typescript-eslint/ban-types
12 | function createHeadingsPlugin<T = {}>(def: HeadingsDef<T>) {
13 |   return createSimpleHtmlBlockPlugin<T>({
14 |     type: def.type,
15 |     hotKey: 'mod+' + def.level,
16 |     replaceWithDefaultOnRemove: true,
17 |     icon: def.icon,
18 |     label: `Heading ${def.level}`,
19 |     tagName: ('h' + def.level) as keyof JSX.IntrinsicElements,
20 |   });
21 | }
22 | 
23 | export default createHeadingsPlugin;
24 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/pluginFactories/createListItemPlugin.tsx:
--------------------------------------------------------------------------------
 1 | import createSimpleHtmlBlockPlugin from './createSimpleHtmlBlockPlugin';
 2 | 
 3 | type ListItemDef = {
 4 |   type: string;
 5 |   tagName: keyof JSX.IntrinsicElements;
 6 | };
 7 | 
 8 | export default function <T>(def: ListItemDef) {
 9 |   return createSimpleHtmlBlockPlugin<T>({
10 |     noButton: true,
11 |     tagName: def.tagName,
12 |     type: def.type,
13 |   });
14 | }
15 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/pluginFactories/createMarkPlugin.tsx:
--------------------------------------------------------------------------------
 1 | import type { ComponentType, PropsWithChildren } from 'react';
 2 | import React from 'react';
 3 | import createComponentPlugin from './createComponentPlugin';
 4 | 
 5 | type MarkPluginDefinition = {
 6 |   type: string;
 7 |   tagName: keyof JSX.IntrinsicElements;
 8 |   icon?: JSX.Element;
 9 |   hotKey?: string;
10 |   label?: string;
11 | };
12 | 
13 | export default (markDef: MarkPluginDefinition) => {
14 |   return createComponentPlugin({
15 |     type: markDef.type,
16 |     object: 'mark',
17 |     hotKey: markDef.hotKey,
18 |     icon: markDef.icon,
19 |     label: markDef.label,
20 |     addToolbarButton: false,
21 |     addHoverButton: true,
22 |     deserialize: {
23 |       tagName: markDef.tagName,
24 |     },
25 |     Component: ({ children, attributes }) => {
26 |       const Tag =
27 |         markDef.tagName as unknown as ComponentType<PropsWithChildren>;
28 |       return <Tag {...attributes}>{children}</Tag>;
29 |     },
30 |   });
31 | };
32 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/pluginFactories/index.ts:
--------------------------------------------------------------------------------
 1 | import createComponentPlugin from './createComponentPlugin';
 2 | import createDataPlugin from './createDataPlugin';
 3 | import createHeadingsPlugin from './createHeadingsPlugin';
 4 | import createListIndentionPlugin from './createListIndentionPlugin';
 5 | import createListItemPlugin from './createListItemPlugin';
 6 | import createListPlugin from './createListPlugin';
 7 | import createMarkPlugin from './createMarkPlugin';
 8 | import createSimpleHtmlBlockPlugin from './createSimpleHtmlBlockPlugin';
 9 | 
10 | export {
11 |   createComponentPlugin,
12 |   createDataPlugin,
13 |   createHeadingsPlugin,
14 |   createListIndentionPlugin,
15 |   createListItemPlugin,
16 |   createListPlugin,
17 |   createMarkPlugin,
18 |   createSimpleHtmlBlockPlugin,
19 | };
20 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/emphasize/em.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | 
 3 | import { lazyLoad } from '@react-page/editor';
 4 | import createMarkPlugin from '../../pluginFactories/createMarkPlugin';
 5 | 
 6 | const ItalicIcon = lazyLoad(() => import('@mui/icons-material/FormatItalic'));
 7 | 
 8 | export default createMarkPlugin({
 9 |   type: 'EMPHASIZE/EM',
10 |   tagName: 'em',
11 |   icon: <ItalicIcon />,
12 |   label: 'Italic',
13 |   hotKey: 'mod+i',
14 | });
15 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/emphasize/index.tsx:
--------------------------------------------------------------------------------
1 | import em from './em';
2 | import strong from './strong';
3 | import underline from './underline';
4 | 
5 | export default { em, strong, underline };
6 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/emphasize/strong.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | 
 3 | import { lazyLoad } from '@react-page/editor';
 4 | import createMarkPlugin from '../../pluginFactories/createMarkPlugin';
 5 | 
 6 | const BoldIcon = lazyLoad(() => import('@mui/icons-material/FormatBold'));
 7 | 
 8 | export default createMarkPlugin({
 9 |   type: 'EMPHASIZE/STRONG',
10 |   tagName: 'strong',
11 |   icon: <BoldIcon />,
12 |   label: 'Bold',
13 |   hotKey: 'mod+b',
14 | });
15 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/emphasize/underline.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | 
 3 | import { lazyLoad } from '@react-page/editor';
 4 | import createMarkPlugin from '../../pluginFactories/createMarkPlugin';
 5 | 
 6 | const UnderlinedIcon = lazyLoad(
 7 |   () => import('@mui/icons-material/FormatUnderlined')
 8 | );
 9 | 
10 | export default createMarkPlugin({
11 |   type: 'EMPHASIZE/U',
12 |   tagName: 'u',
13 |   icon: <UnderlinedIcon />,
14 |   label: 'Underline',
15 |   hotKey: 'mod+u',
16 | });
17 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/index.ts:
--------------------------------------------------------------------------------
 1 | import alignment from './alignment';
 2 | import code from './code/';
 3 | import emphasize from './emphasize';
 4 | import headings from './headings';
 5 | import link from './links';
 6 | import lists from './lists';
 7 | import paragraphs from './paragraphs';
 8 | import quotes from './quotes';
 9 | 
10 | export default {
11 |   paragraphs,
12 |   headings,
13 |   link,
14 |   lists,
15 | 
16 |   quotes,
17 |   code,
18 |   emphasize,
19 |   alignment,
20 | };
21 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/links/anchor.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import createDataPlugin from '../../pluginFactories/createDataPlugin';
 3 | 
 4 | const anchor = createDataPlugin<{ id: string }>({
 5 |   addHoverButton: false,
 6 |   addToolbarButton: true,
 7 |   object: 'block',
 8 |   label: 'Id for Link Anchor',
 9 |   icon: <span>#</span>,
10 |   properties: ['id'],
11 |   dataMatches: (data) => {
12 |     return Boolean(data?.id);
13 |   },
14 |   controls: {
15 |     type: 'autoform',
16 |     schema: {
17 |       type: 'object',
18 |       required: ['id'],
19 |       properties: {
20 |         id: {
21 |           type: 'string',
22 |         },
23 |       },
24 |     },
25 |   },
26 | });
27 | 
28 | export default anchor;
29 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/links/index.tsx:
--------------------------------------------------------------------------------
1 | import link from './link';
2 | import anchor from './anchor';
3 | export default {
4 |   anchor,
5 |   link,
6 | };
7 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/lists/constants.ts:
--------------------------------------------------------------------------------
1 | export const LISTS_TYPE_PREFIX = 'LISTS/';
2 | 
3 | export const UL = 'UNORDERED-LIST';
4 | export const OL = 'ORDERED-LIST';
5 | export const LI = 'LISTS/LIST-ITEM'; // FIXME: this should have a different prefix to avoid hard coded check, but changing that would need a migration
6 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/paragraphs/index.tsx:
--------------------------------------------------------------------------------
 1 | import createComponentPlugin from '../../pluginFactories/createComponentPlugin';
 2 | 
 3 | type Align = 'left' | 'right' | 'center' | 'justify';
 4 | export const getAlignmentFromElement = (el: HTMLElement) => {
 5 |   const align = el?.style?.textAlign as Align;
 6 |   if (align) {
 7 |     return {
 8 |       align,
 9 |     };
10 |   }
11 | };
12 | export default {
13 |   paragraph: createComponentPlugin<{
14 |     align?: Align;
15 |   }>({
16 |     type: 'PARAGRAPH/PARAGRAPH',
17 |     label: 'Paragraph',
18 |     object: 'block',
19 |     addToolbarButton: false,
20 |     addHoverButton: false,
21 |     deserialize: {
22 |       tagName: 'p',
23 |       getData: getAlignmentFromElement,
24 |     },
25 |     getStyle: ({ align }) => ({ textAlign: align }),
26 | 
27 |     Component: 'p',
28 |   }),
29 |   // currently only for deserialize
30 |   pre: createComponentPlugin<{
31 |     align?: Align;
32 |   }>({
33 |     type: 'PARAGRAPH/PRE',
34 |     label: 'Pre',
35 |     object: 'block',
36 |     addToolbarButton: false,
37 |     addHoverButton: false,
38 |     deserialize: {
39 |       tagName: 'pre',
40 |       getData: getAlignmentFromElement,
41 |     },
42 |     getStyle: ({ align }) => ({ textAlign: align }),
43 | 
44 |     Component: 'pre',
45 |   }),
46 | };
47 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/paragraphs/node.css:
--------------------------------------------------------------------------------
1 | .react-page-plugins-content-slate-paragraph-placeholder {
2 |   font-style: italic;
3 |   color: var(--lightBlack);
4 | }
5 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/plugins/quotes.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import { lazyLoad } from '@react-page/editor';
 3 | import createSimpleHtmlBlockPlugin from '../pluginFactories/createSimpleHtmlBlockPlugin';
 4 | 
 5 | const BlockquoteIcon = lazyLoad(
 6 |   () => import('@mui/icons-material/FormatQuote')
 7 | );
 8 | 
 9 | export default {
10 |   blockQuote: createSimpleHtmlBlockPlugin({
11 |     type: 'BLOCKQUOTE/BLOCKQUOTE',
12 |     icon: <BlockquoteIcon />,
13 |     label: 'Quote',
14 |     tagName: 'blockquote',
15 |   }),
16 | };
17 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/slateEnhancer/withInline.ts:
--------------------------------------------------------------------------------
 1 | import type { Editor } from 'slate';
 2 | import type { SlatePlugin } from '../types/SlatePlugin';
 3 | 
 4 | const withInline = (plugins: SlatePlugin[]) => (editor: Editor) => {
 5 |   const { isInline, isVoid } = editor;
 6 |   editor.isInline = (element) => {
 7 |     return plugins.some(
 8 |       (plugin) =>
 9 |         plugin.pluginType === 'component' &&
10 |         plugin.object === 'inline' &&
11 |         plugin.type === element.type
12 |     )
13 |       ? true
14 |       : isInline(element);
15 |   };
16 | 
17 |   editor.isVoid = (element) => {
18 |     return plugins.some(
19 |       (plugin) =>
20 |         plugin.pluginType === 'component' &&
21 |         (plugin.object === 'block' || plugin.object === 'inline') &&
22 |         plugin.type === element.type &&
23 |         plugin.isVoid
24 |     )
25 |       ? true
26 |       : isVoid(element);
27 |   };
28 |   return editor;
29 | };
30 | 
31 | export default withInline;
32 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/slateTypes.d.ts:
--------------------------------------------------------------------------------
 1 | import type { BaseEditor, Descendant } from 'slate';
 2 | import type { ReactEditor } from 'slate-react';
 3 | import type { Data, CustomText } from './types';
 4 | 
 5 | declare module 'slate' {
 6 |   interface CustomTypes {
 7 |     Editor: BaseEditor &
 8 |       ReactEditor & {
 9 |         type: string | null;
10 |         data?: Data | null;
11 |       };
12 |     Element: {
13 |       type?: string | null;
14 |       data?: Data | null;
15 |       children: Descendant[];
16 |     };
17 |     Text: CustomText;
18 |   }
19 | }
20 | 
21 | export {};
22 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/types.ts:
--------------------------------------------------------------------------------
1 | import type { DataTType } from '@react-page/editor';
2 | 
3 | export type Data = DataTType;
4 | export type CustomText = {
5 |   text: string;
6 |   data?: Data;
7 |   type?: string;
8 | };
9 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/types/SlatePlugin.ts:
--------------------------------------------------------------------------------
 1 | import type { SlatePluginDefinition } from './slatePluginDefinitions';
 2 | 
 3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
 4 | export type SlatePlugin = SlatePluginDefinition<any>;
 5 | 
 6 | export type SlatePluginOrListOfPlugins = SlatePlugin | SlatePlugin[];
 7 | 
 8 | export type SlatePluginOrFactory =
 9 |   // eslint-disable-next-line @typescript-eslint/no-explicit-any
10 |   | {
11 |       toPlugin: () => SlatePluginOrListOfPlugins;
12 |     }
13 |   | SlatePluginOrListOfPlugins;
14 | export type SlatePluginCollection = {
15 |   [group: string]: {
16 |     [key: string]: SlatePluginOrFactory;
17 |   };
18 | };
19 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/types/component.ts:
--------------------------------------------------------------------------------
 1 | import type { CellPluginComponentProps } from '@react-page/editor';
 2 | import type { SlatePluginDefinition } from './slatePluginDefinitions';
 3 | import type { SlateState } from './state';
 4 | import type { Translations } from './translations';
 5 | 
 6 | export type SlateProps = CellPluginComponentProps<SlateState> & {
 7 |   plugins: SlatePluginDefinition[];
 8 |   defaultPluginType: string;
 9 |   translations?: Translations;
10 | };
11 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/types/initialSlateState.ts:
--------------------------------------------------------------------------------
 1 | import type { SlatePluginOrFactory } from './SlatePlugin';
 2 | 
 3 | export type SlatePluginNode = {
 4 |   plugin: SlatePluginOrFactory;
 5 |   children?: SlateDefNode[];
 6 |   // eslint-disable-next-line @typescript-eslint/ban-types
 7 |   data?: object;
 8 | };
 9 | 
10 | export type SlateDefNode = SlatePluginNode | string;
11 | export type InitialSlateStateDef = {
12 |   children: SlateDefNode[];
13 | };
14 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/types/state.ts:
--------------------------------------------------------------------------------
1 | import type { Node, Range } from 'slate';
2 | 
3 | export type SlateState = {
4 |   slate: Node[];
5 |   selection?: Range | null;
6 | };
7 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/types/translations.ts:
--------------------------------------------------------------------------------
1 | import type { defaultTranslations } from '../default/settings';
2 | 
3 | export type Translations = typeof defaultTranslations;
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/utils/flattenDeep.ts:
--------------------------------------------------------------------------------
 1 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
 2 | export default function flattenDeep<T>(arr1: any): T[] {
 3 |   if (!Array.isArray(arr1)) {
 4 |     return [arr1];
 5 |   }
 6 |   return arr1.reduce(
 7 |     // eslint-disable-next-line @typescript-eslint/no-explicit-any
 8 |     (acc: T[], val: any) =>
 9 |       Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val),
10 |     []
11 |   );
12 | }
13 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/utils/getCurrentData.ts:
--------------------------------------------------------------------------------
 1 | import { Editor } from 'slate';
 2 | 
 3 | const getCurrentData = (editor: Editor): Record<string, unknown> => {
 4 |   const [existingNodeWithData] = Editor.nodes(editor, {
 5 |     mode: 'all',
 6 |     match: (node) => {
 7 |       return Boolean(node.data);
 8 |     },
 9 |   });
10 |   const existingData = existingNodeWithData
11 |     ? (existingNodeWithData[0]?.data as Record<string, unknown>)
12 |     : {};
13 | 
14 |   return existingData;
15 | };
16 | 
17 | export default getCurrentData;
18 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/utils/getTextContent.ts:
--------------------------------------------------------------------------------
 1 | import type { Node, Text } from 'slate';
 2 | import type { SlatePlugin } from '../types/SlatePlugin';
 3 | 
 4 | const isText = (node: Node): node is Text => {
 5 |   return Boolean((node as Text).text);
 6 | };
 7 | export const getTextContents = (
 8 |   nodes: Node[],
 9 |   options: { slatePlugins: SlatePlugin[] }
10 | ): string[] => {
11 |   return nodes.reduce<string[]>((acc, node) => {
12 |     if (isText(node)) {
13 |       return [...acc, node.text];
14 |     } else if (node.children) {
15 |       const childTexts = getTextContents(node.children as Node[], options);
16 | 
17 |       const everyChildIsTextOrInline = node.children.every((n) => {
18 |         if (isText(n)) return true;
19 | 
20 |         const p = options.slatePlugins.find(
21 |           (f) => f.pluginType === 'component' && f.type === n.type
22 |         );
23 |         if (!p) return true; // could be data plugin or custom
24 | 
25 |         if (p.object === 'block') {
26 |           return false;
27 |         }
28 | 
29 |         return true;
30 |       });
31 | 
32 |       return [
33 |         ...acc,
34 |         ...(everyChildIsTextOrInline ? [childTexts.join('')] : childTexts),
35 |       ];
36 |     } else {
37 |       return acc;
38 |     }
39 |   }, []);
40 | };
41 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/utils/makeSlatePluginsFromDef.ts:
--------------------------------------------------------------------------------
 1 | import type { SlatePlugin, SlatePluginCollection } from '../types/SlatePlugin';
 2 | import flattenDeep from './flattenDeep';
 3 | 
 4 | export default (plugins: SlatePluginCollection) => {
 5 |   return Object.keys(plugins).reduce((acc, groupKey) => {
 6 |     const group = plugins[groupKey];
 7 |     const groupPlugins = Object.keys(group).reduce((innerAcc, key) => {
 8 |       const pluginOrFactory = plugins[groupKey][key];
 9 |       // eslint-disable-next-line @typescript-eslint/no-explicit-any
10 |       const result = (pluginOrFactory as any).toPlugin
11 |         ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
12 |           (pluginOrFactory as any).toPlugin()
13 |         : pluginOrFactory;
14 | 
15 |       return [...innerAcc, ...flattenDeep(result)] as SlatePlugin[];
16 |     }, [] as SlatePlugin[]);
17 | 
18 |     return [...acc, ...groupPlugins];
19 |   }, [] as SlatePlugin[]);
20 | };
21 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/src/utils/useSafeSetState.ts:
--------------------------------------------------------------------------------
 1 | import * as React from 'react';
 2 | 
 3 | export function useSafeSetState<T>(
 4 |   initialState?: T | (() => T)
 5 | ): [T | undefined, React.Dispatch<React.SetStateAction<T>>] {
 6 |   const [state, setState] = React.useState(initialState);
 7 | 
 8 |   const mountedRef = React.useRef(false);
 9 |   React.useEffect(() => {
10 |     mountedRef.current = true;
11 |     return () => {
12 |       mountedRef.current = false;
13 |     };
14 |   }, []);
15 |   const safeSetState = React.useCallback(
16 |     (args: any) => {
17 |       if (mountedRef.current) {
18 |         return setState(args);
19 |       }
20 |     },
21 |     [mountedRef, setState]
22 |   );
23 | 
24 |   return [state, safeSetState];
25 | }
26 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/tsconfig-es.json:
--------------------------------------------------------------------------------
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "lib-es",
5 |     "module": "esnext"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/plugins/content/slate/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "../../../tsconfig.settings.json",
 3 |   "compilerOptions": {
 4 |     "downlevelIteration": true,
 5 |     "rootDir": "src",
 6 |     "outDir": "lib",
 7 |     "paths": {
 8 |       "react": ["../../../../node_modules/@types/react/index"]
 9 |     }
10 |   },
11 |   "include": ["src"],
12 | 
13 |   "exclude": ["lib", "node_modules", "src/**/__tests__/**/*.*"],
14 |   "references": [{ "path": "../../../editor" }]
15 | }
16 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/.npmignore:
--------------------------------------------------------------------------------
1 | src/**/*


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/babel.config.js:
--------------------------------------------------------------------------------
1 | const vendor = require('../../../../babel.config.js');
2 | module.exports = Object.assign({}, vendor);
3 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/src/Renderer/SpacerHtmlRenderer.tsx:
--------------------------------------------------------------------------------
 1 | import type { CellPluginComponentProps } from '@react-page/editor';
 2 | import { lazyLoad } from '@react-page/editor';
 3 | 
 4 | import React from 'react';
 5 | import type { SpacerState } from '../types/state';
 6 | 
 7 | const SpacerResizable = lazyLoad(() => import('./SpacerResizable'));
 8 | const SpacerHtmlRenderer: React.FC<CellPluginComponentProps<SpacerState>> = (
 9 |   props
10 | ) => {
11 |   return (
12 |     <div className={'react-page-plugins-content-spacer'}>
13 |       {props.isEditMode ? (
14 |         <SpacerResizable {...props} />
15 |       ) : (
16 |         <div style={{ height: `${(props.data?.height || 0).toString()}px` }} />
17 |       )}
18 |     </div>
19 |   );
20 | };
21 | 
22 | export default SpacerHtmlRenderer;
23 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/src/default/settings.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import type { SpacerSettings } from '../types/settings';
 3 | 
 4 | export const defaultTranslations = {
 5 |   pluginName: 'Spacer',
 6 |   pluginDescription: 'Resizeable, horizontal and vertical empty space.',
 7 |   elementHeightLabel: 'Element height (px)',
 8 | };
 9 | 
10 | export const defaultSettings: SpacerSettings = {
11 |   Renderer: () => <>Renderer; for this plugin was not provided </>,
12 |   translations: defaultTranslations,
13 | };
14 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/src/index.css:
--------------------------------------------------------------------------------
 1 | .react-page-plugins-content-spacer {
 2 |   border-bottom: none;
 3 |   position: relative;
 4 | }
 5 | 
 6 | .react-page-editable .react-page-plugins-content-spacer {
 7 |   outline: 1px dashed var(--minBlack);
 8 | }
 9 | .react-page-editable-mode-preview .react-page-plugins-content-spacer {
10 |   outline: none;
11 | }
12 | 
13 | .react-page-plugins-content-spacer
14 |   > .react-resizable
15 |   > .react-resizable-handle:before,
16 | .react-page-plugins-content-spacer
17 |   > .react-resizable
18 |   > .react-resizable-handle:hover:before {
19 |   content: ' ';
20 |   position: absolute;
21 |   text-align: center;
22 |   width: 100%;
23 |   bottom: 0;
24 |   right: 0;
25 |   cursor: n-resize;
26 |   line-height: 12px;
27 |   font-size: 1.5em;
28 |   height: 24px;
29 | }
30 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/src/index.tsx:
--------------------------------------------------------------------------------
 1 | import createPlugin from './createPlugin';
 2 | 
 3 | import SpacerHtmlRenderer from './Renderer/SpacerHtmlRenderer';
 4 | 
 5 | const plugin = createPlugin({
 6 |   Renderer: SpacerHtmlRenderer,
 7 | });
 8 | 
 9 | export default plugin;
10 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/src/types/settings.ts:
--------------------------------------------------------------------------------
 1 | import type { CellPluginComponentProps } from '@react-page/editor';
 2 | import type { SpacerState } from './state';
 3 | import type { Translations } from './translations';
 4 | 
 5 | export interface SpacerSettings {
 6 |   Renderer: React.ComponentType<CellPluginComponentProps<SpacerState>>;
 7 | 
 8 |   translations?: Translations;
 9 | }
10 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/src/types/state.ts:
--------------------------------------------------------------------------------
1 | export type SpacerState = {
2 |   height: number;
3 | };
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/src/types/translations.ts:
--------------------------------------------------------------------------------
1 | import type { defaultTranslations } from '../default/settings';
2 | 
3 | export type Translations = typeof defaultTranslations;
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/tsconfig-es.json:
--------------------------------------------------------------------------------
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "lib-es",
5 |     "module": "esnext"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/plugins/content/spacer/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "../../../tsconfig.settings.json",
 3 |   "compilerOptions": {
 4 |     "rootDir": "src",
 5 |     "outDir": "lib"
 6 |   },
 7 |   "include": ["src"],
 8 |   "exclude": ["lib", "node_modules", "src/**/__tests__/**/*.*"],
 9 |   "references": [{ "path": "../../../editor" }]
10 | }
11 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/.npmignore:
--------------------------------------------------------------------------------
1 | src/**/*


--------------------------------------------------------------------------------
/packages/plugins/content/video/babel.config.js:
--------------------------------------------------------------------------------
1 | const vendor = require('../../../../babel.config.js');
2 | module.exports = Object.assign({}, vendor);
3 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@react-page/plugins-video",
 3 |   "version": "0.0.0",
 4 |   "main": "./lib/index.js",
 5 |   "module": "./lib-es/index.js",
 6 |   "sideEffects": false,
 7 |   "typings": "./lib/index.d.ts",
 8 |   "author": "ORY GmbH",
 9 |   "license": "MIT",
10 |   "scripts": {
11 |     "build": "npm-run-all --parallel build:lib build:css",
12 |     "build:watch": "npm-run-all --parallel build:lib:watch build:css:watch",
13 |     "build:lib": "tsc -p ./tsconfig.json && tsc -p ./tsconfig-es.json",
14 |     "build:lib:watch": "yarn build:lib -- --watch",
15 |     "build:css": "postcss --config ../../../../config/postcss.config.js --dir lib/ src/index.css",
16 |     "build:css:watch": "npm-run-all build:css -- -w",
17 |     "docs": "documentation build ./lib/**/*.js --format md --github -o ../../../../docs/api/plugins/video.md",
18 |     "clean": "rimraf \"lib\" && rimraf \"lib-es\" && rm -f *.tsbuildinfo"
19 |   },
20 |   "peerDependencies": {
21 |     "@mui/material": "*",
22 |     "react": ">= 16.14",
23 |     "react-dom": ">= 16.14"
24 |   },
25 |   "dependencies": {
26 |     "@mui/icons-material": "^5.8.0",
27 |     "@react-page/editor": "0.0.0",
28 |     "react-player": "^2.10.1"
29 |   },
30 |   "devDependencies": {},
31 |   "publishConfig": {
32 |     "access": "public"
33 |   }
34 | }
35 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/Renderer/index.css:
--------------------------------------------------------------------------------
1 | .react-page-plugins-content-video-placeholder {
2 |   position: relative;
3 |   width: 100%;
4 |   text-align: center;
5 | }
6 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/common/styles.ts:
--------------------------------------------------------------------------------
 1 | import type React from 'react';
 2 | export const iconStyle: React.CSSProperties = {
 3 |   width: '100%',
 4 |   height: 'auto',
 5 |   padding: '0',
 6 |   color: '#aaa',
 7 |   textAlign: 'center',
 8 |   minWidth: 64,
 9 |   minHeight: 64,
10 |   maxHeight: 256,
11 | };
12 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/createPlugin.tsx:
--------------------------------------------------------------------------------
 1 | import type { CellPlugin } from '@react-page/editor';
 2 | 
 3 | import { defaultSettings } from './default/settings';
 4 | 
 5 | import type { VideoSettings } from './types/settings';
 6 | import type { VideoState } from './types/state';
 7 | 
 8 | const createPlugin: (settings: VideoSettings) => CellPlugin<VideoState> = (
 9 |   settings
10 | ) => {
11 |   const mergedSettings = { ...defaultSettings, ...settings };
12 | 
13 |   return {
14 |     controls: {
15 |       type: 'autoform',
16 | 
17 |       schema: {
18 |         required: ['src'],
19 |         type: 'object',
20 |         properties: {
21 |           src: {
22 |             type: 'string',
23 |             uniforms: {
24 |               placeholder: mergedSettings.translations?.placeholder,
25 |               label: mergedSettings.translations?.label,
26 |             },
27 |           },
28 |         },
29 |       },
30 |     },
31 |     Renderer: mergedSettings.Renderer,
32 |     id: 'ory/editor/core/content/video',
33 |     version: 1,
34 |     icon: mergedSettings.icon,
35 |     title: mergedSettings.translations?.pluginName,
36 |     description: mergedSettings.translations?.pluginDescription,
37 |     isInlineable: true,
38 |   };
39 | };
40 | 
41 | export default createPlugin;
42 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/default/settings.tsx:
--------------------------------------------------------------------------------
 1 | import React from 'react';
 2 | import type { VideoSettings } from '../types/settings';
 3 | import { lazyLoad } from '@react-page/editor';
 4 | 
 5 | const PlayArrow = lazyLoad(() => import('@mui/icons-material/PlayArrow'));
 6 | 
 7 | export const defaultTranslations = {
 8 |   pluginName: 'Video',
 9 |   pluginDescription: 'Include videos from Vimeo or YouTube',
10 |   label: 'Video location (YouTube / Vimeo)',
11 |   placeholder: 'https://www.youtube.com/watch?v=ER97mPHhgtM',
12 | };
13 | 
14 | export const defaultSettings: VideoSettings = {
15 |   Renderer: () => <>Renderer; for this plugin was not provided </>,
16 |   translations: defaultTranslations,
17 |   icon: <PlayArrow />,
18 | };
19 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/default/state.ts:
--------------------------------------------------------------------------------
1 | import type { VideoState } from './../types/state';
2 | export const defaultVideoState: VideoState = {
3 |   src: '',
4 | };
5 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/index.css:
--------------------------------------------------------------------------------
1 | @import './Renderer/index.css';
2 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/index.tsx:
--------------------------------------------------------------------------------
 1 | import createPlugin from './createPlugin';
 2 | 
 3 | import VideoHtmlRenderer from './Renderer/VideoHtmlRenderer';
 4 | 
 5 | const plugin = createPlugin({
 6 |   Renderer: VideoHtmlRenderer,
 7 | });
 8 | 
 9 | export default plugin;
10 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/types/api.ts:
--------------------------------------------------------------------------------
1 | export interface VideoApi {
2 |   changeSrcPreview: (src: string) => void;
3 |   commitSrc: () => void;
4 | }
5 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/types/component.ts:
--------------------------------------------------------------------------------
1 | import type { CellPluginComponentProps } from '@react-page/editor';
2 | 
3 | import type { VideoState } from './state';
4 | 
5 | export type VideoProps = CellPluginComponentProps<VideoState>;
6 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/types/controls.ts:
--------------------------------------------------------------------------------
1 | import type { VideoProps } from './component';
2 | import type { VideoApi } from './api';
3 | 
4 | export type VideoControlsProps = VideoProps & VideoApi;
5 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/types/renderer.ts:
--------------------------------------------------------------------------------
1 | import type { VideoProps } from './component';
2 | 
3 | export type VideoHtmlRendererProps = VideoProps;
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/types/settings.ts:
--------------------------------------------------------------------------------
 1 | import type { VideoHtmlRendererProps } from './renderer';
 2 | import type { Translations } from './translations';
 3 | 
 4 | export type VideoSettings = {
 5 |   Renderer: React.ComponentType<VideoHtmlRendererProps>;
 6 | 
 7 |   placeholder?: string;
 8 |   label?: string;
 9 |   translations?: Translations;
10 |   icon?: React.ReactNode;
11 | };
12 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/types/state.ts:
--------------------------------------------------------------------------------
1 | export type VideoState = {
2 |   src: string;
3 | };
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/src/types/translations.ts:
--------------------------------------------------------------------------------
1 | import type { defaultTranslations } from '../default/settings';
2 | 
3 | export type Translations = typeof defaultTranslations;
4 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/tsconfig-es.json:
--------------------------------------------------------------------------------
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "lib-es",
5 |     "module": "esnext"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/plugins/content/video/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "../../../tsconfig.settings.json",
 3 |   "compilerOptions": {
 4 |     "rootDir": "src",
 5 |     "outDir": "lib"
 6 |   },
 7 |   "include": ["src"],
 8 |   "exclude": ["lib", "node_modules", "src/**/__tests__/**/*.*"],
 9 |   "references": [{ "path": "../../../editor" }]
10 | }
11 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/.npmignore:
--------------------------------------------------------------------------------
1 | src/**/*


--------------------------------------------------------------------------------
/packages/plugins/layout/background/babel.config.js:
--------------------------------------------------------------------------------
1 | const vendor = require('../../../../babel.config.js');
2 | module.exports = Object.assign({}, vendor);
3 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@react-page/plugins-background",
 3 |   "version": "0.0.0",
 4 |   "main": "./lib/index.js",
 5 |   "module": "./lib-es/index.js",
 6 |   "sideEffects": false,
 7 |   "author": "ORY GmbH",
 8 |   "license": "MIT",
 9 |   "scripts": {
10 |     "build": "npm-run-all --parallel build:lib build:css",
11 |     "build:watch": "npm-run-all --parallel build:lib:watch build:css:watch",
12 |     "build:lib": "tsc -p ./tsconfig.json && tsc -p ./tsconfig-es.json",
13 |     "build:lib:watch": "yarn build:lib -- --watch",
14 |     "build:css": "postcss --config ../../../../config/postcss.config.js --dir lib/ src/index.css",
15 |     "build:css:watch": "npm-run-all build:css -- -w",
16 |     "docs": "documentation build ./lib/**/*.js --format md --github -o ../../../../docs/api/plugins/background.md",
17 |     "clean": "rimraf \"lib\" && rimraf \"lib-es\" && rm -f *.tsbuildinfo"
18 |   },
19 |   "peerDependencies": {
20 |     "@mui/material": "*",
21 |     "react": ">= 16.14",
22 |     "react-dom": ">= 16.14"
23 |   },
24 |   "dependencies": {
25 |     "@mui/icons-material": "^5.8.0",
26 |     "@react-page/editor": "0.0.0"
27 |   },
28 |   "devDependencies": {},
29 |   "publishConfig": {
30 |     "access": "public"
31 |   }
32 | }
33 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/const/mode.ts:
--------------------------------------------------------------------------------
1 | export const IMAGE_MODE_FLAG = 1;
2 | export const COLOR_MODE_FLAG = 2;
3 | export const GRADIENT_MODE_FLAG = 4;
4 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/index.css:
--------------------------------------------------------------------------------
 1 | .react-page-plugins-layout-background {
 2 |   background-position: center;
 3 |   background-repeat: no-repeat;
 4 |   background-size: cover;
 5 |   color: white;
 6 |   padding: 12px;
 7 |   position: relative;
 8 | }
 9 | 
10 | .react-page-plugins-layout-background > .react-page-row {
11 |   position: relative;
12 | }
13 | 
14 | .react-page-plugins-layout-background__backstretch {
15 |   position: absolute;
16 |   top: 0;
17 |   left: 0;
18 |   right: 0;
19 |   bottom: 0;
20 | }
21 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/index.tsx:
--------------------------------------------------------------------------------
 1 | import type { BackgroundSettings } from './types/settings';
 2 | import createPlugin from './createPlugin';
 3 | 
 4 | import BackgroundHtmlRenderer from './Renderer/BackgroundHtmlRenderer';
 5 | import type { MakeOptional } from './types/makeOptional';
 6 | import { ModeEnum } from './types/ModeEnum';
 7 | 
 8 | export { ModeEnum };
 9 | import { lazyLoad } from '@react-page/editor';
10 | 
11 | const BackgroundDefaultControls = lazyLoad(() => import('./Controls/Controls'));
12 | 
13 | export default (
14 |   settings: MakeOptional<BackgroundSettings, 'Renderer' | 'Controls'>
15 | ) => {
16 |   const plugin = createPlugin({
17 |     Controls: BackgroundDefaultControls,
18 |     Renderer: BackgroundHtmlRenderer,
19 |     ...settings,
20 |   });
21 |   return plugin;
22 | };
23 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/ModeEnum.ts:
--------------------------------------------------------------------------------
1 | export enum ModeEnum {
2 |   IMAGE_MODE_FLAG = 1,
3 |   COLOR_MODE_FLAG = 2,
4 |   GRADIENT_MODE_FLAG = 4,
5 | }
6 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/api.ts:
--------------------------------------------------------------------------------
 1 | import type { ModeEnum } from './ModeEnum';
 2 | 
 3 | import type { ImageLoaded, RGBColor } from '@react-page/editor';
 4 | 
 5 | export interface BackgroundApi {
 6 |   handleChangeDarken: () => void;
 7 |   handleChangeDarkenPreview: (darken: number) => void;
 8 |   handleChangeLighten: () => void;
 9 |   handleChangeLightenPreview: (lighten: number) => void;
10 |   handleChangeHasPadding: () => void;
11 |   handleChangeModeSwitch: (
12 |     mode: ModeEnum | undefined,
13 |     modeFlag: ModeEnum | undefined
14 |   ) => () => void;
15 |   handleChangeBackgroundColorPreview: (color?: RGBColor) => void;
16 |   handleChangeGradientDegPreview: (
17 |     gradientDegPreview: number | undefined,
18 |     gradientDegPreviewIndex?: number
19 |   ) => void;
20 |   handleChangeGradientOpacityPreview: (
21 |     gradientOpacityPreview: number | undefined,
22 |     gradientOpacityPreviewIndex?: number
23 |   ) => void;
24 |   handleChangeGradientColorPreview: (
25 |     gradientColorPreview: RGBColor | undefined,
26 |     gradientColorPreviewIndex?: number,
27 |     gradientColorPreviewColorIndex?: number
28 |   ) => void;
29 |   handleImageLoaded: (imagePreview: ImageLoaded) => void;
30 |   handleImageUploaded: () => void;
31 | }
32 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/component.ts:
--------------------------------------------------------------------------------
1 | import type { CellPluginComponentProps } from '@react-page/editor';
2 | import type { BackgroundSettings } from './settings';
3 | import type { BackgroundState } from './state';
4 | 
5 | export type BackgroundProps = CellPluginComponentProps<BackgroundState> &
6 |   BackgroundSettings;
7 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/controls.ts:
--------------------------------------------------------------------------------
1 | import type { BackgroundProps } from './component';
2 | 
3 | import type { BackgroundRendererExtraProps } from './renderer';
4 | 
5 | export type BackgroundControlsProps = BackgroundProps &
6 |   BackgroundRendererExtraProps;
7 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/gradient.ts:
--------------------------------------------------------------------------------
1 | import type { RGBColor } from '@react-page/editor';
2 | 
3 | export type Gradient = {
4 |   opacity: number;
5 |   deg: number;
6 |   colors?: { color?: RGBColor }[];
7 | };
8 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/makeOptional.ts:
--------------------------------------------------------------------------------
1 | import type { Omit } from './omit';
2 | export type MakeOptional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
3 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/omit.ts:
--------------------------------------------------------------------------------
1 | export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
2 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/renderer.ts:
--------------------------------------------------------------------------------
 1 | import type { BackgroundProps } from './component';
 2 | import type { ImageLoaded, RGBColor } from '@react-page/editor';
 3 | 
 4 | export interface BackgroundRendererExtraProps {
 5 |   backgroundColorPreview?: RGBColor;
 6 |   gradientDegPreview?: number;
 7 |   gradientDegPreviewIndex?: number;
 8 |   gradientOpacityPreview?: number;
 9 |   gradientOpacityPreviewIndex?: number;
10 |   gradientColorPreview?: RGBColor;
11 |   gradientColorPreviewIndex?: number;
12 |   gradientColorPreviewColorIndex?: number;
13 |   darkenPreview?: number;
14 |   lightenPreview?: number;
15 |   imagePreview?: ImageLoaded;
16 | }
17 | 
18 | export type BackgroundRendererProps = BackgroundProps &
19 |   BackgroundRendererExtraProps;
20 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/settings.ts:
--------------------------------------------------------------------------------
 1 | import type { CellPlugin, ImageUploadType, RGBColor } from '@react-page/editor';
 2 | 
 3 | import type { BackgroundControlsProps } from './controls';
 4 | import type { ModeEnum } from './ModeEnum';
 5 | import type { BackgroundRendererProps } from './renderer';
 6 | import type { BackgroundState } from './state';
 7 | import type { Translations } from './translations';
 8 | 
 9 | export type BackgroundSettings = {
10 |   Renderer: React.ComponentType<BackgroundRendererProps>;
11 |   Controls: React.ComponentType<BackgroundControlsProps>;
12 |   enabledModes?: ModeEnum;
13 |   getInitialChildren?: CellPlugin<BackgroundState>['createInitialChildren'];
14 |   defaultBackgroundColor?: RGBColor;
15 |   defaultGradientColor?: RGBColor;
16 |   defaultGradientSecondaryColor?: RGBColor;
17 |   defaultMode?: ModeEnum;
18 |   defaultModeFlag?: ModeEnum;
19 |   defaultDarken?: number;
20 |   defaultLighten?: number;
21 |   defaultHasPadding?: boolean;
22 |   defaultIsParallax?: boolean;
23 |   imageUpload?: ImageUploadType;
24 |   translations?: Translations;
25 |   cellStyle?: CellPlugin<BackgroundState>['cellStyle'];
26 | };
27 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/state.ts:
--------------------------------------------------------------------------------
 1 | import type { RGBColor } from '@react-page/editor';
 2 | import type { Gradient } from './gradient';
 3 | import type { ModeEnum } from './ModeEnum';
 4 | 
 5 | export type BackgroundState = {
 6 |   background: string;
 7 |   backgroundColor: RGBColor;
 8 |   isParallax: boolean;
 9 |   modeFlag: ModeEnum;
10 |   padding: number;
11 |   lighten: number;
12 |   darken: number;
13 |   hasPadding: boolean;
14 |   gradients: Gradient[];
15 | };
16 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/src/types/translations.ts:
--------------------------------------------------------------------------------
1 | import type { defaultTranslations } from '../default/settings';
2 | 
3 | export type Translations = typeof defaultTranslations;
4 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/tsconfig-es.json:
--------------------------------------------------------------------------------
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "lib-es",
5 |     "module": "esnext"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/plugins/layout/background/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "../../../tsconfig.settings.json",
 3 |   "compilerOptions": {
 4 |     "rootDir": "src",
 5 |     "outDir": "lib"
 6 |   },
 7 |   "include": ["src"],
 8 |   "exclude": ["lib", "node_modules", "src/**/__tests__/**/*.*"],
 9 |   "references": [{ "path": "../../../editor" }]
10 | }
11 | 


--------------------------------------------------------------------------------
/packages/react-admin/.npmignore:
--------------------------------------------------------------------------------
1 | src/**/*


--------------------------------------------------------------------------------
/packages/react-admin/README.md:
--------------------------------------------------------------------------------
1 | # ReadMe
2 | 
3 | see the ReactAdmin example in the docs
4 | 


--------------------------------------------------------------------------------
/packages/react-admin/babel.config.js:
--------------------------------------------------------------------------------
1 | const vendor = require('../../../babel.config.js');
2 | module.exports = Object.assign({}, vendor);
3 | 


--------------------------------------------------------------------------------
/packages/react-admin/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "@react-page/react-admin",
 3 |   "version": "0.0.0",
 4 |   "main": "./lib/index.js",
 5 |   "module": "./lib-es/index.js",
 6 |   "sideEffects": false,
 7 |   "typings": "./lib/index.d.ts",
 8 |   "author": "Panter AG",
 9 |   "license": "MIT",
10 |   "scripts": {
11 |     "build": "npm-run-all --parallel build:lib",
12 |     "build:watch": "npm-run-all --parallel build:lib:watch",
13 |     "build:lib": "tsc -p ./tsconfig.json && tsc -p ./tsconfig-es.json",
14 |     "build:lib:watch": "yarn build:lib -- --watch",
15 |     "clean": "rimraf \"lib\" && rimraf \"lib-es\" && rm -f *.tsbuildinfo"
16 |   },
17 |   "peerDependencies": {
18 |     "@mui/material": "*",
19 |     "react": ">= 16.14",
20 |     "react-admin": "^3.0.0",
21 |     "react-dom": ">= 16.14",
22 |     "react-final-form": "*",
23 |     "uniforms": "*"
24 |   },
25 |   "dependencies": {
26 |     "@mui/icons-material": "^5.8.0",
27 |     "@react-page/editor": "0.0.0"
28 |   },
29 |   "devDependencies": {
30 |     "react-admin": "^3.12.2",
31 |     "uniforms": "^3.2.0"
32 |   },
33 |   "publishConfig": {
34 |     "access": "public"
35 |   }
36 | }
37 | 


--------------------------------------------------------------------------------
/packages/react-admin/src/RaReactPageInput.tsx:
--------------------------------------------------------------------------------
 1 | import { Paper } from '@mui/material';
 2 | import type { EditorProps } from '@react-page/editor';
 3 | import Editor from '@react-page/editor';
 4 | import React from 'react';
 5 | 
 6 | import { Labeled, useInput } from 'react-admin';
 7 | 
 8 | export type RaReactPageInputProps = {
 9 |   label?: string;
10 |   source: string;
11 |   style?: React.CSSProperties;
12 | } & EditorProps;
13 | const RaReactPageInput: React.FC<RaReactPageInputProps> = ({
14 |   label = 'Content',
15 |   source,
16 |   style,
17 |   ...editorProps
18 | }) => {
19 |   const {
20 |     input: { value, onChange },
21 |   } = useInput({ source });
22 |   return (
23 |     <Labeled label={label} source={source} fullWidth>
24 |       <>
25 |         <Paper
26 |           elevation={5}
27 |           style={{
28 |             overflow: 'visible',
29 |             padding: 16,
30 |             marginRight: 64,
31 | 
32 |             ...style,
33 |           }}
34 |         >
35 |           <Editor value={value} onChange={onChange} {...editorProps} />
36 |         </Paper>
37 |       </>
38 |     </Labeled>
39 |   );
40 | };
41 | 
42 | export default RaReactPageInput;
43 | 


--------------------------------------------------------------------------------
/packages/react-admin/src/index.tsx:
--------------------------------------------------------------------------------
1 | import { lazyLoad } from '@react-page/editor';
2 | 
3 | // lazyload everything to avoid accidental bundle size increase
4 | export const RaReactPageInput = lazyLoad(() => import('./RaReactPageInput'));
5 | export const RaSelectReferenceInputField = lazyLoad(
6 |   () => import('./RaSelectReferenceInputField')
7 | );
8 | 


--------------------------------------------------------------------------------
/packages/react-admin/tsconfig-es.json:
--------------------------------------------------------------------------------
1 | {
2 |   "extends": "./tsconfig.json",
3 |   "compilerOptions": {
4 |     "outDir": "lib-es",
5 |     "module": "esnext"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/packages/react-admin/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "../tsconfig.settings.json",
 3 |   "compilerOptions": {
 4 |     "rootDir": "src",
 5 |     "outDir": "lib"
 6 |   },
 7 |   "include": ["src"],
 8 |   "exclude": ["lib", "node_modules", "src/**/__tests__/**/*.*"],
 9 |   "references": [{ "path": "../editor" }]
10 | }
11 | 


--------------------------------------------------------------------------------
/packages/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "files": [],
 3 |   "references": [
 4 |     { "path": "editor" },
 5 | 
 6 |     { "path": "plugins/content/divider" },
 7 |     { "path": "plugins/content/html5-video" },
 8 |     { "path": "plugins/content/image" },
 9 | 
10 |     { "path": "plugins/content/slate" },
11 |     { "path": "plugins/content/spacer" },
12 |     { "path": "plugins/content/video" },
13 |     { "path": "plugins/layout/background" },
14 |     { "path": "react-admin" }
15 |   ]
16 | }
17 | 


--------------------------------------------------------------------------------
/packages/tsconfig.settings.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "compilerOptions": {
 3 |     "incremental": true,
 4 |     "downlevelIteration": true,
 5 |     "rootDirs": ["src"],
 6 |     "outDir": "lib",
 7 |     "strict": true,
 8 |     "moduleResolution": "node",
 9 |     "target": "es5",
10 |     "module": "commonjs",
11 |     "jsx": "react",
12 |     "experimentalDecorators": true,
13 |     "esModuleInterop": true,
14 |     "sourceMap": true,
15 |     "skipLibCheck": true,
16 |     "skipDefaultLibCheck": true,
17 |     "noUnusedLocals": false,
18 |     "declaration": true,
19 |     "declarationMap": true,
20 |     "composite": true,
21 |     "lib": ["es7", "dom"],
22 |     "types": ["node", "jest"]
23 |   }
24 | }
25 | 


--------------------------------------------------------------------------------