@elementor/editor-ui 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +16 -0
- package/dist/index.d.mts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +37 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/components/editable-field.tsx +2 -2
- package/src/components/introduction-modal.tsx +39 -0
- package/src/hooks/__tests__/use-editable.test.ts +51 -0
- package/src/hooks/use-editable.ts +9 -3
- package/src/index.ts +1 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @elementor/editor-ui@0.
|
|
2
|
+
> @elementor/editor-ui@0.4.0 build
|
|
3
3
|
> tsup --config=../../tsup.build.ts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[32mESM[39m [1mdist/index.mjs [22m[
|
|
14
|
-
[32mESM[39m [1mdist/index.mjs.map [22m[
|
|
15
|
-
[32mESM[39m ⚡️ Build success in
|
|
16
|
-
[32mCJS[39m [1mdist/index.js [22m[
|
|
17
|
-
[32mCJS[39m [1mdist/index.js.map [22m[
|
|
18
|
-
[32mCJS[39m ⚡️ Build success in
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m5.24 KB[39m
|
|
14
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m10.46 KB[39m
|
|
15
|
+
[32mESM[39m ⚡️ Build success in 140ms
|
|
16
|
+
[32mCJS[39m [1mdist/index.js [22m[32m7.12 KB[39m
|
|
17
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m10.75 KB[39m
|
|
18
|
+
[32mCJS[39m ⚡️ Build success in 152ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m1.
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m1.
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 42754ms
|
|
21
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m1.75 KB[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m1.75 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @elementor/editor-ui
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b001371: Prevent editable field validation for initial value.
|
|
8
|
+
|
|
9
|
+
## 0.3.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- dd8654a: Add introduction modal to class manager panel
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 158d092: Set `EditableField` component to full width.
|
|
18
|
+
|
|
3
19
|
## 0.2.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -9,10 +9,18 @@ declare const EllipsisWithTooltip: <T extends React$1.ElementType>({ maxWidth, t
|
|
|
9
9
|
|
|
10
10
|
declare const EditableField: React$1.ForwardRefExoticComponent<Omit<any, "ref"> & React$1.RefAttributes<unknown>>;
|
|
11
11
|
|
|
12
|
+
type IntroductionModalProps = {
|
|
13
|
+
open: boolean;
|
|
14
|
+
handleClose: (shouldShowAgain: boolean) => void;
|
|
15
|
+
title: string;
|
|
16
|
+
content: React$1.ReactNode;
|
|
17
|
+
};
|
|
18
|
+
declare const IntroductionModal: ({ open, handleClose, title, content }: IntroductionModalProps) => React$1.JSX.Element;
|
|
19
|
+
|
|
12
20
|
type UseEditableParams = {
|
|
13
21
|
value: string;
|
|
14
22
|
onSubmit: (value: string) => unknown;
|
|
15
|
-
validation?: (value: string) => string |
|
|
23
|
+
validation?: (value: string) => string | null;
|
|
16
24
|
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
17
25
|
};
|
|
18
26
|
declare const useEditable: ({ value, onSubmit, validation, onClick }: UseEditableParams) => {
|
|
@@ -21,7 +29,7 @@ declare const useEditable: ({ value, onSubmit, validation, onClick }: UseEditabl
|
|
|
21
29
|
readonly openEditMode: () => void;
|
|
22
30
|
readonly closeEditMode: () => void;
|
|
23
31
|
readonly value: string;
|
|
24
|
-
readonly error: string | null
|
|
32
|
+
readonly error: string | null;
|
|
25
33
|
readonly getProps: () => {
|
|
26
34
|
suppressContentEditableWarning?: boolean | undefined;
|
|
27
35
|
value: string;
|
|
@@ -34,4 +42,4 @@ declare const useEditable: ({ value, onSubmit, validation, onClick }: UseEditabl
|
|
|
34
42
|
};
|
|
35
43
|
};
|
|
36
44
|
|
|
37
|
-
export { EditableField, EllipsisWithTooltip, useEditable };
|
|
45
|
+
export { EditableField, EllipsisWithTooltip, IntroductionModal, useEditable };
|
package/dist/index.d.ts
CHANGED
|
@@ -9,10 +9,18 @@ declare const EllipsisWithTooltip: <T extends React$1.ElementType>({ maxWidth, t
|
|
|
9
9
|
|
|
10
10
|
declare const EditableField: React$1.ForwardRefExoticComponent<Omit<any, "ref"> & React$1.RefAttributes<unknown>>;
|
|
11
11
|
|
|
12
|
+
type IntroductionModalProps = {
|
|
13
|
+
open: boolean;
|
|
14
|
+
handleClose: (shouldShowAgain: boolean) => void;
|
|
15
|
+
title: string;
|
|
16
|
+
content: React$1.ReactNode;
|
|
17
|
+
};
|
|
18
|
+
declare const IntroductionModal: ({ open, handleClose, title, content }: IntroductionModalProps) => React$1.JSX.Element;
|
|
19
|
+
|
|
12
20
|
type UseEditableParams = {
|
|
13
21
|
value: string;
|
|
14
22
|
onSubmit: (value: string) => unknown;
|
|
15
|
-
validation?: (value: string) => string |
|
|
23
|
+
validation?: (value: string) => string | null;
|
|
16
24
|
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
17
25
|
};
|
|
18
26
|
declare const useEditable: ({ value, onSubmit, validation, onClick }: UseEditableParams) => {
|
|
@@ -21,7 +29,7 @@ declare const useEditable: ({ value, onSubmit, validation, onClick }: UseEditabl
|
|
|
21
29
|
readonly openEditMode: () => void;
|
|
22
30
|
readonly closeEditMode: () => void;
|
|
23
31
|
readonly value: string;
|
|
24
|
-
readonly error: string | null
|
|
32
|
+
readonly error: string | null;
|
|
25
33
|
readonly getProps: () => {
|
|
26
34
|
suppressContentEditableWarning?: boolean | undefined;
|
|
27
35
|
value: string;
|
|
@@ -34,4 +42,4 @@ declare const useEditable: ({ value, onSubmit, validation, onClick }: UseEditabl
|
|
|
34
42
|
};
|
|
35
43
|
};
|
|
36
44
|
|
|
37
|
-
export { EditableField, EllipsisWithTooltip, useEditable };
|
|
45
|
+
export { EditableField, EllipsisWithTooltip, IntroductionModal, useEditable };
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
EditableField: () => EditableField,
|
|
34
34
|
EllipsisWithTooltip: () => EllipsisWithTooltip,
|
|
35
|
+
IntroductionModal: () => IntroductionModal,
|
|
35
36
|
useEditable: () => useEditable
|
|
36
37
|
});
|
|
37
38
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -85,17 +86,41 @@ var React2 = __toESM(require("react"));
|
|
|
85
86
|
var import_react2 = require("react");
|
|
86
87
|
var import_ui2 = require("@elementor/ui");
|
|
87
88
|
var EditableField = (0, import_react2.forwardRef)(
|
|
88
|
-
({ value, error, as: Component = "span", ...props }, ref) => {
|
|
89
|
-
return /* @__PURE__ */ React2.createElement(import_ui2.Tooltip, { title: error, open: !!error, placement: "top" }, /* @__PURE__ */ React2.createElement(Component, { ref, ...props }, value));
|
|
89
|
+
({ value, error, as: Component = "span", sx, ...props }, ref) => {
|
|
90
|
+
return /* @__PURE__ */ React2.createElement(import_ui2.Tooltip, { title: error, open: !!error, placement: "top" }, /* @__PURE__ */ React2.createElement(Component, { ref, sx: { width: "100%", ...sx }, ...props }, value));
|
|
90
91
|
}
|
|
91
92
|
);
|
|
92
93
|
|
|
93
|
-
// src/
|
|
94
|
+
// src/components/introduction-modal.tsx
|
|
95
|
+
var React3 = __toESM(require("react"));
|
|
94
96
|
var import_react3 = require("react");
|
|
97
|
+
var import_ui3 = require("@elementor/ui");
|
|
98
|
+
var import_i18n = require("@wordpress/i18n");
|
|
99
|
+
var IntroductionModal = ({ open, handleClose, title, content }) => {
|
|
100
|
+
const [shouldShowAgain, setShouldShowAgain] = (0, import_react3.useState)(true);
|
|
101
|
+
return /* @__PURE__ */ React3.createElement(import_ui3.Dialog, { open, onClose: handleClose, maxWidth: "sm" }, /* @__PURE__ */ React3.createElement(import_ui3.DialogHeader, { logo: false }, /* @__PURE__ */ React3.createElement(import_ui3.DialogTitle, null, title)), content, /* @__PURE__ */ React3.createElement(import_ui3.DialogActions, null, /* @__PURE__ */ React3.createElement(
|
|
102
|
+
import_ui3.FormControlLabel,
|
|
103
|
+
{
|
|
104
|
+
sx: { marginRight: "auto" },
|
|
105
|
+
control: /* @__PURE__ */ React3.createElement(
|
|
106
|
+
import_ui3.Checkbox,
|
|
107
|
+
{
|
|
108
|
+
checked: !shouldShowAgain,
|
|
109
|
+
onChange: () => setShouldShowAgain(!shouldShowAgain)
|
|
110
|
+
}
|
|
111
|
+
),
|
|
112
|
+
label: (0, import_i18n.__)("Don't show this again")
|
|
113
|
+
}
|
|
114
|
+
), /* @__PURE__ */ React3.createElement(import_ui3.Button, { size: "medium", onClick: () => handleClose(shouldShowAgain), variant: "contained" }, (0, import_i18n.__)("Got it"))));
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// src/hooks/use-editable.ts
|
|
118
|
+
var import_react4 = require("react");
|
|
95
119
|
var useEditable = ({ value, onSubmit, validation, onClick }) => {
|
|
96
|
-
const [isEditing, setIsEditing] = (0,
|
|
97
|
-
const [error, setError] = (0,
|
|
120
|
+
const [isEditing, setIsEditing] = (0, import_react4.useState)(false);
|
|
121
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
98
122
|
const ref = useSelection(isEditing);
|
|
123
|
+
const isDirty = (newValue) => newValue !== value;
|
|
99
124
|
const openEditMode = () => {
|
|
100
125
|
setIsEditing(true);
|
|
101
126
|
};
|
|
@@ -105,6 +130,9 @@ var useEditable = ({ value, onSubmit, validation, onClick }) => {
|
|
|
105
130
|
setIsEditing(false);
|
|
106
131
|
};
|
|
107
132
|
const submit = (newValue) => {
|
|
133
|
+
if (!isDirty(newValue)) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
108
136
|
if (!error) {
|
|
109
137
|
try {
|
|
110
138
|
onSubmit(newValue);
|
|
@@ -116,7 +144,7 @@ var useEditable = ({ value, onSubmit, validation, onClick }) => {
|
|
|
116
144
|
const onChange = (event) => {
|
|
117
145
|
const { innerText: newValue } = event.target;
|
|
118
146
|
if (validation) {
|
|
119
|
-
setError(validation(newValue));
|
|
147
|
+
setError(isDirty(newValue) ? validation(newValue) : null);
|
|
120
148
|
}
|
|
121
149
|
};
|
|
122
150
|
const handleKeyDown = (event) => {
|
|
@@ -160,8 +188,8 @@ var useEditable = ({ value, onSubmit, validation, onClick }) => {
|
|
|
160
188
|
};
|
|
161
189
|
};
|
|
162
190
|
var useSelection = (isEditing) => {
|
|
163
|
-
const ref = (0,
|
|
164
|
-
(0,
|
|
191
|
+
const ref = (0, import_react4.useRef)(null);
|
|
192
|
+
(0, import_react4.useEffect)(() => {
|
|
165
193
|
if (isEditing) {
|
|
166
194
|
selectAll(ref.current);
|
|
167
195
|
}
|
|
@@ -182,6 +210,7 @@ var selectAll = (el) => {
|
|
|
182
210
|
0 && (module.exports = {
|
|
183
211
|
EditableField,
|
|
184
212
|
EllipsisWithTooltip,
|
|
213
|
+
IntroductionModal,
|
|
185
214
|
useEditable
|
|
186
215
|
});
|
|
187
216
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/ellipsis-with-tooltip.tsx","../src/components/editable-field.tsx","../src/hooks/use-editable.ts"],"sourcesContent":["// components\nexport { EllipsisWithTooltip } from './components/ellipsis-with-tooltip';\nexport { EditableField } from './components/editable-field';\n\n// hooks\nexport { useEditable } from './hooks/use-editable';\n","import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { Box, Tooltip } from '@elementor/ui';\n\ntype EllipsisWithTooltipProps< T extends React.ElementType > = {\n\tmaxWidth?: React.CSSProperties[ 'maxWidth' ];\n\ttitle: string;\n\tas?: T;\n} & React.ComponentProps< T >;\n\nexport const EllipsisWithTooltip = < T extends React.ElementType >( {\n\tmaxWidth,\n\ttitle,\n\tas,\n\t...props\n}: EllipsisWithTooltipProps< T > ) => {\n\tconst [ setRef, isOverflowing ] = useIsOverflowing();\n\n\tif ( isOverflowing ) {\n\t\treturn (\n\t\t\t<Tooltip title={ title } placement=\"top\">\n\t\t\t\t<Content maxWidth={ maxWidth } ref={ setRef } as={ as } { ...props }>\n\t\t\t\t\t{ title }\n\t\t\t\t</Content>\n\t\t\t</Tooltip>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Content maxWidth={ maxWidth } ref={ setRef } as={ as } { ...props }>\n\t\t\t{ title }\n\t\t</Content>\n\t);\n};\n\ntype ContentProps< T extends React.ElementType > = React.PropsWithChildren<\n\tOmit< EllipsisWithTooltipProps< T >, 'title' >\n>;\n\nconst Content = React.forwardRef(\n\t< T extends React.ElementType >(\n\t\t{ maxWidth, as: Component = Box, ...props }: ContentProps< T >,\n\t\t// forwardRef loses the typing when using generic components.\n\t\tref: unknown\n\t) => (\n\t\t<Component\n\t\t\tref={ ref }\n\t\t\tposition=\"relative\"\n\t\t\t{ ...props }\n\t\t\tstyle={ { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth } }\n\t\t/>\n\t)\n);\n\nconst useIsOverflowing = () => {\n\tconst [ el, setEl ] = useState< HTMLElement | null >( null );\n\tconst [ isOverflowing, setIsOverflown ] = useState( false );\n\n\tuseEffect( () => {\n\t\tconst observer = new ResizeObserver( ( [ { target } ] ) => {\n\t\t\tsetIsOverflown( target.scrollWidth > target.clientWidth );\n\t\t} );\n\n\t\tif ( el ) {\n\t\t\tobserver.observe( el );\n\t\t}\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [ el ] );\n\n\treturn [ setEl, isOverflowing ] as const;\n};\n","import * as React from 'react';\nimport { forwardRef } from 'react';\nimport { Tooltip } from '@elementor/ui';\n\ntype EditableFieldProps< T extends React.ElementType > = {\n\tvalue: string;\n\terror?: string;\n\tas?: T;\n} & React.ComponentPropsWithRef< T >;\n\nexport const EditableField = forwardRef(\n\t< T extends React.ElementType >(\n\t\t{ value, error, as: Component = 'span', ...props }: EditableFieldProps< T >,\n\t\tref: unknown\n\t) => {\n\t\treturn (\n\t\t\t<Tooltip title={ error } open={ !! error } placement=\"top\">\n\t\t\t\t<Component ref={ ref } { ...props }>\n\t\t\t\t\t{ value }\n\t\t\t\t</Component>\n\t\t\t</Tooltip>\n\t\t);\n\t}\n);\n","import { useEffect, useRef, useState } from 'react';\n\ntype UseEditableParams = {\n\tvalue: string;\n\tonSubmit: ( value: string ) => unknown;\n\tvalidation?: ( value: string ) => string | undefined | null;\n\tonClick?: ( event: React.MouseEvent< HTMLDivElement > ) => void;\n};\n\nexport const useEditable = ( { value, onSubmit, validation, onClick }: UseEditableParams ) => {\n\tconst [ isEditing, setIsEditing ] = useState( false );\n\tconst [ error, setError ] = useState< string | null | undefined >( null );\n\n\tconst ref = useSelection( isEditing );\n\n\tconst openEditMode = () => {\n\t\tsetIsEditing( true );\n\t};\n\n\tconst closeEditMode = () => {\n\t\tref.current?.blur();\n\n\t\tsetError( null );\n\t\tsetIsEditing( false );\n\t};\n\n\tconst submit = ( newValue: string ) => {\n\t\tif ( ! error ) {\n\t\t\ttry {\n\t\t\t\tonSubmit( newValue );\n\t\t\t} finally {\n\t\t\t\tcloseEditMode();\n\t\t\t}\n\t\t}\n\t};\n\n\tconst onChange = ( event: React.ChangeEvent< HTMLSpanElement > ) => {\n\t\tconst { innerText: newValue } = event.target;\n\n\t\tif ( validation ) {\n\t\t\tsetError( validation( newValue ) );\n\t\t}\n\t};\n\n\tconst handleKeyDown = ( event: React.KeyboardEvent ) => {\n\t\tevent.stopPropagation();\n\n\t\tif ( [ 'Escape' ].includes( event.key ) ) {\n\t\t\treturn closeEditMode();\n\t\t}\n\n\t\tif ( [ 'Enter' ].includes( event.key ) ) {\n\t\t\tevent.preventDefault();\n\t\t\treturn submit( ( event.target as HTMLElement ).innerText );\n\t\t}\n\t};\n\n\tconst handleClick = ( event: React.MouseEvent< HTMLDivElement > ) => {\n\t\tif ( isEditing ) {\n\t\t\tevent.stopPropagation();\n\t\t}\n\n\t\tonClick?.( event );\n\t};\n\n\tconst listeners = {\n\t\tonClick: handleClick,\n\t\tonKeyDown: handleKeyDown,\n\t\tonInput: onChange,\n\t\tonBlur: closeEditMode,\n\t} as const;\n\n\tconst attributes = {\n\t\tvalue,\n\t\trole: 'textbox',\n\t\tcontentEditable: isEditing,\n\t\t...( isEditing && {\n\t\t\tsuppressContentEditableWarning: true,\n\t\t} ),\n\t} as const;\n\n\treturn {\n\t\tref,\n\t\tisEditing,\n\t\topenEditMode,\n\t\tcloseEditMode,\n\t\tvalue,\n\t\terror,\n\t\tgetProps: () => ( { ...listeners, ...attributes } ),\n\t} as const;\n};\n\nconst useSelection = ( isEditing: boolean ) => {\n\tconst ref = useRef< HTMLElement | null >( null );\n\n\tuseEffect( () => {\n\t\tif ( isEditing ) {\n\t\t\tselectAll( ref.current );\n\t\t}\n\t}, [ isEditing ] );\n\n\treturn ref;\n};\n\nconst selectAll = ( el: HTMLElement | null ) => {\n\tconst selection = getSelection();\n\n\tif ( ! selection || ! el ) {\n\t\treturn;\n\t}\n\n\tconst range = document.createRange();\n\trange.selectNodeContents( el );\n\n\tselection.removeAllRanges();\n\tselection.addRange( range );\n};\n"],"mappings":"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","names":["React","import_react","import_ui","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/ellipsis-with-tooltip.tsx","../src/components/editable-field.tsx","../src/components/introduction-modal.tsx","../src/hooks/use-editable.ts"],"sourcesContent":["// components\nexport { EllipsisWithTooltip } from './components/ellipsis-with-tooltip';\nexport { EditableField } from './components/editable-field';\nexport { IntroductionModal } from './components/introduction-modal';\n\n// hooks\nexport { useEditable } from './hooks/use-editable';\n","import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { Box, Tooltip } from '@elementor/ui';\n\ntype EllipsisWithTooltipProps< T extends React.ElementType > = {\n\tmaxWidth?: React.CSSProperties[ 'maxWidth' ];\n\ttitle: string;\n\tas?: T;\n} & React.ComponentProps< T >;\n\nexport const EllipsisWithTooltip = < T extends React.ElementType >( {\n\tmaxWidth,\n\ttitle,\n\tas,\n\t...props\n}: EllipsisWithTooltipProps< T > ) => {\n\tconst [ setRef, isOverflowing ] = useIsOverflowing();\n\n\tif ( isOverflowing ) {\n\t\treturn (\n\t\t\t<Tooltip title={ title } placement=\"top\">\n\t\t\t\t<Content maxWidth={ maxWidth } ref={ setRef } as={ as } { ...props }>\n\t\t\t\t\t{ title }\n\t\t\t\t</Content>\n\t\t\t</Tooltip>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Content maxWidth={ maxWidth } ref={ setRef } as={ as } { ...props }>\n\t\t\t{ title }\n\t\t</Content>\n\t);\n};\n\ntype ContentProps< T extends React.ElementType > = React.PropsWithChildren<\n\tOmit< EllipsisWithTooltipProps< T >, 'title' >\n>;\n\nconst Content = React.forwardRef(\n\t< T extends React.ElementType >(\n\t\t{ maxWidth, as: Component = Box, ...props }: ContentProps< T >,\n\t\t// forwardRef loses the typing when using generic components.\n\t\tref: unknown\n\t) => (\n\t\t<Component\n\t\t\tref={ ref }\n\t\t\tposition=\"relative\"\n\t\t\t{ ...props }\n\t\t\tstyle={ { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth } }\n\t\t/>\n\t)\n);\n\nconst useIsOverflowing = () => {\n\tconst [ el, setEl ] = useState< HTMLElement | null >( null );\n\tconst [ isOverflowing, setIsOverflown ] = useState( false );\n\n\tuseEffect( () => {\n\t\tconst observer = new ResizeObserver( ( [ { target } ] ) => {\n\t\t\tsetIsOverflown( target.scrollWidth > target.clientWidth );\n\t\t} );\n\n\t\tif ( el ) {\n\t\t\tobserver.observe( el );\n\t\t}\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [ el ] );\n\n\treturn [ setEl, isOverflowing ] as const;\n};\n","import * as React from 'react';\nimport { forwardRef } from 'react';\nimport { Tooltip } from '@elementor/ui';\n\ntype EditableFieldProps< T extends React.ElementType > = {\n\tvalue: string;\n\terror?: string;\n\tas?: T;\n} & React.ComponentPropsWithRef< T >;\n\nexport const EditableField = forwardRef(\n\t< T extends React.ElementType >(\n\t\t{ value, error, as: Component = 'span', sx, ...props }: EditableFieldProps< T >,\n\t\tref: unknown\n\t) => {\n\t\treturn (\n\t\t\t<Tooltip title={ error } open={ !! error } placement=\"top\">\n\t\t\t\t<Component ref={ ref } sx={ { width: '100%', ...sx } } { ...props }>\n\t\t\t\t\t{ value }\n\t\t\t\t</Component>\n\t\t\t</Tooltip>\n\t\t);\n\t}\n);\n","import * as React from 'react';\nimport { useState } from 'react';\nimport { Button, Checkbox, Dialog, DialogActions, DialogHeader, DialogTitle, FormControlLabel } from '@elementor/ui';\nimport { __ } from '@wordpress/i18n';\n\ntype IntroductionModalProps = {\n\topen: boolean;\n\thandleClose: ( shouldShowAgain: boolean ) => void;\n\ttitle: string;\n\tcontent: React.ReactNode;\n};\n\nexport const IntroductionModal = ( { open, handleClose, title, content }: IntroductionModalProps ) => {\n\tconst [ shouldShowAgain, setShouldShowAgain ] = useState( true );\n\n\treturn (\n\t\t<Dialog open={ open } onClose={ handleClose } maxWidth={ 'sm' }>\n\t\t\t<DialogHeader logo={ false }>\n\t\t\t\t<DialogTitle>{ title }</DialogTitle>\n\t\t\t</DialogHeader>\n\t\t\t{ content }\n\t\t\t<DialogActions>\n\t\t\t\t<FormControlLabel\n\t\t\t\t\tsx={ { marginRight: 'auto' } }\n\t\t\t\t\tcontrol={\n\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\tchecked={ ! shouldShowAgain }\n\t\t\t\t\t\t\tonChange={ () => setShouldShowAgain( ! shouldShowAgain ) }\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\tlabel={ __( \"Don't show this again\" ) }\n\t\t\t\t/>\n\t\t\t\t<Button size={ 'medium' } onClick={ () => handleClose( shouldShowAgain ) } variant=\"contained\">\n\t\t\t\t\t{ __( 'Got it' ) }\n\t\t\t\t</Button>\n\t\t\t</DialogActions>\n\t\t</Dialog>\n\t);\n};\n","import { useEffect, useRef, useState } from 'react';\n\ntype UseEditableParams = {\n\tvalue: string;\n\tonSubmit: ( value: string ) => unknown;\n\tvalidation?: ( value: string ) => string | null;\n\tonClick?: ( event: React.MouseEvent< HTMLDivElement > ) => void;\n};\n\nexport const useEditable = ( { value, onSubmit, validation, onClick }: UseEditableParams ) => {\n\tconst [ isEditing, setIsEditing ] = useState( false );\n\tconst [ error, setError ] = useState< string | null >( null );\n\n\tconst ref = useSelection( isEditing );\n\n\tconst isDirty = ( newValue: string ) => newValue !== value;\n\n\tconst openEditMode = () => {\n\t\tsetIsEditing( true );\n\t};\n\n\tconst closeEditMode = () => {\n\t\tref.current?.blur();\n\n\t\tsetError( null );\n\t\tsetIsEditing( false );\n\t};\n\n\tconst submit = ( newValue: string ) => {\n\t\tif ( ! isDirty( newValue ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( ! error ) {\n\t\t\ttry {\n\t\t\t\tonSubmit( newValue );\n\t\t\t} finally {\n\t\t\t\tcloseEditMode();\n\t\t\t}\n\t\t}\n\t};\n\n\tconst onChange = ( event: React.ChangeEvent< HTMLSpanElement > ) => {\n\t\tconst { innerText: newValue } = event.target;\n\n\t\tif ( validation ) {\n\t\t\tsetError( isDirty( newValue ) ? validation( newValue ) : null );\n\t\t}\n\t};\n\n\tconst handleKeyDown = ( event: React.KeyboardEvent ) => {\n\t\tevent.stopPropagation();\n\n\t\tif ( [ 'Escape' ].includes( event.key ) ) {\n\t\t\treturn closeEditMode();\n\t\t}\n\n\t\tif ( [ 'Enter' ].includes( event.key ) ) {\n\t\t\tevent.preventDefault();\n\t\t\treturn submit( ( event.target as HTMLElement ).innerText );\n\t\t}\n\t};\n\n\tconst handleClick = ( event: React.MouseEvent< HTMLDivElement > ) => {\n\t\tif ( isEditing ) {\n\t\t\tevent.stopPropagation();\n\t\t}\n\n\t\tonClick?.( event );\n\t};\n\n\tconst listeners = {\n\t\tonClick: handleClick,\n\t\tonKeyDown: handleKeyDown,\n\t\tonInput: onChange,\n\t\tonBlur: closeEditMode,\n\t} as const;\n\n\tconst attributes = {\n\t\tvalue,\n\t\trole: 'textbox',\n\t\tcontentEditable: isEditing,\n\t\t...( isEditing && {\n\t\t\tsuppressContentEditableWarning: true,\n\t\t} ),\n\t} as const;\n\n\treturn {\n\t\tref,\n\t\tisEditing,\n\t\topenEditMode,\n\t\tcloseEditMode,\n\t\tvalue,\n\t\terror,\n\t\tgetProps: () => ( { ...listeners, ...attributes } ),\n\t} as const;\n};\n\nconst useSelection = ( isEditing: boolean ) => {\n\tconst ref = useRef< HTMLElement | null >( null );\n\n\tuseEffect( () => {\n\t\tif ( isEditing ) {\n\t\t\tselectAll( ref.current );\n\t\t}\n\t}, [ isEditing ] );\n\n\treturn ref;\n};\n\nconst selectAll = ( el: HTMLElement | null ) => {\n\tconst selection = getSelection();\n\n\tif ( ! selection || ! el ) {\n\t\treturn;\n\t}\n\n\tconst range = document.createRange();\n\trange.selectNodeContents( el );\n\n\tselection.removeAllRanges();\n\tselection.addRange( range );\n};\n"],"mappings":"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","names":["React","import_react","import_ui","React","import_react","import_ui","import_react"]}
|
package/dist/index.mjs
CHANGED
|
@@ -47,17 +47,41 @@ import * as React2 from "react";
|
|
|
47
47
|
import { forwardRef as forwardRef2 } from "react";
|
|
48
48
|
import { Tooltip as Tooltip2 } from "@elementor/ui";
|
|
49
49
|
var EditableField = forwardRef2(
|
|
50
|
-
({ value, error, as: Component = "span", ...props }, ref) => {
|
|
51
|
-
return /* @__PURE__ */ React2.createElement(Tooltip2, { title: error, open: !!error, placement: "top" }, /* @__PURE__ */ React2.createElement(Component, { ref, ...props }, value));
|
|
50
|
+
({ value, error, as: Component = "span", sx, ...props }, ref) => {
|
|
51
|
+
return /* @__PURE__ */ React2.createElement(Tooltip2, { title: error, open: !!error, placement: "top" }, /* @__PURE__ */ React2.createElement(Component, { ref, sx: { width: "100%", ...sx }, ...props }, value));
|
|
52
52
|
}
|
|
53
53
|
);
|
|
54
54
|
|
|
55
|
+
// src/components/introduction-modal.tsx
|
|
56
|
+
import * as React3 from "react";
|
|
57
|
+
import { useState as useState2 } from "react";
|
|
58
|
+
import { Button, Checkbox, Dialog, DialogActions, DialogHeader, DialogTitle, FormControlLabel } from "@elementor/ui";
|
|
59
|
+
import { __ } from "@wordpress/i18n";
|
|
60
|
+
var IntroductionModal = ({ open, handleClose, title, content }) => {
|
|
61
|
+
const [shouldShowAgain, setShouldShowAgain] = useState2(true);
|
|
62
|
+
return /* @__PURE__ */ React3.createElement(Dialog, { open, onClose: handleClose, maxWidth: "sm" }, /* @__PURE__ */ React3.createElement(DialogHeader, { logo: false }, /* @__PURE__ */ React3.createElement(DialogTitle, null, title)), content, /* @__PURE__ */ React3.createElement(DialogActions, null, /* @__PURE__ */ React3.createElement(
|
|
63
|
+
FormControlLabel,
|
|
64
|
+
{
|
|
65
|
+
sx: { marginRight: "auto" },
|
|
66
|
+
control: /* @__PURE__ */ React3.createElement(
|
|
67
|
+
Checkbox,
|
|
68
|
+
{
|
|
69
|
+
checked: !shouldShowAgain,
|
|
70
|
+
onChange: () => setShouldShowAgain(!shouldShowAgain)
|
|
71
|
+
}
|
|
72
|
+
),
|
|
73
|
+
label: __("Don't show this again")
|
|
74
|
+
}
|
|
75
|
+
), /* @__PURE__ */ React3.createElement(Button, { size: "medium", onClick: () => handleClose(shouldShowAgain), variant: "contained" }, __("Got it"))));
|
|
76
|
+
};
|
|
77
|
+
|
|
55
78
|
// src/hooks/use-editable.ts
|
|
56
|
-
import { useEffect as useEffect2, useRef, useState as
|
|
79
|
+
import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
|
|
57
80
|
var useEditable = ({ value, onSubmit, validation, onClick }) => {
|
|
58
|
-
const [isEditing, setIsEditing] =
|
|
59
|
-
const [error, setError] =
|
|
81
|
+
const [isEditing, setIsEditing] = useState3(false);
|
|
82
|
+
const [error, setError] = useState3(null);
|
|
60
83
|
const ref = useSelection(isEditing);
|
|
84
|
+
const isDirty = (newValue) => newValue !== value;
|
|
61
85
|
const openEditMode = () => {
|
|
62
86
|
setIsEditing(true);
|
|
63
87
|
};
|
|
@@ -67,6 +91,9 @@ var useEditable = ({ value, onSubmit, validation, onClick }) => {
|
|
|
67
91
|
setIsEditing(false);
|
|
68
92
|
};
|
|
69
93
|
const submit = (newValue) => {
|
|
94
|
+
if (!isDirty(newValue)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
70
97
|
if (!error) {
|
|
71
98
|
try {
|
|
72
99
|
onSubmit(newValue);
|
|
@@ -78,7 +105,7 @@ var useEditable = ({ value, onSubmit, validation, onClick }) => {
|
|
|
78
105
|
const onChange = (event) => {
|
|
79
106
|
const { innerText: newValue } = event.target;
|
|
80
107
|
if (validation) {
|
|
81
|
-
setError(validation(newValue));
|
|
108
|
+
setError(isDirty(newValue) ? validation(newValue) : null);
|
|
82
109
|
}
|
|
83
110
|
};
|
|
84
111
|
const handleKeyDown = (event) => {
|
|
@@ -143,6 +170,7 @@ var selectAll = (el) => {
|
|
|
143
170
|
export {
|
|
144
171
|
EditableField,
|
|
145
172
|
EllipsisWithTooltip,
|
|
173
|
+
IntroductionModal,
|
|
146
174
|
useEditable
|
|
147
175
|
};
|
|
148
176
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ellipsis-with-tooltip.tsx","../src/components/editable-field.tsx","../src/hooks/use-editable.ts"],"sourcesContent":["import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { Box, Tooltip } from '@elementor/ui';\n\ntype EllipsisWithTooltipProps< T extends React.ElementType > = {\n\tmaxWidth?: React.CSSProperties[ 'maxWidth' ];\n\ttitle: string;\n\tas?: T;\n} & React.ComponentProps< T >;\n\nexport const EllipsisWithTooltip = < T extends React.ElementType >( {\n\tmaxWidth,\n\ttitle,\n\tas,\n\t...props\n}: EllipsisWithTooltipProps< T > ) => {\n\tconst [ setRef, isOverflowing ] = useIsOverflowing();\n\n\tif ( isOverflowing ) {\n\t\treturn (\n\t\t\t<Tooltip title={ title } placement=\"top\">\n\t\t\t\t<Content maxWidth={ maxWidth } ref={ setRef } as={ as } { ...props }>\n\t\t\t\t\t{ title }\n\t\t\t\t</Content>\n\t\t\t</Tooltip>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Content maxWidth={ maxWidth } ref={ setRef } as={ as } { ...props }>\n\t\t\t{ title }\n\t\t</Content>\n\t);\n};\n\ntype ContentProps< T extends React.ElementType > = React.PropsWithChildren<\n\tOmit< EllipsisWithTooltipProps< T >, 'title' >\n>;\n\nconst Content = React.forwardRef(\n\t< T extends React.ElementType >(\n\t\t{ maxWidth, as: Component = Box, ...props }: ContentProps< T >,\n\t\t// forwardRef loses the typing when using generic components.\n\t\tref: unknown\n\t) => (\n\t\t<Component\n\t\t\tref={ ref }\n\t\t\tposition=\"relative\"\n\t\t\t{ ...props }\n\t\t\tstyle={ { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth } }\n\t\t/>\n\t)\n);\n\nconst useIsOverflowing = () => {\n\tconst [ el, setEl ] = useState< HTMLElement | null >( null );\n\tconst [ isOverflowing, setIsOverflown ] = useState( false );\n\n\tuseEffect( () => {\n\t\tconst observer = new ResizeObserver( ( [ { target } ] ) => {\n\t\t\tsetIsOverflown( target.scrollWidth > target.clientWidth );\n\t\t} );\n\n\t\tif ( el ) {\n\t\t\tobserver.observe( el );\n\t\t}\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [ el ] );\n\n\treturn [ setEl, isOverflowing ] as const;\n};\n","import * as React from 'react';\nimport { forwardRef } from 'react';\nimport { Tooltip } from '@elementor/ui';\n\ntype EditableFieldProps< T extends React.ElementType > = {\n\tvalue: string;\n\terror?: string;\n\tas?: T;\n} & React.ComponentPropsWithRef< T >;\n\nexport const EditableField = forwardRef(\n\t< T extends React.ElementType >(\n\t\t{ value, error, as: Component = 'span', ...props }: EditableFieldProps< T >,\n\t\tref: unknown\n\t) => {\n\t\treturn (\n\t\t\t<Tooltip title={ error } open={ !! error } placement=\"top\">\n\t\t\t\t<Component ref={ ref } { ...props }>\n\t\t\t\t\t{ value }\n\t\t\t\t</Component>\n\t\t\t</Tooltip>\n\t\t);\n\t}\n);\n","import { useEffect, useRef, useState } from 'react';\n\ntype UseEditableParams = {\n\tvalue: string;\n\tonSubmit: ( value: string ) => unknown;\n\tvalidation?: ( value: string ) => string | undefined | null;\n\tonClick?: ( event: React.MouseEvent< HTMLDivElement > ) => void;\n};\n\nexport const useEditable = ( { value, onSubmit, validation, onClick }: UseEditableParams ) => {\n\tconst [ isEditing, setIsEditing ] = useState( false );\n\tconst [ error, setError ] = useState< string | null | undefined >( null );\n\n\tconst ref = useSelection( isEditing );\n\n\tconst openEditMode = () => {\n\t\tsetIsEditing( true );\n\t};\n\n\tconst closeEditMode = () => {\n\t\tref.current?.blur();\n\n\t\tsetError( null );\n\t\tsetIsEditing( false );\n\t};\n\n\tconst submit = ( newValue: string ) => {\n\t\tif ( ! error ) {\n\t\t\ttry {\n\t\t\t\tonSubmit( newValue );\n\t\t\t} finally {\n\t\t\t\tcloseEditMode();\n\t\t\t}\n\t\t}\n\t};\n\n\tconst onChange = ( event: React.ChangeEvent< HTMLSpanElement > ) => {\n\t\tconst { innerText: newValue } = event.target;\n\n\t\tif ( validation ) {\n\t\t\tsetError( validation( newValue ) );\n\t\t}\n\t};\n\n\tconst handleKeyDown = ( event: React.KeyboardEvent ) => {\n\t\tevent.stopPropagation();\n\n\t\tif ( [ 'Escape' ].includes( event.key ) ) {\n\t\t\treturn closeEditMode();\n\t\t}\n\n\t\tif ( [ 'Enter' ].includes( event.key ) ) {\n\t\t\tevent.preventDefault();\n\t\t\treturn submit( ( event.target as HTMLElement ).innerText );\n\t\t}\n\t};\n\n\tconst handleClick = ( event: React.MouseEvent< HTMLDivElement > ) => {\n\t\tif ( isEditing ) {\n\t\t\tevent.stopPropagation();\n\t\t}\n\n\t\tonClick?.( event );\n\t};\n\n\tconst listeners = {\n\t\tonClick: handleClick,\n\t\tonKeyDown: handleKeyDown,\n\t\tonInput: onChange,\n\t\tonBlur: closeEditMode,\n\t} as const;\n\n\tconst attributes = {\n\t\tvalue,\n\t\trole: 'textbox',\n\t\tcontentEditable: isEditing,\n\t\t...( isEditing && {\n\t\t\tsuppressContentEditableWarning: true,\n\t\t} ),\n\t} as const;\n\n\treturn {\n\t\tref,\n\t\tisEditing,\n\t\topenEditMode,\n\t\tcloseEditMode,\n\t\tvalue,\n\t\terror,\n\t\tgetProps: () => ( { ...listeners, ...attributes } ),\n\t} as const;\n};\n\nconst useSelection = ( isEditing: boolean ) => {\n\tconst ref = useRef< HTMLElement | null >( null );\n\n\tuseEffect( () => {\n\t\tif ( isEditing ) {\n\t\t\tselectAll( ref.current );\n\t\t}\n\t}, [ isEditing ] );\n\n\treturn ref;\n};\n\nconst selectAll = ( el: HTMLElement | null ) => {\n\tconst selection = getSelection();\n\n\tif ( ! selection || ! el ) {\n\t\treturn;\n\t}\n\n\tconst range = document.createRange();\n\trange.selectNodeContents( el );\n\n\tselection.removeAllRanges();\n\tselection.addRange( range );\n};\n"],"mappings":"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","names":["React","forwardRef","Tooltip","useEffect","useState"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/ellipsis-with-tooltip.tsx","../src/components/editable-field.tsx","../src/components/introduction-modal.tsx","../src/hooks/use-editable.ts"],"sourcesContent":["import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { Box, Tooltip } from '@elementor/ui';\n\ntype EllipsisWithTooltipProps< T extends React.ElementType > = {\n\tmaxWidth?: React.CSSProperties[ 'maxWidth' ];\n\ttitle: string;\n\tas?: T;\n} & React.ComponentProps< T >;\n\nexport const EllipsisWithTooltip = < T extends React.ElementType >( {\n\tmaxWidth,\n\ttitle,\n\tas,\n\t...props\n}: EllipsisWithTooltipProps< T > ) => {\n\tconst [ setRef, isOverflowing ] = useIsOverflowing();\n\n\tif ( isOverflowing ) {\n\t\treturn (\n\t\t\t<Tooltip title={ title } placement=\"top\">\n\t\t\t\t<Content maxWidth={ maxWidth } ref={ setRef } as={ as } { ...props }>\n\t\t\t\t\t{ title }\n\t\t\t\t</Content>\n\t\t\t</Tooltip>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Content maxWidth={ maxWidth } ref={ setRef } as={ as } { ...props }>\n\t\t\t{ title }\n\t\t</Content>\n\t);\n};\n\ntype ContentProps< T extends React.ElementType > = React.PropsWithChildren<\n\tOmit< EllipsisWithTooltipProps< T >, 'title' >\n>;\n\nconst Content = React.forwardRef(\n\t< T extends React.ElementType >(\n\t\t{ maxWidth, as: Component = Box, ...props }: ContentProps< T >,\n\t\t// forwardRef loses the typing when using generic components.\n\t\tref: unknown\n\t) => (\n\t\t<Component\n\t\t\tref={ ref }\n\t\t\tposition=\"relative\"\n\t\t\t{ ...props }\n\t\t\tstyle={ { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth } }\n\t\t/>\n\t)\n);\n\nconst useIsOverflowing = () => {\n\tconst [ el, setEl ] = useState< HTMLElement | null >( null );\n\tconst [ isOverflowing, setIsOverflown ] = useState( false );\n\n\tuseEffect( () => {\n\t\tconst observer = new ResizeObserver( ( [ { target } ] ) => {\n\t\t\tsetIsOverflown( target.scrollWidth > target.clientWidth );\n\t\t} );\n\n\t\tif ( el ) {\n\t\t\tobserver.observe( el );\n\t\t}\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t};\n\t}, [ el ] );\n\n\treturn [ setEl, isOverflowing ] as const;\n};\n","import * as React from 'react';\nimport { forwardRef } from 'react';\nimport { Tooltip } from '@elementor/ui';\n\ntype EditableFieldProps< T extends React.ElementType > = {\n\tvalue: string;\n\terror?: string;\n\tas?: T;\n} & React.ComponentPropsWithRef< T >;\n\nexport const EditableField = forwardRef(\n\t< T extends React.ElementType >(\n\t\t{ value, error, as: Component = 'span', sx, ...props }: EditableFieldProps< T >,\n\t\tref: unknown\n\t) => {\n\t\treturn (\n\t\t\t<Tooltip title={ error } open={ !! error } placement=\"top\">\n\t\t\t\t<Component ref={ ref } sx={ { width: '100%', ...sx } } { ...props }>\n\t\t\t\t\t{ value }\n\t\t\t\t</Component>\n\t\t\t</Tooltip>\n\t\t);\n\t}\n);\n","import * as React from 'react';\nimport { useState } from 'react';\nimport { Button, Checkbox, Dialog, DialogActions, DialogHeader, DialogTitle, FormControlLabel } from '@elementor/ui';\nimport { __ } from '@wordpress/i18n';\n\ntype IntroductionModalProps = {\n\topen: boolean;\n\thandleClose: ( shouldShowAgain: boolean ) => void;\n\ttitle: string;\n\tcontent: React.ReactNode;\n};\n\nexport const IntroductionModal = ( { open, handleClose, title, content }: IntroductionModalProps ) => {\n\tconst [ shouldShowAgain, setShouldShowAgain ] = useState( true );\n\n\treturn (\n\t\t<Dialog open={ open } onClose={ handleClose } maxWidth={ 'sm' }>\n\t\t\t<DialogHeader logo={ false }>\n\t\t\t\t<DialogTitle>{ title }</DialogTitle>\n\t\t\t</DialogHeader>\n\t\t\t{ content }\n\t\t\t<DialogActions>\n\t\t\t\t<FormControlLabel\n\t\t\t\t\tsx={ { marginRight: 'auto' } }\n\t\t\t\t\tcontrol={\n\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\tchecked={ ! shouldShowAgain }\n\t\t\t\t\t\t\tonChange={ () => setShouldShowAgain( ! shouldShowAgain ) }\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\tlabel={ __( \"Don't show this again\" ) }\n\t\t\t\t/>\n\t\t\t\t<Button size={ 'medium' } onClick={ () => handleClose( shouldShowAgain ) } variant=\"contained\">\n\t\t\t\t\t{ __( 'Got it' ) }\n\t\t\t\t</Button>\n\t\t\t</DialogActions>\n\t\t</Dialog>\n\t);\n};\n","import { useEffect, useRef, useState } from 'react';\n\ntype UseEditableParams = {\n\tvalue: string;\n\tonSubmit: ( value: string ) => unknown;\n\tvalidation?: ( value: string ) => string | null;\n\tonClick?: ( event: React.MouseEvent< HTMLDivElement > ) => void;\n};\n\nexport const useEditable = ( { value, onSubmit, validation, onClick }: UseEditableParams ) => {\n\tconst [ isEditing, setIsEditing ] = useState( false );\n\tconst [ error, setError ] = useState< string | null >( null );\n\n\tconst ref = useSelection( isEditing );\n\n\tconst isDirty = ( newValue: string ) => newValue !== value;\n\n\tconst openEditMode = () => {\n\t\tsetIsEditing( true );\n\t};\n\n\tconst closeEditMode = () => {\n\t\tref.current?.blur();\n\n\t\tsetError( null );\n\t\tsetIsEditing( false );\n\t};\n\n\tconst submit = ( newValue: string ) => {\n\t\tif ( ! isDirty( newValue ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( ! error ) {\n\t\t\ttry {\n\t\t\t\tonSubmit( newValue );\n\t\t\t} finally {\n\t\t\t\tcloseEditMode();\n\t\t\t}\n\t\t}\n\t};\n\n\tconst onChange = ( event: React.ChangeEvent< HTMLSpanElement > ) => {\n\t\tconst { innerText: newValue } = event.target;\n\n\t\tif ( validation ) {\n\t\t\tsetError( isDirty( newValue ) ? validation( newValue ) : null );\n\t\t}\n\t};\n\n\tconst handleKeyDown = ( event: React.KeyboardEvent ) => {\n\t\tevent.stopPropagation();\n\n\t\tif ( [ 'Escape' ].includes( event.key ) ) {\n\t\t\treturn closeEditMode();\n\t\t}\n\n\t\tif ( [ 'Enter' ].includes( event.key ) ) {\n\t\t\tevent.preventDefault();\n\t\t\treturn submit( ( event.target as HTMLElement ).innerText );\n\t\t}\n\t};\n\n\tconst handleClick = ( event: React.MouseEvent< HTMLDivElement > ) => {\n\t\tif ( isEditing ) {\n\t\t\tevent.stopPropagation();\n\t\t}\n\n\t\tonClick?.( event );\n\t};\n\n\tconst listeners = {\n\t\tonClick: handleClick,\n\t\tonKeyDown: handleKeyDown,\n\t\tonInput: onChange,\n\t\tonBlur: closeEditMode,\n\t} as const;\n\n\tconst attributes = {\n\t\tvalue,\n\t\trole: 'textbox',\n\t\tcontentEditable: isEditing,\n\t\t...( isEditing && {\n\t\t\tsuppressContentEditableWarning: true,\n\t\t} ),\n\t} as const;\n\n\treturn {\n\t\tref,\n\t\tisEditing,\n\t\topenEditMode,\n\t\tcloseEditMode,\n\t\tvalue,\n\t\terror,\n\t\tgetProps: () => ( { ...listeners, ...attributes } ),\n\t} as const;\n};\n\nconst useSelection = ( isEditing: boolean ) => {\n\tconst ref = useRef< HTMLElement | null >( null );\n\n\tuseEffect( () => {\n\t\tif ( isEditing ) {\n\t\t\tselectAll( ref.current );\n\t\t}\n\t}, [ isEditing ] );\n\n\treturn ref;\n};\n\nconst selectAll = ( el: HTMLElement | null ) => {\n\tconst selection = getSelection();\n\n\tif ( ! selection || ! el ) {\n\t\treturn;\n\t}\n\n\tconst range = document.createRange();\n\trange.selectNodeContents( el );\n\n\tselection.removeAllRanges();\n\tselection.addRange( range );\n};\n"],"mappings":"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","names":["React","forwardRef","Tooltip","React","useState","useEffect","useState"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-ui",
|
|
3
3
|
"description": "Elementor Editor UI",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"react": "^18.3.1"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@elementor/ui": "1.26.0"
|
|
39
|
+
"@elementor/ui": "1.26.0",
|
|
40
|
+
"@wordpress/i18n": "^5.13.0"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"tsup": "^8.3.5"
|
|
@@ -10,12 +10,12 @@ type EditableFieldProps< T extends React.ElementType > = {
|
|
|
10
10
|
|
|
11
11
|
export const EditableField = forwardRef(
|
|
12
12
|
< T extends React.ElementType >(
|
|
13
|
-
{ value, error, as: Component = 'span', ...props }: EditableFieldProps< T >,
|
|
13
|
+
{ value, error, as: Component = 'span', sx, ...props }: EditableFieldProps< T >,
|
|
14
14
|
ref: unknown
|
|
15
15
|
) => {
|
|
16
16
|
return (
|
|
17
17
|
<Tooltip title={ error } open={ !! error } placement="top">
|
|
18
|
-
<Component ref={ ref } { ...props }>
|
|
18
|
+
<Component ref={ ref } sx={ { width: '100%', ...sx } } { ...props }>
|
|
19
19
|
{ value }
|
|
20
20
|
</Component>
|
|
21
21
|
</Tooltip>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Button, Checkbox, Dialog, DialogActions, DialogHeader, DialogTitle, FormControlLabel } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
type IntroductionModalProps = {
|
|
7
|
+
open: boolean;
|
|
8
|
+
handleClose: ( shouldShowAgain: boolean ) => void;
|
|
9
|
+
title: string;
|
|
10
|
+
content: React.ReactNode;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const IntroductionModal = ( { open, handleClose, title, content }: IntroductionModalProps ) => {
|
|
14
|
+
const [ shouldShowAgain, setShouldShowAgain ] = useState( true );
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Dialog open={ open } onClose={ handleClose } maxWidth={ 'sm' }>
|
|
18
|
+
<DialogHeader logo={ false }>
|
|
19
|
+
<DialogTitle>{ title }</DialogTitle>
|
|
20
|
+
</DialogHeader>
|
|
21
|
+
{ content }
|
|
22
|
+
<DialogActions>
|
|
23
|
+
<FormControlLabel
|
|
24
|
+
sx={ { marginRight: 'auto' } }
|
|
25
|
+
control={
|
|
26
|
+
<Checkbox
|
|
27
|
+
checked={ ! shouldShowAgain }
|
|
28
|
+
onChange={ () => setShouldShowAgain( ! shouldShowAgain ) }
|
|
29
|
+
/>
|
|
30
|
+
}
|
|
31
|
+
label={ __( "Don't show this again" ) }
|
|
32
|
+
/>
|
|
33
|
+
<Button size={ 'medium' } onClick={ () => handleClose( shouldShowAgain ) } variant="contained">
|
|
34
|
+
{ __( 'Got it' ) }
|
|
35
|
+
</Button>
|
|
36
|
+
</DialogActions>
|
|
37
|
+
</Dialog>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -155,4 +155,55 @@ describe( 'useEditable', () => {
|
|
|
155
155
|
// Assert.
|
|
156
156
|
expect( onSubmit ).not.toHaveBeenCalled();
|
|
157
157
|
} );
|
|
158
|
+
|
|
159
|
+
it( 'should not run validation & submit if the value has not changed', () => {
|
|
160
|
+
// Arrange.
|
|
161
|
+
const value = 'initial value';
|
|
162
|
+
const onSubmit = jest.fn();
|
|
163
|
+
|
|
164
|
+
const validation = () => {
|
|
165
|
+
return 'test-error';
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const { result } = renderHook( () =>
|
|
169
|
+
useEditable( {
|
|
170
|
+
value,
|
|
171
|
+
onSubmit,
|
|
172
|
+
validation,
|
|
173
|
+
} )
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Act.
|
|
177
|
+
act( result.current.openEditMode );
|
|
178
|
+
|
|
179
|
+
// Assert.
|
|
180
|
+
expect( result.current.error ).toBeNull();
|
|
181
|
+
|
|
182
|
+
// Act.
|
|
183
|
+
act( () => {
|
|
184
|
+
result.current.getProps().onInput( { target: { innerText: 'new value' } } as never );
|
|
185
|
+
} );
|
|
186
|
+
|
|
187
|
+
// Assert.
|
|
188
|
+
expect( result.current.error ).toBe( 'test-error' );
|
|
189
|
+
|
|
190
|
+
act( () => {
|
|
191
|
+
result.current.getProps().onInput( { target: { innerText: value } } as never );
|
|
192
|
+
} );
|
|
193
|
+
|
|
194
|
+
expect( result.current.error ).toBe( null );
|
|
195
|
+
|
|
196
|
+
// Act.
|
|
197
|
+
act( () => {
|
|
198
|
+
result.current.getProps().onKeyDown( {
|
|
199
|
+
key: 'Enter',
|
|
200
|
+
stopPropagation: jest.fn(),
|
|
201
|
+
preventDefault: jest.fn(),
|
|
202
|
+
target: { innerText: value },
|
|
203
|
+
} as never );
|
|
204
|
+
} );
|
|
205
|
+
|
|
206
|
+
// Assert.
|
|
207
|
+
expect( onSubmit ).not.toHaveBeenCalled();
|
|
208
|
+
} );
|
|
158
209
|
} );
|
|
@@ -3,16 +3,18 @@ import { useEffect, useRef, useState } from 'react';
|
|
|
3
3
|
type UseEditableParams = {
|
|
4
4
|
value: string;
|
|
5
5
|
onSubmit: ( value: string ) => unknown;
|
|
6
|
-
validation?: ( value: string ) => string |
|
|
6
|
+
validation?: ( value: string ) => string | null;
|
|
7
7
|
onClick?: ( event: React.MouseEvent< HTMLDivElement > ) => void;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export const useEditable = ( { value, onSubmit, validation, onClick }: UseEditableParams ) => {
|
|
11
11
|
const [ isEditing, setIsEditing ] = useState( false );
|
|
12
|
-
const [ error, setError ] = useState< string | null
|
|
12
|
+
const [ error, setError ] = useState< string | null >( null );
|
|
13
13
|
|
|
14
14
|
const ref = useSelection( isEditing );
|
|
15
15
|
|
|
16
|
+
const isDirty = ( newValue: string ) => newValue !== value;
|
|
17
|
+
|
|
16
18
|
const openEditMode = () => {
|
|
17
19
|
setIsEditing( true );
|
|
18
20
|
};
|
|
@@ -25,6 +27,10 @@ export const useEditable = ( { value, onSubmit, validation, onClick }: UseEditab
|
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
const submit = ( newValue: string ) => {
|
|
30
|
+
if ( ! isDirty( newValue ) ) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
if ( ! error ) {
|
|
29
35
|
try {
|
|
30
36
|
onSubmit( newValue );
|
|
@@ -38,7 +44,7 @@ export const useEditable = ( { value, onSubmit, validation, onClick }: UseEditab
|
|
|
38
44
|
const { innerText: newValue } = event.target;
|
|
39
45
|
|
|
40
46
|
if ( validation ) {
|
|
41
|
-
setError( validation( newValue ) );
|
|
47
|
+
setError( isDirty( newValue ) ? validation( newValue ) : null );
|
|
42
48
|
}
|
|
43
49
|
};
|
|
44
50
|
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// components
|
|
2
2
|
export { EllipsisWithTooltip } from './components/ellipsis-with-tooltip';
|
|
3
3
|
export { EditableField } from './components/editable-field';
|
|
4
|
+
export { IntroductionModal } from './components/introduction-modal';
|
|
4
5
|
|
|
5
6
|
// hooks
|
|
6
7
|
export { useEditable } from './hooks/use-editable';
|