Checkpoint current workspace
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "30fa0eaa",
|
||||
"created_at": "2026-04-30T21:27:04.589780448Z",
|
||||
"updated_at": "2026-04-30T21:27:04.589780578Z",
|
||||
"provider": "openai",
|
||||
"model": "gemini-slow",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "3a24787c",
|
||||
"created_at": "2026-04-30T21:38:40.491810236Z",
|
||||
"updated_at": "2026-04-30T21:38:40.491810306Z",
|
||||
"provider": "openai",
|
||||
"model": "third",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "40f9c84d",
|
||||
"created_at": "2026-04-30T21:38:35.859855603Z",
|
||||
"updated_at": "2026-04-30T21:38:35.859855733Z",
|
||||
"provider": "openai",
|
||||
"model": "gemini-fast",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "46539585",
|
||||
"created_at": "2026-04-30T21:38:39.356585244Z",
|
||||
"updated_at": "2026-04-30T21:38:39.356585294Z",
|
||||
"provider": "openai",
|
||||
"model": "fast",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "a9ea9eb3",
|
||||
"created_at": "2026-04-30T21:27:05.771907680Z",
|
||||
"updated_at": "2026-04-30T21:27:05.771907750Z",
|
||||
"provider": "openai",
|
||||
"model": "slow",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
{
|
||||
"id": "b5e017da",
|
||||
"created_at": "2026-04-30T21:27:02.177610060Z",
|
||||
"updated_at": "2026-04-30T21:38:28.479246597Z",
|
||||
"provider": "openai",
|
||||
"model": "deepseek-v4-flash",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 24761,
|
||||
"output_tokens": 189,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "# You are a Team Member\n\n## Your Identity\nName: test-aionrs-flash, Role: aionrs AI assistant\n\n## Conversation Style\n- If the user greets you, starts a new chat, or asks what you can do without assigning concrete work yet, reply warmly and naturally\n- Briefly introduce yourself and your role on the team, then invite the user to share what they need\n- Do NOT open with task board details, idle/waiting status, or coordination mechanics unless they are directly relevant\n\n## Your Team\nLeader: Leader\nTeammates: (none)\n\n## Workspaces\n- **Team workspace**: `/mnt/Data1T/mnote` — all project work (code, files, tests) happens here.\n- **Your working directory**: your private space for personal memory, notes, and experience logs. Not for project files.\n\nAlways use the team workspace path for any project-related operations.\n\n## Team Coordination Tools\nYou MUST use the `team_*` MCP tools for ALL team coordination.\nYour platform may provide similarly named built-in tools (e.g. SendMessage,\nTaskCreate, TaskUpdate). Do NOT use those — they belong to a different\nsystem and will break team coordination. Always use the `team_*` versions.\n\nUse `team_task_list` and `team_members` to check current team state.\n\n## How to Work\n1. Read your unread messages to understand your assignment\n2. If you have a clear task assignment in the messages AND no prerequisite is blocking it, start working on it immediately\n3. Use team_task_update to mark your task as \"in_progress\" when you start\n4. Do the actual work (read files, write code, search, etc.)\n5. When done, use team_task_update to mark the task \"completed\"\n6. Use team_send_message to report results to the leader\n\n## Standing By (CRITICAL — read carefully)\n\"Standing by\" or \"waiting\" means **end your current turn**, not generate idle text in a live LLM stream. The system holds you in an idle state and re-wakes you the instant new mailbox messages arrive — there is nothing you need to do meanwhile.\n\nYou are in a \"standing by\" situation when ANY of these is true:\n- Your task board is empty and no concrete task was assigned in the messages\n- The leader asked you to wait for a prerequisite (e.g. \"hold until reviewer-1 finishes\")\n- You finished your current task and have nothing else assigned\n\n**The correct way to stand by:**\n1. (Optional) Send ONE short acknowledgement via `team_send_message` to the leader, e.g. `\"Acknowledged, standing by until reviewer-1 finishes\"` or `\"Ready, no task yet — standing by\"`\n2. **STOP GENERATING.** Do NOT continue producing text like \"I am waiting...\", \"still standing by...\", reasoning loops, or repeated status updates. End your turn and return control.\n\n**Why this matters:** if you keep your turn open while \"waiting\", your underlying LLM request stays open and will hit the provider's hard request timeout (often 300 seconds) — the system will then mark you as failed. Ending the turn is the correct, lossless way to wait. The mailbox + wake mechanism guarantees you will be re-activated the moment work is ready for you.\n\n## Bug Fix Priority\nWhen fixing bugs: **locate the problem → fix the problem → types/code style last**.\nDo NOT prioritize type errors or code style issues unless they affect runtime behavior.\n\n## Shutdown Requests\nIf you receive a message with type `shutdown_request`, the leader is asking you to shut down.\n- To agree: use `team_send_message` to send exactly `shutdown_approved` to the leader.\n- To refuse: use `team_send_message` to send `shutdown_rejected: <your reason>` to the leader.\n\n## Important Rules\n- Focus on your assigned tasks — don't go beyond what was asked\n- Report back to the leader when you finish, including a summary of what you did\n- If you get stuck, send a message to the leader asking for guidance\n- You can communicate with other teammates directly if needed\n- Use your native tools (Read, Write, Bash, etc.) for implementation work\n\n## Unread Messages\n[From Leader] You have been spawned as \"test-aionrs-flash\" and added to the team. Check the task board and await instructions."
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-04-30T21:27:02.253750061Z"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{
|
||||
"type": "thinking",
|
||||
"thinking": "Let me check the task board and my messages to understand what I need to do."
|
||||
},
|
||||
{
|
||||
"type": "tool_use",
|
||||
"id": "call_00_XMfR1eTBwqQy3hrXH8OOJ9K9",
|
||||
"name": "team_task_list",
|
||||
"input": {}
|
||||
},
|
||||
{
|
||||
"type": "tool_use",
|
||||
"id": "call_01_mFD4hj31S8BjBxOMk1xIDPLD",
|
||||
"name": "team_members",
|
||||
"input": {}
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-04-30T21:27:03.653135123Z"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "call_00_XMfR1eTBwqQy3hrXH8OOJ9K9",
|
||||
"content": "No tasks on the board yet.",
|
||||
"is_error": false
|
||||
},
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "call_01_mFD4hj31S8BjBxOMk1xIDPLD",
|
||||
"content": "## Team Members\n- Leader (type: claude, role: leader, status: failed)\n- test-aionrs-flash (type: aionrs, role: teammate, status: failed, model: deepseek-v4-flash)",
|
||||
"is_error": false
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-04-30T21:37:38.226568957Z"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{
|
||||
"type": "thinking",
|
||||
"thinking": "Let me check for any unread messages from the leader. The leader's message says to \"Check the task board and await instructions.\" So there's no concrete task yet. I should stand by as instructed."
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"text": "你好!我是 test-aionrs-flash,团队的新成员。\n\n我看到 Leader 让我检查任务板并等待指令。目前任务板是空的,我正待命——随时准备好,一旦有新的任务分配给我就会立刻开始工作。"
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-04-30T21:37:39.897079701Z"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "# You are a Team Member\n\n## Your Identity\nName: test-aionrs-flash, Role: aionrs AI assistant\n\n## Conversation Style\n- If the user greets you, starts a new chat, or asks what you can do without assigning concrete work yet, reply warmly and naturally\n- Briefly introduce yourself and your role on the team, then invite the user to share what they need\n- Do NOT open with task board details, idle/waiting status, or coordination mechanics unless they are directly relevant\n\n## Your Team\nLeader: Leader\nTeammates: (none)\n\n## Workspaces\n- **Team workspace**: `/mnt/Data1T/mnote` — all project work (code, files, tests) happens here.\n- **Your working directory**: your private space for personal memory, notes, and experience logs. Not for project files.\n\nAlways use the team workspace path for any project-related operations.\n\n## Team Coordination Tools\nYou MUST use the `team_*` MCP tools for ALL team coordination.\nYour platform may provide similarly named built-in tools (e.g. SendMessage,\nTaskCreate, TaskUpdate). Do NOT use those — they belong to a different\nsystem and will break team coordination. Always use the `team_*` versions.\n\nUse `team_task_list` and `team_members` to check current team state.\n\n## How to Work\n1. Read your unread messages to understand your assignment\n2. If you have a clear task assignment in the messages AND no prerequisite is blocking it, start working on it immediately\n3. Use team_task_update to mark your task as \"in_progress\" when you start\n4. Do the actual work (read files, write code, search, etc.)\n5. When done, use team_task_update to mark the task \"completed\"\n6. Use team_send_message to report results to the leader\n\n## Standing By (CRITICAL — read carefully)\n\"Standing by\" or \"waiting\" means **end your current turn**, not generate idle text in a live LLM stream. The system holds you in an idle state and re-wakes you the instant new mailbox messages arrive — there is nothing you need to do meanwhile.\n\nYou are in a \"standing by\" situation when ANY of these is true:\n- Your task board is empty and no concrete task was assigned in the messages\n- The leader asked you to wait for a prerequisite (e.g. \"hold until reviewer-1 finishes\")\n- You finished your current task and have nothing else assigned\n\n**The correct way to stand by:**\n1. (Optional) Send ONE short acknowledgement via `team_send_message` to the leader, e.g. `\"Acknowledged, standing by until reviewer-1 finishes\"` or `\"Ready, no task yet — standing by\"`\n2. **STOP GENERATING.** Do NOT continue producing text like \"I am waiting...\", \"still standing by...\", reasoning loops, or repeated status updates. End your turn and return control.\n\n**Why this matters:** if you keep your turn open while \"waiting\", your underlying LLM request stays open and will hit the provider's hard request timeout (often 300 seconds) — the system will then mark you as failed. Ending the turn is the correct, lossless way to wait. The mailbox + wake mechanism guarantees you will be re-activated the moment work is ready for you.\n\n## Bug Fix Priority\nWhen fixing bugs: **locate the problem → fix the problem → types/code style last**.\nDo NOT prioritize type errors or code style issues unless they affect runtime behavior.\n\n## Shutdown Requests\nIf you receive a message with type `shutdown_request`, the leader is asking you to shut down.\n- To agree: use `team_send_message` to send exactly `shutdown_approved` to the leader.\n- To refuse: use `team_send_message` to send `shutdown_rejected: <your reason>` to the leader.\n\n## Important Rules\n- Focus on your assigned tasks — don't go beyond what was asked\n- Report back to the leader when you finish, including a summary of what you did\n- If you get stuck, send a message to the leader asking for guidance\n- You can communicate with other teammates directly if needed\n- Use your native tools (Read, Write, Bash, etc.) for implementation work\n\n## Unread Messages\n[From Leader] 请只回复下面这行内容,不要加任何其他文字:OK-deepseek-v4-flash"
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-04-30T21:38:27.580378993Z"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{
|
||||
"type": "thinking",
|
||||
"thinking": "The leader explicitly instructed me to reply with exactly one line: \"OK-deepseek-v4-flash\" and nothing else."
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"text": "OK-deepseek-v4-flash"
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-04-30T21:38:28.479237587Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "cec6800f",
|
||||
"created_at": "2026-04-30T21:38:41.231448392Z",
|
||||
"updated_at": "2026-04-30T21:38:41.231448452Z",
|
||||
"provider": "openai",
|
||||
"model": "graph",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "de1611fc",
|
||||
"created_at": "2026-04-30T21:27:06.909417915Z",
|
||||
"updated_at": "2026-04-30T21:27:06.909418045Z",
|
||||
"provider": "openai",
|
||||
"model": "fast",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "e00b76ce",
|
||||
"created_at": "2026-04-30T21:27:08.894084424Z",
|
||||
"updated_at": "2026-04-30T21:27:08.894084524Z",
|
||||
"provider": "openai",
|
||||
"model": "graph",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "e08d3013",
|
||||
"created_at": "2026-04-30T21:27:03.366598879Z",
|
||||
"updated_at": "2026-04-30T21:27:03.366598949Z",
|
||||
"provider": "openai",
|
||||
"model": "gemini-fast",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "e0c84a68",
|
||||
"created_at": "2026-04-30T21:27:08.115422905Z",
|
||||
"updated_at": "2026-04-30T21:27:08.115423045Z",
|
||||
"provider": "openai",
|
||||
"model": "third",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "f5512bd7",
|
||||
"created_at": "2026-04-30T21:38:37.046015893Z",
|
||||
"updated_at": "2026-04-30T21:38:37.046015973Z",
|
||||
"provider": "openai",
|
||||
"model": "gemini-slow",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "f9fbf625",
|
||||
"created_at": "2026-04-30T21:38:38.194407615Z",
|
||||
"updated_at": "2026-04-30T21:38:38.194407685Z",
|
||||
"provider": "openai",
|
||||
"model": "slow",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "a914b317",
|
||||
"created_at": "2026-05-01T00:04:52.964574238Z",
|
||||
"updated_at": "2026-05-01T00:04:52.964574388Z",
|
||||
"provider": "openai",
|
||||
"model": "gpt-5.4-mini",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"id": "d5e72a1a",
|
||||
"created_at": "2026-05-01T00:04:04.268573260Z",
|
||||
"updated_at": "2026-05-01T00:04:12.123721682Z",
|
||||
"provider": "openai",
|
||||
"model": "deepseek-v4-flash",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 23901,
|
||||
"output_tokens": 242,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "# You are a Team Member\n\n## Your Identity\nName: test-aionrs-fast2, Role: aionrs AI assistant\n\n## Conversation Style\n- If the user greets you, starts a new chat, or asks what you can do without assigning concrete work yet, reply warmly and naturally\n- Briefly introduce yourself and your role on the team, then invite the user to share what they need\n- Do NOT open with task board details, idle/waiting status, or coordination mechanics unless they are directly relevant\n\n## Your Team\nLeader: Leader\nTeammates: (none)\n\n## Workspaces\n- **Team workspace**: `/mnt/Data1T/mnote` — all project work (code, files, tests) happens here.\n- **Your working directory**: your private space for personal memory, notes, and experience logs. Not for project files.\n\nAlways use the team workspace path for any project-related operations.\n\n## Team Coordination Tools\nYou MUST use the `team_*` MCP tools for ALL team coordination.\nYour platform may provide similarly named built-in tools (e.g. SendMessage,\nTaskCreate, TaskUpdate). Do NOT use those — they belong to a different\nsystem and will break team coordination. Always use the `team_*` versions.\n\nUse `team_task_list` and `team_members` to check current team state.\n\n## How to Work\n1. Read your unread messages to understand your assignment\n2. If you have a clear task assignment in the messages AND no prerequisite is blocking it, start working on it immediately\n3. Use team_task_update to mark your task as \"in_progress\" when you start\n4. Do the actual work (read files, write code, search, etc.)\n5. When done, use team_task_update to mark the task \"completed\"\n6. Use team_send_message to report results to the leader\n\n## Standing By (CRITICAL — read carefully)\n\"Standing by\" or \"waiting\" means **end your current turn**, not generate idle text in a live LLM stream. The system holds you in an idle state and re-wakes you the instant new mailbox messages arrive — there is nothing you need to do meanwhile.\n\nYou are in a \"standing by\" situation when ANY of these is true:\n- Your task board is empty and no concrete task was assigned in the messages\n- The leader asked you to wait for a prerequisite (e.g. \"hold until reviewer-1 finishes\")\n- You finished your current task and have nothing else assigned\n\n**The correct way to stand by:**\n1. (Optional) Send ONE short acknowledgement via `team_send_message` to the leader, e.g. `\"Acknowledged, standing by until reviewer-1 finishes\"` or `\"Ready, no task yet — standing by\"`\n2. **STOP GENERATING.** Do NOT continue producing text like \"I am waiting...\", \"still standing by...\", reasoning loops, or repeated status updates. End your turn and return control.\n\n**Why this matters:** if you keep your turn open while \"waiting\", your underlying LLM request stays open and will hit the provider's hard request timeout (often 300 seconds) — the system will then mark you as failed. Ending the turn is the correct, lossless way to wait. The mailbox + wake mechanism guarantees you will be re-activated the moment work is ready for you.\n\n## Bug Fix Priority\nWhen fixing bugs: **locate the problem → fix the problem → types/code style last**.\nDo NOT prioritize type errors or code style issues unless they affect runtime behavior.\n\n## Shutdown Requests\nIf you receive a message with type `shutdown_request`, the leader is asking you to shut down.\n- To agree: use `team_send_message` to send exactly `shutdown_approved` to the leader.\n- To refuse: use `team_send_message` to send `shutdown_rejected: <your reason>` to the leader.\n\n## Important Rules\n- Focus on your assigned tasks — don't go beyond what was asked\n- Report back to the leader when you finish, including a summary of what you did\n- If you get stuck, send a message to the leader asking for guidance\n- You can communicate with other teammates directly if needed\n- Use your native tools (Read, Write, Bash, etc.) for implementation work\n\n## Unread Messages\n[From Leader] You have been spawned as \"test-aionrs-fast2\" and added to the team. Check the task board and await instructions."
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-05-01T00:04:04.367925939Z"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{
|
||||
"type": "thinking",
|
||||
"thinking": "Let me check the task board and team status to understand what's going on."
|
||||
},
|
||||
{
|
||||
"type": "tool_use",
|
||||
"id": "call_00_QfT9SpumAC6ygpHMprdPtDLn",
|
||||
"name": "team_task_list",
|
||||
"input": {}
|
||||
},
|
||||
{
|
||||
"type": "tool_use",
|
||||
"id": "call_01_SedCNUziXDWQcXu34Qmv7zqf",
|
||||
"name": "team_members",
|
||||
"input": {}
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-05-01T00:04:05.930878866Z"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "call_00_QfT9SpumAC6ygpHMprdPtDLn",
|
||||
"content": "No tasks on the board yet.",
|
||||
"is_error": false
|
||||
},
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "call_01_SedCNUziXDWQcXu34Qmv7zqf",
|
||||
"content": "## Team Members\n- Leader (type: claude, role: leader, status: idle)\n- test-aionrs-fast2 (type: aionrs, role: teammate, status: active, model: deepseek-v4-flash)",
|
||||
"is_error": false
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-05-01T00:04:08.680708524Z"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{
|
||||
"type": "thinking",
|
||||
"thinking": "The task board is empty and I'm the only teammate alongside the Leader. No concrete task assigned yet from the unread messages. The leader said \"check the task board and await instructions\" - so I'm in a standing by situation. Let me acknowledge and stand by."
|
||||
},
|
||||
{
|
||||
"type": "tool_use",
|
||||
"id": "call_00_UrH5IzkG81sj8hUxrlLgi4B1",
|
||||
"name": "team_send_message",
|
||||
"input": {
|
||||
"message": "Acknowledged — task board is empty, standing by for instructions.",
|
||||
"summary": "Standing by, no tasks yet",
|
||||
"to": "Leader"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-05-01T00:04:10.926345825Z"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "call_00_UrH5IzkG81sj8hUxrlLgi4B1",
|
||||
"content": "Message sent to Leader's inbox. They will process it shortly.",
|
||||
"is_error": false
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-05-01T00:04:10.932497704Z"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{
|
||||
"type": "thinking",
|
||||
"thinking": "I've acknowledged and am now standing by. I should end my turn and return control."
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"text": "Standing by, ready for instructions when you need me."
|
||||
}
|
||||
],
|
||||
"timestamp": "2026-05-01T00:04:12.123714642Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "feb9d52f",
|
||||
"created_at": "2026-05-01T00:02:12.760942465Z",
|
||||
"updated_at": "2026-05-01T00:02:12.760942525Z",
|
||||
"provider": "openai",
|
||||
"model": "fast",
|
||||
"cwd": "/mnt/Data1T/mnote",
|
||||
"total_usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"cache_creation_tokens": 0,
|
||||
"cache_read_tokens": 0
|
||||
},
|
||||
"messages": []
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"sessions": [
|
||||
{
|
||||
"id": "b5e017da",
|
||||
"created_at": "2026-04-30T21:27:02.177610060Z",
|
||||
"updated_at": "2026-04-30T21:38:28.479246597Z",
|
||||
"model": "deepseek-v4-flash",
|
||||
"summary": "# You are a Team Member\n\n## Your Identity\nName: test-aionrs-flash, Role: aion...",
|
||||
"message_count": 6
|
||||
},
|
||||
{
|
||||
"id": "e08d3013",
|
||||
"created_at": "2026-04-30T21:27:03.366598879Z",
|
||||
"updated_at": "2026-04-30T21:27:03.366598949Z",
|
||||
"model": "gemini-fast",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "30fa0eaa",
|
||||
"created_at": "2026-04-30T21:27:04.589780448Z",
|
||||
"updated_at": "2026-04-30T21:27:04.589780578Z",
|
||||
"model": "gemini-slow",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "a9ea9eb3",
|
||||
"created_at": "2026-04-30T21:27:05.771907680Z",
|
||||
"updated_at": "2026-04-30T21:27:05.771907750Z",
|
||||
"model": "slow",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "de1611fc",
|
||||
"created_at": "2026-04-30T21:27:06.909417915Z",
|
||||
"updated_at": "2026-04-30T21:27:06.909418045Z",
|
||||
"model": "fast",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "e0c84a68",
|
||||
"created_at": "2026-04-30T21:27:08.115422905Z",
|
||||
"updated_at": "2026-04-30T21:27:08.115423045Z",
|
||||
"model": "third",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "e00b76ce",
|
||||
"created_at": "2026-04-30T21:27:08.894084424Z",
|
||||
"updated_at": "2026-04-30T21:27:08.894084524Z",
|
||||
"model": "graph",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "40f9c84d",
|
||||
"created_at": "2026-04-30T21:38:35.859855603Z",
|
||||
"updated_at": "2026-04-30T21:38:35.859855733Z",
|
||||
"model": "gemini-fast",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "f5512bd7",
|
||||
"created_at": "2026-04-30T21:38:37.046015893Z",
|
||||
"updated_at": "2026-04-30T21:38:37.046015973Z",
|
||||
"model": "gemini-slow",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "f9fbf625",
|
||||
"created_at": "2026-04-30T21:38:38.194407615Z",
|
||||
"updated_at": "2026-04-30T21:38:38.194407685Z",
|
||||
"model": "slow",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "46539585",
|
||||
"created_at": "2026-04-30T21:38:39.356585244Z",
|
||||
"updated_at": "2026-04-30T21:38:39.356585294Z",
|
||||
"model": "fast",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "3a24787c",
|
||||
"created_at": "2026-04-30T21:38:40.491810236Z",
|
||||
"updated_at": "2026-04-30T21:38:40.491810306Z",
|
||||
"model": "third",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "cec6800f",
|
||||
"created_at": "2026-04-30T21:38:41.231448392Z",
|
||||
"updated_at": "2026-04-30T21:38:41.231448452Z",
|
||||
"model": "graph",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "feb9d52f",
|
||||
"created_at": "2026-05-01T00:02:12.760942465Z",
|
||||
"updated_at": "2026-05-01T00:02:12.760942525Z",
|
||||
"model": "fast",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
},
|
||||
{
|
||||
"id": "d5e72a1a",
|
||||
"created_at": "2026-05-01T00:04:04.268573260Z",
|
||||
"updated_at": "2026-05-01T00:04:12.123721682Z",
|
||||
"model": "deepseek-v4-flash",
|
||||
"summary": "# You are a Team Member\n\n## Your Identity\nName: test-aionrs-fast2, Role: aion...",
|
||||
"message_count": 6
|
||||
},
|
||||
{
|
||||
"id": "a914b317",
|
||||
"created_at": "2026-05-01T00:04:52.964574238Z",
|
||||
"updated_at": "2026-05-01T00:04:52.964574388Z",
|
||||
"model": "gpt-5.4-mini",
|
||||
"summary": "",
|
||||
"message_count": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/aionui-skills
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/cron
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/office-cli
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/skill-creator
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/aionui-skills
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/cron
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/office-cli
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/skill-creator
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/aionui-skills
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/cron
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/office-cli
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/lix/.config/AionUi/config/builtin-skills/_builtin/skill-creator
|
||||
@@ -129,6 +129,7 @@ GREEN:
|
||||
|
||||
## 4. Phase A:基线和全局 token
|
||||
|
||||
|
||||
| ID | 状态 | 任务 | 验收要点 |
|
||||
| --- | --- | --- | --- |
|
||||
| A1 | GREEN | 固定基线视口与截图目录 | `task129` 已支持 `WOLAI_ALINE_VIEWPORTS`;主线程已生成 `1392x1213`、`1440x900`、`390x844` 三组截图;subagent 已复测默认视口 |
|
||||
@@ -140,6 +141,7 @@ GREEN:
|
||||
|
||||
## 5. Phase B:Sidebar / 页面树
|
||||
|
||||
|
||||
| ID | 状态 | 任务 | 验收要点 |
|
||||
| --- | --- | --- | --- |
|
||||
| B1 | PARITY | 侧栏宽度与背景 | `task131` 覆盖宽 `248px`、背景 `rgb(245,245,245)`、无右侧 inset、topbar.x=sidebar.right;subagent post-fix2 复核通过 |
|
||||
@@ -206,6 +208,7 @@ RED / GREEN:
|
||||
|
||||
## 6. Phase C:顶栏、breadcrumb、搜索
|
||||
|
||||
|
||||
| ID | 状态 | 任务 | 验收要点 |
|
||||
| --- | --- | --- | --- |
|
||||
| C1 | PARITY | 顶栏高度与按钮密度 | `task135` 覆盖顶栏约 40px、右侧按钮组无搜索入口、icon 不再渲染成黑色方块;`task119` 复核 topbarHeight=40 |
|
||||
@@ -264,6 +267,7 @@ GREEN:
|
||||
|
||||
## 7. Phase D:文档画布与阅读态
|
||||
|
||||
|
||||
| ID | 状态 | 任务 | 验收要点 |
|
||||
| --- | --- | --- | --- |
|
||||
| D1 | PARITY | 主内容列宽 | `task136` 覆盖普通文档主列 `760px`,大屏居中不贴左;移动端沿既有 media query 保持不溢出 |
|
||||
@@ -322,6 +326,7 @@ GREEN:
|
||||
|
||||
## 8. Phase E:主编辑器块交互
|
||||
|
||||
|
||||
| ID | 状态 | 任务 | 验收要点 |
|
||||
| --- | --- | --- | --- |
|
||||
| E0 | DONE | editable-test 焦点护栏 | Wolai Hermes editable-test 与本地 smoke 均断言写入前焦点在正文测试块,不在标题、breadcrumb 或隐藏输入 |
|
||||
@@ -361,35 +366,59 @@ GREEN:
|
||||
- `tiptap-notion-like-registry` / `tiptap-notion-like-template` 包含 197 个 registry 组件,核心能力不是单个菜单,而是 `DragContextMenu`、`SlashDropdownMenu`、`NotionToolbarFloating`、AI、颜色、链接、表格、图片、TOC、缩进、节点背景、节点对齐、emoji、mention、协作和移动端 toolbar 的组合。
|
||||
- `leptos-tiptap` 当前已支持 `starter-kit` 与 `full`:blockquote、bold、bullet/ordered/task list、code/codeBlock、heading、history、horizontalRule、italic、strike、text-align、highlight、image、link、placeholder、youtube;未直接覆盖表格、数学、emoji、mention、TOC、AI、collaboration caret、节点背景、节点对齐、缩进和 UniqueID。
|
||||
- Phase E 后续实施按 Wolai 基线优先级拆小任务;参考 Tiptap 能力先进入 checklist,不直接视为 mnote 必须一次性照搬。
|
||||
- E11-E31 统一改为“参考 Tiptap 来 aline mnote”:每个任务先定位 `tiptap-notion-like-registry` / `tiptap-notion-like-template` 的组件、hook、extension 或 `leptos-tiptap` bridge 命令,再对照 Wolai 实测决定 mnote 的最小实现。不得绕过已有 Tiptap 参考自行造一套同类 UI 或命令。
|
||||
- 旧 E16 / E24 / E28 中分散的颜色、背景色、link popover、floating toolbar 能力已合并为 E15-E17 的统一能力包;后续实现颜色相关功能时优先参考 `ColorMenu`、`NodeBackground`、`highlight` / `link` bridge,不再分别在 selection toolbar、drag menu、floating toolbar 中重复造轮子。
|
||||
|
||||
### Phase E Tiptap 参考优先 backlog
|
||||
|
||||
执行规则:E11-E31 中任何一项进入实现前,必须先在任务记录中写出参考路径、可复用代码点、mnote 真源落点和 Wolai-aline smoke 断言。若参考实现不适合直接复用,需要说明不复用的原因。
|
||||
|
||||
### Phase E Tiptap 参考执行记录(2026-05-01)
|
||||
|
||||
- E11 参考入口已固化:`tiptap-notion-like-registry/materialized/tiptap-ui/*`、`tiptap-notion-like-registry/materialized/tiptap-extension/*`、`tiptap-notion-like-template/tiptap-notion-like-template/src/components/tiptap-*`、`leptos-tiptap/src/api/commands.rs`。后续 E13-E31 实现前必须先写参考路径和不复用原因。
|
||||
- E12 bridge 边界:`rust/spikes/leptos-tiptap-spike` 以 `leptos-tiptap` `features=["component", "full"]` 编译;可直接复用的命令包括基础块转换、`set_horizontal_rule`、`toggle_task_list`、`toggle_bullet_list`、`toggle_ordered_list`、`set/toggle_text_align`、`set/toggle_highlight`、`set/toggle_link`、`set_image`、`set_youtube_video`、history 与通用 `insert_content(_at)`。
|
||||
- E12 缺口边界:TableKit 已补最小 table schema、行列/标题行列/隐藏边框命令和保存链;完整 TableHandle、TableSelectionOverlay、列宽拖拽、fit、数据表格、Mention、Emoji、TOC、AI、UniqueID/anchor、NodeBackground、NodeAlignment、Indent、ListNormalization 仍不在 `leptos-tiptap` bridge 直接能力内;进入实现时优先扩 bridge 或落 mnote tree/page 命令,不允许只加前端临时 DOM 状态。
|
||||
- E13 Wolai slash 基线:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task142-e13-slash-wolai-baseline/report.md`;Wolai 菜单为 fixed 弹层约 `315x400`,首屏分组 `AI 助理 /ai`、`基础块列表 /jichukuai`,完整分组还包括进阶块、脚注/注释、快速分栏、转换为、媒体与附件、第三方应用、快速输入、插入引用、行内块、快速功能、文字颜色、背景色、荧光背景色;包含分割线、简单表格/数据表格、图片、页面目录、Emoji,未见明确 mention。
|
||||
- E13 当前本地 slash 状态:`rust/spikes/leptos-tiptap-spike/src/lib.rs` 的 `SLASH_ACTIONS` 已包含 `分割线` 与 `简单表格 /jdbg`,分别走 `editor.set_horizontal_rule()` 和真实 Tiptap table 插入;参考 template `components/tiptap-node/horizontal-rule-node/*`。本地与 Wolai 明确缺口是页面 `/ym`、折叠块、页面目录 `/toc`、数据表格 `/db`、Emoji `/bq`、颜色分组、插入引用和行内块;图片 `/tp` 已进入 E24 最小真源切片,但上传/最近上传/浮动工具条仍未完成。
|
||||
- E13 分割线真源闭环:2026-05-01 已补 `EditorBlockType::Divider`、`TiptapNode::HorizontalRule`、`mnote-web` bootstrap `divider -> horizontalRule` 恢复、bridge `horizontalRule -> divider` 保存、JS bridge `Map -> Object` 规范化,以及从 `conflictDetectionKey` 后缀恢复 revision;本地 smoke 已断言 slash 点击后 `/api/documents/content` 返回 `divider`,刷新后 ProseMirror 仍有 `<hr>`。主线程通过截图目录:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task143-e13-divider-persistence-local-v8`;subagent 后验通过截图目录:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task143-e13-divider-persistence-subagent`。
|
||||
- E15/E16 当前本地 toolbar 状态:`rust/spikes/leptos-tiptap-spike/src/lib.rs` 中 `mnote-leptos-tiptap-toolbar` 已用 `toggle_bold/italic/strike/code`、`toggle_mark(Underline)`、`set/toggle_link`、`set_color/unset_color`、`set_highlight/unset_highlight`、`set_text_align` 等 bridge 命令;参考路径为 `tiptap-ui/color-menu/*`、`color-text-button/*`、`color-highlight-button/*`、`mark-button/*`、`text-align-button/*`。缺口是 node background、recent colors、drag menu 颜色子菜单复用、完整 link popover、AI、sup/sub、indent/outdent。
|
||||
- E19 列表缩进真源闭环:2026-05-01 已按 Wolai Hermes 基线确认 `Tab` 会把第二个列表项挂到父项 `sub-node-container`,`Shift+Tab` 提升回同级,不只是视觉 padding。参考路径为 `tiptap-extension/indent-extension.ts`、`list-normalization-extension.ts` 与 `leptos-tiptap/src/api/commands.rs` 的 `sink_list_item` / `lift_list_item`;本地已有 Tiptap 列表键盘命令,修复点落在 `core-protocol` Tiptap bridge 与 `bridge-runtime` canonical legacy content,保存时保留 `childBlockIds` / `children`,`mnote-web` bootstrap 可从 legacy `children` 恢复嵌套 Tiptap 列表。Wolai 基线:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task144-e19-indent-wolai-baseline/comparison-matrix.md`;本地 smoke:`MNOTE_PHASE_E_SCREENSHOT_DIR=/mnt/Data1T/mnote/tmp/wolai-editor-parity/task144-e19-indent-local-green-final node scripts/task144-e19-indent-list-smoke.js`,通过并覆盖 Tiptap JSON、`/api/documents/save`、`/api/documents/content` 真源和刷新恢复。
|
||||
- E20 块布局/文字居中局部闭环:2026-05-01 已按 Wolai Hermes 基线确认 `Ctrl/Cmd+Shift+U` 会进入块布局选中态,块菜单存在 `文字居中`,点击后 Wolai 视觉居中且刷新后保持;Wolai DOM 语义表现为内部内容 class `_1PQWZ`,不是根块 `text-align:center`。本地当前实现 `Ctrl+Shift+U` 后显示 `data-testid=block-layout-outline` 虚线轮廓,并采用 `leptos-tiptap` `set_text_align(TiptapTextAlign::Center)` 作为 Tiptap 参考优先的文字居中真源实现;保存请求、`/api/documents/content` 与刷新恢复均保留 `textAlign=center`。Wolai 基线:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task145-e20-alignment-wolai-baseline/precise-summary.json`;本地 smoke:`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_PHASE_E_SCREENSHOT_DIR=/mnt/Data1T/mnote/tmp/wolai-editor-parity/task145-e20-layout-align-local-current node scripts/task145-e20-alignment-smoke.js`。剩余拆分:selection toolbar 当前 Wolai 基线未出现对齐入口,拖拽分栏/节点级对齐尚无有效 Wolai 基线,后续不能把 E20 标 DONE。
|
||||
- E21 页面当前类型勾选态与 slash 拼音入口局部闭环:2026-05-01 `task137-wolai-phase-e-smoke.js` 已覆盖 `转换为 -> 页面` 后二次打开块菜单时 `block-transform-item-page` 的 `data-current=true` 与 `✓` 勾选态;本轮复跑通过截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task146-e21-current-state-regression`。同日新增 slash 查询态 smoke:输入 `/` 后继续输入 `zhw`,本地菜单显示 `转换为 /zhw`,对应 Wolai slash 基线 `task142-e13-slash-wolai-baseline` 中 `转换为 /zhw`;RED 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task146-e21-slash-zhw-red`,GREEN 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task146-e21-slash-zhw-green`。2026-05-01 继续补 `页面 /ym` 查询入口,Wolai 基线同目录 `04-slash-menu-candidates.json` / `06-slash-menu-rows.json` 均包含 `页面 /ym`;本地 RED 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task147-e21-slash-ym-red`,GREEN 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task147-e21-slash-ym-green`。同日补 H4 小标题二次打开当前态:RED 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task148-e21-h4-current-red`,GREEN 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task148-e21-h4-current-green`,当前项写入 `data-current=true` 并显示 `✓`。同日补基础转换快捷键 `Ctrl/Cmd+Shift+1/2/3/5/6/7` 的本地命令映射,RED 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task149-e21-hotkey-h1-red`,GREEN 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task149-e21-hotkey-h1-green`。当前 `/zhw` 与 `/ym` 入口只作为 Wolai slash 分组入口展示,真实转换/页面创建仍走块菜单或选区工具栏,后续需补 Wolai 二次勾选态基线和其余类型全量当前态。
|
||||
- E22 折叠标题局部闭环:2026-05-01 复用 Wolai Hermes `task138-phase-e-wolai-refresh` 基线,确认 `转换为 -> 折叠标题` 会展开三级菜单 `折叠主标题/折叠大标题/折叠中标题/折叠小标题`,不是 disabled 文案。本地已补 `leptos-tiptap` heading `collapsed` attr、`core-protocol` Tiptap bridge、`bridge-runtime` legacy props、`mnote-web` bootstrap 和块菜单三级菜单;`task150-e22-folding-blocks-smoke.js` 覆盖点击 `折叠主标题` 后 h1 `data-collapsed=true`、保存请求 `attrs.collapsed=true`、`/api/documents/content` 真源和刷新恢复。当前只完成折叠标题最小切片,折叠待办/折叠列表和折叠后的子块显隐状态仍需后续拆分。
|
||||
- E23 简单表格局部闭环:2026-05-01 Wolai Hermes 可编辑基线已确认 `简单表格 /jdbg` 默认插入 `4x3` HTML `<table class="table-content">`,外层 `data-block-type="table"`,URL 不变;行侧/列顶 aux 点击会插入行/列并呈现淡红 overlay,选项菜单含标题行/标题列/隐藏边框线 switch,未确认到清空/fit。当前本地已对齐 slash `简单表格 /jdbg`,并通过 bridge 调用 Tiptap 官方 `insertTable({ rows: 4, cols: 3, withHeaderRow: false })` 插入 `4x3` 真实 Tiptap table,并补表格 toolbar 的下方插入行、右侧插入列、清空当前单元格、删除行/列/表格;已补 `选项` 菜单,`标题行`、`标题列`、`隐藏边框线` 均使用 `role="switch"` 和 `aria-checked`,切换后写入 `tableHeader` 节点或 `attrs.hiddenBorders=true`。已补表格行侧/列顶 aux controls 和最小 TableSelectionOverlay:`table-row-aux-*` 点击后从 `4x3` 进入 `5x3`,`table-col-aux-*` 点击后进入 `5x4`,并显示 `data-testid="table-selection-overlay"` 淡红覆盖层,toolbar 保持可用。2026-05-01 继续补列宽拖拽:Tiptap table 开启 `resizable=true`,列宽拖拽回到官方 `columnResizing` 路径;拖拽首列右边缘后写入单元格 `attrs.colwidth`,保存请求、`/api/documents/content` 与 reload 后 DOM 宽度/col 样式均由 `task151-e23-table-smoke.js` 覆盖;保留 `MnoteTableView` 作为 mnote 属性同步适配,避免 resizable node view 丢失 `data-hidden-borders` / `data-block-id`。2026-05-01 继续补真实 ProseMirror TableSelection:bridge 增加 `select_table_row` / `select_table_column` 命令,行侧/列顶 aux 插入后同步 Tiptap 官方 `CellSelection.rowSelection` / `CellSelection.colSelection`,smoke 断言目标行/列 `.selectedCell` 数量和位置,并静态断言不再使用 `setCellSelection` 或手写 `simple_table_node()` 插入路径;同时把 `@tiptap/pm/tables` 纳入 shared hosted modules,避免 tableEditing decorations 与 EditorView 跨 bundle 混用。Wolai 基线截图:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-wolai-tablekit-baseline/`;本地列宽版截图:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-table-resize-green`;本地官方 resize 复核截图:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-official-resize-green`;本地官方 TableKit 命令复核截图:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-official-tablekit-commands-green`;本地真实 TableSelection 截图:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-table-selection-green`;回归截图:`task144-e19-regression-after-e23-resize`、`task145-e20-regression-after-e23-resize`、`task150-e22-regression-after-e23-resize`、`task137-phase-e-regression-after-e23-resize`。
|
||||
- E24 图片最小真源闭环:2026-05-01 已按 Wolai E13 slash 基线确认 `媒体与附件` 分组存在 `图片 /tp` 与 `最近上传图片 /tp`;第一段实现 `图片 /tp` 最小切片,参考 `leptos-tiptap` 官方 `TiptapImageResource` / `set_image` bridge(`src/api/types/extensions/image.rs`、`src/api/commands.rs`、`tiptap/src/extensions/tiptap_image.ts`)与 template `components/tiptap-node/image-node/*`、`image-upload-node/*`,不手写 image JSON。当前本地 `SLASH_ACTIONS` 已补 `图片 /tp` 和 `媒体与附件` 分组,`p0_extensions()` 显式启用 `TiptapExtension::Image`,点击后调用 `editor.set_image(TiptapImageResource { ... })` 插入真实 Tiptap `image` 节点;`core-protocol` 新增 `EditorBlockType::Image` / `TiptapNode::Image`,`bridge-runtime` 保存为 legacy `image` 且保留 `props.tiptapImage`,`mnote-web` bootstrap 从 content API 恢复为 `<img>`;本地只读占位资源走 `/api/editor/image-placeholder.svg`,避免 smoke 依赖外网或破图。第二段补图片点击选中态与图片专用 floating toolbar,参考 `tiptap-notion-like-registry/materialized/tiptap-node/image-node/image-node-floating.tsx`、`image-node-extension.ts`、`tiptap-ui/image-align-button/use-image-align.ts`、`tiptap-ui/image-download-button/use-image-download.ts`:本地点击 `<img>` 后展示 `image-floating-toolbar`,提供左/中/右对齐和同源图片下载,删除入口本切片保持禁用;图片对齐通过 `Image.extend({ addAttributes: { "data-align" } })` 扩展官方 Image schema 后调用 `editor.update_attributes(TiptapSchemaTarget::Node(TiptapNodeName::Image), ...)`,不是 UI 伪样式;同源下载只读当前 NodeSelection 图片 DOM 的 `src/title/alt`,用隐藏 `<a download>` 触发,不触发保存链。`task152-e24-image-smoke.js` 覆盖 slash 入口、DOM `<img>`、图片实际加载、图片 toolbar、同源下载事件、删除入口禁用态、居中对齐 `data-align`、保存请求 `tiptapDocument`、`/api/documents/content` image 真源与 reload 恢复;通过截图目录:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task152-e24-image-download-green`。剩余:真实上传、最近上传图片、caption、resize、replace、跨源下载 fallback、删除保存链、移动端 toolbar、上传失败态另拆后续。
|
||||
|
||||
- E25 TOC 最小真源闭环:2026-05-01 已按 Wolai slash 基线确认 `页面目录 /toc`,并参考 `tiptap-notion-like-template/src/components/tiptap-node/toc-node/*`、`toc-show-title-button/*`、`toc-sidebar/*` 与 `notion-like-editor.tsx` 中 `TableOfContents.configure({ onUpdate })` 的数据链路。当前本地先完成第一段:`leptos-tiptap` 新增 `toc_node` bridge 扩展,真实 Tiptap schema 名为 `tocNode`,slash `页面目录 /toc` 调用 `editor.insert_toc_node(TiptapTocNodeAttrs { top_offset: 0, max_show_count: 20, show_title: true })`,不是普通 div 或手写 spike JSON;NodeView 从当前 Tiptap doc 的 heading 节点派生目录项,支持点击目录项定位并更新 hash,支持标题显示开关并通过 `updateAttributes("tocNode", { showTitle })` 持久化。保存链新增 `EditorBlockType::Toc` / `TiptapNode::TocNode`,`bridge-runtime` legacy content 保留 `props.tiptapTocNode`,`mnote-web` reload 恢复 `tocNode`;`task153-e25-toc-smoke.js` 覆盖 `/toc` 入口、真实 tocNode DOM、heading 列表派生、动态 heading 更新、点击定位、标题开关、保存请求、content API 和 reload 恢复。截图目录:`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task153-e25-toc-local-smoke`。剩余:接入 Tiptap 官方 `@tiptap/extension-table-of-contents` v3 数据源或完成等价 bridge 评估、TOC sidebar、active heading 高亮、完整块菜单标题开关入口、Wolai 像素级视觉、移动端行为、UniqueID/anchor 统一化。
|
||||
|
||||
### Phase E 说明页扩展 backlog
|
||||
|
||||
| ID | 状态 | 任务 | 验收要点 |
|
||||
| --- | --- | --- | --- |
|
||||
| E11 | TODO | `Tab` / `Shift+Tab` 缩进结构 | 缩进改变父子块结构,不只是视觉 padding;覆盖不允许缩进的块类型 |
|
||||
| E12 | TODO | `Ctrl/Cmd+Shift+U` 块布局 | 显示/隐藏块布局虚线框,且不影响编辑保存 |
|
||||
| E13 | TODO | 块转换三入口 | 块菜单、快捷键、slash `/zh + 拼音首字母` 均能转换文本类块 |
|
||||
| E14 | TODO | 复制/粘贴与匹配样式粘贴 | 文本选择、块选择、`Ctrl/Cmd+Shift+V` 分别有 smoke |
|
||||
| E15 | TODO | 链接创建 | 选中文字 `Ctrl/Cmd+K` 与直接粘贴 URL 创建链接 |
|
||||
| E16 | TODO | 文本颜色/背景色/行内公式/页面引用 | selection toolbar 子菜单真实写入 Tiptap 内容,不只显示入口 |
|
||||
| E17 | TODO | 评论入口 | 块评论、选中文字评论、评论气泡数量和 `Ctrl/Cmd+Alt+M` 后续对标 |
|
||||
| E18 | TODO | 块引用与右侧边栏引用 | 块引用搜索、引用预览/别名、右侧边栏拖拽引用后续对标 |
|
||||
| E19 | TODO | 块历史 | 块历史查看与恢复版本按 Wolai 说明页单列验证 |
|
||||
| E20 | TODO | 拖拽分栏 | 横线/竖线预览、父子块随父块移动、测试块间安全释放与清理 |
|
||||
| E21 | DONE | 块菜单二级转换基础版 | `转换为` hover 后主菜单保持、二级菜单包含 Wolai 当前项目;`文本/待办/高级待办/H1/H2/H3/H4/页面/列表/数字列表/引述/代码` 其中 H4 与页面至少有真实 smoke |
|
||||
| E22 | TODO | 折叠标题三级菜单 | hover `折叠标题` 显示 `折叠主标题/折叠大标题/折叠中标题/折叠小标题`;真实折叠语义需接 editor/core 命令,不用 disabled 文案伪装完成 |
|
||||
| E23 | TODO | 折叠待办三级菜单 | hover `折叠待办` 显示 `折叠待办列表/折叠高级待办列表`;真实折叠待办语义需接 editor/core 命令 |
|
||||
| E24 | TODO | 复制链接/颜色/文字翻译子菜单 | 复制链接、颜色、文字翻译按 Wolai 展开子菜单;颜色至少覆盖文字色/背景色真实写入,复制链接不只反馈文案 |
|
||||
| E25 | TODO | 块菜单关闭状态机 | Esc 与外部点击关闭所有层级;鼠标移出菜单保持打开,三级菜单可按 Wolai 收回到二级菜单;smoke 覆盖三条路径 |
|
||||
| E26 | DONE | `转换为 -> 页面` 真源 | 已按 task140 修正:本地转换时调用 `/api/tree/commands` 创建 `parentId=当前文档` 的真实子页面,当前块原地变 page block,页面块 href 指向子页面且点击可打开,刷新后页面树显示同名子页面;仍需在后续任务补齐 Wolai 重新打开菜单时 `页面` 勾选态的完整二次复核 |
|
||||
| E27 | TODO | 参考 Tiptap slash 插入扩展 | 对齐 `tiptap-notion-like-template`:slash 菜单除文本/标题/列表/引用/代码外,还应覆盖 AI continue/ask、mention、emoji、table、divider、TOC、image upload;每项要按 schema/后端能力拆 smoke,不只显示文案 |
|
||||
| E28 | TODO | 参考 Tiptap floating toolbar 扩展 | 对齐 floating toolbar:Improve/AI、TurnInto、bold/italic/underline/strike/code、image floating、link popover、text color、superscript/subscript、text align、indent/outdent;当前仅覆盖基础行内样式与颜色入口,真实写入需补齐 |
|
||||
| E29 | TODO | 参考 Tiptap drag context menu 扩展 | 对齐 drag context:copy to clipboard、copy anchor link、reset formatting、Ask AI、ColorMenu、TableAlign/Fit/Clear、TOC show title、image download、delete;当前块菜单仍有多项静态或缺失 |
|
||||
| E30 | TODO | 参考 Tiptap 表格/图片/TOC 节点 | 对齐 TableKit/TableHandle/TableSelectionOverlay/ImageUpload/Image floating/TOC sidebar;本地 `leptos-tiptap` crate 当前 full feature 只到 image/link/highlight/youtube,表格、数学、emoji、mention、TOC、协作光标等需按架构另列能力边界 |
|
||||
| E31 | TODO | 参考 Tiptap 节点级样式扩展 | 对齐 NodeBackground、NodeAlignment、Indent、ListNormalization、UniqueID/anchor;当前有 text-align/color/highlight 的局部能力,块背景、缩进结构、锚点复制和列表规范化需补 smoke 与真源映射 |
|
||||
| E11 | DONE | Tiptap 参考优先执行门 | 已固化:每个 Phase E 子任务先记录参考路径、可复用代码点、mnote 真源落点和 Wolai-aline smoke;参考入口覆盖 `registry/materialized/tiptap-extension/*`、`registry/materialized/tiptap-ui/*`、`template/src/components/tiptap-*`、`leptos-tiptap/src/api/commands.rs`,无参考路径不得直接实现 UI |
|
||||
| E12 | DONE | `leptos-tiptap` bridge 能力边界 | 已盘点:当前 full bridge 覆盖基础块/行内 mark、history、horizontalRule、task/bullet/ordered list、text-align、highlight、image、link、youtube、table/tableRow/tableCell/tableHeader 最小 schema;仍缺 mention、emoji、TOC、AI、UniqueID、NodeBackground/Alignment、非列表 Indent/ListNormalization,后续按能力包判断扩 bridge、走 mnote 命令或暂缓 |
|
||||
| E13 | PARTIAL | SlashDropdownMenu 能力包 | 参考 `tiptap-ui/slash-dropdown-menu/*` 与 template horizontalRule;本地已覆盖 AI 文案入口、基础块、待办、标题、列表、引述、代码、分割线、简单表格、图片,其中分割线已走 `set_horizontal_rule()`、保存为 kernel `divider`、刷新恢复为 `<hr>`,简单表格已走真实 Tiptap `table` schema,默认 `4x3` 并由 `task151-e23-table-smoke.js` 覆盖保存/刷新/基础行列、表格选项、行/列 aux 插入、selection overlay 和列宽拖拽持久化操作,图片 `/tp` 已走 `set_image` 并由 `task152-e24-image-smoke.js` 覆盖保存/刷新;Wolai 基线已确认还需补页面、折叠块、TOC、数据表格、Emoji、颜色、引用、行内块等分组,且每项需真实 schema/bridge 或明确未接入状态 |
|
||||
| E14 | PARTIAL | DragContextMenu 能力包 | 以 `DragContextMenu` 为主参考重组块手柄菜单;当前四点/三横线、菜单位置、基础二级转换已对齐,后续补 copy/delete/copy anchor/reset formatting/Ask AI 等命令时复用同一菜单模型 |
|
||||
| E15 | PARTIAL | NotionToolbarFloating 能力包 | 参考 `NotionToolbarFloating`;本地 selection toolbar 已接 TurnInto、bold/italic/underline/strike/code、link、color、text-align 的真实 Tiptap 命令;仍缺 AI、superscript/subscript、indent/outdent、完整 link popover 和 image floating toolbar |
|
||||
| E16 | PARTIAL | 颜色与节点样式统一能力包 | 参考 `ColorMenu`、`color-text-button`、`color-highlight-button`、`node-background-extension.ts`;本地 toolbar 文字色走 `set_color`,背景色走 `set_highlight`,清除颜色走 `unset_color` + `unset_highlight`;仍缺 node background bridge、recent colors、drag menu 颜色子菜单复用和 smoke 对 JSON/刷新恢复断言 |
|
||||
| E17 | PARTIAL | Link / Page / Reference 能力包 | 参考 link popover 与 `leptos-tiptap` `set_link/toggle_link`;已完成 `转换为 -> 页面` 真源和页面树可见,仍需补选中文字 `Ctrl/Cmd+K`、直接粘贴 URL、页面引用、块引用、右侧引用预览 |
|
||||
| E18 | TODO | Clipboard / Paste 能力包 | 参考 registry 的 clipboard/copy 相关按钮与 Tiptap paste 规则;覆盖文本选择、块选择、复制副本、匹配样式粘贴、跨块粘贴,smoke 验证真实 Tiptap JSON 和 mnote 保存链 |
|
||||
| E19 | PARTIAL | Indent / ListNormalization 能力包 | 已完成列表项 `Tab` / `Shift+Tab` 真父子结构闭环:Tiptap JSON 嵌套列表、mnote 保存链 `childBlockIds` / legacy `children`、刷新恢复均由 `task144-e19-indent-list-smoke.js` 覆盖;后续补非列表块 indent-extension、list-normalization 边界和不允许缩进块类型 |
|
||||
| E20 | PARTIAL | NodeAlignment / BlockLayout 能力包 | 已完成 `Ctrl/Cmd+Shift+U` 块布局虚线轮廓和块菜单 `文字居中` 的 Tiptap textAlign 保存链:快捷键后 `block-layout-outline`、块菜单入口、点击后视觉居中、保存请求、`/api/documents/content` 和刷新恢复由 `task145-e20-alignment-smoke.js` 覆盖;剩余 selection toolbar 是否有对齐入口、拖拽分栏预览与节点级对齐需继续拆小任务,不能标 DONE |
|
||||
| E21 | PARTIAL | TurnInto 转换能力包 | 参考 TurnInto 菜单模型;当前 `文本/待办/高级待办/H1-H4/页面/列表/数字列表/引述/代码` 基础入口部分完成,页面转换已接真实子页面;页面块与 H4 小标题二次打开 `转换为` 已有 `✓` 当前态 smoke,slash `zhw` 已能显示 `转换为 /zhw`,slash `ym` 已能显示 `页面 /ym`,基础快捷键 `Ctrl/Cmd+Shift+1/2/3/5/6/7` 已接本地 Tiptap 转换命令;后续补其余类型全量当前态与 Wolai 二次勾选态基线 |
|
||||
| E22 | PARTIAL | Folding Blocks 能力包 | 已完成 `转换为 -> 折叠标题 -> 折叠主标题` 最小真源闭环:三级菜单、heading collapsed attr、保存请求、content API 和刷新恢复由 `task150-e22-folding-blocks-smoke.js` 覆盖;后续补折叠大/中/小标题 smoke、折叠待办/折叠列表真实语义、折叠后的子块显隐与当前态 |
|
||||
| E23 | PARTIAL | TableKit 能力包 | 已完成简单表格可验收切片:`leptos-tiptap` 增加 table/tableRow/tableCell/tableHeader schema,slash `简单表格 /jdbg` 按 Wolai 基线插入 `4x3` 真实 `<table>`,本地 table toolbar 支持下方插入行、右侧插入列、清空当前单元格、删除当前行/列/表格,并补 `选项` 菜单的标题行、标题列、隐藏边框线 switch;已补行侧/列顶 aux controls 和最小 TableSelectionOverlay,点击行/列 aux 会插入行/列并显示对应淡红选择覆盖层,toolbar 保持可用;`core-protocol`/`bridge-runtime`/`mnote-web` 保存与刷新恢复保留 `table` Tiptap 快照、`tableHeader` 和 `attrs.hiddenBorders`;本地 smoke `task151-e23-table-smoke.js` 覆盖入口、DOM、row/column aux 插入、selection overlay、列宽拖拽、switch 语义/状态、保存请求、content API、reload 和删除。剩余表格对齐、fit、数据表格入口,以及 Wolai 选项菜单图标/toolbar 视觉细节另拆后续 |
|
||||
| E24 | PARTIAL | Image / Media 能力包 | 已完成图片 `/tp` 最小真源闭环与图片 toolbar 小闭环:slash `媒体与附件` 分组入口调用 `leptos-tiptap` 官方 `set_image(TiptapImageResource)`,启用 `TiptapExtension::Image`,保存链新增 `EditorBlockType::Image` / `TiptapNode::Image` 并保留 `props.tiptapImage`,`mnote-web` reload 恢复 `<img>`;点击图片后出现 `image-floating-toolbar`,删除入口本切片保持禁用,左/中/右对齐通过官方 Image 扩展 `addAttributes("data-align")` + `updateAttributes("image")` 持久化,同源下载通过隐藏 `<a download>` 触发且不改文档;`task152-e24-image-smoke.js` 覆盖入口、实际图片加载、toolbar、同源下载、删除入口禁用态、居中对齐、保存请求、content API 和刷新恢复;剩余上传、最近上传、caption、resize、replace、跨源下载 fallback、删除保存链、移动端 toolbar、失败态 |
|
||||
| E25 | PARTIAL | TOC 能力包 | 已完成 `/toc` 最小真源闭环:`leptos-tiptap` 新增真实 `tocNode` schema/command,slash `页面目录 /toc` 插入真实节点,NodeView 从当前 headings 派生目录项,支持点击定位、标题显示开关、保存请求、content API 与 reload 恢复;`task153-e25-toc-smoke.js` 覆盖入口、动态 heading 更新、hash 定位和 `props.tiptapTocNode`。剩余 TOC sidebar、active heading 高亮、完整块菜单入口、官方 TableOfContents v3 数据源评估、移动端与像素级视觉 |
|
||||
| E26 | TODO | UniqueID / Anchor 能力包 | 参考 UniqueID/anchor/copy anchor link 相关实现;每个块需要稳定 id,复制链接应指向可恢复的页面/块锚点,刷新后仍可定位 |
|
||||
| E27 | TODO | AI 编辑能力包 | 参考 `ai-context`、AI icons、Improve/Ask AI/continue/regenerate/summarize/translate;先接 mnote 现有 AI command/tool 真源,再做 Wolai 菜单入口和流式状态 |
|
||||
| E28 | TODO | Mention / Emoji 能力包 | 参考 mention trigger 与 emoji menu;实现 `@`、emoji 搜索、键盘导航、插入后的 Tiptap JSON 和 mnote 保存链,不作为纯文本占位 |
|
||||
| E29 | TODO | Comment / History 能力包 | 参考评论入口、块历史入口的菜单形态,结合 mnote 后端能力决定先做 smoke 占位还是真实存储;`Ctrl/Cmd+Alt+M`、评论气泡数量、块历史恢复需单列对标 |
|
||||
| E30 | TODO | Menu / Floating 状态机能力包 | 参考 `use-floating-element`、`use-menu-navigation`、`use-floating-toolbar-visibility`;统一 Esc、外部点击、鼠标移出、方向键、Enter、层级菜单收起逻辑,避免每个菜单各写一套状态机 |
|
||||
| E31 | PARTIAL | Tiptap 参考对标 smoke 矩阵 | `task137-wolai-phase-e-smoke.js` 已覆盖 E13 分割线的 DOM `<hr>`、`/api/documents/content` `divider`、刷新恢复和页面转换 `_self` 打开;后续每完成一个能力包仍必须同时断言 Tiptap JSON/schema、mnote 真源保存、Wolai 视觉/交互截图、刷新恢复;截图差异未复核不得标 DONE |
|
||||
|
||||
## 9. Phase F:Page Aggregate 和命令边界
|
||||
|
||||
|
||||
| ID | 状态 | 任务 | 验收要点 |
|
||||
| --- | --- | --- | --- |
|
||||
| F1 | TODO | 标题单一真源 | 标题修改后 breadcrumb、sidebar、file tree、document title 同步 |
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9150,6 +9150,10 @@ fn normalize_editor_block_type_for_save(raw_type: &str) -> EditorBlockType {
|
||||
"todo" | "task" => EditorBlockType::Todo,
|
||||
"quote" | "blockquote" => EditorBlockType::Quote,
|
||||
"code" | "code_block" | "code-block" => EditorBlockType::CodeBlock,
|
||||
"divider" | "horizontal_rule" | "horizontalrule" => EditorBlockType::Divider,
|
||||
"table" => EditorBlockType::Table,
|
||||
"image" | "picture" => EditorBlockType::Image,
|
||||
"toc" | "toc_node" | "tocnode" => EditorBlockType::Toc,
|
||||
"page_reference" => EditorBlockType::PageReference,
|
||||
"block_reference" => EditorBlockType::BlockReference,
|
||||
_ => EditorBlockType::Paragraph,
|
||||
@@ -9174,6 +9178,11 @@ fn normalize_editor_block_from_legacy(block: &Value, index: usize) -> EditorBloc
|
||||
.and_then(Value::as_u64)
|
||||
.and_then(|value| u8::try_from(value).ok())
|
||||
.map(|value| value.clamp(1, 6));
|
||||
props.collapsed = block
|
||||
.get("props")
|
||||
.and_then(Value::as_object)
|
||||
.and_then(|map| map.get("collapsed"))
|
||||
.and_then(Value::as_bool);
|
||||
}
|
||||
if matches!(
|
||||
normalize_editor_block_type_for_save(&raw_type),
|
||||
@@ -9196,6 +9205,30 @@ fn normalize_editor_block_from_legacy(block: &Value, index: usize) -> EditorBloc
|
||||
.and_then(Value::as_str)
|
||||
.map(ToOwned::to_owned);
|
||||
}
|
||||
if let Some(tiptap_table) = block
|
||||
.get("props")
|
||||
.and_then(Value::as_object)
|
||||
.and_then(|map| map.get("tiptapTable"))
|
||||
.cloned()
|
||||
{
|
||||
props.extra.insert("tiptapTable".into(), tiptap_table);
|
||||
}
|
||||
if let Some(tiptap_image) = block
|
||||
.get("props")
|
||||
.and_then(Value::as_object)
|
||||
.and_then(|map| map.get("tiptapImage"))
|
||||
.cloned()
|
||||
{
|
||||
props.extra.insert("tiptapImage".into(), tiptap_image);
|
||||
}
|
||||
if let Some(tiptap_toc) = block
|
||||
.get("props")
|
||||
.and_then(Value::as_object)
|
||||
.and_then(|map| map.get("tiptapTocNode").or_else(|| map.get("tiptapToc")))
|
||||
.cloned()
|
||||
{
|
||||
props.extra.insert("tiptapTocNode".into(), tiptap_toc);
|
||||
}
|
||||
let text = read_trimmed_string_field(block, &["content"])
|
||||
.filter(|value| !value.is_empty())
|
||||
.unwrap_or_else(|| extract_inline_text(block));
|
||||
@@ -9265,17 +9298,83 @@ fn normalize_save_editor_document(
|
||||
}
|
||||
|
||||
fn legacy_props_from_editor_block(block: &EditorBlock) -> Option<Value> {
|
||||
let mut props = serde_json::Map::new();
|
||||
match block.block_type {
|
||||
EditorBlockType::Heading => Some(json!({
|
||||
"level": block.props.heading_level.unwrap_or(1),
|
||||
})),
|
||||
EditorBlockType::Todo => Some(json!({
|
||||
"checked": block.props.checked.unwrap_or(false),
|
||||
})),
|
||||
EditorBlockType::CodeBlock => Some(json!({
|
||||
"language": block.props.language,
|
||||
})),
|
||||
_ => None,
|
||||
EditorBlockType::Heading => {
|
||||
props.insert(
|
||||
"level".into(),
|
||||
json!(block.props.heading_level.unwrap_or(1)),
|
||||
);
|
||||
if let Some(collapsed) = block.props.collapsed {
|
||||
props.insert("collapsed".into(), json!(collapsed));
|
||||
}
|
||||
}
|
||||
EditorBlockType::Todo => {
|
||||
props.insert(
|
||||
"checked".into(),
|
||||
json!(block.props.checked.unwrap_or(false)),
|
||||
);
|
||||
}
|
||||
EditorBlockType::CodeBlock => {
|
||||
props.insert("language".into(), json!(block.props.language));
|
||||
}
|
||||
EditorBlockType::Table => {
|
||||
if let Some(tiptap_table) = block.props.extra.get("tiptapTable") {
|
||||
props.insert("tiptapTable".into(), tiptap_table.clone());
|
||||
}
|
||||
}
|
||||
EditorBlockType::Image => {
|
||||
if let Some(tiptap_image) = block.props.extra.get("tiptapImage") {
|
||||
props.insert("tiptapImage".into(), tiptap_image.clone());
|
||||
if let Some(attrs) = tiptap_image.get("attrs").and_then(Value::as_object) {
|
||||
for key in ["src", "alt", "title"] {
|
||||
if let Some(value) = attrs.get(key) {
|
||||
props.insert(key.into(), value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorBlockType::Toc => {
|
||||
if let Some(tiptap_toc) = block.props.extra.get("tiptapTocNode") {
|
||||
props.insert("tiptapTocNode".into(), tiptap_toc.clone());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Some(text_align) = block
|
||||
.props
|
||||
.extra
|
||||
.get("textAlign")
|
||||
.or_else(|| block.props.extra.get("text_align"))
|
||||
.and_then(Value::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| matches!(*value, "left" | "center" | "right" | "justify"))
|
||||
{
|
||||
props.insert("textAlign".into(), json!(text_align));
|
||||
}
|
||||
if props.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Value::Object(props))
|
||||
}
|
||||
}
|
||||
|
||||
fn legacy_type_from_editor_block(block: &EditorBlock) -> &'static str {
|
||||
match block.block_type {
|
||||
EditorBlockType::Paragraph => "paragraph",
|
||||
EditorBlockType::Heading => "heading",
|
||||
EditorBlockType::BulletListItem => "bullet_list_item",
|
||||
EditorBlockType::NumberedListItem => "numbered_list_item",
|
||||
EditorBlockType::Quote => "blockquote",
|
||||
EditorBlockType::Todo => "todo",
|
||||
EditorBlockType::CodeBlock => "code_block",
|
||||
EditorBlockType::Divider => "divider",
|
||||
EditorBlockType::Table => "table",
|
||||
EditorBlockType::Image => "image",
|
||||
EditorBlockType::Toc => "toc",
|
||||
EditorBlockType::PageReference => "page_reference",
|
||||
EditorBlockType::BlockReference => "block_reference",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9292,6 +9391,54 @@ fn legacy_text_from_editor_block(block: &EditorBlock) -> String {
|
||||
}
|
||||
|
||||
fn legacy_content_from_editor_document(document: &EditorBlockDocument) -> Value {
|
||||
fn block_to_legacy_value(block: &EditorBlock, document: &EditorBlockDocument) -> Value {
|
||||
let children = block
|
||||
.child_block_ids
|
||||
.iter()
|
||||
.filter_map(|child_id| {
|
||||
document
|
||||
.blocks
|
||||
.iter()
|
||||
.find(|candidate| &candidate.block_id == child_id)
|
||||
})
|
||||
.map(|child| block_to_legacy_value(child, document))
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
let mut value = json!({
|
||||
"id": block.block_id,
|
||||
"type": legacy_type_from_editor_block(block),
|
||||
"props": legacy_props_from_editor_block(block),
|
||||
"content": if matches!(block.block_type, EditorBlockType::Divider) {
|
||||
Value::Array(Vec::new())
|
||||
} else {
|
||||
Value::String(legacy_text_from_editor_block(block))
|
||||
},
|
||||
});
|
||||
if !children.is_empty() {
|
||||
if let Value::Object(map) = &mut value {
|
||||
map.insert("children".into(), Value::Array(children));
|
||||
}
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
fn mark_block_tree_seen(
|
||||
block: &EditorBlock,
|
||||
document: &EditorBlockDocument,
|
||||
seen: &mut std::collections::BTreeSet<String>,
|
||||
) {
|
||||
seen.insert(block.block_id.clone());
|
||||
for child_id in &block.child_block_ids {
|
||||
if let Some(child) = document
|
||||
.blocks
|
||||
.iter()
|
||||
.find(|candidate| &candidate.block_id == child_id)
|
||||
{
|
||||
mark_block_tree_seen(child, document, seen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut ordered = Vec::<&EditorBlock>::new();
|
||||
let mut seen = std::collections::BTreeSet::<String>::new();
|
||||
for root_block_id in &document.root_block_ids {
|
||||
@@ -9300,7 +9447,7 @@ fn legacy_content_from_editor_document(document: &EditorBlockDocument) -> Value
|
||||
.iter()
|
||||
.find(|block| &block.block_id == root_block_id)
|
||||
{
|
||||
seen.insert(block.block_id.clone());
|
||||
mark_block_tree_seen(block, document, &mut seen);
|
||||
ordered.push(block);
|
||||
}
|
||||
}
|
||||
@@ -9313,14 +9460,7 @@ fn legacy_content_from_editor_document(document: &EditorBlockDocument) -> Value
|
||||
Value::Array(
|
||||
ordered
|
||||
.into_iter()
|
||||
.map(|block| {
|
||||
json!({
|
||||
"id": block.block_id,
|
||||
"type": block.block_type,
|
||||
"props": legacy_props_from_editor_block(block),
|
||||
"content": legacy_text_from_editor_block(block),
|
||||
})
|
||||
})
|
||||
.map(|block| block_to_legacy_value(block, document))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
@@ -10607,6 +10747,299 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn documents_save_command_plan_preserves_horizontal_rule_as_divider() {
|
||||
let plan = execute_runtime_input(RuntimeInput::Command {
|
||||
context: demo_context(),
|
||||
command: RuntimeCommandEnvelopeWire {
|
||||
name: "documents.save".into(),
|
||||
command_id: "cmd_save_divider".into(),
|
||||
idempotency_key: Some("idem_save_divider".into()),
|
||||
actor: RuntimeActorWire {
|
||||
actor_type: "user".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("sess_1".into()),
|
||||
},
|
||||
source: RuntimeSourceWire {
|
||||
channel: "rust-web".into(),
|
||||
client: "mnote-web".into(),
|
||||
},
|
||||
target: Some(RuntimeTargetWire {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("doc_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: json!({
|
||||
"documentId": "doc_1",
|
||||
"workspaceId": "ws_1",
|
||||
"revision": 5,
|
||||
"content": [],
|
||||
"tiptapDocument": {
|
||||
"type": "doc",
|
||||
"content": [
|
||||
{
|
||||
"type": "horizontalRule",
|
||||
"attrs": {
|
||||
"blockId": "divider_1"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"conflictDetectionKey": "doc_1:5"
|
||||
}),
|
||||
preflight_data: None,
|
||||
reason: Some("保存分割线".into()),
|
||||
refs: vec!["phase-e-divider".into()],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
},
|
||||
})
|
||||
.expect("documents.save horizontalRule plan should build");
|
||||
|
||||
let RuntimeExecutionPlan::Command(plan) = plan else {
|
||||
panic!("expected command plan");
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/editorDocument/blocks/0/blockType"),
|
||||
Some(&json!("divider"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/type"),
|
||||
Some(&json!("divider"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/content"),
|
||||
Some(&json!([]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn documents_save_command_plan_preserves_tiptap_image() {
|
||||
let plan = execute_runtime_input(RuntimeInput::Command {
|
||||
context: demo_context(),
|
||||
command: RuntimeCommandEnvelopeWire {
|
||||
name: "documents.save".into(),
|
||||
command_id: "cmd_save_image".into(),
|
||||
idempotency_key: Some("idem_save_image".into()),
|
||||
actor: RuntimeActorWire {
|
||||
actor_type: "user".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("sess_1".into()),
|
||||
},
|
||||
source: RuntimeSourceWire {
|
||||
channel: "rust-web".into(),
|
||||
client: "mnote-web".into(),
|
||||
},
|
||||
target: Some(RuntimeTargetWire {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("doc_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: json!({
|
||||
"documentId": "doc_1",
|
||||
"workspaceId": "ws_1",
|
||||
"revision": 5,
|
||||
"content": [],
|
||||
"tiptapDocument": {
|
||||
"type": "doc",
|
||||
"content": [{
|
||||
"type": "image",
|
||||
"attrs": {
|
||||
"src": "/api/editor/image-placeholder.svg",
|
||||
"alt": "E24 图片占位",
|
||||
"title": "E24 图片"
|
||||
}
|
||||
}]
|
||||
},
|
||||
"conflictDetectionKey": "doc_1:5"
|
||||
}),
|
||||
preflight_data: None,
|
||||
reason: Some("保存图片".into()),
|
||||
refs: vec!["phase-e-image".into()],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
},
|
||||
})
|
||||
.expect("documents.save image plan should build");
|
||||
|
||||
let RuntimeExecutionPlan::Command(plan) = plan else {
|
||||
panic!("expected command plan");
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/editorDocument/blocks/0/blockType"),
|
||||
Some(&json!("image"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/type"),
|
||||
Some(&json!("image"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/props/tiptapImage/type"),
|
||||
Some(&json!("image"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/props/src"),
|
||||
Some(&json!("/api/editor/image-placeholder.svg"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn documents_save_command_plan_preserves_tiptap_table() {
|
||||
let plan = execute_runtime_input(RuntimeInput::Command {
|
||||
context: demo_context(),
|
||||
command: RuntimeCommandEnvelopeWire {
|
||||
name: "documents.save".into(),
|
||||
command_id: "cmd_save_table".into(),
|
||||
idempotency_key: Some("idem_save_table".into()),
|
||||
actor: RuntimeActorWire {
|
||||
actor_type: "user".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("sess_1".into()),
|
||||
},
|
||||
source: RuntimeSourceWire {
|
||||
channel: "rust-web".into(),
|
||||
client: "mnote-web".into(),
|
||||
},
|
||||
target: Some(RuntimeTargetWire {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("doc_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: json!({
|
||||
"documentId": "doc_1",
|
||||
"workspaceId": "ws_1",
|
||||
"revision": 5,
|
||||
"content": [],
|
||||
"tiptapDocument": {
|
||||
"type": "doc",
|
||||
"content": [{
|
||||
"type": "table",
|
||||
"attrs": { "blockId": "table_1" },
|
||||
"content": [{
|
||||
"type": "tableRow",
|
||||
"content": [{
|
||||
"type": "tableCell",
|
||||
"attrs": { "colspan": 1, "rowspan": 1, "colwidth": null },
|
||||
"content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "A1" }] }]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
},
|
||||
"conflictDetectionKey": "doc_1:5"
|
||||
}),
|
||||
preflight_data: None,
|
||||
reason: Some("保存简单表格".into()),
|
||||
refs: vec!["phase-e-table".into()],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
},
|
||||
})
|
||||
.expect("documents.save table plan should build");
|
||||
|
||||
let RuntimeExecutionPlan::Command(plan) = plan else {
|
||||
panic!("expected command plan");
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/editorDocument/blocks/0/blockType"),
|
||||
Some(&json!("table"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/type"),
|
||||
Some(&json!("table"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/props/tiptapTable/type"),
|
||||
Some(&json!("table"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/content"),
|
||||
Some(&json!("A1"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn documents_save_command_plan_preserves_nested_list_children() {
|
||||
let plan = execute_runtime_input(RuntimeInput::Command {
|
||||
context: demo_context(),
|
||||
command: RuntimeCommandEnvelopeWire {
|
||||
name: "documents.save".into(),
|
||||
command_id: "cmd_save_nested_list".into(),
|
||||
idempotency_key: Some("idem_save_nested_list".into()),
|
||||
actor: RuntimeActorWire {
|
||||
actor_type: "user".into(),
|
||||
actor_id: "user_1".into(),
|
||||
session_id: Some("sess_1".into()),
|
||||
},
|
||||
source: RuntimeSourceWire {
|
||||
channel: "rust-web".into(),
|
||||
client: "mnote-web".into(),
|
||||
},
|
||||
target: Some(RuntimeTargetWire {
|
||||
workspace_id: Some("ws_1".into()),
|
||||
page_id: Some("doc_1".into()),
|
||||
block_id: None,
|
||||
}),
|
||||
payload: json!({
|
||||
"documentId": "doc_1",
|
||||
"workspaceId": "ws_1",
|
||||
"revision": 5,
|
||||
"content": [],
|
||||
"tiptapDocument": {
|
||||
"type": "doc",
|
||||
"content": [{
|
||||
"type": "bulletList",
|
||||
"content": [{
|
||||
"type": "listItem",
|
||||
"attrs": { "blockId": "parent" },
|
||||
"content": [
|
||||
{ "type": "paragraph", "content": [{ "type": "text", "text": "E19 parent" }] },
|
||||
{ "type": "bulletList", "content": [{
|
||||
"type": "listItem",
|
||||
"attrs": { "blockId": "child" },
|
||||
"content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "E19 child" }] }]
|
||||
}]}
|
||||
]
|
||||
}]
|
||||
}]
|
||||
},
|
||||
"conflictDetectionKey": "doc_1:5"
|
||||
}),
|
||||
preflight_data: None,
|
||||
reason: Some("保存嵌套列表".into()),
|
||||
refs: vec!["phase-e-indent".into()],
|
||||
dry_run: false,
|
||||
validate_only: false,
|
||||
},
|
||||
})
|
||||
.expect("documents.save nested list plan should build");
|
||||
|
||||
let RuntimeExecutionPlan::Command(plan) = plan else {
|
||||
panic!("expected command plan");
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/editorDocument/rootBlockIds"),
|
||||
Some(&json!(["parent"]))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json
|
||||
.pointer("/editorDocument/blocks/0/childBlockIds"),
|
||||
Some(&json!(["child"]))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/children/0/type"),
|
||||
Some(&json!("bullet_list_item"))
|
||||
);
|
||||
assert_eq!(
|
||||
plan.args_json.pointer("/content/0/children/0/content"),
|
||||
Some(&json!("E19 child"))
|
||||
);
|
||||
assert_eq!(plan.args_json.pointer("/content/1"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_body_save_command_plan_uses_canonical_page_command() {
|
||||
let plan = execute_runtime_input(RuntimeInput::Command {
|
||||
|
||||
@@ -12,6 +12,10 @@ pub enum EditorBlockType {
|
||||
Quote,
|
||||
Todo,
|
||||
CodeBlock,
|
||||
Divider,
|
||||
Table,
|
||||
Image,
|
||||
Toc,
|
||||
PageReference,
|
||||
BlockReference,
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::editor::model::{
|
||||
TextMark,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -17,6 +18,13 @@ pub enum TiptapBlockType {
|
||||
TaskItem,
|
||||
Blockquote,
|
||||
CodeBlock,
|
||||
HorizontalRule,
|
||||
Table,
|
||||
Image,
|
||||
TocNode,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableHeader,
|
||||
Text,
|
||||
HardBreak,
|
||||
Doc,
|
||||
@@ -28,6 +36,10 @@ pub struct TiptapHeadingAttrs {
|
||||
pub level: u8,
|
||||
#[serde(default)]
|
||||
pub block_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub text_align: Option<String>,
|
||||
#[serde(default)]
|
||||
pub collapsed: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
@@ -44,6 +56,8 @@ pub struct TiptapTaskItemAttrs {
|
||||
pub struct TiptapParagraphAttrs {
|
||||
#[serde(default)]
|
||||
pub block_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub text_align: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
@@ -65,6 +79,8 @@ pub struct TiptapListItemAttrs {
|
||||
pub struct TiptapBlockquoteAttrs {
|
||||
#[serde(default)]
|
||||
pub block_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub text_align: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -72,6 +88,66 @@ pub struct TiptapBlockquoteAttrs {
|
||||
pub struct TiptapCodeBlockAttrs {
|
||||
pub language: Option<String>,
|
||||
pub block_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub text_align: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TiptapHorizontalRuleAttrs {
|
||||
#[serde(default)]
|
||||
pub block_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TiptapImageAttrs {
|
||||
pub src: String,
|
||||
#[serde(default)]
|
||||
pub alt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub title: Option<String>,
|
||||
#[serde(default)]
|
||||
pub block_id: Option<String>,
|
||||
#[serde(flatten)]
|
||||
pub extra: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TiptapTableAttrs {
|
||||
#[serde(default)]
|
||||
pub block_id: Option<String>,
|
||||
#[serde(flatten)]
|
||||
pub extra: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TiptapTocNodeAttrs {
|
||||
#[serde(default)]
|
||||
pub top_offset: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub max_show_count: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub show_title: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub block_id: Option<String>,
|
||||
#[serde(flatten)]
|
||||
pub extra: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TiptapTableCellAttrs {
|
||||
#[serde(default)]
|
||||
pub colspan: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub rowspan: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub colwidth: Value,
|
||||
#[serde(flatten)]
|
||||
pub extra: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -137,6 +213,41 @@ pub enum TiptapNode {
|
||||
#[serde(default)]
|
||||
content: Vec<TiptapNode>,
|
||||
},
|
||||
HorizontalRule {
|
||||
#[serde(default)]
|
||||
attrs: TiptapHorizontalRuleAttrs,
|
||||
},
|
||||
Image {
|
||||
attrs: TiptapImageAttrs,
|
||||
},
|
||||
Table {
|
||||
#[serde(default)]
|
||||
attrs: TiptapTableAttrs,
|
||||
#[serde(default)]
|
||||
content: Vec<TiptapNode>,
|
||||
},
|
||||
TocNode {
|
||||
#[serde(default)]
|
||||
attrs: TiptapTocNodeAttrs,
|
||||
},
|
||||
TableRow {
|
||||
#[serde(default)]
|
||||
attrs: BTreeMap<String, Value>,
|
||||
#[serde(default)]
|
||||
content: Vec<TiptapNode>,
|
||||
},
|
||||
TableCell {
|
||||
#[serde(default)]
|
||||
attrs: TiptapTableCellAttrs,
|
||||
#[serde(default)]
|
||||
content: Vec<TiptapNode>,
|
||||
},
|
||||
TableHeader {
|
||||
#[serde(default)]
|
||||
attrs: TiptapTableCellAttrs,
|
||||
#[serde(default)]
|
||||
content: Vec<TiptapNode>,
|
||||
},
|
||||
Text {
|
||||
text: String,
|
||||
#[serde(default)]
|
||||
@@ -153,6 +264,113 @@ pub enum EditorBlockDocumentTiptapError {
|
||||
|
||||
pub struct EditorBlockDocumentTiptapBridge;
|
||||
|
||||
fn text_align_from_props(props: &BlockProps) -> Option<String> {
|
||||
props
|
||||
.extra
|
||||
.get("textAlign")
|
||||
.or_else(|| props.extra.get("text_align"))
|
||||
.and_then(|value| value.as_str())
|
||||
.map(str::trim)
|
||||
.filter(|value| matches!(*value, "left" | "center" | "right" | "justify"))
|
||||
.map(ToOwned::to_owned)
|
||||
}
|
||||
|
||||
fn table_snapshot_from_props(props: &BlockProps) -> Option<TiptapNode> {
|
||||
props
|
||||
.extra
|
||||
.get("tiptapTable")
|
||||
.cloned()
|
||||
.and_then(|value| serde_json::from_value::<TiptapNode>(value).ok())
|
||||
}
|
||||
|
||||
fn image_snapshot_from_props(props: &BlockProps) -> Option<TiptapNode> {
|
||||
props
|
||||
.extra
|
||||
.get("tiptapImage")
|
||||
.cloned()
|
||||
.and_then(|value| serde_json::from_value::<TiptapNode>(value).ok())
|
||||
}
|
||||
|
||||
fn toc_snapshot_from_props(props: &BlockProps) -> Option<TiptapNode> {
|
||||
props
|
||||
.extra
|
||||
.get("tiptapTocNode")
|
||||
.or_else(|| props.extra.get("tiptapToc"))
|
||||
.cloned()
|
||||
.and_then(|value| serde_json::from_value::<TiptapNode>(value).ok())
|
||||
}
|
||||
|
||||
fn props_with_image_snapshot(node: &TiptapNode) -> BlockProps {
|
||||
let mut props = BlockProps::default();
|
||||
if let Ok(value) = serde_json::to_value(node) {
|
||||
props.extra.insert("tiptapImage".into(), value);
|
||||
}
|
||||
props
|
||||
}
|
||||
|
||||
fn props_with_table_snapshot(node: &TiptapNode) -> BlockProps {
|
||||
let mut props = BlockProps::default();
|
||||
if let Ok(value) = serde_json::to_value(node) {
|
||||
props.extra.insert("tiptapTable".into(), value);
|
||||
}
|
||||
props
|
||||
}
|
||||
|
||||
fn props_with_toc_snapshot(node: &TiptapNode) -> BlockProps {
|
||||
let mut props = BlockProps::default();
|
||||
if let Ok(value) = serde_json::to_value(node) {
|
||||
props.extra.insert("tiptapTocNode".into(), value);
|
||||
}
|
||||
props
|
||||
}
|
||||
|
||||
fn collect_table_text_nodes(nodes: &[TiptapNode], out: &mut Vec<ContentNode>) {
|
||||
for node in nodes {
|
||||
match node {
|
||||
TiptapNode::Text { text, marks } => out.push(ContentNode {
|
||||
payload: ContentNodePayload::Text {
|
||||
text: text.clone(),
|
||||
marks: marks.iter().filter_map(tiptap_mark_to_text_mark).collect(),
|
||||
},
|
||||
attrs: BTreeMap::new(),
|
||||
}),
|
||||
TiptapNode::HardBreak => out.push(ContentNode {
|
||||
payload: ContentNodePayload::HardBreak,
|
||||
attrs: BTreeMap::new(),
|
||||
}),
|
||||
TiptapNode::Doc { content }
|
||||
| TiptapNode::Paragraph { content, .. }
|
||||
| TiptapNode::Heading { content, .. }
|
||||
| TiptapNode::BulletList { content, .. }
|
||||
| TiptapNode::OrderedList { content, .. }
|
||||
| TiptapNode::TaskList { content, .. }
|
||||
| TiptapNode::ListItem { content, .. }
|
||||
| TiptapNode::TaskItem { content, .. }
|
||||
| TiptapNode::Blockquote { content, .. }
|
||||
| TiptapNode::CodeBlock { content, .. }
|
||||
| TiptapNode::Table { content, .. }
|
||||
| TiptapNode::TableRow { content, .. }
|
||||
| TiptapNode::TableCell { content, .. }
|
||||
| TiptapNode::TableHeader { content, .. } => collect_table_text_nodes(content, out),
|
||||
TiptapNode::HorizontalRule { .. }
|
||||
| TiptapNode::Image { .. }
|
||||
| TiptapNode::TocNode { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn props_with_text_align(text_align: Option<String>) -> BlockProps {
|
||||
let mut props = BlockProps::default();
|
||||
if let Some(text_align) = text_align
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| matches!(*value, "left" | "center" | "right" | "justify"))
|
||||
{
|
||||
props.extra.insert("textAlign".into(), text_align.into());
|
||||
}
|
||||
props
|
||||
}
|
||||
|
||||
impl EditorBlockDocumentTiptapBridge {
|
||||
pub fn to_tiptap_doc(
|
||||
document: &EditorBlockDocument,
|
||||
@@ -166,7 +384,7 @@ impl EditorBlockDocumentTiptapBridge {
|
||||
.ok_or(EditorBlockDocumentTiptapError::InvalidDocument(
|
||||
"根块不存在",
|
||||
))?;
|
||||
content.push(block_to_tiptap_node(block)?);
|
||||
content.push(block_to_tiptap_node(block, document)?);
|
||||
}
|
||||
Ok(TiptapNode::Doc { content })
|
||||
}
|
||||
@@ -180,9 +398,9 @@ impl EditorBlockDocumentTiptapBridge {
|
||||
let mut blocks = Vec::new();
|
||||
let mut root_block_ids = Vec::new();
|
||||
for (index, node) in content.iter().enumerate() {
|
||||
let block = node_to_block(node, index)?;
|
||||
root_block_ids.push(block.block_id.clone());
|
||||
blocks.push(block);
|
||||
let (node_root_ids, mut node_blocks) = node_to_blocks(node, index)?;
|
||||
root_block_ids.extend(node_root_ids);
|
||||
blocks.append(&mut node_blocks);
|
||||
}
|
||||
Ok(EditorBlockDocument {
|
||||
document_id: document_id.into(),
|
||||
@@ -197,12 +415,82 @@ impl EditorBlockDocumentTiptapBridge {
|
||||
}
|
||||
}
|
||||
|
||||
fn block_to_tiptap_node(block: &EditorBlock) -> Result<TiptapNode, EditorBlockDocumentTiptapError> {
|
||||
fn node_to_blocks(
|
||||
node: &TiptapNode,
|
||||
index: usize,
|
||||
) -> Result<(Vec<String>, Vec<EditorBlock>), EditorBlockDocumentTiptapError> {
|
||||
match node {
|
||||
TiptapNode::BulletList { attrs, content } => list_node_to_blocks(
|
||||
attrs.block_id.as_deref(),
|
||||
EditorBlockType::BulletListItem,
|
||||
content,
|
||||
&format!("block_{}", index + 1),
|
||||
),
|
||||
TiptapNode::OrderedList { attrs, content } => list_node_to_blocks(
|
||||
attrs.block_id.as_deref(),
|
||||
EditorBlockType::NumberedListItem,
|
||||
content,
|
||||
&format!("block_{}", index + 1),
|
||||
),
|
||||
TiptapNode::TaskList { attrs, content } => list_node_to_blocks(
|
||||
attrs.block_id.as_deref(),
|
||||
EditorBlockType::Todo,
|
||||
content,
|
||||
&format!("block_{}", index + 1),
|
||||
),
|
||||
_ => {
|
||||
let block = node_to_block(node, index)?;
|
||||
Ok((vec![block.block_id.clone()], vec![block]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn block_child_tiptap_nodes(
|
||||
block: &EditorBlock,
|
||||
document: &EditorBlockDocument,
|
||||
) -> Result<Vec<TiptapNode>, EditorBlockDocumentTiptapError> {
|
||||
block
|
||||
.child_block_ids
|
||||
.iter()
|
||||
.map(|child_id| {
|
||||
let child = document
|
||||
.blocks
|
||||
.iter()
|
||||
.find(|candidate| &candidate.block_id == child_id)
|
||||
.ok_or(EditorBlockDocumentTiptapError::InvalidDocument(
|
||||
"子块不存在",
|
||||
))?;
|
||||
block_to_tiptap_node(child, document)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn list_item_content_from_block(
|
||||
block: &EditorBlock,
|
||||
inline_content: Vec<TiptapNode>,
|
||||
document: &EditorBlockDocument,
|
||||
) -> Result<Vec<TiptapNode>, EditorBlockDocumentTiptapError> {
|
||||
let mut content = vec![TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
text_align: text_align_from_props(&block.props),
|
||||
},
|
||||
content: inline_content,
|
||||
}];
|
||||
content.extend(block_child_tiptap_nodes(block, document)?);
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
fn block_to_tiptap_node(
|
||||
block: &EditorBlock,
|
||||
document: &EditorBlockDocument,
|
||||
) -> Result<TiptapNode, EditorBlockDocumentTiptapError> {
|
||||
let content = text_nodes_to_tiptap(&block.content_nodes)?;
|
||||
match block.block_type {
|
||||
EditorBlockType::Paragraph => Ok(TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
text_align: text_align_from_props(&block.props),
|
||||
},
|
||||
content,
|
||||
}),
|
||||
@@ -210,6 +498,8 @@ fn block_to_tiptap_node(block: &EditorBlock) -> Result<TiptapNode, EditorBlockDo
|
||||
attrs: TiptapHeadingAttrs {
|
||||
level: block.props.heading_level.unwrap_or(1),
|
||||
block_id: Some(block.block_id.clone()),
|
||||
text_align: text_align_from_props(&block.props),
|
||||
collapsed: block.props.collapsed,
|
||||
},
|
||||
content,
|
||||
}),
|
||||
@@ -221,12 +511,7 @@ fn block_to_tiptap_node(block: &EditorBlock) -> Result<TiptapNode, EditorBlockDo
|
||||
attrs: TiptapListItemAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
},
|
||||
content: vec![TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
},
|
||||
content,
|
||||
}],
|
||||
content: list_item_content_from_block(block, content, document)?,
|
||||
}],
|
||||
}),
|
||||
EditorBlockType::NumberedListItem => Ok(TiptapNode::OrderedList {
|
||||
@@ -237,12 +522,7 @@ fn block_to_tiptap_node(block: &EditorBlock) -> Result<TiptapNode, EditorBlockDo
|
||||
attrs: TiptapListItemAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
},
|
||||
content: vec![TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
},
|
||||
content,
|
||||
}],
|
||||
content: list_item_content_from_block(block, content, document)?,
|
||||
}],
|
||||
}),
|
||||
EditorBlockType::Todo => Ok(TiptapNode::TaskList {
|
||||
@@ -254,21 +534,18 @@ fn block_to_tiptap_node(block: &EditorBlock) -> Result<TiptapNode, EditorBlockDo
|
||||
checked: block.props.checked.unwrap_or(false),
|
||||
block_id: Some(block.block_id.clone()),
|
||||
},
|
||||
content: vec![TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
},
|
||||
content,
|
||||
}],
|
||||
content: list_item_content_from_block(block, content, document)?,
|
||||
}],
|
||||
}),
|
||||
EditorBlockType::Quote => Ok(TiptapNode::Blockquote {
|
||||
attrs: TiptapBlockquoteAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
text_align: text_align_from_props(&block.props),
|
||||
},
|
||||
content: vec![TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
text_align: text_align_from_props(&block.props),
|
||||
},
|
||||
content,
|
||||
}],
|
||||
@@ -277,9 +554,24 @@ fn block_to_tiptap_node(block: &EditorBlock) -> Result<TiptapNode, EditorBlockDo
|
||||
attrs: TiptapCodeBlockAttrs {
|
||||
language: block.props.language.clone(),
|
||||
block_id: Some(block.block_id.clone()),
|
||||
text_align: text_align_from_props(&block.props),
|
||||
},
|
||||
content,
|
||||
}),
|
||||
EditorBlockType::Divider => Ok(TiptapNode::HorizontalRule {
|
||||
attrs: TiptapHorizontalRuleAttrs {
|
||||
block_id: Some(block.block_id.clone()),
|
||||
},
|
||||
}),
|
||||
EditorBlockType::Table => table_snapshot_from_props(&block.props).ok_or(
|
||||
EditorBlockDocumentTiptapError::InvalidDocument("表格块缺少 Tiptap 快照"),
|
||||
),
|
||||
EditorBlockType::Image => image_snapshot_from_props(&block.props).ok_or(
|
||||
EditorBlockDocumentTiptapError::InvalidDocument("图片块缺少 Tiptap 快照"),
|
||||
),
|
||||
EditorBlockType::Toc => toc_snapshot_from_props(&block.props).ok_or(
|
||||
EditorBlockDocumentTiptapError::InvalidDocument("目录块缺少 Tiptap 快照"),
|
||||
),
|
||||
_ => Err(EditorBlockDocumentTiptapError::UnsupportedNode(
|
||||
"当前块型暂不支持导出到 Tiptap",
|
||||
)),
|
||||
@@ -295,7 +587,7 @@ fn node_to_block(
|
||||
TiptapNode::Paragraph { attrs, content } => Ok(EditorBlock {
|
||||
block_id: attrs.block_id.clone().unwrap_or(fallback_block_id),
|
||||
block_type: EditorBlockType::Paragraph,
|
||||
props: BlockProps::default(),
|
||||
props: props_with_text_align(attrs.text_align.clone()),
|
||||
content_nodes: text_nodes_from_tiptap(content)?,
|
||||
child_block_ids: vec![],
|
||||
}),
|
||||
@@ -304,7 +596,8 @@ fn node_to_block(
|
||||
block_type: EditorBlockType::Heading,
|
||||
props: BlockProps {
|
||||
heading_level: Some(attrs.level),
|
||||
..BlockProps::default()
|
||||
collapsed: attrs.collapsed,
|
||||
..props_with_text_align(attrs.text_align.clone())
|
||||
},
|
||||
content_nodes: text_nodes_from_tiptap(content)?,
|
||||
child_block_ids: vec![],
|
||||
@@ -325,7 +618,7 @@ fn node_to_block(
|
||||
TiptapNode::Blockquote { attrs, content } => Ok(EditorBlock {
|
||||
block_id: attrs.block_id.clone().unwrap_or(fallback_block_id),
|
||||
block_type: EditorBlockType::Quote,
|
||||
props: BlockProps::default(),
|
||||
props: props_with_text_align(attrs.text_align.clone()),
|
||||
content_nodes: text_nodes_from_tiptap(extract_block_container_content(content)?)?,
|
||||
child_block_ids: vec![],
|
||||
}),
|
||||
@@ -334,11 +627,43 @@ fn node_to_block(
|
||||
block_type: EditorBlockType::CodeBlock,
|
||||
props: BlockProps {
|
||||
language: attrs.language.clone(),
|
||||
..BlockProps::default()
|
||||
..props_with_text_align(attrs.text_align.clone())
|
||||
},
|
||||
content_nodes: text_nodes_from_tiptap(content)?,
|
||||
child_block_ids: vec![],
|
||||
}),
|
||||
TiptapNode::HorizontalRule { attrs } => Ok(EditorBlock {
|
||||
block_id: attrs.block_id.clone().unwrap_or(fallback_block_id),
|
||||
block_type: EditorBlockType::Divider,
|
||||
props: BlockProps::default(),
|
||||
content_nodes: vec![],
|
||||
child_block_ids: vec![],
|
||||
}),
|
||||
TiptapNode::Table { attrs, content } => {
|
||||
let mut content_nodes = Vec::new();
|
||||
collect_table_text_nodes(content, &mut content_nodes);
|
||||
Ok(EditorBlock {
|
||||
block_id: attrs.block_id.clone().unwrap_or(fallback_block_id),
|
||||
block_type: EditorBlockType::Table,
|
||||
props: props_with_table_snapshot(node),
|
||||
content_nodes,
|
||||
child_block_ids: vec![],
|
||||
})
|
||||
}
|
||||
TiptapNode::Image { attrs } => Ok(EditorBlock {
|
||||
block_id: attrs.block_id.clone().unwrap_or(fallback_block_id),
|
||||
block_type: EditorBlockType::Image,
|
||||
props: props_with_image_snapshot(node),
|
||||
content_nodes: vec![],
|
||||
child_block_ids: vec![],
|
||||
}),
|
||||
TiptapNode::TocNode { attrs } => Ok(EditorBlock {
|
||||
block_id: attrs.block_id.clone().unwrap_or(fallback_block_id),
|
||||
block_type: EditorBlockType::Toc,
|
||||
props: props_with_toc_snapshot(node),
|
||||
content_nodes: vec![],
|
||||
child_block_ids: vec![],
|
||||
}),
|
||||
_ => Err(EditorBlockDocumentTiptapError::UnsupportedNode(
|
||||
"当前节点暂不支持导入为 EditorBlockDocument",
|
||||
)),
|
||||
@@ -359,6 +684,112 @@ fn list_node_to_block(
|
||||
})
|
||||
}
|
||||
|
||||
fn list_node_to_blocks(
|
||||
list_block_id: Option<&str>,
|
||||
block_type: EditorBlockType,
|
||||
content: &[TiptapNode],
|
||||
fallback_prefix: &str,
|
||||
) -> Result<(Vec<String>, Vec<EditorBlock>), EditorBlockDocumentTiptapError> {
|
||||
let mut root_ids = Vec::new();
|
||||
let mut blocks = Vec::new();
|
||||
let use_list_id_for_single_item = content.len() == 1;
|
||||
|
||||
for (index, item) in content.iter().enumerate() {
|
||||
let fallback_block_id = if use_list_id_for_single_item {
|
||||
list_block_id
|
||||
.map(ToOwned::to_owned)
|
||||
.unwrap_or_else(|| fallback_prefix.to_string())
|
||||
} else {
|
||||
format!("{fallback_prefix}_item_{}", index + 1)
|
||||
};
|
||||
let (block, mut child_blocks) = list_item_node_to_block(
|
||||
item,
|
||||
block_type.clone(),
|
||||
&fallback_block_id,
|
||||
&format!("{fallback_prefix}_child_{}", index + 1),
|
||||
)?;
|
||||
root_ids.push(block.block_id.clone());
|
||||
blocks.push(block);
|
||||
blocks.append(&mut child_blocks);
|
||||
}
|
||||
|
||||
Ok((root_ids, blocks))
|
||||
}
|
||||
|
||||
fn list_item_node_to_block(
|
||||
item: &TiptapNode,
|
||||
block_type: EditorBlockType,
|
||||
fallback_block_id: &str,
|
||||
child_fallback_prefix: &str,
|
||||
) -> Result<(EditorBlock, Vec<EditorBlock>), EditorBlockDocumentTiptapError> {
|
||||
let (block_id, checked, content) = match item {
|
||||
TiptapNode::ListItem { attrs, content } => (
|
||||
attrs
|
||||
.block_id
|
||||
.clone()
|
||||
.unwrap_or_else(|| fallback_block_id.to_string()),
|
||||
None,
|
||||
content,
|
||||
),
|
||||
TiptapNode::TaskItem { attrs, content } => (
|
||||
attrs
|
||||
.block_id
|
||||
.clone()
|
||||
.unwrap_or_else(|| fallback_block_id.to_string()),
|
||||
Some(attrs.checked),
|
||||
content,
|
||||
),
|
||||
_ => {
|
||||
return Err(EditorBlockDocumentTiptapError::InvalidDocument(
|
||||
"列表节点首子节点类型不正确",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let inline_content = extract_block_container_content(content)?;
|
||||
let mut child_block_ids = Vec::new();
|
||||
let mut child_blocks = Vec::new();
|
||||
for (index, child) in content.iter().enumerate() {
|
||||
let (child_root_ids, mut nested_blocks) = match child {
|
||||
TiptapNode::BulletList { attrs, content } => list_node_to_blocks(
|
||||
attrs.block_id.as_deref(),
|
||||
EditorBlockType::BulletListItem,
|
||||
content,
|
||||
&format!("{child_fallback_prefix}_bullet_{}", index + 1),
|
||||
)?,
|
||||
TiptapNode::OrderedList { attrs, content } => list_node_to_blocks(
|
||||
attrs.block_id.as_deref(),
|
||||
EditorBlockType::NumberedListItem,
|
||||
content,
|
||||
&format!("{child_fallback_prefix}_ordered_{}", index + 1),
|
||||
)?,
|
||||
TiptapNode::TaskList { attrs, content } => list_node_to_blocks(
|
||||
attrs.block_id.as_deref(),
|
||||
EditorBlockType::Todo,
|
||||
content,
|
||||
&format!("{child_fallback_prefix}_task_{}", index + 1),
|
||||
)?,
|
||||
_ => continue,
|
||||
};
|
||||
child_block_ids.extend(child_root_ids);
|
||||
child_blocks.append(&mut nested_blocks);
|
||||
}
|
||||
|
||||
Ok((
|
||||
EditorBlock {
|
||||
block_id,
|
||||
block_type,
|
||||
props: BlockProps {
|
||||
checked,
|
||||
..BlockProps::default()
|
||||
},
|
||||
content_nodes: text_nodes_from_tiptap(inline_content)?,
|
||||
child_block_ids,
|
||||
},
|
||||
child_blocks,
|
||||
))
|
||||
}
|
||||
|
||||
fn list_task_node_to_block(
|
||||
block_id: String,
|
||||
content: &[TiptapNode],
|
||||
@@ -492,3 +923,224 @@ fn tiptap_mark_to_text_mark(mark: &TiptapMark) -> Option<TextMark> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn converts_horizontal_rule_to_divider_block() {
|
||||
let doc = TiptapNode::Doc {
|
||||
content: vec![TiptapNode::HorizontalRule {
|
||||
attrs: TiptapHorizontalRuleAttrs {
|
||||
block_id: Some("divider_1".into()),
|
||||
},
|
||||
}],
|
||||
};
|
||||
|
||||
let parsed = EditorBlockDocumentTiptapBridge::from_tiptap_doc("doc_1", &doc)
|
||||
.expect("horizontalRule should convert to divider");
|
||||
|
||||
assert_eq!(parsed.root_block_ids, vec!["divider_1"]);
|
||||
assert_eq!(parsed.blocks[0].block_type, EditorBlockType::Divider);
|
||||
assert!(parsed.blocks[0].content_nodes.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converts_divider_block_to_horizontal_rule() {
|
||||
let document = EditorBlockDocument {
|
||||
document_id: "doc_1".into(),
|
||||
root_block_ids: vec!["divider_1".into()],
|
||||
blocks: vec![EditorBlock {
|
||||
block_id: "divider_1".into(),
|
||||
block_type: EditorBlockType::Divider,
|
||||
props: BlockProps::default(),
|
||||
content_nodes: vec![],
|
||||
child_block_ids: vec![],
|
||||
}],
|
||||
};
|
||||
|
||||
let tiptap = EditorBlockDocumentTiptapBridge::to_tiptap_doc(&document)
|
||||
.expect("divider should convert to horizontalRule");
|
||||
|
||||
assert_eq!(
|
||||
tiptap,
|
||||
TiptapNode::Doc {
|
||||
content: vec![TiptapNode::HorizontalRule {
|
||||
attrs: TiptapHorizontalRuleAttrs {
|
||||
block_id: Some("divider_1".into()),
|
||||
},
|
||||
}],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converts_nested_bullet_list_to_child_blocks() {
|
||||
let doc = TiptapNode::Doc {
|
||||
content: vec![TiptapNode::BulletList {
|
||||
attrs: TiptapListAttrs {
|
||||
block_id: Some("list_root".into()),
|
||||
},
|
||||
content: vec![TiptapNode::ListItem {
|
||||
attrs: TiptapListItemAttrs {
|
||||
block_id: Some("parent".into()),
|
||||
},
|
||||
content: vec![
|
||||
TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs::default(),
|
||||
content: vec![TiptapNode::Text {
|
||||
text: "E19 parent".into(),
|
||||
marks: vec![],
|
||||
}],
|
||||
},
|
||||
TiptapNode::BulletList {
|
||||
attrs: TiptapListAttrs::default(),
|
||||
content: vec![TiptapNode::ListItem {
|
||||
attrs: TiptapListItemAttrs {
|
||||
block_id: Some("child".into()),
|
||||
},
|
||||
content: vec![TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs::default(),
|
||||
content: vec![TiptapNode::Text {
|
||||
text: "E19 child".into(),
|
||||
marks: vec![],
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
let parsed = EditorBlockDocumentTiptapBridge::from_tiptap_doc("doc_1", &doc)
|
||||
.expect("nested list should convert to child blocks");
|
||||
|
||||
assert_eq!(parsed.root_block_ids, vec!["parent"]);
|
||||
assert_eq!(parsed.blocks.len(), 2);
|
||||
assert_eq!(parsed.blocks[0].block_id, "parent");
|
||||
assert_eq!(parsed.blocks[0].block_type, EditorBlockType::BulletListItem);
|
||||
assert_eq!(parsed.blocks[0].child_block_ids, vec!["child"]);
|
||||
assert_eq!(parsed.blocks[1].block_id, "child");
|
||||
assert_eq!(parsed.blocks[1].block_type, EditorBlockType::BulletListItem);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn converts_child_blocks_to_nested_bullet_list() {
|
||||
let document = EditorBlockDocument {
|
||||
document_id: "doc_1".into(),
|
||||
root_block_ids: vec!["parent".into()],
|
||||
blocks: vec![
|
||||
EditorBlock {
|
||||
block_id: "parent".into(),
|
||||
block_type: EditorBlockType::BulletListItem,
|
||||
props: BlockProps::default(),
|
||||
content_nodes: vec![ContentNode {
|
||||
payload: ContentNodePayload::Text {
|
||||
text: "E19 parent".into(),
|
||||
marks: vec![],
|
||||
},
|
||||
attrs: BTreeMap::new(),
|
||||
}],
|
||||
child_block_ids: vec!["child".into()],
|
||||
},
|
||||
EditorBlock {
|
||||
block_id: "child".into(),
|
||||
block_type: EditorBlockType::BulletListItem,
|
||||
props: BlockProps::default(),
|
||||
content_nodes: vec![ContentNode {
|
||||
payload: ContentNodePayload::Text {
|
||||
text: "E19 child".into(),
|
||||
marks: vec![],
|
||||
},
|
||||
attrs: BTreeMap::new(),
|
||||
}],
|
||||
child_block_ids: vec![],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let tiptap = EditorBlockDocumentTiptapBridge::to_tiptap_doc(&document)
|
||||
.expect("child blocks should convert to nested list");
|
||||
|
||||
let TiptapNode::Doc { content } = tiptap else {
|
||||
panic!("expected doc");
|
||||
};
|
||||
let Some(TiptapNode::BulletList { content, .. }) = content.first() else {
|
||||
panic!("expected root bullet list");
|
||||
};
|
||||
let Some(TiptapNode::ListItem { content, .. }) = content.first() else {
|
||||
panic!("expected root list item");
|
||||
};
|
||||
assert!(content
|
||||
.iter()
|
||||
.any(|node| matches!(node, TiptapNode::BulletList { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_toc_node_snapshot() {
|
||||
let doc = TiptapNode::Doc {
|
||||
content: vec![TiptapNode::TocNode {
|
||||
attrs: TiptapTocNodeAttrs {
|
||||
top_offset: Some(0),
|
||||
max_show_count: Some(20),
|
||||
show_title: Some(true),
|
||||
block_id: Some("toc_1".into()),
|
||||
extra: BTreeMap::new(),
|
||||
},
|
||||
}],
|
||||
};
|
||||
|
||||
let parsed = EditorBlockDocumentTiptapBridge::from_tiptap_doc("doc_1", &doc)
|
||||
.expect("tocNode should convert to toc block");
|
||||
assert_eq!(parsed.root_block_ids, vec!["toc_1"]);
|
||||
assert_eq!(parsed.blocks[0].block_type, EditorBlockType::Toc);
|
||||
assert_eq!(
|
||||
parsed.blocks[0]
|
||||
.props
|
||||
.extra
|
||||
.get("tiptapTocNode")
|
||||
.and_then(|value| value.get("type"))
|
||||
.and_then(Value::as_str),
|
||||
Some("tocNode")
|
||||
);
|
||||
|
||||
let restored = EditorBlockDocumentTiptapBridge::to_tiptap_doc(&parsed)
|
||||
.expect("toc block should restore to tocNode");
|
||||
assert_eq!(restored, doc);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_paragraph_text_alignment() {
|
||||
let doc = TiptapNode::Doc {
|
||||
content: vec![TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs {
|
||||
block_id: Some("align_1".into()),
|
||||
text_align: Some("center".into()),
|
||||
},
|
||||
content: vec![TiptapNode::Text {
|
||||
text: "E20 center".into(),
|
||||
marks: vec![],
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
let parsed = EditorBlockDocumentTiptapBridge::from_tiptap_doc("doc_1", &doc)
|
||||
.expect("textAlign should convert to block props");
|
||||
assert_eq!(
|
||||
parsed.blocks[0].props.extra.get("textAlign"),
|
||||
Some(&serde_json::json!("center"))
|
||||
);
|
||||
|
||||
let restored = EditorBlockDocumentTiptapBridge::to_tiptap_doc(&parsed)
|
||||
.expect("textAlign should restore to tiptap attrs");
|
||||
let TiptapNode::Doc { content } = restored else {
|
||||
panic!("expected doc");
|
||||
};
|
||||
let Some(TiptapNode::Paragraph { attrs, .. }) = content.first() else {
|
||||
panic!("expected paragraph");
|
||||
};
|
||||
assert_eq!(attrs.text_align.as_deref(), Some("center"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ fn tiptap_import_preserves_explicit_block_ids_and_marks() {
|
||||
TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs {
|
||||
block_id: Some("p-1".into()),
|
||||
text_align: None,
|
||||
},
|
||||
content: vec![TiptapNode::Text {
|
||||
text: "Hello".into(),
|
||||
@@ -161,6 +162,8 @@ fn tiptap_import_preserves_explicit_block_ids_and_marks() {
|
||||
attrs: TiptapHeadingAttrs {
|
||||
level: 3,
|
||||
block_id: Some("h-1".into()),
|
||||
text_align: None,
|
||||
collapsed: None,
|
||||
},
|
||||
content: vec![TiptapNode::Text {
|
||||
text: "H".into(),
|
||||
@@ -179,6 +182,7 @@ fn tiptap_import_preserves_explicit_block_ids_and_marks() {
|
||||
content: vec![TiptapNode::Paragraph {
|
||||
attrs: TiptapParagraphAttrs {
|
||||
block_id: Some("t-1".into()),
|
||||
text_align: None,
|
||||
},
|
||||
content: vec![TiptapNode::Text {
|
||||
text: "todo".into(),
|
||||
@@ -191,6 +195,7 @@ fn tiptap_import_preserves_explicit_block_ids_and_marks() {
|
||||
attrs: TiptapCodeBlockAttrs {
|
||||
language: Some("ts".into()),
|
||||
block_id: Some("c-1".into()),
|
||||
text_align: None,
|
||||
},
|
||||
content: vec![TiptapNode::Text {
|
||||
text: "let x = 1;".into(),
|
||||
@@ -214,3 +219,119 @@ fn tiptap_import_preserves_explicit_block_ids_and_marks() {
|
||||
other => panic!("unexpected payload: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tiptap_heading_round_trip_preserves_collapsed_attr() {
|
||||
let doc: TiptapNode = serde_json::from_value(serde_json::json!({
|
||||
"type": "doc",
|
||||
"content": [{
|
||||
"type": "heading",
|
||||
"attrs": {
|
||||
"level": 1,
|
||||
"blockId": "folded-h1",
|
||||
"collapsed": true
|
||||
},
|
||||
"content": [{ "type": "text", "text": "折叠主标题" }]
|
||||
}]
|
||||
}))
|
||||
.expect("heading JSON should parse");
|
||||
|
||||
let imported = EditorBlockDocumentTiptapBridge::from_tiptap_doc("doc_folded", &doc)
|
||||
.expect("heading should import");
|
||||
assert_eq!(imported.blocks[0].props.heading_level, Some(1));
|
||||
assert_eq!(imported.blocks[0].props.collapsed, Some(true));
|
||||
|
||||
let exported =
|
||||
EditorBlockDocumentTiptapBridge::to_tiptap_doc(&imported).expect("heading should export");
|
||||
let exported_value = serde_json::to_value(exported).expect("exported doc should serialize");
|
||||
assert_eq!(
|
||||
exported_value.pointer("/content/0/attrs/collapsed"),
|
||||
Some(&serde_json::json!(true))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tiptap_image_round_trip_preserves_image_node() {
|
||||
let doc: TiptapNode = serde_json::from_value(serde_json::json!({
|
||||
"type": "doc",
|
||||
"content": [{
|
||||
"type": "image",
|
||||
"attrs": {
|
||||
"src": "/api/editor/image-placeholder.svg",
|
||||
"alt": "E24 图片占位",
|
||||
"title": "E24 图片"
|
||||
}
|
||||
}]
|
||||
}))
|
||||
.expect("image JSON should parse");
|
||||
|
||||
let imported = EditorBlockDocumentTiptapBridge::from_tiptap_doc("doc_image", &doc)
|
||||
.expect("image should import");
|
||||
assert_eq!(imported.blocks[0].block_type, EditorBlockType::Image);
|
||||
|
||||
let exported =
|
||||
EditorBlockDocumentTiptapBridge::to_tiptap_doc(&imported).expect("image should export");
|
||||
let exported_value = serde_json::to_value(exported).expect("exported doc should serialize");
|
||||
assert_eq!(
|
||||
exported_value.pointer("/content/0/type"),
|
||||
Some(&serde_json::json!("image"))
|
||||
);
|
||||
assert_eq!(
|
||||
exported_value.pointer("/content/0/attrs/src"),
|
||||
Some(&serde_json::json!("/api/editor/image-placeholder.svg"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tiptap_table_round_trip_preserves_table_node() {
|
||||
let doc: TiptapNode = serde_json::from_value(serde_json::json!({
|
||||
"type": "doc",
|
||||
"content": [{
|
||||
"type": "table",
|
||||
"attrs": { "blockId": "table-1" },
|
||||
"content": [{
|
||||
"type": "tableRow",
|
||||
"content": [{
|
||||
"type": "tableCell",
|
||||
"attrs": { "colspan": 1, "rowspan": 1, "colwidth": null },
|
||||
"content": [{
|
||||
"type": "paragraph",
|
||||
"content": [{ "type": "text", "text": "A1" }]
|
||||
}]
|
||||
}, {
|
||||
"type": "tableCell",
|
||||
"attrs": { "colspan": 1, "rowspan": 1, "colwidth": null },
|
||||
"content": [{ "type": "paragraph" }]
|
||||
}]
|
||||
}, {
|
||||
"type": "tableRow",
|
||||
"content": [{
|
||||
"type": "tableCell",
|
||||
"attrs": { "colspan": 1, "rowspan": 1, "colwidth": null },
|
||||
"content": [{ "type": "paragraph" }]
|
||||
}, {
|
||||
"type": "tableCell",
|
||||
"attrs": { "colspan": 1, "rowspan": 1, "colwidth": null },
|
||||
"content": [{ "type": "paragraph" }]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}))
|
||||
.expect("table JSON should parse");
|
||||
|
||||
let imported = EditorBlockDocumentTiptapBridge::from_tiptap_doc("doc_table", &doc)
|
||||
.expect("table should import");
|
||||
assert_eq!(imported.blocks[0].block_type, EditorBlockType::Table);
|
||||
|
||||
let exported =
|
||||
EditorBlockDocumentTiptapBridge::to_tiptap_doc(&imported).expect("table should export");
|
||||
let exported_value = serde_json::to_value(exported).expect("exported doc should serialize");
|
||||
assert_eq!(
|
||||
exported_value.pointer("/content/0/type"),
|
||||
Some(&serde_json::json!("table"))
|
||||
);
|
||||
assert_eq!(
|
||||
exported_value.pointer("/content/0/content/0/content/0/content/0/content/0/text"),
|
||||
Some(&serde_json::json!("A1"))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ pub fn build_router(state: AppState) -> Router {
|
||||
"/api/leptos-tiptap-runtime/{*asset_path}",
|
||||
get(web_shell::leptos_tiptap_asset),
|
||||
)
|
||||
.route(
|
||||
"/api/editor/image-placeholder.svg",
|
||||
get(web_shell::editor_image_placeholder_asset),
|
||||
)
|
||||
.route("/api/search/documents", post(search::documents))
|
||||
.route("/api/gateway/health", get(gateway::gateway_health))
|
||||
.route("/api/runtime/config", get(session::runtime_config))
|
||||
|
||||
@@ -311,26 +311,93 @@ pub(crate) fn render_editor_island_adapter_script() -> &'static str {
|
||||
const type = typeof block?.type === 'string' ? block.type : 'paragraph';
|
||||
const text = flattenText(block?.content);
|
||||
const content = text ? [{ type: 'text', text }] : [];
|
||||
const textAlign = typeof block?.props?.textAlign === 'string'
|
||||
? block.props.textAlign
|
||||
: typeof block?.props?.text_align === 'string'
|
||||
? block.props.text_align
|
||||
: undefined;
|
||||
const withTextAlign = (attrs = {}) => textAlign ? { ...attrs, textAlign } : attrs;
|
||||
const nestedChildren = Array.isArray(block?.children)
|
||||
? block.children.map(legacyBlockToTiptap).filter(Boolean)
|
||||
: [];
|
||||
const withListChildren = (itemType, listType, attrs = {}) => ({
|
||||
type: listType,
|
||||
content: [{
|
||||
type: itemType,
|
||||
attrs,
|
||||
content: [
|
||||
{ type: 'paragraph', content },
|
||||
...nestedChildren,
|
||||
],
|
||||
}],
|
||||
});
|
||||
if (type === 'heading') {
|
||||
const level = Number(block?.props?.level || block?.level || 1) || 1;
|
||||
return { type: 'heading', attrs: { level: Math.max(1, Math.min(6, level)) }, content };
|
||||
const collapsed = typeof block?.props?.collapsed === 'boolean' ? { collapsed: block.props.collapsed } : {};
|
||||
return { type: 'heading', attrs: withTextAlign({ level: Math.max(1, Math.min(6, level)), ...collapsed }), content };
|
||||
}
|
||||
if (type === 'bulletListItem' || type === 'bullet_list_item') {
|
||||
return { type: 'bulletList', content: [{ type: 'listItem', content: [{ type: 'paragraph', content }] }] };
|
||||
return withListChildren('listItem', 'bulletList');
|
||||
}
|
||||
if (type === 'numberedListItem' || type === 'numbered_list_item') {
|
||||
return { type: 'orderedList', content: [{ type: 'listItem', content: [{ type: 'paragraph', content }] }] };
|
||||
return withListChildren('listItem', 'orderedList');
|
||||
}
|
||||
if (type === 'checkListItem' || type === 'advancedTodo' || type === 'todo') {
|
||||
return { type: 'taskList', content: [{ type: 'taskItem', attrs: { checked: Boolean(block?.props?.checked) }, content: [{ type: 'paragraph', content }] }] };
|
||||
return withListChildren('taskItem', 'taskList', { checked: Boolean(block?.props?.checked) });
|
||||
}
|
||||
if (type === 'quote' || type === 'blockquote') {
|
||||
return { type: 'blockquote', content: [{ type: 'paragraph', content }] };
|
||||
return { type: 'blockquote', attrs: withTextAlign(), content: [{ type: 'paragraph', attrs: withTextAlign(), content }] };
|
||||
}
|
||||
if (type === 'codeBlock') {
|
||||
return { type: 'codeBlock', attrs: { language: block?.props?.language || null }, content };
|
||||
if (type === 'codeBlock' || type === 'code_block') {
|
||||
return { type: 'codeBlock', attrs: withTextAlign({ language: block?.props?.language || null }), content };
|
||||
}
|
||||
return { type: 'paragraph', content };
|
||||
if (type === 'divider' || type === 'horizontalRule' || type === 'horizontal_rule') {
|
||||
return { type: 'horizontalRule' };
|
||||
}
|
||||
if (type === 'table') {
|
||||
const tableSnapshot = block?.props?.tiptapTable;
|
||||
if (tableSnapshot && typeof tableSnapshot === 'object' && tableSnapshot.type === 'table') {
|
||||
return tableSnapshot;
|
||||
}
|
||||
return {
|
||||
type: 'table',
|
||||
content: [{
|
||||
type: 'tableRow',
|
||||
content: [{
|
||||
type: 'tableCell',
|
||||
attrs: { colspan: 1, rowspan: 1, colwidth: null },
|
||||
content: [{ type: 'paragraph', content }],
|
||||
}],
|
||||
}],
|
||||
};
|
||||
}
|
||||
if (type === 'toc' || type === 'tocNode' || type === 'toc_node') {
|
||||
const tocSnapshot = block?.props?.tiptapTocNode || block?.props?.tiptapToc;
|
||||
if (tocSnapshot && typeof tocSnapshot === 'object' && tocSnapshot.type === 'tocNode') {
|
||||
return tocSnapshot;
|
||||
}
|
||||
return {
|
||||
type: 'tocNode',
|
||||
attrs: {
|
||||
topOffset: Number(block?.props?.topOffset || block?.props?.top_offset || 0) || 0,
|
||||
maxShowCount: Number(block?.props?.maxShowCount || block?.props?.max_show_count || 20) || 20,
|
||||
showTitle: block?.props?.showTitle !== false,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (type === 'image') {
|
||||
const imageSnapshot = block?.props?.tiptapImage;
|
||||
if (imageSnapshot && typeof imageSnapshot === 'object' && imageSnapshot.type === 'image') {
|
||||
return imageSnapshot;
|
||||
}
|
||||
const attrs = {
|
||||
src: String(block?.props?.src || block?.src || ''),
|
||||
alt: block?.props?.alt || block?.alt || null,
|
||||
title: block?.props?.title || block?.title || null,
|
||||
};
|
||||
return attrs.src ? { type: 'image', attrs } : null;
|
||||
}
|
||||
return { type: 'paragraph', attrs: withTextAlign(), content };
|
||||
};
|
||||
|
||||
const textToTiptapDocument = (text) => ({
|
||||
@@ -371,9 +438,20 @@ pub(crate) fn render_editor_island_adapter_script() -> &'static str {
|
||||
|
||||
const pageBody = aggregate.body || {};
|
||||
const permissions = aggregate.head?.permissions || {};
|
||||
const conflictDetectionKey = typeof pageBody.conflictDetectionKey === 'string'
|
||||
? pageBody.conflictDetectionKey
|
||||
: typeof pageBody.conflict_detection_key === 'string'
|
||||
? pageBody.conflict_detection_key
|
||||
: null;
|
||||
const revisionFromConflictKey = (value) => {
|
||||
const match = String(value || '').match(/:(\d+)$/);
|
||||
return match ? Number(match[1]) : null;
|
||||
};
|
||||
const pageBodyRevision = Number.isInteger(pageBody.revision) ? pageBody.revision : null;
|
||||
const keyRevision = revisionFromConflictKey(conflictDetectionKey);
|
||||
const editorMeta = {
|
||||
revision: Number.isInteger(pageBody.revision) ? pageBody.revision : null,
|
||||
conflictDetectionKey: typeof pageBody.conflictDetectionKey === 'string' ? pageBody.conflictDetectionKey : null,
|
||||
revision: pageBodyRevision && pageBodyRevision > 0 ? pageBodyRevision : keyRevision,
|
||||
conflictDetectionKey,
|
||||
};
|
||||
const mountOptions = {
|
||||
documentId: bootstrap.documentId,
|
||||
@@ -389,8 +467,26 @@ pub(crate) fn render_editor_island_adapter_script() -> &'static str {
|
||||
|
||||
let saveTimer = 0;
|
||||
let lastSavedSerialized = '';
|
||||
const normalizeBridgeValue = (value) => {
|
||||
if (value instanceof Map) {
|
||||
const out = {};
|
||||
for (const [key, item] of value.entries()) {
|
||||
out[key] = normalizeBridgeValue(item);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(normalizeBridgeValue);
|
||||
}
|
||||
if (value && typeof value === 'object') {
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).map(([key, item]) => [key, normalizeBridgeValue(item)]),
|
||||
);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
const normalizeEnvelopePayload = (event) => {
|
||||
const detail = event?.detail;
|
||||
const detail = normalizeBridgeValue(event?.detail);
|
||||
if (!detail || typeof detail !== 'object') return null;
|
||||
const payload = detail.payload && typeof detail.payload === 'object' ? detail.payload : detail;
|
||||
return payload && typeof payload === 'object' ? payload : null;
|
||||
@@ -512,6 +608,24 @@ fn runtime_asset_content_type(asset_path: &str) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn editor_image_placeholder_asset() -> Response {
|
||||
const SVG: &str = r##"<svg xmlns="http://www.w3.org/2000/svg" width="640" height="360" viewBox="0 0 640 360" role="img" aria-label="E24 image placeholder">
|
||||
<rect width="640" height="360" rx="18" fill="#f3f4f6"/>
|
||||
<rect x="42" y="42" width="556" height="276" rx="14" fill="#ffffff" stroke="#d1d5db" stroke-width="2"/>
|
||||
<circle cx="168" cy="132" r="34" fill="#93c5fd"/>
|
||||
<path d="M98 278 246 174 340 242 410 192 542 278Z" fill="#86efac"/>
|
||||
<path d="M98 278 246 174 340 242 410 192 542 278" fill="none" stroke="#16a34a" stroke-width="8" stroke-linejoin="round"/>
|
||||
<text x="320" y="322" text-anchor="middle" font-family="Arial, sans-serif" font-size="22" fill="#374151">E24 Image</text>
|
||||
</svg>"##;
|
||||
Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header(header::CONTENT_TYPE, "image/svg+xml; charset=utf-8")
|
||||
.header(header::CACHE_CONTROL, "no-store")
|
||||
.header(HEADER_MNOTE_WEB_OWNER, "mnote-web")
|
||||
.body(Body::from(SVG))
|
||||
.unwrap_or_else(|_| Response::new(Body::empty()))
|
||||
}
|
||||
|
||||
pub async fn leptos_tiptap_manifest() -> Response {
|
||||
let manifest = json!({
|
||||
"entryAssetPath": "mnote-leptos-tiptap-spike-island.js",
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ export interface InitOutput {
|
||||
readonly intounderlyingsource_cancel: (a: number) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h36e788bd1cd1f0f7: (a: number, b: number, c: any) => [number, number];
|
||||
readonly wasm_bindgen__convert__closures_____invoke__hb0ba6117a7ec12e8: (a: number, b: number, c: any, d: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h1ea2b89742286ce6: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__hdfdf165eabd6279b: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h2593b18d2d6f8a75: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h03deb55668e1377f: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h837fba73fce77300: (a: number, b: number, c: any) => void;
|
||||
|
||||
+50
-14
@@ -21,15 +21,22 @@ import { register_ordered_list } from './snippets/leptos-tiptap-c355e6ec24c3df4c
|
||||
import { register_paragraph } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_paragraph.js';
|
||||
import { register_placeholder } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_placeholder.js';
|
||||
import { register_strike } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_strike.js';
|
||||
import { register_table } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_table.js';
|
||||
import { register_table_cell } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_table_cell.js';
|
||||
import { register_table_header } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_table_header.js';
|
||||
import { register_table_row } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_table_row.js';
|
||||
import { register_task_item } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_task_item.js';
|
||||
import { register_task_list } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_task_list.js';
|
||||
import { register_text } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_text.js';
|
||||
import { register_text_align } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_text_align.js';
|
||||
import { register_text_style } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_text_style.js';
|
||||
import { register_toc_node } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_toc_node.js';
|
||||
import { register_underline } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_underline.js';
|
||||
import { register_youtube } from './snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/tiptap_youtube.js';
|
||||
import * as import1 from "./snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/bridge_runtime.js"
|
||||
import * as import2 from "./snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/bridge_runtime.js"
|
||||
import * as import1 from "./snippets/mnote-leptos-tiptap-spike-fdb5779a1690afd2/inline0.js"
|
||||
import * as import2 from "./snippets/mnote-leptos-tiptap-spike-fdb5779a1690afd2/inline0.js"
|
||||
import * as import3 from "./snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/bridge_runtime.js"
|
||||
import * as import4 from "./snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/bridge_runtime.js"
|
||||
|
||||
|
||||
export class IntoUnderlyingByteSource {
|
||||
@@ -491,6 +498,10 @@ function __wbg_get_imports() {
|
||||
const ret = arg0.getBoundingClientRect();
|
||||
return ret;
|
||||
},
|
||||
__wbg_getElementsByTagName_0307fb99c94d7de4: function(arg0, arg1, arg2) {
|
||||
const ret = arg0.getElementsByTagName(getStringFromWasm0(arg1, arg2));
|
||||
return ret;
|
||||
},
|
||||
__wbg_getItem_7fe1351b9ea3b2f3: function() { return handleError(function (arg0, arg1, arg2, arg3) {
|
||||
const ret = arg1.getItem(getStringFromWasm0(arg2, arg3));
|
||||
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
@@ -798,6 +809,10 @@ function __wbg_get_imports() {
|
||||
__wbg_prototypesetcall_a6b02eb00b0f4ce2: function(arg0, arg1, arg2) {
|
||||
Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
|
||||
},
|
||||
__wbg_querySelector_12b6c7cdf26a3483: function() { return handleError(function (arg0, arg1, arg2) {
|
||||
const ret = arg0.querySelector(getStringFromWasm0(arg1, arg2));
|
||||
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
||||
}, arguments); },
|
||||
__wbg_querySelector_8d395ebd237ebd46: function() { return handleError(function (arg0, arg1, arg2) {
|
||||
const ret = arg0.querySelector(getStringFromWasm0(arg1, arg2));
|
||||
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
||||
@@ -872,6 +887,18 @@ function __wbg_get_imports() {
|
||||
__wbg_register_strike_cd23a4801fbee3aa: function() { return handleError(function () {
|
||||
register_strike();
|
||||
}, arguments); },
|
||||
__wbg_register_table_590493ea4d3d2ed0: function() { return handleError(function () {
|
||||
register_table();
|
||||
}, arguments); },
|
||||
__wbg_register_table_cell_5c14e6780bc3c5d8: function() { return handleError(function () {
|
||||
register_table_cell();
|
||||
}, arguments); },
|
||||
__wbg_register_table_header_7194a6f98b99eb87: function() { return handleError(function () {
|
||||
register_table_header();
|
||||
}, arguments); },
|
||||
__wbg_register_table_row_d051d596b6164ab0: function() { return handleError(function () {
|
||||
register_table_row();
|
||||
}, arguments); },
|
||||
__wbg_register_task_item_f3bd8792f78774ac: function() { return handleError(function () {
|
||||
register_task_item();
|
||||
}, arguments); },
|
||||
@@ -887,6 +914,9 @@ function __wbg_get_imports() {
|
||||
__wbg_register_text_style_61ece26a92563bc1: function() { return handleError(function () {
|
||||
register_text_style();
|
||||
}, arguments); },
|
||||
__wbg_register_toc_node_f7f31f30d7a88bdc: function() { return handleError(function () {
|
||||
register_toc_node();
|
||||
}, arguments); },
|
||||
__wbg_register_underline_f8cd359f982028f4: function() { return handleError(function () {
|
||||
register_underline();
|
||||
}, arguments); },
|
||||
@@ -1013,6 +1043,10 @@ function __wbg_get_imports() {
|
||||
__wbg_set_scrollTop_e931da7f2ad87c86: function(arg0, arg1) {
|
||||
arg0.scrollTop = arg1;
|
||||
},
|
||||
__wbg_shiftKey_e483c13c966878f6: function(arg0) {
|
||||
const ret = arg0.shiftKey;
|
||||
return ret;
|
||||
},
|
||||
__wbg_stack_3b0d974bbf31e44f: function(arg0, arg1) {
|
||||
const ret = arg1.stack;
|
||||
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
@@ -1100,37 +1134,37 @@ function __wbg_get_imports() {
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1120, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
|
||||
const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h1ea2b89742286ce6);
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1456, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
|
||||
const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hdfdf165eabd6279b);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1382, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1686, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2593b18d2d6f8a75);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000003: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1473, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1777, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h36e788bd1cd1f0f7);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000004: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1307, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1611, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h03deb55668e1377f);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000005: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1384, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1688, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h837fba73fce77300);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000006: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1320, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1624, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`.
|
||||
const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hd17f30facfdd737f);
|
||||
return ret;
|
||||
},
|
||||
__wbindgen_cast_0000000000000007: function(arg0, arg1) {
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1383, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1687, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hf726e22cfd1ee0a9);
|
||||
return ret;
|
||||
},
|
||||
@@ -1167,8 +1201,10 @@ function __wbg_get_imports() {
|
||||
return {
|
||||
__proto__: null,
|
||||
"./mnote-leptos-tiptap-spike-island_bg.js": import0,
|
||||
"./snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/bridge_runtime.js": import1,
|
||||
"./snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/bridge_runtime.js": import2,
|
||||
"./snippets/mnote-leptos-tiptap-spike-fdb5779a1690afd2/inline0.js": import1,
|
||||
"./snippets/mnote-leptos-tiptap-spike-fdb5779a1690afd2/inline0.js": import2,
|
||||
"./snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/bridge_runtime.js": import3,
|
||||
"./snippets/leptos-tiptap-c355e6ec24c3df4c/src/js/generated/bridge_runtime.js": import4,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1185,8 +1221,8 @@ function wasm_bindgen__convert__closures_____invoke__h60e57afd955e8441(arg0, arg
|
||||
return ret !== 0;
|
||||
}
|
||||
|
||||
function wasm_bindgen__convert__closures_____invoke__h1ea2b89742286ce6(arg0, arg1, arg2) {
|
||||
wasm.wasm_bindgen__convert__closures_____invoke__h1ea2b89742286ce6(arg0, arg1, arg2);
|
||||
function wasm_bindgen__convert__closures_____invoke__hdfdf165eabd6279b(arg0, arg1, arg2) {
|
||||
wasm.wasm_bindgen__convert__closures_____invoke__hdfdf165eabd6279b(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
function wasm_bindgen__convert__closures_____invoke__h2593b18d2d6f8a75(arg0, arg1, arg2) {
|
||||
|
||||
BIN
Binary file not shown.
Vendored
+1
-1
@@ -18,7 +18,7 @@ export const intounderlyingsource_pull: (a: number, b: any) => any;
|
||||
export const intounderlyingsource_cancel: (a: number) => void;
|
||||
export const wasm_bindgen__convert__closures_____invoke__h36e788bd1cd1f0f7: (a: number, b: number, c: any) => [number, number];
|
||||
export const wasm_bindgen__convert__closures_____invoke__hb0ba6117a7ec12e8: (a: number, b: number, c: any, d: any) => void;
|
||||
export const wasm_bindgen__convert__closures_____invoke__h1ea2b89742286ce6: (a: number, b: number, c: any) => void;
|
||||
export const wasm_bindgen__convert__closures_____invoke__hdfdf165eabd6279b: (a: number, b: number, c: any) => void;
|
||||
export const wasm_bindgen__convert__closures_____invoke__h2593b18d2d6f8a75: (a: number, b: number, c: any) => void;
|
||||
export const wasm_bindgen__convert__closures_____invoke__h03deb55668e1377f: (a: number, b: number, c: any) => void;
|
||||
export const wasm_bindgen__convert__closures_____invoke__h837fba73fce77300: (a: number, b: number, c: any) => void;
|
||||
|
||||
+14
-14
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var x=t.CommandManager,m=t.Editor,k=t.Extension,b=t.InputRule,y=t.Mark,r=t.Node,h=t.NodePos,E=t.NodeView,R=t.PasteRule,f=t.Tracker,P=t.callOrReturn,C=t.canInsertNode,T=t.combineTransactionSteps,A=t.createChainableState,S=t.createDocument,B=t.createNodeFromContent,N=t.createStyleTag,O=t.defaultBlockAt,w=t.deleteProps,v=t.elementFromString,M=t.escapeForRegEx,I=t.extensions,q=t.findChildren,F=t.findChildrenInRange,D=t.findDuplicates,j=t.findParentNode,L=t.findParentNodeClosestToPos,K=t.fromString,H=t.generateHTML,G=t.generateJSON,z=t.generateText,J=t.getAttributes,U=t.getAttributesFromExtensions,V=t.getChangedRanges,Y=t.getDebugJSON,W=t.getExtensionField,$=t.getHTMLFromFragment,Q=t.getMarkAttributes,X=t.getMarkRange,Z=t.getMarkType,tt=t.getMarksBetween,et=t.getNodeAtPosition,nt=t.getNodeAttributes,ot=t.getNodeType,it=t.getRenderedAttributes,rt=t.getSchema,st=t.getSchemaByResolvedExtensions,lt=t.getSchemaTypeByName,at=t.getSchemaTypeNameByName,dt=t.getSplittedAttributes,pt=t.getText,ct=t.getTextBetween,ut=t.getTextContentFromNodes,gt=t.getTextSerializersFromSchema,_t=t.injectExtensionAttributesToParseRule,xt=t.inputRulesPlugin,mt=t.isActive,kt=t.isAtEndOfNode,bt=t.isAtStartOfNode,yt=t.isEmptyObject,ht=t.isExtensionRulesEnabled,Et=t.isFunction,Rt=t.isList,ft=t.isMacOS,Pt=t.isMarkActive,Ct=t.isNodeActive,Tt=t.isNodeEmpty,At=t.isNodeSelection,St=t.isNumber,Bt=t.isPlainObject,Nt=t.isRegExp,Ot=t.isSafari,wt=t.isString,vt=t.isTextSelection,Mt=t.isiOS,It=t.markInputRule,qt=t.markPasteRule,s=t.mergeAttributes,Ft=t.mergeDeep,Dt=t.minMax,jt=t.nodeInputRule,Lt=t.nodePasteRule,Kt=t.objectIncludes,Ht=t.pasteRulesPlugin,Gt=t.posToDOMRect,zt=t.removeDuplicates,Jt=t.resolveFocusPosition,Ut=t.rewriteUnknownContent,Vt=t.selectionToInsertionEnd,Yt=t.splitExtensions,Wt=t.textInputRule,$t=t.textPasteRule,Qt=t.textblockTypeInputRule,l=t.wrappingInputRule;var u=/^\s*>\s$/,a=r.create({name:"blockquote",addOptions(){return{HTMLAttributes:{}}},content:"block+",group:"block",defining:!0,parseHTML(){return[{tag:"blockquote"}]},renderHTML({HTMLAttributes:e}){return["blockquote",s(this.options.HTMLAttributes,e),0]},addCommands(){return{setBlockquote:()=>({commands:e})=>e.wrapIn(this.name),toggleBlockquote:()=>({commands:e})=>e.toggleWrap(this.name),unsetBlockquote:()=>({commands:e})=>e.lift(this.name)}},addKeyboardShortcuts(){return{"Mod-Shift-b":()=>this.editor.commands.toggleBlockquote()}},addInputRules(){return[l({find:u,type:this.type})]}});var d="__LEPTOS_TIPTAP_BRIDGE__";function g(){let e=globalThis,o=e[d];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[d]=i,i}function p(){return g()}function c(e){p().registerExtension(e)}var _={name:"blockquote",create:()=>a,commands:{set_blockquote:e=>e.chain().focus().setBlockquote().run(),toggle_blockquote:e=>e.chain().focus().toggleBlockquote().run(),unset_blockquote:e=>e.chain().focus().unsetBlockquote().run()},selection_keys:["blockquote"],selection_state:e=>({blockquote:e.isActive("blockquote")})};function se(){c(_)}export{se as register_blockquote};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var x=e.CommandManager,m=e.Editor,k=e.Extension,b=e.InputRule,y=e.Mark,r=e.Node,h=e.NodePos,f=e.NodeView,E=e.PasteRule,R=e.Tracker,P=e.callOrReturn,C=e.canInsertNode,T=e.combineTransactionSteps,A=e.createChainableState,S=e.createDocument,B=e.createNodeFromContent,w=e.createStyleTag,N=e.defaultBlockAt,O=e.deleteProps,v=e.elementFromString,M=e.escapeForRegEx,I=e.extensions,q=e.findChildren,F=e.findChildrenInRange,D=e.findDuplicates,j=e.findParentNode,L=e.findParentNodeClosestToPos,K=e.fromString,H=e.generateHTML,G=e.generateJSON,z=e.generateText,J=e.getAttributes,U=e.getAttributesFromExtensions,V=e.getChangedRanges,Y=e.getDebugJSON,W=e.getExtensionField,$=e.getHTMLFromFragment,Q=e.getMarkAttributes,X=e.getMarkRange,Z=e.getMarkType,ee=e.getMarksBetween,te=e.getNodeAtPosition,ne=e.getNodeAttributes,oe=e.getNodeType,ie=e.getRenderedAttributes,re=e.getSchema,se=e.getSchemaByResolvedExtensions,le=e.getSchemaTypeByName,ae=e.getSchemaTypeNameByName,de=e.getSplittedAttributes,pe=e.getText,ce=e.getTextBetween,ue=e.getTextContentFromNodes,ge=e.getTextSerializersFromSchema,_e=e.injectExtensionAttributesToParseRule,xe=e.inputRulesPlugin,me=e.isActive,ke=e.isAtEndOfNode,be=e.isAtStartOfNode,ye=e.isEmptyObject,he=e.isExtensionRulesEnabled,fe=e.isFunction,Ee=e.isList,Re=e.isMacOS,Pe=e.isMarkActive,Ce=e.isNodeActive,Te=e.isNodeEmpty,Ae=e.isNodeSelection,Se=e.isNumber,Be=e.isPlainObject,we=e.isRegExp,Ne=e.isSafari,Oe=e.isString,ve=e.isTextSelection,Me=e.isiOS,Ie=e.markInputRule,qe=e.markPasteRule,s=e.mergeAttributes,Fe=e.mergeDeep,De=e.minMax,je=e.nodeInputRule,Le=e.nodePasteRule,Ke=e.objectIncludes,He=e.pasteRulesPlugin,Ge=e.posToDOMRect,ze=e.removeDuplicates,Je=e.resolveFocusPosition,Ue=e.rewriteUnknownContent,Ve=e.selectionToInsertionEnd,Ye=e.splitExtensions,We=e.textInputRule,$e=e.textPasteRule,Qe=e.textblockTypeInputRule,l=e.wrappingInputRule;var u=/^\s*>\s$/,a=r.create({name:"blockquote",addOptions(){return{HTMLAttributes:{}}},content:"block+",group:"block",defining:!0,parseHTML(){return[{tag:"blockquote"}]},renderHTML({HTMLAttributes:t}){return["blockquote",s(this.options.HTMLAttributes,t),0]},addCommands(){return{setBlockquote:()=>({commands:t})=>t.wrapIn(this.name),toggleBlockquote:()=>({commands:t})=>t.toggleWrap(this.name),unsetBlockquote:()=>({commands:t})=>t.lift(this.name)}},addKeyboardShortcuts(){return{"Mod-Shift-b":()=>this.editor.commands.toggleBlockquote()}},addInputRules(){return[l({find:u,type:this.type})]}});var d="__LEPTOS_TIPTAP_BRIDGE__";function g(){let t=globalThis,o=t[d];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[d]=i,i}function p(){return g()}function c(t){p().registerExtension(t)}var _={name:"blockquote",create:()=>a,commands:{set_blockquote:t=>t.chain().focus().setBlockquote().run(),toggle_blockquote:t=>t.chain().focus().toggleBlockquote().run(),unset_blockquote:t=>t.chain().focus().unsetBlockquote().run()},selection_keys:["blockquote"],selection_state:t=>({blockquote:t.isActive("blockquote")})};function st(){c(_)}export{st as register_blockquote};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var y=t.CommandManager,h=t.Editor,R=t.Extension,f=t.InputRule,l=t.Mark,E=t.Node,P=t.NodePos,A=t.NodeView,C=t.PasteRule,T=t.Tracker,S=t.callOrReturn,B=t.canInsertNode,N=t.combineTransactionSteps,O=t.createChainableState,w=t.createDocument,M=t.createNodeFromContent,v=t.createStyleTag,I=t.defaultBlockAt,F=t.deleteProps,D=t.elementFromString,j=t.escapeForRegEx,L=t.extensions,K=t.findChildren,H=t.findChildrenInRange,q=t.findDuplicates,G=t.findParentNode,z=t.findParentNodeClosestToPos,J=t.fromString,$=t.generateHTML,U=t.generateJSON,V=t.generateText,Y=t.getAttributes,W=t.getAttributesFromExtensions,Q=t.getChangedRanges,X=t.getDebugJSON,Z=t.getExtensionField,tt=t.getHTMLFromFragment,et=t.getMarkAttributes,nt=t.getMarkRange,ot=t.getMarkType,rt=t.getMarksBetween,it=t.getNodeAtPosition,st=t.getNodeAttributes,lt=t.getNodeType,at=t.getRenderedAttributes,dt=t.getSchema,pt=t.getSchemaByResolvedExtensions,ct=t.getSchemaTypeByName,ut=t.getSchemaTypeNameByName,gt=t.getSplittedAttributes,_t=t.getText,xt=t.getTextBetween,mt=t.getTextContentFromNodes,kt=t.getTextSerializersFromSchema,bt=t.injectExtensionAttributesToParseRule,yt=t.inputRulesPlugin,ht=t.isActive,Rt=t.isAtEndOfNode,ft=t.isAtStartOfNode,Et=t.isEmptyObject,Pt=t.isExtensionRulesEnabled,At=t.isFunction,Ct=t.isList,Tt=t.isMacOS,St=t.isMarkActive,Bt=t.isNodeActive,Nt=t.isNodeEmpty,Ot=t.isNodeSelection,wt=t.isNumber,Mt=t.isPlainObject,vt=t.isRegExp,It=t.isSafari,Ft=t.isString,Dt=t.isTextSelection,jt=t.isiOS,o=t.markInputRule,r=t.markPasteRule,a=t.mergeAttributes,Lt=t.mergeDeep,Kt=t.minMax,Ht=t.nodeInputRule,qt=t.nodePasteRule,Gt=t.objectIncludes,zt=t.pasteRulesPlugin,Jt=t.posToDOMRect,$t=t.removeDuplicates,Ut=t.resolveFocusPosition,Vt=t.rewriteUnknownContent,Yt=t.selectionToInsertionEnd,Wt=t.splitExtensions,Qt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,te=t.wrappingInputRule;var g=/(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))$/,_=/(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))/g,x=/(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))$/,m=/(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))/g,d=l.create({name:"bold",addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"strong"},{tag:"b",getAttrs:e=>e.style.fontWeight!=="normal"&&null},{style:"font-weight=400",clearMark:e=>e.type.name===this.name},{style:"font-weight",getAttrs:e=>/^(bold(er)?|[5-9]\d{2,})$/.test(e)&&null}]},renderHTML({HTMLAttributes:e}){return["strong",a(this.options.HTMLAttributes,e),0]},addCommands(){return{setBold:()=>({commands:e})=>e.setMark(this.name),toggleBold:()=>({commands:e})=>e.toggleMark(this.name),unsetBold:()=>({commands:e})=>e.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-b":()=>this.editor.commands.toggleBold(),"Mod-B":()=>this.editor.commands.toggleBold()}},addInputRules(){return[o({find:g,type:this.type}),o({find:x,type:this.type})]},addPasteRules(){return[r({find:_,type:this.type}),r({find:m,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function k(){let e=globalThis,i=e[p];if(i!=null)return i;let s={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[p]=s,s}function c(){return k()}function u(e){c().registerExtension(e)}var b={name:"bold",create:()=>d,commands:{set_bold:e=>e.chain().focus().setBold().run(),toggle_bold:e=>e.chain().focus().toggleBold().run(),unset_bold:e=>e.chain().focus().unsetBold().run()},selection_keys:["bold"],selection_state:e=>({bold:e.isActive("bold")})};function de(){u(b)}export{de as register_bold};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var y=t.CommandManager,h=t.Editor,f=t.Extension,R=t.InputRule,l=t.Mark,E=t.Node,P=t.NodePos,A=t.NodeView,C=t.PasteRule,T=t.Tracker,S=t.callOrReturn,B=t.canInsertNode,w=t.combineTransactionSteps,N=t.createChainableState,O=t.createDocument,M=t.createNodeFromContent,v=t.createStyleTag,I=t.defaultBlockAt,F=t.deleteProps,D=t.elementFromString,j=t.escapeForRegEx,L=t.extensions,K=t.findChildren,H=t.findChildrenInRange,q=t.findDuplicates,G=t.findParentNode,z=t.findParentNodeClosestToPos,J=t.fromString,$=t.generateHTML,U=t.generateJSON,V=t.generateText,Y=t.getAttributes,W=t.getAttributesFromExtensions,Q=t.getChangedRanges,X=t.getDebugJSON,Z=t.getExtensionField,tt=t.getHTMLFromFragment,et=t.getMarkAttributes,nt=t.getMarkRange,ot=t.getMarkType,rt=t.getMarksBetween,it=t.getNodeAtPosition,st=t.getNodeAttributes,lt=t.getNodeType,at=t.getRenderedAttributes,dt=t.getSchema,pt=t.getSchemaByResolvedExtensions,ut=t.getSchemaTypeByName,ct=t.getSchemaTypeNameByName,gt=t.getSplittedAttributes,_t=t.getText,mt=t.getTextBetween,xt=t.getTextContentFromNodes,kt=t.getTextSerializersFromSchema,bt=t.injectExtensionAttributesToParseRule,yt=t.inputRulesPlugin,ht=t.isActive,ft=t.isAtEndOfNode,Rt=t.isAtStartOfNode,Et=t.isEmptyObject,Pt=t.isExtensionRulesEnabled,At=t.isFunction,Ct=t.isList,Tt=t.isMacOS,St=t.isMarkActive,Bt=t.isNodeActive,wt=t.isNodeEmpty,Nt=t.isNodeSelection,Ot=t.isNumber,Mt=t.isPlainObject,vt=t.isRegExp,It=t.isSafari,Ft=t.isString,Dt=t.isTextSelection,jt=t.isiOS,o=t.markInputRule,r=t.markPasteRule,a=t.mergeAttributes,Lt=t.mergeDeep,Kt=t.minMax,Ht=t.nodeInputRule,qt=t.nodePasteRule,Gt=t.objectIncludes,zt=t.pasteRulesPlugin,Jt=t.posToDOMRect,$t=t.removeDuplicates,Ut=t.resolveFocusPosition,Vt=t.rewriteUnknownContent,Yt=t.selectionToInsertionEnd,Wt=t.splitExtensions,Qt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,te=t.wrappingInputRule;var g=/(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))$/,_=/(?:^|\s)(\*\*(?!\s+\*\*)((?:[^*]+))\*\*(?!\s+\*\*))/g,m=/(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))$/,x=/(?:^|\s)(__(?!\s+__)((?:[^_]+))__(?!\s+__))/g,d=l.create({name:"bold",addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"strong"},{tag:"b",getAttrs:e=>e.style.fontWeight!=="normal"&&null},{style:"font-weight=400",clearMark:e=>e.type.name===this.name},{style:"font-weight",getAttrs:e=>/^(bold(er)?|[5-9]\d{2,})$/.test(e)&&null}]},renderHTML({HTMLAttributes:e}){return["strong",a(this.options.HTMLAttributes,e),0]},addCommands(){return{setBold:()=>({commands:e})=>e.setMark(this.name),toggleBold:()=>({commands:e})=>e.toggleMark(this.name),unsetBold:()=>({commands:e})=>e.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-b":()=>this.editor.commands.toggleBold(),"Mod-B":()=>this.editor.commands.toggleBold()}},addInputRules(){return[o({find:g,type:this.type}),o({find:m,type:this.type})]},addPasteRules(){return[r({find:_,type:this.type}),r({find:x,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function k(){let e=globalThis,i=e[p];if(i!=null)return i;let s={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[p]=s,s}function u(){return k()}function c(e){u().registerExtension(e)}var b={name:"bold",create:()=>d,commands:{set_bold:e=>e.chain().focus().setBold().run(),toggle_bold:e=>e.chain().focus().toggleBold().run(),unset_bold:e=>e.chain().focus().unsetBold().run()},selection_keys:["bold"],selection_state:e=>({bold:e.isActive("bold")})};function de(){c(b)}export{de as register_bold};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var o=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(o==null||o.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=o.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,y=t.Extension,h=t.InputRule,E=t.Mark,s=t.Node,R=t.NodePos,f=t.NodeView,A=t.PasteRule,T=t.Tracker,P=t.callOrReturn,C=t.canInsertNode,S=t.combineTransactionSteps,N=t.createChainableState,B=t.createDocument,O=t.createNodeFromContent,w=t.createStyleTag,M=t.defaultBlockAt,v=t.deleteProps,I=t.elementFromString,F=t.escapeForRegEx,D=t.extensions,L=t.findChildren,j=t.findChildrenInRange,K=t.findDuplicates,H=t.findParentNode,q=t.findParentNodeClosestToPos,G=t.fromString,z=t.generateHTML,J=t.generateJSON,U=t.generateText,V=t.getAttributes,Y=t.getAttributesFromExtensions,$=t.getChangedRanges,Q=t.getDebugJSON,W=t.getExtensionField,X=t.getHTMLFromFragment,Z=t.getMarkAttributes,tt=t.getMarkRange,et=t.getMarkType,nt=t.getMarksBetween,ot=t.getNodeAtPosition,it=t.getNodeAttributes,rt=t.getNodeType,st=t.getRenderedAttributes,lt=t.getSchema,at=t.getSchemaByResolvedExtensions,pt=t.getSchemaTypeByName,dt=t.getSchemaTypeNameByName,ut=t.getSplittedAttributes,ct=t.getText,gt=t.getTextBetween,_t=t.getTextContentFromNodes,xt=t.getTextSerializersFromSchema,mt=t.injectExtensionAttributesToParseRule,kt=t.inputRulesPlugin,bt=t.isActive,yt=t.isAtEndOfNode,ht=t.isAtStartOfNode,Et=t.isEmptyObject,Rt=t.isExtensionRulesEnabled,ft=t.isFunction,At=t.isList,Tt=t.isMacOS,Pt=t.isMarkActive,Ct=t.isNodeActive,St=t.isNodeEmpty,Nt=t.isNodeSelection,Bt=t.isNumber,Ot=t.isPlainObject,wt=t.isRegExp,Mt=t.isSafari,vt=t.isString,It=t.isTextSelection,Ft=t.isiOS,Dt=t.markInputRule,Lt=t.markPasteRule,l=t.mergeAttributes,jt=t.mergeDeep,Kt=t.minMax,Ht=t.nodeInputRule,qt=t.nodePasteRule,Gt=t.objectIncludes,zt=t.pasteRulesPlugin,Jt=t.posToDOMRect,Ut=t.removeDuplicates,Vt=t.resolveFocusPosition,Yt=t.rewriteUnknownContent,$t=t.selectionToInsertionEnd,Qt=t.splitExtensions,Wt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,i=t.wrappingInputRule;var _="listItem",a="textStyle",p=/^\s*([-+*])\s$/,d=s.create({name:"bulletList",addOptions(){return{itemTypeName:"listItem",HTMLAttributes:{},keepMarks:!1,keepAttributes:!1}},group:"block list",content(){return`${this.options.itemTypeName}+`},parseHTML(){return[{tag:"ul"}]},renderHTML({HTMLAttributes:e}){return["ul",l(this.options.HTMLAttributes,e),0]},addCommands(){return{toggleBulletList:()=>({commands:e,chain:n})=>this.options.keepAttributes?n().toggleList(this.name,this.options.itemTypeName,this.options.keepMarks).updateAttributes(_,this.editor.getAttributes(a)).run():e.toggleList(this.name,this.options.itemTypeName,this.options.keepMarks)}},addKeyboardShortcuts(){return{"Mod-Shift-8":()=>this.editor.commands.toggleBulletList()}},addInputRules(){let e=i({find:p,type:this.type});return(this.options.keepMarks||this.options.keepAttributes)&&(e=i({find:p,type:this.type,keepMarks:this.options.keepMarks,keepAttributes:this.options.keepAttributes,getAttributes:()=>this.editor.getAttributes(a),editor:this.editor})),[e]}});var u="__LEPTOS_TIPTAP_BRIDGE__";function x(){let e=globalThis,n=e[u];if(n!=null)return n;let r={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[u]=r,r}function c(){return x()}function g(e){c().registerExtension(e)}var m={name:"bullet_list",create:()=>d,commands:{toggle_bullet_list:e=>e.chain().focus().toggleBulletList().run()},selection_keys:["bullet_list"],selection_state:e=>({bullet_list:e.isActive("bulletList")})};function ae(){g(m)}export{ae as register_bullet_list};
|
||||
var o=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(o==null||o.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=o.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,y=t.Extension,h=t.InputRule,f=t.Mark,s=t.Node,E=t.NodePos,R=t.NodeView,A=t.PasteRule,T=t.Tracker,P=t.callOrReturn,C=t.canInsertNode,S=t.combineTransactionSteps,N=t.createChainableState,w=t.createDocument,B=t.createNodeFromContent,O=t.createStyleTag,M=t.defaultBlockAt,v=t.deleteProps,I=t.elementFromString,F=t.escapeForRegEx,D=t.extensions,L=t.findChildren,j=t.findChildrenInRange,K=t.findDuplicates,H=t.findParentNode,q=t.findParentNodeClosestToPos,G=t.fromString,z=t.generateHTML,J=t.generateJSON,U=t.generateText,V=t.getAttributes,Y=t.getAttributesFromExtensions,$=t.getChangedRanges,Q=t.getDebugJSON,W=t.getExtensionField,X=t.getHTMLFromFragment,Z=t.getMarkAttributes,tt=t.getMarkRange,et=t.getMarkType,nt=t.getMarksBetween,ot=t.getNodeAtPosition,it=t.getNodeAttributes,rt=t.getNodeType,st=t.getRenderedAttributes,lt=t.getSchema,at=t.getSchemaByResolvedExtensions,dt=t.getSchemaTypeByName,pt=t.getSchemaTypeNameByName,ut=t.getSplittedAttributes,ct=t.getText,gt=t.getTextBetween,_t=t.getTextContentFromNodes,mt=t.getTextSerializersFromSchema,xt=t.injectExtensionAttributesToParseRule,kt=t.inputRulesPlugin,bt=t.isActive,yt=t.isAtEndOfNode,ht=t.isAtStartOfNode,ft=t.isEmptyObject,Et=t.isExtensionRulesEnabled,Rt=t.isFunction,At=t.isList,Tt=t.isMacOS,Pt=t.isMarkActive,Ct=t.isNodeActive,St=t.isNodeEmpty,Nt=t.isNodeSelection,wt=t.isNumber,Bt=t.isPlainObject,Ot=t.isRegExp,Mt=t.isSafari,vt=t.isString,It=t.isTextSelection,Ft=t.isiOS,Dt=t.markInputRule,Lt=t.markPasteRule,l=t.mergeAttributes,jt=t.mergeDeep,Kt=t.minMax,Ht=t.nodeInputRule,qt=t.nodePasteRule,Gt=t.objectIncludes,zt=t.pasteRulesPlugin,Jt=t.posToDOMRect,Ut=t.removeDuplicates,Vt=t.resolveFocusPosition,Yt=t.rewriteUnknownContent,$t=t.selectionToInsertionEnd,Qt=t.splitExtensions,Wt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,i=t.wrappingInputRule;var _="listItem",a="textStyle",d=/^\s*([-+*])\s$/,p=s.create({name:"bulletList",addOptions(){return{itemTypeName:"listItem",HTMLAttributes:{},keepMarks:!1,keepAttributes:!1}},group:"block list",content(){return`${this.options.itemTypeName}+`},parseHTML(){return[{tag:"ul"}]},renderHTML({HTMLAttributes:e}){return["ul",l(this.options.HTMLAttributes,e),0]},addCommands(){return{toggleBulletList:()=>({commands:e,chain:n})=>this.options.keepAttributes?n().toggleList(this.name,this.options.itemTypeName,this.options.keepMarks).updateAttributes(_,this.editor.getAttributes(a)).run():e.toggleList(this.name,this.options.itemTypeName,this.options.keepMarks)}},addKeyboardShortcuts(){return{"Mod-Shift-8":()=>this.editor.commands.toggleBulletList()}},addInputRules(){let e=i({find:d,type:this.type});return(this.options.keepMarks||this.options.keepAttributes)&&(e=i({find:d,type:this.type,keepMarks:this.options.keepMarks,keepAttributes:this.options.keepAttributes,getAttributes:()=>this.editor.getAttributes(a),editor:this.editor})),[e]}});var u="__LEPTOS_TIPTAP_BRIDGE__";function m(){let e=globalThis,n=e[u];if(n!=null)return n;let r={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[u]=r,r}function c(){return m()}function g(e){c().registerExtension(e)}var x={name:"bullet_list",create:()=>p,commands:{toggle_bullet_list:e=>e.chain().focus().toggleBulletList().run()},selection_keys:["bullet_list"],selection_state:e=>({bullet_list:e.isActive("bulletList")})};function ae(){g(x)}export{ae as register_bullet_list};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,y=t.Extension,h=t.InputRule,i=t.Mark,R=t.Node,E=t.NodePos,f=t.NodeView,C=t.PasteRule,P=t.Tracker,T=t.callOrReturn,A=t.canInsertNode,S=t.combineTransactionSteps,N=t.createChainableState,O=t.createDocument,B=t.createNodeFromContent,w=t.createStyleTag,M=t.defaultBlockAt,v=t.deleteProps,I=t.elementFromString,F=t.escapeForRegEx,D=t.extensions,j=t.findChildren,L=t.findChildrenInRange,K=t.findDuplicates,H=t.findParentNode,q=t.findParentNodeClosestToPos,G=t.fromString,z=t.generateHTML,J=t.generateJSON,U=t.generateText,V=t.getAttributes,Y=t.getAttributesFromExtensions,Q=t.getChangedRanges,W=t.getDebugJSON,X=t.getExtensionField,Z=t.getHTMLFromFragment,$=t.getMarkAttributes,tt=t.getMarkRange,et=t.getMarkType,nt=t.getMarksBetween,ot=t.getNodeAtPosition,rt=t.getNodeAttributes,it=t.getNodeType,st=t.getRenderedAttributes,at=t.getSchema,lt=t.getSchemaByResolvedExtensions,dt=t.getSchemaTypeByName,pt=t.getSchemaTypeNameByName,ct=t.getSplittedAttributes,ut=t.getText,gt=t.getTextBetween,_t=t.getTextContentFromNodes,xt=t.getTextSerializersFromSchema,mt=t.injectExtensionAttributesToParseRule,kt=t.inputRulesPlugin,bt=t.isActive,yt=t.isAtEndOfNode,ht=t.isAtStartOfNode,Rt=t.isEmptyObject,Et=t.isExtensionRulesEnabled,ft=t.isFunction,Ct=t.isList,Pt=t.isMacOS,Tt=t.isMarkActive,At=t.isNodeActive,St=t.isNodeEmpty,Nt=t.isNodeSelection,Ot=t.isNumber,Bt=t.isPlainObject,wt=t.isRegExp,Mt=t.isSafari,vt=t.isString,It=t.isTextSelection,Ft=t.isiOS,s=t.markInputRule,a=t.markPasteRule,l=t.mergeAttributes,Dt=t.mergeDeep,jt=t.minMax,Lt=t.nodeInputRule,Kt=t.nodePasteRule,Ht=t.objectIncludes,qt=t.pasteRulesPlugin,Gt=t.posToDOMRect,zt=t.removeDuplicates,Jt=t.resolveFocusPosition,Ut=t.rewriteUnknownContent,Vt=t.selectionToInsertionEnd,Yt=t.splitExtensions,Qt=t.textInputRule,Wt=t.textPasteRule,Xt=t.textblockTypeInputRule,Zt=t.wrappingInputRule;var g=/(^|[^`])`([^`]+)`(?!`)/,_=/(^|[^`])`([^`]+)`(?!`)/g,d=i.create({name:"code",addOptions(){return{HTMLAttributes:{}}},excludes:"_",code:!0,exitable:!0,parseHTML(){return[{tag:"code"}]},renderHTML({HTMLAttributes:e}){return["code",l(this.options.HTMLAttributes,e),0]},addCommands(){return{setCode:()=>({commands:e})=>e.setMark(this.name),toggleCode:()=>({commands:e})=>e.toggleMark(this.name),unsetCode:()=>({commands:e})=>e.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-e":()=>this.editor.commands.toggleCode()}},addInputRules(){return[s({find:g,type:this.type})]},addPasteRules(){return[a({find:_,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function x(){let e=globalThis,o=e[p];if(o!=null)return o;let r={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[p]=r,r}function c(){return x()}function u(e){c().registerExtension(e)}var m={name:"code",create:()=>d,commands:{set_code:e=>e.chain().focus().setCode().run(),toggle_code:e=>e.chain().focus().toggleCode().run(),unset_code:e=>e.chain().focus().unsetCode().run()}};function ae(){u(m)}export{ae as register_code};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=e.CommandManager,b=e.Editor,y=e.Extension,h=e.InputRule,i=e.Mark,R=e.Node,E=e.NodePos,f=e.NodeView,C=e.PasteRule,P=e.Tracker,T=e.callOrReturn,A=e.canInsertNode,S=e.combineTransactionSteps,w=e.createChainableState,N=e.createDocument,O=e.createNodeFromContent,B=e.createStyleTag,M=e.defaultBlockAt,v=e.deleteProps,I=e.elementFromString,F=e.escapeForRegEx,D=e.extensions,j=e.findChildren,L=e.findChildrenInRange,K=e.findDuplicates,H=e.findParentNode,q=e.findParentNodeClosestToPos,G=e.fromString,z=e.generateHTML,J=e.generateJSON,U=e.generateText,V=e.getAttributes,Y=e.getAttributesFromExtensions,Q=e.getChangedRanges,W=e.getDebugJSON,X=e.getExtensionField,Z=e.getHTMLFromFragment,$=e.getMarkAttributes,ee=e.getMarkRange,te=e.getMarkType,ne=e.getMarksBetween,oe=e.getNodeAtPosition,re=e.getNodeAttributes,ie=e.getNodeType,se=e.getRenderedAttributes,le=e.getSchema,ae=e.getSchemaByResolvedExtensions,de=e.getSchemaTypeByName,pe=e.getSchemaTypeNameByName,ce=e.getSplittedAttributes,ue=e.getText,ge=e.getTextBetween,_e=e.getTextContentFromNodes,xe=e.getTextSerializersFromSchema,me=e.injectExtensionAttributesToParseRule,ke=e.inputRulesPlugin,be=e.isActive,ye=e.isAtEndOfNode,he=e.isAtStartOfNode,Re=e.isEmptyObject,Ee=e.isExtensionRulesEnabled,fe=e.isFunction,Ce=e.isList,Pe=e.isMacOS,Te=e.isMarkActive,Ae=e.isNodeActive,Se=e.isNodeEmpty,we=e.isNodeSelection,Ne=e.isNumber,Oe=e.isPlainObject,Be=e.isRegExp,Me=e.isSafari,ve=e.isString,Ie=e.isTextSelection,Fe=e.isiOS,s=e.markInputRule,l=e.markPasteRule,a=e.mergeAttributes,De=e.mergeDeep,je=e.minMax,Le=e.nodeInputRule,Ke=e.nodePasteRule,He=e.objectIncludes,qe=e.pasteRulesPlugin,Ge=e.posToDOMRect,ze=e.removeDuplicates,Je=e.resolveFocusPosition,Ue=e.rewriteUnknownContent,Ve=e.selectionToInsertionEnd,Ye=e.splitExtensions,Qe=e.textInputRule,We=e.textPasteRule,Xe=e.textblockTypeInputRule,Ze=e.wrappingInputRule;var g=/(^|[^`])`([^`]+)`(?!`)/,_=/(^|[^`])`([^`]+)`(?!`)/g,d=i.create({name:"code",addOptions(){return{HTMLAttributes:{}}},excludes:"_",code:!0,exitable:!0,parseHTML(){return[{tag:"code"}]},renderHTML({HTMLAttributes:t}){return["code",a(this.options.HTMLAttributes,t),0]},addCommands(){return{setCode:()=>({commands:t})=>t.setMark(this.name),toggleCode:()=>({commands:t})=>t.toggleMark(this.name),unsetCode:()=>({commands:t})=>t.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-e":()=>this.editor.commands.toggleCode()}},addInputRules(){return[s({find:g,type:this.type})]},addPasteRules(){return[l({find:_,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function x(){let t=globalThis,o=t[p];if(o!=null)return o;let r={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[p]=r,r}function c(){return x()}function u(t){c().registerExtension(t)}var m={name:"code",create:()=>d,commands:{set_code:t=>t.chain().focus().setCode().run(),toggle_code:t=>t.chain().focus().toggleCode().run(),unset_code:t=>t.chain().focus().unsetCode().run()}};function lt(){u(m)}export{lt as register_code};
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
var p=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(p==null||p.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=p.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var B=e.CommandManager,O=e.Editor,w=e.Extension,v=e.InputRule,M=e.Mark,x=e.Node,D=e.NodePos,I=e.NodeView,F=e.PasteRule,j=e.Tracker,L=e.callOrReturn,K=e.canInsertNode,H=e.combineTransactionSteps,G=e.createChainableState,q=e.createDocument,z=e.createNodeFromContent,$=e.createStyleTag,J=e.defaultBlockAt,W=e.deleteProps,V=e.elementFromString,U=e.escapeForRegEx,Y=e.extensions,Q=e.findChildren,X=e.findChildrenInRange,Z=e.findDuplicates,ee=e.findParentNode,te=e.findParentNodeClosestToPos,ne=e.fromString,oe=e.generateHTML,re=e.generateJSON,ie=e.generateText,se=e.getAttributes,ae=e.getAttributesFromExtensions,le=e.getChangedRanges,de=e.getDebugJSON,pe=e.getExtensionField,ce=e.getHTMLFromFragment,ue=e.getMarkAttributes,ge=e.getMarkRange,xe=e.getMarkType,_e=e.getMarksBetween,me=e.getNodeAtPosition,ke=e.getNodeAttributes,be=e.getNodeType,ye=e.getRenderedAttributes,fe=e.getSchema,he=e.getSchemaByResolvedExtensions,Ee=e.getSchemaTypeByName,Se=e.getSchemaTypeNameByName,Pe=e.getSplittedAttributes,Ce=e.getText,Ae=e.getTextBetween,Re=e.getTextContentFromNodes,Te=e.getTextSerializersFromSchema,Ne=e.injectExtensionAttributesToParseRule,Be=e.inputRulesPlugin,Oe=e.isActive,we=e.isAtEndOfNode,ve=e.isAtStartOfNode,Me=e.isEmptyObject,De=e.isExtensionRulesEnabled,Ie=e.isFunction,Fe=e.isList,je=e.isMacOS,Le=e.isMarkActive,Ke=e.isNodeActive,He=e.isNodeEmpty,Ge=e.isNodeSelection,qe=e.isNumber,ze=e.isPlainObject,$e=e.isRegExp,Je=e.isSafari,We=e.isString,Ve=e.isTextSelection,Ue=e.isiOS,Ye=e.markInputRule,Qe=e.markPasteRule,_=e.mergeAttributes,Xe=e.mergeDeep,Ze=e.minMax,et=e.nodeInputRule,tt=e.nodePasteRule,nt=e.objectIncludes,ot=e.pasteRulesPlugin,rt=e.posToDOMRect,it=e.removeDuplicates,st=e.resolveFocusPosition,at=e.rewriteUnknownContent,lt=e.selectionToInsertionEnd,dt=e.splitExtensions,pt=e.textInputRule,ct=e.textPasteRule,c=e.textblockTypeInputRule,ut=e.wrappingInputRule;var u=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(u==null||u.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var a=u.modules["@tiptap/pm/state"];if(a==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/state" is unavailable');var xt=a.AllSelection,_t=a.EditorState,mt=a.NodeSelection,m=a.Plugin,k=a.PluginKey,b=a.Selection,kt=a.SelectionRange,y=a.TextSelection,bt=a.Transaction;var A=/^```([a-z]+)?[\s\n]$/,R=/^~~~([a-z]+)?[\s\n]$/,f=x.create({name:"codeBlock",addOptions(){return{languageClassPrefix:"language-",exitOnTripleEnter:!0,exitOnArrowDown:!0,defaultLanguage:null,HTMLAttributes:{}}},content:"text*",marks:"",group:"block",code:!0,defining:!0,addAttributes(){return{language:{default:this.options.defaultLanguage,parseHTML:t=>{var n;let{languageClassPrefix:o}=this.options,l=[...((n=t.firstElementChild)===null||n===void 0?void 0:n.classList)||[]].filter(r=>r.startsWith(o)).map(r=>r.replace(o,""))[0];return l||null},rendered:!1}}},parseHTML(){return[{tag:"pre",preserveWhitespace:"full"}]},renderHTML({node:t,HTMLAttributes:n}){return["pre",_(this.options.HTMLAttributes,n),["code",{class:t.attrs.language?this.options.languageClassPrefix+t.attrs.language:null},0]]},addCommands(){return{setCodeBlock:t=>({commands:n})=>n.setNode(this.name,t),toggleCodeBlock:t=>({commands:n})=>n.toggleNode(this.name,"paragraph",t)}},addKeyboardShortcuts(){return{"Mod-Alt-c":()=>this.editor.commands.toggleCodeBlock(),Backspace:()=>{let{empty:t,$anchor:n}=this.editor.state.selection,o=n.pos===1;return!t||n.parent.type.name!==this.name?!1:o||!n.parent.textContent.length?this.editor.commands.clearNodes():!1},Enter:({editor:t})=>{if(!this.options.exitOnTripleEnter)return!1;let{state:n}=t,{selection:o}=n,{$from:i,empty:s}=o;if(!s||i.parent.type!==this.type)return!1;let l=i.parentOffset===i.parent.nodeSize-2,r=i.parent.textContent.endsWith(`
|
||||
var p=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(p==null||p.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=p.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var N=e.CommandManager,B=e.Editor,O=e.Extension,v=e.InputRule,M=e.Mark,_=e.Node,D=e.NodePos,I=e.NodeView,F=e.PasteRule,j=e.Tracker,L=e.callOrReturn,K=e.canInsertNode,H=e.combineTransactionSteps,G=e.createChainableState,q=e.createDocument,z=e.createNodeFromContent,$=e.createStyleTag,J=e.defaultBlockAt,W=e.deleteProps,V=e.elementFromString,U=e.escapeForRegEx,Y=e.extensions,Q=e.findChildren,X=e.findChildrenInRange,Z=e.findDuplicates,ee=e.findParentNode,te=e.findParentNodeClosestToPos,ne=e.fromString,oe=e.generateHTML,re=e.generateJSON,ie=e.generateText,se=e.getAttributes,le=e.getAttributesFromExtensions,ae=e.getChangedRanges,de=e.getDebugJSON,pe=e.getExtensionField,ce=e.getHTMLFromFragment,ue=e.getMarkAttributes,ge=e.getMarkRange,_e=e.getMarkType,xe=e.getMarksBetween,me=e.getNodeAtPosition,ke=e.getNodeAttributes,be=e.getNodeType,ye=e.getRenderedAttributes,fe=e.getSchema,he=e.getSchemaByResolvedExtensions,Ee=e.getSchemaTypeByName,Se=e.getSchemaTypeNameByName,Pe=e.getSplittedAttributes,Ce=e.getText,Ae=e.getTextBetween,Re=e.getTextContentFromNodes,Te=e.getTextSerializersFromSchema,we=e.injectExtensionAttributesToParseRule,Ne=e.inputRulesPlugin,Be=e.isActive,Oe=e.isAtEndOfNode,ve=e.isAtStartOfNode,Me=e.isEmptyObject,De=e.isExtensionRulesEnabled,Ie=e.isFunction,Fe=e.isList,je=e.isMacOS,Le=e.isMarkActive,Ke=e.isNodeActive,He=e.isNodeEmpty,Ge=e.isNodeSelection,qe=e.isNumber,ze=e.isPlainObject,$e=e.isRegExp,Je=e.isSafari,We=e.isString,Ve=e.isTextSelection,Ue=e.isiOS,Ye=e.markInputRule,Qe=e.markPasteRule,x=e.mergeAttributes,Xe=e.mergeDeep,Ze=e.minMax,et=e.nodeInputRule,tt=e.nodePasteRule,nt=e.objectIncludes,ot=e.pasteRulesPlugin,rt=e.posToDOMRect,it=e.removeDuplicates,st=e.resolveFocusPosition,lt=e.rewriteUnknownContent,at=e.selectionToInsertionEnd,dt=e.splitExtensions,pt=e.textInputRule,ct=e.textPasteRule,c=e.textblockTypeInputRule,ut=e.wrappingInputRule;var u=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(u==null||u.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var l=u.modules["@tiptap/pm/state"];if(l==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/state" is unavailable');var _t=l.AllSelection,xt=l.EditorState,mt=l.NodeSelection,m=l.Plugin,k=l.PluginKey,b=l.Selection,kt=l.SelectionRange,y=l.TextSelection,bt=l.Transaction;var A=/^```([a-z]+)?[\s\n]$/,R=/^~~~([a-z]+)?[\s\n]$/,f=_.create({name:"codeBlock",addOptions(){return{languageClassPrefix:"language-",exitOnTripleEnter:!0,exitOnArrowDown:!0,defaultLanguage:null,HTMLAttributes:{}}},content:"text*",marks:"",group:"block",code:!0,defining:!0,addAttributes(){return{language:{default:this.options.defaultLanguage,parseHTML:t=>{var n;let{languageClassPrefix:o}=this.options,a=[...((n=t.firstElementChild)===null||n===void 0?void 0:n.classList)||[]].filter(r=>r.startsWith(o)).map(r=>r.replace(o,""))[0];return a||null},rendered:!1}}},parseHTML(){return[{tag:"pre",preserveWhitespace:"full"}]},renderHTML({node:t,HTMLAttributes:n}){return["pre",x(this.options.HTMLAttributes,n),["code",{class:t.attrs.language?this.options.languageClassPrefix+t.attrs.language:null},0]]},addCommands(){return{setCodeBlock:t=>({commands:n})=>n.setNode(this.name,t),toggleCodeBlock:t=>({commands:n})=>n.toggleNode(this.name,"paragraph",t)}},addKeyboardShortcuts(){return{"Mod-Alt-c":()=>this.editor.commands.toggleCodeBlock(),Backspace:()=>{let{empty:t,$anchor:n}=this.editor.state.selection,o=n.pos===1;return!t||n.parent.type.name!==this.name?!1:o||!n.parent.textContent.length?this.editor.commands.clearNodes():!1},Enter:({editor:t})=>{if(!this.options.exitOnTripleEnter)return!1;let{state:n}=t,{selection:o}=n,{$from:i,empty:s}=o;if(!s||i.parent.type!==this.type)return!1;let a=i.parentOffset===i.parent.nodeSize-2,r=i.parent.textContent.endsWith(`
|
||||
|
||||
`);return!l||!r?!1:t.chain().command(({tr:d})=>(d.delete(i.pos-2,i.pos),!0)).exitCode().run()},ArrowDown:({editor:t})=>{if(!this.options.exitOnArrowDown)return!1;let{state:n}=t,{selection:o,doc:i}=n,{$from:s,empty:l}=o;if(!l||s.parent.type!==this.type||!(s.parentOffset===s.parent.nodeSize-2))return!1;let d=s.after();return d===void 0?!1:i.nodeAt(d)?t.commands.command(({tr:C})=>(C.setSelection(b.near(i.resolve(d))),!0)):t.commands.exitCode()}}},addInputRules(){return[c({find:A,type:this.type,getAttributes:t=>({language:t[1]})}),c({find:R,type:this.type,getAttributes:t=>({language:t[1]})})]},addProseMirrorPlugins(){return[new m({key:new k("codeBlockVSCodeHandler"),props:{handlePaste:(t,n)=>{if(!n.clipboardData||this.editor.isActive(this.type.name))return!1;let o=n.clipboardData.getData("text/plain"),i=n.clipboardData.getData("vscode-editor-data"),s=i?JSON.parse(i):void 0,l=s?.mode;if(!o||!l)return!1;let{tr:r,schema:d}=t.state,g=d.text(o.replace(/\r\n?/g,`
|
||||
`));return r.replaceSelectionWith(this.type.create({language:l},g)),r.selection.$from.parent.type!==this.type&&r.setSelection(y.near(r.doc.resolve(Math.max(0,r.selection.from-2)))),r.setMeta("paste",!0),t.dispatch(r),!0}}})]}});var h="__LEPTOS_TIPTAP_BRIDGE__";function T(){let t=globalThis,n=t[h];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[h]=o,o}function E(){return T()}function S(t){E().registerExtension(t)}function P(t){if(t?.language!=null)return{language:t.language}}var N={name:"code_block",create:()=>f,commands:{set_code_block:(t,n)=>n.kind==="set_code_block"?t.chain().focus().setCodeBlock(P(n.attributes)).run():!1,toggle_code_block:(t,n)=>n.kind==="toggle_code_block"?t.chain().focus().toggleCodeBlock(P(n.attributes)).run():!1}};function Tt(){S(N)}export{Tt as register_code_block};
|
||||
`);return!a||!r?!1:t.chain().command(({tr:d})=>(d.delete(i.pos-2,i.pos),!0)).exitCode().run()},ArrowDown:({editor:t})=>{if(!this.options.exitOnArrowDown)return!1;let{state:n}=t,{selection:o,doc:i}=n,{$from:s,empty:a}=o;if(!a||s.parent.type!==this.type||!(s.parentOffset===s.parent.nodeSize-2))return!1;let d=s.after();return d===void 0?!1:i.nodeAt(d)?t.commands.command(({tr:C})=>(C.setSelection(b.near(i.resolve(d))),!0)):t.commands.exitCode()}}},addInputRules(){return[c({find:A,type:this.type,getAttributes:t=>({language:t[1]})}),c({find:R,type:this.type,getAttributes:t=>({language:t[1]})})]},addProseMirrorPlugins(){return[new m({key:new k("codeBlockVSCodeHandler"),props:{handlePaste:(t,n)=>{if(!n.clipboardData||this.editor.isActive(this.type.name))return!1;let o=n.clipboardData.getData("text/plain"),i=n.clipboardData.getData("vscode-editor-data"),s=i?JSON.parse(i):void 0,a=s?.mode;if(!o||!a)return!1;let{tr:r,schema:d}=t.state,g=d.text(o.replace(/\r\n?/g,`
|
||||
`));return r.replaceSelectionWith(this.type.create({language:a},g)),r.selection.$from.parent.type!==this.type&&r.setSelection(y.near(r.doc.resolve(Math.max(0,r.selection.from-2)))),r.setMeta("paste",!0),t.dispatch(r),!0}}})]}});var h="__LEPTOS_TIPTAP_BRIDGE__";function T(){let t=globalThis,n=t[h];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[h]=o,o}function E(){return T()}function S(t){E().registerExtension(t)}function P(t){if(t?.language!=null)return{language:t.language}}var w={name:"code_block",create:()=>f,commands:{set_code_block:(t,n)=>n.kind==="set_code_block"?t.chain().focus().setCodeBlock(P(n.attributes)).run():!1,toggle_code_block:(t,n)=>n.kind==="toggle_code_block"?t.chain().focus().toggleCodeBlock(P(n.attributes)).run():!1}};function Tt(){S(w)}export{Tt as register_code_block};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var u=t.CommandManager,g=t.Editor,_=t.Extension,x=t.InputRule,m=t.Mark,r=t.Node,k=t.NodePos,b=t.NodeView,y=t.PasteRule,E=t.Tracker,R=t.callOrReturn,h=t.canInsertNode,f=t.combineTransactionSteps,P=t.createChainableState,C=t.createDocument,S=t.createNodeFromContent,T=t.createStyleTag,A=t.defaultBlockAt,N=t.deleteProps,O=t.elementFromString,B=t.escapeForRegEx,w=t.extensions,v=t.findChildren,I=t.findChildrenInRange,M=t.findDuplicates,D=t.findParentNode,F=t.findParentNodeClosestToPos,j=t.fromString,L=t.generateHTML,K=t.generateJSON,q=t.generateText,G=t.getAttributes,H=t.getAttributesFromExtensions,z=t.getChangedRanges,J=t.getDebugJSON,U=t.getExtensionField,V=t.getHTMLFromFragment,Y=t.getMarkAttributes,Q=t.getMarkRange,W=t.getMarkType,X=t.getMarksBetween,Z=t.getNodeAtPosition,$=t.getNodeAttributes,tt=t.getNodeType,et=t.getRenderedAttributes,nt=t.getSchema,ot=t.getSchemaByResolvedExtensions,it=t.getSchemaTypeByName,rt=t.getSchemaTypeNameByName,st=t.getSplittedAttributes,lt=t.getText,at=t.getTextBetween,dt=t.getTextContentFromNodes,pt=t.getTextSerializersFromSchema,ct=t.injectExtensionAttributesToParseRule,ut=t.inputRulesPlugin,gt=t.isActive,_t=t.isAtEndOfNode,xt=t.isAtStartOfNode,mt=t.isEmptyObject,kt=t.isExtensionRulesEnabled,bt=t.isFunction,yt=t.isList,Et=t.isMacOS,Rt=t.isMarkActive,ht=t.isNodeActive,ft=t.isNodeEmpty,Pt=t.isNodeSelection,Ct=t.isNumber,St=t.isPlainObject,Tt=t.isRegExp,At=t.isSafari,Nt=t.isString,Ot=t.isTextSelection,Bt=t.isiOS,wt=t.markInputRule,vt=t.markPasteRule,It=t.mergeAttributes,Mt=t.mergeDeep,Dt=t.minMax,Ft=t.nodeInputRule,jt=t.nodePasteRule,Lt=t.objectIncludes,Kt=t.pasteRulesPlugin,qt=t.posToDOMRect,Gt=t.removeDuplicates,Ht=t.resolveFocusPosition,zt=t.rewriteUnknownContent,Jt=t.selectionToInsertionEnd,Ut=t.splitExtensions,Vt=t.textInputRule,Yt=t.textPasteRule,Qt=t.textblockTypeInputRule,Wt=t.wrappingInputRule;var s=r.create({name:"doc",topNode:!0,content:"block+"});var l="__LEPTOS_TIPTAP_BRIDGE__";function p(){let e=globalThis,o=e[l];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[l]=i,i}function a(){return p()}function d(e){a().registerExtension(e)}var c={name:"document",create:()=>s};function re(){d(c)}export{re as register_document};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var u=e.CommandManager,g=e.Editor,_=e.Extension,x=e.InputRule,m=e.Mark,r=e.Node,k=e.NodePos,b=e.NodeView,y=e.PasteRule,E=e.Tracker,h=e.callOrReturn,R=e.canInsertNode,f=e.combineTransactionSteps,P=e.createChainableState,C=e.createDocument,S=e.createNodeFromContent,T=e.createStyleTag,A=e.defaultBlockAt,w=e.deleteProps,N=e.elementFromString,O=e.escapeForRegEx,B=e.extensions,v=e.findChildren,I=e.findChildrenInRange,M=e.findDuplicates,D=e.findParentNode,F=e.findParentNodeClosestToPos,j=e.fromString,L=e.generateHTML,K=e.generateJSON,q=e.generateText,G=e.getAttributes,H=e.getAttributesFromExtensions,z=e.getChangedRanges,J=e.getDebugJSON,U=e.getExtensionField,V=e.getHTMLFromFragment,Y=e.getMarkAttributes,Q=e.getMarkRange,W=e.getMarkType,X=e.getMarksBetween,Z=e.getNodeAtPosition,$=e.getNodeAttributes,ee=e.getNodeType,te=e.getRenderedAttributes,ne=e.getSchema,oe=e.getSchemaByResolvedExtensions,ie=e.getSchemaTypeByName,re=e.getSchemaTypeNameByName,se=e.getSplittedAttributes,le=e.getText,ae=e.getTextBetween,de=e.getTextContentFromNodes,pe=e.getTextSerializersFromSchema,ce=e.injectExtensionAttributesToParseRule,ue=e.inputRulesPlugin,ge=e.isActive,_e=e.isAtEndOfNode,xe=e.isAtStartOfNode,me=e.isEmptyObject,ke=e.isExtensionRulesEnabled,be=e.isFunction,ye=e.isList,Ee=e.isMacOS,he=e.isMarkActive,Re=e.isNodeActive,fe=e.isNodeEmpty,Pe=e.isNodeSelection,Ce=e.isNumber,Se=e.isPlainObject,Te=e.isRegExp,Ae=e.isSafari,we=e.isString,Ne=e.isTextSelection,Oe=e.isiOS,Be=e.markInputRule,ve=e.markPasteRule,Ie=e.mergeAttributes,Me=e.mergeDeep,De=e.minMax,Fe=e.nodeInputRule,je=e.nodePasteRule,Le=e.objectIncludes,Ke=e.pasteRulesPlugin,qe=e.posToDOMRect,Ge=e.removeDuplicates,He=e.resolveFocusPosition,ze=e.rewriteUnknownContent,Je=e.selectionToInsertionEnd,Ue=e.splitExtensions,Ve=e.textInputRule,Ye=e.textPasteRule,Qe=e.textblockTypeInputRule,We=e.wrappingInputRule;var s=r.create({name:"doc",topNode:!0,content:"block+"});var l="__LEPTOS_TIPTAP_BRIDGE__";function p(){let t=globalThis,o=t[l];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[l]=i,i}function a(){return p()}function d(t){a().registerExtension(t)}var c={name:"document",create:()=>s};function rt(){d(c)}export{rt as register_document};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var x=t.CommandManager,m=t.Editor,s=t.Extension,k=t.InputRule,b=t.Mark,y=t.Node,E=t.NodePos,h=t.NodeView,R=t.PasteRule,P=t.Tracker,f=t.callOrReturn,C=t.canInsertNode,T=t.combineTransactionSteps,S=t.createChainableState,A=t.createDocument,O=t.createNodeFromContent,N=t.createStyleTag,w=t.defaultBlockAt,B=t.deleteProps,v=t.elementFromString,I=t.escapeForRegEx,M=t.extensions,D=t.findChildren,F=t.findChildrenInRange,j=t.findDuplicates,L=t.findParentNode,K=t.findParentNodeClosestToPos,G=t.fromString,q=t.generateHTML,H=t.generateJSON,z=t.generateText,J=t.getAttributes,U=t.getAttributesFromExtensions,V=t.getChangedRanges,Y=t.getDebugJSON,Q=t.getExtensionField,W=t.getHTMLFromFragment,X=t.getMarkAttributes,Z=t.getMarkRange,$=t.getMarkType,tt=t.getMarksBetween,et=t.getNodeAtPosition,nt=t.getNodeAttributes,ot=t.getNodeType,rt=t.getRenderedAttributes,it=t.getSchema,st=t.getSchemaByResolvedExtensions,lt=t.getSchemaTypeByName,at=t.getSchemaTypeNameByName,pt=t.getSplittedAttributes,dt=t.getText,ct=t.getTextBetween,ut=t.getTextContentFromNodes,gt=t.getTextSerializersFromSchema,_t=t.injectExtensionAttributesToParseRule,xt=t.inputRulesPlugin,mt=t.isActive,kt=t.isAtEndOfNode,bt=t.isAtStartOfNode,yt=t.isEmptyObject,Et=t.isExtensionRulesEnabled,ht=t.isFunction,Rt=t.isList,Pt=t.isMacOS,ft=t.isMarkActive,Ct=t.isNodeActive,Tt=t.isNodeEmpty,St=t.isNodeSelection,At=t.isNumber,Ot=t.isPlainObject,Nt=t.isRegExp,wt=t.isSafari,Bt=t.isString,vt=t.isTextSelection,It=t.isiOS,Mt=t.markInputRule,Dt=t.markPasteRule,Ft=t.mergeAttributes,jt=t.mergeDeep,Lt=t.minMax,Kt=t.nodeInputRule,Gt=t.nodePasteRule,qt=t.objectIncludes,Ht=t.pasteRulesPlugin,zt=t.posToDOMRect,Jt=t.removeDuplicates,Ut=t.resolveFocusPosition,Vt=t.rewriteUnknownContent,Yt=t.selectionToInsertionEnd,Qt=t.splitExtensions,Wt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,$t=t.wrappingInputRule;var o=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(o==null||o.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var l=o.modules["@tiptap/pm/dropcursor"];if(l==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/dropcursor" is unavailable');var a=l.dropCursor;var p=s.create({name:"dropCursor",addOptions(){return{color:"currentColor",width:1,class:void 0}},addProseMirrorPlugins(){return[a(this.options)]}});var d="__LEPTOS_TIPTAP_BRIDGE__";function g(){let e=globalThis,r=e[d];if(r!=null)return r;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[d]=i,i}function c(){return g()}function u(e){c().registerExtension(e)}var _={name:"dropcursor",create:()=>p};function de(){u(_)}export{de as register_dropcursor};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var x=e.CommandManager,m=e.Editor,s=e.Extension,k=e.InputRule,b=e.Mark,y=e.Node,E=e.NodePos,h=e.NodeView,f=e.PasteRule,R=e.Tracker,P=e.callOrReturn,C=e.canInsertNode,T=e.combineTransactionSteps,S=e.createChainableState,A=e.createDocument,w=e.createNodeFromContent,O=e.createStyleTag,N=e.defaultBlockAt,B=e.deleteProps,v=e.elementFromString,I=e.escapeForRegEx,M=e.extensions,D=e.findChildren,F=e.findChildrenInRange,j=e.findDuplicates,L=e.findParentNode,K=e.findParentNodeClosestToPos,G=e.fromString,q=e.generateHTML,H=e.generateJSON,z=e.generateText,J=e.getAttributes,U=e.getAttributesFromExtensions,V=e.getChangedRanges,Y=e.getDebugJSON,Q=e.getExtensionField,W=e.getHTMLFromFragment,X=e.getMarkAttributes,Z=e.getMarkRange,$=e.getMarkType,ee=e.getMarksBetween,te=e.getNodeAtPosition,ne=e.getNodeAttributes,oe=e.getNodeType,re=e.getRenderedAttributes,ie=e.getSchema,se=e.getSchemaByResolvedExtensions,le=e.getSchemaTypeByName,ae=e.getSchemaTypeNameByName,de=e.getSplittedAttributes,pe=e.getText,ce=e.getTextBetween,ue=e.getTextContentFromNodes,ge=e.getTextSerializersFromSchema,_e=e.injectExtensionAttributesToParseRule,xe=e.inputRulesPlugin,me=e.isActive,ke=e.isAtEndOfNode,be=e.isAtStartOfNode,ye=e.isEmptyObject,Ee=e.isExtensionRulesEnabled,he=e.isFunction,fe=e.isList,Re=e.isMacOS,Pe=e.isMarkActive,Ce=e.isNodeActive,Te=e.isNodeEmpty,Se=e.isNodeSelection,Ae=e.isNumber,we=e.isPlainObject,Oe=e.isRegExp,Ne=e.isSafari,Be=e.isString,ve=e.isTextSelection,Ie=e.isiOS,Me=e.markInputRule,De=e.markPasteRule,Fe=e.mergeAttributes,je=e.mergeDeep,Le=e.minMax,Ke=e.nodeInputRule,Ge=e.nodePasteRule,qe=e.objectIncludes,He=e.pasteRulesPlugin,ze=e.posToDOMRect,Je=e.removeDuplicates,Ue=e.resolveFocusPosition,Ve=e.rewriteUnknownContent,Ye=e.selectionToInsertionEnd,Qe=e.splitExtensions,We=e.textInputRule,Xe=e.textPasteRule,Ze=e.textblockTypeInputRule,$e=e.wrappingInputRule;var o=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(o==null||o.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var l=o.modules["@tiptap/pm/dropcursor"];if(l==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/dropcursor" is unavailable');var a=l.dropCursor;var d=s.create({name:"dropCursor",addOptions(){return{color:"currentColor",width:1,class:void 0}},addProseMirrorPlugins(){return[a(this.options)]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function g(){let t=globalThis,r=t[p];if(r!=null)return r;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[p]=i,i}function c(){return g()}function u(t){c().registerExtension(t)}var _={name:"dropcursor",create:()=>d};function pt(){u(_)}export{pt as register_dropcursor};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var r=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(r==null||r.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=r.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,a=t.Extension,y=t.InputRule,E=t.Mark,R=t.Node,h=t.NodePos,P=t.NodeView,f=t.PasteRule,C=t.Tracker,l=t.callOrReturn,T=t.canInsertNode,S=t.combineTransactionSteps,A=t.createChainableState,N=t.createDocument,O=t.createNodeFromContent,w=t.createStyleTag,B=t.defaultBlockAt,v=t.deleteProps,I=t.elementFromString,M=t.escapeForRegEx,F=t.extensions,D=t.findChildren,j=t.findChildrenInRange,G=t.findDuplicates,L=t.findParentNode,K=t.findParentNodeClosestToPos,q=t.fromString,H=t.generateHTML,z=t.generateJSON,J=t.generateText,U=t.getAttributes,V=t.getAttributesFromExtensions,Y=t.getChangedRanges,Q=t.getDebugJSON,p=t.getExtensionField,W=t.getHTMLFromFragment,X=t.getMarkAttributes,Z=t.getMarkRange,$=t.getMarkType,tt=t.getMarksBetween,et=t.getNodeAtPosition,nt=t.getNodeAttributes,ot=t.getNodeType,rt=t.getRenderedAttributes,it=t.getSchema,st=t.getSchemaByResolvedExtensions,at=t.getSchemaTypeByName,lt=t.getSchemaTypeNameByName,pt=t.getSplittedAttributes,dt=t.getText,ct=t.getTextBetween,ut=t.getTextContentFromNodes,gt=t.getTextSerializersFromSchema,_t=t.injectExtensionAttributesToParseRule,xt=t.inputRulesPlugin,mt=t.isActive,kt=t.isAtEndOfNode,bt=t.isAtStartOfNode,yt=t.isEmptyObject,Et=t.isExtensionRulesEnabled,Rt=t.isFunction,ht=t.isList,Pt=t.isMacOS,ft=t.isMarkActive,Ct=t.isNodeActive,Tt=t.isNodeEmpty,St=t.isNodeSelection,At=t.isNumber,Nt=t.isPlainObject,Ot=t.isRegExp,wt=t.isSafari,Bt=t.isString,vt=t.isTextSelection,It=t.isiOS,Mt=t.markInputRule,Ft=t.markPasteRule,Dt=t.mergeAttributes,jt=t.mergeDeep,Gt=t.minMax,Lt=t.nodeInputRule,Kt=t.nodePasteRule,qt=t.objectIncludes,Ht=t.pasteRulesPlugin,zt=t.posToDOMRect,Jt=t.removeDuplicates,Ut=t.resolveFocusPosition,Vt=t.rewriteUnknownContent,Yt=t.selectionToInsertionEnd,Qt=t.splitExtensions,Wt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,$t=t.wrappingInputRule;var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var s=i.modules["@tiptap/pm/gapcursor"];if(s==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/gapcursor" is unavailable');var ee=s.GapCursor,d=s.gapCursor;var c=a.create({name:"gapCursor",addProseMirrorPlugins(){return[d()]},extendNodeSchema(e){var n;let o={name:e.name,options:e.options,storage:e.storage};return{allowGapCursor:(n=l(p(e,"allowGapCursor",o)))!==null&&n!==void 0?n:null}}});var u="__LEPTOS_TIPTAP_BRIDGE__";function x(){let e=globalThis,n=e[u];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[u]=o,o}function g(){return x()}function _(e){g().registerExtension(e)}var m={name:"gapcursor",create:()=>c};function ce(){_(m)}export{ce as register_gapcursor};
|
||||
var r=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(r==null||r.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=r.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=e.CommandManager,b=e.Editor,l=e.Extension,y=e.InputRule,E=e.Mark,h=e.Node,f=e.NodePos,R=e.NodeView,P=e.PasteRule,C=e.Tracker,a=e.callOrReturn,T=e.canInsertNode,S=e.combineTransactionSteps,A=e.createChainableState,w=e.createDocument,N=e.createNodeFromContent,O=e.createStyleTag,B=e.defaultBlockAt,v=e.deleteProps,I=e.elementFromString,M=e.escapeForRegEx,F=e.extensions,D=e.findChildren,j=e.findChildrenInRange,G=e.findDuplicates,L=e.findParentNode,K=e.findParentNodeClosestToPos,q=e.fromString,H=e.generateHTML,z=e.generateJSON,J=e.generateText,U=e.getAttributes,V=e.getAttributesFromExtensions,Y=e.getChangedRanges,Q=e.getDebugJSON,d=e.getExtensionField,W=e.getHTMLFromFragment,X=e.getMarkAttributes,Z=e.getMarkRange,$=e.getMarkType,ee=e.getMarksBetween,te=e.getNodeAtPosition,ne=e.getNodeAttributes,oe=e.getNodeType,re=e.getRenderedAttributes,ie=e.getSchema,se=e.getSchemaByResolvedExtensions,le=e.getSchemaTypeByName,ae=e.getSchemaTypeNameByName,de=e.getSplittedAttributes,pe=e.getText,ce=e.getTextBetween,ue=e.getTextContentFromNodes,ge=e.getTextSerializersFromSchema,_e=e.injectExtensionAttributesToParseRule,xe=e.inputRulesPlugin,me=e.isActive,ke=e.isAtEndOfNode,be=e.isAtStartOfNode,ye=e.isEmptyObject,Ee=e.isExtensionRulesEnabled,he=e.isFunction,fe=e.isList,Re=e.isMacOS,Pe=e.isMarkActive,Ce=e.isNodeActive,Te=e.isNodeEmpty,Se=e.isNodeSelection,Ae=e.isNumber,we=e.isPlainObject,Ne=e.isRegExp,Oe=e.isSafari,Be=e.isString,ve=e.isTextSelection,Ie=e.isiOS,Me=e.markInputRule,Fe=e.markPasteRule,De=e.mergeAttributes,je=e.mergeDeep,Ge=e.minMax,Le=e.nodeInputRule,Ke=e.nodePasteRule,qe=e.objectIncludes,He=e.pasteRulesPlugin,ze=e.posToDOMRect,Je=e.removeDuplicates,Ue=e.resolveFocusPosition,Ve=e.rewriteUnknownContent,Ye=e.selectionToInsertionEnd,Qe=e.splitExtensions,We=e.textInputRule,Xe=e.textPasteRule,Ze=e.textblockTypeInputRule,$e=e.wrappingInputRule;var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var s=i.modules["@tiptap/pm/gapcursor"];if(s==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/gapcursor" is unavailable');var tt=s.GapCursor,p=s.gapCursor;var c=l.create({name:"gapCursor",addProseMirrorPlugins(){return[p()]},extendNodeSchema(t){var n;let o={name:t.name,options:t.options,storage:t.storage};return{allowGapCursor:(n=a(d(t,"allowGapCursor",o)))!==null&&n!==void 0?n:null}}});var u="__LEPTOS_TIPTAP_BRIDGE__";function x(){let t=globalThis,n=t[u];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[u]=o,o}function g(){return x()}function _(t){g().registerExtension(t)}var m={name:"gapcursor",create:()=>c};function ct(){_(m)}export{ct as register_gapcursor};
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=i.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var R=t.CommandManager,P=t.Editor,C=t.Extension,T=t.InputRule,S=t.Mark,a=t.Node,A=t.NodePos,B=t.NodeView,N=t.PasteRule,O=t.Tracker,M=t.callOrReturn,w=t.canInsertNode,v=t.combineTransactionSteps,I=t.createChainableState,F=t.createDocument,D=t.createNodeFromContent,j=t.createStyleTag,H=t.defaultBlockAt,L=t.deleteProps,K=t.elementFromString,q=t.escapeForRegEx,G=t.extensions,z=t.findChildren,J=t.findChildrenInRange,$=t.findDuplicates,U=t.findParentNode,V=t.findParentNodeClosestToPos,Y=t.fromString,Q=t.generateHTML,W=t.generateJSON,X=t.generateText,Z=t.getAttributes,tt=t.getAttributesFromExtensions,et=t.getChangedRanges,nt=t.getDebugJSON,ot=t.getExtensionField,rt=t.getHTMLFromFragment,it=t.getMarkAttributes,st=t.getMarkRange,at=t.getMarkType,lt=t.getMarksBetween,dt=t.getNodeAtPosition,pt=t.getNodeAttributes,ct=t.getNodeType,ut=t.getRenderedAttributes,gt=t.getSchema,_t=t.getSchemaByResolvedExtensions,xt=t.getSchemaTypeByName,mt=t.getSchemaTypeNameByName,kt=t.getSplittedAttributes,bt=t.getText,yt=t.getTextBetween,ft=t.getTextContentFromNodes,ht=t.getTextSerializersFromSchema,Et=t.injectExtensionAttributesToParseRule,Rt=t.inputRulesPlugin,Pt=t.isActive,Ct=t.isAtEndOfNode,Tt=t.isAtStartOfNode,St=t.isEmptyObject,At=t.isExtensionRulesEnabled,Bt=t.isFunction,Nt=t.isList,Ot=t.isMacOS,Mt=t.isMarkActive,wt=t.isNodeActive,vt=t.isNodeEmpty,It=t.isNodeSelection,Ft=t.isNumber,Dt=t.isPlainObject,jt=t.isRegExp,Ht=t.isSafari,Lt=t.isString,Kt=t.isTextSelection,qt=t.isiOS,Gt=t.markInputRule,zt=t.markPasteRule,l=t.mergeAttributes,Jt=t.mergeDeep,$t=t.minMax,Ut=t.nodeInputRule,Vt=t.nodePasteRule,Yt=t.objectIncludes,Qt=t.pasteRulesPlugin,Wt=t.posToDOMRect,Xt=t.removeDuplicates,Zt=t.resolveFocusPosition,te=t.rewriteUnknownContent,ee=t.selectionToInsertionEnd,ne=t.splitExtensions,oe=t.textInputRule,re=t.textPasteRule,ie=t.textblockTypeInputRule,se=t.wrappingInputRule;var d=a.create({name:"hardBreak",addOptions(){return{keepMarks:!0,HTMLAttributes:{}}},inline:!0,group:"inline",selectable:!1,linebreakReplacement:!0,parseHTML(){return[{tag:"br"}]},renderHTML({HTMLAttributes:e}){return["br",l(this.options.HTMLAttributes,e)]},renderText(){return`
|
||||
`},addCommands(){return{setHardBreak:()=>({commands:e,chain:n,state:o,editor:g})=>e.first([()=>e.exitCode(),()=>e.command(()=>{let{selection:r,storedMarks:_}=o;if(r.$from.parent.type.spec.isolating)return!1;let{keepMarks:x}=this.options,{splittableMarks:m}=g.extensionManager,s=_||r.$to.parentOffset&&r.$from.marks();return n().insertContent({type:this.name}).command(({tr:k,dispatch:b})=>{if(b&&s&&x){let y=s.filter(f=>m.includes(f.type.name));k.ensureMarks(y)}return!0}).run()})])}},addKeyboardShortcuts(){return{"Mod-Enter":()=>this.editor.commands.setHardBreak(),"Shift-Enter":()=>this.editor.commands.setHardBreak()}}});var p="__LEPTOS_TIPTAP_BRIDGE__";function h(){let e=globalThis,n=e[p];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[p]=o,o}function c(){return h()}function u(e){c().registerExtension(e)}var E={name:"hard_break",create:()=>d,commands:{set_hard_break:e=>e.chain().focus().setHardBreak().run()}};function xe(){u(E)}export{xe as register_hard_break};
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=i.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var R=e.CommandManager,P=e.Editor,C=e.Extension,T=e.InputRule,S=e.Mark,a=e.Node,A=e.NodePos,B=e.NodeView,w=e.PasteRule,N=e.Tracker,O=e.callOrReturn,M=e.canInsertNode,v=e.combineTransactionSteps,I=e.createChainableState,F=e.createDocument,D=e.createNodeFromContent,j=e.createStyleTag,H=e.defaultBlockAt,L=e.deleteProps,K=e.elementFromString,q=e.escapeForRegEx,G=e.extensions,z=e.findChildren,J=e.findChildrenInRange,$=e.findDuplicates,U=e.findParentNode,V=e.findParentNodeClosestToPos,Y=e.fromString,Q=e.generateHTML,W=e.generateJSON,X=e.generateText,Z=e.getAttributes,ee=e.getAttributesFromExtensions,te=e.getChangedRanges,ne=e.getDebugJSON,oe=e.getExtensionField,re=e.getHTMLFromFragment,ie=e.getMarkAttributes,se=e.getMarkRange,ae=e.getMarkType,le=e.getMarksBetween,de=e.getNodeAtPosition,pe=e.getNodeAttributes,ce=e.getNodeType,ue=e.getRenderedAttributes,ge=e.getSchema,_e=e.getSchemaByResolvedExtensions,me=e.getSchemaTypeByName,xe=e.getSchemaTypeNameByName,ke=e.getSplittedAttributes,be=e.getText,ye=e.getTextBetween,he=e.getTextContentFromNodes,fe=e.getTextSerializersFromSchema,Ee=e.injectExtensionAttributesToParseRule,Re=e.inputRulesPlugin,Pe=e.isActive,Ce=e.isAtEndOfNode,Te=e.isAtStartOfNode,Se=e.isEmptyObject,Ae=e.isExtensionRulesEnabled,Be=e.isFunction,we=e.isList,Ne=e.isMacOS,Oe=e.isMarkActive,Me=e.isNodeActive,ve=e.isNodeEmpty,Ie=e.isNodeSelection,Fe=e.isNumber,De=e.isPlainObject,je=e.isRegExp,He=e.isSafari,Le=e.isString,Ke=e.isTextSelection,qe=e.isiOS,Ge=e.markInputRule,ze=e.markPasteRule,l=e.mergeAttributes,Je=e.mergeDeep,$e=e.minMax,Ue=e.nodeInputRule,Ve=e.nodePasteRule,Ye=e.objectIncludes,Qe=e.pasteRulesPlugin,We=e.posToDOMRect,Xe=e.removeDuplicates,Ze=e.resolveFocusPosition,et=e.rewriteUnknownContent,tt=e.selectionToInsertionEnd,nt=e.splitExtensions,ot=e.textInputRule,rt=e.textPasteRule,it=e.textblockTypeInputRule,st=e.wrappingInputRule;var d=a.create({name:"hardBreak",addOptions(){return{keepMarks:!0,HTMLAttributes:{}}},inline:!0,group:"inline",selectable:!1,linebreakReplacement:!0,parseHTML(){return[{tag:"br"}]},renderHTML({HTMLAttributes:t}){return["br",l(this.options.HTMLAttributes,t)]},renderText(){return`
|
||||
`},addCommands(){return{setHardBreak:()=>({commands:t,chain:n,state:o,editor:g})=>t.first([()=>t.exitCode(),()=>t.command(()=>{let{selection:r,storedMarks:_}=o;if(r.$from.parent.type.spec.isolating)return!1;let{keepMarks:m}=this.options,{splittableMarks:x}=g.extensionManager,s=_||r.$to.parentOffset&&r.$from.marks();return n().insertContent({type:this.name}).command(({tr:k,dispatch:b})=>{if(b&&s&&m){let y=s.filter(h=>x.includes(h.type.name));k.ensureMarks(y)}return!0}).run()})])}},addKeyboardShortcuts(){return{"Mod-Enter":()=>this.editor.commands.setHardBreak(),"Shift-Enter":()=>this.editor.commands.setHardBreak()}}});var p="__LEPTOS_TIPTAP_BRIDGE__";function f(){let t=globalThis,n=t[p];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[p]=o,o}function c(){return f()}function u(t){c().registerExtension(t)}var E={name:"hard_break",create:()=>d,commands:{set_hard_break:t=>t.chain().focus().setHardBreak().run()}};function mt(){u(E)}export{mt as register_hard_break};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=i.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var x=e.CommandManager,m=e.Editor,k=e.Extension,b=e.InputRule,y=e.Mark,r=e.Node,h=e.NodePos,f=e.NodeView,E=e.PasteRule,R=e.Tracker,A=e.callOrReturn,P=e.canInsertNode,v=e.combineTransactionSteps,T=e.createChainableState,C=e.createDocument,S=e.createNodeFromContent,N=e.createStyleTag,O=e.defaultBlockAt,B=e.deleteProps,w=e.elementFromString,M=e.escapeForRegEx,I=e.extensions,F=e.findChildren,D=e.findChildrenInRange,j=e.findDuplicates,H=e.findParentNode,L=e.findParentNodeClosestToPos,K=e.fromString,q=e.generateHTML,G=e.generateJSON,$=e.generateText,z=e.getAttributes,J=e.getAttributesFromExtensions,U=e.getChangedRanges,V=e.getDebugJSON,Y=e.getExtensionField,Q=e.getHTMLFromFragment,W=e.getMarkAttributes,X=e.getMarkRange,Z=e.getMarkType,ee=e.getMarksBetween,te=e.getNodeAtPosition,ne=e.getNodeAttributes,oe=e.getNodeType,ie=e.getRenderedAttributes,re=e.getSchema,se=e.getSchemaByResolvedExtensions,le=e.getSchemaTypeByName,ae=e.getSchemaTypeNameByName,de=e.getSplittedAttributes,pe=e.getText,ce=e.getTextBetween,ue=e.getTextContentFromNodes,ge=e.getTextSerializersFromSchema,_e=e.injectExtensionAttributesToParseRule,xe=e.inputRulesPlugin,me=e.isActive,ke=e.isAtEndOfNode,be=e.isAtStartOfNode,ye=e.isEmptyObject,he=e.isExtensionRulesEnabled,fe=e.isFunction,Ee=e.isList,Re=e.isMacOS,Ae=e.isMarkActive,Pe=e.isNodeActive,ve=e.isNodeEmpty,Te=e.isNodeSelection,Ce=e.isNumber,Se=e.isPlainObject,Ne=e.isRegExp,Oe=e.isSafari,Be=e.isString,we=e.isTextSelection,Me=e.isiOS,Ie=e.markInputRule,Fe=e.markPasteRule,s=e.mergeAttributes,De=e.mergeDeep,je=e.minMax,He=e.nodeInputRule,Le=e.nodePasteRule,Ke=e.objectIncludes,qe=e.pasteRulesPlugin,Ge=e.posToDOMRect,$e=e.removeDuplicates,ze=e.resolveFocusPosition,Je=e.rewriteUnknownContent,Ue=e.selectionToInsertionEnd,Ve=e.splitExtensions,Ye=e.textInputRule,Qe=e.textPasteRule,l=e.textblockTypeInputRule,We=e.wrappingInputRule;var a=r.create({name:"heading",addOptions(){return{levels:[1,2,3,4,5,6],HTMLAttributes:{}}},content:"inline*",group:"block",defining:!0,addAttributes(){return{level:{default:1,rendered:!1}}},parseHTML(){return this.options.levels.map(t=>({tag:`h${t}`,attrs:{level:t}}))},renderHTML({node:t,HTMLAttributes:n}){return[`h${this.options.levels.includes(t.attrs.level)?t.attrs.level:this.options.levels[0]}`,s(this.options.HTMLAttributes,n),0]},addCommands(){return{setHeading:t=>({commands:n})=>this.options.levels.includes(t.level)?n.setNode(this.name,t):!1,toggleHeading:t=>({commands:n})=>this.options.levels.includes(t.level)?n.toggleNode(this.name,"paragraph",t):!1}},addKeyboardShortcuts(){return this.options.levels.reduce((t,n)=>({...t,[`Mod-Alt-${n}`]:()=>this.editor.commands.toggleHeading({level:n})}),{})},addInputRules(){return this.options.levels.map(t=>l({find:new RegExp(`^(#{${Math.min(...this.options.levels)},${t}})\\s$`),type:this.type,getAttributes:{level:t}}))}});var d="__LEPTOS_TIPTAP_BRIDGE__";function u(){let t=globalThis,n=t[d];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[d]=o,o}function p(){return u()}function c(t){p().registerExtension(t)}var g={name:"heading",create:()=>a,commands:{set_heading:(t,n)=>n.kind==="set_heading"?t.chain().focus().setHeading({level:n.level}).run():!1,toggle_heading:(t,n)=>n.kind==="toggle_heading"?t.chain().focus().toggleHeading({level:n.level}).run():!1},selection_keys:["h1","h2","h3","h4","h5","h6"],selection_state:t=>({h1:t.isActive("heading",{level:1}),h2:t.isActive("heading",{level:2}),h3:t.isActive("heading",{level:3}),h4:t.isActive("heading",{level:4}),h5:t.isActive("heading",{level:5}),h6:t.isActive("heading",{level:6})})};function st(){c(g)}export{st as register_heading};
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=i.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var x=e.CommandManager,m=e.Editor,k=e.Extension,b=e.InputRule,y=e.Mark,r=e.Node,h=e.NodePos,f=e.NodeView,E=e.PasteRule,R=e.Tracker,A=e.callOrReturn,P=e.canInsertNode,T=e.combineTransactionSteps,v=e.createChainableState,C=e.createDocument,S=e.createNodeFromContent,w=e.createStyleTag,N=e.defaultBlockAt,O=e.deleteProps,B=e.elementFromString,M=e.escapeForRegEx,I=e.extensions,F=e.findChildren,D=e.findChildrenInRange,j=e.findDuplicates,H=e.findParentNode,L=e.findParentNodeClosestToPos,K=e.fromString,q=e.generateHTML,G=e.generateJSON,$=e.generateText,z=e.getAttributes,J=e.getAttributesFromExtensions,U=e.getChangedRanges,V=e.getDebugJSON,Y=e.getExtensionField,Q=e.getHTMLFromFragment,W=e.getMarkAttributes,X=e.getMarkRange,Z=e.getMarkType,ee=e.getMarksBetween,te=e.getNodeAtPosition,ne=e.getNodeAttributes,oe=e.getNodeType,ie=e.getRenderedAttributes,re=e.getSchema,se=e.getSchemaByResolvedExtensions,le=e.getSchemaTypeByName,ae=e.getSchemaTypeNameByName,de=e.getSplittedAttributes,pe=e.getText,ue=e.getTextBetween,ce=e.getTextContentFromNodes,ge=e.getTextSerializersFromSchema,_e=e.injectExtensionAttributesToParseRule,xe=e.inputRulesPlugin,me=e.isActive,ke=e.isAtEndOfNode,be=e.isAtStartOfNode,ye=e.isEmptyObject,he=e.isExtensionRulesEnabled,fe=e.isFunction,Ee=e.isList,Re=e.isMacOS,Ae=e.isMarkActive,Pe=e.isNodeActive,Te=e.isNodeEmpty,ve=e.isNodeSelection,Ce=e.isNumber,Se=e.isPlainObject,we=e.isRegExp,Ne=e.isSafari,Oe=e.isString,Be=e.isTextSelection,Me=e.isiOS,Ie=e.markInputRule,Fe=e.markPasteRule,s=e.mergeAttributes,De=e.mergeDeep,je=e.minMax,He=e.nodeInputRule,Le=e.nodePasteRule,Ke=e.objectIncludes,qe=e.pasteRulesPlugin,Ge=e.posToDOMRect,$e=e.removeDuplicates,ze=e.resolveFocusPosition,Je=e.rewriteUnknownContent,Ue=e.selectionToInsertionEnd,Ve=e.splitExtensions,Ye=e.textInputRule,Qe=e.textPasteRule,l=e.textblockTypeInputRule,We=e.wrappingInputRule;var a=r.create({name:"heading",addOptions(){return{levels:[1,2,3,4,5,6],HTMLAttributes:{}}},content:"inline*",group:"block",defining:!0,addAttributes(){return{level:{default:1,rendered:!1}}},parseHTML(){return this.options.levels.map(t=>({tag:`h${t}`,attrs:{level:t}}))},renderHTML({node:t,HTMLAttributes:n}){return[`h${this.options.levels.includes(t.attrs.level)?t.attrs.level:this.options.levels[0]}`,s(this.options.HTMLAttributes,n),0]},addCommands(){return{setHeading:t=>({commands:n})=>this.options.levels.includes(t.level)?n.setNode(this.name,t):!1,toggleHeading:t=>({commands:n})=>this.options.levels.includes(t.level)?n.toggleNode(this.name,"paragraph",t):!1}},addKeyboardShortcuts(){return this.options.levels.reduce((t,n)=>({...t,[`Mod-Alt-${n}`]:()=>this.editor.commands.toggleHeading({level:n})}),{})},addInputRules(){return this.options.levels.map(t=>l({find:new RegExp(`^(#{${Math.min(...this.options.levels)},${t}})\\s$`),type:this.type,getAttributes:{level:t}}))}});var d="__LEPTOS_TIPTAP_BRIDGE__";function c(){let t=globalThis,n=t[d];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[d]=o,o}function p(){return c()}function u(t){p().registerExtension(t)}var g={name:"heading",create:()=>a.extend({addAttributes(){return{...this.parent?.(),collapsed:{default:null,parseHTML:t=>{let n=t.getAttribute("data-collapsed");return n==="true"?!0:n==="false"?!1:null},renderHTML:t=>t.collapsed===!0?{"data-collapsed":"true"}:{}}}}}),commands:{set_heading:(t,n)=>n.kind==="set_heading"?t.chain().focus().setHeading({level:n.level,...n.collapsed==null?{}:{collapsed:n.collapsed}}).run():!1,toggle_heading:(t,n)=>n.kind==="toggle_heading"?t.chain().focus().toggleHeading({level:n.level,...n.collapsed==null?{}:{collapsed:n.collapsed}}).run():!1},selection_keys:["h1","h2","h3","h4","h5","h6"],selection_state:t=>({h1:t.isActive("heading",{level:1}),h2:t.isActive("heading",{level:2}),h3:t.isActive("heading",{level:3}),h4:t.isActive("heading",{level:4}),h5:t.isActive("heading",{level:5}),h6:t.isActive("heading",{level:6})})};function st(){u(g)}export{st as register_heading};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var o=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(o==null||o.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=o.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var b=t.CommandManager,h=t.Editor,y=t.Extension,f=t.InputRule,r=t.Mark,R=t.Node,E=t.NodePos,P=t.NodeView,T=t.PasteRule,A=t.Tracker,C=t.callOrReturn,S=t.canInsertNode,N=t.combineTransactionSteps,O=t.createChainableState,B=t.createDocument,w=t.createNodeFromContent,M=t.createStyleTag,v=t.defaultBlockAt,I=t.deleteProps,F=t.elementFromString,D=t.escapeForRegEx,H=t.extensions,j=t.findChildren,L=t.findChildrenInRange,K=t.findDuplicates,q=t.findParentNode,G=t.findParentNodeClosestToPos,z=t.fromString,J=t.generateHTML,U=t.generateJSON,V=t.generateText,Y=t.getAttributes,$=t.getAttributesFromExtensions,Q=t.getChangedRanges,W=t.getDebugJSON,X=t.getExtensionField,Z=t.getHTMLFromFragment,tt=t.getMarkAttributes,et=t.getMarkRange,nt=t.getMarkType,ot=t.getMarksBetween,it=t.getNodeAtPosition,rt=t.getNodeAttributes,st=t.getNodeType,lt=t.getRenderedAttributes,at=t.getSchema,dt=t.getSchemaByResolvedExtensions,pt=t.getSchemaTypeByName,ut=t.getSchemaTypeNameByName,ct=t.getSplittedAttributes,gt=t.getText,_t=t.getTextBetween,xt=t.getTextContentFromNodes,mt=t.getTextSerializersFromSchema,kt=t.injectExtensionAttributesToParseRule,bt=t.inputRulesPlugin,ht=t.isActive,yt=t.isAtEndOfNode,ft=t.isAtStartOfNode,Rt=t.isEmptyObject,Et=t.isExtensionRulesEnabled,Pt=t.isFunction,Tt=t.isList,At=t.isMacOS,Ct=t.isMarkActive,St=t.isNodeActive,Nt=t.isNodeEmpty,Ot=t.isNodeSelection,Bt=t.isNumber,wt=t.isPlainObject,Mt=t.isRegExp,vt=t.isSafari,It=t.isString,Ft=t.isTextSelection,Dt=t.isiOS,s=t.markInputRule,l=t.markPasteRule,a=t.mergeAttributes,Ht=t.mergeDeep,jt=t.minMax,Lt=t.nodeInputRule,Kt=t.nodePasteRule,qt=t.objectIncludes,Gt=t.pasteRulesPlugin,zt=t.posToDOMRect,Jt=t.removeDuplicates,Ut=t.resolveFocusPosition,Vt=t.rewriteUnknownContent,Yt=t.selectionToInsertionEnd,$t=t.splitExtensions,Qt=t.textInputRule,Wt=t.textPasteRule,Xt=t.textblockTypeInputRule,Zt=t.wrappingInputRule;var _=/(?:^|\s)(==(?!\s+==)((?:[^=]+))==(?!\s+==))$/,x=/(?:^|\s)(==(?!\s+==)((?:[^=]+))==(?!\s+==))/g,d=r.create({name:"highlight",addOptions(){return{multicolor:!1,HTMLAttributes:{}}},addAttributes(){return this.options.multicolor?{color:{default:null,parseHTML:e=>e.getAttribute("data-color")||e.style.backgroundColor,renderHTML:e=>e.color?{"data-color":e.color,style:`background-color: ${e.color}; color: inherit`}:{}}}:{}},parseHTML(){return[{tag:"mark"}]},renderHTML({HTMLAttributes:e}){return["mark",a(this.options.HTMLAttributes,e),0]},addCommands(){return{setHighlight:e=>({commands:n})=>n.setMark(this.name,e),toggleHighlight:e=>({commands:n})=>n.toggleMark(this.name,e),unsetHighlight:()=>({commands:e})=>e.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-Shift-h":()=>this.editor.commands.toggleHighlight()}},addInputRules(){return[s({find:_,type:this.type})]},addPasteRules(){return[l({find:x,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function m(){let e=globalThis,n=e[p];if(n!=null)return n;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[p]=i,i}function u(){return m()}function c(e){u().registerExtension(e)}function g(e){if(e?.color!=null)return{color:e.color}}var k={name:"highlight",create:()=>d.configure({multicolor:!0}),commands:{set_highlight:(e,n)=>n.kind==="set_highlight"?e.chain().focus().setHighlight(g(n.attributes)).run():!1,toggle_highlight:(e,n)=>n.kind==="toggle_highlight"?e.chain().focus().toggleHighlight(g(n.attributes)).run():!1,unset_highlight:e=>e.chain().focus().unsetHighlight().run()},selection_keys:["highlight"],selection_state:e=>({highlight:e.isActive("highlight")})};function ae(){c(k)}export{ae as register_highlight};
|
||||
var o=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(o==null||o.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=o.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var b=t.CommandManager,h=t.Editor,y=t.Extension,f=t.InputRule,r=t.Mark,R=t.Node,E=t.NodePos,P=t.NodeView,T=t.PasteRule,A=t.Tracker,C=t.callOrReturn,S=t.canInsertNode,w=t.combineTransactionSteps,N=t.createChainableState,O=t.createDocument,B=t.createNodeFromContent,M=t.createStyleTag,v=t.defaultBlockAt,I=t.deleteProps,F=t.elementFromString,D=t.escapeForRegEx,H=t.extensions,j=t.findChildren,L=t.findChildrenInRange,K=t.findDuplicates,q=t.findParentNode,G=t.findParentNodeClosestToPos,z=t.fromString,J=t.generateHTML,U=t.generateJSON,V=t.generateText,Y=t.getAttributes,$=t.getAttributesFromExtensions,Q=t.getChangedRanges,W=t.getDebugJSON,X=t.getExtensionField,Z=t.getHTMLFromFragment,tt=t.getMarkAttributes,et=t.getMarkRange,nt=t.getMarkType,ot=t.getMarksBetween,it=t.getNodeAtPosition,rt=t.getNodeAttributes,st=t.getNodeType,lt=t.getRenderedAttributes,at=t.getSchema,dt=t.getSchemaByResolvedExtensions,pt=t.getSchemaTypeByName,ut=t.getSchemaTypeNameByName,ct=t.getSplittedAttributes,gt=t.getText,_t=t.getTextBetween,xt=t.getTextContentFromNodes,mt=t.getTextSerializersFromSchema,kt=t.injectExtensionAttributesToParseRule,bt=t.inputRulesPlugin,ht=t.isActive,yt=t.isAtEndOfNode,ft=t.isAtStartOfNode,Rt=t.isEmptyObject,Et=t.isExtensionRulesEnabled,Pt=t.isFunction,Tt=t.isList,At=t.isMacOS,Ct=t.isMarkActive,St=t.isNodeActive,wt=t.isNodeEmpty,Nt=t.isNodeSelection,Ot=t.isNumber,Bt=t.isPlainObject,Mt=t.isRegExp,vt=t.isSafari,It=t.isString,Ft=t.isTextSelection,Dt=t.isiOS,s=t.markInputRule,l=t.markPasteRule,a=t.mergeAttributes,Ht=t.mergeDeep,jt=t.minMax,Lt=t.nodeInputRule,Kt=t.nodePasteRule,qt=t.objectIncludes,Gt=t.pasteRulesPlugin,zt=t.posToDOMRect,Jt=t.removeDuplicates,Ut=t.resolveFocusPosition,Vt=t.rewriteUnknownContent,Yt=t.selectionToInsertionEnd,$t=t.splitExtensions,Qt=t.textInputRule,Wt=t.textPasteRule,Xt=t.textblockTypeInputRule,Zt=t.wrappingInputRule;var _=/(?:^|\s)(==(?!\s+==)((?:[^=]+))==(?!\s+==))$/,x=/(?:^|\s)(==(?!\s+==)((?:[^=]+))==(?!\s+==))/g,d=r.create({name:"highlight",addOptions(){return{multicolor:!1,HTMLAttributes:{}}},addAttributes(){return this.options.multicolor?{color:{default:null,parseHTML:e=>e.getAttribute("data-color")||e.style.backgroundColor,renderHTML:e=>e.color?{"data-color":e.color,style:`background-color: ${e.color}; color: inherit`}:{}}}:{}},parseHTML(){return[{tag:"mark"}]},renderHTML({HTMLAttributes:e}){return["mark",a(this.options.HTMLAttributes,e),0]},addCommands(){return{setHighlight:e=>({commands:n})=>n.setMark(this.name,e),toggleHighlight:e=>({commands:n})=>n.toggleMark(this.name,e),unsetHighlight:()=>({commands:e})=>e.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-Shift-h":()=>this.editor.commands.toggleHighlight()}},addInputRules(){return[s({find:_,type:this.type})]},addPasteRules(){return[l({find:x,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function m(){let e=globalThis,n=e[p];if(n!=null)return n;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[p]=i,i}function u(){return m()}function c(e){u().registerExtension(e)}function g(e){if(e?.color!=null)return{color:e.color}}var k={name:"highlight",create:()=>d.configure({multicolor:!0}),commands:{set_highlight:(e,n)=>n.kind==="set_highlight"?e.chain().focus().setHighlight(g(n.attributes)).run():!1,toggle_highlight:(e,n)=>n.kind==="toggle_highlight"?e.chain().focus().toggleHighlight(g(n.attributes)).run():!1,unset_highlight:e=>e.chain().focus().unsetHighlight().run()},selection_keys:["highlight"],selection_state:e=>({highlight:e.isActive("highlight")})};function ae(){c(k)}export{ae as register_highlight};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var r=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(r==null||r.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=r.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,l=t.Extension,y=t.InputRule,h=t.Mark,E=t.Node,f=t.NodePos,R=t.NodeView,P=t.PasteRule,S=t.Tracker,T=t.callOrReturn,C=t.canInsertNode,A=t.combineTransactionSteps,N=t.createChainableState,O=t.createDocument,w=t.createNodeFromContent,B=t.createStyleTag,v=t.defaultBlockAt,M=t.deleteProps,D=t.elementFromString,I=t.escapeForRegEx,F=t.extensions,j=t.findChildren,H=t.findChildrenInRange,L=t.findDuplicates,K=t.findParentNode,G=t.findParentNodeClosestToPos,q=t.fromString,z=t.generateHTML,J=t.generateJSON,U=t.generateText,V=t.getAttributes,Y=t.getAttributesFromExtensions,Q=t.getChangedRanges,W=t.getDebugJSON,X=t.getExtensionField,Z=t.getHTMLFromFragment,$=t.getMarkAttributes,tt=t.getMarkRange,et=t.getMarkType,nt=t.getMarksBetween,ot=t.getNodeAtPosition,rt=t.getNodeAttributes,it=t.getNodeType,st=t.getRenderedAttributes,lt=t.getSchema,at=t.getSchemaByResolvedExtensions,dt=t.getSchemaTypeByName,pt=t.getSchemaTypeNameByName,ct=t.getSplittedAttributes,ut=t.getText,gt=t.getTextBetween,_t=t.getTextContentFromNodes,xt=t.getTextSerializersFromSchema,mt=t.injectExtensionAttributesToParseRule,kt=t.inputRulesPlugin,bt=t.isActive,yt=t.isAtEndOfNode,ht=t.isAtStartOfNode,Et=t.isEmptyObject,ft=t.isExtensionRulesEnabled,Rt=t.isFunction,Pt=t.isList,St=t.isMacOS,Tt=t.isMarkActive,Ct=t.isNodeActive,At=t.isNodeEmpty,Nt=t.isNodeSelection,Ot=t.isNumber,wt=t.isPlainObject,Bt=t.isRegExp,vt=t.isSafari,Mt=t.isString,Dt=t.isTextSelection,It=t.isiOS,Ft=t.markInputRule,jt=t.markPasteRule,Ht=t.mergeAttributes,Lt=t.mergeDeep,Kt=t.minMax,Gt=t.nodeInputRule,qt=t.nodePasteRule,zt=t.objectIncludes,Jt=t.pasteRulesPlugin,Ut=t.posToDOMRect,Vt=t.removeDuplicates,Yt=t.resolveFocusPosition,Qt=t.rewriteUnknownContent,Wt=t.selectionToInsertionEnd,Xt=t.splitExtensions,Zt=t.textInputRule,$t=t.textPasteRule,te=t.textblockTypeInputRule,ee=t.wrappingInputRule;var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var n=i.modules["@tiptap/pm/history"];if(n==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/history" is unavailable');var oe=n.closeHistory,a=n.history,re=n.isHistoryTransaction,d=n.redo,ie=n.redoDepth,se=n.redoNoScroll,p=n.undo,le=n.undoDepth,ae=n.undoNoScroll;var c=l.create({name:"history",addOptions(){return{depth:100,newGroupDelay:500}},addCommands(){return{undo:()=>({state:e,dispatch:o})=>p(e,o),redo:()=>({state:e,dispatch:o})=>d(e,o)}},addProseMirrorPlugins(){return[a(this.options)]},addKeyboardShortcuts(){return{"Mod-z":()=>this.editor.commands.undo(),"Shift-Mod-z":()=>this.editor.commands.redo(),"Mod-y":()=>this.editor.commands.redo(),"Mod-\u044F":()=>this.editor.commands.undo(),"Shift-Mod-\u044F":()=>this.editor.commands.redo()}}});var u="__LEPTOS_TIPTAP_BRIDGE__";function x(){let e=globalThis,o=e[u];if(o!=null)return o;let s={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[u]=s,s}function g(){return x()}function _(e){g().registerExtension(e)}var m={name:"history",create:()=>c,commands:{undo:e=>e.chain().focus().undo().run(),redo:e=>e.chain().focus().redo().run()}};function be(){_(m)}export{be as register_history};
|
||||
var r=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(r==null||r.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=r.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,l=t.Extension,y=t.InputRule,h=t.Mark,E=t.Node,f=t.NodePos,R=t.NodeView,P=t.PasteRule,S=t.Tracker,T=t.callOrReturn,C=t.canInsertNode,A=t.combineTransactionSteps,w=t.createChainableState,N=t.createDocument,O=t.createNodeFromContent,B=t.createStyleTag,v=t.defaultBlockAt,M=t.deleteProps,D=t.elementFromString,I=t.escapeForRegEx,F=t.extensions,j=t.findChildren,H=t.findChildrenInRange,L=t.findDuplicates,K=t.findParentNode,G=t.findParentNodeClosestToPos,q=t.fromString,z=t.generateHTML,J=t.generateJSON,U=t.generateText,V=t.getAttributes,Y=t.getAttributesFromExtensions,Q=t.getChangedRanges,W=t.getDebugJSON,X=t.getExtensionField,Z=t.getHTMLFromFragment,$=t.getMarkAttributes,tt=t.getMarkRange,et=t.getMarkType,nt=t.getMarksBetween,ot=t.getNodeAtPosition,rt=t.getNodeAttributes,it=t.getNodeType,st=t.getRenderedAttributes,lt=t.getSchema,at=t.getSchemaByResolvedExtensions,dt=t.getSchemaTypeByName,pt=t.getSchemaTypeNameByName,ct=t.getSplittedAttributes,ut=t.getText,gt=t.getTextBetween,_t=t.getTextContentFromNodes,xt=t.getTextSerializersFromSchema,mt=t.injectExtensionAttributesToParseRule,kt=t.inputRulesPlugin,bt=t.isActive,yt=t.isAtEndOfNode,ht=t.isAtStartOfNode,Et=t.isEmptyObject,ft=t.isExtensionRulesEnabled,Rt=t.isFunction,Pt=t.isList,St=t.isMacOS,Tt=t.isMarkActive,Ct=t.isNodeActive,At=t.isNodeEmpty,wt=t.isNodeSelection,Nt=t.isNumber,Ot=t.isPlainObject,Bt=t.isRegExp,vt=t.isSafari,Mt=t.isString,Dt=t.isTextSelection,It=t.isiOS,Ft=t.markInputRule,jt=t.markPasteRule,Ht=t.mergeAttributes,Lt=t.mergeDeep,Kt=t.minMax,Gt=t.nodeInputRule,qt=t.nodePasteRule,zt=t.objectIncludes,Jt=t.pasteRulesPlugin,Ut=t.posToDOMRect,Vt=t.removeDuplicates,Yt=t.resolveFocusPosition,Qt=t.rewriteUnknownContent,Wt=t.selectionToInsertionEnd,Xt=t.splitExtensions,Zt=t.textInputRule,$t=t.textPasteRule,te=t.textblockTypeInputRule,ee=t.wrappingInputRule;var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var n=i.modules["@tiptap/pm/history"];if(n==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/history" is unavailable');var oe=n.closeHistory,a=n.history,re=n.isHistoryTransaction,d=n.redo,ie=n.redoDepth,se=n.redoNoScroll,p=n.undo,le=n.undoDepth,ae=n.undoNoScroll;var c=l.create({name:"history",addOptions(){return{depth:100,newGroupDelay:500}},addCommands(){return{undo:()=>({state:e,dispatch:o})=>p(e,o),redo:()=>({state:e,dispatch:o})=>d(e,o)}},addProseMirrorPlugins(){return[a(this.options)]},addKeyboardShortcuts(){return{"Mod-z":()=>this.editor.commands.undo(),"Shift-Mod-z":()=>this.editor.commands.redo(),"Mod-y":()=>this.editor.commands.redo(),"Mod-\u044F":()=>this.editor.commands.undo(),"Shift-Mod-\u044F":()=>this.editor.commands.redo()}}});var u="__LEPTOS_TIPTAP_BRIDGE__";function x(){let e=globalThis,o=e[u];if(o!=null)return o;let s={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[u]=s,s}function g(){return x()}function _(e){g().registerExtension(e)}var m={name:"history",create:()=>c,commands:{undo:e=>e.chain().focus().undo().run(),redo:e=>e.chain().focus().redo().run()}};function be(){_(m)}export{be as register_history};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var d=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(d==null||d.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=d.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var N=e.CommandManager,O=e.Editor,B=e.Extension,w=e.InputRule,v=e.Mark,m=e.Node,I=e.NodePos,M=e.NodeView,F=e.PasteRule,D=e.Tracker,j=e.callOrReturn,k=e.canInsertNode,L=e.combineTransactionSteps,H=e.createChainableState,K=e.createDocument,z=e.createNodeFromContent,G=e.createStyleTag,q=e.defaultBlockAt,$=e.deleteProps,J=e.elementFromString,V=e.escapeForRegEx,U=e.extensions,Y=e.findChildren,Q=e.findChildrenInRange,W=e.findDuplicates,X=e.findParentNode,Z=e.findParentNodeClosestToPos,ee=e.fromString,te=e.generateHTML,ne=e.generateJSON,oe=e.generateText,ie=e.getAttributes,re=e.getAttributesFromExtensions,se=e.getChangedRanges,le=e.getDebugJSON,ae=e.getExtensionField,pe=e.getHTMLFromFragment,de=e.getMarkAttributes,ce=e.getMarkRange,ue=e.getMarkType,ge=e.getMarksBetween,_e=e.getNodeAtPosition,xe=e.getNodeAttributes,me=e.getNodeType,ke=e.getRenderedAttributes,be=e.getSchema,ye=e.getSchemaByResolvedExtensions,fe=e.getSchemaTypeByName,he=e.getSchemaTypeNameByName,Ee=e.getSplittedAttributes,Re=e.getText,Se=e.getTextBetween,Te=e.getTextContentFromNodes,Pe=e.getTextSerializersFromSchema,Ae=e.injectExtensionAttributesToParseRule,Ce=e.inputRulesPlugin,Ne=e.isActive,Oe=e.isAtEndOfNode,Be=e.isAtStartOfNode,we=e.isEmptyObject,ve=e.isExtensionRulesEnabled,Ie=e.isFunction,Me=e.isList,Fe=e.isMacOS,De=e.isMarkActive,je=e.isNodeActive,Le=e.isNodeEmpty,b=e.isNodeSelection,He=e.isNumber,Ke=e.isPlainObject,ze=e.isRegExp,Ge=e.isSafari,qe=e.isString,$e=e.isTextSelection,Je=e.isiOS,Ve=e.markInputRule,Ue=e.markPasteRule,y=e.mergeAttributes,Ye=e.mergeDeep,Qe=e.minMax,f=e.nodeInputRule,We=e.nodePasteRule,Xe=e.objectIncludes,Ze=e.pasteRulesPlugin,et=e.posToDOMRect,tt=e.removeDuplicates,nt=e.resolveFocusPosition,ot=e.rewriteUnknownContent,it=e.selectionToInsertionEnd,rt=e.splitExtensions,st=e.textInputRule,lt=e.textPasteRule,at=e.textblockTypeInputRule,pt=e.wrappingInputRule;var c=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(c==null||c.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var o=c.modules["@tiptap/pm/state"];if(o==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/state" is unavailable');var ct=o.AllSelection,ut=o.EditorState,h=o.NodeSelection,gt=o.Plugin,_t=o.PluginKey,xt=o.Selection,mt=o.SelectionRange,a=o.TextSelection,kt=o.Transaction;var E=m.create({name:"horizontalRule",addOptions(){return{HTMLAttributes:{}}},group:"block",parseHTML(){return[{tag:"hr"}]},renderHTML({HTMLAttributes:n}){return["hr",y(this.options.HTMLAttributes,n)]},addCommands(){return{setHorizontalRule:()=>({chain:n,state:r})=>{if(!k(r,r.schema.nodes[this.name]))return!1;let{selection:s}=r,{$from:u,$to:g}=s,l=n();return u.parentOffset===0?l.insertContentAt({from:Math.max(u.pos-1,0),to:g.pos},{type:this.name}):b(s)?l.insertContentAt(g.pos,{type:this.name}):l.insertContent({type:this.name}),l.command(({tr:t,dispatch:P})=>{var p;if(P){let{$to:i}=t.selection,_=i.end();if(i.nodeAfter)i.nodeAfter.isTextblock?t.setSelection(a.create(t.doc,i.pos+1)):i.nodeAfter.isBlock?t.setSelection(h.create(t.doc,i.pos)):t.setSelection(a.create(t.doc,i.pos));else{let x=(p=i.parent.type.contentMatch.defaultType)===null||p===void 0?void 0:p.create();x&&(t.insert(_,x),t.setSelection(a.create(t.doc,_+1)))}t.scrollIntoView()}return!0}).run()}}},addInputRules(){return[f({find:/^(?:---|—-|___\s|\*\*\*\s)$/,type:this.type})]}});var R="__LEPTOS_TIPTAP_BRIDGE__";function A(){let n=globalThis,r=n[R];if(r!=null)return r;let s={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return n[R]=s,s}function S(){return A()}function T(n){S().registerExtension(n)}var C={name:"horizontal_rule",create:()=>E,commands:{set_horizontal_rule:n=>n.chain().focus().setHorizontalRule().run()}};function At(){T(C)}export{At as register_horizontal_rule};
|
||||
var p=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(p==null||p.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=p.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var w=e.CommandManager,N=e.Editor,O=e.Extension,B=e.InputRule,v=e.Mark,m=e.Node,I=e.NodePos,M=e.NodeView,F=e.PasteRule,D=e.Tracker,j=e.callOrReturn,k=e.canInsertNode,L=e.combineTransactionSteps,H=e.createChainableState,K=e.createDocument,z=e.createNodeFromContent,G=e.createStyleTag,q=e.defaultBlockAt,$=e.deleteProps,J=e.elementFromString,V=e.escapeForRegEx,U=e.extensions,Y=e.findChildren,Q=e.findChildrenInRange,W=e.findDuplicates,X=e.findParentNode,Z=e.findParentNodeClosestToPos,ee=e.fromString,te=e.generateHTML,ne=e.generateJSON,oe=e.generateText,ie=e.getAttributes,re=e.getAttributesFromExtensions,se=e.getChangedRanges,le=e.getDebugJSON,ae=e.getExtensionField,de=e.getHTMLFromFragment,pe=e.getMarkAttributes,ce=e.getMarkRange,ue=e.getMarkType,ge=e.getMarksBetween,_e=e.getNodeAtPosition,xe=e.getNodeAttributes,me=e.getNodeType,ke=e.getRenderedAttributes,be=e.getSchema,ye=e.getSchemaByResolvedExtensions,he=e.getSchemaTypeByName,fe=e.getSchemaTypeNameByName,Ee=e.getSplittedAttributes,Re=e.getText,Se=e.getTextBetween,Te=e.getTextContentFromNodes,Pe=e.getTextSerializersFromSchema,Ae=e.injectExtensionAttributesToParseRule,Ce=e.inputRulesPlugin,we=e.isActive,Ne=e.isAtEndOfNode,Oe=e.isAtStartOfNode,Be=e.isEmptyObject,ve=e.isExtensionRulesEnabled,Ie=e.isFunction,Me=e.isList,Fe=e.isMacOS,De=e.isMarkActive,je=e.isNodeActive,Le=e.isNodeEmpty,b=e.isNodeSelection,He=e.isNumber,Ke=e.isPlainObject,ze=e.isRegExp,Ge=e.isSafari,qe=e.isString,$e=e.isTextSelection,Je=e.isiOS,Ve=e.markInputRule,Ue=e.markPasteRule,y=e.mergeAttributes,Ye=e.mergeDeep,Qe=e.minMax,h=e.nodeInputRule,We=e.nodePasteRule,Xe=e.objectIncludes,Ze=e.pasteRulesPlugin,et=e.posToDOMRect,tt=e.removeDuplicates,nt=e.resolveFocusPosition,ot=e.rewriteUnknownContent,it=e.selectionToInsertionEnd,rt=e.splitExtensions,st=e.textInputRule,lt=e.textPasteRule,at=e.textblockTypeInputRule,dt=e.wrappingInputRule;var c=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(c==null||c.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var o=c.modules["@tiptap/pm/state"];if(o==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/state" is unavailable');var ct=o.AllSelection,ut=o.EditorState,f=o.NodeSelection,gt=o.Plugin,_t=o.PluginKey,xt=o.Selection,mt=o.SelectionRange,a=o.TextSelection,kt=o.Transaction;var E=m.create({name:"horizontalRule",addOptions(){return{HTMLAttributes:{}}},group:"block",parseHTML(){return[{tag:"hr"}]},renderHTML({HTMLAttributes:n}){return["hr",y(this.options.HTMLAttributes,n)]},addCommands(){return{setHorizontalRule:()=>({chain:n,state:r})=>{if(!k(r,r.schema.nodes[this.name]))return!1;let{selection:s}=r,{$from:u,$to:g}=s,l=n();return u.parentOffset===0?l.insertContentAt({from:Math.max(u.pos-1,0),to:g.pos},{type:this.name}):b(s)?l.insertContentAt(g.pos,{type:this.name}):l.insertContent({type:this.name}),l.command(({tr:t,dispatch:P})=>{var d;if(P){let{$to:i}=t.selection,_=i.end();if(i.nodeAfter)i.nodeAfter.isTextblock?t.setSelection(a.create(t.doc,i.pos+1)):i.nodeAfter.isBlock?t.setSelection(f.create(t.doc,i.pos)):t.setSelection(a.create(t.doc,i.pos));else{let x=(d=i.parent.type.contentMatch.defaultType)===null||d===void 0?void 0:d.create();x&&(t.insert(_,x),t.setSelection(a.create(t.doc,_+1)))}t.scrollIntoView()}return!0}).run()}}},addInputRules(){return[h({find:/^(?:---|—-|___\s|\*\*\*\s)$/,type:this.type})]}});var R="__LEPTOS_TIPTAP_BRIDGE__";function A(){let n=globalThis,r=n[R];if(r!=null)return r;let s={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return n[R]=s,s}function S(){return A()}function T(n){S().registerExtension(n)}var C={name:"horizontal_rule",create:()=>E,commands:{set_horizontal_rule:n=>n.chain().focus().setHorizontalRule().run()}};function At(){T(C)}export{At as register_horizontal_rule};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=i.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,y=t.Extension,f=t.InputRule,E=t.Mark,r=t.Node,h=t.NodePos,R=t.NodeView,P=t.PasteRule,C=t.Tracker,A=t.callOrReturn,T=t.canInsertNode,S=t.combineTransactionSteps,N=t.createChainableState,O=t.createDocument,B=t.createNodeFromContent,w=t.createStyleTag,I=t.defaultBlockAt,v=t.deleteProps,M=t.elementFromString,F=t.escapeForRegEx,D=t.extensions,j=t.findChildren,L=t.findChildrenInRange,H=t.findDuplicates,K=t.findParentNode,q=t.findParentNodeClosestToPos,G=t.fromString,z=t.generateHTML,J=t.generateJSON,U=t.generateText,V=t.getAttributes,Y=t.getAttributesFromExtensions,$=t.getChangedRanges,Q=t.getDebugJSON,W=t.getExtensionField,X=t.getHTMLFromFragment,Z=t.getMarkAttributes,tt=t.getMarkRange,et=t.getMarkType,nt=t.getMarksBetween,ot=t.getNodeAtPosition,it=t.getNodeAttributes,rt=t.getNodeType,st=t.getRenderedAttributes,lt=t.getSchema,at=t.getSchemaByResolvedExtensions,dt=t.getSchemaTypeByName,pt=t.getSchemaTypeNameByName,ut=t.getSplittedAttributes,ct=t.getText,gt=t.getTextBetween,_t=t.getTextContentFromNodes,xt=t.getTextSerializersFromSchema,mt=t.injectExtensionAttributesToParseRule,kt=t.inputRulesPlugin,bt=t.isActive,yt=t.isAtEndOfNode,ft=t.isAtStartOfNode,Et=t.isEmptyObject,ht=t.isExtensionRulesEnabled,Rt=t.isFunction,Pt=t.isList,Ct=t.isMacOS,At=t.isMarkActive,Tt=t.isNodeActive,St=t.isNodeEmpty,Nt=t.isNodeSelection,Ot=t.isNumber,Bt=t.isPlainObject,wt=t.isRegExp,It=t.isSafari,vt=t.isString,Mt=t.isTextSelection,Ft=t.isiOS,Dt=t.markInputRule,jt=t.markPasteRule,s=t.mergeAttributes,Lt=t.mergeDeep,Ht=t.minMax,l=t.nodeInputRule,Kt=t.nodePasteRule,qt=t.objectIncludes,Gt=t.pasteRulesPlugin,zt=t.posToDOMRect,Jt=t.removeDuplicates,Ut=t.resolveFocusPosition,Vt=t.rewriteUnknownContent,Yt=t.selectionToInsertionEnd,$t=t.splitExtensions,Qt=t.textInputRule,Wt=t.textPasteRule,Xt=t.textblockTypeInputRule,Zt=t.wrappingInputRule;var g=/(?:^|\s)(!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\))$/,a=r.create({name:"image",addOptions(){return{inline:!1,allowBase64:!1,HTMLAttributes:{}}},inline(){return this.options.inline},group(){return this.options.inline?"inline":"block"},draggable:!0,addAttributes(){return{src:{default:null},alt:{default:null},title:{default:null}}},parseHTML(){return[{tag:this.options.allowBase64?"img[src]":'img[src]:not([src^="data:"])'}]},renderHTML({HTMLAttributes:e}){return["img",s(this.options.HTMLAttributes,e)]},addCommands(){return{setImage:e=>({commands:n})=>n.insertContent({type:this.name,attrs:e})}},addInputRules(){return[l({find:g,type:this.type,getAttributes:e=>{let[,,n,o,c]=e;return{src:o,alt:n,title:c}}})]}});var d="__LEPTOS_TIPTAP_BRIDGE__";function _(){let e=globalThis,n=e[d];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[d]=o,o}function p(){return _()}function u(e){p().registerExtension(e)}function x(e){return{src:e.src,alt:e.alt??void 0,title:e.title??void 0}}var m={name:"image",create:()=>a,commands:{set_image:(e,n)=>n.kind==="set_image"?e.chain().focus().setImage(x(n)).run():!1}};function ae(){u(m)}export{ae as register_image};
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=i.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var b=t.CommandManager,y=t.Editor,f=t.Extension,h=t.InputRule,E=t.Mark,r=t.Node,R=t.NodePos,P=t.NodeView,T=t.PasteRule,A=t.Tracker,C=t.callOrReturn,S=t.canInsertNode,w=t.combineTransactionSteps,N=t.createChainableState,O=t.createDocument,B=t.createNodeFromContent,I=t.createStyleTag,M=t.defaultBlockAt,v=t.deleteProps,F=t.elementFromString,D=t.escapeForRegEx,j=t.extensions,L=t.findChildren,H=t.findChildrenInRange,K=t.findDuplicates,q=t.findParentNode,G=t.findParentNodeClosestToPos,z=t.fromString,J=t.generateHTML,U=t.generateJSON,V=t.generateText,Y=t.getAttributes,$=t.getAttributesFromExtensions,Q=t.getChangedRanges,W=t.getDebugJSON,X=t.getExtensionField,Z=t.getHTMLFromFragment,tt=t.getMarkAttributes,et=t.getMarkRange,nt=t.getMarkType,ot=t.getMarksBetween,it=t.getNodeAtPosition,rt=t.getNodeAttributes,st=t.getNodeType,lt=t.getRenderedAttributes,at=t.getSchema,dt=t.getSchemaByResolvedExtensions,pt=t.getSchemaTypeByName,ut=t.getSchemaTypeNameByName,ct=t.getSplittedAttributes,gt=t.getText,_t=t.getTextBetween,mt=t.getTextContentFromNodes,xt=t.getTextSerializersFromSchema,kt=t.injectExtensionAttributesToParseRule,bt=t.inputRulesPlugin,yt=t.isActive,ft=t.isAtEndOfNode,ht=t.isAtStartOfNode,Et=t.isEmptyObject,Rt=t.isExtensionRulesEnabled,Pt=t.isFunction,Tt=t.isList,At=t.isMacOS,Ct=t.isMarkActive,St=t.isNodeActive,wt=t.isNodeEmpty,Nt=t.isNodeSelection,Ot=t.isNumber,Bt=t.isPlainObject,It=t.isRegExp,Mt=t.isSafari,vt=t.isString,Ft=t.isTextSelection,Dt=t.isiOS,jt=t.markInputRule,Lt=t.markPasteRule,s=t.mergeAttributes,Ht=t.mergeDeep,Kt=t.minMax,l=t.nodeInputRule,qt=t.nodePasteRule,Gt=t.objectIncludes,zt=t.pasteRulesPlugin,Jt=t.posToDOMRect,Ut=t.removeDuplicates,Vt=t.resolveFocusPosition,Yt=t.rewriteUnknownContent,$t=t.selectionToInsertionEnd,Qt=t.splitExtensions,Wt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,te=t.wrappingInputRule;var g=/(?:^|\s)(!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\))$/,a=r.create({name:"image",addOptions(){return{inline:!1,allowBase64:!1,HTMLAttributes:{}}},inline(){return this.options.inline},group(){return this.options.inline?"inline":"block"},draggable:!0,addAttributes(){return{src:{default:null},alt:{default:null},title:{default:null}}},parseHTML(){return[{tag:this.options.allowBase64?"img[src]":'img[src]:not([src^="data:"])'}]},renderHTML({HTMLAttributes:e}){return["img",s(this.options.HTMLAttributes,e)]},addCommands(){return{setImage:e=>({commands:n})=>n.insertContent({type:this.name,attrs:e})}},addInputRules(){return[l({find:g,type:this.type,getAttributes:e=>{let[,,n,o,c]=e;return{src:o,alt:n,title:c}}})]}});var d="__LEPTOS_TIPTAP_BRIDGE__";function _(){let e=globalThis,n=e[d];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[d]=o,o}function p(){return _()}function u(e){p().registerExtension(e)}function m(e){return{src:e.src,alt:e.alt??void 0,title:e.title??void 0}}var x=a.extend({addAttributes(){return{...this.parent?.(),"data-align":{default:null,parseHTML:e=>e.getAttribute("data-align"),renderHTML:e=>{let n=e["data-align"];return typeof n=="string"&&n.length>0?{"data-align":n}:{}}}}}}),k={name:"image",create:()=>x,commands:{set_image:(e,n)=>n.kind==="set_image"?e.chain().focus().setImage(m(n)).run():!1}};function de(){u(k)}export{de as register_image};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var y=t.CommandManager,h=t.Editor,R=t.Extension,f=t.InputRule,a=t.Mark,E=t.Node,P=t.NodePos,C=t.NodeView,T=t.PasteRule,A=t.Tracker,S=t.callOrReturn,N=t.canInsertNode,O=t.combineTransactionSteps,I=t.createChainableState,B=t.createDocument,w=t.createNodeFromContent,M=t.createStyleTag,v=t.defaultBlockAt,F=t.deleteProps,D=t.elementFromString,j=t.escapeForRegEx,L=t.extensions,K=t.findChildren,H=t.findChildrenInRange,q=t.findDuplicates,G=t.findParentNode,z=t.findParentNodeClosestToPos,J=t.fromString,U=t.generateHTML,V=t.generateJSON,Y=t.generateText,$=t.getAttributes,Q=t.getAttributesFromExtensions,W=t.getChangedRanges,X=t.getDebugJSON,Z=t.getExtensionField,tt=t.getHTMLFromFragment,et=t.getMarkAttributes,nt=t.getMarkRange,ot=t.getMarkType,it=t.getMarksBetween,rt=t.getNodeAtPosition,st=t.getNodeAttributes,at=t.getNodeType,lt=t.getRenderedAttributes,dt=t.getSchema,pt=t.getSchemaByResolvedExtensions,ct=t.getSchemaTypeByName,ut=t.getSchemaTypeNameByName,gt=t.getSplittedAttributes,_t=t.getText,xt=t.getTextBetween,mt=t.getTextContentFromNodes,kt=t.getTextSerializersFromSchema,bt=t.injectExtensionAttributesToParseRule,yt=t.inputRulesPlugin,ht=t.isActive,Rt=t.isAtEndOfNode,ft=t.isAtStartOfNode,Et=t.isEmptyObject,Pt=t.isExtensionRulesEnabled,Ct=t.isFunction,Tt=t.isList,At=t.isMacOS,St=t.isMarkActive,Nt=t.isNodeActive,Ot=t.isNodeEmpty,It=t.isNodeSelection,Bt=t.isNumber,wt=t.isPlainObject,Mt=t.isRegExp,vt=t.isSafari,Ft=t.isString,Dt=t.isTextSelection,jt=t.isiOS,o=t.markInputRule,i=t.markPasteRule,l=t.mergeAttributes,Lt=t.mergeDeep,Kt=t.minMax,Ht=t.nodeInputRule,qt=t.nodePasteRule,Gt=t.objectIncludes,zt=t.pasteRulesPlugin,Jt=t.posToDOMRect,Ut=t.removeDuplicates,Vt=t.resolveFocusPosition,Yt=t.rewriteUnknownContent,$t=t.selectionToInsertionEnd,Qt=t.splitExtensions,Wt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,te=t.wrappingInputRule;var g=/(?:^|\s)(\*(?!\s+\*)((?:[^*]+))\*(?!\s+\*))$/,_=/(?:^|\s)(\*(?!\s+\*)((?:[^*]+))\*(?!\s+\*))/g,x=/(?:^|\s)(_(?!\s+_)((?:[^_]+))_(?!\s+_))$/,m=/(?:^|\s)(_(?!\s+_)((?:[^_]+))_(?!\s+_))/g,d=a.create({name:"italic",addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"em"},{tag:"i",getAttrs:e=>e.style.fontStyle!=="normal"&&null},{style:"font-style=normal",clearMark:e=>e.type.name===this.name},{style:"font-style=italic"}]},renderHTML({HTMLAttributes:e}){return["em",l(this.options.HTMLAttributes,e),0]},addCommands(){return{setItalic:()=>({commands:e})=>e.setMark(this.name),toggleItalic:()=>({commands:e})=>e.toggleMark(this.name),unsetItalic:()=>({commands:e})=>e.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-i":()=>this.editor.commands.toggleItalic(),"Mod-I":()=>this.editor.commands.toggleItalic()}},addInputRules(){return[o({find:g,type:this.type}),o({find:x,type:this.type})]},addPasteRules(){return[i({find:_,type:this.type}),i({find:m,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function k(){let e=globalThis,r=e[p];if(r!=null)return r;let s={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[p]=s,s}function c(){return k()}function u(e){c().registerExtension(e)}var b={name:"italic",create:()=>d,commands:{set_italic:e=>e.chain().focus().setItalic().run(),toggle_italic:e=>e.chain().focus().toggleItalic().run(),unset_italic:e=>e.chain().focus().unsetItalic().run()},selection_keys:["italic"],selection_state:e=>({italic:e.isActive("italic")})};function de(){u(b)}export{de as register_italic};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var y=t.CommandManager,h=t.Editor,f=t.Extension,R=t.InputRule,l=t.Mark,E=t.Node,P=t.NodePos,C=t.NodeView,T=t.PasteRule,A=t.Tracker,S=t.callOrReturn,w=t.canInsertNode,N=t.combineTransactionSteps,O=t.createChainableState,I=t.createDocument,B=t.createNodeFromContent,M=t.createStyleTag,v=t.defaultBlockAt,F=t.deleteProps,D=t.elementFromString,j=t.escapeForRegEx,L=t.extensions,K=t.findChildren,H=t.findChildrenInRange,q=t.findDuplicates,G=t.findParentNode,z=t.findParentNodeClosestToPos,J=t.fromString,U=t.generateHTML,V=t.generateJSON,Y=t.generateText,$=t.getAttributes,Q=t.getAttributesFromExtensions,W=t.getChangedRanges,X=t.getDebugJSON,Z=t.getExtensionField,tt=t.getHTMLFromFragment,et=t.getMarkAttributes,nt=t.getMarkRange,ot=t.getMarkType,it=t.getMarksBetween,rt=t.getNodeAtPosition,st=t.getNodeAttributes,lt=t.getNodeType,at=t.getRenderedAttributes,dt=t.getSchema,pt=t.getSchemaByResolvedExtensions,ct=t.getSchemaTypeByName,ut=t.getSchemaTypeNameByName,gt=t.getSplittedAttributes,_t=t.getText,mt=t.getTextBetween,xt=t.getTextContentFromNodes,kt=t.getTextSerializersFromSchema,bt=t.injectExtensionAttributesToParseRule,yt=t.inputRulesPlugin,ht=t.isActive,ft=t.isAtEndOfNode,Rt=t.isAtStartOfNode,Et=t.isEmptyObject,Pt=t.isExtensionRulesEnabled,Ct=t.isFunction,Tt=t.isList,At=t.isMacOS,St=t.isMarkActive,wt=t.isNodeActive,Nt=t.isNodeEmpty,Ot=t.isNodeSelection,It=t.isNumber,Bt=t.isPlainObject,Mt=t.isRegExp,vt=t.isSafari,Ft=t.isString,Dt=t.isTextSelection,jt=t.isiOS,o=t.markInputRule,i=t.markPasteRule,a=t.mergeAttributes,Lt=t.mergeDeep,Kt=t.minMax,Ht=t.nodeInputRule,qt=t.nodePasteRule,Gt=t.objectIncludes,zt=t.pasteRulesPlugin,Jt=t.posToDOMRect,Ut=t.removeDuplicates,Vt=t.resolveFocusPosition,Yt=t.rewriteUnknownContent,$t=t.selectionToInsertionEnd,Qt=t.splitExtensions,Wt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,te=t.wrappingInputRule;var g=/(?:^|\s)(\*(?!\s+\*)((?:[^*]+))\*(?!\s+\*))$/,_=/(?:^|\s)(\*(?!\s+\*)((?:[^*]+))\*(?!\s+\*))/g,m=/(?:^|\s)(_(?!\s+_)((?:[^_]+))_(?!\s+_))$/,x=/(?:^|\s)(_(?!\s+_)((?:[^_]+))_(?!\s+_))/g,d=l.create({name:"italic",addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"em"},{tag:"i",getAttrs:e=>e.style.fontStyle!=="normal"&&null},{style:"font-style=normal",clearMark:e=>e.type.name===this.name},{style:"font-style=italic"}]},renderHTML({HTMLAttributes:e}){return["em",a(this.options.HTMLAttributes,e),0]},addCommands(){return{setItalic:()=>({commands:e})=>e.setMark(this.name),toggleItalic:()=>({commands:e})=>e.toggleMark(this.name),unsetItalic:()=>({commands:e})=>e.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-i":()=>this.editor.commands.toggleItalic(),"Mod-I":()=>this.editor.commands.toggleItalic()}},addInputRules(){return[o({find:g,type:this.type}),o({find:m,type:this.type})]},addPasteRules(){return[i({find:_,type:this.type}),i({find:x,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function k(){let e=globalThis,r=e[p];if(r!=null)return r;let s={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[p]=s,s}function c(){return k()}function u(e){c().registerExtension(e)}var b={name:"italic",create:()=>d,commands:{set_italic:e=>e.chain().focus().setItalic().run(),toggle_italic:e=>e.chain().focus().toggleItalic().run(),unset_italic:e=>e.chain().focus().unsetItalic().run()},selection_keys:["italic"],selection_state:e=>({italic:e.isActive("italic")})};function de(){u(b)}export{de as register_italic};
|
||||
|
||||
+3
-3
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
var o=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(o==null||o.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=o.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=t.CommandManager,_=t.Editor,m=t.Extension,x=t.InputRule,k=t.Mark,r=t.Node,b=t.NodePos,y=t.NodeView,h=t.PasteRule,E=t.Tracker,f=t.callOrReturn,R=t.canInsertNode,P=t.combineTransactionSteps,T=t.createChainableState,A=t.createDocument,C=t.createNodeFromContent,S=t.createStyleTag,N=t.defaultBlockAt,O=t.deleteProps,I=t.elementFromString,B=t.escapeForRegEx,w=t.extensions,v=t.findChildren,M=t.findChildrenInRange,L=t.findDuplicates,F=t.findParentNode,D=t.findParentNodeClosestToPos,j=t.fromString,K=t.generateHTML,H=t.generateJSON,q=t.generateText,G=t.getAttributes,z=t.getAttributesFromExtensions,J=t.getChangedRanges,U=t.getDebugJSON,V=t.getExtensionField,Y=t.getHTMLFromFragment,Q=t.getMarkAttributes,W=t.getMarkRange,X=t.getMarkType,Z=t.getMarksBetween,$=t.getNodeAtPosition,tt=t.getNodeAttributes,et=t.getNodeType,nt=t.getRenderedAttributes,ot=t.getSchema,it=t.getSchemaByResolvedExtensions,rt=t.getSchemaTypeByName,st=t.getSchemaTypeNameByName,lt=t.getSplittedAttributes,at=t.getText,dt=t.getTextBetween,pt=t.getTextContentFromNodes,ct=t.getTextSerializersFromSchema,ut=t.injectExtensionAttributesToParseRule,gt=t.inputRulesPlugin,_t=t.isActive,mt=t.isAtEndOfNode,xt=t.isAtStartOfNode,kt=t.isEmptyObject,bt=t.isExtensionRulesEnabled,yt=t.isFunction,ht=t.isList,Et=t.isMacOS,ft=t.isMarkActive,Rt=t.isNodeActive,Pt=t.isNodeEmpty,Tt=t.isNodeSelection,At=t.isNumber,Ct=t.isPlainObject,St=t.isRegExp,Nt=t.isSafari,Ot=t.isString,It=t.isTextSelection,Bt=t.isiOS,wt=t.markInputRule,vt=t.markPasteRule,s=t.mergeAttributes,Mt=t.mergeDeep,Lt=t.minMax,Ft=t.nodeInputRule,Dt=t.nodePasteRule,jt=t.objectIncludes,Kt=t.pasteRulesPlugin,Ht=t.posToDOMRect,qt=t.removeDuplicates,Gt=t.resolveFocusPosition,zt=t.rewriteUnknownContent,Jt=t.selectionToInsertionEnd,Ut=t.splitExtensions,Vt=t.textInputRule,Yt=t.textPasteRule,Qt=t.textblockTypeInputRule,Wt=t.wrappingInputRule;var l=r.create({name:"listItem",addOptions(){return{HTMLAttributes:{},bulletListTypeName:"bulletList",orderedListTypeName:"orderedList"}},content:"paragraph block*",defining:!0,parseHTML(){return[{tag:"li"}]},renderHTML({HTMLAttributes:e}){return["li",s(this.options.HTMLAttributes,e),0]},addKeyboardShortcuts(){return{Enter:()=>this.editor.commands.splitListItem(this.name),Tab:()=>this.editor.commands.sinkListItem(this.name),"Shift-Tab":()=>this.editor.commands.liftListItem(this.name)}}});var a="__LEPTOS_TIPTAP_BRIDGE__";function c(){let e=globalThis,n=e[a];if(n!=null)return n;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[a]=i,i}function d(){return c()}function p(e){d().registerExtension(e)}var u={name:"list_item",create:()=>l,commands:{split_list_item:(e,n)=>n.kind==="split_list_item"?e.chain().focus().splitListItem(e.isActive("taskList")?"taskItem":"listItem",n.attributes??{}).run():!1,sink_list_item:e=>e.chain().focus().sinkListItem(e.isActive("taskList")?"taskItem":"listItem").run(),lift_list_item:e=>e.chain().focus().liftListItem(e.isActive("taskList")?"taskItem":"listItem").run()}};function re(){p(u)}export{re as register_list_item};
|
||||
var o=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(o==null||o.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=o.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=t.CommandManager,_=t.Editor,m=t.Extension,x=t.InputRule,k=t.Mark,r=t.Node,b=t.NodePos,y=t.NodeView,h=t.PasteRule,f=t.Tracker,E=t.callOrReturn,R=t.canInsertNode,P=t.combineTransactionSteps,T=t.createChainableState,A=t.createDocument,C=t.createNodeFromContent,S=t.createStyleTag,w=t.defaultBlockAt,N=t.deleteProps,O=t.elementFromString,I=t.escapeForRegEx,B=t.extensions,v=t.findChildren,M=t.findChildrenInRange,L=t.findDuplicates,F=t.findParentNode,D=t.findParentNodeClosestToPos,j=t.fromString,K=t.generateHTML,H=t.generateJSON,q=t.generateText,G=t.getAttributes,z=t.getAttributesFromExtensions,J=t.getChangedRanges,U=t.getDebugJSON,V=t.getExtensionField,Y=t.getHTMLFromFragment,Q=t.getMarkAttributes,W=t.getMarkRange,X=t.getMarkType,Z=t.getMarksBetween,$=t.getNodeAtPosition,tt=t.getNodeAttributes,et=t.getNodeType,nt=t.getRenderedAttributes,ot=t.getSchema,it=t.getSchemaByResolvedExtensions,rt=t.getSchemaTypeByName,st=t.getSchemaTypeNameByName,lt=t.getSplittedAttributes,at=t.getText,dt=t.getTextBetween,pt=t.getTextContentFromNodes,ct=t.getTextSerializersFromSchema,ut=t.injectExtensionAttributesToParseRule,gt=t.inputRulesPlugin,_t=t.isActive,mt=t.isAtEndOfNode,xt=t.isAtStartOfNode,kt=t.isEmptyObject,bt=t.isExtensionRulesEnabled,yt=t.isFunction,ht=t.isList,ft=t.isMacOS,Et=t.isMarkActive,Rt=t.isNodeActive,Pt=t.isNodeEmpty,Tt=t.isNodeSelection,At=t.isNumber,Ct=t.isPlainObject,St=t.isRegExp,wt=t.isSafari,Nt=t.isString,Ot=t.isTextSelection,It=t.isiOS,Bt=t.markInputRule,vt=t.markPasteRule,s=t.mergeAttributes,Mt=t.mergeDeep,Lt=t.minMax,Ft=t.nodeInputRule,Dt=t.nodePasteRule,jt=t.objectIncludes,Kt=t.pasteRulesPlugin,Ht=t.posToDOMRect,qt=t.removeDuplicates,Gt=t.resolveFocusPosition,zt=t.rewriteUnknownContent,Jt=t.selectionToInsertionEnd,Ut=t.splitExtensions,Vt=t.textInputRule,Yt=t.textPasteRule,Qt=t.textblockTypeInputRule,Wt=t.wrappingInputRule;var l=r.create({name:"listItem",addOptions(){return{HTMLAttributes:{},bulletListTypeName:"bulletList",orderedListTypeName:"orderedList"}},content:"paragraph block*",defining:!0,parseHTML(){return[{tag:"li"}]},renderHTML({HTMLAttributes:e}){return["li",s(this.options.HTMLAttributes,e),0]},addKeyboardShortcuts(){return{Enter:()=>this.editor.commands.splitListItem(this.name),Tab:()=>this.editor.commands.sinkListItem(this.name),"Shift-Tab":()=>this.editor.commands.liftListItem(this.name)}}});var a="__LEPTOS_TIPTAP_BRIDGE__";function c(){let e=globalThis,n=e[a];if(n!=null)return n;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[a]=i,i}function d(){return c()}function p(e){d().registerExtension(e)}var u={name:"list_item",create:()=>l,commands:{split_list_item:(e,n)=>n.kind==="split_list_item"?e.chain().focus().splitListItem(e.isActive("taskList")?"taskItem":"listItem",n.attributes??{}).run():!1,sink_list_item:e=>e.chain().focus().sinkListItem(e.isActive("taskList")?"taskItem":"listItem").run(),lift_list_item:e=>e.chain().focus().liftListItem(e.isActive("taskList")?"taskItem":"listItem").run()}};function re(){p(u)}export{re as register_list_item};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=i.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,y=t.Extension,h=t.InputRule,f=t.Mark,a=t.Node,E=t.NodePos,R=t.NodeView,A=t.PasteRule,T=t.Tracker,P=t.callOrReturn,C=t.canInsertNode,S=t.combineTransactionSteps,N=t.createChainableState,O=t.createDocument,B=t.createNodeFromContent,M=t.createStyleTag,w=t.defaultBlockAt,I=t.deleteProps,v=t.elementFromString,F=t.escapeForRegEx,L=t.extensions,D=t.findChildren,j=t.findChildrenInRange,H=t.findDuplicates,K=t.findParentNode,q=t.findParentNodeClosestToPos,G=t.fromString,z=t.generateHTML,J=t.generateJSON,U=t.generateText,V=t.getAttributes,Y=t.getAttributesFromExtensions,$=t.getChangedRanges,W=t.getDebugJSON,Q=t.getExtensionField,X=t.getHTMLFromFragment,Z=t.getMarkAttributes,tt=t.getMarkRange,et=t.getMarkType,nt=t.getMarksBetween,ot=t.getNodeAtPosition,it=t.getNodeAttributes,rt=t.getNodeType,st=t.getRenderedAttributes,at=t.getSchema,lt=t.getSchemaByResolvedExtensions,dt=t.getSchemaTypeByName,pt=t.getSchemaTypeNameByName,ut=t.getSplittedAttributes,ct=t.getText,gt=t.getTextBetween,_t=t.getTextContentFromNodes,xt=t.getTextSerializersFromSchema,mt=t.injectExtensionAttributesToParseRule,kt=t.inputRulesPlugin,bt=t.isActive,yt=t.isAtEndOfNode,ht=t.isAtStartOfNode,ft=t.isEmptyObject,Et=t.isExtensionRulesEnabled,Rt=t.isFunction,At=t.isList,Tt=t.isMacOS,Pt=t.isMarkActive,Ct=t.isNodeActive,St=t.isNodeEmpty,Nt=t.isNodeSelection,Ot=t.isNumber,Bt=t.isPlainObject,Mt=t.isRegExp,wt=t.isSafari,It=t.isString,vt=t.isTextSelection,Ft=t.isiOS,Lt=t.markInputRule,Dt=t.markPasteRule,r=t.mergeAttributes,jt=t.mergeDeep,Ht=t.minMax,Kt=t.nodeInputRule,qt=t.nodePasteRule,Gt=t.objectIncludes,zt=t.pasteRulesPlugin,Jt=t.posToDOMRect,Ut=t.removeDuplicates,Vt=t.resolveFocusPosition,Yt=t.rewriteUnknownContent,$t=t.selectionToInsertionEnd,Wt=t.splitExtensions,Qt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,s=t.wrappingInputRule;var _="listItem",l="textStyle",d=/^(\d+)\.\s$/,p=a.create({name:"orderedList",addOptions(){return{itemTypeName:"listItem",HTMLAttributes:{},keepMarks:!1,keepAttributes:!1}},group:"block list",content(){return`${this.options.itemTypeName}+`},addAttributes(){return{start:{default:1,parseHTML:e=>e.hasAttribute("start")?parseInt(e.getAttribute("start")||"",10):1},type:{default:null,parseHTML:e=>e.getAttribute("type")}}},parseHTML(){return[{tag:"ol"}]},renderHTML({HTMLAttributes:e}){let{start:n,...o}=e;return n===1?["ol",r(this.options.HTMLAttributes,o),0]:["ol",r(this.options.HTMLAttributes,e),0]},addCommands(){return{toggleOrderedList:()=>({commands:e,chain:n})=>this.options.keepAttributes?n().toggleList(this.name,this.options.itemTypeName,this.options.keepMarks).updateAttributes(_,this.editor.getAttributes(l)).run():e.toggleList(this.name,this.options.itemTypeName,this.options.keepMarks)}},addKeyboardShortcuts(){return{"Mod-Shift-7":()=>this.editor.commands.toggleOrderedList()}},addInputRules(){let e=s({find:d,type:this.type,getAttributes:n=>({start:+n[1]}),joinPredicate:(n,o)=>o.childCount+o.attrs.start===+n[1]});return(this.options.keepMarks||this.options.keepAttributes)&&(e=s({find:d,type:this.type,keepMarks:this.options.keepMarks,keepAttributes:this.options.keepAttributes,getAttributes:n=>({start:+n[1],...this.editor.getAttributes(l)}),joinPredicate:(n,o)=>o.childCount+o.attrs.start===+n[1],editor:this.editor})),[e]}});var u="__LEPTOS_TIPTAP_BRIDGE__";function x(){let e=globalThis,n=e[u];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[u]=o,o}function c(){return x()}function g(e){c().registerExtension(e)}var m={name:"ordered_list",create:()=>p,commands:{toggle_ordered_list:e=>e.chain().focus().toggleOrderedList().run()},selection_keys:["ordered_list"],selection_state:e=>({ordered_list:e.isActive("orderedList")})};function le(){g(m)}export{le as register_ordered_list};
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=i.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,y=t.Extension,h=t.InputRule,f=t.Mark,l=t.Node,E=t.NodePos,R=t.NodeView,A=t.PasteRule,T=t.Tracker,P=t.callOrReturn,C=t.canInsertNode,S=t.combineTransactionSteps,N=t.createChainableState,O=t.createDocument,w=t.createNodeFromContent,B=t.createStyleTag,M=t.defaultBlockAt,I=t.deleteProps,v=t.elementFromString,F=t.escapeForRegEx,L=t.extensions,D=t.findChildren,j=t.findChildrenInRange,H=t.findDuplicates,K=t.findParentNode,q=t.findParentNodeClosestToPos,G=t.fromString,z=t.generateHTML,J=t.generateJSON,U=t.generateText,V=t.getAttributes,Y=t.getAttributesFromExtensions,$=t.getChangedRanges,W=t.getDebugJSON,Q=t.getExtensionField,X=t.getHTMLFromFragment,Z=t.getMarkAttributes,tt=t.getMarkRange,et=t.getMarkType,nt=t.getMarksBetween,ot=t.getNodeAtPosition,it=t.getNodeAttributes,rt=t.getNodeType,st=t.getRenderedAttributes,lt=t.getSchema,at=t.getSchemaByResolvedExtensions,dt=t.getSchemaTypeByName,pt=t.getSchemaTypeNameByName,ut=t.getSplittedAttributes,ct=t.getText,gt=t.getTextBetween,_t=t.getTextContentFromNodes,mt=t.getTextSerializersFromSchema,xt=t.injectExtensionAttributesToParseRule,kt=t.inputRulesPlugin,bt=t.isActive,yt=t.isAtEndOfNode,ht=t.isAtStartOfNode,ft=t.isEmptyObject,Et=t.isExtensionRulesEnabled,Rt=t.isFunction,At=t.isList,Tt=t.isMacOS,Pt=t.isMarkActive,Ct=t.isNodeActive,St=t.isNodeEmpty,Nt=t.isNodeSelection,Ot=t.isNumber,wt=t.isPlainObject,Bt=t.isRegExp,Mt=t.isSafari,It=t.isString,vt=t.isTextSelection,Ft=t.isiOS,Lt=t.markInputRule,Dt=t.markPasteRule,r=t.mergeAttributes,jt=t.mergeDeep,Ht=t.minMax,Kt=t.nodeInputRule,qt=t.nodePasteRule,Gt=t.objectIncludes,zt=t.pasteRulesPlugin,Jt=t.posToDOMRect,Ut=t.removeDuplicates,Vt=t.resolveFocusPosition,Yt=t.rewriteUnknownContent,$t=t.selectionToInsertionEnd,Wt=t.splitExtensions,Qt=t.textInputRule,Xt=t.textPasteRule,Zt=t.textblockTypeInputRule,s=t.wrappingInputRule;var _="listItem",a="textStyle",d=/^(\d+)\.\s$/,p=l.create({name:"orderedList",addOptions(){return{itemTypeName:"listItem",HTMLAttributes:{},keepMarks:!1,keepAttributes:!1}},group:"block list",content(){return`${this.options.itemTypeName}+`},addAttributes(){return{start:{default:1,parseHTML:e=>e.hasAttribute("start")?parseInt(e.getAttribute("start")||"",10):1},type:{default:null,parseHTML:e=>e.getAttribute("type")}}},parseHTML(){return[{tag:"ol"}]},renderHTML({HTMLAttributes:e}){let{start:n,...o}=e;return n===1?["ol",r(this.options.HTMLAttributes,o),0]:["ol",r(this.options.HTMLAttributes,e),0]},addCommands(){return{toggleOrderedList:()=>({commands:e,chain:n})=>this.options.keepAttributes?n().toggleList(this.name,this.options.itemTypeName,this.options.keepMarks).updateAttributes(_,this.editor.getAttributes(a)).run():e.toggleList(this.name,this.options.itemTypeName,this.options.keepMarks)}},addKeyboardShortcuts(){return{"Mod-Shift-7":()=>this.editor.commands.toggleOrderedList()}},addInputRules(){let e=s({find:d,type:this.type,getAttributes:n=>({start:+n[1]}),joinPredicate:(n,o)=>o.childCount+o.attrs.start===+n[1]});return(this.options.keepMarks||this.options.keepAttributes)&&(e=s({find:d,type:this.type,keepMarks:this.options.keepMarks,keepAttributes:this.options.keepAttributes,getAttributes:n=>({start:+n[1],...this.editor.getAttributes(a)}),joinPredicate:(n,o)=>o.childCount+o.attrs.start===+n[1],editor:this.editor})),[e]}});var u="__LEPTOS_TIPTAP_BRIDGE__";function m(){let e=globalThis,n=e[u];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[u]=o,o}function c(){return m()}function g(e){c().registerExtension(e)}var x={name:"ordered_list",create:()=>p,commands:{toggle_ordered_list:e=>e.chain().focus().toggleOrderedList().run()},selection_keys:["ordered_list"],selection_state:e=>({ordered_list:e.isActive("orderedList")})};function ae(){g(x)}export{ae as register_ordered_list};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=t.CommandManager,_=t.Editor,x=t.Extension,m=t.InputRule,k=t.Mark,i=t.Node,b=t.NodePos,y=t.NodeView,h=t.PasteRule,E=t.Tracker,P=t.callOrReturn,R=t.canInsertNode,f=t.combineTransactionSteps,C=t.createChainableState,T=t.createDocument,A=t.createNodeFromContent,S=t.createStyleTag,N=t.defaultBlockAt,O=t.deleteProps,B=t.elementFromString,w=t.escapeForRegEx,v=t.extensions,M=t.findChildren,I=t.findChildrenInRange,F=t.findDuplicates,D=t.findParentNode,j=t.findParentNodeClosestToPos,L=t.fromString,K=t.generateHTML,H=t.generateJSON,q=t.generateText,G=t.getAttributes,z=t.getAttributesFromExtensions,J=t.getChangedRanges,U=t.getDebugJSON,V=t.getExtensionField,Y=t.getHTMLFromFragment,Q=t.getMarkAttributes,W=t.getMarkRange,X=t.getMarkType,Z=t.getMarksBetween,$=t.getNodeAtPosition,tt=t.getNodeAttributes,et=t.getNodeType,nt=t.getRenderedAttributes,ot=t.getSchema,rt=t.getSchemaByResolvedExtensions,it=t.getSchemaTypeByName,st=t.getSchemaTypeNameByName,at=t.getSplittedAttributes,lt=t.getText,pt=t.getTextBetween,dt=t.getTextContentFromNodes,ct=t.getTextSerializersFromSchema,ut=t.injectExtensionAttributesToParseRule,gt=t.inputRulesPlugin,_t=t.isActive,xt=t.isAtEndOfNode,mt=t.isAtStartOfNode,kt=t.isEmptyObject,bt=t.isExtensionRulesEnabled,yt=t.isFunction,ht=t.isList,Et=t.isMacOS,Pt=t.isMarkActive,Rt=t.isNodeActive,ft=t.isNodeEmpty,Ct=t.isNodeSelection,Tt=t.isNumber,At=t.isPlainObject,St=t.isRegExp,Nt=t.isSafari,Ot=t.isString,Bt=t.isTextSelection,wt=t.isiOS,vt=t.markInputRule,Mt=t.markPasteRule,s=t.mergeAttributes,It=t.mergeDeep,Ft=t.minMax,Dt=t.nodeInputRule,jt=t.nodePasteRule,Lt=t.objectIncludes,Kt=t.pasteRulesPlugin,Ht=t.posToDOMRect,qt=t.removeDuplicates,Gt=t.resolveFocusPosition,zt=t.rewriteUnknownContent,Jt=t.selectionToInsertionEnd,Ut=t.splitExtensions,Vt=t.textInputRule,Yt=t.textPasteRule,Qt=t.textblockTypeInputRule,Wt=t.wrappingInputRule;var a=i.create({name:"paragraph",priority:1e3,addOptions(){return{HTMLAttributes:{}}},group:"block",content:"inline*",parseHTML(){return[{tag:"p"}]},renderHTML({HTMLAttributes:e}){return["p",s(this.options.HTMLAttributes,e),0]},addCommands(){return{setParagraph:()=>({commands:e})=>e.setNode(this.name)}},addKeyboardShortcuts(){return{"Mod-Alt-0":()=>this.editor.commands.setParagraph()}}});var l="__LEPTOS_TIPTAP_BRIDGE__";function c(){let e=globalThis,o=e[l];if(o!=null)return o;let r={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[l]=r,r}function p(){return c()}function d(e){p().registerExtension(e)}var u={name:"paragraph",create:()=>a,commands:{set_paragraph:e=>e.chain().focus().setParagraph().run()},selection_keys:["paragraph"],selection_state:e=>({paragraph:e.isActive("paragraph")})};function ie(){d(u)}export{ie as register_paragraph};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=e.CommandManager,_=e.Editor,x=e.Extension,m=e.InputRule,k=e.Mark,i=e.Node,b=e.NodePos,y=e.NodeView,h=e.PasteRule,E=e.Tracker,f=e.callOrReturn,P=e.canInsertNode,R=e.combineTransactionSteps,C=e.createChainableState,T=e.createDocument,A=e.createNodeFromContent,S=e.createStyleTag,w=e.defaultBlockAt,N=e.deleteProps,O=e.elementFromString,B=e.escapeForRegEx,v=e.extensions,M=e.findChildren,I=e.findChildrenInRange,F=e.findDuplicates,D=e.findParentNode,j=e.findParentNodeClosestToPos,L=e.fromString,K=e.generateHTML,H=e.generateJSON,q=e.generateText,G=e.getAttributes,z=e.getAttributesFromExtensions,J=e.getChangedRanges,U=e.getDebugJSON,V=e.getExtensionField,Y=e.getHTMLFromFragment,Q=e.getMarkAttributes,W=e.getMarkRange,X=e.getMarkType,Z=e.getMarksBetween,$=e.getNodeAtPosition,ee=e.getNodeAttributes,te=e.getNodeType,ne=e.getRenderedAttributes,oe=e.getSchema,re=e.getSchemaByResolvedExtensions,ie=e.getSchemaTypeByName,se=e.getSchemaTypeNameByName,ae=e.getSplittedAttributes,le=e.getText,de=e.getTextBetween,pe=e.getTextContentFromNodes,ce=e.getTextSerializersFromSchema,ue=e.injectExtensionAttributesToParseRule,ge=e.inputRulesPlugin,_e=e.isActive,xe=e.isAtEndOfNode,me=e.isAtStartOfNode,ke=e.isEmptyObject,be=e.isExtensionRulesEnabled,ye=e.isFunction,he=e.isList,Ee=e.isMacOS,fe=e.isMarkActive,Pe=e.isNodeActive,Re=e.isNodeEmpty,Ce=e.isNodeSelection,Te=e.isNumber,Ae=e.isPlainObject,Se=e.isRegExp,we=e.isSafari,Ne=e.isString,Oe=e.isTextSelection,Be=e.isiOS,ve=e.markInputRule,Me=e.markPasteRule,s=e.mergeAttributes,Ie=e.mergeDeep,Fe=e.minMax,De=e.nodeInputRule,je=e.nodePasteRule,Le=e.objectIncludes,Ke=e.pasteRulesPlugin,He=e.posToDOMRect,qe=e.removeDuplicates,Ge=e.resolveFocusPosition,ze=e.rewriteUnknownContent,Je=e.selectionToInsertionEnd,Ue=e.splitExtensions,Ve=e.textInputRule,Ye=e.textPasteRule,Qe=e.textblockTypeInputRule,We=e.wrappingInputRule;var a=i.create({name:"paragraph",priority:1e3,addOptions(){return{HTMLAttributes:{}}},group:"block",content:"inline*",parseHTML(){return[{tag:"p"}]},renderHTML({HTMLAttributes:t}){return["p",s(this.options.HTMLAttributes,t),0]},addCommands(){return{setParagraph:()=>({commands:t})=>t.setNode(this.name)}},addKeyboardShortcuts(){return{"Mod-Alt-0":()=>this.editor.commands.setParagraph()}}});var l="__LEPTOS_TIPTAP_BRIDGE__";function c(){let t=globalThis,o=t[l];if(o!=null)return o;let r={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[l]=r,r}function d(){return c()}function p(t){d().registerExtension(t)}var u={name:"paragraph",create:()=>a,commands:{set_paragraph:t=>t.chain().focus().setParagraph().run()},selection_keys:["paragraph"],selection_state:t=>({paragraph:t.isActive("paragraph")})};function it(){p(u)}export{it as register_paragraph};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var a=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(a==null||a.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=a.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var O=t.CommandManager,N=t.Editor,m=t.Extension,B=t.InputRule,v=t.Mark,D=t.Node,I=t.NodePos,F=t.NodeView,M=t.PasteRule,j=t.Tracker,L=t.callOrReturn,K=t.canInsertNode,G=t.combineTransactionSteps,q=t.createChainableState,H=t.createDocument,z=t.createNodeFromContent,J=t.createStyleTag,V=t.defaultBlockAt,W=t.deleteProps,U=t.elementFromString,Y=t.escapeForRegEx,Q=t.extensions,X=t.findChildren,Z=t.findChildrenInRange,$=t.findDuplicates,tt=t.findParentNode,et=t.findParentNodeClosestToPos,nt=t.fromString,ot=t.generateHTML,it=t.generateJSON,rt=t.generateText,st=t.getAttributes,lt=t.getAttributesFromExtensions,at=t.getChangedRanges,pt=t.getDebugJSON,dt=t.getExtensionField,ct=t.getHTMLFromFragment,ut=t.getMarkAttributes,gt=t.getMarkRange,_t=t.getMarkType,xt=t.getMarksBetween,mt=t.getNodeAtPosition,kt=t.getNodeAttributes,bt=t.getNodeType,yt=t.getRenderedAttributes,ht=t.getSchema,Et=t.getSchemaByResolvedExtensions,Pt=t.getSchemaTypeByName,ft=t.getSchemaTypeNameByName,St=t.getSplittedAttributes,Rt=t.getText,Ct=t.getTextBetween,Tt=t.getTextContentFromNodes,At=t.getTextSerializersFromSchema,wt=t.injectExtensionAttributesToParseRule,Ot=t.inputRulesPlugin,Nt=t.isActive,Bt=t.isAtEndOfNode,vt=t.isAtStartOfNode,Dt=t.isEmptyObject,It=t.isExtensionRulesEnabled,Ft=t.isFunction,Mt=t.isList,jt=t.isMacOS,Lt=t.isMarkActive,Kt=t.isNodeActive,k=t.isNodeEmpty,Gt=t.isNodeSelection,qt=t.isNumber,Ht=t.isPlainObject,zt=t.isRegExp,Jt=t.isSafari,Vt=t.isString,Wt=t.isTextSelection,Ut=t.isiOS,Yt=t.markInputRule,Qt=t.markPasteRule,Xt=t.mergeAttributes,Zt=t.mergeDeep,$t=t.minMax,te=t.nodeInputRule,ee=t.nodePasteRule,ne=t.objectIncludes,oe=t.pasteRulesPlugin,ie=t.posToDOMRect,re=t.removeDuplicates,se=t.resolveFocusPosition,le=t.rewriteUnknownContent,ae=t.selectionToInsertionEnd,pe=t.splitExtensions,de=t.textInputRule,ce=t.textPasteRule,ue=t.textblockTypeInputRule,ge=t.wrappingInputRule;var p=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(p==null||p.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var n=p.modules["@tiptap/pm/state"];if(n==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/state" is unavailable');var xe=n.AllSelection,me=n.EditorState,ke=n.NodeSelection,b=n.Plugin,y=n.PluginKey,be=n.Selection,ye=n.SelectionRange,he=n.TextSelection,Ee=n.Transaction;var d=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(d==null||d.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var o=d.modules["@tiptap/pm/view"];if(o==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/view" is unavailable');var h=o.Decoration,E=o.DecorationSet,fe=o.EditorView,Se=o.__endComposition,Re=o.__parseFromClipboard;var c=m.create({name:"placeholder",addOptions(){return{emptyEditorClass:"is-editor-empty",emptyNodeClass:"is-empty",placeholder:"Write something \u2026",showOnlyWhenEditable:!0,showOnlyCurrent:!0,includeChildren:!1}},addProseMirrorPlugins(){return[new b({key:new y("placeholder"),props:{decorations:({doc:e,selection:s})=>{let l=this.editor.isEditable||!this.options.showOnlyWhenEditable,{anchor:u}=s,g=[];if(!l)return null;let R=this.editor.isEmpty;return e.descendants((i,r)=>{let _=u>=r&&u<=r+i.nodeSize,C=!i.isLeaf&&k(i);if((_||!this.options.showOnlyCurrent)&&C){let x=[this.options.emptyNodeClass];R&&x.push(this.options.emptyEditorClass);let T=h.node(r,r+i.nodeSize,{class:x.join(" "),"data-placeholder":typeof this.options.placeholder=="function"?this.options.placeholder({editor:this.editor,node:i,pos:r,hasAnchor:_}):this.options.placeholder});g.push(T)}return this.options.includeChildren}),E.create(e,g)}}})]}});var P="__LEPTOS_TIPTAP_BRIDGE__";function A(){let e=globalThis,s=e[P];if(s!=null)return s;let l={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[P]=l,l}function f(){return A()}function S(e){f().registerExtension(e)}var w={name:"placeholder",create:({placeholder:e})=>e==null?c:c.configure({placeholder:e})};function Fe(){S(w)}export{Fe as register_placeholder};
|
||||
var a=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(a==null||a.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=a.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var O=e.CommandManager,N=e.Editor,m=e.Extension,B=e.InputRule,v=e.Mark,D=e.Node,I=e.NodePos,F=e.NodeView,M=e.PasteRule,j=e.Tracker,L=e.callOrReturn,K=e.canInsertNode,G=e.combineTransactionSteps,q=e.createChainableState,H=e.createDocument,z=e.createNodeFromContent,J=e.createStyleTag,V=e.defaultBlockAt,W=e.deleteProps,U=e.elementFromString,Y=e.escapeForRegEx,Q=e.extensions,X=e.findChildren,Z=e.findChildrenInRange,$=e.findDuplicates,ee=e.findParentNode,te=e.findParentNodeClosestToPos,ne=e.fromString,oe=e.generateHTML,ie=e.generateJSON,re=e.generateText,se=e.getAttributes,le=e.getAttributesFromExtensions,ae=e.getChangedRanges,de=e.getDebugJSON,pe=e.getExtensionField,ce=e.getHTMLFromFragment,ue=e.getMarkAttributes,ge=e.getMarkRange,_e=e.getMarkType,xe=e.getMarksBetween,me=e.getNodeAtPosition,be=e.getNodeAttributes,ke=e.getNodeType,ye=e.getRenderedAttributes,he=e.getSchema,Ee=e.getSchemaByResolvedExtensions,fe=e.getSchemaTypeByName,Pe=e.getSchemaTypeNameByName,Se=e.getSplittedAttributes,Re=e.getText,Ce=e.getTextBetween,Te=e.getTextContentFromNodes,we=e.getTextSerializersFromSchema,Ae=e.injectExtensionAttributesToParseRule,Oe=e.inputRulesPlugin,Ne=e.isActive,Be=e.isAtEndOfNode,ve=e.isAtStartOfNode,De=e.isEmptyObject,Ie=e.isExtensionRulesEnabled,Fe=e.isFunction,Me=e.isList,je=e.isMacOS,Le=e.isMarkActive,Ke=e.isNodeActive,b=e.isNodeEmpty,Ge=e.isNodeSelection,qe=e.isNumber,He=e.isPlainObject,ze=e.isRegExp,Je=e.isSafari,Ve=e.isString,We=e.isTextSelection,Ue=e.isiOS,Ye=e.markInputRule,Qe=e.markPasteRule,Xe=e.mergeAttributes,Ze=e.mergeDeep,$e=e.minMax,et=e.nodeInputRule,tt=e.nodePasteRule,nt=e.objectIncludes,ot=e.pasteRulesPlugin,it=e.posToDOMRect,rt=e.removeDuplicates,st=e.resolveFocusPosition,lt=e.rewriteUnknownContent,at=e.selectionToInsertionEnd,dt=e.splitExtensions,pt=e.textInputRule,ct=e.textPasteRule,ut=e.textblockTypeInputRule,gt=e.wrappingInputRule;var d=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(d==null||d.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var n=d.modules["@tiptap/pm/state"];if(n==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/state" is unavailable');var xt=n.AllSelection,mt=n.EditorState,bt=n.NodeSelection,k=n.Plugin,y=n.PluginKey,kt=n.Selection,yt=n.SelectionRange,ht=n.TextSelection,Et=n.Transaction;var p=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(p==null||p.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var o=p.modules["@tiptap/pm/view"];if(o==null)throw new Error('leptos-tiptap bridge module "@tiptap/pm/view" is unavailable');var h=o.Decoration,E=o.DecorationSet,Pt=o.EditorView,St=o.__endComposition,Rt=o.__parseFromClipboard;var c=m.create({name:"placeholder",addOptions(){return{emptyEditorClass:"is-editor-empty",emptyNodeClass:"is-empty",placeholder:"Write something \u2026",showOnlyWhenEditable:!0,showOnlyCurrent:!0,includeChildren:!1}},addProseMirrorPlugins(){return[new k({key:new y("placeholder"),props:{decorations:({doc:t,selection:s})=>{let l=this.editor.isEditable||!this.options.showOnlyWhenEditable,{anchor:u}=s,g=[];if(!l)return null;let R=this.editor.isEmpty;return t.descendants((i,r)=>{let _=u>=r&&u<=r+i.nodeSize,C=!i.isLeaf&&b(i);if((_||!this.options.showOnlyCurrent)&&C){let x=[this.options.emptyNodeClass];R&&x.push(this.options.emptyEditorClass);let T=h.node(r,r+i.nodeSize,{class:x.join(" "),"data-placeholder":typeof this.options.placeholder=="function"?this.options.placeholder({editor:this.editor,node:i,pos:r,hasAnchor:_}):this.options.placeholder});g.push(T)}return this.options.includeChildren}),E.create(t,g)}}})]}});var f="__LEPTOS_TIPTAP_BRIDGE__";function w(){let t=globalThis,s=t[f];if(s!=null)return s;let l={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[f]=l,l}function P(){return w()}function S(t){P().registerExtension(t)}var A={name:"placeholder",create:({placeholder:t})=>t==null?c:c.configure({placeholder:t})};function Ft(){S(A)}export{Ft as register_placeholder};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=t.CommandManager,b=t.Editor,y=t.Extension,h=t.InputRule,r=t.Mark,R=t.Node,E=t.NodePos,f=t.NodeView,S=t.PasteRule,P=t.Tracker,C=t.callOrReturn,T=t.canInsertNode,A=t.combineTransactionSteps,N=t.createChainableState,O=t.createDocument,B=t.createNodeFromContent,w=t.createStyleTag,M=t.defaultBlockAt,v=t.deleteProps,I=t.elementFromString,F=t.escapeForRegEx,D=t.extensions,j=t.findChildren,L=t.findChildrenInRange,K=t.findDuplicates,H=t.findParentNode,q=t.findParentNodeClosestToPos,G=t.fromString,z=t.generateHTML,J=t.generateJSON,U=t.generateText,V=t.getAttributes,Y=t.getAttributesFromExtensions,$=t.getChangedRanges,Q=t.getDebugJSON,W=t.getExtensionField,X=t.getHTMLFromFragment,Z=t.getMarkAttributes,tt=t.getMarkRange,et=t.getMarkType,nt=t.getMarksBetween,ot=t.getNodeAtPosition,it=t.getNodeAttributes,rt=t.getNodeType,st=t.getRenderedAttributes,at=t.getSchema,lt=t.getSchemaByResolvedExtensions,dt=t.getSchemaTypeByName,pt=t.getSchemaTypeNameByName,ct=t.getSplittedAttributes,ut=t.getText,gt=t.getTextBetween,_t=t.getTextContentFromNodes,xt=t.getTextSerializersFromSchema,mt=t.injectExtensionAttributesToParseRule,kt=t.inputRulesPlugin,bt=t.isActive,yt=t.isAtEndOfNode,ht=t.isAtStartOfNode,Rt=t.isEmptyObject,Et=t.isExtensionRulesEnabled,ft=t.isFunction,St=t.isList,Pt=t.isMacOS,Ct=t.isMarkActive,Tt=t.isNodeActive,At=t.isNodeEmpty,Nt=t.isNodeSelection,Ot=t.isNumber,Bt=t.isPlainObject,wt=t.isRegExp,Mt=t.isSafari,vt=t.isString,It=t.isTextSelection,Ft=t.isiOS,s=t.markInputRule,a=t.markPasteRule,l=t.mergeAttributes,Dt=t.mergeDeep,jt=t.minMax,Lt=t.nodeInputRule,Kt=t.nodePasteRule,Ht=t.objectIncludes,qt=t.pasteRulesPlugin,Gt=t.posToDOMRect,zt=t.removeDuplicates,Jt=t.resolveFocusPosition,Ut=t.rewriteUnknownContent,Vt=t.selectionToInsertionEnd,Yt=t.splitExtensions,$t=t.textInputRule,Qt=t.textPasteRule,Wt=t.textblockTypeInputRule,Xt=t.wrappingInputRule;var g=/(?:^|\s)(~~(?!\s+~~)((?:[^~]+))~~(?!\s+~~))$/,_=/(?:^|\s)(~~(?!\s+~~)((?:[^~]+))~~(?!\s+~~))/g,d=r.create({name:"strike",addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"s"},{tag:"del"},{tag:"strike"},{style:"text-decoration",consuming:!1,getAttrs:e=>e.includes("line-through")?{}:!1}]},renderHTML({HTMLAttributes:e}){return["s",l(this.options.HTMLAttributes,e),0]},addCommands(){return{setStrike:()=>({commands:e})=>e.setMark(this.name),toggleStrike:()=>({commands:e})=>e.toggleMark(this.name),unsetStrike:()=>({commands:e})=>e.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-Shift-s":()=>this.editor.commands.toggleStrike()}},addInputRules(){return[s({find:g,type:this.type})]},addPasteRules(){return[a({find:_,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function x(){let e=globalThis,o=e[p];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[p]=i,i}function c(){return x()}function u(e){c().registerExtension(e)}var m={name:"strike",create:()=>d,commands:{set_strike:e=>e.chain().focus().setStrike().run(),toggle_strike:e=>e.chain().focus().toggleStrike().run(),unset_strike:e=>e.chain().focus().unsetStrike().run()},selection_keys:["strike"],selection_state:e=>({strike:e.isActive("strike")})};function ae(){u(m)}export{ae as register_strike};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var k=e.CommandManager,b=e.Editor,y=e.Extension,h=e.InputRule,r=e.Mark,f=e.Node,R=e.NodePos,E=e.NodeView,S=e.PasteRule,P=e.Tracker,C=e.callOrReturn,T=e.canInsertNode,A=e.combineTransactionSteps,w=e.createChainableState,N=e.createDocument,O=e.createNodeFromContent,B=e.createStyleTag,M=e.defaultBlockAt,v=e.deleteProps,I=e.elementFromString,F=e.escapeForRegEx,D=e.extensions,j=e.findChildren,L=e.findChildrenInRange,K=e.findDuplicates,H=e.findParentNode,q=e.findParentNodeClosestToPos,G=e.fromString,z=e.generateHTML,J=e.generateJSON,U=e.generateText,V=e.getAttributes,Y=e.getAttributesFromExtensions,$=e.getChangedRanges,Q=e.getDebugJSON,W=e.getExtensionField,X=e.getHTMLFromFragment,Z=e.getMarkAttributes,ee=e.getMarkRange,te=e.getMarkType,ne=e.getMarksBetween,oe=e.getNodeAtPosition,ie=e.getNodeAttributes,re=e.getNodeType,se=e.getRenderedAttributes,le=e.getSchema,ae=e.getSchemaByResolvedExtensions,de=e.getSchemaTypeByName,pe=e.getSchemaTypeNameByName,ue=e.getSplittedAttributes,ce=e.getText,ge=e.getTextBetween,_e=e.getTextContentFromNodes,xe=e.getTextSerializersFromSchema,me=e.injectExtensionAttributesToParseRule,ke=e.inputRulesPlugin,be=e.isActive,ye=e.isAtEndOfNode,he=e.isAtStartOfNode,fe=e.isEmptyObject,Re=e.isExtensionRulesEnabled,Ee=e.isFunction,Se=e.isList,Pe=e.isMacOS,Ce=e.isMarkActive,Te=e.isNodeActive,Ae=e.isNodeEmpty,we=e.isNodeSelection,Ne=e.isNumber,Oe=e.isPlainObject,Be=e.isRegExp,Me=e.isSafari,ve=e.isString,Ie=e.isTextSelection,Fe=e.isiOS,s=e.markInputRule,l=e.markPasteRule,a=e.mergeAttributes,De=e.mergeDeep,je=e.minMax,Le=e.nodeInputRule,Ke=e.nodePasteRule,He=e.objectIncludes,qe=e.pasteRulesPlugin,Ge=e.posToDOMRect,ze=e.removeDuplicates,Je=e.resolveFocusPosition,Ue=e.rewriteUnknownContent,Ve=e.selectionToInsertionEnd,Ye=e.splitExtensions,$e=e.textInputRule,Qe=e.textPasteRule,We=e.textblockTypeInputRule,Xe=e.wrappingInputRule;var g=/(?:^|\s)(~~(?!\s+~~)((?:[^~]+))~~(?!\s+~~))$/,_=/(?:^|\s)(~~(?!\s+~~)((?:[^~]+))~~(?!\s+~~))/g,d=r.create({name:"strike",addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"s"},{tag:"del"},{tag:"strike"},{style:"text-decoration",consuming:!1,getAttrs:t=>t.includes("line-through")?{}:!1}]},renderHTML({HTMLAttributes:t}){return["s",a(this.options.HTMLAttributes,t),0]},addCommands(){return{setStrike:()=>({commands:t})=>t.setMark(this.name),toggleStrike:()=>({commands:t})=>t.toggleMark(this.name),unsetStrike:()=>({commands:t})=>t.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-Shift-s":()=>this.editor.commands.toggleStrike()}},addInputRules(){return[s({find:g,type:this.type})]},addPasteRules(){return[l({find:_,type:this.type})]}});var p="__LEPTOS_TIPTAP_BRIDGE__";function x(){let t=globalThis,o=t[p];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[p]=i,i}function u(){return x()}function c(t){u().registerExtension(t)}var m={name:"strike",create:()=>d,commands:{set_strike:t=>t.chain().focus().setStrike().run(),toggle_strike:t=>t.chain().focus().toggleStrike().run(),unset_strike:t=>t.chain().focus().unsetStrike().run()},selection_keys:["strike"],selection_state:t=>({strike:t.isActive("strike")})};function lt(){c(m)}export{lt as register_strike};
|
||||
|
||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=i.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var _=e.CommandManager,x=e.Editor,m=e.Extension,b=e.InputRule,k=e.Mark,r=e.Node,y=e.NodePos,h=e.NodeView,E=e.PasteRule,f=e.Tracker,R=e.callOrReturn,P=e.canInsertNode,T=e.combineTransactionSteps,C=e.createChainableState,A=e.createDocument,S=e.createNodeFromContent,w=e.createStyleTag,N=e.defaultBlockAt,O=e.deleteProps,B=e.elementFromString,v=e.escapeForRegEx,M=e.extensions,I=e.findChildren,F=e.findChildrenInRange,D=e.findDuplicates,j=e.findParentNode,L=e.findParentNodeClosestToPos,H=e.fromString,K=e.generateHTML,q=e.generateJSON,G=e.generateText,z=e.getAttributes,J=e.getAttributesFromExtensions,U=e.getChangedRanges,V=e.getDebugJSON,Y=e.getExtensionField,Q=e.getHTMLFromFragment,W=e.getMarkAttributes,X=e.getMarkRange,Z=e.getMarkType,$=e.getMarksBetween,ee=e.getNodeAtPosition,te=e.getNodeAttributes,ne=e.getNodeType,oe=e.getRenderedAttributes,ie=e.getSchema,re=e.getSchemaByResolvedExtensions,se=e.getSchemaTypeByName,le=e.getSchemaTypeNameByName,ae=e.getSplittedAttributes,de=e.getText,pe=e.getTextBetween,ce=e.getTextContentFromNodes,ue=e.getTextSerializersFromSchema,ge=e.injectExtensionAttributesToParseRule,_e=e.inputRulesPlugin,xe=e.isActive,me=e.isAtEndOfNode,be=e.isAtStartOfNode,ke=e.isEmptyObject,ye=e.isExtensionRulesEnabled,he=e.isFunction,Ee=e.isList,fe=e.isMacOS,Re=e.isMarkActive,Pe=e.isNodeActive,Te=e.isNodeEmpty,Ce=e.isNodeSelection,Ae=e.isNumber,Se=e.isPlainObject,we=e.isRegExp,Ne=e.isSafari,Oe=e.isString,Be=e.isTextSelection,ve=e.isiOS,Me=e.markInputRule,Ie=e.markPasteRule,s=e.mergeAttributes,Fe=e.mergeDeep,De=e.minMax,je=e.nodeInputRule,Le=e.nodePasteRule,He=e.objectIncludes,Ke=e.pasteRulesPlugin,qe=e.posToDOMRect,Ge=e.removeDuplicates,ze=e.resolveFocusPosition,Je=e.rewriteUnknownContent,Ue=e.selectionToInsertionEnd,Ve=e.splitExtensions,Ye=e.textInputRule,Qe=e.textPasteRule,We=e.textblockTypeInputRule,Xe=e.wrappingInputRule;var l=r.create({name:"tableCell",addOptions(){return{HTMLAttributes:{}}},content:"block+",addAttributes(){return{colspan:{default:1},rowspan:{default:1},colwidth:{default:null,parseHTML:t=>{let n=t.getAttribute("colwidth");return n?n.split(",").map(c=>parseInt(c,10)):null}}}},tableRole:"cell",isolating:!0,parseHTML(){return[{tag:"td"}]},renderHTML({HTMLAttributes:t}){return["td",s(this.options.HTMLAttributes,t),0]}});var a="__LEPTOS_TIPTAP_BRIDGE__";function u(){let t=globalThis,n=t[a];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[a]=o,o}function d(){return u()}function p(t){d().registerExtension(t)}var g={name:"table_cell",create:()=>l};function st(){p(g)}export{st as register_table_cell};
|
||||
+1
@@ -0,0 +1 @@
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=i.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var _=e.CommandManager,x=e.Editor,m=e.Extension,b=e.InputRule,k=e.Mark,r=e.Node,y=e.NodePos,h=e.NodeView,E=e.PasteRule,f=e.Tracker,R=e.callOrReturn,P=e.canInsertNode,T=e.combineTransactionSteps,A=e.createChainableState,C=e.createDocument,S=e.createNodeFromContent,w=e.createStyleTag,N=e.defaultBlockAt,O=e.deleteProps,B=e.elementFromString,v=e.escapeForRegEx,M=e.extensions,I=e.findChildren,F=e.findChildrenInRange,D=e.findDuplicates,j=e.findParentNode,L=e.findParentNodeClosestToPos,H=e.fromString,K=e.generateHTML,q=e.generateJSON,G=e.generateText,z=e.getAttributes,J=e.getAttributesFromExtensions,U=e.getChangedRanges,V=e.getDebugJSON,Y=e.getExtensionField,Q=e.getHTMLFromFragment,W=e.getMarkAttributes,X=e.getMarkRange,Z=e.getMarkType,$=e.getMarksBetween,ee=e.getNodeAtPosition,te=e.getNodeAttributes,ne=e.getNodeType,oe=e.getRenderedAttributes,ie=e.getSchema,re=e.getSchemaByResolvedExtensions,se=e.getSchemaTypeByName,le=e.getSchemaTypeNameByName,ae=e.getSplittedAttributes,de=e.getText,pe=e.getTextBetween,ce=e.getTextContentFromNodes,ue=e.getTextSerializersFromSchema,ge=e.injectExtensionAttributesToParseRule,_e=e.inputRulesPlugin,xe=e.isActive,me=e.isAtEndOfNode,be=e.isAtStartOfNode,ke=e.isEmptyObject,ye=e.isExtensionRulesEnabled,he=e.isFunction,Ee=e.isList,fe=e.isMacOS,Re=e.isMarkActive,Pe=e.isNodeActive,Te=e.isNodeEmpty,Ae=e.isNodeSelection,Ce=e.isNumber,Se=e.isPlainObject,we=e.isRegExp,Ne=e.isSafari,Oe=e.isString,Be=e.isTextSelection,ve=e.isiOS,Me=e.markInputRule,Ie=e.markPasteRule,s=e.mergeAttributes,Fe=e.mergeDeep,De=e.minMax,je=e.nodeInputRule,Le=e.nodePasteRule,He=e.objectIncludes,Ke=e.pasteRulesPlugin,qe=e.posToDOMRect,Ge=e.removeDuplicates,ze=e.resolveFocusPosition,Je=e.rewriteUnknownContent,Ue=e.selectionToInsertionEnd,Ve=e.splitExtensions,Ye=e.textInputRule,Qe=e.textPasteRule,We=e.textblockTypeInputRule,Xe=e.wrappingInputRule;var l=r.create({name:"tableHeader",addOptions(){return{HTMLAttributes:{}}},content:"block+",addAttributes(){return{colspan:{default:1},rowspan:{default:1},colwidth:{default:null,parseHTML:t=>{let n=t.getAttribute("colwidth");return n?n.split(",").map(c=>parseInt(c,10)):null}}}},tableRole:"header_cell",isolating:!0,parseHTML(){return[{tag:"th"}]},renderHTML({HTMLAttributes:t}){return["th",s(this.options.HTMLAttributes,t),0]}});var a="__LEPTOS_TIPTAP_BRIDGE__";function u(){let t=globalThis,n=t[a];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[a]=o,o}function d(){return u()}function p(t){d().registerExtension(t)}var g={name:"table_header",create:()=>l};function st(){p(g)}export{st as register_table_header};
|
||||
+1
@@ -0,0 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=e.CommandManager,_=e.Editor,x=e.Extension,m=e.InputRule,b=e.Mark,r=e.Node,k=e.NodePos,y=e.NodeView,E=e.PasteRule,h=e.Tracker,R=e.callOrReturn,f=e.canInsertNode,P=e.combineTransactionSteps,T=e.createChainableState,C=e.createDocument,A=e.createNodeFromContent,S=e.createStyleTag,w=e.defaultBlockAt,N=e.deleteProps,O=e.elementFromString,B=e.escapeForRegEx,v=e.extensions,M=e.findChildren,I=e.findChildrenInRange,F=e.findDuplicates,D=e.findParentNode,j=e.findParentNodeClosestToPos,L=e.fromString,H=e.generateHTML,K=e.generateJSON,q=e.generateText,G=e.getAttributes,z=e.getAttributesFromExtensions,J=e.getChangedRanges,U=e.getDebugJSON,V=e.getExtensionField,Y=e.getHTMLFromFragment,Q=e.getMarkAttributes,W=e.getMarkRange,X=e.getMarkType,Z=e.getMarksBetween,$=e.getNodeAtPosition,ee=e.getNodeAttributes,te=e.getNodeType,ne=e.getRenderedAttributes,oe=e.getSchema,ie=e.getSchemaByResolvedExtensions,re=e.getSchemaTypeByName,se=e.getSchemaTypeNameByName,le=e.getSplittedAttributes,ae=e.getText,de=e.getTextBetween,pe=e.getTextContentFromNodes,ce=e.getTextSerializersFromSchema,ue=e.injectExtensionAttributesToParseRule,ge=e.inputRulesPlugin,_e=e.isActive,xe=e.isAtEndOfNode,me=e.isAtStartOfNode,be=e.isEmptyObject,ke=e.isExtensionRulesEnabled,ye=e.isFunction,Ee=e.isList,he=e.isMacOS,Re=e.isMarkActive,fe=e.isNodeActive,Pe=e.isNodeEmpty,Te=e.isNodeSelection,Ce=e.isNumber,Ae=e.isPlainObject,Se=e.isRegExp,we=e.isSafari,Ne=e.isString,Oe=e.isTextSelection,Be=e.isiOS,ve=e.markInputRule,Me=e.markPasteRule,s=e.mergeAttributes,Ie=e.mergeDeep,Fe=e.minMax,De=e.nodeInputRule,je=e.nodePasteRule,Le=e.objectIncludes,He=e.pasteRulesPlugin,Ke=e.posToDOMRect,qe=e.removeDuplicates,Ge=e.resolveFocusPosition,ze=e.rewriteUnknownContent,Je=e.selectionToInsertionEnd,Ue=e.splitExtensions,Ve=e.textInputRule,Ye=e.textPasteRule,Qe=e.textblockTypeInputRule,We=e.wrappingInputRule;var l=r.create({name:"tableRow",addOptions(){return{HTMLAttributes:{}}},content:"(tableCell | tableHeader)*",tableRole:"row",parseHTML(){return[{tag:"tr"}]},renderHTML({HTMLAttributes:t}){return["tr",s(this.options.HTMLAttributes,t),0]}});var a="__LEPTOS_TIPTAP_BRIDGE__";function c(){let t=globalThis,o=t[a];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[a]=i,i}function d(){return c()}function p(t){d().registerExtension(t)}var u={name:"table_row",create:()=>l};function rt(){p(u)}export{rt as register_table_row};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var u=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(u==null||u.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=u.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var P=t.CommandManager,S=t.Editor,O=t.Extension,N=t.InputRule,v=t.Mark,x=t.Node,w=t.NodePos,B=t.NodeView,I=t.PasteRule,M=t.Tracker,D=t.callOrReturn,F=t.canInsertNode,L=t.combineTransactionSteps,j=t.createChainableState,H=t.createDocument,K=t.createNodeFromContent,q=t.createStyleTag,G=t.defaultBlockAt,z=t.deleteProps,J=t.elementFromString,V=t.escapeForRegEx,Y=t.extensions,$=t.findChildren,U=t.findChildrenInRange,W=t.findDuplicates,Q=t.findParentNode,X=t.findParentNodeClosestToPos,Z=t.fromString,tt=t.generateHTML,et=t.generateJSON,nt=t.generateText,ot=t.getAttributes,it=t.getAttributesFromExtensions,rt=t.getChangedRanges,st=t.getDebugJSON,at=t.getExtensionField,lt=t.getHTMLFromFragment,dt=t.getMarkAttributes,ct=t.getMarkRange,pt=t.getMarkType,ut=t.getMarksBetween,gt=t.getNodeAtPosition,mt=t.getNodeAttributes,_t=t.getNodeType,xt=t.getRenderedAttributes,kt=t.getSchema,bt=t.getSchemaByResolvedExtensions,yt=t.getSchemaTypeByName,ht=t.getSchemaTypeNameByName,ft=t.getSplittedAttributes,Et=t.getText,Rt=t.getTextBetween,Tt=t.getTextContentFromNodes,At=t.getTextSerializersFromSchema,Ct=t.injectExtensionAttributesToParseRule,Pt=t.inputRulesPlugin,St=t.isActive,Ot=t.isAtEndOfNode,Nt=t.isAtStartOfNode,vt=t.isEmptyObject,wt=t.isExtensionRulesEnabled,Bt=t.isFunction,It=t.isList,Mt=t.isMacOS,Dt=t.isMarkActive,Ft=t.isNodeActive,Lt=t.isNodeEmpty,jt=t.isNodeSelection,Ht=t.isNumber,Kt=t.isPlainObject,qt=t.isRegExp,Gt=t.isSafari,zt=t.isString,Jt=t.isTextSelection,Vt=t.isiOS,Yt=t.markInputRule,$t=t.markPasteRule,k=t.mergeAttributes,Ut=t.mergeDeep,Wt=t.minMax,Qt=t.nodeInputRule,Xt=t.nodePasteRule,Zt=t.objectIncludes,te=t.pasteRulesPlugin,ee=t.posToDOMRect,ne=t.removeDuplicates,oe=t.resolveFocusPosition,ie=t.rewriteUnknownContent,re=t.selectionToInsertionEnd,se=t.splitExtensions,ae=t.textInputRule,le=t.textPasteRule,de=t.textblockTypeInputRule,b=t.wrappingInputRule;var T=/^\s*(\[([( |x])?\])\s$/,y=x.create({name:"taskItem",addOptions(){return{nested:!1,HTMLAttributes:{},taskListTypeName:"taskList",a11y:void 0}},content(){return this.options.nested?"paragraph block*":"paragraph+"},defining:!0,addAttributes(){return{checked:{default:!1,keepOnSplit:!1,parseHTML:e=>{let r=e.getAttribute("data-checked");return r===""||r==="true"},renderHTML:e=>({"data-checked":e.checked})}}},parseHTML(){return[{tag:`li[data-type="${this.name}"]`,priority:51}]},renderHTML({node:e,HTMLAttributes:r}){return["li",k(this.options.HTMLAttributes,r,{"data-type":this.name}),["label",["input",{type:"checkbox",checked:e.attrs.checked?"checked":null}],["span"]],["div",0]]},addKeyboardShortcuts(){let e={Enter:()=>this.editor.commands.splitListItem(this.name),"Shift-Tab":()=>this.editor.commands.liftListItem(this.name)};return this.options.nested?{...e,Tab:()=>this.editor.commands.sinkListItem(this.name)}:e},addNodeView(){return({node:e,HTMLAttributes:r,getPos:a,editor:l})=>{let s=document.createElement("li"),d=document.createElement("label"),R=document.createElement("span"),o=document.createElement("input"),g=document.createElement("div"),m=()=>{var n,i;o.ariaLabel=((i=(n=this.options.a11y)===null||n===void 0?void 0:n.checkboxLabel)===null||i===void 0?void 0:i.call(n,e,o.checked))||`Task item checkbox for ${e.textContent||"empty task item"}`};return m(),d.contentEditable="false",o.type="checkbox",o.addEventListener("mousedown",n=>n.preventDefault()),o.addEventListener("change",n=>{if(!l.isEditable&&!this.options.onReadOnlyChecked){o.checked=!o.checked;return}let{checked:i}=n.target;l.isEditable&&typeof a=="function"&&l.chain().focus(void 0,{scrollIntoView:!1}).command(({tr:_})=>{let c=a();if(typeof c!="number")return!1;let p=_.doc.nodeAt(c);return _.setNodeMarkup(c,void 0,{...p?.attrs,checked:i}),!0}).run(),!l.isEditable&&this.options.onReadOnlyChecked&&(this.options.onReadOnlyChecked(e,i)||(o.checked=!o.checked))}),Object.entries(this.options.HTMLAttributes).forEach(([n,i])=>{s.setAttribute(n,i)}),s.dataset.checked=e.attrs.checked,o.checked=e.attrs.checked,d.append(o,R),s.append(d,g),Object.entries(r).forEach(([n,i])=>{s.setAttribute(n,i)}),{dom:s,contentDOM:g,update:n=>n.type!==this.type?!1:(s.dataset.checked=n.attrs.checked,o.checked=n.attrs.checked,m(),!0)}}},addInputRules(){return[b({find:T,type:this.type,getAttributes:e=>({checked:e[e.length-1]==="x"})})]}});var h="__LEPTOS_TIPTAP_BRIDGE__";function A(){let e=globalThis,r=e[h];if(r!=null)return r;let a={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[h]=a,a}function f(){return A()}function E(e){f().registerExtension(e)}var C={name:"task_item",create:()=>y.configure({nested:!0})};function be(){E(C)}export{be as register_task_item};
|
||||
var u=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(u==null||u.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=u.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var P=e.CommandManager,S=e.Editor,w=e.Extension,O=e.InputRule,N=e.Mark,k=e.Node,v=e.NodePos,B=e.NodeView,I=e.PasteRule,M=e.Tracker,D=e.callOrReturn,F=e.canInsertNode,L=e.combineTransactionSteps,j=e.createChainableState,H=e.createDocument,K=e.createNodeFromContent,q=e.createStyleTag,G=e.defaultBlockAt,z=e.deleteProps,J=e.elementFromString,V=e.escapeForRegEx,Y=e.extensions,$=e.findChildren,U=e.findChildrenInRange,W=e.findDuplicates,Q=e.findParentNode,X=e.findParentNodeClosestToPos,Z=e.fromString,ee=e.generateHTML,te=e.generateJSON,ne=e.generateText,oe=e.getAttributes,ie=e.getAttributesFromExtensions,re=e.getChangedRanges,se=e.getDebugJSON,ae=e.getExtensionField,le=e.getHTMLFromFragment,de=e.getMarkAttributes,ce=e.getMarkRange,pe=e.getMarkType,ue=e.getMarksBetween,ge=e.getNodeAtPosition,_e=e.getNodeAttributes,me=e.getNodeType,ke=e.getRenderedAttributes,xe=e.getSchema,be=e.getSchemaByResolvedExtensions,ye=e.getSchemaTypeByName,he=e.getSchemaTypeNameByName,fe=e.getSplittedAttributes,Ee=e.getText,Re=e.getTextBetween,Te=e.getTextContentFromNodes,Ae=e.getTextSerializersFromSchema,Ce=e.injectExtensionAttributesToParseRule,Pe=e.inputRulesPlugin,Se=e.isActive,we=e.isAtEndOfNode,Oe=e.isAtStartOfNode,Ne=e.isEmptyObject,ve=e.isExtensionRulesEnabled,Be=e.isFunction,Ie=e.isList,Me=e.isMacOS,De=e.isMarkActive,Fe=e.isNodeActive,Le=e.isNodeEmpty,je=e.isNodeSelection,He=e.isNumber,Ke=e.isPlainObject,qe=e.isRegExp,Ge=e.isSafari,ze=e.isString,Je=e.isTextSelection,Ve=e.isiOS,Ye=e.markInputRule,$e=e.markPasteRule,x=e.mergeAttributes,Ue=e.mergeDeep,We=e.minMax,Qe=e.nodeInputRule,Xe=e.nodePasteRule,Ze=e.objectIncludes,et=e.pasteRulesPlugin,tt=e.posToDOMRect,nt=e.removeDuplicates,ot=e.resolveFocusPosition,it=e.rewriteUnknownContent,rt=e.selectionToInsertionEnd,st=e.splitExtensions,at=e.textInputRule,lt=e.textPasteRule,dt=e.textblockTypeInputRule,b=e.wrappingInputRule;var T=/^\s*(\[([( |x])?\])\s$/,y=k.create({name:"taskItem",addOptions(){return{nested:!1,HTMLAttributes:{},taskListTypeName:"taskList",a11y:void 0}},content(){return this.options.nested?"paragraph block*":"paragraph+"},defining:!0,addAttributes(){return{checked:{default:!1,keepOnSplit:!1,parseHTML:t=>{let r=t.getAttribute("data-checked");return r===""||r==="true"},renderHTML:t=>({"data-checked":t.checked})}}},parseHTML(){return[{tag:`li[data-type="${this.name}"]`,priority:51}]},renderHTML({node:t,HTMLAttributes:r}){return["li",x(this.options.HTMLAttributes,r,{"data-type":this.name}),["label",["input",{type:"checkbox",checked:t.attrs.checked?"checked":null}],["span"]],["div",0]]},addKeyboardShortcuts(){let t={Enter:()=>this.editor.commands.splitListItem(this.name),"Shift-Tab":()=>this.editor.commands.liftListItem(this.name)};return this.options.nested?{...t,Tab:()=>this.editor.commands.sinkListItem(this.name)}:t},addNodeView(){return({node:t,HTMLAttributes:r,getPos:a,editor:l})=>{let s=document.createElement("li"),d=document.createElement("label"),R=document.createElement("span"),o=document.createElement("input"),g=document.createElement("div"),_=()=>{var n,i;o.ariaLabel=((i=(n=this.options.a11y)===null||n===void 0?void 0:n.checkboxLabel)===null||i===void 0?void 0:i.call(n,t,o.checked))||`Task item checkbox for ${t.textContent||"empty task item"}`};return _(),d.contentEditable="false",o.type="checkbox",o.addEventListener("mousedown",n=>n.preventDefault()),o.addEventListener("change",n=>{if(!l.isEditable&&!this.options.onReadOnlyChecked){o.checked=!o.checked;return}let{checked:i}=n.target;l.isEditable&&typeof a=="function"&&l.chain().focus(void 0,{scrollIntoView:!1}).command(({tr:m})=>{let c=a();if(typeof c!="number")return!1;let p=m.doc.nodeAt(c);return m.setNodeMarkup(c,void 0,{...p?.attrs,checked:i}),!0}).run(),!l.isEditable&&this.options.onReadOnlyChecked&&(this.options.onReadOnlyChecked(t,i)||(o.checked=!o.checked))}),Object.entries(this.options.HTMLAttributes).forEach(([n,i])=>{s.setAttribute(n,i)}),s.dataset.checked=t.attrs.checked,o.checked=t.attrs.checked,d.append(o,R),s.append(d,g),Object.entries(r).forEach(([n,i])=>{s.setAttribute(n,i)}),{dom:s,contentDOM:g,update:n=>n.type!==this.type?!1:(s.dataset.checked=n.attrs.checked,o.checked=n.attrs.checked,_(),!0)}}},addInputRules(){return[b({find:T,type:this.type,getAttributes:t=>({checked:t[t.length-1]==="x"})})]}});var h="__LEPTOS_TIPTAP_BRIDGE__";function A(){let t=globalThis,r=t[h];if(r!=null)return r;let a={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[h]=a,a}function f(){return A()}function E(t){f().registerExtension(t)}var C={name:"task_item",create:()=>y.configure({nested:!0})};function bt(){E(C)}export{bt as register_task_item};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=t.CommandManager,_=t.Editor,x=t.Extension,m=t.InputRule,k=t.Mark,r=t.Node,b=t.NodePos,y=t.NodeView,h=t.PasteRule,E=t.Tracker,R=t.callOrReturn,T=t.canInsertNode,f=t.combineTransactionSteps,P=t.createChainableState,C=t.createDocument,A=t.createNodeFromContent,S=t.createStyleTag,N=t.defaultBlockAt,O=t.deleteProps,B=t.elementFromString,w=t.escapeForRegEx,v=t.extensions,M=t.findChildren,I=t.findChildrenInRange,F=t.findDuplicates,D=t.findParentNode,L=t.findParentNodeClosestToPos,j=t.fromString,K=t.generateHTML,H=t.generateJSON,q=t.generateText,G=t.getAttributes,z=t.getAttributesFromExtensions,J=t.getChangedRanges,U=t.getDebugJSON,V=t.getExtensionField,Y=t.getHTMLFromFragment,$=t.getMarkAttributes,Q=t.getMarkRange,W=t.getMarkType,X=t.getMarksBetween,Z=t.getNodeAtPosition,tt=t.getNodeAttributes,et=t.getNodeType,nt=t.getRenderedAttributes,ot=t.getSchema,it=t.getSchemaByResolvedExtensions,rt=t.getSchemaTypeByName,st=t.getSchemaTypeNameByName,at=t.getSplittedAttributes,lt=t.getText,dt=t.getTextBetween,pt=t.getTextContentFromNodes,ct=t.getTextSerializersFromSchema,ut=t.injectExtensionAttributesToParseRule,gt=t.inputRulesPlugin,_t=t.isActive,xt=t.isAtEndOfNode,mt=t.isAtStartOfNode,kt=t.isEmptyObject,bt=t.isExtensionRulesEnabled,yt=t.isFunction,ht=t.isList,Et=t.isMacOS,Rt=t.isMarkActive,Tt=t.isNodeActive,ft=t.isNodeEmpty,Pt=t.isNodeSelection,Ct=t.isNumber,At=t.isPlainObject,St=t.isRegExp,Nt=t.isSafari,Ot=t.isString,Bt=t.isTextSelection,wt=t.isiOS,vt=t.markInputRule,Mt=t.markPasteRule,s=t.mergeAttributes,It=t.mergeDeep,Ft=t.minMax,Dt=t.nodeInputRule,Lt=t.nodePasteRule,jt=t.objectIncludes,Kt=t.pasteRulesPlugin,Ht=t.posToDOMRect,qt=t.removeDuplicates,Gt=t.resolveFocusPosition,zt=t.rewriteUnknownContent,Jt=t.selectionToInsertionEnd,Ut=t.splitExtensions,Vt=t.textInputRule,Yt=t.textPasteRule,$t=t.textblockTypeInputRule,Qt=t.wrappingInputRule;var a=r.create({name:"taskList",addOptions(){return{itemTypeName:"taskItem",HTMLAttributes:{}}},group:"block list",content(){return`${this.options.itemTypeName}+`},parseHTML(){return[{tag:`ul[data-type="${this.name}"]`,priority:51}]},renderHTML({HTMLAttributes:e}){return["ul",s(this.options.HTMLAttributes,e,{"data-type":this.name}),0]},addCommands(){return{toggleTaskList:()=>({commands:e})=>e.toggleList(this.name,this.options.itemTypeName)}},addKeyboardShortcuts(){return{"Mod-Shift-9":()=>this.editor.commands.toggleTaskList()}}});var l="__LEPTOS_TIPTAP_BRIDGE__";function c(){let e=globalThis,o=e[l];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[l]=i,i}function d(){return c()}function p(e){d().registerExtension(e)}var u={name:"task_list",create:()=>a,commands:{toggle_task_list:e=>e.chain().focus().toggleTaskList().run()},selection_keys:["task_list"],selection_state:e=>({task_list:e.isActive("taskList")})};function re(){p(u)}export{re as register_task_list};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=t.CommandManager,_=t.Editor,m=t.Extension,x=t.InputRule,k=t.Mark,r=t.Node,b=t.NodePos,y=t.NodeView,h=t.PasteRule,E=t.Tracker,f=t.callOrReturn,R=t.canInsertNode,T=t.combineTransactionSteps,P=t.createChainableState,C=t.createDocument,A=t.createNodeFromContent,S=t.createStyleTag,N=t.defaultBlockAt,w=t.deleteProps,O=t.elementFromString,B=t.escapeForRegEx,v=t.extensions,M=t.findChildren,I=t.findChildrenInRange,F=t.findDuplicates,D=t.findParentNode,L=t.findParentNodeClosestToPos,j=t.fromString,K=t.generateHTML,H=t.generateJSON,q=t.generateText,G=t.getAttributes,z=t.getAttributesFromExtensions,J=t.getChangedRanges,U=t.getDebugJSON,V=t.getExtensionField,Y=t.getHTMLFromFragment,$=t.getMarkAttributes,Q=t.getMarkRange,W=t.getMarkType,X=t.getMarksBetween,Z=t.getNodeAtPosition,tt=t.getNodeAttributes,et=t.getNodeType,nt=t.getRenderedAttributes,ot=t.getSchema,it=t.getSchemaByResolvedExtensions,rt=t.getSchemaTypeByName,st=t.getSchemaTypeNameByName,lt=t.getSplittedAttributes,at=t.getText,dt=t.getTextBetween,pt=t.getTextContentFromNodes,ct=t.getTextSerializersFromSchema,ut=t.injectExtensionAttributesToParseRule,gt=t.inputRulesPlugin,_t=t.isActive,mt=t.isAtEndOfNode,xt=t.isAtStartOfNode,kt=t.isEmptyObject,bt=t.isExtensionRulesEnabled,yt=t.isFunction,ht=t.isList,Et=t.isMacOS,ft=t.isMarkActive,Rt=t.isNodeActive,Tt=t.isNodeEmpty,Pt=t.isNodeSelection,Ct=t.isNumber,At=t.isPlainObject,St=t.isRegExp,Nt=t.isSafari,wt=t.isString,Ot=t.isTextSelection,Bt=t.isiOS,vt=t.markInputRule,Mt=t.markPasteRule,s=t.mergeAttributes,It=t.mergeDeep,Ft=t.minMax,Dt=t.nodeInputRule,Lt=t.nodePasteRule,jt=t.objectIncludes,Kt=t.pasteRulesPlugin,Ht=t.posToDOMRect,qt=t.removeDuplicates,Gt=t.resolveFocusPosition,zt=t.rewriteUnknownContent,Jt=t.selectionToInsertionEnd,Ut=t.splitExtensions,Vt=t.textInputRule,Yt=t.textPasteRule,$t=t.textblockTypeInputRule,Qt=t.wrappingInputRule;var l=r.create({name:"taskList",addOptions(){return{itemTypeName:"taskItem",HTMLAttributes:{}}},group:"block list",content(){return`${this.options.itemTypeName}+`},parseHTML(){return[{tag:`ul[data-type="${this.name}"]`,priority:51}]},renderHTML({HTMLAttributes:e}){return["ul",s(this.options.HTMLAttributes,e,{"data-type":this.name}),0]},addCommands(){return{toggleTaskList:()=>({commands:e})=>e.toggleList(this.name,this.options.itemTypeName)}},addKeyboardShortcuts(){return{"Mod-Shift-9":()=>this.editor.commands.toggleTaskList()}}});var a="__LEPTOS_TIPTAP_BRIDGE__";function c(){let e=globalThis,o=e[a];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[a]=i,i}function d(){return c()}function p(e){d().registerExtension(e)}var u={name:"task_list",create:()=>l,commands:{toggle_task_list:e=>e.chain().focus().toggleTaskList().run()},selection_keys:["task_list"],selection_state:e=>({task_list:e.isActive("taskList")})};function re(){p(u)}export{re as register_task_list};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=n.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var u=t.CommandManager,g=t.Editor,_=t.Extension,x=t.InputRule,m=t.Mark,r=t.Node,k=t.NodePos,b=t.NodeView,y=t.PasteRule,E=t.Tracker,R=t.callOrReturn,h=t.canInsertNode,f=t.combineTransactionSteps,P=t.createChainableState,C=t.createDocument,T=t.createNodeFromContent,S=t.createStyleTag,A=t.defaultBlockAt,N=t.deleteProps,O=t.elementFromString,B=t.escapeForRegEx,w=t.extensions,v=t.findChildren,I=t.findChildrenInRange,M=t.findDuplicates,F=t.findParentNode,D=t.findParentNodeClosestToPos,j=t.fromString,L=t.generateHTML,K=t.generateJSON,q=t.generateText,G=t.getAttributes,H=t.getAttributesFromExtensions,z=t.getChangedRanges,J=t.getDebugJSON,U=t.getExtensionField,V=t.getHTMLFromFragment,Y=t.getMarkAttributes,Q=t.getMarkRange,W=t.getMarkType,X=t.getMarksBetween,Z=t.getNodeAtPosition,$=t.getNodeAttributes,tt=t.getNodeType,et=t.getRenderedAttributes,nt=t.getSchema,ot=t.getSchemaByResolvedExtensions,it=t.getSchemaTypeByName,rt=t.getSchemaTypeNameByName,st=t.getSplittedAttributes,lt=t.getText,at=t.getTextBetween,dt=t.getTextContentFromNodes,pt=t.getTextSerializersFromSchema,ct=t.injectExtensionAttributesToParseRule,ut=t.inputRulesPlugin,gt=t.isActive,_t=t.isAtEndOfNode,xt=t.isAtStartOfNode,mt=t.isEmptyObject,kt=t.isExtensionRulesEnabled,bt=t.isFunction,yt=t.isList,Et=t.isMacOS,Rt=t.isMarkActive,ht=t.isNodeActive,ft=t.isNodeEmpty,Pt=t.isNodeSelection,Ct=t.isNumber,Tt=t.isPlainObject,St=t.isRegExp,At=t.isSafari,Nt=t.isString,Ot=t.isTextSelection,Bt=t.isiOS,wt=t.markInputRule,vt=t.markPasteRule,It=t.mergeAttributes,Mt=t.mergeDeep,Ft=t.minMax,Dt=t.nodeInputRule,jt=t.nodePasteRule,Lt=t.objectIncludes,Kt=t.pasteRulesPlugin,qt=t.posToDOMRect,Gt=t.removeDuplicates,Ht=t.resolveFocusPosition,zt=t.rewriteUnknownContent,Jt=t.selectionToInsertionEnd,Ut=t.splitExtensions,Vt=t.textInputRule,Yt=t.textPasteRule,Qt=t.textblockTypeInputRule,Wt=t.wrappingInputRule;var s=r.create({name:"text",group:"inline"});var l="__LEPTOS_TIPTAP_BRIDGE__";function p(){let e=globalThis,o=e[l];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[l]=i,i}function a(){return p()}function d(e){a().registerExtension(e)}var c={name:"text",create:()=>s};function re(){d(c)}export{re as register_text};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var u=e.CommandManager,g=e.Editor,_=e.Extension,x=e.InputRule,m=e.Mark,r=e.Node,k=e.NodePos,b=e.NodeView,y=e.PasteRule,E=e.Tracker,h=e.callOrReturn,R=e.canInsertNode,f=e.combineTransactionSteps,P=e.createChainableState,C=e.createDocument,T=e.createNodeFromContent,S=e.createStyleTag,A=e.defaultBlockAt,w=e.deleteProps,N=e.elementFromString,O=e.escapeForRegEx,B=e.extensions,v=e.findChildren,I=e.findChildrenInRange,M=e.findDuplicates,F=e.findParentNode,D=e.findParentNodeClosestToPos,j=e.fromString,L=e.generateHTML,K=e.generateJSON,q=e.generateText,G=e.getAttributes,H=e.getAttributesFromExtensions,z=e.getChangedRanges,J=e.getDebugJSON,U=e.getExtensionField,V=e.getHTMLFromFragment,Y=e.getMarkAttributes,Q=e.getMarkRange,W=e.getMarkType,X=e.getMarksBetween,Z=e.getNodeAtPosition,$=e.getNodeAttributes,ee=e.getNodeType,te=e.getRenderedAttributes,ne=e.getSchema,oe=e.getSchemaByResolvedExtensions,ie=e.getSchemaTypeByName,re=e.getSchemaTypeNameByName,se=e.getSplittedAttributes,le=e.getText,ae=e.getTextBetween,de=e.getTextContentFromNodes,pe=e.getTextSerializersFromSchema,ce=e.injectExtensionAttributesToParseRule,ue=e.inputRulesPlugin,ge=e.isActive,_e=e.isAtEndOfNode,xe=e.isAtStartOfNode,me=e.isEmptyObject,ke=e.isExtensionRulesEnabled,be=e.isFunction,ye=e.isList,Ee=e.isMacOS,he=e.isMarkActive,Re=e.isNodeActive,fe=e.isNodeEmpty,Pe=e.isNodeSelection,Ce=e.isNumber,Te=e.isPlainObject,Se=e.isRegExp,Ae=e.isSafari,we=e.isString,Ne=e.isTextSelection,Oe=e.isiOS,Be=e.markInputRule,ve=e.markPasteRule,Ie=e.mergeAttributes,Me=e.mergeDeep,Fe=e.minMax,De=e.nodeInputRule,je=e.nodePasteRule,Le=e.objectIncludes,Ke=e.pasteRulesPlugin,qe=e.posToDOMRect,Ge=e.removeDuplicates,He=e.resolveFocusPosition,ze=e.rewriteUnknownContent,Je=e.selectionToInsertionEnd,Ue=e.splitExtensions,Ve=e.textInputRule,Ye=e.textPasteRule,Qe=e.textblockTypeInputRule,We=e.wrappingInputRule;var s=r.create({name:"text",group:"inline"});var l="__LEPTOS_TIPTAP_BRIDGE__";function p(){let t=globalThis,o=t[l];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[l]=i,i}function a(){return p()}function d(t){a().registerExtension(t)}var c={name:"text",create:()=>s};function rt(){d(c)}export{rt as register_text};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=i.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var u=t.CommandManager,x=t.Editor,r=t.Extension,_=t.InputRule,m=t.Mark,k=t.Node,b=t.NodePos,y=t.NodeView,f=t.PasteRule,h=t.Tracker,A=t.callOrReturn,E=t.canInsertNode,T=t.combineTransactionSteps,R=t.createChainableState,P=t.createDocument,S=t.createNodeFromContent,C=t.createStyleTag,N=t.defaultBlockAt,O=t.deleteProps,B=t.elementFromString,w=t.escapeForRegEx,v=t.extensions,M=t.findChildren,I=t.findChildrenInRange,j=t.findDuplicates,F=t.findParentNode,D=t.findParentNodeClosestToPos,L=t.fromString,K=t.generateHTML,G=t.generateJSON,H=t.generateText,q=t.getAttributes,z=t.getAttributesFromExtensions,J=t.getChangedRanges,U=t.getDebugJSON,V=t.getExtensionField,Y=t.getHTMLFromFragment,$=t.getMarkAttributes,Q=t.getMarkRange,W=t.getMarkType,X=t.getMarksBetween,Z=t.getNodeAtPosition,tt=t.getNodeAttributes,et=t.getNodeType,nt=t.getRenderedAttributes,ot=t.getSchema,it=t.getSchemaByResolvedExtensions,rt=t.getSchemaTypeByName,st=t.getSchemaTypeNameByName,lt=t.getSplittedAttributes,at=t.getText,dt=t.getTextBetween,pt=t.getTextContentFromNodes,gt=t.getTextSerializersFromSchema,ct=t.injectExtensionAttributesToParseRule,ut=t.inputRulesPlugin,xt=t.isActive,_t=t.isAtEndOfNode,mt=t.isAtStartOfNode,kt=t.isEmptyObject,bt=t.isExtensionRulesEnabled,yt=t.isFunction,ft=t.isList,ht=t.isMacOS,At=t.isMarkActive,Et=t.isNodeActive,Tt=t.isNodeEmpty,Rt=t.isNodeSelection,Pt=t.isNumber,St=t.isPlainObject,Ct=t.isRegExp,Nt=t.isSafari,Ot=t.isString,Bt=t.isTextSelection,wt=t.isiOS,vt=t.markInputRule,Mt=t.markPasteRule,It=t.mergeAttributes,jt=t.mergeDeep,Ft=t.minMax,Dt=t.nodeInputRule,Lt=t.nodePasteRule,Kt=t.objectIncludes,Gt=t.pasteRulesPlugin,Ht=t.posToDOMRect,qt=t.removeDuplicates,zt=t.resolveFocusPosition,Jt=t.rewriteUnknownContent,Ut=t.selectionToInsertionEnd,Vt=t.splitExtensions,Yt=t.textInputRule,$t=t.textPasteRule,Qt=t.textblockTypeInputRule,Wt=t.wrappingInputRule;var s=r.create({name:"textAlign",addOptions(){return{types:[],alignments:["left","center","right","justify"],defaultAlignment:null}},addGlobalAttributes(){return[{types:this.options.types,attributes:{textAlign:{default:this.options.defaultAlignment,parseHTML:e=>{let n=e.style.textAlign;return this.options.alignments.includes(n)?n:this.options.defaultAlignment},renderHTML:e=>e.textAlign?{style:`text-align: ${e.textAlign}`}:{}}}}]},addCommands(){return{setTextAlign:e=>({commands:n})=>this.options.alignments.includes(e)?this.options.types.map(o=>n.updateAttributes(o,{textAlign:e})).every(o=>o):!1,unsetTextAlign:()=>({commands:e})=>this.options.types.map(n=>e.resetAttributes(n,"textAlign")).every(n=>n),toggleTextAlign:e=>({editor:n,commands:o})=>this.options.alignments.includes(e)?n.isActive({textAlign:e})?o.unsetTextAlign():o.setTextAlign(e):!1}},addKeyboardShortcuts(){return{"Mod-Shift-l":()=>this.editor.commands.setTextAlign("left"),"Mod-Shift-e":()=>this.editor.commands.setTextAlign("center"),"Mod-Shift-r":()=>this.editor.commands.setTextAlign("right"),"Mod-Shift-j":()=>this.editor.commands.setTextAlign("justify")}}});var l="__LEPTOS_TIPTAP_BRIDGE__";function g(){let e=globalThis,n=e[l];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[l]=o,o}function a(){return g()}function d(e){a().registerExtension(e)}var p=["left","center","right","justify"],c={name:"text_align",create:()=>s.configure({types:["heading","paragraph"]}),commands:{set_text_align:(e,n)=>n.kind==="set_text_align"&&p.includes(n.alignment)?e.chain().focus().setTextAlign(n.alignment).run():!1,toggle_text_align:(e,n)=>n.kind==="toggle_text_align"&&p.includes(n.alignment)?e.chain().focus().toggleTextAlign(n.alignment).run():!1,unset_text_align:e=>e.chain().focus().unsetTextAlign().run()},selection_keys:["align_left","align_center","align_right","align_justify"],selection_state:e=>({align_left:e.isActive({textAlign:"left"}),align_center:e.isActive({textAlign:"center"}),align_right:e.isActive({textAlign:"right"}),align_justify:e.isActive({textAlign:"justify"})})};function se(){d(c)}export{se as register_text_align};
|
||||
var i=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(i==null||i.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=i.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=t.CommandManager,_=t.Editor,r=t.Extension,x=t.InputRule,m=t.Mark,k=t.Node,b=t.NodePos,y=t.NodeView,f=t.PasteRule,h=t.Tracker,A=t.callOrReturn,E=t.canInsertNode,T=t.combineTransactionSteps,R=t.createChainableState,P=t.createDocument,S=t.createNodeFromContent,C=t.createStyleTag,w=t.defaultBlockAt,N=t.deleteProps,O=t.elementFromString,B=t.escapeForRegEx,v=t.extensions,M=t.findChildren,I=t.findChildrenInRange,j=t.findDuplicates,F=t.findParentNode,D=t.findParentNodeClosestToPos,L=t.fromString,K=t.generateHTML,G=t.generateJSON,H=t.generateText,q=t.getAttributes,z=t.getAttributesFromExtensions,J=t.getChangedRanges,U=t.getDebugJSON,V=t.getExtensionField,Y=t.getHTMLFromFragment,$=t.getMarkAttributes,Q=t.getMarkRange,W=t.getMarkType,X=t.getMarksBetween,Z=t.getNodeAtPosition,tt=t.getNodeAttributes,et=t.getNodeType,nt=t.getRenderedAttributes,ot=t.getSchema,it=t.getSchemaByResolvedExtensions,rt=t.getSchemaTypeByName,st=t.getSchemaTypeNameByName,lt=t.getSplittedAttributes,at=t.getText,dt=t.getTextBetween,pt=t.getTextContentFromNodes,ut=t.getTextSerializersFromSchema,ct=t.injectExtensionAttributesToParseRule,gt=t.inputRulesPlugin,_t=t.isActive,xt=t.isAtEndOfNode,mt=t.isAtStartOfNode,kt=t.isEmptyObject,bt=t.isExtensionRulesEnabled,yt=t.isFunction,ft=t.isList,ht=t.isMacOS,At=t.isMarkActive,Et=t.isNodeActive,Tt=t.isNodeEmpty,Rt=t.isNodeSelection,Pt=t.isNumber,St=t.isPlainObject,Ct=t.isRegExp,wt=t.isSafari,Nt=t.isString,Ot=t.isTextSelection,Bt=t.isiOS,vt=t.markInputRule,Mt=t.markPasteRule,It=t.mergeAttributes,jt=t.mergeDeep,Ft=t.minMax,Dt=t.nodeInputRule,Lt=t.nodePasteRule,Kt=t.objectIncludes,Gt=t.pasteRulesPlugin,Ht=t.posToDOMRect,qt=t.removeDuplicates,zt=t.resolveFocusPosition,Jt=t.rewriteUnknownContent,Ut=t.selectionToInsertionEnd,Vt=t.splitExtensions,Yt=t.textInputRule,$t=t.textPasteRule,Qt=t.textblockTypeInputRule,Wt=t.wrappingInputRule;var s=r.create({name:"textAlign",addOptions(){return{types:[],alignments:["left","center","right","justify"],defaultAlignment:null}},addGlobalAttributes(){return[{types:this.options.types,attributes:{textAlign:{default:this.options.defaultAlignment,parseHTML:e=>{let n=e.style.textAlign;return this.options.alignments.includes(n)?n:this.options.defaultAlignment},renderHTML:e=>e.textAlign?{style:`text-align: ${e.textAlign}`}:{}}}}]},addCommands(){return{setTextAlign:e=>({commands:n})=>this.options.alignments.includes(e)?this.options.types.map(o=>n.updateAttributes(o,{textAlign:e})).every(o=>o):!1,unsetTextAlign:()=>({commands:e})=>this.options.types.map(n=>e.resetAttributes(n,"textAlign")).every(n=>n),toggleTextAlign:e=>({editor:n,commands:o})=>this.options.alignments.includes(e)?n.isActive({textAlign:e})?o.unsetTextAlign():o.setTextAlign(e):!1}},addKeyboardShortcuts(){return{"Mod-Shift-l":()=>this.editor.commands.setTextAlign("left"),"Mod-Shift-e":()=>this.editor.commands.setTextAlign("center"),"Mod-Shift-r":()=>this.editor.commands.setTextAlign("right"),"Mod-Shift-j":()=>this.editor.commands.setTextAlign("justify")}}});var l="__LEPTOS_TIPTAP_BRIDGE__";function u(){let e=globalThis,n=e[l];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[l]=o,o}function a(){return u()}function d(e){a().registerExtension(e)}var p=["left","center","right","justify"],c={name:"text_align",create:()=>s.configure({types:["heading","paragraph"]}),commands:{set_text_align:(e,n)=>n.kind==="set_text_align"&&p.includes(n.alignment)?e.chain().focus().setTextAlign(n.alignment).run():!1,toggle_text_align:(e,n)=>n.kind==="toggle_text_align"&&p.includes(n.alignment)?e.chain().focus().toggleTextAlign(n.alignment).run():!1,unset_text_align:e=>e.chain().focus().unsetTextAlign().run()},selection_keys:["align_left","align_center","align_right","align_justify"],selection_state:e=>({align_left:e.isActive({textAlign:"left"}),align_center:e.isActive({textAlign:"center"}),align_right:e.isActive({textAlign:"right"}),align_justify:e.isActive({textAlign:"justify"})})};function se(){d(c)}export{se as register_text_align};
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
var l=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(l==null||l.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=l.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var f=t.CommandManager,h=t.Editor,a=t.Extension,E=t.InputRule,d=t.Mark,S=t.Node,R=t.NodePos,C=t.NodeView,T=t.PasteRule,A=t.Tracker,P=t.callOrReturn,N=t.canInsertNode,O=t.combineTransactionSteps,v=t.createChainableState,B=t.createDocument,w=t.createNodeFromContent,M=t.createStyleTag,I=t.defaultBlockAt,F=t.deleteProps,D=t.elementFromString,j=t.escapeForRegEx,L=t.extensions,H=t.findChildren,K=t.findChildrenInRange,q=t.findDuplicates,G=t.findParentNode,z=t.findParentNodeClosestToPos,J=t.fromString,$=t.generateHTML,U=t.generateJSON,V=t.generateText,Y=t.getAttributes,Q=t.getAttributesFromExtensions,W=t.getChangedRanges,X=t.getDebugJSON,Z=t.getExtensionField,tt=t.getHTMLFromFragment,et=t.getMarkAttributes,nt=t.getMarkRange,ot=t.getMarkType,rt=t.getMarksBetween,it=t.getNodeAtPosition,st=t.getNodeAttributes,lt=t.getNodeType,at=t.getRenderedAttributes,dt=t.getSchema,pt=t.getSchemaByResolvedExtensions,ct=t.getSchemaTypeByName,ut=t.getSchemaTypeNameByName,gt=t.getSplittedAttributes,_t=t.getText,xt=t.getTextBetween,mt=t.getTextContentFromNodes,kt=t.getTextSerializersFromSchema,bt=t.injectExtensionAttributesToParseRule,yt=t.inputRulesPlugin,ft=t.isActive,ht=t.isAtEndOfNode,Et=t.isAtStartOfNode,St=t.isEmptyObject,Rt=t.isExtensionRulesEnabled,Ct=t.isFunction,Tt=t.isList,At=t.isMacOS,Pt=t.isMarkActive,Nt=t.isNodeActive,Ot=t.isNodeEmpty,vt=t.isNodeSelection,Bt=t.isNumber,wt=t.isPlainObject,Mt=t.isRegExp,It=t.isSafari,Ft=t.isString,Dt=t.isTextSelection,jt=t.isiOS,Lt=t.markInputRule,Ht=t.markPasteRule,p=t.mergeAttributes,Kt=t.mergeDeep,qt=t.minMax,Gt=t.nodeInputRule,zt=t.nodePasteRule,Jt=t.objectIncludes,$t=t.pasteRulesPlugin,Ut=t.posToDOMRect,Vt=t.removeDuplicates,Yt=t.resolveFocusPosition,Qt=t.rewriteUnknownContent,Wt=t.selectionToInsertionEnd,Xt=t.splitExtensions,Zt=t.textInputRule,te=t.textPasteRule,ee=t.textblockTypeInputRule,ne=t.wrappingInputRule;var k=e=>{if(!e.children.length)return;let n=e.querySelectorAll("span");n&&n.forEach(o=>{var i,r;let s=o.getAttribute("style"),m=(r=(i=o.parentElement)===null||i===void 0?void 0:i.closest("span"))===null||r===void 0?void 0:r.getAttribute("style");o.setAttribute("style",`${m};${s}`)})},c=d.create({name:"textStyle",priority:101,addOptions(){return{HTMLAttributes:{},mergeNestedSpanStyles:!1}},parseHTML(){return[{tag:"span",getAttrs:e=>e.hasAttribute("style")?(this.options.mergeNestedSpanStyles&&k(e),{}):!1}]},renderHTML({HTMLAttributes:e}){return["span",p(this.options.HTMLAttributes,e),0]},addCommands(){return{removeEmptyTextStyle:()=>({tr:e})=>{let{selection:n}=e;return e.doc.nodesBetween(n.from,n.to,(o,i)=>{if(o.isTextblock)return!0;o.marks.filter(r=>r.type===this.type).some(r=>Object.values(r.attrs).some(s=>!!s))||e.removeMark(i,i+o.nodeSize,this.type)}),!0}}}});var u=a.create({name:"color",addOptions(){return{types:["textStyle"]}},addGlobalAttributes(){return[{types:this.options.types,attributes:{color:{default:null,parseHTML:e=>{var n;return(n=e.style.color)===null||n===void 0?void 0:n.replace(/['"]+/g,"")},renderHTML:e=>e.color?{style:`color: ${e.color}`}:{}}}}]},addCommands(){return{setColor:e=>({chain:n})=>n().setMark("textStyle",{color:e}).run(),unsetColor:()=>({chain:e})=>e().setMark("textStyle",{color:null}).removeEmptyTextStyle().run()}}});var g="__LEPTOS_TIPTAP_BRIDGE__";function b(){let e=globalThis,n=e[g];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[g]=o,o}function _(){return b()}function x(e){_().registerExtension(e)}var y={name:"text_style",create:()=>[c,u],commands:{set_color:(e,n)=>n.kind==="set_color"?e.chain().focus().setColor(n.attributes.color).run():!1,unset_color:e=>e.chain().focus().unsetColor().run()},selection_keys:["text_style"],selection_state:e=>({text_style:e.isActive("textStyle")})};function xe(){x(y)}export{xe as register_text_style};
|
||||
var l=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(l==null||l.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var t=l.modules["@tiptap/core"];if(t==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var f=t.CommandManager,h=t.Editor,a=t.Extension,E=t.InputRule,d=t.Mark,S=t.Node,R=t.NodePos,C=t.NodeView,T=t.PasteRule,A=t.Tracker,P=t.callOrReturn,w=t.canInsertNode,N=t.combineTransactionSteps,O=t.createChainableState,v=t.createDocument,B=t.createNodeFromContent,M=t.createStyleTag,I=t.defaultBlockAt,F=t.deleteProps,D=t.elementFromString,j=t.escapeForRegEx,L=t.extensions,H=t.findChildren,K=t.findChildrenInRange,q=t.findDuplicates,G=t.findParentNode,z=t.findParentNodeClosestToPos,J=t.fromString,$=t.generateHTML,U=t.generateJSON,V=t.generateText,Y=t.getAttributes,Q=t.getAttributesFromExtensions,W=t.getChangedRanges,X=t.getDebugJSON,Z=t.getExtensionField,tt=t.getHTMLFromFragment,et=t.getMarkAttributes,nt=t.getMarkRange,ot=t.getMarkType,rt=t.getMarksBetween,it=t.getNodeAtPosition,st=t.getNodeAttributes,lt=t.getNodeType,at=t.getRenderedAttributes,dt=t.getSchema,pt=t.getSchemaByResolvedExtensions,ct=t.getSchemaTypeByName,ut=t.getSchemaTypeNameByName,gt=t.getSplittedAttributes,_t=t.getText,xt=t.getTextBetween,mt=t.getTextContentFromNodes,kt=t.getTextSerializersFromSchema,bt=t.injectExtensionAttributesToParseRule,yt=t.inputRulesPlugin,ft=t.isActive,ht=t.isAtEndOfNode,Et=t.isAtStartOfNode,St=t.isEmptyObject,Rt=t.isExtensionRulesEnabled,Ct=t.isFunction,Tt=t.isList,At=t.isMacOS,Pt=t.isMarkActive,wt=t.isNodeActive,Nt=t.isNodeEmpty,Ot=t.isNodeSelection,vt=t.isNumber,Bt=t.isPlainObject,Mt=t.isRegExp,It=t.isSafari,Ft=t.isString,Dt=t.isTextSelection,jt=t.isiOS,Lt=t.markInputRule,Ht=t.markPasteRule,p=t.mergeAttributes,Kt=t.mergeDeep,qt=t.minMax,Gt=t.nodeInputRule,zt=t.nodePasteRule,Jt=t.objectIncludes,$t=t.pasteRulesPlugin,Ut=t.posToDOMRect,Vt=t.removeDuplicates,Yt=t.resolveFocusPosition,Qt=t.rewriteUnknownContent,Wt=t.selectionToInsertionEnd,Xt=t.splitExtensions,Zt=t.textInputRule,te=t.textPasteRule,ee=t.textblockTypeInputRule,ne=t.wrappingInputRule;var k=e=>{if(!e.children.length)return;let n=e.querySelectorAll("span");n&&n.forEach(o=>{var i,r;let s=o.getAttribute("style"),m=(r=(i=o.parentElement)===null||i===void 0?void 0:i.closest("span"))===null||r===void 0?void 0:r.getAttribute("style");o.setAttribute("style",`${m};${s}`)})},c=d.create({name:"textStyle",priority:101,addOptions(){return{HTMLAttributes:{},mergeNestedSpanStyles:!1}},parseHTML(){return[{tag:"span",getAttrs:e=>e.hasAttribute("style")?(this.options.mergeNestedSpanStyles&&k(e),{}):!1}]},renderHTML({HTMLAttributes:e}){return["span",p(this.options.HTMLAttributes,e),0]},addCommands(){return{removeEmptyTextStyle:()=>({tr:e})=>{let{selection:n}=e;return e.doc.nodesBetween(n.from,n.to,(o,i)=>{if(o.isTextblock)return!0;o.marks.filter(r=>r.type===this.type).some(r=>Object.values(r.attrs).some(s=>!!s))||e.removeMark(i,i+o.nodeSize,this.type)}),!0}}}});var u=a.create({name:"color",addOptions(){return{types:["textStyle"]}},addGlobalAttributes(){return[{types:this.options.types,attributes:{color:{default:null,parseHTML:e=>{var n;return(n=e.style.color)===null||n===void 0?void 0:n.replace(/['"]+/g,"")},renderHTML:e=>e.color?{style:`color: ${e.color}`}:{}}}}]},addCommands(){return{setColor:e=>({chain:n})=>n().setMark("textStyle",{color:e}).run(),unsetColor:()=>({chain:e})=>e().setMark("textStyle",{color:null}).removeEmptyTextStyle().run()}}});var g="__LEPTOS_TIPTAP_BRIDGE__";function b(){let e=globalThis,n=e[g];if(n!=null)return n;let o={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return e[g]=o,o}function _(){return b()}function x(e){_().registerExtension(e)}var y={name:"text_style",create:()=>[c,u],commands:{set_color:(e,n)=>n.kind==="set_color"?e.chain().focus().setColor(n.attributes.color).run():!1,unset_color:e=>e.chain().focus().unsetColor().run()},selection_keys:["text_style"],selection_state:e=>({text_style:e.isActive("textStyle")})};function xe(){x(y)}export{xe as register_text_style};
|
||||
|
||||
+1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=e.CommandManager,_=e.Editor,x=e.Extension,m=e.InputRule,r=e.Mark,k=e.Node,b=e.NodePos,y=e.NodeView,E=e.PasteRule,h=e.Tracker,R=e.callOrReturn,f=e.canInsertNode,P=e.combineTransactionSteps,C=e.createChainableState,T=e.createDocument,A=e.createNodeFromContent,S=e.createStyleTag,N=e.defaultBlockAt,O=e.deleteProps,B=e.elementFromString,w=e.escapeForRegEx,M=e.extensions,v=e.findChildren,I=e.findChildrenInRange,F=e.findDuplicates,D=e.findParentNode,j=e.findParentNodeClosestToPos,L=e.fromString,K=e.generateHTML,H=e.generateJSON,U=e.generateText,q=e.getAttributes,G=e.getAttributesFromExtensions,z=e.getChangedRanges,J=e.getDebugJSON,V=e.getExtensionField,Y=e.getHTMLFromFragment,Q=e.getMarkAttributes,W=e.getMarkRange,X=e.getMarkType,Z=e.getMarksBetween,$=e.getNodeAtPosition,ee=e.getNodeAttributes,te=e.getNodeType,ne=e.getRenderedAttributes,oe=e.getSchema,ie=e.getSchemaByResolvedExtensions,re=e.getSchemaTypeByName,se=e.getSchemaTypeNameByName,le=e.getSplittedAttributes,ae=e.getText,de=e.getTextBetween,pe=e.getTextContentFromNodes,ce=e.getTextSerializersFromSchema,ue=e.injectExtensionAttributesToParseRule,ge=e.inputRulesPlugin,_e=e.isActive,xe=e.isAtEndOfNode,me=e.isAtStartOfNode,ke=e.isEmptyObject,be=e.isExtensionRulesEnabled,ye=e.isFunction,Ee=e.isList,he=e.isMacOS,Re=e.isMarkActive,fe=e.isNodeActive,Pe=e.isNodeEmpty,Ce=e.isNodeSelection,Te=e.isNumber,Ae=e.isPlainObject,Se=e.isRegExp,Ne=e.isSafari,Oe=e.isString,Be=e.isTextSelection,we=e.isiOS,Me=e.markInputRule,ve=e.markPasteRule,s=e.mergeAttributes,Ie=e.mergeDeep,Fe=e.minMax,De=e.nodeInputRule,je=e.nodePasteRule,Le=e.objectIncludes,Ke=e.pasteRulesPlugin,He=e.posToDOMRect,Ue=e.removeDuplicates,qe=e.resolveFocusPosition,Ge=e.rewriteUnknownContent,ze=e.selectionToInsertionEnd,Je=e.splitExtensions,Ve=e.textInputRule,Ye=e.textPasteRule,Qe=e.textblockTypeInputRule,We=e.wrappingInputRule;var l=r.create({name:"underline",addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"u"},{style:"text-decoration",consuming:!1,getAttrs:t=>t.includes("underline")?{}:!1}]},renderHTML({HTMLAttributes:t}){return["u",s(this.options.HTMLAttributes,t),0]},addCommands(){return{setUnderline:()=>({commands:t})=>t.setMark(this.name),toggleUnderline:()=>({commands:t})=>t.toggleMark(this.name),unsetUnderline:()=>({commands:t})=>t.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-u":()=>this.editor.commands.toggleUnderline(),"Mod-U":()=>this.editor.commands.toggleUnderline()}}});var a="__LEPTOS_TIPTAP_BRIDGE__";function c(){let t=globalThis,o=t[a];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[a]=i,i}function d(){return c()}function p(t){d().registerExtension(t)}var u={name:"underline",create:()=>l,selection_keys:["underline"],selection_state:t=>({underline:t.isActive("underline")})};function rt(){p(u)}export{rt as register_underline};
|
||||
var n=globalThis.__LEPTOS_TIPTAP_BRIDGE__;if(n==null||n.modules==null)throw new Error("leptos-tiptap bridge bindings are unavailable");var e=n.modules["@tiptap/core"];if(e==null)throw new Error('leptos-tiptap bridge module "@tiptap/core" is unavailable');var g=e.CommandManager,_=e.Editor,x=e.Extension,m=e.InputRule,r=e.Mark,k=e.Node,b=e.NodePos,y=e.NodeView,h=e.PasteRule,E=e.Tracker,f=e.callOrReturn,R=e.canInsertNode,P=e.combineTransactionSteps,C=e.createChainableState,T=e.createDocument,A=e.createNodeFromContent,S=e.createStyleTag,w=e.defaultBlockAt,N=e.deleteProps,O=e.elementFromString,B=e.escapeForRegEx,M=e.extensions,v=e.findChildren,I=e.findChildrenInRange,F=e.findDuplicates,D=e.findParentNode,j=e.findParentNodeClosestToPos,L=e.fromString,K=e.generateHTML,H=e.generateJSON,U=e.generateText,q=e.getAttributes,G=e.getAttributesFromExtensions,z=e.getChangedRanges,J=e.getDebugJSON,V=e.getExtensionField,Y=e.getHTMLFromFragment,Q=e.getMarkAttributes,W=e.getMarkRange,X=e.getMarkType,Z=e.getMarksBetween,$=e.getNodeAtPosition,ee=e.getNodeAttributes,te=e.getNodeType,ne=e.getRenderedAttributes,oe=e.getSchema,ie=e.getSchemaByResolvedExtensions,re=e.getSchemaTypeByName,se=e.getSchemaTypeNameByName,le=e.getSplittedAttributes,ae=e.getText,de=e.getTextBetween,pe=e.getTextContentFromNodes,ue=e.getTextSerializersFromSchema,ce=e.injectExtensionAttributesToParseRule,ge=e.inputRulesPlugin,_e=e.isActive,xe=e.isAtEndOfNode,me=e.isAtStartOfNode,ke=e.isEmptyObject,be=e.isExtensionRulesEnabled,ye=e.isFunction,he=e.isList,Ee=e.isMacOS,fe=e.isMarkActive,Re=e.isNodeActive,Pe=e.isNodeEmpty,Ce=e.isNodeSelection,Te=e.isNumber,Ae=e.isPlainObject,Se=e.isRegExp,we=e.isSafari,Ne=e.isString,Oe=e.isTextSelection,Be=e.isiOS,Me=e.markInputRule,ve=e.markPasteRule,s=e.mergeAttributes,Ie=e.mergeDeep,Fe=e.minMax,De=e.nodeInputRule,je=e.nodePasteRule,Le=e.objectIncludes,Ke=e.pasteRulesPlugin,He=e.posToDOMRect,Ue=e.removeDuplicates,qe=e.resolveFocusPosition,Ge=e.rewriteUnknownContent,ze=e.selectionToInsertionEnd,Je=e.splitExtensions,Ve=e.textInputRule,Ye=e.textPasteRule,Qe=e.textblockTypeInputRule,We=e.wrappingInputRule;var l=r.create({name:"underline",addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"u"},{style:"text-decoration",consuming:!1,getAttrs:t=>t.includes("underline")?{}:!1}]},renderHTML({HTMLAttributes:t}){return["u",s(this.options.HTMLAttributes,t),0]},addCommands(){return{setUnderline:()=>({commands:t})=>t.setMark(this.name),toggleUnderline:()=>({commands:t})=>t.toggleMark(this.name),unsetUnderline:()=>({commands:t})=>t.unsetMark(this.name)}},addKeyboardShortcuts(){return{"Mod-u":()=>this.editor.commands.toggleUnderline(),"Mod-U":()=>this.editor.commands.toggleUnderline()}}});var a="__LEPTOS_TIPTAP_BRIDGE__";function u(){let t=globalThis,o=t[a];if(o!=null)return o;let i={modules:{},registerExtension:()=>{throw new Error("leptos-tiptap bridge runtime is not initialized")}};return t[a]=i,i}function d(){return u()}function p(t){d().registerExtension(t)}var c={name:"underline",create:()=>l,selection_keys:["underline"],selection_state:t=>({underline:t.isActive("underline")})};function rt(){p(c)}export{rt as register_underline};
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+58
@@ -0,0 +1,58 @@
|
||||
|
||||
export function select_mnote_image_node(image) {
|
||||
try {
|
||||
const root = image?.closest?.('.ProseMirror');
|
||||
const editor = root?.editor;
|
||||
const view = editor?.view;
|
||||
if (!editor || !view || typeof view.posAtDOM !== 'function') return false;
|
||||
const pos = view.posAtDOM(image, 0);
|
||||
if (!Number.isFinite(pos)) return false;
|
||||
return editor.chain().focus().setNodeSelection(pos).run() === true;
|
||||
} catch (error) {
|
||||
console.warn('mnote image NodeSelection failed', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function mnoteImageExtension(url, contentType) {
|
||||
const urlMatch = String(url || '').match(/\.([a-zA-Z0-9]+)(?:[?#].*)?$/);
|
||||
if (urlMatch?.[1]) return `.${urlMatch[1].toLowerCase()}`;
|
||||
const mimeMap = {
|
||||
'image/jpeg': '.jpg',
|
||||
'image/jpg': '.jpg',
|
||||
'image/png': '.png',
|
||||
'image/gif': '.gif',
|
||||
'image/webp': '.webp',
|
||||
'image/svg+xml': '.svg',
|
||||
'image/bmp': '.bmp',
|
||||
};
|
||||
return mimeMap[String(contentType || '').toLowerCase()] || '.jpg';
|
||||
}
|
||||
|
||||
function mnoteImageFilename(image, url) {
|
||||
const raw = image.getAttribute('title') || image.getAttribute('alt') || `image-${Date.now()}`;
|
||||
const base = raw.replace(/[\/:*?"<>|]+/g, '-').trim() || `image-${Date.now()}`;
|
||||
return /\.[a-zA-Z0-9]+$/.test(base) ? base : `${base}${mnoteImageExtension(url)}`;
|
||||
}
|
||||
|
||||
export function download_mnote_selected_image() {
|
||||
try {
|
||||
const image = document.querySelector('.editor-surface .ProseMirror img.ProseMirror-selectednode[src]');
|
||||
if (!(image instanceof HTMLImageElement)) return false;
|
||||
const src = image.getAttribute('src');
|
||||
if (!src) return false;
|
||||
const url = new URL(src, window.location.href);
|
||||
if (!(url.protocol === 'http:' || url.protocol === 'https:' || url.protocol === 'data:')) return false;
|
||||
const link = document.createElement('a');
|
||||
link.href = url.href;
|
||||
link.download = mnoteImageFilename(image, url.href);
|
||||
link.style.display = 'none';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.warn('mnote image download failed', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert");
|
||||
const fs = require("node:fs");
|
||||
const { chromium } = require("playwright");
|
||||
const { fetchWithTimeout } = require("./task114-rust-web-gateway-entry-smoke.js");
|
||||
|
||||
const BASE_URL = (process.env.MNOTE_UI_BASE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
|
||||
const UI_TIMEOUT_MS = Number(process.env.MNOTE_SMOKE_UI_TIMEOUT_MS || 30_000);
|
||||
const SCREENSHOT_DIR = process.env.MNOTE_PHASE_E_SCREENSHOT_DIR || "/mnt/Data1T/mnote/tmp/wolai-editor-parity/task144-e19-indent-local-smoke";
|
||||
|
||||
async function readJsonResponse(response, label) {
|
||||
const text = await response.text();
|
||||
let payload = null;
|
||||
try {
|
||||
payload = text ? JSON.parse(text) : null;
|
||||
} catch {
|
||||
throw new Error(`${label} 返回了非 JSON 内容: ${text.slice(0, 1200)}`);
|
||||
}
|
||||
assert(response.ok, `${label} 请求失败: ${response.status}; body: ${text.slice(0, 1200)}`);
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function postTreeCommand(body, label) {
|
||||
const response = await fetchWithTimeout(`${BASE_URL}/api/tree/commands`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const payload = await readJsonResponse(response, label);
|
||||
assert(payload?.result, `${label} 缺少 result`);
|
||||
return payload.result;
|
||||
}
|
||||
|
||||
async function createTempDocument() {
|
||||
const title = `task144-e19-indent-${Date.now().toString(36)}`;
|
||||
const result = await postTreeCommand({ action: "create", title }, "创建 E19 临时文档");
|
||||
assert(result.documentId, "创建 E19 临时文档缺少 documentId");
|
||||
assert(result.workspaceId, "创建 E19 临时文档缺少 workspaceId");
|
||||
return { documentId: result.documentId, workspaceId: result.workspaceId, title };
|
||||
}
|
||||
|
||||
async function purgeTempDocument(target) {
|
||||
if (!target?.documentId || !target?.workspaceId) return;
|
||||
await postTreeCommand({ action: "purge", workspaceId: target.workspaceId, documentId: target.documentId }, "清理 E19 临时文档");
|
||||
}
|
||||
|
||||
async function loadDocumentContent(target, label) {
|
||||
const url = `${BASE_URL}/api/documents/content?documentId=${encodeURIComponent(target.documentId)}&workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await fetchWithTimeout(url, { method: "GET" });
|
||||
return readJsonResponse(response, label);
|
||||
}
|
||||
|
||||
async function waitForRuntimeIsland(page) {
|
||||
const root = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"]').first();
|
||||
await root.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const editor = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror[contenteditable="true"]').first();
|
||||
await editor.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const editorNode = host?.querySelector('.editor-surface .ProseMirror[contenteditable="true"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") !== "error" && editorNode instanceof HTMLElement && editorNode.isContentEditable;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
return editor;
|
||||
}
|
||||
|
||||
async function waitForSavedText(page, text) {
|
||||
await page.waitForFunction((expected) => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const editor = host?.querySelector('.editor-surface .ProseMirror');
|
||||
return host?.getAttribute("data-runtime-editor-status") === "saved" && (editor?.textContent || "").includes(expected);
|
||||
}, text, { timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
|
||||
async function screenshot(page, name) {
|
||||
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
|
||||
await page.screenshot({ path: `${SCREENSHOT_DIR}/${name}.png`, fullPage: true });
|
||||
}
|
||||
|
||||
function collectTypes(value, out = []) {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((item) => collectTypes(item, out));
|
||||
return out;
|
||||
}
|
||||
if (!value || typeof value !== "object") return out;
|
||||
if (typeof value.type === "string") out.push(value.type);
|
||||
collectTypes(value.content, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
function hasNestedBulletList(value) {
|
||||
if (!value || typeof value !== "object") return false;
|
||||
if (Array.isArray(value)) return value.some(hasNestedBulletList);
|
||||
if (value.type === "listItem" && Array.isArray(value.content)) {
|
||||
return value.content.some((item) => item?.type === "bulletList" || item?.type === "orderedList" || item?.type === "taskList");
|
||||
}
|
||||
if ((value.type === "bullet_list_item" || value.type === "numbered_list_item" || value.type === "todo") && Array.isArray(value.children)) {
|
||||
return value.children.length > 0;
|
||||
}
|
||||
return hasNestedBulletList(value.content);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext({ viewport: { width: 1440, height: 960 } });
|
||||
const page = await context.newPage();
|
||||
const saveRequests = [];
|
||||
page.on("request", (request) => {
|
||||
if (!request.url().includes("/api/documents/save")) return;
|
||||
const body = request.postData();
|
||||
if (!body) return;
|
||||
try {
|
||||
saveRequests.push(JSON.parse(body));
|
||||
} catch {
|
||||
saveRequests.push({ raw: body });
|
||||
}
|
||||
});
|
||||
|
||||
let target = null;
|
||||
try {
|
||||
target = await createTempDocument();
|
||||
const url = `${BASE_URL}/documents/${encodeURIComponent(target.documentId)}?workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await page.goto(url, { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
assert(response, "文档页没有返回响应");
|
||||
assert.equal(response.status(), 200, `文档页状态码异常: ${response.status()}`);
|
||||
|
||||
const editor = await waitForRuntimeIsland(page);
|
||||
await editor.click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.keyboard.type("/");
|
||||
const slashBullet = page.locator('[data-testid="slash-item-bullet"]').first();
|
||||
await slashBullet.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await slashBullet.click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.keyboard.type("E19 parent");
|
||||
await page.keyboard.press("Enter");
|
||||
await page.keyboard.type("E19 child");
|
||||
await waitForSavedText(page, "E19 child");
|
||||
await screenshot(page, "01-before-indent");
|
||||
|
||||
await page.keyboard.press("Tab");
|
||||
await page.waitForFunction(() => !!document.querySelector('.editor-surface .ProseMirror ul li ul li'), null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedText(page, "E19 child");
|
||||
await screenshot(page, "02-after-tab-indent");
|
||||
|
||||
const lastSave = saveRequests.at(-1);
|
||||
assert(lastSave?.tiptapDocument, `Tab 缩进后必须走 /api/documents/save 并提交 tiptapDocument: ${JSON.stringify(lastSave).slice(0, 1200)}`);
|
||||
assert(hasNestedBulletList(lastSave.tiptapDocument), `保存请求里的 Tiptap JSON 必须包含真实嵌套列表结构: ${JSON.stringify(lastSave.tiptapDocument).slice(0, 1600)}`);
|
||||
assert(collectTypes(lastSave.tiptapDocument).filter((type) => type === "bulletList").length >= 2, "保存请求应包含父/子两层 bulletList");
|
||||
|
||||
await page.keyboard.press("Shift+Tab");
|
||||
await page.waitForFunction(() => !document.querySelector('.editor-surface .ProseMirror ul li ul li'), null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedText(page, "E19 child");
|
||||
await screenshot(page, "03-after-shift-tab-outdent");
|
||||
|
||||
await page.keyboard.press("Tab");
|
||||
await page.waitForFunction(() => !!document.querySelector('.editor-surface .ProseMirror ul li ul li'), null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedText(page, "E19 child");
|
||||
await page.reload({ waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
await waitForRuntimeIsland(page);
|
||||
await page.waitForFunction(() => !!document.querySelector('.editor-surface .ProseMirror ul li ul li'), null, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "04-after-reload-nested-list");
|
||||
|
||||
const contentAfterReload = await loadDocumentContent(target, "读取缩进保存后的正文");
|
||||
const savedContent = contentAfterReload?.result?.content;
|
||||
assert(hasNestedBulletList(savedContent), `刷新后的 /api/documents/content 必须保留嵌套列表真源: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
|
||||
console.log(JSON.stringify({ ok: true, baseUrl: BASE_URL, documentId: target.documentId, screenshotDir: SCREENSHOT_DIR }, null, 2));
|
||||
} finally {
|
||||
if (target) await purgeTempDocument(target).catch(() => undefined);
|
||||
await page.close().catch(() => undefined);
|
||||
await context.close().catch(() => undefined);
|
||||
await browser.close().catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.stack || error.message : String(error));
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert");
|
||||
const fs = require("node:fs");
|
||||
const { chromium } = require("playwright");
|
||||
const { fetchWithTimeout } = require("./task114-rust-web-gateway-entry-smoke.js");
|
||||
|
||||
const BASE_URL = (process.env.MNOTE_UI_BASE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
|
||||
const UI_TIMEOUT_MS = Number(process.env.MNOTE_SMOKE_UI_TIMEOUT_MS || 30_000);
|
||||
const SCREENSHOT_DIR = process.env.MNOTE_PHASE_E_SCREENSHOT_DIR || "/mnt/Data1T/mnote/tmp/wolai-editor-parity/task145-e20-alignment-local-smoke";
|
||||
|
||||
async function readJsonResponse(response, label) {
|
||||
const text = await response.text();
|
||||
let payload = null;
|
||||
try {
|
||||
payload = text ? JSON.parse(text) : null;
|
||||
} catch {
|
||||
throw new Error(`${label} 返回了非 JSON 内容: ${text.slice(0, 1200)}`);
|
||||
}
|
||||
assert(response.ok, `${label} 请求失败: ${response.status}; body: ${text.slice(0, 1200)}`);
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function postTreeCommand(body, label) {
|
||||
const response = await fetchWithTimeout(`${BASE_URL}/api/tree/commands`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const payload = await readJsonResponse(response, label);
|
||||
assert(payload?.result, `${label} 缺少 result`);
|
||||
return payload.result;
|
||||
}
|
||||
|
||||
async function createTempDocument() {
|
||||
const title = `task145-e20-align-${Date.now().toString(36)}`;
|
||||
const result = await postTreeCommand({ action: "create", title }, "创建 E20 临时文档");
|
||||
assert(result.documentId, "创建 E20 临时文档缺少 documentId");
|
||||
assert(result.workspaceId, "创建 E20 临时文档缺少 workspaceId");
|
||||
return { documentId: result.documentId, workspaceId: result.workspaceId, title };
|
||||
}
|
||||
|
||||
async function purgeTempDocument(target) {
|
||||
if (!target?.documentId || !target?.workspaceId) return;
|
||||
await postTreeCommand({ action: "purge", workspaceId: target.workspaceId, documentId: target.documentId }, "清理 E20 临时文档");
|
||||
}
|
||||
|
||||
async function loadDocumentContent(target, label) {
|
||||
const url = `${BASE_URL}/api/documents/content?documentId=${encodeURIComponent(target.documentId)}&workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await fetchWithTimeout(url, { method: "GET" });
|
||||
return readJsonResponse(response, label);
|
||||
}
|
||||
|
||||
async function waitForRuntimeIsland(page) {
|
||||
const root = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"]').first();
|
||||
await root.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const editor = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror[contenteditable="true"]').first();
|
||||
await editor.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const editorNode = host?.querySelector('.editor-surface .ProseMirror[contenteditable="true"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") !== "error" && editorNode instanceof HTMLElement && editorNode.isContentEditable;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
return editor;
|
||||
}
|
||||
|
||||
async function waitForSavedText(page, text) {
|
||||
await page.waitForFunction((expected) => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const editor = host?.querySelector('.editor-surface .ProseMirror');
|
||||
return host?.getAttribute("data-runtime-editor-status") === "saved" && (editor?.textContent || "").includes(expected);
|
||||
}, text, { timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
|
||||
async function screenshot(page, name) {
|
||||
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
|
||||
await page.screenshot({ path: `${SCREENSHOT_DIR}/${name}.png`, fullPage: true });
|
||||
}
|
||||
|
||||
function findNodeWithTextAlign(value, align = "center") {
|
||||
if (!value || typeof value !== "object") return null;
|
||||
if (Array.isArray(value)) return value.map((item) => findNodeWithTextAlign(item, align)).find(Boolean) || null;
|
||||
if (value.attrs?.textAlign === align || value.props?.textAlign === align) return value;
|
||||
return findNodeWithTextAlign(value.content, align) || findNodeWithTextAlign(value.children, align) || null;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext({ viewport: { width: 1440, height: 960 } });
|
||||
const page = await context.newPage();
|
||||
const saveRequests = [];
|
||||
page.on("request", (request) => {
|
||||
if (!request.url().includes("/api/documents/save")) return;
|
||||
const body = request.postData();
|
||||
if (!body) return;
|
||||
try {
|
||||
saveRequests.push(JSON.parse(body));
|
||||
} catch {
|
||||
saveRequests.push({ raw: body });
|
||||
}
|
||||
});
|
||||
|
||||
let target = null;
|
||||
try {
|
||||
target = await createTempDocument();
|
||||
const url = `${BASE_URL}/documents/${encodeURIComponent(target.documentId)}?workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await page.goto(url, { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
assert(response, "文档页没有返回响应");
|
||||
assert.equal(response.status(), 200, `文档页状态码异常: ${response.status()}`);
|
||||
|
||||
const editor = await waitForRuntimeIsland(page);
|
||||
await editor.click({ timeout: UI_TIMEOUT_MS });
|
||||
const text = `E20 align center ${Date.now().toString(36)}`;
|
||||
await page.keyboard.type(text);
|
||||
await waitForSavedText(page, text);
|
||||
await screenshot(page, "01-before-align");
|
||||
|
||||
await page.keyboard.press("Control+Shift+U");
|
||||
const layoutOutline = page.locator('[data-testid="block-layout-outline"]').first();
|
||||
await layoutOutline.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const outlineStyle = await layoutOutline.evaluate((node) => {
|
||||
const style = window.getComputedStyle(node);
|
||||
return {
|
||||
borderStyle: style.borderTopStyle,
|
||||
borderColor: style.borderTopColor,
|
||||
minHeight: style.minHeight,
|
||||
};
|
||||
});
|
||||
assert.equal(outlineStyle.borderStyle, "dashed", `Ctrl+Shift+U 后块布局轮廓应为虚线: ${JSON.stringify(outlineStyle)}`);
|
||||
await screenshot(page, "01a-after-layout-hotkey");
|
||||
|
||||
const firstBlock = page.locator('.editor-surface .ProseMirror > *').filter({ hasText: text }).first();
|
||||
await firstBlock.hover({ timeout: UI_TIMEOUT_MS });
|
||||
const handle = page.locator('[data-testid="mnote-leptos-tiptap-handle"]').first();
|
||||
await handle.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.locator('[data-testid="block-drag-handle-trigger"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
const menu = page.locator('[data-testid="block-drag-menu"]').first();
|
||||
await menu.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.locator('[data-testid="block-drag-menu-item-align-center"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
|
||||
await page.waitForFunction((expected) => {
|
||||
const block = Array.from(document.querySelectorAll('.editor-surface .ProseMirror > *')).find((node) => (node.textContent || '').includes(expected));
|
||||
return block && window.getComputedStyle(block).textAlign === 'center';
|
||||
}, text, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedText(page, text);
|
||||
await screenshot(page, "02-after-align-center");
|
||||
|
||||
const lastSave = saveRequests.at(-1);
|
||||
assert(lastSave?.tiptapDocument, `居中后必须提交 tiptapDocument: ${JSON.stringify(lastSave).slice(0, 1200)}`);
|
||||
assert(findNodeWithTextAlign(lastSave.tiptapDocument, "center"), `保存请求 Tiptap JSON 必须包含 attrs.textAlign=center: ${JSON.stringify(lastSave.tiptapDocument).slice(0, 1600)}`);
|
||||
|
||||
const contentAfterAlign = await loadDocumentContent(target, "读取对齐保存后的正文");
|
||||
const savedContent = contentAfterAlign?.result?.content;
|
||||
assert(findNodeWithTextAlign(savedContent, "center"), `/api/documents/content 必须保留 props.textAlign=center: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
|
||||
await page.reload({ waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
await waitForRuntimeIsland(page);
|
||||
await page.waitForFunction((expected) => {
|
||||
const block = Array.from(document.querySelectorAll('.editor-surface .ProseMirror > *')).find((node) => (node.textContent || '').includes(expected));
|
||||
return block && window.getComputedStyle(block).textAlign === 'center';
|
||||
}, text, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "03-after-reload-align-center");
|
||||
|
||||
console.log(JSON.stringify({ ok: true, baseUrl: BASE_URL, documentId: target.documentId, screenshotDir: SCREENSHOT_DIR }, null, 2));
|
||||
} finally {
|
||||
if (target) await purgeTempDocument(target).catch(() => undefined);
|
||||
await page.close().catch(() => undefined);
|
||||
await context.close().catch(() => undefined);
|
||||
await browser.close().catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.stack || error.message : String(error));
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert");
|
||||
const fs = require("node:fs");
|
||||
const { chromium } = require("playwright");
|
||||
const { fetchWithTimeout } = require("./task114-rust-web-gateway-entry-smoke.js");
|
||||
|
||||
const BASE_URL = (process.env.MNOTE_UI_BASE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
|
||||
const UI_TIMEOUT_MS = Number(process.env.MNOTE_SMOKE_UI_TIMEOUT_MS || 30_000);
|
||||
const SCREENSHOT_DIR = process.env.MNOTE_PHASE_E_SCREENSHOT_DIR || "/mnt/Data1T/mnote/tmp/wolai-editor-parity/task150-e22-folding-blocks-local-smoke";
|
||||
|
||||
async function readJsonResponse(response, label) {
|
||||
const text = await response.text();
|
||||
let payload = null;
|
||||
try {
|
||||
payload = text ? JSON.parse(text) : null;
|
||||
} catch {
|
||||
throw new Error(`${label} 返回了非 JSON 内容: ${text.slice(0, 1200)}`);
|
||||
}
|
||||
assert(response.ok, `${label} 请求失败: ${response.status}; body: ${text.slice(0, 1200)}`);
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function postTreeCommand(body, label) {
|
||||
const response = await fetchWithTimeout(`${BASE_URL}/api/tree/commands`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const payload = await readJsonResponse(response, label);
|
||||
assert(payload?.result, `${label} 缺少 result`);
|
||||
return payload.result;
|
||||
}
|
||||
|
||||
async function createTempDocument() {
|
||||
const title = `task150-e22-folding-${Date.now().toString(36)}`;
|
||||
const result = await postTreeCommand({ action: "create", title }, "创建 E22 临时文档");
|
||||
assert(result.documentId, "创建 E22 临时文档缺少 documentId");
|
||||
assert(result.workspaceId, "创建 E22 临时文档缺少 workspaceId");
|
||||
return { documentId: result.documentId, workspaceId: result.workspaceId, title };
|
||||
}
|
||||
|
||||
async function purgeTempDocument(target) {
|
||||
if (!target?.documentId || !target?.workspaceId) return;
|
||||
await postTreeCommand({ action: "purge", workspaceId: target.workspaceId, documentId: target.documentId }, "清理 E22 临时文档");
|
||||
}
|
||||
|
||||
async function loadDocumentContent(target, label) {
|
||||
const url = `${BASE_URL}/api/documents/content?documentId=${encodeURIComponent(target.documentId)}&workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await fetchWithTimeout(url, { method: "GET" });
|
||||
return readJsonResponse(response, label);
|
||||
}
|
||||
|
||||
async function waitForRuntimeIsland(page) {
|
||||
const root = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"]').first();
|
||||
await root.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const editor = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror[contenteditable="true"]').first();
|
||||
await editor.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const editorNode = host?.querySelector('.editor-surface .ProseMirror[contenteditable="true"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") !== "error" && editorNode instanceof HTMLElement && editorNode.isContentEditable;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
return editor;
|
||||
}
|
||||
|
||||
async function waitForSavedText(page, text) {
|
||||
await page.waitForFunction((expected) => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const editor = host?.querySelector('.editor-surface .ProseMirror');
|
||||
return host?.getAttribute("data-runtime-editor-status") === "saved" && (editor?.textContent || "").includes(expected);
|
||||
}, text, { timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
|
||||
async function screenshot(page, name) {
|
||||
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
|
||||
await page.screenshot({ path: `${SCREENSHOT_DIR}/${name}.png`, fullPage: true });
|
||||
}
|
||||
|
||||
function findCollapsedHeading(value) {
|
||||
if (!value || typeof value !== "object") return null;
|
||||
if (Array.isArray(value)) return value.map(findCollapsedHeading).find(Boolean) || null;
|
||||
const isHeading = value.type === "heading" || value.blockType === "heading";
|
||||
const attrs = value.attrs || value.props || {};
|
||||
if (isHeading && (attrs.collapsed === true || value.collapsed === true)) return value;
|
||||
return findCollapsedHeading(value.content) || findCollapsedHeading(value.children) || null;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext({ viewport: { width: 1440, height: 960 } });
|
||||
const page = await context.newPage();
|
||||
const saveRequests = [];
|
||||
page.on("request", (request) => {
|
||||
if (!request.url().includes("/api/documents/save")) return;
|
||||
const body = request.postData();
|
||||
if (!body) return;
|
||||
try {
|
||||
saveRequests.push(JSON.parse(body));
|
||||
} catch {
|
||||
saveRequests.push({ raw: body });
|
||||
}
|
||||
});
|
||||
|
||||
let target = null;
|
||||
try {
|
||||
target = await createTempDocument();
|
||||
const url = `${BASE_URL}/documents/${encodeURIComponent(target.documentId)}?workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await page.goto(url, { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
assert(response, "文档页没有返回响应");
|
||||
assert.equal(response.status(), 200, `文档页状态码异常: ${response.status()}`);
|
||||
|
||||
const editor = await waitForRuntimeIsland(page);
|
||||
await editor.click({ timeout: UI_TIMEOUT_MS });
|
||||
const text = `E22 folded heading ${Date.now().toString(36)}`;
|
||||
await page.keyboard.type(text);
|
||||
await waitForSavedText(page, text);
|
||||
await screenshot(page, "01-before-folded-title");
|
||||
|
||||
const firstBlock = page.locator('.editor-surface .ProseMirror > *').filter({ hasText: text }).first();
|
||||
await firstBlock.hover({ timeout: UI_TIMEOUT_MS });
|
||||
await page.locator('[data-testid="mnote-leptos-tiptap-handle"]').first().waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.locator('[data-testid="block-drag-handle-trigger"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.locator('[data-testid="block-drag-menu"]').first().waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.locator('[data-testid="block-drag-menu-item-turn-into"]').first().hover({ timeout: UI_TIMEOUT_MS });
|
||||
const transformMenu = page.locator('[data-testid="block-transform-submenu"]').first();
|
||||
await transformMenu.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "02-transform-submenu-before-e22");
|
||||
|
||||
const foldedTitle = page.locator('[data-testid="block-transform-item-folded-title"]').first();
|
||||
assert.equal(await foldedTitle.isDisabled(), false, "折叠标题不能是 disabled 静态文案");
|
||||
await foldedTitle.hover({ timeout: UI_TIMEOUT_MS });
|
||||
const foldedTitleSubmenu = page.locator('[data-testid="block-transform-folded-title-submenu"]').first();
|
||||
await foldedTitleSubmenu.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const labels = await foldedTitleSubmenu.locator('[data-testid^="block-transform-folded-heading-"]').evaluateAll((nodes) => nodes.map((node) => (node.textContent || "").trim()));
|
||||
for (const expected of ["折叠主标题", "折叠大标题", "折叠中标题", "折叠小标题"]) {
|
||||
assert(labels.some((label) => label.includes(expected)), `折叠标题三级菜单缺少 ${expected}: ${labels.join(" | ")}`);
|
||||
}
|
||||
await screenshot(page, "03-folded-title-tertiary-submenu");
|
||||
|
||||
await page.locator('[data-testid="block-transform-folded-heading-1"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction((expected) => {
|
||||
const heading = Array.from(document.querySelectorAll('.editor-surface .ProseMirror h1')).find((node) => (node.textContent || '').includes(expected));
|
||||
return heading instanceof HTMLElement && heading.getAttribute('data-collapsed') === 'true';
|
||||
}, text, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedText(page, text);
|
||||
await screenshot(page, "04-after-folded-heading-click");
|
||||
|
||||
const lastSave = saveRequests.at(-1);
|
||||
assert(lastSave?.tiptapDocument, `折叠标题后必须提交 tiptapDocument: ${JSON.stringify(lastSave).slice(0, 1200)}`);
|
||||
assert(findCollapsedHeading(lastSave.tiptapDocument), `保存请求 Tiptap JSON 必须包含 heading attrs.collapsed=true: ${JSON.stringify(lastSave.tiptapDocument).slice(0, 1600)}`);
|
||||
|
||||
const contentAfterFold = await loadDocumentContent(target, "读取折叠标题保存后的正文");
|
||||
const savedContent = contentAfterFold?.result?.content;
|
||||
assert(findCollapsedHeading(savedContent), `/api/documents/content 必须保留折叠标题语义: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
|
||||
await page.reload({ waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
await waitForRuntimeIsland(page);
|
||||
await page.waitForFunction((expected) => {
|
||||
const heading = Array.from(document.querySelectorAll('.editor-surface .ProseMirror h1')).find((node) => (node.textContent || '').includes(expected));
|
||||
return heading instanceof HTMLElement && heading.getAttribute('data-collapsed') === 'true';
|
||||
}, text, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "05-after-reload-folded-heading");
|
||||
|
||||
console.log(JSON.stringify({ ok: true, baseUrl: BASE_URL, documentId: target.documentId, screenshotDir: SCREENSHOT_DIR }, null, 2));
|
||||
} finally {
|
||||
if (target) await purgeTempDocument(target).catch(() => undefined);
|
||||
await page.close().catch(() => undefined);
|
||||
await context.close().catch(() => undefined);
|
||||
await browser.close().catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.stack || error.message : String(error));
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,439 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert");
|
||||
const fs = require("node:fs");
|
||||
const { chromium } = require("playwright");
|
||||
const { fetchWithTimeout } = require("./task114-rust-web-gateway-entry-smoke.js");
|
||||
|
||||
const BASE_URL = (process.env.MNOTE_UI_BASE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
|
||||
const UI_TIMEOUT_MS = Number(process.env.MNOTE_SMOKE_UI_TIMEOUT_MS || 30_000);
|
||||
const SCREENSHOT_DIR = process.env.MNOTE_PHASE_E_SCREENSHOT_DIR || "/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-table-local-smoke";
|
||||
|
||||
const TABLE_EXTENSION_SOURCE = "/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/tiptap/src/extensions/tiptap_table.ts";
|
||||
const LEPTOS_SPIKE_SOURCE = "/mnt/Data1T/mnote/rust/spikes/leptos-tiptap-spike/src/lib.rs";
|
||||
|
||||
function assertOfficialTableSelectionBridge() {
|
||||
const source = fs.readFileSync(TABLE_EXTENSION_SOURCE, "utf8");
|
||||
assert(
|
||||
source.includes("CellSelection.rowSelection") && source.includes("CellSelection.colSelection"),
|
||||
"E23 表格行/列选择必须复用 @tiptap/pm/tables 的 CellSelection.rowSelection/colSelection",
|
||||
);
|
||||
assert(
|
||||
!source.includes("setCellSelection"),
|
||||
"E23 表格行/列选择不能绕过官方 CellSelection 静态选择逻辑",
|
||||
);
|
||||
}
|
||||
|
||||
function assertOfficialTableInsertBridge() {
|
||||
const source = fs.readFileSync(LEPTOS_SPIKE_SOURCE, "utf8");
|
||||
assert(
|
||||
source.includes("editor.insert_table(4, 3, false)"),
|
||||
"E23 简单表格必须通过 bridge 调用 Tiptap 官方 insertTable(rows=4, cols=3, withHeaderRow=false)",
|
||||
);
|
||||
assert(
|
||||
!source.includes(`insert_content(
|
||||
TiptapContent::json(simple_table_node())`),
|
||||
"E23 简单表格不能再通过手写 JSON simple_table_node() 走 insert_content",
|
||||
);
|
||||
}
|
||||
|
||||
async function readJsonResponse(response, label) {
|
||||
const text = await response.text();
|
||||
let payload = null;
|
||||
try {
|
||||
payload = text ? JSON.parse(text) : null;
|
||||
} catch {
|
||||
throw new Error(`${label} 返回了非 JSON 内容: ${text.slice(0, 1200)}`);
|
||||
}
|
||||
assert(response.ok, `${label} 请求失败: ${response.status}; body: ${text.slice(0, 1200)}`);
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function postTreeCommand(body, label) {
|
||||
const response = await fetchWithTimeout(`${BASE_URL}/api/tree/commands`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const payload = await readJsonResponse(response, label);
|
||||
assert(payload?.result, `${label} 缺少 result`);
|
||||
return payload.result;
|
||||
}
|
||||
|
||||
async function createTempDocument() {
|
||||
const title = `task151-e23-table-${Date.now().toString(36)}`;
|
||||
const result = await postTreeCommand({ action: "create", title }, "创建 E23 临时文档");
|
||||
assert(result.documentId, "创建 E23 临时文档缺少 documentId");
|
||||
assert(result.workspaceId, "创建 E23 临时文档缺少 workspaceId");
|
||||
return { documentId: result.documentId, workspaceId: result.workspaceId, title };
|
||||
}
|
||||
|
||||
async function purgeTempDocument(target) {
|
||||
if (!target?.documentId || !target?.workspaceId) return;
|
||||
await postTreeCommand({ action: "purge", workspaceId: target.workspaceId, documentId: target.documentId }, "清理 E23 临时文档");
|
||||
}
|
||||
|
||||
async function loadDocumentContent(target, label) {
|
||||
const url = `${BASE_URL}/api/documents/content?documentId=${encodeURIComponent(target.documentId)}&workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await fetchWithTimeout(url, { method: "GET" });
|
||||
return readJsonResponse(response, label);
|
||||
}
|
||||
|
||||
async function waitForRuntimeIsland(page) {
|
||||
const root = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"]').first();
|
||||
await root.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const editor = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror[contenteditable="true"]').first();
|
||||
await editor.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const editorNode = host?.querySelector('.editor-surface .ProseMirror[contenteditable="true"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") !== "error" && editorNode instanceof HTMLElement && editorNode.isContentEditable;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
return editor;
|
||||
}
|
||||
|
||||
async function waitForSavedTable(page, minRows = 2, minCells = 4) {
|
||||
await page.waitForFunction(({ minRows, minCells }) => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const table = host?.querySelector('.editor-surface .ProseMirror table');
|
||||
return host?.getAttribute("data-runtime-editor-status") === "saved"
|
||||
&& table instanceof HTMLTableElement
|
||||
&& table.querySelectorAll('tr').length >= minRows
|
||||
&& table.querySelectorAll('td,th').length >= minCells;
|
||||
}, { minRows, minCells }, { timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
|
||||
async function waitForSavedWithoutTable(page) {
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") === "saved"
|
||||
&& !host.querySelector('.editor-surface .ProseMirror table');
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
|
||||
async function screenshot(page, name) {
|
||||
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
|
||||
await page.screenshot({ path: `${SCREENSHOT_DIR}/${name}.png`, fullPage: true });
|
||||
}
|
||||
|
||||
async function clickTableCell(page, { row = 0, col = 0, text = null } = {}) {
|
||||
const point = await page.locator('.editor-surface .ProseMirror table').first().evaluate((table, options) => {
|
||||
const rows = Array.from(table.querySelectorAll('tr'));
|
||||
let cell = null;
|
||||
if (options.text) {
|
||||
cell = Array.from(table.querySelectorAll('td,th')).find((candidate) => (candidate.textContent || '').includes(options.text));
|
||||
} else {
|
||||
const rowIndex = options.row < 0 ? rows.length + options.row : options.row;
|
||||
const targetRow = rows[rowIndex];
|
||||
const cells = targetRow ? Array.from(targetRow.querySelectorAll('td,th')) : [];
|
||||
const colIndex = options.col < 0 ? cells.length + options.col : options.col;
|
||||
cell = cells[colIndex] || null;
|
||||
}
|
||||
if (!(cell instanceof HTMLElement)) return null;
|
||||
const rect = cell.getBoundingClientRect();
|
||||
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
|
||||
}, { row, col, text });
|
||||
assert(point, `找不到可点击的表格单元格: ${JSON.stringify({ row, col, text })}`);
|
||||
await page.mouse.click(point.x, point.y);
|
||||
}
|
||||
|
||||
function findTable(value) {
|
||||
if (!value || typeof value !== "object") return null;
|
||||
if (Array.isArray(value)) return value.map(findTable).find(Boolean) || null;
|
||||
if (value.type === "table" || value.blockType === "table") return value;
|
||||
return findTable(value.content) || findTable(value.children) || findTable(value.props?.tiptapTable);
|
||||
}
|
||||
|
||||
function tableText(value) {
|
||||
if (!value || typeof value !== "object") return "";
|
||||
if (Array.isArray(value)) return value.map(tableText).join("");
|
||||
if (typeof value.text === "string") return value.text;
|
||||
if (typeof value.content === "string") return value.content;
|
||||
return `${tableText(value.content)}${tableText(value.children)}${tableText(value.props?.tiptapTable)}`;
|
||||
}
|
||||
|
||||
function countNodeType(value, type) {
|
||||
if (!value || typeof value !== "object") return 0;
|
||||
if (Array.isArray(value)) return value.reduce((sum, item) => sum + countNodeType(item, type), 0);
|
||||
const own = value.type === type || value.blockType === type ? 1 : 0;
|
||||
return own + countNodeType(value.content, type) + countNodeType(value.children, type) + countNodeType(value.props?.tiptapTable, type);
|
||||
}
|
||||
|
||||
function findColwidth(value) {
|
||||
if (!value || typeof value !== "object") return null;
|
||||
if (Array.isArray(value)) return value.map(findColwidth).find(Boolean) || null;
|
||||
const colwidth = value.attrs?.colwidth;
|
||||
if (Array.isArray(colwidth) && colwidth.some((width) => typeof width === "number" && width > 0)) {
|
||||
return colwidth;
|
||||
}
|
||||
return findColwidth(value.content) || findColwidth(value.children) || findColwidth(value.props?.tiptapTable);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext({ viewport: { width: 1440, height: 960 } });
|
||||
const page = await context.newPage();
|
||||
const saveRequests = [];
|
||||
page.on("request", (request) => {
|
||||
if (!request.url().includes("/api/documents/save")) return;
|
||||
const body = request.postData();
|
||||
if (!body) return;
|
||||
try {
|
||||
saveRequests.push(JSON.parse(body));
|
||||
} catch {
|
||||
saveRequests.push({ raw: body });
|
||||
}
|
||||
});
|
||||
|
||||
assertOfficialTableSelectionBridge();
|
||||
assertOfficialTableInsertBridge();
|
||||
|
||||
let target = null;
|
||||
try {
|
||||
target = await createTempDocument();
|
||||
const url = `${BASE_URL}/documents/${encodeURIComponent(target.documentId)}?workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await page.goto(url, { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
assert(response, "文档页没有返回响应");
|
||||
assert.equal(response.status(), 200, `文档页状态码异常: ${response.status()}`);
|
||||
|
||||
const editor = await waitForRuntimeIsland(page);
|
||||
await editor.click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.keyboard.type("/");
|
||||
const slash = page.locator('[data-testid="mnote-leptos-tiptap-slash-menu"]').first();
|
||||
await slash.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const slashText = await slash.innerText();
|
||||
assert(slashText.includes("进阶块列表"), `slash 菜单缺少进阶块列表: ${slashText}`);
|
||||
assert(slashText.includes("简单表格"), `slash 菜单缺少简单表格: ${slashText}`);
|
||||
assert(slashText.includes("/jdbg"), `slash 菜单缺少简单表格快捷码 /jdbg: ${slashText}`);
|
||||
|
||||
const simpleTableItem = page.locator('[data-testid="slash-item-simple-table"]').first();
|
||||
await simpleTableItem.scrollIntoViewIfNeeded({ timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "01-slash-simple-table-entry");
|
||||
await simpleTableItem.click({ timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 4, 12);
|
||||
await screenshot(page, "02-after-simple-table-insert");
|
||||
|
||||
const tableShape = await page.locator('.editor-surface .ProseMirror table').first().evaluate((table) => ({
|
||||
rows: table.querySelectorAll('tr').length,
|
||||
cells: table.querySelectorAll('td,th').length,
|
||||
text: table.textContent || "",
|
||||
}));
|
||||
assert.equal(tableShape.rows, 4, `简单表格应按 Wolai 基线插入 4 行: ${JSON.stringify(tableShape)}`);
|
||||
assert.equal(tableShape.cells, 12, `简单表格应按 Wolai 基线插入 3 列共 12 个单元格: ${JSON.stringify(tableShape)}`);
|
||||
|
||||
const firstCell = page.locator('.editor-surface .ProseMirror table td, .editor-surface .ProseMirror table th').first();
|
||||
await firstCell.click({ timeout: UI_TIMEOUT_MS });
|
||||
const tableToolbar = page.locator('[data-testid="mnote-leptos-tiptap-table-toolbar"]').first();
|
||||
await tableToolbar.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const tableControls = page.locator('[data-testid="mnote-leptos-tiptap-table-controls"]').first();
|
||||
await tableControls.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
assert(await page.locator('[data-testid="table-row-aux-0"]').first().isVisible(), "表格应显示首行左侧 aux 选择手柄");
|
||||
assert(await page.locator('[data-testid="table-col-aux-0"]').first().isVisible(), "表格应显示首列顶部 aux 选择手柄");
|
||||
await page.locator('[data-testid="table-row-aux-0"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const selection = document.querySelector('[data-testid="table-selection-overlay"]');
|
||||
const table = document.querySelector('.editor-surface .ProseMirror table');
|
||||
return selection?.getAttribute('data-selection-kind') === 'row'
|
||||
&& selection?.getAttribute('data-selection-index') === '0'
|
||||
&& table?.querySelectorAll('tr').length === 5
|
||||
&& table?.querySelectorAll('td,th').length === 15;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 5, 15);
|
||||
await page.waitForFunction(() => {
|
||||
const table = document.querySelector('.editor-surface .ProseMirror table');
|
||||
if (!(table instanceof HTMLTableElement)) return false;
|
||||
const rows = Array.from(table.querySelectorAll('tr'));
|
||||
const targetRow = rows[0];
|
||||
const selectedCells = Array.from(table.querySelectorAll('.selectedCell'));
|
||||
const targetCells = targetRow ? Array.from(targetRow.querySelectorAll('td,th')) : [];
|
||||
return targetCells.length > 0
|
||||
&& selectedCells.length === targetCells.length
|
||||
&& selectedCells.every((cell) => targetCells.includes(cell));
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "03a-table-row-aux-insert");
|
||||
await page.locator('[data-testid="table-col-aux-0"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const selection = document.querySelector('[data-testid="table-selection-overlay"]');
|
||||
const table = document.querySelector('.editor-surface .ProseMirror table');
|
||||
return selection?.getAttribute('data-selection-kind') === 'column'
|
||||
&& selection?.getAttribute('data-selection-index') === '0'
|
||||
&& table?.querySelectorAll('tr').length === 5
|
||||
&& table?.querySelectorAll('td,th').length === 20;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 5, 20);
|
||||
await page.waitForFunction(() => {
|
||||
const table = document.querySelector('.editor-surface .ProseMirror table');
|
||||
if (!(table instanceof HTMLTableElement)) return false;
|
||||
const rows = Array.from(table.querySelectorAll('tr'));
|
||||
const selectedCells = Array.from(table.querySelectorAll('.selectedCell'));
|
||||
const firstColumnCells = rows
|
||||
.map((row) => row.querySelector('td,th'))
|
||||
.filter((cell) => cell instanceof HTMLTableCellElement);
|
||||
return firstColumnCells.length === rows.length
|
||||
&& selectedCells.length === firstColumnCells.length
|
||||
&& selectedCells.every((cell) => firstColumnCells.includes(cell));
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "03b-table-column-aux-insert");
|
||||
await clickTableCell(page, { row: -1, col: 0 });
|
||||
for (const testid of [
|
||||
"table-toolbar-add-row-after",
|
||||
"table-toolbar-add-column-after",
|
||||
"table-toolbar-clear-cell",
|
||||
"table-toolbar-delete-row",
|
||||
"table-toolbar-delete-column",
|
||||
"table-toolbar-delete-table",
|
||||
"table-toolbar-options",
|
||||
]) {
|
||||
assert(await page.locator(`[data-testid="${testid}"]`).first().isVisible(), `表格 toolbar 缺少 ${testid}`);
|
||||
}
|
||||
await screenshot(page, "03-table-toolbar-visible");
|
||||
|
||||
const initialColumnMetrics = await page.locator('.editor-surface .ProseMirror table td, .editor-surface .ProseMirror table th').first().evaluate((cell) => {
|
||||
const rect = cell.getBoundingClientRect();
|
||||
return { left: rect.left, right: rect.right, top: rect.top, height: rect.height, width: rect.width };
|
||||
});
|
||||
await page.mouse.move(initialColumnMetrics.right - 2, initialColumnMetrics.top + initialColumnMetrics.height / 2);
|
||||
await page.waitForFunction(() => {
|
||||
const editor = document.querySelector('.editor-surface .ProseMirror');
|
||||
return editor?.classList.contains('resize-cursor')
|
||||
|| document.querySelectorAll('.editor-surface .ProseMirror .column-resize-handle').length > 0;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "03c-table-column-resize-handle");
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(initialColumnMetrics.right + 86, initialColumnMetrics.top + initialColumnMetrics.height / 2, { steps: 8 });
|
||||
await page.mouse.up();
|
||||
await page.waitForFunction((initialWidth) => {
|
||||
const firstCell = document.querySelector('.editor-surface .ProseMirror table td, .editor-surface .ProseMirror table th');
|
||||
const firstCol = document.querySelector('.editor-surface .ProseMirror table col');
|
||||
const domWidth = firstCell instanceof HTMLElement ? firstCell.getBoundingClientRect().width : 0;
|
||||
const styleWidth = firstCol instanceof HTMLTableColElement ? parseFloat(firstCol.style.width || '0') : 0;
|
||||
const attrWidth = firstCell instanceof HTMLElement ? Number((firstCell.getAttribute('data-colwidth') || '').split(',')[0]) : 0;
|
||||
return domWidth >= initialWidth + 40 || styleWidth >= initialWidth + 40 || attrWidth >= initialWidth + 40;
|
||||
}, initialColumnMetrics.width, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 5, 20);
|
||||
await screenshot(page, "03d-after-column-resize");
|
||||
|
||||
await page.keyboard.type("A1");
|
||||
await page.locator('[data-testid="table-toolbar-add-row-after"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 6, 24);
|
||||
await page.locator('[data-testid="table-toolbar-add-column-after"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 6, 30);
|
||||
await screenshot(page, "04-after-row-column-ops");
|
||||
|
||||
await clickTableCell(page, { text: "A1" });
|
||||
await page.locator('[data-testid="table-toolbar-clear-cell"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => !(document.querySelector('.editor-surface .ProseMirror table')?.textContent || '').includes('A1'), null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 6, 30);
|
||||
await screenshot(page, "05-after-clear-cell");
|
||||
|
||||
await page.locator('[data-testid="table-toolbar-options"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
const optionsMenu = page.locator('[data-testid="table-toolbar-options-menu"]').first();
|
||||
await optionsMenu.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
for (const testid of [
|
||||
"table-option-toggle-header-row",
|
||||
"table-option-toggle-header-column",
|
||||
"table-option-toggle-hidden-borders",
|
||||
]) {
|
||||
const option = page.locator(`[data-testid="${testid}"]`).first();
|
||||
assert(await option.isVisible(), `表格选项菜单缺少 ${testid}`);
|
||||
assert.equal(await option.getAttribute("role"), "switch", `${testid} 应使用 switch 语义`);
|
||||
assert.equal(await option.getAttribute("aria-checked"), "false", `${testid} 初始应为关闭态`);
|
||||
}
|
||||
await screenshot(page, "06-table-options-menu");
|
||||
|
||||
await page.locator('[data-testid="table-option-toggle-header-row"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => document.querySelector('[data-testid="table-option-toggle-header-row"]')?.getAttribute('aria-checked') === 'true', null, { timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const table = document.querySelector('.editor-surface .ProseMirror table');
|
||||
const firstRowCells = [...(table?.querySelectorAll('tr:first-child > td, tr:first-child > th') || [])];
|
||||
return firstRowCells.length >= 4 && firstRowCells.every((cell) => cell.tagName === 'TH');
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 5, 20);
|
||||
|
||||
await page.locator('[data-testid="table-option-toggle-header-column"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => document.querySelector('[data-testid="table-option-toggle-header-column"]')?.getAttribute('aria-checked') === 'true', null, { timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const rows = [...document.querySelectorAll('.editor-surface .ProseMirror table tr')];
|
||||
return rows.length >= 5 && rows.every((row) => row.firstElementChild?.tagName === 'TH');
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 5, 20);
|
||||
|
||||
await page.locator('[data-testid="table-option-toggle-hidden-borders"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => document.querySelector('[data-testid="table-option-toggle-hidden-borders"]')?.getAttribute('aria-checked') === 'true', null, { timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const table = document.querySelector('.editor-surface .ProseMirror table');
|
||||
const firstCell = table?.querySelector('td,th');
|
||||
return table?.getAttribute('data-hidden-borders') === 'true'
|
||||
&& firstCell instanceof HTMLElement
|
||||
&& getComputedStyle(firstCell).borderTopWidth === '0px';
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedTable(page, 5, 20);
|
||||
await screenshot(page, "07-after-table-options");
|
||||
|
||||
const lastSave = saveRequests.at(-1);
|
||||
assert(lastSave?.tiptapDocument, `表格操作后必须提交 tiptapDocument: ${JSON.stringify(lastSave).slice(0, 1200)}`);
|
||||
const savedTable = findTable(lastSave.tiptapDocument);
|
||||
assert(savedTable, `保存请求 Tiptap JSON 必须包含 table: ${JSON.stringify(lastSave.tiptapDocument).slice(0, 1600)}`);
|
||||
assert(!tableText(savedTable).includes("A1"), `清空单元格后保存请求不应保留 A1: ${JSON.stringify(savedTable).slice(0, 1600)}`);
|
||||
assert.equal(savedTable.attrs?.hiddenBorders, true, `隐藏边框应写入 table attrs.hiddenBorders: ${JSON.stringify(savedTable).slice(0, 1600)}`);
|
||||
assert(countNodeType(savedTable, "tableHeader") >= 8, `标题行/标题列应写入 tableHeader 节点: ${JSON.stringify(savedTable).slice(0, 1600)}`);
|
||||
const savedColwidth = findColwidth(savedTable);
|
||||
assert(savedColwidth?.some((width) => width >= initialColumnMetrics.width + 40), `列宽拖拽应写入保存请求 attrs.colwidth: ${JSON.stringify(savedTable).slice(0, 1600)}`);
|
||||
|
||||
const contentAfterTable = await loadDocumentContent(target, "读取表格保存后的正文");
|
||||
const savedContent = contentAfterTable?.result?.content;
|
||||
const contentTable = findTable(savedContent);
|
||||
const contentTiptapTable = findTable(contentTable?.props?.tiptapTable) || contentTable;
|
||||
assert(contentTable, `/api/documents/content 必须保留 table 语义: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
assert(!tableText(contentTiptapTable).includes("A1"), `/api/documents/content 清空单元格后不应保留 A1: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
assert.equal(contentTiptapTable.attrs?.hiddenBorders, true, `/api/documents/content 应保留隐藏边框属性: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
assert(countNodeType(contentTiptapTable, "tableHeader") >= 8, `/api/documents/content 应保留标题行/列语义: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
const contentColwidth = findColwidth(contentTiptapTable);
|
||||
assert(contentColwidth?.some((width) => width >= initialColumnMetrics.width + 40), `/api/documents/content 应保留列宽 attrs.colwidth: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
|
||||
await page.reload({ waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
await waitForRuntimeIsland(page);
|
||||
await page.waitForFunction((initialWidth) => {
|
||||
const table = document.querySelector('.editor-surface .ProseMirror table');
|
||||
return table instanceof HTMLTableElement
|
||||
&& table.querySelectorAll('tr').length >= 5
|
||||
&& table.querySelectorAll('td,th').length >= 20
|
||||
&& table.getAttribute('data-hidden-borders') === 'true'
|
||||
&& [...table.querySelectorAll('tr:first-child > td, tr:first-child > th')].every((cell) => cell.tagName === 'TH')
|
||||
&& [...table.querySelectorAll('tr')].every((row) => row.firstElementChild?.tagName === 'TH')
|
||||
&& (() => {
|
||||
const firstCell = table.querySelector('td,th');
|
||||
const firstCol = table.querySelector('col');
|
||||
const domWidth = firstCell instanceof HTMLElement ? firstCell.getBoundingClientRect().width : 0;
|
||||
const styleWidth = firstCol instanceof HTMLTableColElement ? parseFloat(firstCol.style.width || firstCol.style.minWidth || '0') : 0;
|
||||
const attrWidth = firstCell instanceof HTMLElement ? Number((firstCell.getAttribute('data-colwidth') || '').split(',')[0]) : 0;
|
||||
return domWidth >= initialWidth + 40 || styleWidth >= initialWidth + 40 || attrWidth >= initialWidth + 40;
|
||||
})()
|
||||
&& !(table.textContent || '').includes('A1');
|
||||
}, initialColumnMetrics.width, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "08-after-reload-table-ops");
|
||||
|
||||
await page.locator('.editor-surface .ProseMirror table td, .editor-surface .ProseMirror table th').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await tableToolbar.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.locator('[data-testid="table-toolbar-delete-table"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedWithoutTable(page);
|
||||
const contentAfterDelete = await loadDocumentContent(target, "读取删除表格后的正文");
|
||||
assert(!findTable(contentAfterDelete?.result?.content), `删除表格后 content API 不应保留 table: ${JSON.stringify(contentAfterDelete).slice(0, 1600)}`);
|
||||
await screenshot(page, "09-after-delete-table");
|
||||
|
||||
console.log(JSON.stringify({ ok: true, baseUrl: BASE_URL, documentId: target.documentId, screenshotDir: SCREENSHOT_DIR }, null, 2));
|
||||
} finally {
|
||||
if (target) await purgeTempDocument(target).catch(() => undefined);
|
||||
await page.close().catch(() => undefined);
|
||||
await context.close().catch(() => undefined);
|
||||
await browser.close().catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.stack || error.message : String(error));
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert");
|
||||
const fs = require("node:fs");
|
||||
const { chromium } = require("playwright");
|
||||
const { fetchWithTimeout } = require("./task114-rust-web-gateway-entry-smoke.js");
|
||||
|
||||
const BASE_URL = (process.env.MNOTE_UI_BASE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
|
||||
const UI_TIMEOUT_MS = Number(process.env.MNOTE_SMOKE_UI_TIMEOUT_MS || 30_000);
|
||||
const SCREENSHOT_DIR = process.env.MNOTE_PHASE_E_SCREENSHOT_DIR || "/mnt/Data1T/mnote/tmp/wolai-editor-parity/task152-e24-image-local-smoke";
|
||||
const IMAGE_SRC = "/api/editor/image-placeholder.svg";
|
||||
const LEPTOS_SPIKE_SOURCE = "/mnt/Data1T/mnote/rust/spikes/leptos-tiptap-spike/src/lib.rs";
|
||||
|
||||
function assertOfficialImageBridge() {
|
||||
const source = fs.readFileSync(LEPTOS_SPIKE_SOURCE, "utf8");
|
||||
assert(
|
||||
source.includes("editor.set_image(TiptapImageResource"),
|
||||
"E24 图片入口必须通过 leptos-tiptap 的 set_image / TiptapImageResource bridge",
|
||||
);
|
||||
assert(
|
||||
!source.includes('TiptapContent::json(json!({ "type": "image"'),
|
||||
"E24 图片入口不能手写 image JSON 绕过 Tiptap setImage",
|
||||
);
|
||||
const imageExtension = fs.readFileSync("/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/tiptap/src/extensions/tiptap_image.ts", "utf8");
|
||||
assert(
|
||||
imageExtension.includes("Image.extend") && imageExtension.includes('"data-align"'),
|
||||
"E24 图片对齐必须复用 Tiptap Image.extend/addAttributes,而不是在 UI 里伪造样式",
|
||||
);
|
||||
}
|
||||
|
||||
async function readJsonResponse(response, label) {
|
||||
const text = await response.text();
|
||||
let payload = null;
|
||||
try {
|
||||
payload = text ? JSON.parse(text) : null;
|
||||
} catch {
|
||||
throw new Error(`${label} 返回了非 JSON 内容: ${text.slice(0, 1200)}`);
|
||||
}
|
||||
assert(response.ok, `${label} 请求失败: ${response.status}; body: ${text.slice(0, 1200)}`);
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function postTreeCommand(body, label) {
|
||||
const response = await fetchWithTimeout(`${BASE_URL}/api/tree/commands`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const payload = await readJsonResponse(response, label);
|
||||
assert(payload?.result, `${label} 缺少 result`);
|
||||
return payload.result;
|
||||
}
|
||||
|
||||
async function createTempDocument() {
|
||||
const title = `task152-e24-image-${Date.now().toString(36)}`;
|
||||
const result = await postTreeCommand({ action: "create", title }, "创建 E24 临时文档");
|
||||
assert(result.documentId, "创建 E24 临时文档缺少 documentId");
|
||||
assert(result.workspaceId, "创建 E24 临时文档缺少 workspaceId");
|
||||
return { documentId: result.documentId, workspaceId: result.workspaceId, title };
|
||||
}
|
||||
|
||||
async function purgeTempDocument(target) {
|
||||
if (!target?.documentId || !target?.workspaceId) return;
|
||||
await postTreeCommand({ action: "purge", workspaceId: target.workspaceId, documentId: target.documentId }, "清理 E24 临时文档");
|
||||
}
|
||||
|
||||
async function loadDocumentContent(target, label) {
|
||||
const url = `${BASE_URL}/api/documents/content?documentId=${encodeURIComponent(target.documentId)}&workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await fetchWithTimeout(url, { method: "GET" });
|
||||
return readJsonResponse(response, label);
|
||||
}
|
||||
|
||||
async function waitForRuntimeIsland(page) {
|
||||
const root = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"]').first();
|
||||
await root.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const editor = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror[contenteditable="true"]').first();
|
||||
await editor.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const editorNode = host?.querySelector('.editor-surface .ProseMirror[contenteditable="true"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") !== "error" && editorNode instanceof HTMLElement && editorNode.isContentEditable;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
return editor;
|
||||
}
|
||||
|
||||
async function waitForSavedImage(page) {
|
||||
await page.waitForFunction((expectedSrc) => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const image = host?.querySelector('.editor-surface .ProseMirror img[src]');
|
||||
return host?.getAttribute("data-runtime-editor-status") === "saved"
|
||||
&& image instanceof HTMLImageElement
|
||||
&& image.getAttribute("src") === expectedSrc
|
||||
&& image.naturalWidth > 0
|
||||
&& image.naturalHeight > 0;
|
||||
}, IMAGE_SRC, { timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
|
||||
async function screenshot(page, name) {
|
||||
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
|
||||
await page.screenshot({ path: `${SCREENSHOT_DIR}/${name}.png`, fullPage: true });
|
||||
}
|
||||
|
||||
async function waitForCondition(label, predicate, timeoutMs = UI_TIMEOUT_MS) {
|
||||
const started = Date.now();
|
||||
let lastError = null;
|
||||
while (Date.now() - started < timeoutMs) {
|
||||
try {
|
||||
if (predicate()) return;
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
throw new Error(`${label} 超时${lastError ? `: ${lastError.message || lastError}` : ""}`);
|
||||
}
|
||||
|
||||
function findImage(value) {
|
||||
if (!value || typeof value !== "object") return null;
|
||||
if (Array.isArray(value)) return value.map(findImage).find(Boolean) || null;
|
||||
if (value.type === "image" || value.blockType === "image") return value;
|
||||
return findImage(value.content) || findImage(value.children) || findImage(value.props?.tiptapImage);
|
||||
}
|
||||
|
||||
function imageSrc(value) {
|
||||
const image = findImage(value);
|
||||
return image?.attrs?.src || image?.props?.src || image?.src || null;
|
||||
}
|
||||
|
||||
function imageAlign(value) {
|
||||
const image = findImage(value);
|
||||
return image?.attrs?.["data-align"]
|
||||
|| image?.props?.["data-align"]
|
||||
|| image?.props?.tiptapImage?.attrs?.["data-align"]
|
||||
|| null;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
assertOfficialImageBridge();
|
||||
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext({ viewport: { width: 1440, height: 960 }, acceptDownloads: true });
|
||||
const page = await context.newPage();
|
||||
const saveRequests = [];
|
||||
page.on("request", (request) => {
|
||||
if (!request.url().includes("/api/documents/save")) return;
|
||||
const body = request.postData();
|
||||
if (!body) return;
|
||||
try {
|
||||
saveRequests.push(JSON.parse(body));
|
||||
} catch {
|
||||
saveRequests.push({ raw: body });
|
||||
}
|
||||
});
|
||||
|
||||
let target = null;
|
||||
try {
|
||||
target = await createTempDocument();
|
||||
const url = `${BASE_URL}/documents/${encodeURIComponent(target.documentId)}?workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await page.goto(url, { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
assert(response, "文档页没有返回响应");
|
||||
assert.equal(response.status(), 200, `文档页状态码异常: ${response.status()}`);
|
||||
|
||||
const editor = await waitForRuntimeIsland(page);
|
||||
await editor.click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.keyboard.type("/");
|
||||
const slash = page.locator('[data-testid="mnote-leptos-tiptap-slash-menu"]').first();
|
||||
await slash.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const slashText = await slash.innerText();
|
||||
assert(slashText.includes("媒体与附件"), `slash 菜单缺少媒体与附件分组: ${slashText}`);
|
||||
assert(slashText.includes("图片"), `slash 菜单缺少图片入口: ${slashText}`);
|
||||
assert(slashText.includes("/tp"), `slash 菜单缺少图片快捷码 /tp: ${slashText}`);
|
||||
|
||||
const imageItem = page.locator('[data-testid="slash-item-image"]').first();
|
||||
await imageItem.scrollIntoViewIfNeeded({ timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "01-slash-image-entry");
|
||||
await imageItem.click({ timeout: UI_TIMEOUT_MS });
|
||||
await waitForSavedImage(page);
|
||||
await screenshot(page, "02-after-image-insert");
|
||||
|
||||
const image = page.locator('.editor-surface .ProseMirror img[src]').first();
|
||||
await image.click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const selectedImage = document.querySelector('.editor-surface .ProseMirror img.ProseMirror-selectednode[src]');
|
||||
const toolbar = document.querySelector('[data-testid="image-floating-toolbar"]');
|
||||
return selectedImage instanceof HTMLImageElement
|
||||
&& toolbar instanceof HTMLElement
|
||||
&& getComputedStyle(toolbar).display !== "none"
|
||||
&& toolbar.getBoundingClientRect().width > 0
|
||||
&& toolbar.getBoundingClientRect().height > 0;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "03-image-floating-toolbar");
|
||||
|
||||
const imageToolbar = page.locator('[data-testid="image-floating-toolbar"]').first();
|
||||
await imageToolbar.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
for (const testid of [
|
||||
"image-align-left",
|
||||
"image-align-center",
|
||||
"image-align-right",
|
||||
"image-download",
|
||||
"image-delete",
|
||||
]) {
|
||||
await imageToolbar.locator(`[data-testid="${testid}"]`).first().waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
assert.equal(await imageToolbar.locator('[data-testid="image-download"]').first().isDisabled(), false, "同源图片下载入口应可用");
|
||||
assert.equal(await imageToolbar.locator('[data-testid="image-delete"]').first().isDisabled(), true, "删除图片入口本切片应保持禁用,真实删除保存链后续单列");
|
||||
const currentUrlAfterImageSelect = page.url();
|
||||
|
||||
const downloadPromise = page.waitForEvent("download", { timeout: UI_TIMEOUT_MS });
|
||||
await imageToolbar.locator('[data-testid="image-download"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
const download = await downloadPromise;
|
||||
const suggestedFilename = download.suggestedFilename();
|
||||
assert(suggestedFilename.includes("E24"), `图片下载文件名应来自图片 title/alt: ${suggestedFilename}`);
|
||||
assert(/\.svg$/i.test(suggestedFilename), `图片下载文件名应保留 SVG 扩展名: ${suggestedFilename}`);
|
||||
await download.delete().catch(() => undefined);
|
||||
assert.equal(page.url(), currentUrlAfterImageSelect, "下载图片不应触发页面跳转");
|
||||
|
||||
await imageToolbar.locator('[data-testid="image-align-center"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const image = document.querySelector('.editor-surface .ProseMirror img[src]');
|
||||
const toolbar = document.querySelector('[data-testid="image-floating-toolbar"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") === "saved"
|
||||
&& image instanceof HTMLImageElement
|
||||
&& image.getAttribute("data-align") === "center"
|
||||
&& toolbar instanceof HTMLElement
|
||||
&& toolbar.getAttribute("data-align") === "center";
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await waitForCondition("等待图片对齐保存请求", () => saveRequests.some((request) => imageAlign(request.tiptapDocument) === "center"));
|
||||
await screenshot(page, "03-image-floating-toolbar");
|
||||
|
||||
const imgAttrs = await image.evaluate((img) => ({
|
||||
src: img.getAttribute("src"),
|
||||
alt: img.getAttribute("alt"),
|
||||
title: img.getAttribute("title"),
|
||||
dataAlign: img.getAttribute("data-align"),
|
||||
}));
|
||||
assert.equal(imgAttrs.src, IMAGE_SRC, `图片 src 应保持稳定测试 URL: ${JSON.stringify(imgAttrs)}`);
|
||||
assert.equal(imgAttrs.alt, "E24 图片占位", `图片 alt 应由 setImage 写入: ${JSON.stringify(imgAttrs)}`);
|
||||
assert.equal(imgAttrs.title, "E24 图片", `图片 title 应由 setImage 写入: ${JSON.stringify(imgAttrs)}`);
|
||||
assert.equal(imgAttrs.dataAlign, "center", `图片居中应通过 data-align 写入 DOM: ${JSON.stringify(imgAttrs)}`);
|
||||
assert.equal(page.url(), currentUrlAfterImageSelect, "点击图片打开工具条不应触发页面跳转");
|
||||
|
||||
const lastSave = [...saveRequests].reverse().find((request) => imageAlign(request.tiptapDocument) === "center") || saveRequests.at(-1);
|
||||
assert(lastSave?.tiptapDocument, `图片插入后必须提交 tiptapDocument: ${JSON.stringify(lastSave).slice(0, 1200)}`);
|
||||
assert.equal(imageSrc(lastSave.tiptapDocument), IMAGE_SRC, `保存请求 Tiptap JSON 必须包含 image attrs.src: ${JSON.stringify(lastSave.tiptapDocument).slice(0, 1600)}`);
|
||||
assert.equal(imageAlign(lastSave.tiptapDocument), "center", `保存请求 Tiptap JSON 必须保留 image data-align: ${JSON.stringify(lastSave.tiptapDocument).slice(0, 1600)}`);
|
||||
|
||||
const contentAfterImage = await loadDocumentContent(target, "读取图片保存后的正文");
|
||||
const savedContent = contentAfterImage?.result?.content;
|
||||
assert.equal(imageSrc(savedContent), IMAGE_SRC, `/api/documents/content 必须保留 image 真源: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
assert.equal(imageAlign(savedContent), "center", `/api/documents/content 必须保留 image data-align: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
|
||||
await page.reload({ waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
await waitForRuntimeIsland(page);
|
||||
await page.waitForFunction((expectedSrc) => {
|
||||
const image = document.querySelector('.editor-surface .ProseMirror img[src]');
|
||||
return image instanceof HTMLImageElement
|
||||
&& image.getAttribute("src") === expectedSrc
|
||||
&& image.getAttribute("data-align") === "center"
|
||||
&& image.naturalWidth > 0
|
||||
&& image.naturalHeight > 0;
|
||||
}, IMAGE_SRC, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "04-after-reload-image");
|
||||
|
||||
console.log(JSON.stringify({ ok: true, baseUrl: BASE_URL, documentId: target.documentId, screenshotDir: SCREENSHOT_DIR }, null, 2));
|
||||
} finally {
|
||||
if (target) await purgeTempDocument(target).catch(() => undefined);
|
||||
await page.close().catch(() => undefined);
|
||||
await context.close().catch(() => undefined);
|
||||
await browser.close().catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.stack || error.message : String(error));
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
const assert = require("node:assert");
|
||||
const fs = require("node:fs");
|
||||
const { chromium } = require("playwright");
|
||||
const { fetchWithTimeout } = require("./task114-rust-web-gateway-entry-smoke.js");
|
||||
|
||||
const BASE_URL = (process.env.MNOTE_UI_BASE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
|
||||
const UI_TIMEOUT_MS = Number(process.env.MNOTE_SMOKE_UI_TIMEOUT_MS || 30_000);
|
||||
const SCREENSHOT_DIR = process.env.MNOTE_PHASE_E_SCREENSHOT_DIR || "/mnt/Data1T/mnote/tmp/wolai-editor-parity/task153-e25-toc-local-smoke";
|
||||
const TOC_EXTENSION_SOURCE = "/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/tiptap/src/extensions/tiptap_toc_node.ts";
|
||||
const LEPTOS_SPIKE_SOURCE = "/mnt/Data1T/mnote/rust/spikes/leptos-tiptap-spike/src/lib.rs";
|
||||
|
||||
function assertTocBridgeSource() {
|
||||
const extension = fs.readFileSync(TOC_EXTENSION_SOURCE, "utf8");
|
||||
assert(extension.includes('name: "tocNode"'), "E25 必须注册真实 Tiptap tocNode schema");
|
||||
assert(extension.includes("Node.create"), "E25 tocNode 必须基于 Tiptap Node.create");
|
||||
assert(extension.includes("insertTocNode"), "E25 必须提供 insertTocNode 命令入口");
|
||||
assert(extension.includes("editor.state.doc.descendants"), "E25 TOC 列表必须从当前 Tiptap doc headings 派生,不能写死静态列表");
|
||||
const spike = fs.readFileSync(LEPTOS_SPIKE_SOURCE, "utf8");
|
||||
assert(spike.includes("editor.insert_toc_node(TiptapTocNodeAttrs"), "E25 /toc 必须通过 leptos-tiptap insert_toc_node bridge");
|
||||
assert(!spike.includes('TiptapContent::json(json!({ "type": "tocNode"'), "E25 /toc 不能在 spike 中手写 tocNode JSON 绕过 bridge 命令");
|
||||
}
|
||||
|
||||
async function readJsonResponse(response, label) {
|
||||
const text = await response.text();
|
||||
let payload = null;
|
||||
try {
|
||||
payload = text ? JSON.parse(text) : null;
|
||||
} catch {
|
||||
throw new Error(`${label} 返回了非 JSON 内容: ${text.slice(0, 1200)}`);
|
||||
}
|
||||
assert(response.ok, `${label} 请求失败: ${response.status}; body: ${text.slice(0, 1200)}`);
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function postTreeCommand(body, label) {
|
||||
const response = await fetchWithTimeout(`${BASE_URL}/api/tree/commands`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const payload = await readJsonResponse(response, label);
|
||||
assert(payload?.result, `${label} 缺少 result`);
|
||||
return payload.result;
|
||||
}
|
||||
|
||||
async function createTempDocument() {
|
||||
const title = `task153-e25-toc-${Date.now().toString(36)}`;
|
||||
const result = await postTreeCommand({ action: "create", title }, "创建 E25 临时文档");
|
||||
assert(result.documentId, "创建 E25 临时文档缺少 documentId");
|
||||
assert(result.workspaceId, "创建 E25 临时文档缺少 workspaceId");
|
||||
return { documentId: result.documentId, workspaceId: result.workspaceId, title };
|
||||
}
|
||||
|
||||
async function purgeTempDocument(target) {
|
||||
if (!target?.documentId || !target?.workspaceId) return;
|
||||
await postTreeCommand({ action: "purge", workspaceId: target.workspaceId, documentId: target.documentId }, "清理 E25 临时文档");
|
||||
}
|
||||
|
||||
async function loadDocumentContent(target, label) {
|
||||
const url = `${BASE_URL}/api/documents/content?documentId=${encodeURIComponent(target.documentId)}&workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await fetchWithTimeout(url, { method: "GET" });
|
||||
return readJsonResponse(response, label);
|
||||
}
|
||||
|
||||
async function waitForRuntimeIsland(page) {
|
||||
const root = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"]').first();
|
||||
await root.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const editor = page.locator('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror[contenteditable="true"]').first();
|
||||
await editor.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const editorNode = host?.querySelector('.editor-surface .ProseMirror[contenteditable="true"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") !== "error" && editorNode instanceof HTMLElement && editorNode.isContentEditable;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
return editor;
|
||||
}
|
||||
|
||||
async function screenshot(page, name) {
|
||||
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
|
||||
await page.screenshot({ path: `${SCREENSHOT_DIR}/${name}.png`, fullPage: true });
|
||||
}
|
||||
|
||||
function findToc(value) {
|
||||
if (!value || typeof value !== "object") return null;
|
||||
if (Array.isArray(value)) return value.map(findToc).find(Boolean) || null;
|
||||
if (value.type === "tocNode" || value.blockType === "toc" || value.type === "toc") return value;
|
||||
return findToc(value.content) || findToc(value.children) || findToc(value.props?.tiptapTocNode) || findToc(value.props?.tiptapToc);
|
||||
}
|
||||
|
||||
function tocShowTitle(value) {
|
||||
const toc = findToc(value);
|
||||
return toc?.attrs?.showTitle ?? toc?.props?.tiptapTocNode?.attrs?.showTitle ?? null;
|
||||
}
|
||||
|
||||
async function setHeadingFixture(page) {
|
||||
await page.evaluate(() => {
|
||||
const editor = document.querySelector('.editor-surface .ProseMirror')?.editor;
|
||||
if (!editor) throw new Error('找不到 Tiptap editor');
|
||||
editor.commands.setContent({
|
||||
type: 'doc',
|
||||
content: [
|
||||
{ type: 'heading', attrs: { level: 1 }, content: [{ type: 'text', text: 'E25 主标题' }] },
|
||||
{ type: 'paragraph', content: [{ type: 'text', text: 'E25 正文' }] },
|
||||
{ type: 'heading', attrs: { level: 2 }, content: [{ type: 'text', text: 'E25 子标题' }] },
|
||||
{ type: 'paragraph' },
|
||||
],
|
||||
});
|
||||
editor.commands.focus('end');
|
||||
});
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") !== "error"
|
||||
&& document.querySelectorAll('.editor-surface .ProseMirror h1, .editor-surface .ProseMirror h2').length >= 2;
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
}
|
||||
|
||||
async function main() {
|
||||
assertTocBridgeSource();
|
||||
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext({ viewport: { width: 1440, height: 960 } });
|
||||
const page = await context.newPage();
|
||||
const saveRequests = [];
|
||||
page.on("request", (request) => {
|
||||
if (!request.url().includes("/api/documents/save")) return;
|
||||
const body = request.postData();
|
||||
if (!body) return;
|
||||
try {
|
||||
saveRequests.push(JSON.parse(body));
|
||||
} catch {
|
||||
saveRequests.push({ raw: body });
|
||||
}
|
||||
});
|
||||
|
||||
let target = null;
|
||||
try {
|
||||
target = await createTempDocument();
|
||||
const url = `${BASE_URL}/documents/${encodeURIComponent(target.documentId)}?workspaceId=${encodeURIComponent(target.workspaceId)}`;
|
||||
const response = await page.goto(url, { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
assert(response, "文档页没有返回响应");
|
||||
assert.equal(response.status(), 200, `文档页状态码异常: ${response.status()}`);
|
||||
|
||||
const editor = await waitForRuntimeIsland(page);
|
||||
await setHeadingFixture(page);
|
||||
await editor.click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.keyboard.type("/");
|
||||
const slash = page.locator('[data-testid="mnote-leptos-tiptap-slash-menu"]').first();
|
||||
await slash.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const slashText = await slash.innerText();
|
||||
assert(slashText.includes("页面目录"), `slash 菜单缺少页面目录: ${slashText}`);
|
||||
assert(slashText.includes("/toc"), `slash 菜单缺少页面目录快捷码 /toc: ${slashText}`);
|
||||
|
||||
const tocItem = page.locator('[data-testid="slash-item-toc"]').first();
|
||||
await tocItem.scrollIntoViewIfNeeded({ timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "01-slash-toc-entry");
|
||||
await tocItem.click({ timeout: UI_TIMEOUT_MS });
|
||||
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const toc = document.querySelector('.editor-surface .ProseMirror [data-type="toc-node"]');
|
||||
const items = Array.from(document.querySelectorAll('.tiptap-table-of-contents-item')).map((item) => item.textContent || '');
|
||||
return host?.getAttribute("data-runtime-editor-status") === "saved"
|
||||
&& toc instanceof HTMLElement
|
||||
&& toc.getAttribute("data-show-title") === "true"
|
||||
&& items.includes("E25 主标题")
|
||||
&& items.includes("E25 子标题");
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "02-after-toc-insert");
|
||||
|
||||
await page.evaluate(() => {
|
||||
const editor = document.querySelector('.editor-surface .ProseMirror')?.editor;
|
||||
if (!editor) throw new Error('找不到 Tiptap editor');
|
||||
const doc = editor.getJSON();
|
||||
const content = Array.isArray(doc.content) ? [...doc.content] : [];
|
||||
content.push({ type: 'heading', attrs: { level: 2 }, content: [{ type: 'text', text: 'E25 动态标题' }] });
|
||||
editor.commands.setContent({ ...doc, content });
|
||||
});
|
||||
await page.waitForFunction(() => Array.from(document.querySelectorAll('.tiptap-table-of-contents-item')).some((item) => (item.textContent || '').includes('E25 动态标题')), null, { timeout: UI_TIMEOUT_MS });
|
||||
|
||||
const firstTocItem = page.locator('.tiptap-table-of-contents-item', { hasText: 'E25 主标题' }).first();
|
||||
await firstTocItem.click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => window.location.hash.startsWith('#heading-'), null, { timeout: UI_TIMEOUT_MS });
|
||||
|
||||
await page.locator('[data-testid="toc-show-title-toggle"]').first().click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(() => {
|
||||
const host = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
||||
const toc = document.querySelector('.editor-surface .ProseMirror [data-type="toc-node"]');
|
||||
return host?.getAttribute("data-runtime-editor-status") === "saved"
|
||||
&& toc instanceof HTMLElement
|
||||
&& toc.getAttribute("data-show-title") === "false"
|
||||
&& !document.querySelector('.tiptap-table-of-contents-title');
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "03-toc-title-hidden");
|
||||
|
||||
const lastSave = [...saveRequests].reverse().find((request) => findToc(request.tiptapDocument));
|
||||
assert(lastSave?.tiptapDocument, `TOC 插入后必须提交 tiptapDocument: ${JSON.stringify(lastSave).slice(0, 1200)}`);
|
||||
assert.equal(findToc(lastSave.tiptapDocument)?.type, "tocNode", `保存请求必须包含 tocNode: ${JSON.stringify(lastSave.tiptapDocument).slice(0, 1600)}`);
|
||||
|
||||
const contentAfterToc = await loadDocumentContent(target, "读取 TOC 保存后的正文");
|
||||
const savedContent = contentAfterToc?.result?.content;
|
||||
assert(findToc(savedContent), `/api/documents/content 必须保留 tocNode 真源: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
assert.equal(tocShowTitle(savedContent), false, `/api/documents/content 必须保留 showTitle=false: ${JSON.stringify(savedContent).slice(0, 1600)}`);
|
||||
|
||||
await page.reload({ waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
|
||||
await waitForRuntimeIsland(page);
|
||||
await page.waitForFunction(() => {
|
||||
const toc = document.querySelector('.editor-surface .ProseMirror [data-type="toc-node"]');
|
||||
const items = Array.from(document.querySelectorAll('.tiptap-table-of-contents-item')).map((item) => item.textContent || '');
|
||||
return toc instanceof HTMLElement
|
||||
&& toc.getAttribute("data-show-title") === "false"
|
||||
&& items.includes("E25 主标题")
|
||||
&& items.includes("E25 动态标题");
|
||||
}, null, { timeout: UI_TIMEOUT_MS });
|
||||
await screenshot(page, "04-after-reload-toc");
|
||||
|
||||
console.log(JSON.stringify({ ok: true, baseUrl: BASE_URL, documentId: target.documentId, screenshotDir: SCREENSHOT_DIR }, null, 2));
|
||||
} finally {
|
||||
if (target) await purgeTempDocument(target).catch(() => undefined);
|
||||
await page.close().catch(() => undefined);
|
||||
await context.close().catch(() => undefined);
|
||||
await browser.close().catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.stack || error.message : String(error));
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user