@rulab/adminjs-components 0.0.2 → 0.0.4

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.
Files changed (37) hide show
  1. package/dist/bundle.js +8 -0
  2. package/dist/components/CustomSlug/CustomSlug.jsx +29 -0
  3. package/dist/components/CustomSlug/index.js +1 -0
  4. package/dist/components/CustomSlug/styles.js +15 -0
  5. package/dist/components/Editor/config.js +11 -0
  6. package/dist/components/Editor/index.js +1 -0
  7. package/dist/components/Editor/styles.js +64 -0
  8. package/dist/components/StringList/SortableList/SortableList.jsx +43 -0
  9. package/dist/components/StringList/SortableList/components/SortableItem/DragHandle.jsx +10 -0
  10. package/dist/components/StringList/SortableList/components/SortableItem/SortableItem.jsx +32 -0
  11. package/dist/components/StringList/SortableList/components/SortableItem/styles.js +20 -0
  12. package/dist/components/StringList/SortableList/components/SortableItem/types.js +1 -0
  13. package/dist/components/StringList/SortableList/components/index.js +2 -0
  14. package/dist/components/StringList/SortableList/index.js +1 -0
  15. package/dist/components/StringList/SortableList/styles.js +8 -0
  16. package/dist/components/StringList/StringList.jsx +67 -0
  17. package/dist/components/StringList/index.js +1 -0
  18. package/dist/components/StringList/styles.js +16 -0
  19. package/dist/components/index.js +3 -0
  20. package/dist/editorFeature.js +16 -0
  21. package/dist/index.cjs +33 -4
  22. package/dist/index.d.cts +6 -1
  23. package/dist/index.d.mts +8 -0
  24. package/dist/index.d.ts +6 -1
  25. package/dist/index.js +32 -4
  26. package/dist/index.mjs +37 -0
  27. package/dist/utils/index.js +1 -0
  28. package/dist/utils/slugifyImport.js +3 -0
  29. package/dist/utils/slugifyTitle.js +10 -0
  30. package/package.json +2 -1
  31. package/src/components/CustomSlug/CustomSlug.tsx +4 -2
  32. package/src/components/Editor/Editor.jsx +2 -1
  33. package/src/components/Editor/EditorShow.jsx +22 -0
  34. package/src/components/Editor/index.ts +2 -1
  35. package/src/components/index.ts +2 -1
  36. package/src/utils/parseHtml.ts +12 -0
  37. package/src/utils/slugifyTitle.ts +1 -1
package/dist/bundle.js ADDED
@@ -0,0 +1,8 @@
1
+ import path from "path";
2
+ import * as url from "url";
3
+ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
4
+ const bundleComponent = (loader, componentName) => {
5
+ const componentPath = path.join(__dirname, `./components/${componentName}`);
6
+ return loader.add(componentName, componentPath);
7
+ };
8
+ export default bundleComponent;
@@ -0,0 +1,29 @@
1
+ import React, { useEffect, useState, } from "react";
2
+ import { ThemeProvider } from "styled-components";
3
+ import { theme, Label } from "@adminjs/design-system";
4
+ import { slugifyTitle } from "../../utils/index.js";
5
+ import { StyledInputWrapper, StyledCustomInput, StyledGenerateButton, } from "./styles.js";
6
+ const CustomSlug = ({ property, record, onChange }) => {
7
+ const [inputValue, setInputValue] = useState(record.params.slug);
8
+ useEffect(() => {
9
+ onChange(property.path, inputValue);
10
+ }, [inputValue]);
11
+ return (<ThemeProvider theme={theme}>
12
+ <Label htmlFor="customSlug">Slug</Label>
13
+ <StyledInputWrapper>
14
+ <StyledCustomInput id={property.path} name={property.path} value={inputValue} onChange={handleInput}/>
15
+ <StyledGenerateButton variant="outlined" onClick={generateSlug}>
16
+ Generate Slug
17
+ </StyledGenerateButton>
18
+ </StyledInputWrapper>
19
+ </ThemeProvider>);
20
+ function handleInput(e) {
21
+ setInputValue(e.target.value);
22
+ }
23
+ function generateSlug(e) {
24
+ e.preventDefault();
25
+ const title = record.title;
26
+ setInputValue(slugifyTitle(title));
27
+ }
28
+ };
29
+ export default CustomSlug;
@@ -0,0 +1 @@
1
+ export { default } from "./CustomSlug.js";
@@ -0,0 +1,15 @@
1
+ // @ts-ignore
2
+ import { styled } from "@adminjs/design-system/styled-components";
3
+ // @ts-ignore
4
+ import { Button, Box, Input } from "@adminjs/design-system";
5
+ export const StyledInputWrapper = styled(Box) `
6
+ display: flex;
7
+ margin-bottom: 40px;
8
+ `;
9
+ export const StyledCustomInput = styled(Input) `
10
+ width: 100%;
11
+ margin-right: 10px;
12
+ `;
13
+ export const StyledGenerateButton = styled(Button) `
14
+ white-space: nowrap;
15
+ `;
@@ -0,0 +1,11 @@
1
+ import Header from "@editorjs/header";
2
+ import Paragraph from "@editorjs/paragraph";
3
+ import List from "@editorjs/list";
4
+ export const EDITOR_TOOLS = {
5
+ paragraph: {
6
+ class: Paragraph,
7
+ inlineToolbar: true,
8
+ },
9
+ list: List,
10
+ header: Header,
11
+ };
@@ -0,0 +1 @@
1
+ export { default } from "./Editor.jsx";
@@ -0,0 +1,64 @@
1
+ import { Box } from "@adminjs/design-system";
2
+ import { styled } from "@adminjs/design-system/styled-components";
3
+ export const Label = styled.div `
4
+ font-size: 12px;
5
+ margin-bottom: 8px;
6
+ `;
7
+ export const EditorWrapper = styled(Box) `
8
+ padding: 12px;
9
+ border: 1px solid rgb(187, 195, 203);
10
+ `;
11
+ export const StyledEditor = styled.div `
12
+ .cdx-block,
13
+ .ce-header {
14
+ padding-left: 58px;
15
+ }
16
+
17
+ .cdx-list {
18
+ padding-left: 85px;
19
+ }
20
+
21
+ .ce-block__content {
22
+ width: 100%;
23
+ max-width: none;
24
+ }
25
+
26
+ .ce-toolbar__content {
27
+ max-width: none;
28
+ left: 0;
29
+ }
30
+
31
+ .ce-toolbar__actions {
32
+ left: 0;
33
+ }
34
+
35
+ h1.ce-header {
36
+ font-size: 22px;
37
+ font-weight: bold;
38
+ }
39
+
40
+ h2.ce-header {
41
+ font-size: 20px;
42
+ font-weight: bold;
43
+ }
44
+
45
+ h3.ce-header {
46
+ font-size: 18px;
47
+ font-weight: bold;
48
+ }
49
+
50
+ h4.ce-header {
51
+ font-size: 16px;
52
+ font-weight: bold;
53
+ }
54
+
55
+ h5.ce-header {
56
+ font-size: 15px;
57
+ font-weight: bold;
58
+ }
59
+
60
+ h6.ce-header {
61
+ font-size: 14px;
62
+ font-weight: bold;
63
+ }
64
+ `;
@@ -0,0 +1,43 @@
1
+ import React, { Fragment, useMemo, useState } from 'react';
2
+ import { DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors, DragOverlay, defaultDropAnimationSideEffects, } from '@dnd-kit/core';
3
+ import { SortableContext, arrayMove, sortableKeyboardCoordinates, verticalListSortingStrategy, } from '@dnd-kit/sortable';
4
+ import { SortableItem } from './components/index.js';
5
+ import { StyledListWrapper } from './styles.js';
6
+ const dropAnimationConfig = {
7
+ sideEffects: defaultDropAnimationSideEffects({
8
+ styles: {
9
+ active: {
10
+ opacity: '0.4',
11
+ },
12
+ },
13
+ }),
14
+ };
15
+ export function SortableList({ items, onChange, renderItem, }) {
16
+ const [active, setActive] = useState(null);
17
+ const activeItem = useMemo(() => items.find((item) => item.id === active?.id), [active, items]);
18
+ const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, {
19
+ coordinateGetter: sortableKeyboardCoordinates,
20
+ }));
21
+ return (<DndContext sensors={sensors} onDragStart={({ active }) => {
22
+ setActive(active);
23
+ }} onDragEnd={({ active, over }) => {
24
+ if (over && active.id !== over?.id) {
25
+ const activeIndex = items.findIndex(({ id }) => id === active.id);
26
+ const overIndex = items.findIndex(({ id }) => id === over.id);
27
+ onChange(arrayMove(items, activeIndex, overIndex));
28
+ }
29
+ setActive(null);
30
+ }} onDragCancel={() => {
31
+ setActive(null);
32
+ }}>
33
+ <SortableContext items={items} strategy={verticalListSortingStrategy}>
34
+ <StyledListWrapper role="application">
35
+ {items.map((item, index) => (<Fragment key={index}>{renderItem(item)}</Fragment>))}
36
+ </StyledListWrapper>
37
+ </SortableContext>
38
+ <DragOverlay dropAnimation={dropAnimationConfig}>
39
+ {activeItem ? renderItem(activeItem) : null}
40
+ </DragOverlay>
41
+ </DndContext>);
42
+ }
43
+ SortableList.Item = SortableItem;
@@ -0,0 +1,10 @@
1
+ import React, { useContext } from 'react';
2
+ import { DragButton } from './styles.js';
3
+ export const DragHandle = ({ context }) => {
4
+ const { attributes, listeners, ref } = useContext(context);
5
+ return (<DragButton {...attributes} {...listeners} ref={ref}>
6
+ <svg viewBox="0 0 20 20" width="13">
7
+ <path d="M7 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 2zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 14zm6-8a2 2 0 1 0-.001-4.001A2 2 0 0 0 13 6zm0 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 14z"></path>
8
+ </svg>
9
+ </DragButton>);
10
+ };
@@ -0,0 +1,32 @@
1
+ import React, { createContext, useMemo } from 'react';
2
+ import { useSortable } from '@dnd-kit/sortable';
3
+ import { Button, Icon } from '@adminjs/design-system';
4
+ import { DragHandle } from './DragHandle.js';
5
+ import { StyledListItem } from './styles.js';
6
+ const SortableItemContext = createContext({
7
+ attributes: {},
8
+ listeners: undefined,
9
+ ref() { },
10
+ });
11
+ export function SortableItem({ children, id, onDelete, }) {
12
+ const { attributes, isDragging, listeners, setNodeRef, setActivatorNodeRef } = useSortable({ id });
13
+ const context = useMemo(() => ({
14
+ attributes,
15
+ listeners,
16
+ ref: setActivatorNodeRef,
17
+ }), [attributes, listeners, setActivatorNodeRef]);
18
+ const style = {
19
+ opacity: isDragging ? 0.4 : undefined,
20
+ };
21
+ return (<SortableItemContext.Provider value={context}>
22
+ <StyledListItem ref={setNodeRef} style={style}>
23
+ <div>
24
+ <DragHandle context={SortableItemContext}/>
25
+ {children}
26
+ </div>
27
+ <Button variant="outlined" color="danger" size="icon" onClick={(e) => onDelete(e, id)}>
28
+ <Icon icon="X" color="red"/>
29
+ </Button>
30
+ </StyledListItem>
31
+ </SortableItemContext.Provider>);
32
+ }
@@ -0,0 +1,20 @@
1
+ import { styled } from '@adminjs/design-system/styled-components';
2
+ export const StyledListItem = styled.li `
3
+ display: flex;
4
+ justify-content: space-between;
5
+ align-items: center;
6
+ background-color: #fff;
7
+ padding: 10px 20px 10px 15px;
8
+ box-shadow:
9
+ 0 0 0 calc(1px / var(--scale-x, 1)) rgba(63, 63, 68, 0.05),
10
+ 0 1px calc(3px / var(--scale-x, 1)) 0 rgba(34, 33, 81, 0.15);
11
+ border-radius: 5px;
12
+ list-style: none;
13
+ `;
14
+ export const DragButton = styled.button `
15
+ padding: 3px;
16
+ margin-right: 15px;
17
+ cursor: move;
18
+ background: none;
19
+ border: none;
20
+ `;
@@ -0,0 +1,2 @@
1
+ export { SortableItem } from './SortableItem/SortableItem.js';
2
+ export { DragHandle } from './SortableItem/DragHandle.js';
@@ -0,0 +1 @@
1
+ export { SortableList } from './SortableList.js';
@@ -0,0 +1,8 @@
1
+ import { styled } from '@adminjs/design-system/styled-components';
2
+ export const StyledListWrapper = styled.ul `
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: 12px;
6
+ padding: 0;
7
+ list-style: none;
8
+ `;
@@ -0,0 +1,67 @@
1
+ import React, { useState, useEffect, } from "react";
2
+ import { ThemeProvider } from "styled-components";
3
+ import { theme, Button, Input, Label } from "@adminjs/design-system";
4
+ import { StyledWrapper, StyledCustomInput, StyledListWrapper, StyledInputWrapper, } from "./styles.js";
5
+ import { SortableList } from "./SortableList/SortableList.js";
6
+ const StringList = ({ record, onChange, property }) => {
7
+ const stringListValue = record.params?.[property.path] ?? property.props.value ?? "";
8
+ const initialList = stringListValue
9
+ ? prepareDataForList(stringListValue)
10
+ : [];
11
+ const [inputValue, setInputValue] = useState("");
12
+ const [list, setList] = useState(initialList);
13
+ const serializedData = prepareDataForDatabase(list);
14
+ useEffect(() => {
15
+ onChange(property.path, serializedData);
16
+ }, [serializedData]);
17
+ return (<ThemeProvider theme={theme}>
18
+ <Label htmlFor="custom">String List</Label>
19
+ <StyledWrapper>
20
+ <StyledListWrapper>
21
+ <SortableList items={list} onChange={setList} renderItem={(item) => (<SortableList.Item id={item.id} onDelete={handleDeleteButton}>
22
+ {item.value}
23
+ </SortableList.Item>)}/>
24
+ </StyledListWrapper>
25
+ <StyledInputWrapper>
26
+ <Input id="stringList" name={property.path} value={serializedData} hidden/>
27
+ <StyledCustomInput id="custom" name="customInput" value={inputValue} onChange={handleInput} onKeyPress={handleEnterPress}/>
28
+ <Button variant="outlined" onClick={handleAddButton}>
29
+ Add
30
+ </Button>
31
+ </StyledInputWrapper>
32
+ </StyledWrapper>
33
+ </ThemeProvider>);
34
+ function handleInput(e) {
35
+ setInputValue(e.target.value);
36
+ }
37
+ function handleEnterPress(e) {
38
+ if (e.key === "Enter") {
39
+ handleAddButton(e);
40
+ }
41
+ }
42
+ function handleAddButton(e) {
43
+ e.preventDefault();
44
+ if (Boolean(inputValue)) {
45
+ setList([...list, createListObject(inputValue)]);
46
+ setInputValue("");
47
+ }
48
+ }
49
+ function handleDeleteButton(e, id) {
50
+ e.preventDefault();
51
+ const newData = list.filter((item) => item.id !== id);
52
+ setList(newData);
53
+ }
54
+ function prepareDataForDatabase(list) {
55
+ return list.map(({ value }) => value).join("|");
56
+ }
57
+ function prepareDataForList(str) {
58
+ return str.split("|").map((item) => createListObject(item));
59
+ }
60
+ function createListObject(value) {
61
+ return {
62
+ id: `${Date.now()}-${Math.floor(Math.random() * 1000)}`,
63
+ value: value,
64
+ };
65
+ }
66
+ };
67
+ export default StringList;
@@ -0,0 +1 @@
1
+ export { default } from "./StringList.js";
@@ -0,0 +1,16 @@
1
+ import { styled } from "@adminjs/design-system/styled-components";
2
+ import { Box, Input } from "@adminjs/design-system";
3
+ export const StyledWrapper = styled(Box) `
4
+ display: flex;
5
+ flex-direction: column;
6
+ `;
7
+ export const StyledCustomInput = styled(Input) `
8
+ width: 100%;
9
+ margin-right: 10px;
10
+ `;
11
+ export const StyledInputWrapper = styled(Box) `
12
+ display: flex;
13
+ `;
14
+ export const StyledListWrapper = styled(Box) `
15
+ margin-bottom: 15px;
16
+ `;
@@ -0,0 +1,3 @@
1
+ export { default as CustomSlug } from "./CustomSlug/CustomSlug.js";
2
+ export { default as StringList } from "./StringList/StringList.js";
3
+ export { default as Editor } from "./Editor";
@@ -0,0 +1,16 @@
1
+ import { buildFeature, } from "adminjs";
2
+ import bundleComponent from "./bundle.js";
3
+ const editorFeature = (options) => {
4
+ const { componentLoader, name } = options;
5
+ const editComponent = bundleComponent(componentLoader, "Editor");
6
+ return buildFeature({
7
+ properties: {
8
+ [name]: {
9
+ components: {
10
+ edit: editComponent,
11
+ },
12
+ },
13
+ },
14
+ });
15
+ };
16
+ export default editorFeature;
package/dist/index.cjs CHANGED
@@ -32,6 +32,7 @@ var src_exports = {};
32
32
  __export(src_exports, {
33
33
  CustomSlug: () => CustomSlug_default,
34
34
  Editor: () => Editor_default,
35
+ EditorShow: () => EditorShow_default,
35
36
  StringList: () => StringList_default
36
37
  });
37
38
  module.exports = __toCommonJS(src_exports);
@@ -49,7 +50,7 @@ var slugifyImport_default = import_slugify.default;
49
50
  var slugifyTitle = (title) => {
50
51
  return slugifyImport_default(title, {
51
52
  replacement: "-",
52
- remove: void 0,
53
+ remove: /[*+~.()'"!:@]/g,
53
54
  lower: true,
54
55
  locale: "vi",
55
56
  trim: true
@@ -91,8 +92,10 @@ var CustomSlug = ({ property, record, onChange }) => {
91
92
  }
92
93
  function generateSlug(e) {
93
94
  e.preventDefault();
94
- const title = record.title;
95
- setInputValue(slugifyTitle(title));
95
+ const title = record.params.title;
96
+ if (title) {
97
+ setInputValue(slugifyTitle(title));
98
+ }
96
99
  }
97
100
  };
98
101
  var CustomSlug_default = CustomSlug;
@@ -416,6 +419,7 @@ var EDITOR_TOOLS = {
416
419
  // src/components/Editor/Editor.jsx
417
420
  var Editor = ({ property, record, onChangeAdmin, editorId }) => {
418
421
  const [jsonData, setJsonData] = (0, import_react6.useState)();
422
+ const isSavedData = Boolean(record.params[property.path]);
419
423
  const ref = (0, import_react6.useRef)();
420
424
  (0, import_react6.useEffect)(() => {
421
425
  onChangeAdmin(property.path, jsonData);
@@ -425,7 +429,7 @@ var Editor = ({ property, record, onChangeAdmin, editorId }) => {
425
429
  const editor = new import_editorjs.default({
426
430
  holder: editorId,
427
431
  tools: EDITOR_TOOLS,
428
- data: JSON.parse(record.params.editor),
432
+ data: isSavedData ? JSON.parse(record.params[property.path]) : "",
429
433
  async onChange(api, event) {
430
434
  const data = await api.saver.save();
431
435
  setJsonData(JSON.stringify(data));
@@ -440,9 +444,34 @@ var Editor = ({ property, record, onChangeAdmin, editorId }) => {
440
444
  return /* @__PURE__ */ import_react6.default.createElement(import_styled_components8.ThemeProvider, { theme: import_design_system7.theme }, /* @__PURE__ */ import_react6.default.createElement(Label3, null, "Text"), /* @__PURE__ */ import_react6.default.createElement(EditorWrapper, null, /* @__PURE__ */ import_react6.default.createElement(StyledEditor, { id: editorId })));
441
445
  };
442
446
  var Editor_default = Editor;
447
+
448
+ // src/components/Editor/EditorShow.jsx
449
+ var import_react7 = __toESM(require("react"), 1);
450
+ var import_styled_components9 = require("styled-components");
451
+ var import_design_system8 = require("@adminjs/design-system");
452
+
453
+ // src/utils/parseHtml.ts
454
+ var import_editorjs_html = __toESM(require("editorjs-html"), 1);
455
+ var parseHtml = (jsonData) => {
456
+ const edjsParser = (0, import_editorjs_html.default)();
457
+ try {
458
+ const data = edjsParser.parse(JSON.parse(String(jsonData)));
459
+ return String(data).replace(/>,</g, "><");
460
+ } catch (e) {
461
+ return;
462
+ }
463
+ };
464
+
465
+ // src/components/Editor/EditorShow.jsx
466
+ var EditorShow = ({ property, record }) => {
467
+ const htmlContent = parseHtml(record.params[property.path]);
468
+ return /* @__PURE__ */ import_react7.default.createElement(import_styled_components9.ThemeProvider, { theme: import_design_system8.theme }, /* @__PURE__ */ import_react7.default.createElement(Label3, null, "Content"), htmlContent && /* @__PURE__ */ import_react7.default.createElement("div", { dangerouslySetInnerHTML: { __html: String(htmlContent) } }));
469
+ };
470
+ var EditorShow_default = EditorShow;
443
471
  // Annotate the CommonJS export names for ESM import in node:
444
472
  0 && (module.exports = {
445
473
  CustomSlug,
446
474
  Editor,
475
+ EditorShow,
447
476
  StringList
448
477
  });
package/dist/index.d.cts CHANGED
@@ -14,4 +14,9 @@ declare function Editor({ property, record, onChangeAdmin, editorId }: {
14
14
  editorId: any;
15
15
  }): React.JSX.Element;
16
16
 
17
- export { CustomSlug, Editor, StringList };
17
+ declare function EditorShow({ property, record }: {
18
+ property: any;
19
+ record: any;
20
+ }): React.JSX.Element;
21
+
22
+ export { CustomSlug, Editor, EditorShow, StringList };
@@ -0,0 +1,8 @@
1
+ import { FeatureType, ComponentLoader } from 'adminjs';
2
+
3
+ type EditorOptions = {
4
+ componentLoader: ComponentLoader;
5
+ };
6
+ declare const editorFeature: (options: EditorOptions) => FeatureType;
7
+
8
+ export { editorFeature as default, editorFeature };
package/dist/index.d.ts CHANGED
@@ -14,4 +14,9 @@ declare function Editor({ property, record, onChangeAdmin, editorId }: {
14
14
  editorId: any;
15
15
  }): React.JSX.Element;
16
16
 
17
- export { CustomSlug, Editor, StringList };
17
+ declare function EditorShow({ property, record }: {
18
+ property: any;
19
+ record: any;
20
+ }): React.JSX.Element;
21
+
22
+ export { CustomSlug, Editor, EditorShow, StringList };
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var slugifyImport_default = slugify;
14
14
  var slugifyTitle = (title) => {
15
15
  return slugifyImport_default(title, {
16
16
  replacement: "-",
17
- remove: void 0,
17
+ remove: /[*+~.()'"!:@]/g,
18
18
  lower: true,
19
19
  locale: "vi",
20
20
  trim: true
@@ -56,8 +56,10 @@ var CustomSlug = ({ property, record, onChange }) => {
56
56
  }
57
57
  function generateSlug(e) {
58
58
  e.preventDefault();
59
- const title = record.title;
60
- setInputValue(slugifyTitle(title));
59
+ const title = record.params.title;
60
+ if (title) {
61
+ setInputValue(slugifyTitle(title));
62
+ }
61
63
  }
62
64
  };
63
65
  var CustomSlug_default = CustomSlug;
@@ -397,6 +399,7 @@ var EDITOR_TOOLS = {
397
399
  // src/components/Editor/Editor.jsx
398
400
  var Editor = ({ property, record, onChangeAdmin, editorId }) => {
399
401
  const [jsonData, setJsonData] = useState4();
402
+ const isSavedData = Boolean(record.params[property.path]);
400
403
  const ref = useRef();
401
404
  useEffect3(() => {
402
405
  onChangeAdmin(property.path, jsonData);
@@ -406,7 +409,7 @@ var Editor = ({ property, record, onChangeAdmin, editorId }) => {
406
409
  const editor = new EditorJS({
407
410
  holder: editorId,
408
411
  tools: EDITOR_TOOLS,
409
- data: JSON.parse(record.params.editor),
412
+ data: isSavedData ? JSON.parse(record.params[property.path]) : "",
410
413
  async onChange(api, event) {
411
414
  const data = await api.saver.save();
412
415
  setJsonData(JSON.stringify(data));
@@ -421,8 +424,33 @@ var Editor = ({ property, record, onChangeAdmin, editorId }) => {
421
424
  return /* @__PURE__ */ React6.createElement(ThemeProvider3, { theme: theme3 }, /* @__PURE__ */ React6.createElement(Label3, null, "Text"), /* @__PURE__ */ React6.createElement(EditorWrapper, null, /* @__PURE__ */ React6.createElement(StyledEditor, { id: editorId })));
422
425
  };
423
426
  var Editor_default = Editor;
427
+
428
+ // src/components/Editor/EditorShow.jsx
429
+ import React7, { memo as memo2, useState as useState5, useEffect as useEffect4, useRef as useRef2 } from "react";
430
+ import { ThemeProvider as ThemeProvider4 } from "styled-components";
431
+ import { theme as theme4 } from "@adminjs/design-system";
432
+
433
+ // src/utils/parseHtml.ts
434
+ import edjsHTML from "editorjs-html";
435
+ var parseHtml = (jsonData) => {
436
+ const edjsParser = edjsHTML();
437
+ try {
438
+ const data = edjsParser.parse(JSON.parse(String(jsonData)));
439
+ return String(data).replace(/>,</g, "><");
440
+ } catch (e) {
441
+ return;
442
+ }
443
+ };
444
+
445
+ // src/components/Editor/EditorShow.jsx
446
+ var EditorShow = ({ property, record }) => {
447
+ const htmlContent = parseHtml(record.params[property.path]);
448
+ return /* @__PURE__ */ React7.createElement(ThemeProvider4, { theme: theme4 }, /* @__PURE__ */ React7.createElement(Label3, null, "Content"), htmlContent && /* @__PURE__ */ React7.createElement("div", { dangerouslySetInnerHTML: { __html: String(htmlContent) } }));
449
+ };
450
+ var EditorShow_default = EditorShow;
424
451
  export {
425
452
  CustomSlug_default as CustomSlug,
426
453
  Editor_default as Editor,
454
+ EditorShow_default as EditorShow,
427
455
  StringList_default as StringList
428
456
  };
package/dist/index.mjs ADDED
@@ -0,0 +1,37 @@
1
+ // src/features/editorFeature.ts
2
+ import {
3
+ buildFeature
4
+ } from "adminjs";
5
+
6
+ // src/bundle.ts
7
+ import path from "path";
8
+ import * as url from "url";
9
+ var __dirname = url.fileURLToPath(new URL(".", import.meta.url));
10
+ var bundle = (loader, componentName) => {
11
+ const componentPath = path.join(__dirname, `./components/${componentName}`);
12
+ return loader.add(componentName, componentPath);
13
+ };
14
+ var bundle_default = bundle;
15
+
16
+ // src/features/editorFeature.ts
17
+ var editorFeature = (options) => {
18
+ const { componentLoader } = options;
19
+ const editComponent = bundle_default(componentLoader, "Editor");
20
+ return buildFeature({
21
+ properties: {
22
+ editor: {
23
+ components: {
24
+ edit: editComponent
25
+ }
26
+ }
27
+ }
28
+ });
29
+ };
30
+ var editorFeature_default = editorFeature;
31
+
32
+ // src/index.ts
33
+ var src_default = editorFeature_default;
34
+ export {
35
+ src_default as default,
36
+ editorFeature_default as editorFeature
37
+ };
@@ -0,0 +1 @@
1
+ export { slugifyTitle } from "./slugifyTitle.js";
@@ -0,0 +1,3 @@
1
+ // This is a fix of typescript module import error
2
+ import * as slugify from "slugify";
3
+ export default slugify;
@@ -0,0 +1,10 @@
1
+ import * as slugify from "slugify";
2
+ export const slugifyTitle = (title) => {
3
+ return slugify.default(title, {
4
+ replacement: "-",
5
+ remove: undefined,
6
+ lower: true,
7
+ locale: "vi",
8
+ trim: true,
9
+ });
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulab/adminjs-components",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -25,6 +25,7 @@
25
25
  "@editorjs/list": "^1.9.0",
26
26
  "@editorjs/paragraph": "^2.11.6",
27
27
  "adminjs": "^7.8.1",
28
+ "editorjs-html": "^3.4.3",
28
29
  "react": "^18.2.0",
29
30
  "slugify": "^1.6.6",
30
31
  "styled-components": "^6.1.11"
@@ -50,8 +50,10 @@ const CustomSlug: FC<CustomSlugTypes> = ({ property, record, onChange }) => {
50
50
 
51
51
  function generateSlug(e: SyntheticEvent<HTMLInputElement>) {
52
52
  e.preventDefault();
53
- const title = record.title;
54
- setInputValue(slugifyTitle(title));
53
+ const title = record.params.title;
54
+ if (title) {
55
+ setInputValue(slugifyTitle(title));
56
+ }
55
57
  }
56
58
  };
57
59
 
@@ -9,6 +9,7 @@ import { EDITOR_TOOLS } from "./config";
9
9
 
10
10
  const Editor = ({ property, record, onChangeAdmin, editorId }) => {
11
11
  const [jsonData, setJsonData] = useState();
12
+ const isSavedData = Boolean(record.params[property.path]);
12
13
 
13
14
  const ref = useRef();
14
15
 
@@ -21,7 +22,7 @@ const Editor = ({ property, record, onChangeAdmin, editorId }) => {
21
22
  const editor = new EditorJS({
22
23
  holder: editorId,
23
24
  tools: EDITOR_TOOLS,
24
- data: JSON.parse(record.params.editor),
25
+ data: isSavedData ? JSON.parse(record.params[property.path]) : "",
25
26
  async onChange(api, event) {
26
27
  const data = await api.saver.save();
27
28
  setJsonData(JSON.stringify(data));
@@ -0,0 +1,22 @@
1
+ import React, { memo, useState, useEffect, useRef } from "react";
2
+ import { ThemeProvider } from "styled-components";
3
+ import { theme } from "@adminjs/design-system";
4
+
5
+ import { parseHtml } from "../../utils/parseHtml";
6
+
7
+ import { Label } from "./styles";
8
+
9
+ const EditorShow = ({ property, record }) => {
10
+ const htmlContent = parseHtml(record.params[property.path]);
11
+
12
+ return (
13
+ <ThemeProvider theme={theme}>
14
+ <Label>Content</Label>
15
+ {htmlContent && (
16
+ <div dangerouslySetInnerHTML={{ __html: String(htmlContent) }} />
17
+ )}
18
+ </ThemeProvider>
19
+ );
20
+ };
21
+
22
+ export default EditorShow;
@@ -1 +1,2 @@
1
- export { default } from "./Editor.jsx";
1
+ export * from "./Editor.jsx";
2
+ export * from "./EditorShow.jsx";
@@ -1,3 +1,4 @@
1
1
  export { default as CustomSlug } from "./CustomSlug/CustomSlug.js";
2
2
  export { default as StringList } from "./StringList/StringList.js";
3
- export { default as Editor } from "./Editor";
3
+ export { default as Editor } from "./Editor/Editor.jsx";
4
+ export { default as EditorShow } from "./Editor/EditorShow.jsx";
@@ -0,0 +1,12 @@
1
+ import edjsHTML from "editorjs-html";
2
+
3
+ export const parseHtml = (jsonData?: string) => {
4
+ const edjsParser = edjsHTML();
5
+
6
+ try {
7
+ const data = edjsParser.parse(JSON.parse(String(jsonData)));
8
+ return String(data).replace(/>,</g, "><");
9
+ } catch (e) {
10
+ return;
11
+ }
12
+ };
@@ -3,7 +3,7 @@ import slugify from "./slugifyImport.js";
3
3
  export const slugifyTitle = (title: string) => {
4
4
  return slugify(title, {
5
5
  replacement: "-",
6
- remove: undefined,
6
+ remove: /[*+~.()'"!:@]/g,
7
7
  lower: true,
8
8
  locale: "vi",
9
9
  trim: true,