@rulab/adminjs-components 0.0.3 → 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 -8
  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 -8
  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,10 +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)();
419
- console.log(
420
- record.params[property.path],
421
- "record.params[property.path].path"
422
- );
422
+ const isSavedData = Boolean(record.params[property.path]);
423
423
  const ref = (0, import_react6.useRef)();
424
424
  (0, import_react6.useEffect)(() => {
425
425
  onChangeAdmin(property.path, jsonData);
@@ -429,7 +429,7 @@ var Editor = ({ property, record, onChangeAdmin, editorId }) => {
429
429
  const editor = new import_editorjs.default({
430
430
  holder: editorId,
431
431
  tools: EDITOR_TOOLS,
432
- data: JSON.parse(record.params[property.path]),
432
+ data: isSavedData ? JSON.parse(record.params[property.path]) : "",
433
433
  async onChange(api, event) {
434
434
  const data = await api.saver.save();
435
435
  setJsonData(JSON.stringify(data));
@@ -444,9 +444,34 @@ var Editor = ({ property, record, onChangeAdmin, editorId }) => {
444
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 })));
445
445
  };
446
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;
447
471
  // Annotate the CommonJS export names for ESM import in node:
448
472
  0 && (module.exports = {
449
473
  CustomSlug,
450
474
  Editor,
475
+ EditorShow,
451
476
  StringList
452
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,10 +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();
400
- console.log(
401
- record.params[property.path],
402
- "record.params[property.path].path"
403
- );
402
+ const isSavedData = Boolean(record.params[property.path]);
404
403
  const ref = useRef();
405
404
  useEffect3(() => {
406
405
  onChangeAdmin(property.path, jsonData);
@@ -410,7 +409,7 @@ var Editor = ({ property, record, onChangeAdmin, editorId }) => {
410
409
  const editor = new EditorJS({
411
410
  holder: editorId,
412
411
  tools: EDITOR_TOOLS,
413
- data: JSON.parse(record.params[property.path]),
412
+ data: isSavedData ? JSON.parse(record.params[property.path]) : "",
414
413
  async onChange(api, event) {
415
414
  const data = await api.saver.save();
416
415
  setJsonData(JSON.stringify(data));
@@ -425,8 +424,33 @@ var Editor = ({ property, record, onChangeAdmin, editorId }) => {
425
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 })));
426
425
  };
427
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;
428
451
  export {
429
452
  CustomSlug_default as CustomSlug,
430
453
  Editor_default as Editor,
454
+ EditorShow_default as EditorShow,
431
455
  StringList_default as StringList
432
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.3",
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[property.path]),
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,