pds-dev-kit-web 2.2.225 → 2.2.226

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.
@@ -24,11 +24,14 @@ export type RichTextEditorProps = {
24
24
  fileSizeValidationText?: string;
25
25
  height?: string | number;
26
26
  tinymceScriptSrc?: string;
27
- onChange?: (value: string) => void;
27
+ onChange?: (value: string, isValid?: boolean) => void;
28
28
  onBlur?: (value: string, count: number) => void;
29
- onCountCharacter?: (count: number) => void;
30
29
  onImageUpload?: ImageUploadHandler;
31
30
  isLoadingUsed?: boolean;
31
+ /**
32
+ * @deprecated onChange 이벤트를 사용해주세요.
33
+ */
34
+ onCountCharacter?: (count: number) => void;
32
35
  };
33
36
  declare function RichTextEditor({ toolbar, defaultText, hintText, maxLength, minLength, maxFileSize, requirementMode, lengthValidationText, requiredValidationText, fileSizeValidationText, height, tinymceScriptSrc, onChange, onBlur, onCountCharacter, onImageUpload, isLoadingUsed }: RichTextEditorProps): JSX.Element;
34
37
  export default RichTextEditor;
@@ -52,19 +52,20 @@ var uuid_1 = require("uuid");
52
52
  var components_1 = require("../../../common/components");
53
53
  var styled_components_1 = __importDefault(require("styled-components"));
54
54
  var DesktopAlertDialog_1 = require("../DesktopAlertDialog");
55
+ var DEFAULT_ELEMENT_COUNT = 7;
55
56
  function RichTextEditor(_a) {
56
57
  var _this = this;
57
- var _b;
58
- var toolbar = _a.toolbar, defaultText = _a.defaultText, hintText = _a.hintText, maxLength = _a.maxLength, minLength = _a.minLength, maxFileSize = _a.maxFileSize, _c = _a.requirementMode, requirementMode = _c === void 0 ? 'none' : _c, lengthValidationText = _a.lengthValidationText, requiredValidationText = _a.requiredValidationText, fileSizeValidationText = _a.fileSizeValidationText, _d = _a.height, height = _d === void 0 ? 600 : _d, _e = _a.tinymceScriptSrc, tinymceScriptSrc = _e === void 0 ? '/tinymce/tinymce.min.js' : _e, onChange = _a.onChange, onBlur = _a.onBlur, onCountCharacter = _a.onCountCharacter, onImageUpload = _a.onImageUpload, _f = _a.isLoadingUsed, isLoadingUsed = _f === void 0 ? true : _f;
58
+ var _b, _c, _d;
59
+ var toolbar = _a.toolbar, defaultText = _a.defaultText, hintText = _a.hintText, maxLength = _a.maxLength, minLength = _a.minLength, maxFileSize = _a.maxFileSize, _e = _a.requirementMode, requirementMode = _e === void 0 ? 'none' : _e, lengthValidationText = _a.lengthValidationText, requiredValidationText = _a.requiredValidationText, fileSizeValidationText = _a.fileSizeValidationText, _f = _a.height, height = _f === void 0 ? 600 : _f, _g = _a.tinymceScriptSrc, tinymceScriptSrc = _g === void 0 ? '/tinymce/tinymce.min.js' : _g, onChange = _a.onChange, onBlur = _a.onBlur, onCountCharacter = _a.onCountCharacter, onImageUpload = _a.onImageUpload, _h = _a.isLoadingUsed, isLoadingUsed = _h === void 0 ? true : _h;
59
60
  var t = (0, react_i18next_1.useTranslation)('translation').t;
60
- var _g = (0, react_1.useState)(0), count = _g[0], setCount = _g[1];
61
- var _h = (0, react_1.useState)(true), isEditorLoading = _h[0], setIsEditorLoading = _h[1];
62
- var _j = (0, react_1.useState)(false), isFileValidationAlertDialogOpen = _j[0], setIsFilValidationAlertDialogOpen = _j[1];
61
+ var _j = (0, react_1.useState)(0), count = _j[0], setCount = _j[1];
62
+ var _k = (0, react_1.useState)(true), isEditorLoading = _k[0], setIsEditorLoading = _k[1];
63
+ var _l = (0, react_1.useState)(false), isEditorDirty = _l[0], setIsEditorDirty = _l[1];
64
+ var _m = (0, react_1.useState)(false), isFileValidationAlertDialogOpen = _m[0], setIsFilValidationAlertDialogOpen = _m[1];
63
65
  var editorRef = (0, react_1.useRef)(null);
64
- var isEditorDirty = (0, react_1.useRef)(false);
65
66
  var editorContent = (_b = editorRef.current) === null || _b === void 0 ? void 0 : _b.getContent();
67
+ var elementsCount = Array.from((_d = (_c = editorRef.current) === null || _c === void 0 ? void 0 : _c.contentDocument.all) !== null && _d !== void 0 ? _d : []).filter(function (element) { return !['BR', 'P'].includes(element.tagName); }).length - DEFAULT_ELEMENT_COUNT;
66
68
  var useDarkMode = window.PdsUtils.tone === 'DARK';
67
- var validationText = (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {});
68
69
  (0, react_1.useEffect)(function () {
69
70
  if (defaultText && defaultText.length === 0) {
70
71
  setCount(defaultText.length);
@@ -94,14 +95,34 @@ function RichTextEditor(_a) {
94
95
  }
95
96
  };
96
97
  var handleEditorValueChange = function (value, editor) {
98
+ // NOTE: 기본 요소를 제외한 추가된 HTML 요소의 개수
99
+ var addedElementsCount = Array.from(editor.contentDocument.all).filter(function (element) { return !['BR', 'P'].includes(element.tagName); }).length - DEFAULT_ELEMENT_COUNT;
97
100
  var wordCount = editor.plugins.wordcount;
101
+ var charCount = 0;
98
102
  if (wordCount) {
99
- var charCount = wordCount.body.getCharacterCount();
103
+ charCount = wordCount.body.getCharacterCount();
100
104
  onCountCharacter === null || onCountCharacter === void 0 ? void 0 : onCountCharacter(charCount);
101
105
  setCount(charCount);
102
106
  }
103
- isEditorDirty.current = true;
104
- onChange === null || onChange === void 0 ? void 0 : onChange(value);
107
+ var isValid = function () {
108
+ // NOTE: 추가된 HTML 요소가 존재해도, maxLength를 초과할 경우.
109
+ if (maxLength && charCount > maxLength) {
110
+ return false;
111
+ }
112
+ // NOTE: 기본 요소를 제외한 추가된 HTML 요소가 존재하는 경우 유효성 검사를 통과합니다.
113
+ if (addedElementsCount > 0) {
114
+ return true;
115
+ }
116
+ if (requirementMode === 'use' && charCount === 0) {
117
+ return false;
118
+ }
119
+ if (minLength && charCount < minLength) {
120
+ return false;
121
+ }
122
+ return true;
123
+ };
124
+ setIsEditorDirty(value ? true : false);
125
+ onChange === null || onChange === void 0 ? void 0 : onChange(value, isValid());
105
126
  };
106
127
  var handleEditorBlur = function () {
107
128
  var _a, _b;
@@ -179,17 +200,22 @@ function RichTextEditor(_a) {
179
200
  }
180
201
  });
181
202
  }); };
182
- if (requirementMode === 'use' &&
183
- isEditorDirty.current &&
184
- (!editorContent || editorContent.length === 0)) {
185
- validationText = (0, jsx_runtime_1.jsx)(S_Error, { children: requiredValidationText });
186
- }
187
- if (minLength && count > 0 && count < minLength) {
188
- validationText = (0, jsx_runtime_1.jsx)(S_Error, { children: lengthValidationText });
189
- }
190
- if (maxLength && count > 0 && count > maxLength) {
191
- validationText = (0, jsx_runtime_1.jsx)(S_Error, { children: lengthValidationText });
192
- }
203
+ var validationText = (0, react_1.useMemo)(function () {
204
+ if (requirementMode === 'use' &&
205
+ !isEditorDirty &&
206
+ (!editorContent || editorContent.length === 0) &&
207
+ elementsCount <= 0) {
208
+ return (0, jsx_runtime_1.jsx)(S_Error, { children: requiredValidationText });
209
+ }
210
+ if (elementsCount <= 0 && minLength && count > 0 && count < minLength) {
211
+ return (0, jsx_runtime_1.jsx)(S_Error, { children: lengthValidationText });
212
+ }
213
+ // 추가된 HTML 요소가 있어도, maxLength에 의한 validation은 수행합니다.
214
+ if (maxLength && count > 0 && count > maxLength) {
215
+ return (0, jsx_runtime_1.jsx)(S_Error, { children: lengthValidationText });
216
+ }
217
+ return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {});
218
+ }, [requirementMode, isEditorDirty, editorContent, elementsCount, count, minLength, maxLength]);
193
219
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(S_Editor, { children: [isEditorLoading && isLoadingUsed && ((0, jsx_runtime_1.jsx)(S_LoadingWrapper, { children: (0, jsx_runtime_1.jsx)(components_1.CircularProgress, {}) })), (0, jsx_runtime_1.jsx)(tinymce_react_1.Editor, { tinymceScriptSrc: tinymceScriptSrc, onInit: handleInit, onEditorChange: handleEditorValueChange, initialValue: defaultText, init: {
194
220
  menubar: false,
195
221
  promotion: false,
@@ -24,11 +24,14 @@ export type RichTextEditorProps = {
24
24
  fileSizeValidationText?: string;
25
25
  height?: string | number;
26
26
  tinymceScriptSrc?: string;
27
- onChange?: (value: string) => void;
27
+ onChange?: (value: string, isValid?: boolean) => void;
28
28
  onBlur?: (value: string, count: number) => void;
29
- onCountCharacter?: (count: number) => void;
30
29
  onImageUpload?: ImageUploadHandler;
31
30
  isLoadingUsed?: boolean;
31
+ /**
32
+ * @deprecated onChange 이벤트를 사용해주세요.
33
+ */
34
+ onCountCharacter?: (count: number) => void;
32
35
  };
33
36
  declare function RichTextEditor({ toolbar, defaultText, hintText, maxLength, minLength, maxFileSize, required, lengthValidationText, requiredValidationText, fileSizeValidationText, height, tinymceScriptSrc, onChange, onBlur, onCountCharacter, onImageUpload, isLoadingUsed }: RichTextEditorProps): JSX.Element;
34
37
  export default RichTextEditor;
@@ -52,19 +52,20 @@ var uuid_1 = require("uuid");
52
52
  var components_1 = require("../../../common/components");
53
53
  var styled_components_1 = __importDefault(require("styled-components"));
54
54
  var MobileAlertDialog_1 = require("../MobileAlertDialog");
55
+ var DEFAULT_ELEMENT_COUNT = 7;
55
56
  function RichTextEditor(_a) {
56
57
  var _this = this;
57
- var _b;
58
- var toolbar = _a.toolbar, defaultText = _a.defaultText, hintText = _a.hintText, maxLength = _a.maxLength, minLength = _a.minLength, maxFileSize = _a.maxFileSize, required = _a.required, lengthValidationText = _a.lengthValidationText, requiredValidationText = _a.requiredValidationText, fileSizeValidationText = _a.fileSizeValidationText, _c = _a.height, height = _c === void 0 ? 600 : _c, _d = _a.tinymceScriptSrc, tinymceScriptSrc = _d === void 0 ? '/tinymce/tinymce.min.js' : _d, onChange = _a.onChange, onBlur = _a.onBlur, onCountCharacter = _a.onCountCharacter, onImageUpload = _a.onImageUpload, _e = _a.isLoadingUsed, isLoadingUsed = _e === void 0 ? true : _e;
58
+ var _b, _c, _d;
59
+ var toolbar = _a.toolbar, defaultText = _a.defaultText, hintText = _a.hintText, maxLength = _a.maxLength, minLength = _a.minLength, maxFileSize = _a.maxFileSize, required = _a.required, lengthValidationText = _a.lengthValidationText, requiredValidationText = _a.requiredValidationText, fileSizeValidationText = _a.fileSizeValidationText, _e = _a.height, height = _e === void 0 ? 600 : _e, _f = _a.tinymceScriptSrc, tinymceScriptSrc = _f === void 0 ? '/tinymce/tinymce.min.js' : _f, onChange = _a.onChange, onBlur = _a.onBlur, onCountCharacter = _a.onCountCharacter, onImageUpload = _a.onImageUpload, _g = _a.isLoadingUsed, isLoadingUsed = _g === void 0 ? true : _g;
59
60
  var t = (0, react_i18next_1.useTranslation)('translation').t;
60
- var _f = (0, react_1.useState)(0), count = _f[0], setCount = _f[1];
61
- var _g = (0, react_1.useState)(true), isEditorLoading = _g[0], setIsEditorLoading = _g[1];
62
- var _h = (0, react_1.useState)(false), isFileValidationAlertDialogOpen = _h[0], setIsFilValidationAlertDialogOpen = _h[1];
61
+ var _h = (0, react_1.useState)(0), count = _h[0], setCount = _h[1];
62
+ var _j = (0, react_1.useState)(true), isEditorLoading = _j[0], setIsEditorLoading = _j[1];
63
+ var _k = (0, react_1.useState)(false), isEditorDirty = _k[0], setIsEditorDirty = _k[1];
64
+ var _l = (0, react_1.useState)(false), isFileValidationAlertDialogOpen = _l[0], setIsFilValidationAlertDialogOpen = _l[1];
63
65
  var editorRef = (0, react_1.useRef)(null);
64
- var isEditorDirty = (0, react_1.useRef)(false);
65
66
  var editorContent = (_b = editorRef.current) === null || _b === void 0 ? void 0 : _b.getContent();
67
+ var elementsCount = Array.from((_d = (_c = editorRef.current) === null || _c === void 0 ? void 0 : _c.contentDocument.all) !== null && _d !== void 0 ? _d : []).filter(function (element) { return !['BR', 'P'].includes(element.tagName); }).length - DEFAULT_ELEMENT_COUNT;
66
68
  var useDarkMode = window.PdsUtils.tone === 'DARK';
67
- var validationText = (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {});
68
69
  (0, react_1.useEffect)(function () {
69
70
  if (defaultText && defaultText.length === 0) {
70
71
  setCount(defaultText.length);
@@ -94,14 +95,34 @@ function RichTextEditor(_a) {
94
95
  }
95
96
  };
96
97
  var handleEditorValueChange = function (value, editor) {
98
+ // NOTE: 기본 요소를 제외한 추가된 HTML 요소의 개수
99
+ var addedElementsCount = Array.from(editor.contentDocument.all).filter(function (element) { return !['BR', 'P'].includes(element.tagName); }).length - DEFAULT_ELEMENT_COUNT;
97
100
  var wordCount = editor.plugins.wordcount;
101
+ var charCount = 0;
98
102
  if (wordCount) {
99
- var charCount = wordCount.body.getCharacterCount();
103
+ charCount = wordCount.body.getCharacterCount();
100
104
  onCountCharacter === null || onCountCharacter === void 0 ? void 0 : onCountCharacter(charCount);
101
105
  setCount(charCount);
102
106
  }
103
- isEditorDirty.current = true;
104
- onChange === null || onChange === void 0 ? void 0 : onChange(value);
107
+ var isValid = function () {
108
+ // NOTE: 추가된 HTML 요소가 존재해도, maxLength를 초과할 경우.
109
+ if (maxLength && charCount > maxLength) {
110
+ return false;
111
+ }
112
+ // NOTE: 기본 요소를 제외한 추가된 HTML 요소가 존재하는 경우 유효성 검사를 통과합니다.
113
+ if (addedElementsCount > 0) {
114
+ return true;
115
+ }
116
+ if (required && charCount === 0) {
117
+ return false;
118
+ }
119
+ if (minLength && charCount < minLength) {
120
+ return false;
121
+ }
122
+ return true;
123
+ };
124
+ setIsEditorDirty(value ? true : false);
125
+ onChange === null || onChange === void 0 ? void 0 : onChange(value, isValid());
105
126
  };
106
127
  var handleEditorBlur = function () {
107
128
  var _a, _b;
@@ -179,15 +200,21 @@ function RichTextEditor(_a) {
179
200
  }
180
201
  });
181
202
  }); };
182
- if (required && isEditorDirty.current && (!editorContent || editorContent.length === 0)) {
183
- validationText = (0, jsx_runtime_1.jsx)(S_Error, { children: requiredValidationText });
184
- }
185
- if (minLength && count > 0 && count < minLength) {
186
- validationText = (0, jsx_runtime_1.jsx)(S_Error, { children: lengthValidationText });
187
- }
188
- if (maxLength && count > 0 && count > maxLength) {
189
- validationText = (0, jsx_runtime_1.jsx)(S_Error, { children: lengthValidationText });
190
- }
203
+ var validationText = (0, react_1.useMemo)(function () {
204
+ if (required &&
205
+ !isEditorDirty &&
206
+ (!editorContent || editorContent.length === 0) &&
207
+ elementsCount <= 0) {
208
+ return (0, jsx_runtime_1.jsx)(S_Error, { children: requiredValidationText });
209
+ }
210
+ if (elementsCount <= 0 && minLength && count > 0 && count < minLength) {
211
+ return (0, jsx_runtime_1.jsx)(S_Error, { children: lengthValidationText });
212
+ }
213
+ if (maxLength && count > 0 && count > maxLength) {
214
+ return (0, jsx_runtime_1.jsx)(S_Error, { children: lengthValidationText });
215
+ }
216
+ return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {});
217
+ }, [required, isEditorDirty, editorContent, elementsCount, count, minLength, maxLength]);
191
218
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(S_Editor, { children: [isEditorLoading && isLoadingUsed && ((0, jsx_runtime_1.jsx)(S_LoadingWrapper, { children: (0, jsx_runtime_1.jsx)(components_1.CircularProgress, {}) })), (0, jsx_runtime_1.jsx)(tinymce_react_1.Editor, { tinymceScriptSrc: tinymceScriptSrc, onInit: handleInit, onEditorChange: handleEditorValueChange, initialValue: defaultText, init: {
192
219
  images_max_width: '100%',
193
220
  menubar: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pds-dev-kit-web",
3
- "version": "2.2.225",
3
+ "version": "2.2.226",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "main": "dist/index.js",
package/release-note.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # PDS-DEV-KIT-WEB Release Notes
2
- ## [v2.2.225]
2
+ ## [v2.2.226]
3
3
  ## daily|https://design.storybook.publ.biz/
4
4
 
5
5
  ### 업데이트 사항
6
- * [PDS-1355] AdminListItem의 데이터 누락시 기본 폴백 텍스트 처리
6
+ * [PDS-1356] RichTextEditor 개선