@msdshsk/react-er-canvas 0.0.1

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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +48 -0
  3. package/README.ja.md +216 -0
  4. package/README.md +216 -0
  5. package/dist/components/JoinEdge.d.ts +10 -0
  6. package/dist/components/JoinEdge.d.ts.map +1 -0
  7. package/dist/components/MermaidER.d.ts +46 -0
  8. package/dist/components/MermaidER.d.ts.map +1 -0
  9. package/dist/components/TableNode.d.ts +30 -0
  10. package/dist/components/TableNode.d.ts.map +1 -0
  11. package/dist/core/index.d.ts +5 -0
  12. package/dist/core/index.d.ts.map +1 -0
  13. package/dist/core/layout.d.ts +58 -0
  14. package/dist/core/layout.d.ts.map +1 -0
  15. package/dist/core/layout.test.d.ts +2 -0
  16. package/dist/core/layout.test.d.ts.map +1 -0
  17. package/dist/core/model.d.ts +55 -0
  18. package/dist/core/model.d.ts.map +1 -0
  19. package/dist/core/parser/grammar.d.ts +22 -0
  20. package/dist/core/parser/grammar.d.ts.map +1 -0
  21. package/dist/core/parser/index.d.ts +15 -0
  22. package/dist/core/parser/index.d.ts.map +1 -0
  23. package/dist/core/parser/lexer.d.ts +18 -0
  24. package/dist/core/parser/lexer.d.ts.map +1 -0
  25. package/dist/core/parser/parser.test.d.ts +2 -0
  26. package/dist/core/parser/parser.test.d.ts.map +1 -0
  27. package/dist/core/parser/resolve.test.d.ts +2 -0
  28. package/dist/core/parser/resolve.test.d.ts.map +1 -0
  29. package/dist/core-BtdV83x9.cjs +2 -0
  30. package/dist/core-BtdV83x9.cjs.map +1 -0
  31. package/dist/core-DZ30VgUT.js +345 -0
  32. package/dist/core-DZ30VgUT.js.map +1 -0
  33. package/dist/core.cjs +1 -0
  34. package/dist/core.js +2 -0
  35. package/dist/index.cjs +2 -0
  36. package/dist/index.cjs.map +1 -0
  37. package/dist/index.d.ts +6 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +592 -0
  40. package/dist/index.js.map +1 -0
  41. package/package.json +92 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-DZ30VgUT.js","names":[],"sources":["../src/core/parser/lexer.ts","../src/core/parser/grammar.ts","../src/core/parser/index.ts","../src/core/layout.ts"],"sourcesContent":["import { createToken, Lexer } from 'chevrotain';\n\nexport const WhiteSpace = createToken({\n name: 'WhiteSpace',\n pattern: /[\\s\\r\\n]+/,\n group: Lexer.SKIPPED,\n});\n\nexport const GroupStart = createToken({\n name: 'GroupStart',\n pattern: /%%[ \\t]*@group[ \\t]+[A-Za-z_][A-Za-z0-9_]*/,\n});\n\nexport const GroupEnd = createToken({\n name: 'GroupEnd',\n pattern: /%%[ \\t]*@endgroup\\b/,\n});\n\nexport const Comment = createToken({\n name: 'Comment',\n pattern: /%%[^\\r\\n]*/,\n group: Lexer.SKIPPED,\n});\n\nexport const ErDiagram = createToken({\n name: 'ErDiagram',\n pattern: /erDiagram\\b/,\n});\n\nexport const KeyConstraint = createToken({\n name: 'KeyConstraint',\n pattern: /(?:PK|FK|UK)\\b/,\n});\n\nexport const Identifier = createToken({\n name: 'Identifier',\n pattern: /[A-Za-z_][A-Za-z0-9_-]*(?:\\([^)\\r\\n]*\\))?/,\n});\n\nexport const RelSymbol = createToken({\n name: 'RelSymbol',\n pattern: /(?:\\|\\||\\|o|\\}\\||\\}o)(?:--|\\.\\.)(?:\\|\\||o\\||\\|\\{|o\\{)/,\n});\n\nexport const StringLiteral = createToken({\n name: 'StringLiteral',\n pattern: /\"[^\"\\r\\n]*\"/,\n});\n\nexport const LBrace = createToken({ name: 'LBrace', pattern: /\\{/ });\nexport const RBrace = createToken({ name: 'RBrace', pattern: /\\}/ });\nexport const Colon = createToken({ name: 'Colon', pattern: /:/ });\n\nexport const Comma = createToken({\n name: 'Comma',\n pattern: /,/,\n group: Lexer.SKIPPED,\n});\n\nexport const RefDirective = createToken({\n name: 'RefDirective',\n pattern: /%%[ \\t]*@ref[ \\t]+[A-Za-z_][A-Za-z0-9_]*\\.[A-Za-z_][A-Za-z0-9_-]*[ \\t]*->[ \\t]*[A-Za-z_][A-Za-z0-9_]*\\.[A-Za-z_][A-Za-z0-9_-]*/,\n});\n\nexport const allTokens = [\n WhiteSpace,\n Comma,\n GroupStart,\n GroupEnd,\n RefDirective,\n Comment,\n ErDiagram,\n KeyConstraint,\n Identifier,\n RelSymbol,\n StringLiteral,\n LBrace,\n RBrace,\n Colon,\n];\n\nexport const erLexer = new Lexer(allTokens);\n","import { EmbeddedActionsParser } from 'chevrotain';\nimport {\n allTokens,\n ErDiagram,\n Identifier,\n LBrace,\n RBrace,\n Colon,\n RelSymbol,\n StringLiteral,\n KeyConstraint,\n GroupStart,\n GroupEnd,\n RefDirective,\n} from './lexer';\nimport type { Cardinality, Column, ERModel, Group, Relation, Table } from '../model';\n\nconst LEFT_CARDINALITY: Record<string, Cardinality> = {\n '||': 'one',\n '|o': 'one-or-zero',\n '}|': 'one-or-many',\n '}o': 'zero-or-many',\n};\n\nconst RIGHT_CARDINALITY: Record<string, Cardinality> = {\n '||': 'one',\n 'o|': 'one-or-zero',\n '|{': 'one-or-many',\n 'o{': 'zero-or-many',\n};\n\nfunction parseRelSymbol(symbol: string): {\n from: Cardinality;\n to: Cardinality;\n identifying: boolean;\n} {\n const identifying = symbol.includes('--');\n const middle = identifying ? '--' : '..';\n const [leftSym, rightSym] = symbol.split(middle);\n return {\n from: LEFT_CARDINALITY[leftSym] ?? 'one',\n to: RIGHT_CARDINALITY[rightSym] ?? 'one',\n identifying,\n };\n}\n\nclass ERGrammar extends EmbeddedActionsParser {\n private tables: Map<string, Table> = new Map();\n private relations: Relation[] = [];\n private groupOrder: string[] = [];\n private groupMembers: Map<string, string[]> = new Map();\n private currentGroup: string | undefined;\n private lastRelation: Relation | undefined;\n\n constructor() {\n super(allTokens);\n this.performSelfAnalysis();\n }\n\n public resetState(): void {\n // Chevrotain's parent class provides its own reset() that clears\n // internal recognizer state (errors, RULE_STACK, lookahead caches).\n // We invoke that here, then clear our domain state.\n super.reset();\n this.tables = new Map();\n this.relations = [];\n this.groupOrder = [];\n this.groupMembers = new Map();\n this.currentGroup = undefined;\n this.lastRelation = undefined;\n }\n\n public buildModel(): ERModel {\n const groups: Group[] = this.groupOrder.map((name) => ({\n name,\n tables: this.groupMembers.get(name) ?? [],\n }));\n return {\n tables: Array.from(this.tables.values()),\n relations: this.relations,\n groups,\n };\n }\n\n private ensureTable(name: string): Table {\n let table = this.tables.get(name);\n if (!table) {\n table = { name, columns: [], group: this.currentGroup };\n this.tables.set(name, table);\n }\n if (this.currentGroup && !table.group) {\n table.group = this.currentGroup;\n }\n if (this.currentGroup) {\n const members = this.groupMembers.get(this.currentGroup) ?? [];\n if (!members.includes(name)) {\n members.push(name);\n this.groupMembers.set(this.currentGroup, members);\n }\n }\n return table;\n }\n\n public diagram = this.RULE('diagram', () => {\n this.CONSUME(ErDiagram);\n this.MANY(() => this.SUBRULE(this.statement));\n });\n\n private statement = this.RULE('statement', () => {\n this.OR([\n { ALT: () => this.SUBRULE(this.entityOrRelation) },\n {\n ALT: () => {\n const tok = this.CONSUME(GroupStart);\n this.ACTION(() => {\n const match = /@group[ \\t]+([A-Za-z_][A-Za-z0-9_]*)/.exec(tok.image);\n const name = match ? match[1] : 'unnamed';\n this.currentGroup = name;\n if (!this.groupMembers.has(name)) {\n this.groupMembers.set(name, []);\n this.groupOrder.push(name);\n }\n });\n },\n },\n {\n ALT: () => {\n this.CONSUME(GroupEnd);\n this.ACTION(() => {\n this.currentGroup = undefined;\n });\n },\n },\n {\n ALT: () => {\n const tok = this.CONSUME(RefDirective);\n this.ACTION(() => {\n const m = /@ref[ \\t]+([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z_][A-Za-z0-9_-]*)[ \\t]*->[ \\t]*([A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z_][A-Za-z0-9_-]*)/.exec(\n tok.image,\n );\n if (!m || !this.lastRelation) return;\n const [, aTable, aCol, bTable, bCol] = m;\n const rel = this.lastRelation;\n if (aTable === rel.from && bTable === rel.to) {\n rel.fromColumn = aCol;\n rel.toColumn = bCol;\n } else if (aTable === rel.to && bTable === rel.from) {\n rel.fromColumn = bCol;\n rel.toColumn = aCol;\n }\n });\n },\n },\n ]);\n });\n\n private entityOrRelation = this.RULE('entityOrRelation', () => {\n const left = this.CONSUME(Identifier).image;\n this.OR([\n {\n ALT: () => {\n const columns = this.SUBRULE(this.entityBody);\n this.ACTION(() => {\n const table = this.ensureTable(left);\n table.columns = columns;\n });\n },\n },\n {\n ALT: () => {\n const symbolToken = this.CONSUME(RelSymbol);\n const right = this.CONSUME2(Identifier).image;\n let label: string | undefined;\n this.OPTION(() => {\n this.CONSUME(Colon);\n this.OR2([\n {\n ALT: () => {\n label = this.CONSUME3(Identifier).image;\n },\n },\n {\n ALT: () => {\n const s = this.CONSUME(StringLiteral).image;\n label = s.slice(1, -1);\n },\n },\n ]);\n });\n this.ACTION(() => {\n this.ensureTable(left);\n this.ensureTable(right);\n const card = parseRelSymbol(symbolToken.image);\n const relation: Relation = {\n id: `${left}__${right}__${this.relations.length}`,\n from: left,\n to: right,\n fromCardinality: card.from,\n toCardinality: card.to,\n identifying: card.identifying,\n label,\n };\n this.relations.push(relation);\n this.lastRelation = relation;\n });\n },\n },\n ]);\n });\n\n private entityBody = this.RULE('entityBody', (): Column[] => {\n const columns: Column[] = [];\n this.CONSUME(LBrace);\n this.MANY(() => {\n const col = this.SUBRULE(this.attribute);\n columns.push(col);\n });\n this.CONSUME(RBrace);\n return columns;\n });\n\n private attribute = this.RULE('attribute', (): Column => {\n const type = this.CONSUME(Identifier, { LABEL: 'type' }).image;\n const name = this.CONSUME2(Identifier, { LABEL: 'name' }).image;\n const keys: { pk?: boolean; fk?: boolean; uk?: boolean } = {};\n this.MANY(() => {\n const k = this.CONSUME(KeyConstraint).image.toUpperCase();\n if (k === 'PK') keys.pk = true;\n else if (k === 'FK') keys.fk = true;\n else if (k === 'UK') keys.uk = true;\n });\n let comment: string | undefined;\n this.OPTION(() => {\n const s = this.CONSUME(StringLiteral).image;\n comment = s.slice(1, -1);\n });\n return { type, name, keys, comment };\n });\n}\n\nexport const erGrammar = new ERGrammar();\n","import type { Cardinality, Column, ERModel, Relation, Table } from '../model';\nimport { erLexer } from './lexer';\nimport { erGrammar } from './grammar';\n\nexport class MermaidERParseError extends Error {\n constructor(\n message: string,\n public readonly errors: ReadonlyArray<{ message: string; line?: number; column?: number }>,\n ) {\n super(message);\n this.name = 'MermaidERParseError';\n }\n}\n\nexport function parseMermaidER(source: string): ERModel {\n const lexed = erLexer.tokenize(source);\n if (lexed.errors.length > 0) {\n const first = lexed.errors[0];\n throw new MermaidERParseError(\n `Lex error at line ${first.line}:${first.column}: ${first.message}`,\n lexed.errors.map((e) => ({\n message: e.message,\n line: e.line ?? undefined,\n column: e.column ?? undefined,\n })),\n );\n }\n\n erGrammar.resetState();\n erGrammar.input = lexed.tokens;\n erGrammar.diagram();\n\n if (erGrammar.errors.length > 0) {\n const first = erGrammar.errors[0];\n throw new MermaidERParseError(\n `Parse error at line ${first.token.startLine}:${first.token.startColumn}: ${first.message}`,\n erGrammar.errors.map((e) => ({\n message: e.message,\n line: e.token.startLine,\n column: e.token.startColumn,\n })),\n );\n }\n\n const model = erGrammar.buildModel();\n return resolveColumnRefs(model);\n}\n\nconst PK_CARDINALITIES: ReadonlySet<Cardinality> = new Set(['one', 'one-or-zero']);\n\nfunction resolveColumnRefs(model: ERModel): ERModel {\n const tableMap = new Map(model.tables.map((t) => [t.name, t]));\n\n for (const rel of model.relations) {\n if (rel.fromColumn && rel.toColumn) continue;\n\n const fromTable = tableMap.get(rel.from);\n const toTable = tableMap.get(rel.to);\n if (!fromTable || !toTable) continue;\n\n const fromIsPkSide = PK_CARDINALITIES.has(rel.fromCardinality);\n const toIsPkSide = PK_CARDINALITIES.has(rel.toCardinality);\n\n let pkTable: Table;\n let fkTable: Table;\n let pkOnFromSide: boolean;\n\n if (fromIsPkSide && !toIsPkSide) {\n pkTable = fromTable;\n fkTable = toTable;\n pkOnFromSide = true;\n } else if (toIsPkSide && !fromIsPkSide) {\n pkTable = toTable;\n fkTable = fromTable;\n pkOnFromSide = false;\n } else {\n pkTable = fromTable;\n fkTable = toTable;\n pkOnFromSide = true;\n }\n\n const pkCol = pkTable.columns.find((c) => c.keys.pk);\n const fkCol = inferFkColumn(rel, fkTable, pkTable, pkCol?.name);\n\n if (!pkCol || !fkCol) continue;\n\n if (pkOnFromSide) {\n if (!rel.fromColumn) rel.fromColumn = pkCol.name;\n if (!rel.toColumn) rel.toColumn = fkCol.name;\n } else {\n if (!rel.fromColumn) rel.fromColumn = fkCol.name;\n if (!rel.toColumn) rel.toColumn = pkCol.name;\n }\n }\n\n return model;\n}\n\nfunction inferFkColumn(\n rel: Relation,\n fkTable: Table,\n pkTable: Table,\n pkColName: string | undefined,\n): Column | undefined {\n const fkCols = fkTable.columns.filter((c) => c.keys.fk);\n\n if (fkCols.length === 0) {\n return guessByNaming(fkTable.columns, pkTable.name, pkColName);\n }\n if (fkCols.length === 1) return fkCols[0];\n\n if (rel.label) {\n const prefix = `${fkTable.name}_`;\n const suffix = '_foreign';\n if (rel.label.startsWith(prefix) && rel.label.endsWith(suffix)) {\n const colName = rel.label.slice(prefix.length, rel.label.length - suffix.length);\n const col = fkCols.find((c) => c.name === colName);\n if (col) return col;\n }\n if (rel.label.startsWith(prefix)) {\n const colCandidate = rel.label.slice(prefix.length);\n const col = fkCols.find((c) => c.name === colCandidate);\n if (col) return col;\n }\n }\n\n const guessed = guessByNaming(fkCols, pkTable.name, pkColName);\n if (guessed) return guessed;\n\n return fkCols[0];\n}\n\nfunction guessByNaming(\n candidates: Column[],\n pkTableName: string,\n pkColName: string | undefined,\n): Column | undefined {\n const pkTableLower = pkTableName.toLowerCase();\n const pkColLower = pkColName?.toLowerCase() ?? 'id';\n\n return (\n candidates.find((c) => c.name.toLowerCase() === `${pkTableLower}_${pkColLower}`) ??\n candidates.find((c) => c.name.toLowerCase() === `${pkTableLower}_id`) ??\n candidates.find(\n (c) =>\n c.name.toLowerCase().includes(pkTableLower) &&\n (c.keys.fk || c.name.toLowerCase().endsWith('_id')),\n )\n );\n}\n","import ELK from 'elkjs/lib/elk.bundled.js';\nimport type { ElkExtendedEdge, ElkNode } from 'elkjs/lib/elk-api';\nimport type { ERModel } from './model';\n\nexport type LayoutDirection = 'RIGHT' | 'DOWN' | 'LEFT' | 'UP';\n\nexport type LayoutAlgorithm =\n | 'layered'\n | 'stress'\n | 'force'\n | 'mrtree'\n | 'rectpacking'\n | 'radial';\n\nexport interface LayoutOptions {\n engine?: 'elk';\n algorithm?: LayoutAlgorithm;\n direction?: LayoutDirection;\n /**\n * Target aspect ratio (width / height). Combined with the layered algorithm,\n * enables wrapping so the layout fits common screen sizes.\n * Example: `16/9`, `Math.SQRT2` for A4 landscape, `1` for square.\n */\n aspectRatio?: number;\n nodeSpacing?: number;\n rankSpacing?: number;\n /** Raw ELK layoutOptions, merged after the defaults. */\n raw?: Record<string, string>;\n}\n\nexport interface PositionedNode {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface EdgePoint {\n x: number;\n y: number;\n}\n\nexport interface PositionedEdge {\n id: string;\n source: string;\n target: string;\n startPoint?: EdgePoint;\n endPoint?: EdgePoint;\n bendPoints?: EdgePoint[];\n}\n\nexport interface LayoutResult {\n nodes: PositionedNode[];\n edges: PositionedEdge[];\n width: number;\n height: number;\n}\n\nexport const NODE_WIDTH = 240;\nexport const HEADER_HEIGHT = 32;\nexport const ROW_HEIGHT = 22;\nexport const VERTICAL_PADDING = 8;\n\nexport function estimateNodeHeight(columnCount: number): number {\n return HEADER_HEIGHT + Math.max(columnCount, 1) * ROW_HEIGHT + VERTICAL_PADDING * 2;\n}\n\nexport function buildElkLayoutOptions(opts: {\n algorithm: LayoutAlgorithm;\n direction: LayoutDirection;\n aspectRatio: number | undefined;\n nodeSpacing: number;\n rankSpacing: number;\n raw: Record<string, string>;\n}): Record<string, string> {\n const out: Record<string, string> = {\n 'elk.algorithm': opts.algorithm,\n 'elk.spacing.nodeNode': String(opts.nodeSpacing),\n };\n\n if (opts.aspectRatio !== undefined) {\n out['elk.aspectRatio'] = String(opts.aspectRatio);\n }\n\n switch (opts.algorithm) {\n case 'layered':\n out['elk.direction'] = opts.direction;\n out['elk.layered.spacing.nodeNodeBetweenLayers'] = String(opts.rankSpacing);\n out['elk.edgeRouting'] = 'ORTHOGONAL';\n if (opts.aspectRatio !== undefined) {\n out['elk.layered.wrapping.strategy'] = 'MULTI_EDGE';\n }\n break;\n case 'mrtree':\n out['elk.direction'] = opts.direction;\n break;\n case 'stress':\n out['elk.stress.desiredEdgeLength'] = String(opts.nodeSpacing * 4);\n break;\n case 'force':\n out['elk.force.repulsivePower'] = '1';\n break;\n case 'rectpacking':\n out['elk.rectpacking.packing.strategy'] = 'SIMPLE';\n break;\n case 'radial':\n // radial defaults\n break;\n }\n\n return { ...out, ...opts.raw };\n}\n\n// Reuse a single ELK instance across calls. Constructing one allocates a heavy\n// engine; doing it per layout (i.e., per keystroke in live-editing scenarios)\n// is wasteful. ELK's `layout()` is reentrant-safe enough for our usage.\nconst elk = new ELK();\n\nexport async function layoutER(\n model: ERModel,\n options: LayoutOptions = {},\n): Promise<LayoutResult> {\n const {\n algorithm = 'layered',\n direction = 'DOWN',\n aspectRatio,\n nodeSpacing = 60,\n rankSpacing = 80,\n raw = {},\n } = options;\n\n const graph: ElkNode = {\n id: 'root',\n layoutOptions: buildElkLayoutOptions({\n algorithm,\n direction,\n aspectRatio,\n nodeSpacing,\n rankSpacing,\n raw,\n }),\n children: model.tables.map((t) => ({\n id: t.name,\n width: NODE_WIDTH,\n height: estimateNodeHeight(t.columns.length),\n })),\n edges: model.relations.map<ElkExtendedEdge>((r) => ({\n id: r.id,\n sources: [r.from],\n targets: [r.to],\n })),\n };\n\n const layouted = await elk.layout(graph);\n\n const nodes: PositionedNode[] = (layouted.children ?? []).map((c) => ({\n id: c.id,\n x: c.x ?? 0,\n y: c.y ?? 0,\n width: c.width ?? NODE_WIDTH,\n height: c.height ?? estimateNodeHeight(0),\n }));\n\n const layoutedEdges = (layouted.edges ?? []) as ElkExtendedEdge[];\n const edges: PositionedEdge[] = layoutedEdges.map((e) => {\n const section = e.sections?.[0];\n return {\n id: e.id,\n source: e.sources[0],\n target: e.targets[0],\n startPoint: section?.startPoint,\n endPoint: section?.endPoint,\n bendPoints: section?.bendPoints,\n };\n });\n\n return {\n nodes,\n edges,\n width: layouted.width ?? 0,\n height: layouted.height ?? 0,\n };\n}\n"],"mappings":"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"}
package/dist/core.cjs ADDED
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./core-BtdV83x9.cjs`);exports.HEADER_HEIGHT=e.t,exports.MermaidERParseError=e.s,exports.NODE_WIDTH=e.n,exports.ROW_HEIGHT=e.r,exports.VERTICAL_PADDING=e.i,exports.estimateNodeHeight=e.a,exports.layoutER=e.o,exports.parseMermaidER=e.c;
package/dist/core.js ADDED
@@ -0,0 +1,2 @@
1
+ import { a as e, c as t, i as n, n as r, o as i, r as a, s as o, t as s } from "./core-DZ30VgUT.js";
2
+ export { s as HEADER_HEIGHT, o as MermaidERParseError, r as NODE_WIDTH, a as ROW_HEIGHT, n as VERTICAL_PADDING, e as estimateNodeHeight, i as layoutER, t as parseMermaidER };
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./core-BtdV83x9.cjs`);let t=require(`react`),n=require(`@xyflow/react`),r=require(`react/jsx-runtime`);var i=(0,t.createContext)(new Map),a=(0,t.createContext)({enabled:!1,selected:new Set,onToggle:()=>void 0}),o=(0,t.createContext)(!1),s=(0,t.createContext)({}),c={pk:{label:`PK`,bg:`#f59e0b`},fk:{label:`FK`,bg:`#3b82f6`},uk:{label:`UK`,bg:`#10b981`}};function l({tableName:e,column:t,highlighted:n,onClick:i,selectionEnabled:a,selected:o,onSelectToggle:s}){let l=[];return t.keys.pk&&l.push(c.pk),t.keys.fk&&l.push(c.fk),t.keys.uk&&l.push(c.uk),(0,r.jsxs)(`div`,{title:t.comment,onClick:i?()=>i(e,t.name):void 0,style:{display:`flex`,alignItems:`center`,gap:6,padding:`0 10px`,fontSize:12,fontFamily:`ui-monospace, SFMono-Regular, Consolas, monospace`,borderTop:`1px solid #eee`,height:22,boxSizing:`border-box`,cursor:i?`pointer`:`default`,background:n?`#fef3c7`:o?`#eff6ff`:`transparent`,transition:`background 0.15s`},children:[a&&(0,r.jsx)(`input`,{type:`checkbox`,checked:o,onChange:e=>s(e.target.checked),onClick:e=>e.stopPropagation(),style:{width:13,height:13,margin:0,flexShrink:0,cursor:`pointer`}}),(0,r.jsx)(`span`,{style:{display:`flex`,gap:2,flexShrink:0,minWidth:18},children:l.map(e=>(0,r.jsx)(`span`,{style:{display:`inline-block`,padding:`0 4px`,borderRadius:3,background:e.bg,color:`#fff`,fontSize:9,fontWeight:700,lineHeight:`14px`},children:e.label},e.label))}),(0,r.jsx)(`span`,{style:{flexShrink:0,fontWeight:t.keys.pk?600:400,color:`#1f2937`},children:t.name}),t.type&&(0,r.jsx)(`span`,{style:{flex:1,textAlign:`right`,color:`#9ca3af`,fontStyle:`italic`,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},children:t.type})]})}var u=(0,t.memo)(function({data:e}){let{table:c}=e,u=(0,t.useContext)(i),d=(0,t.useContext)(a),f=(0,t.useContext)(o),p=(0,t.useContext)(s),m=p.onColumnClick,h=u.get(c.name),g=c.group?`#1e40af`:`#374151`,_=e=>({...e,width:f?9:6,height:f?9:6,background:f?`#3b82f6`:`transparent`,border:f?`1.5px solid #fff`:`none`,boxShadow:f?`0 0 0 1px rgba(59,130,246,0.4)`:`none`,opacity:f?.85:0,pointerEvents:f?`auto`:`none`,cursor:f?`crosshair`:`default`});return(0,r.jsxs)(`div`,{style:{background:`#fff`,border:`1px solid #c4c4c4`,borderRadius:6,boxShadow:`0 2px 6px rgba(0,0,0,0.08)`,overflow:`visible`,width:`100%`,height:`100%`,display:`flex`,flexDirection:`column`,position:`relative`},children:[(0,r.jsx)(n.Handle,{id:`__default-target`,type:`target`,position:n.Position.Left,style:_({top:32/2})}),(0,r.jsx)(n.Handle,{id:`__default-source`,type:`source`,position:n.Position.Right,style:_({top:32/2})}),(0,r.jsxs)(`div`,{style:{padding:`6px 10px`,background:g,color:`#fff`,fontWeight:600,fontSize:13,height:32,boxSizing:`border-box`,display:`flex`,alignItems:`center`,justifyContent:`space-between`,gap:8,borderTopLeftRadius:6,borderTopRightRadius:6},children:[(0,r.jsx)(`span`,{style:{overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},children:c.name}),(0,r.jsxs)(`span`,{style:{display:`flex`,alignItems:`center`,gap:4,flexShrink:0},children:[c.group&&(0,r.jsx)(`span`,{style:{fontSize:10,opacity:.75,fontWeight:400,padding:`1px 5px`,border:`1px solid rgba(255,255,255,0.3)`,borderRadius:3},children:c.group}),p.onTableRemove&&(0,r.jsx)(`button`,{className:`nodrag`,onClick:e=>{e.stopPropagation(),p.onTableRemove?.(c.name)},onMouseDown:e=>e.stopPropagation(),title:`Remove this table`,style:{background:`rgba(255,255,255,0.18)`,border:`none`,color:`#fff`,width:18,height:18,borderRadius:3,cursor:`pointer`,fontSize:13,fontWeight:700,padding:0,lineHeight:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:`×`})]})]}),c.columns.map((e,i)=>{let a=32+i*22+22/2,o=h?.has(e.name)??!1,s=`${c.name}.${e.name}`,u=d.enabled&&d.selected.has(s);return(0,r.jsxs)(t.Fragment,{children:[(0,r.jsx)(n.Handle,{id:`${e.name}__target`,type:`target`,position:n.Position.Left,style:_({top:a})}),(0,r.jsx)(n.Handle,{id:`${e.name}__source`,type:`source`,position:n.Position.Right,style:_({top:a})}),(0,r.jsx)(l,{tableName:c.name,column:e,highlighted:o,onClick:m,selectionEnabled:d.enabled,selected:u,onSelectToggle:t=>d.onToggle(c.name,e.name,t)})]},`${e.name}-${i}`)})]})}),d=(0,t.memo)(function({id:e,sourceX:t,sourceY:i,targetX:a,targetY:o,sourcePosition:s,targetPosition:c,data:l,selected:u}){let[d,f,p]=(0,n.getSmoothStepPath)({sourceX:t,sourceY:i,sourcePosition:s,targetX:a,targetY:o,targetPosition:c}),m=l??{},h=!!u||!!m.hovered,g=m.color||`#3b82f6`;return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.BaseEdge,{id:e,path:d,style:{stroke:g,strokeWidth:h?2.5:2,strokeDasharray:`6 3`}}),(0,r.jsx)(n.EdgeLabelRenderer,{children:(0,r.jsxs)(`div`,{className:`nodrag nopan`,style:{position:`absolute`,transform:`translate(-50%, -50%) translate(${f}px, ${p}px)`,background:g,color:`#fff`,fontSize:10,fontFamily:`ui-monospace, SFMono-Regular, Consolas, monospace`,fontWeight:700,borderRadius:3,padding:`2px 4px 2px 6px`,display:`flex`,alignItems:`center`,gap:4,pointerEvents:`all`,boxShadow:h?`0 0 0 2px rgba(0,0,0,0.4)`:`0 1px 2px rgba(0,0,0,0.15)`,userSelect:`none`},children:[(0,r.jsx)(`span`,{children:m.type}),m.onDelete&&(0,r.jsx)(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),m.onDelete?.()},onMouseDown:e=>e.stopPropagation(),title:`Remove this JOIN`,style:{background:`rgba(255,255,255,0.25)`,border:`none`,color:`#fff`,width:14,height:14,borderRadius:2,cursor:`pointer`,fontSize:11,fontWeight:700,padding:0,lineHeight:1,display:`flex`,alignItems:`center`,justifyContent:`center`},children:`×`})]})})]})}),f={table:u},p={joinEdge:d};function m(t){try{return{model:e.c(t),error:null}}catch(t){if(t instanceof e.s)return{model:null,error:t};throw t}}function h(e,t){return t?`${t}__${e}`:`__default-${e}`}var g=`join:`;function _(e){if(!e||e.startsWith(`__default-`))return;let t=/^(.+)__(?:source|target)$/.exec(e);return t?t[1]:void 0}function ee(e){return`${e.table}.${e.column}`}var v={INNER:`#3b82f6`,LEFT:`#8b5cf6`,RIGHT:`#a855f7`,FULL:`#ec4899`,CROSS:`#6b7280`};function y(c){let{source:l,model:u,algorithm:d,direction:y,aspectRatio:b,positions:x,onPositionsChange:S,showColumnCheckboxes:C,selectedColumns:w,onColumnSelectionChange:T,enableManualJoins:E,joins:D,onJoinConnect:O,onJoinDelete:k,onTableRemove:A,onColumnClick:j,onTableClick:M,deleteKeyCode:N=`Delete`,className:P,style:F,highlightReferencesOnHover:I=!0}=c,{model:L,error:R}=(0,t.useMemo)(()=>u?{model:u,error:null}:l==null?{model:null,error:null}:m(l),[l,u]),[z,B]=(0,t.useState)(null),[V,H]=(0,t.useState)(null);(0,t.useEffect)(()=>{if(!L){B(null);return}let t=!1;return e.o(L,{algorithm:d,direction:y,aspectRatio:b}).then(e=>{t||B(e)}),()=>{t=!0}},[L,d,y,b]);let U=(0,t.useMemo)(()=>{if(!z||!L)return[];let e=new Map(L.tables.map(e=>[e.name,e])),t=[];for(let n of z.nodes){let r=e.get(n.id);if(!r)continue;let i=x?.[n.id],a={table:r};t.push({id:n.id,type:`table`,position:i??{x:n.x,y:n.y},data:a,width:n.width,height:n.height,draggable:!0,deletable:!1})}return t},[z,L,x]),[W,G,K]=(0,n.useNodesState)(U);(0,t.useEffect)(()=>{G(U)},[U,G]);let q=(0,t.useCallback)((e,t,n)=>{if(!S)return;let r={...x??{}};for(let e of n)r[e.id]={x:e.position.x,y:e.position.y};S(r)},[x,S]),J=(0,t.useMemo)(()=>{if(!(!V||!L))return L.relations.find(e=>e.id===V)},[V,L]),Y=(0,t.useMemo)(()=>{if(!V||!D||!V.startsWith(g))return;let e=V.slice(5);return D.find(t=>t.id===e)},[V,D]),X=(0,t.useMemo)(()=>{let e=new Map;if(!I)return e;let t=(t,n)=>{if(!n)return;let r=e.get(t)??new Set;r.add(n),e.set(t,r)};return J&&(t(J.from,J.fromColumn),t(J.to,J.toColumn)),Y&&(t(Y.source.table,Y.source.column),t(Y.target.table,Y.target.column)),e},[J,Y,I]),Z=(0,t.useMemo)(()=>new Set((w??[]).map(ee)),[w]),Q=(0,t.useCallback)((e,t,n)=>{if(!T)return;let r=w??[];if(n){if(r.some(n=>n.table===e&&n.column===t))return;T([...r,{table:e,column:t}])}else T(r.filter(n=>!(n.table===e&&n.column===t)))},[w,T]),te=(0,t.useMemo)(()=>({enabled:C??!1,selected:Z,onToggle:Q}),[C,Z,Q]),ne=(0,t.useMemo)(()=>{if(!z||!L)return[];let e=new Set(L.tables.map(e=>e.name)),t=new Map(L.relations.map(e=>[e.id,e])),n=[];for(let r of z.edges){if(!e.has(r.source)||!e.has(r.target))continue;let i=t.get(r.id),a=r.id===V;n.push({id:r.id,source:r.source,target:r.target,sourceHandle:h(`source`,i?.fromColumn),targetHandle:h(`target`,i?.toColumn),type:`smoothstep`,animated:a,deletable:!1,style:{stroke:a?`#f59e0b`:`#9ca3af`,strokeWidth:a?2:1.5},label:i?.label,labelStyle:{fontSize:10,fill:`#6b7280`},labelBgStyle:{fill:`#fff`,fillOpacity:.85},labelBgPadding:[4,2],labelBgBorderRadius:3})}let r=[];for(let t of D??[]){if(!e.has(t.source.table)||!e.has(t.target.table))continue;let n=`${g}${t.id}`,i=n===V,a=v[t.type]??`#3b82f6`,o={type:t.type,color:a,hovered:i,onDelete:k?()=>k(t.id):void 0};r.push({id:n,source:t.source.table,target:t.target.table,sourceHandle:h(`source`,t.source.column),targetHandle:h(`target`,t.target.column),type:`joinEdge`,deletable:!0,data:o})}return[...n,...r]},[z,L,D,V,k]),re=(0,t.useCallback)(e=>{O&&(!e.source||!e.target||O({table:e.source,column:_(e.sourceHandle)},{table:e.target,column:_(e.targetHandle)}))},[O]),ie=(0,t.useCallback)(e=>{if(k)for(let t of e)t.id.startsWith(g)&&k(t.id.slice(5))},[k]),$=!!E,ae=(0,t.useMemo)(()=>({onTableRemove:A,onColumnClick:j}),[A,j]);return(0,r.jsxs)(`div`,{className:P,style:{width:`100%`,height:`100%`,position:`relative`,...F},children:[R&&(0,r.jsx)(`div`,{style:{position:`absolute`,top:8,left:8,right:8,zIndex:10,padding:`8px 12px`,background:`#fef2f2`,border:`1px solid #fecaca`,borderRadius:6,color:`#991b1b`,fontFamily:`ui-monospace, SFMono-Regular, Consolas, monospace`,fontSize:12,whiteSpace:`pre-wrap`},children:R.message}),!R&&!z&&(0,r.jsx)(`div`,{style:{position:`absolute`,inset:0,display:`flex`,alignItems:`center`,justifyContent:`center`,color:`#9ca3af`,fontSize:13},children:`Computing layout…`}),(0,r.jsx)(i.Provider,{value:X,children:(0,r.jsx)(a.Provider,{value:te,children:(0,r.jsx)(o.Provider,{value:$,children:(0,r.jsx)(s.Provider,{value:ae,children:(0,r.jsxs)(n.ReactFlow,{nodes:W,edges:ne,nodeTypes:f,edgeTypes:p,fitView:!0,onNodesChange:K,onNodeDragStop:q,onNodeClick:M?(e,t)=>M(t.id):void 0,onEdgeMouseEnter:(e,t)=>H(t.id),onEdgeMouseLeave:()=>H(null),onConnect:re,onEdgesDelete:ie,nodesDraggable:!0,nodesConnectable:$,elementsSelectable:!0,deleteKeyCode:N,minZoom:.1,maxZoom:4,children:[(0,r.jsx)(n.Background,{}),(0,r.jsx)(n.Controls,{}),(0,r.jsx)(n.MiniMap,{pannable:!0,zoomable:!0})]})})})})})]})}exports.HEADER_HEIGHT=e.t,exports.MermaidER=y,exports.MermaidERParseError=e.s,exports.NODE_WIDTH=e.n,exports.ROW_HEIGHT=e.r,exports.VERTICAL_PADDING=e.i,exports.estimateNodeHeight=e.a,exports.layoutER=e.o,exports.parseMermaidER=e.c;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/components/TableNode.tsx","../src/components/JoinEdge.tsx","../src/components/MermaidER.tsx"],"sourcesContent":["import { Fragment, createContext, memo, useContext } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport type { NodeProps } from '@xyflow/react';\nimport type { Column, Table } from '../core/model';\nimport { HEADER_HEIGHT, ROW_HEIGHT } from '../core/layout';\n\nexport interface TableNodeData extends Record<string, unknown> {\n table: Table;\n}\n\n/**\n * Map from table name -> set of highlighted column names.\n * Provided by MermaidER, consumed by TableNode for hover-driven highlighting\n * without forcing the whole node array to recompute on every hover change.\n */\nexport const HighlightContext = createContext<ReadonlyMap<string, ReadonlySet<string>>>(new Map());\n\nexport interface ColumnSelectionContextValue {\n enabled: boolean;\n /** \"table.column\" keys for fast lookup. */\n selected: ReadonlySet<string>;\n onToggle: (table: string, column: string, checked: boolean) => void;\n}\n\nexport const ColumnSelectionContext = createContext<ColumnSelectionContextValue>({\n enabled: false,\n selected: new Set(),\n onToggle: () => undefined,\n});\n\n/** When true, column handles become visible/connectable for manual JOIN drawing. */\nexport const ConnectModeContext = createContext<boolean>(false);\n\nexport interface TableActionsContextValue {\n /** When provided, a delete affordance is shown on the table header. */\n onTableRemove?: (table: string) => void;\n /** Per-column click handler. Provided via context (not node data) so its\n * identity can change without invalidating the React Flow node array. */\n onColumnClick?: (table: string, column: string) => void;\n}\n\nexport const TableActionsContext = createContext<TableActionsContextValue>({});\n\nconst KEY_STYLES: Record<'pk' | 'fk' | 'uk', { label: string; bg: string }> = {\n pk: { label: 'PK', bg: '#f59e0b' },\n fk: { label: 'FK', bg: '#3b82f6' },\n uk: { label: 'UK', bg: '#10b981' },\n};\n\nfunction ColumnRow({\n tableName,\n column,\n highlighted,\n onClick,\n selectionEnabled,\n selected,\n onSelectToggle,\n}: {\n tableName: string;\n column: Column;\n highlighted: boolean;\n onClick?: (table: string, column: string) => void;\n selectionEnabled: boolean;\n selected: boolean;\n onSelectToggle: (checked: boolean) => void;\n}) {\n const badges: Array<{ label: string; bg: string }> = [];\n if (column.keys.pk) badges.push(KEY_STYLES.pk);\n if (column.keys.fk) badges.push(KEY_STYLES.fk);\n if (column.keys.uk) badges.push(KEY_STYLES.uk);\n\n return (\n <div\n title={column.comment}\n onClick={onClick ? () => onClick(tableName, column.name) : undefined}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '0 10px',\n fontSize: 12,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n borderTop: '1px solid #eee',\n height: ROW_HEIGHT,\n boxSizing: 'border-box',\n cursor: onClick ? 'pointer' : 'default',\n background: highlighted ? '#fef3c7' : selected ? '#eff6ff' : 'transparent',\n transition: 'background 0.15s',\n }}\n >\n {selectionEnabled && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(e) => onSelectToggle(e.target.checked)}\n onClick={(e) => e.stopPropagation()}\n style={{\n width: 13,\n height: 13,\n margin: 0,\n flexShrink: 0,\n cursor: 'pointer',\n }}\n />\n )}\n <span style={{ display: 'flex', gap: 2, flexShrink: 0, minWidth: 18 }}>\n {badges.map((b) => (\n <span\n key={b.label}\n style={{\n display: 'inline-block',\n padding: '0 4px',\n borderRadius: 3,\n background: b.bg,\n color: '#fff',\n fontSize: 9,\n fontWeight: 700,\n lineHeight: '14px',\n }}\n >\n {b.label}\n </span>\n ))}\n </span>\n <span\n style={{\n flexShrink: 0,\n fontWeight: column.keys.pk ? 600 : 400,\n color: '#1f2937',\n }}\n >\n {column.name}\n </span>\n {column.type && (\n <span\n style={{\n flex: 1,\n textAlign: 'right',\n color: '#9ca3af',\n fontStyle: 'italic',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {column.type}\n </span>\n )}\n </div>\n );\n}\n\nexport const TableNode = memo(function TableNode({ data }: NodeProps) {\n const { table } = data as TableNodeData;\n const highlightMap = useContext(HighlightContext);\n const selection = useContext(ColumnSelectionContext);\n const connectMode = useContext(ConnectModeContext);\n const tableActions = useContext(TableActionsContext);\n const onColumnClick = tableActions.onColumnClick;\n const highlightedCols = highlightMap.get(table.name);\n const headerBg = table.group ? '#1e40af' : '#374151';\n\n const handleStyle = (extra: { top?: number }): React.CSSProperties => ({\n ...extra,\n width: connectMode ? 9 : 6,\n height: connectMode ? 9 : 6,\n background: connectMode ? '#3b82f6' : 'transparent',\n border: connectMode ? '1.5px solid #fff' : 'none',\n boxShadow: connectMode ? '0 0 0 1px rgba(59,130,246,0.4)' : 'none',\n opacity: connectMode ? 0.85 : 0,\n pointerEvents: connectMode ? 'auto' : 'none',\n cursor: connectMode ? 'crosshair' : 'default',\n });\n\n return (\n <div\n style={{\n background: '#fff',\n border: '1px solid #c4c4c4',\n borderRadius: 6,\n boxShadow: '0 2px 6px rgba(0,0,0,0.08)',\n overflow: 'visible',\n width: '100%',\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n position: 'relative',\n }}\n >\n <Handle\n id=\"__default-target\"\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n <Handle\n id=\"__default-source\"\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: HEADER_HEIGHT / 2 })}\n />\n\n <div\n style={{\n padding: '6px 10px',\n background: headerBg,\n color: '#fff',\n fontWeight: 600,\n fontSize: 13,\n height: HEADER_HEIGHT,\n boxSizing: 'border-box',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 8,\n borderTopLeftRadius: 6,\n borderTopRightRadius: 6,\n }}\n >\n <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {table.name}\n </span>\n <span style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0 }}>\n {table.group && (\n <span\n style={{\n fontSize: 10,\n opacity: 0.75,\n fontWeight: 400,\n padding: '1px 5px',\n border: '1px solid rgba(255,255,255,0.3)',\n borderRadius: 3,\n }}\n >\n {table.group}\n </span>\n )}\n {tableActions.onTableRemove && (\n <button\n className=\"nodrag\"\n onClick={(e) => {\n e.stopPropagation();\n tableActions.onTableRemove?.(table.name);\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this table\"\n style={{\n background: 'rgba(255,255,255,0.18)',\n border: 'none',\n color: '#fff',\n width: 18,\n height: 18,\n borderRadius: 3,\n cursor: 'pointer',\n fontSize: 13,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </span>\n </div>\n\n {table.columns.map((col, i) => {\n const handleY = HEADER_HEIGHT + i * ROW_HEIGHT + ROW_HEIGHT / 2;\n const highlighted = highlightedCols?.has(col.name) ?? false;\n const selectionKey = `${table.name}.${col.name}`;\n const selected = selection.enabled && selection.selected.has(selectionKey);\n return (\n <Fragment key={`${col.name}-${i}`}>\n <Handle\n id={`${col.name}__target`}\n type=\"target\"\n position={Position.Left}\n style={handleStyle({ top: handleY })}\n />\n <Handle\n id={`${col.name}__source`}\n type=\"source\"\n position={Position.Right}\n style={handleStyle({ top: handleY })}\n />\n <ColumnRow\n tableName={table.name}\n column={col}\n highlighted={highlighted}\n onClick={onColumnClick}\n selectionEnabled={selection.enabled}\n selected={selected}\n onSelectToggle={(checked) =>\n selection.onToggle(table.name, col.name, checked)\n }\n />\n </Fragment>\n );\n })}\n </div>\n );\n});\n","import { memo } from 'react';\nimport {\n BaseEdge,\n EdgeLabelRenderer,\n getSmoothStepPath,\n type EdgeProps,\n} from '@xyflow/react';\nimport type { JoinType } from '../core/model';\n\nexport interface JoinEdgeData extends Record<string, unknown> {\n type: JoinType;\n color: string;\n hovered?: boolean;\n onDelete?: () => void;\n}\n\nexport const JoinEdge = memo(function JoinEdge({\n id,\n sourceX,\n sourceY,\n targetX,\n targetY,\n sourcePosition,\n targetPosition,\n data,\n selected,\n}: EdgeProps) {\n const [edgePath, labelX, labelY] = getSmoothStepPath({\n sourceX,\n sourceY,\n sourcePosition,\n targetX,\n targetY,\n targetPosition,\n });\n\n const d = (data ?? {}) as JoinEdgeData;\n const emphasized = !!selected || !!d.hovered;\n const color = d.color || '#3b82f6';\n\n return (\n <>\n <BaseEdge\n id={id}\n path={edgePath}\n style={{\n stroke: color,\n strokeWidth: emphasized ? 2.5 : 2,\n strokeDasharray: '6 3',\n }}\n />\n <EdgeLabelRenderer>\n <div\n className=\"nodrag nopan\"\n style={{\n position: 'absolute',\n transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,\n background: color,\n color: '#fff',\n fontSize: 10,\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontWeight: 700,\n borderRadius: 3,\n padding: '2px 4px 2px 6px',\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n pointerEvents: 'all',\n boxShadow: emphasized\n ? '0 0 0 2px rgba(0,0,0,0.4)'\n : '0 1px 2px rgba(0,0,0,0.15)',\n userSelect: 'none',\n }}\n >\n <span>{d.type}</span>\n {d.onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n d.onDelete?.();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n title=\"Remove this JOIN\"\n style={{\n background: 'rgba(255,255,255,0.25)',\n border: 'none',\n color: '#fff',\n width: 14,\n height: 14,\n borderRadius: 2,\n cursor: 'pointer',\n fontSize: 11,\n fontWeight: 700,\n padding: 0,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n ×\n </button>\n )}\n </div>\n </EdgeLabelRenderer>\n </>\n );\n});\n","import {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type CSSProperties,\n} from 'react';\nimport {\n ReactFlow,\n Background,\n Controls,\n MiniMap,\n useNodesState,\n type Connection,\n type Edge,\n type EdgeTypes,\n type Node,\n type NodeTypes,\n} from '@xyflow/react';\n// React Flow's CSS is intentionally NOT imported here. Consumers must add it\n// once at their app entry point: `import '@xyflow/react/dist/style.css';`.\n// Importing it from this file would cause double-injection in apps that\n// already use React Flow, and inflate this library's bundled assets.\nimport { parseMermaidER, MermaidERParseError } from '../core/parser';\nimport {\n layoutER,\n type LayoutAlgorithm,\n type LayoutDirection,\n type LayoutResult,\n} from '../core/layout';\nimport type {\n ColumnRef,\n ERModel,\n Join,\n PartialColumnRef,\n Relation,\n} from '../core/model';\nimport {\n ColumnSelectionContext,\n ConnectModeContext,\n HighlightContext,\n TableActionsContext,\n TableNode,\n type ColumnSelectionContextValue,\n type TableActionsContextValue,\n type TableNodeData,\n} from './TableNode';\nimport { JoinEdge, type JoinEdgeData } from './JoinEdge';\n\nconst nodeTypes: NodeTypes = {\n table: TableNode,\n};\n\nconst edgeTypes: EdgeTypes = {\n joinEdge: JoinEdge,\n};\n\nexport interface NodePosition {\n x: number;\n y: number;\n}\n\nexport type NodePositions = Record<string, NodePosition>;\n\nexport interface MermaidERProps {\n /** Mermaid ER source. Mutually exclusive with `model`. */\n source?: string;\n /** Pre-built ER model. Takes precedence over `source`. */\n model?: ERModel;\n layout?: 'elk';\n algorithm?: LayoutAlgorithm;\n direction?: LayoutDirection;\n aspectRatio?: number;\n positions?: NodePositions;\n onPositionsChange?: (positions: NodePositions) => void;\n showColumnCheckboxes?: boolean;\n selectedColumns?: ColumnRef[];\n onColumnSelectionChange?: (selectedColumns: ColumnRef[]) => void;\n /** Enable column-to-column / card-to-card drag for manual JOINs. */\n enableManualJoins?: boolean;\n /** Existing manual joins to render alongside FK relations. */\n joins?: Join[];\n /**\n * Fired when the user finishes a connect drag. The consumer typically opens\n * a dialog to ask for join type, then appends a complete `Join` to its state.\n * `column` may be undefined when the drag landed on a default (table-center) handle.\n */\n onJoinConnect?: (source: PartialColumnRef, target: PartialColumnRef) => void;\n /** Fired when the user removes a manual join via Delete or the trash icon. */\n onJoinDelete?: (joinId: string) => void;\n /** When provided, a small × appears on each table header to remove it from the canvas. */\n onTableRemove?: (table: string) => void;\n highlightReferencesOnHover?: boolean;\n onColumnClick?: (table: string, column: string) => void;\n onTableClick?: (table: string) => void;\n /** Override the default delete-key code(s). Default is 'Delete' (Backspace ignored to prevent accidents). */\n deleteKeyCode?: string | string[] | null;\n className?: string;\n style?: CSSProperties;\n}\n\ninterface ParseState {\n model: ERModel | null;\n error: MermaidERParseError | null;\n}\n\nfunction safeParse(source: string): ParseState {\n try {\n return { model: parseMermaidER(source), error: null };\n } catch (e) {\n if (e instanceof MermaidERParseError) {\n return { model: null, error: e };\n }\n throw e;\n }\n}\n\nfunction handleIdFor(side: 'source' | 'target', column: string | undefined): string {\n return column ? `${column}__${side}` : `__default-${side}`;\n}\n\nconst JOIN_EDGE_PREFIX = 'join:';\n\nfunction parseHandleColumn(handleId: string | null | undefined): string | undefined {\n if (!handleId) return undefined;\n if (handleId.startsWith('__default-')) return undefined;\n const m = /^(.+)__(?:source|target)$/.exec(handleId);\n return m ? m[1] : undefined;\n}\n\nfunction refKey(ref: ColumnRef): string {\n return `${ref.table}.${ref.column}`;\n}\n\nconst JOIN_TYPE_COLOR: Record<Join['type'], string> = {\n INNER: '#3b82f6',\n LEFT: '#8b5cf6',\n RIGHT: '#a855f7',\n FULL: '#ec4899',\n CROSS: '#6b7280',\n};\n\nexport function MermaidER(props: MermaidERProps) {\n const {\n source,\n model: modelProp,\n algorithm,\n direction,\n aspectRatio,\n positions,\n onPositionsChange,\n showColumnCheckboxes,\n selectedColumns,\n onColumnSelectionChange,\n enableManualJoins,\n joins,\n onJoinConnect,\n onJoinDelete,\n onTableRemove,\n onColumnClick,\n onTableClick,\n deleteKeyCode = 'Delete',\n className,\n style,\n highlightReferencesOnHover = true,\n } = props;\n\n const { model, error } = useMemo<ParseState>(() => {\n if (modelProp) return { model: modelProp, error: null };\n if (source != null) return safeParse(source);\n return { model: null, error: null };\n }, [source, modelProp]);\n\n const [layout, setLayout] = useState<LayoutResult | null>(null);\n const [hoveredEdgeId, setHoveredEdgeId] = useState<string | null>(null);\n\n useEffect(() => {\n if (!model) {\n setLayout(null);\n return;\n }\n let cancelled = false;\n layoutER(model, { algorithm, direction, aspectRatio }).then((result) => {\n if (!cancelled) setLayout(result);\n });\n return () => {\n cancelled = true;\n };\n }, [model, algorithm, direction, aspectRatio]);\n\n const baseNodes = useMemo<Node[]>(() => {\n if (!layout || !model) return [];\n const tableMap = new Map(model.tables.map((t) => [t.name, t]));\n const result: Node[] = [];\n for (const n of layout.nodes) {\n const table = tableMap.get(n.id);\n // Skip stale nodes: a model update can arrive before the new layout\n // finishes; in that gap, layout may still reference a removed table.\n if (!table) continue;\n const override = positions?.[n.id];\n const data: TableNodeData = { table };\n result.push({\n id: n.id,\n type: 'table',\n position: override ?? { x: n.x, y: n.y },\n data,\n width: n.width,\n height: n.height,\n draggable: true,\n deletable: false,\n });\n }\n return result;\n // `onColumnClick` is intentionally NOT a dep — it flows via TableActionsContext\n // so a non-stable callback identity from the parent doesn't reset React Flow\n // node state (which would clobber an in-flight drag).\n }, [layout, model, positions]);\n\n const [nodes, setNodes, onNodesChange] = useNodesState<Node>(baseNodes);\n\n useEffect(() => {\n setNodes(baseNodes);\n }, [baseNodes, setNodes]);\n\n const handleNodeDragStop = useCallback(\n (_: unknown, _primary: Node, dragged: Node[]) => {\n if (!onPositionsChange) return;\n const next: NodePositions = { ...(positions ?? {}) };\n for (const n of dragged) {\n next[n.id] = { x: n.position.x, y: n.position.y };\n }\n onPositionsChange(next);\n },\n [positions, onPositionsChange],\n );\n\n const hoveredRelation = useMemo<Relation | undefined>(() => {\n if (!hoveredEdgeId || !model) return undefined;\n return model.relations.find((r) => r.id === hoveredEdgeId);\n }, [hoveredEdgeId, model]);\n\n const hoveredJoin = useMemo<Join | undefined>(() => {\n if (!hoveredEdgeId || !joins) return undefined;\n if (!hoveredEdgeId.startsWith(JOIN_EDGE_PREFIX)) return undefined;\n const id = hoveredEdgeId.slice(JOIN_EDGE_PREFIX.length);\n return joins.find((j) => j.id === id);\n }, [hoveredEdgeId, joins]);\n\n const highlightMap = useMemo<ReadonlyMap<string, ReadonlySet<string>>>(() => {\n const map = new Map<string, Set<string>>();\n if (!highlightReferencesOnHover) return map;\n\n const add = (table: string, column: string | undefined) => {\n if (!column) return;\n const set = map.get(table) ?? new Set();\n set.add(column);\n map.set(table, set);\n };\n\n if (hoveredRelation) {\n add(hoveredRelation.from, hoveredRelation.fromColumn);\n add(hoveredRelation.to, hoveredRelation.toColumn);\n }\n if (hoveredJoin) {\n add(hoveredJoin.source.table, hoveredJoin.source.column);\n add(hoveredJoin.target.table, hoveredJoin.target.column);\n }\n return map;\n }, [hoveredRelation, hoveredJoin, highlightReferencesOnHover]);\n\n const selectionSet = useMemo<ReadonlySet<string>>(() => {\n return new Set((selectedColumns ?? []).map(refKey));\n }, [selectedColumns]);\n\n const handleColumnSelectToggle = useCallback(\n (table: string, column: string, checked: boolean) => {\n if (!onColumnSelectionChange) return;\n const list = selectedColumns ?? [];\n if (checked) {\n if (list.some((r) => r.table === table && r.column === column)) return;\n onColumnSelectionChange([...list, { table, column }]);\n } else {\n onColumnSelectionChange(\n list.filter((r) => !(r.table === table && r.column === column)),\n );\n }\n },\n [selectedColumns, onColumnSelectionChange],\n );\n\n const selectionContext = useMemo<ColumnSelectionContextValue>(\n () => ({\n enabled: showColumnCheckboxes ?? false,\n selected: selectionSet,\n onToggle: handleColumnSelectToggle,\n }),\n [showColumnCheckboxes, selectionSet, handleColumnSelectToggle],\n );\n\n const edges = useMemo<Edge[]>(() => {\n if (!layout || !model) return [];\n const tableSet = new Set(model.tables.map((t) => t.name));\n const relMap = new Map(model.relations.map((r) => [r.id, r]));\n\n const fkEdges: Edge[] = [];\n for (const e of layout.edges) {\n // Skip stale edges referencing tables removed since the layout was computed.\n if (!tableSet.has(e.source) || !tableSet.has(e.target)) continue;\n const rel = relMap.get(e.id);\n const isHovered = e.id === hoveredEdgeId;\n fkEdges.push({\n id: e.id,\n source: e.source,\n target: e.target,\n sourceHandle: handleIdFor('source', rel?.fromColumn),\n targetHandle: handleIdFor('target', rel?.toColumn),\n type: 'smoothstep',\n animated: isHovered,\n deletable: false,\n style: {\n stroke: isHovered ? '#f59e0b' : '#9ca3af',\n strokeWidth: isHovered ? 2 : 1.5,\n },\n label: rel?.label,\n labelStyle: { fontSize: 10, fill: '#6b7280' },\n labelBgStyle: { fill: '#fff', fillOpacity: 0.85 },\n labelBgPadding: [4, 2] as [number, number],\n labelBgBorderRadius: 3,\n });\n }\n\n const joinEdges: Edge[] = [];\n for (const j of joins ?? []) {\n if (!tableSet.has(j.source.table) || !tableSet.has(j.target.table)) continue;\n const edgeId = `${JOIN_EDGE_PREFIX}${j.id}`;\n const isHovered = edgeId === hoveredEdgeId;\n const color = JOIN_TYPE_COLOR[j.type] ?? '#3b82f6';\n const data: JoinEdgeData = {\n type: j.type,\n color,\n hovered: isHovered,\n onDelete: onJoinDelete ? () => onJoinDelete(j.id) : undefined,\n };\n joinEdges.push({\n id: edgeId,\n source: j.source.table,\n target: j.target.table,\n sourceHandle: handleIdFor('source', j.source.column),\n targetHandle: handleIdFor('target', j.target.column),\n type: 'joinEdge',\n deletable: true,\n data: data as unknown as Record<string, unknown>,\n });\n }\n\n return [...fkEdges, ...joinEdges];\n }, [layout, model, joins, hoveredEdgeId, onJoinDelete]);\n\n const handleConnect = useCallback(\n (conn: Connection) => {\n if (!onJoinConnect) return;\n if (!conn.source || !conn.target) return;\n onJoinConnect(\n { table: conn.source, column: parseHandleColumn(conn.sourceHandle) },\n { table: conn.target, column: parseHandleColumn(conn.targetHandle) },\n );\n },\n [onJoinConnect],\n );\n\n const handleEdgesDelete = useCallback(\n (deleted: Edge[]) => {\n if (!onJoinDelete) return;\n for (const e of deleted) {\n if (e.id.startsWith(JOIN_EDGE_PREFIX)) {\n onJoinDelete(e.id.slice(JOIN_EDGE_PREFIX.length));\n }\n }\n },\n [onJoinDelete],\n );\n\n const connectModeOn = !!enableManualJoins;\n const tableActions = useMemo<TableActionsContextValue>(\n () => ({ onTableRemove, onColumnClick }),\n [onTableRemove, onColumnClick],\n );\n\n return (\n <div\n className={className}\n style={{ width: '100%', height: '100%', position: 'relative', ...style }}\n >\n {error && (\n <div\n style={{\n position: 'absolute',\n top: 8,\n left: 8,\n right: 8,\n zIndex: 10,\n padding: '8px 12px',\n background: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: 6,\n color: '#991b1b',\n fontFamily: 'ui-monospace, SFMono-Regular, Consolas, monospace',\n fontSize: 12,\n whiteSpace: 'pre-wrap',\n }}\n >\n {error.message}\n </div>\n )}\n {!error && !layout && (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n color: '#9ca3af',\n fontSize: 13,\n }}\n >\n Computing layout…\n </div>\n )}\n <HighlightContext.Provider value={highlightMap}>\n <ColumnSelectionContext.Provider value={selectionContext}>\n <ConnectModeContext.Provider value={connectModeOn}>\n <TableActionsContext.Provider value={tableActions}>\n <ReactFlow\n nodes={nodes}\n edges={edges}\n nodeTypes={nodeTypes}\n edgeTypes={edgeTypes}\n fitView\n onNodesChange={onNodesChange}\n onNodeDragStop={handleNodeDragStop}\n onNodeClick={\n onTableClick ? (_, node) => onTableClick(node.id) : undefined\n }\n onEdgeMouseEnter={(_, edge) => setHoveredEdgeId(edge.id)}\n onEdgeMouseLeave={() => setHoveredEdgeId(null)}\n onConnect={handleConnect}\n onEdgesDelete={handleEdgesDelete}\n nodesDraggable\n nodesConnectable={connectModeOn}\n elementsSelectable\n deleteKeyCode={deleteKeyCode}\n minZoom={0.1}\n maxZoom={4}\n >\n <Background />\n <Controls />\n <MiniMap pannable zoomable />\n </ReactFlow>\n </TableActionsContext.Provider>\n </ConnectModeContext.Provider>\n </ColumnSelectionContext.Provider>\n </HighlightContext.Provider>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { MermaidER } from './components/MermaidER';
2
+ export type { MermaidERProps, NodePosition, NodePositions, } from './components/MermaidER';
3
+ export type { TableNodeData } from './components/TableNode';
4
+ export type { JoinEdgeData } from './components/JoinEdge';
5
+ export * from './core';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EACV,cAAc,EACd,YAAY,EACZ,aAAa,GACd,MAAM,wBAAwB,CAAC;AAKhC,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,cAAc,QAAQ,CAAC"}