diff --git a/src/components/EditorCanvas/Table.jsx b/src/components/EditorCanvas/Table.jsx deleted file mode 100644 index 1e656f9a..00000000 --- a/src/components/EditorCanvas/Table.jsx +++ /dev/null @@ -1,376 +0,0 @@ -import { useState } from "react"; -import { - Tab, - ObjectType, - tableFieldHeight, - tableHeaderHeight, - tableColorStripHeight, -} from "../../data/constants"; -import { - IconEdit, - IconMore, - IconMinus, - IconDeleteStroked, - IconKeyStroked, -} from "@douyinfe/semi-icons"; -import { Popover, Tag, Button, SideSheet } from "@douyinfe/semi-ui"; -import { useLayout, useSettings, useDiagram, useSelect } from "../../hooks"; -import TableInfo from "../EditorSidePanel/TablesTab/TableInfo"; -import { useTranslation } from "react-i18next"; -import { dbToTypes } from "../../data/datatypes"; -import { isRtl } from "../../i18n/utils/rtl"; -import i18n from "../../i18n/i18n"; - -export default function Table(props) { - const [hoveredField, setHoveredField] = useState(-1); - const { database } = useDiagram(); - const { - tableData, - onPointerDown, - setHoveredTable, - handleGripField, - setLinkingLine, - } = props; - const { layout } = useLayout(); - const { deleteTable, deleteField } = useDiagram(); - const { settings } = useSettings(); - const { t } = useTranslation(); - const { selectedElement, setSelectedElement } = useSelect(); - - const height = - tableData.fields.length * tableFieldHeight + tableHeaderHeight + 7; - const openEditor = () => { - if (!layout.sidebar) { - setSelectedElement((prev) => ({ - ...prev, - element: ObjectType.TABLE, - id: tableData.id, - open: true, - })); - } else { - setSelectedElement((prev) => ({ - ...prev, - currentTab: Tab.TABLES, - element: ObjectType.TABLE, - id: tableData.id, - open: true, - })); - if (selectedElement.currentTab !== Tab.TABLES) return; - document - .getElementById(`scroll_table_${tableData.id}`) - .scrollIntoView({ behavior: "smooth" }); - } - }; - - return ( - <> - -
-
-
-
- {tableData.name} -
-
-
- -
- } - position="rightTop" - showArrow - trigger="click" - style={{ width: "200px", wordBreak: "break-word" }} - > -
-
-
- {tableData.fields.map((e, i) => { - return settings.showFieldSummary ? ( - -
-

{e.name}

-

- {e.type + - ((dbToTypes[database][e.type].isSized || - dbToTypes[database][e.type].hasPrecision) && - e.size && - e.size !== "" - ? "(" + e.size + ")" - : "")} -

-
-
- {e.primary && ( - - {t("primary")} - - )} - {e.unique && ( - - {t("unique")} - - )} - {e.notNull && ( - - {t("not_null")} - - )} - {e.increment && ( - - {t("autoincrement")} - - )} -

- {t("default_value")}: - {e.default === "" ? t("not_set") : e.default} -

-

- {t("comment")}: - {e.comment === "" ? t("not_set") : e.comment} -

-
- } - position="right" - showArrow - style={ - isRtl(i18n.language) - ? { direction: "rtl" } - : { direction: "ltr" } - } - > - {field(e, i)} - - ) : ( - field(e, i) - ); - })} - -
- - setSelectedElement((prev) => ({ - ...prev, - open: !prev.open, - })) - } - style={{ paddingBottom: "16px" }} - > -
- -
-
- - ); - - function field(fieldData, index) { - return ( -
{ - if (!e.isPrimary) return; - - setHoveredField(index); - setHoveredTable({ - tableId: tableData.id, - field: index, - }); - }} - onPointerLeave={(e) => { - if (!e.isPrimary) return; - - setHoveredField(-1); - }} - onPointerDown={(e) => { - // Required for onPointerLeave to trigger when a touch pointer leaves - // https://stackoverflow.com/a/70976017/1137077 - e.target.releasePointerCapture(e.pointerId); - }} - > -
-
-
- {hoveredField === index ? ( -
-
- ); - } -} diff --git a/src/components/EditorCanvas/Table/components/TableField.jsx b/src/components/EditorCanvas/Table/components/TableField.jsx new file mode 100644 index 00000000..e96ce7b8 --- /dev/null +++ b/src/components/EditorCanvas/Table/components/TableField.jsx @@ -0,0 +1,133 @@ +import React, { forwardRef } from "react"; +import { dbToTypes } from "../../../../data/datatypes"; +import { useDiagram } from "../../../../hooks"; +import { Button } from "@douyinfe/semi-ui"; +import { IconMinus, IconKeyStroked } from "@douyinfe/semi-icons"; + +const TableField = forwardRef((props, ref) => { + const { + tableData, + fieldData, + index, + setHoveredTable, + handleGripField, + setLinkingLine, + setHoveredField, + hoveredField, + tableFieldHeight, + tableHeaderHeight, + tableColorStripHeight, + } = props; + const { database, deleteField } = useDiagram(); + + const FieldSize = React.memo(({ field }) => { + let hasSize = + dbToTypes[database][field.type].isSized || + dbToTypes[database][field.type].hasPrecision; + let sizeValid = field.size && field.size !== ""; + + if (hasSize && sizeValid) { + return field.type + `(${field.size})`; + } else { + return field.type; + } + }); + + FieldSize.displayName = "FieldSize"; + + return ( +
{ + if (!e.isPrimary) return; + + setHoveredField(index); + setHoveredTable({ + tableId: tableData.id, + field: index, + }); + }} + onPointerLeave={(e) => { + if (!e.isPrimary) return; + + setHoveredField(-1); + }} + onPointerDown={(e) => { + // Required for onPointerLeave to trigger when a touch pointer leaves + // https://stackoverflow.com/a/70976017/1137077 + e.target.releasePointerCapture(e.pointerId); + }} + > +
+
+ +
+ {hoveredField === index ? ( +
+
+ ); +}); + +TableField.displayName = "TableField"; + +export default TableField; diff --git a/src/components/EditorCanvas/Table/components/TableFieldPopover.jsx b/src/components/EditorCanvas/Table/components/TableFieldPopover.jsx new file mode 100644 index 00000000..00d19bee --- /dev/null +++ b/src/components/EditorCanvas/Table/components/TableFieldPopover.jsx @@ -0,0 +1,83 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import i18n from "../../../../i18n/i18n"; +import { isRtl } from "../../../../i18n/utils/rtl"; +import { Popover, Tag } from "@douyinfe/semi-ui"; +import { dbToTypes } from "../../../../data/datatypes"; +import { useDiagram } from "../../../../hooks"; + +export default function TableFieldPopover({ fieldData, children, visible }) { + const { database } = useDiagram(); + const { t } = useTranslation(); + + if (!visible) { + return {children}; + } + + const FieldSize = React.memo(({ field }) => { + let hasSize = + dbToTypes[database][field.type].isSized || + dbToTypes[database][field.type].hasPrecision; + let sizeValid = field.size && field.size !== ""; + + if (hasSize && sizeValid) { + return `(${field.size})`; + } else { + return ""; + } + }); + + FieldSize.displayName = "FieldSize"; + + return ( + +
+

{fieldData.name}

+

{}

+
+ +
+ + {fieldData.primary && ( + + {t("primary")} + + )} + {fieldData.unique && ( + + {t("unique")} + + )} + {fieldData.notNull && ( + + {t("not_null")} + + )} + {fieldData.increment && ( + + {t("autoincrement")} + + )} +

+ {t("default_value")}: + {fieldData.default === "" ? t("not_set") : fieldData.default} +

+

+ {t("comment")}: + {fieldData.comment === "" ? t("not_set") : fieldData.comment} +

+ + } + position="right" + showArrow + style={isRtl(i18n.language) ? { direction: "rtl" } : { direction: "ltr" }} + > + {children} +
+ ); +} diff --git a/src/components/EditorCanvas/Table/components/TableHeader.jsx b/src/components/EditorCanvas/Table/components/TableHeader.jsx new file mode 100644 index 00000000..7d214ac5 --- /dev/null +++ b/src/components/EditorCanvas/Table/components/TableHeader.jsx @@ -0,0 +1,105 @@ +import { IconEdit, IconMore, IconDeleteStroked } from "@douyinfe/semi-icons"; +import { Popover, Tag, Button } from "@douyinfe/semi-ui"; +import { useDiagram } from "../../../../hooks"; + +export default function TableHeader({ tableData, settings, openEditor, t }) { + const { deleteTable } = useDiagram(); + + return ( +
+
+ {tableData.name} +
+
+
+ +
+ } + position="rightTop" + showArrow + trigger="click" + style={{ width: "200px", wordBreak: "break-word" }} + > +
+
+ + ); +} diff --git a/src/components/EditorCanvas/Table/index.jsx b/src/components/EditorCanvas/Table/index.jsx new file mode 100644 index 00000000..69bc5208 --- /dev/null +++ b/src/components/EditorCanvas/Table/index.jsx @@ -0,0 +1,156 @@ +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { SideSheet } from "@douyinfe/semi-ui"; +import { useLayout, useSettings, useSelect } from "../../../hooks"; + +import { + Tab, + ObjectType, + tableFieldHeight, + tableHeaderHeight, + tableColorStripHeight, +} from "../../../data/constants"; + +import TableFieldPopover from "./components/TableFieldPopover"; +import TableField from "./components/TableField"; +import TableHeader from "./components/TableHeader"; + +import TableInfo from "../../EditorSidePanel/TablesTab/TableInfo"; + +export default function Table(props) { + const [hoveredField, setHoveredField] = useState(-1); + const { + tableData, + onPointerDown, + setHoveredTable, + handleGripField, + setLinkingLine, + } = props; + const { layout } = useLayout(); + const { settings } = useSettings(); + const { t } = useTranslation(); + const { selectedElement, setSelectedElement } = useSelect(); + + const height = + tableData.fields.length * tableFieldHeight + tableHeaderHeight + 7; + + const openEditor = () => { + if (!layout.sidebar) { + setSelectedElement((prev) => ({ + ...prev, + element: ObjectType.TABLE, + id: tableData.id, + open: true, + })); + } else { + setSelectedElement((prev) => ({ + ...prev, + currentTab: Tab.TABLES, + element: ObjectType.TABLE, + id: tableData.id, + open: true, + })); + if (selectedElement.currentTab !== Tab.TABLES) return; + document + .getElementById(`scroll_table_${tableData.id}`) + .scrollIntoView({ behavior: "smooth" }); + } + }; + + const TableHeaderBand = React.memo(({ color }) => { + return ( +
+ ); + }); + + TableHeaderBand.displayName = "TableHeaderBand"; + + return ( + <> + +
+ + + + + {tableData.fields.map((fieldData, index) => { + return ( + + + + ); + })} +
+
+ + + setSelectedElement((prev) => ({ + ...prev, + open: !prev.open, + })) + } + style={{ paddingBottom: "16px" }} + > +
+ +
+
+ + ); +}