@arbidocs/blocks 0.4.99 → 0.4.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/agents/index.cjs +207 -207
  2. package/dist/agents/index.js +2 -2
  3. package/dist/{chunk-C5RF47LD.js → chunk-6HZNFOHW.js} +3 -3
  4. package/dist/{chunk-C5RF47LD.js.map → chunk-6HZNFOHW.js.map} +1 -1
  5. package/dist/{chunk-4ZTIMQ7Z.js → chunk-72PQ42YI.js} +933 -64
  6. package/dist/chunk-72PQ42YI.js.map +1 -0
  7. package/dist/{chunk-44TPPPRJ.cjs → chunk-B7P73VHX.cjs} +930 -60
  8. package/dist/chunk-B7P73VHX.cjs.map +1 -0
  9. package/dist/{chunk-3ICWR3BK.js → chunk-E2QWWLK5.js} +3 -3
  10. package/dist/{chunk-3ICWR3BK.js.map → chunk-E2QWWLK5.js.map} +1 -1
  11. package/dist/{chunk-QBEUCOC7.cjs → chunk-IE55TWIG.cjs} +5 -5
  12. package/dist/{chunk-QBEUCOC7.cjs.map → chunk-IE55TWIG.cjs.map} +1 -1
  13. package/dist/{chunk-5NQIBJPP.js → chunk-NJX774HB.js} +3 -3
  14. package/dist/{chunk-5NQIBJPP.js.map → chunk-NJX774HB.js.map} +1 -1
  15. package/dist/{chunk-DDYXFALG.cjs → chunk-NW3LFDZL.cjs} +3 -3
  16. package/dist/{chunk-DDYXFALG.cjs.map → chunk-NW3LFDZL.cjs.map} +1 -1
  17. package/dist/{chunk-MABEOI4S.cjs → chunk-O24WPHLD.cjs} +5 -5
  18. package/dist/{chunk-MABEOI4S.cjs.map → chunk-O24WPHLD.cjs.map} +1 -1
  19. package/dist/connect/docx.cjs +6 -6
  20. package/dist/connect/docx.js +4 -4
  21. package/dist/connect/index.cjs +3 -3
  22. package/dist/connect/index.js +2 -2
  23. package/dist/docx/NativeDocxEditor.d.ts +6 -1
  24. package/dist/docx/index.cjs +39 -35
  25. package/dist/docx/index.d.ts +1 -0
  26. package/dist/docx/index.js +3 -3
  27. package/dist/docx/layout/GenerateImage.d.ts +50 -0
  28. package/dist/docx/layout/LayoutRibbon.d.ts +32 -0
  29. package/dist/docx/layout/LayoutTabs.d.ts +20 -0
  30. package/dist/docx/layout/PictureRibbon.d.ts +23 -0
  31. package/dist/docx/layout/TableKeys.d.ts +25 -0
  32. package/dist/docx/layout/TableRibbon.d.ts +11 -0
  33. package/dist/docx/layout/caption.d.ts +38 -0
  34. package/dist/docx/layout/presets.d.ts +40 -0
  35. package/dist/facts/index.cjs +1 -1
  36. package/dist/facts/index.js +1 -1
  37. package/dist/files/index.cjs +1 -1
  38. package/dist/files/index.js +1 -1
  39. package/dist/home/index.cjs +1 -1
  40. package/dist/home/index.js +1 -1
  41. package/dist/index.cjs +258 -258
  42. package/dist/index.js +4 -4
  43. package/dist/shell/index.cjs +1 -1
  44. package/dist/shell/index.js +1 -1
  45. package/dist/studio/index.cjs +1 -1
  46. package/dist/studio/index.js +1 -1
  47. package/dist/workflow-canvas/index.cjs +9 -9
  48. package/dist/workflow-canvas/index.js +2 -2
  49. package/package.json +5 -4
  50. package/src/docx/README.md +22 -0
  51. package/src/docx/layout/layout.css +120 -0
  52. package/src/docx/styles.css +2 -0
  53. package/dist/chunk-44TPPPRJ.cjs.map +0 -1
  54. package/dist/chunk-4ZTIMQ7Z.js.map +0 -1
@@ -12,6 +12,7 @@ var lucideReact = require('lucide-react');
12
12
  var jsxRuntime = require('react/jsx-runtime');
13
13
  var reactDom = require('react-dom');
14
14
  var template = require('@arbidocs/coedit/template');
15
+ var editor = require('@docx-editor.dev/core/editor');
15
16
  var server = require('react-dom/server');
16
17
  var Y = require('yjs');
17
18
  var coedit = require('@arbidocs/coedit');
@@ -2355,6 +2356,241 @@ function HouseTemplateProvider({
2355
2356
  );
2356
2357
  return /* @__PURE__ */ jsxRuntime.jsx(HouseTemplateContext.Provider, { value: enabled ? value : null, children });
2357
2358
  }
2359
+ function RibbonMenu({
2360
+ label,
2361
+ icon,
2362
+ children,
2363
+ className,
2364
+ testId,
2365
+ title
2366
+ }) {
2367
+ const [open, setOpen] = React3.useState(false);
2368
+ const element = React3.useRef(null);
2369
+ React3.useEffect(() => {
2370
+ if (!open) return;
2371
+ const dismiss = (event) => {
2372
+ if (!element.current?.contains(event.target)) setOpen(false);
2373
+ };
2374
+ const escape = (event) => {
2375
+ if (event.key === "Escape") setOpen(false);
2376
+ };
2377
+ document.addEventListener("pointerdown", dismiss);
2378
+ document.addEventListener("keydown", escape);
2379
+ return () => {
2380
+ document.removeEventListener("pointerdown", dismiss);
2381
+ document.removeEventListener("keydown", escape);
2382
+ };
2383
+ }, [open]);
2384
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-menu", ref: element, children: [
2385
+ /* @__PURE__ */ jsxRuntime.jsx(
2386
+ "button",
2387
+ {
2388
+ type: "button",
2389
+ className: ["native-docx-ribbon-trigger", className].filter(Boolean).join(" "),
2390
+ "aria-label": label,
2391
+ title: title ?? label,
2392
+ "aria-expanded": open,
2393
+ "data-testid": testId,
2394
+ onMouseDown: (event) => event.preventDefault(),
2395
+ onClick: () => setOpen((value) => !value),
2396
+ children: icon
2397
+ }
2398
+ ),
2399
+ open && /* @__PURE__ */ jsxRuntime.jsx(
2400
+ "div",
2401
+ {
2402
+ className: "native-docx-ribbon-popover",
2403
+ role: "group",
2404
+ "aria-label": label,
2405
+ onMouseDown: (event) => {
2406
+ if (!(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement))
2407
+ event.preventDefault();
2408
+ },
2409
+ children: typeof children === "function" ? children(() => setOpen(false)) : children
2410
+ }
2411
+ )
2412
+ ] });
2413
+ }
2414
+ var titleOf = (prompt) => {
2415
+ const line = prompt.trim().split("\n")[0];
2416
+ return line.length > 80 ? `${line.slice(0, 79)}\u2026` : line;
2417
+ };
2418
+ function rememberCaret(editor) {
2419
+ const surface = editor.surface;
2420
+ const head = surface?.state().selection?.head;
2421
+ if (!surface || !head) return null;
2422
+ return { paraId: surface.session.paraIdOf(head.paragraphId), ...head };
2423
+ }
2424
+ var mounted = [];
2425
+ var running = 0;
2426
+ var listeners = /* @__PURE__ */ new Set();
2427
+ var setRunning = (delta) => {
2428
+ running += delta;
2429
+ listeners.forEach((listener) => listener());
2430
+ };
2431
+ var subscribe = (listener) => {
2432
+ listeners.add(listener);
2433
+ return () => void listeners.delete(listener);
2434
+ };
2435
+ function insertionTarget(origin, caret, editors = mounted) {
2436
+ if (editors.includes(origin) && origin.surface) return origin;
2437
+ const paraId = caret?.paraId;
2438
+ if (!paraId) return null;
2439
+ for (let i = editors.length - 1; i >= 0; i--) {
2440
+ const session = editors[i].surface?.session;
2441
+ if (session?.nodeIdOf(paraId)) return editors[i];
2442
+ }
2443
+ return null;
2444
+ }
2445
+ function restoreCaret(editor, caret) {
2446
+ const surface = editor.surface;
2447
+ if (!surface || !caret) return;
2448
+ const paragraphId = caret.paraId && surface.session.nodeIdOf(caret.paraId) || caret.paragraphId;
2449
+ if (!surface.session.paragraphIds().includes(paragraphId)) return;
2450
+ const point = { paragraphId, offset: caret.offset };
2451
+ surface.setSelection({ anchor: point, head: point });
2452
+ }
2453
+ async function insertGeneratedImage(editor$1, bytes, prompt, caret) {
2454
+ const image = react.normalizeImageBytes(bytes);
2455
+ if (!image.ok) throw new Error("The generated image is not in a format Word can embed.");
2456
+ let result;
2457
+ for (let attempt = 0; attempt < 3 && !result?.ok; attempt++) {
2458
+ editor$1.focus();
2459
+ restoreCaret(editor$1, caret);
2460
+ result = await editor.executeImageCommand(editor$1, {
2461
+ type: "insertImage",
2462
+ data: image.bytes,
2463
+ mime: image.mime,
2464
+ widthPoints: image.widthPoints,
2465
+ heightPoints: image.heightPoints,
2466
+ description: prompt.trim(),
2467
+ title: titleOf(prompt)
2468
+ });
2469
+ if (!result.ok && result.reason !== "stale drawing selection") break;
2470
+ }
2471
+ if (!result?.ok) throw new Error(result?.reason || "The picture could not be inserted here.");
2472
+ }
2473
+ var AUTO = "";
2474
+ function useGenerateImageTarget() {
2475
+ const editor = react.useDocxEditor();
2476
+ const loaded2 = react.useEditorState((snapshot) => !snapshot.isLoading);
2477
+ React3.useEffect(() => {
2478
+ if (!editor || !loaded2) return;
2479
+ mounted.push(editor);
2480
+ return () => void mounted.splice(mounted.indexOf(editor), 1);
2481
+ }, [editor, loaded2]);
2482
+ }
2483
+ function GenerateImageButton({ generation }) {
2484
+ const editor = react.useDocxEditor();
2485
+ const [prompt, setPrompt] = React3.useState("");
2486
+ const [aspectRatio, setAspectRatio] = React3.useState(AUTO);
2487
+ const [busy, setBusy] = React3.useState(false);
2488
+ const [error, setError] = React3.useState("");
2489
+ const abort = React3.useRef(null);
2490
+ const close = React3.useRef(() => {
2491
+ });
2492
+ const editable = react.useEditorState((snapshot) => snapshot.editable);
2493
+ const generating = React3.useSyncExternalStore(subscribe, () => running > 0);
2494
+ async function run() {
2495
+ if (!editor || !prompt.trim() || busy) return;
2496
+ const caret = rememberCaret(editor);
2497
+ const controller = new AbortController();
2498
+ abort.current = controller;
2499
+ setBusy(true);
2500
+ setRunning(1);
2501
+ setError("");
2502
+ try {
2503
+ const bytes = await generation.generate(prompt.trim(), {
2504
+ aspectRatio: aspectRatio || void 0,
2505
+ signal: controller.signal
2506
+ });
2507
+ if (controller.signal.aborted) return;
2508
+ const target = insertionTarget(editor, caret);
2509
+ if (!target) throw new Error("The document was closed before the generated image was ready.");
2510
+ await insertGeneratedImage(target, bytes, prompt, caret);
2511
+ setPrompt("");
2512
+ close.current();
2513
+ generation.notify?.("Generated image inserted", "success");
2514
+ } catch (failure) {
2515
+ if (controller.signal.aborted) return;
2516
+ const message = failure instanceof Error ? failure.message : String(failure);
2517
+ setError(message);
2518
+ generation.notify?.(message, "error");
2519
+ } finally {
2520
+ abort.current = null;
2521
+ setRunning(-1);
2522
+ setBusy(false);
2523
+ }
2524
+ }
2525
+ if (!editable && !generating) return null;
2526
+ return /* @__PURE__ */ jsxRuntime.jsx(
2527
+ RibbonMenu,
2528
+ {
2529
+ label: generating ? "Generating image\u2026" : "Generate image",
2530
+ icon: generating ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 16, className: "native-docx-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { size: 16 }),
2531
+ testId: "docx-generate-image",
2532
+ children: (dismiss) => {
2533
+ close.current = dismiss;
2534
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2535
+ "form",
2536
+ {
2537
+ className: "native-docx-form native-docx-generate-image",
2538
+ onSubmit: (event) => {
2539
+ event.preventDefault();
2540
+ void run();
2541
+ },
2542
+ children: [
2543
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
2544
+ "Describe the image",
2545
+ /* @__PURE__ */ jsxRuntime.jsx(
2546
+ "textarea",
2547
+ {
2548
+ autoFocus: true,
2549
+ rows: 3,
2550
+ value: prompt,
2551
+ disabled: busy,
2552
+ placeholder: "A watercolour of a lighthouse at dawn",
2553
+ "data-testid": "docx-generate-image-prompt",
2554
+ onChange: (event) => setPrompt(event.target.value),
2555
+ onKeyDown: (event) => {
2556
+ if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) void run();
2557
+ }
2558
+ }
2559
+ )
2560
+ ] }),
2561
+ generation.aspectRatios && generation.aspectRatios.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
2562
+ "Aspect ratio",
2563
+ /* @__PURE__ */ jsxRuntime.jsxs(
2564
+ "select",
2565
+ {
2566
+ value: aspectRatio,
2567
+ disabled: busy,
2568
+ onChange: (event) => setAspectRatio(event.target.value),
2569
+ children: [
2570
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: AUTO, children: "Auto" }),
2571
+ generation.aspectRatios.map((ratio) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: ratio.value, children: ratio.label }, ratio.value))
2572
+ ]
2573
+ }
2574
+ )
2575
+ ] }),
2576
+ busy && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", "data-testid": "docx-generate-image-status", children: "Generating\u2026 the picture is inserted where your cursor was. You can keep writing." }),
2577
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error }),
2578
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-form-actions", children: busy ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => abort.current?.abort(), children: "Cancel" }) : /* @__PURE__ */ jsxRuntime.jsx(
2579
+ "button",
2580
+ {
2581
+ type: "submit",
2582
+ disabled: !prompt.trim(),
2583
+ "data-testid": "docx-generate-image-submit",
2584
+ children: "Generate"
2585
+ }
2586
+ ) })
2587
+ ]
2588
+ }
2589
+ );
2590
+ }
2591
+ }
2592
+ );
2593
+ }
2358
2594
  function wordDraftHtml(markdown) {
2359
2595
  const template = document.createElement("template");
2360
2596
  template.innerHTML = server.renderToStaticMarkup(/* @__PURE__ */ jsxRuntime.jsx(ui.AiMarkdown, { children: markdown }));
@@ -2442,61 +2678,6 @@ var WordDraftStream = class {
2442
2678
  }
2443
2679
  }
2444
2680
  };
2445
- function RibbonMenu({
2446
- label,
2447
- icon,
2448
- children,
2449
- className,
2450
- testId,
2451
- title
2452
- }) {
2453
- const [open, setOpen] = React3.useState(false);
2454
- const element = React3.useRef(null);
2455
- React3.useEffect(() => {
2456
- if (!open) return;
2457
- const dismiss = (event) => {
2458
- if (!element.current?.contains(event.target)) setOpen(false);
2459
- };
2460
- const escape = (event) => {
2461
- if (event.key === "Escape") setOpen(false);
2462
- };
2463
- document.addEventListener("pointerdown", dismiss);
2464
- document.addEventListener("keydown", escape);
2465
- return () => {
2466
- document.removeEventListener("pointerdown", dismiss);
2467
- document.removeEventListener("keydown", escape);
2468
- };
2469
- }, [open]);
2470
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-menu", ref: element, children: [
2471
- /* @__PURE__ */ jsxRuntime.jsx(
2472
- "button",
2473
- {
2474
- type: "button",
2475
- className: ["native-docx-ribbon-trigger", className].filter(Boolean).join(" "),
2476
- "aria-label": label,
2477
- title: title ?? label,
2478
- "aria-expanded": open,
2479
- "data-testid": testId,
2480
- onMouseDown: (event) => event.preventDefault(),
2481
- onClick: () => setOpen((value) => !value),
2482
- children: icon
2483
- }
2484
- ),
2485
- open && /* @__PURE__ */ jsxRuntime.jsx(
2486
- "div",
2487
- {
2488
- className: "native-docx-ribbon-popover",
2489
- role: "group",
2490
- "aria-label": label,
2491
- onMouseDown: (event) => {
2492
- if (!(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement))
2493
- event.preventDefault();
2494
- },
2495
- children: typeof children === "function" ? children(() => setOpen(false)) : children
2496
- }
2497
- )
2498
- ] });
2499
- }
2500
2681
 
2501
2682
  // src/docx/wordStyles.ts
2502
2683
  var QUICK_STYLES = ["Normal", "Title", "heading 1", "heading 2", "heading 3"];
@@ -2786,6 +2967,679 @@ function WordShortcuts({ scope }) {
2786
2967
  }, [scope]);
2787
2968
  return null;
2788
2969
  }
2970
+
2971
+ // src/docx/layout/presets.ts
2972
+ var TWIPS_PER_INCH = 1440;
2973
+ var MARGIN_PRESETS = [
2974
+ { id: "normal", label: "Normal", top: 1440, right: 1440, bottom: 1440, left: 1440 },
2975
+ { id: "narrow", label: "Narrow", top: 720, right: 720, bottom: 720, left: 720 },
2976
+ { id: "moderate", label: "Moderate", top: 1440, right: 1080, bottom: 1440, left: 1080 },
2977
+ { id: "wide", label: "Wide", top: 1440, right: 2880, bottom: 1440, left: 2880 }
2978
+ ];
2979
+ var PAPER_SIZES = [
2980
+ { id: "letter", label: "Letter", width: 12240, height: 15840 },
2981
+ { id: "legal", label: "Legal", width: 12240, height: 20160 },
2982
+ { id: "a4", label: "A4", width: 11906, height: 16838 },
2983
+ { id: "a5", label: "A5", width: 8391, height: 11906 },
2984
+ { id: "executive", label: "Executive", width: 10440, height: 15120 }
2985
+ ];
2986
+ var TOLERANCE = 20;
2987
+ var near = (a, b) => Math.abs(a - b) <= TOLERANCE;
2988
+ function matchMargins(setup) {
2989
+ if (!setup) return null;
2990
+ const m = setup.marginsTwips;
2991
+ return MARGIN_PRESETS.find(
2992
+ (p) => near(p.top, m.top) && near(p.right, m.right) && near(p.bottom, m.bottom) && near(p.left, m.left)
2993
+ )?.id ?? null;
2994
+ }
2995
+ function matchPaper(setup) {
2996
+ if (!setup) return null;
2997
+ const short = Math.min(setup.pageWidthTwips, setup.pageHeightTwips);
2998
+ const long = Math.max(setup.pageWidthTwips, setup.pageHeightTwips);
2999
+ return PAPER_SIZES.find((p) => near(p.width, short) && near(p.height, long))?.id ?? null;
3000
+ }
3001
+ function orientedSize(paper, orientation) {
3002
+ return orientation === "landscape" ? { pageWidthTwips: paper.height, pageHeightTwips: paper.width } : { pageWidthTwips: paper.width, pageHeightTwips: paper.height };
3003
+ }
3004
+ function inches(twips) {
3005
+ return `${Number((twips / TWIPS_PER_INCH).toFixed(2))}"`;
3006
+ }
3007
+ function paperDescription(paper) {
3008
+ return `${inches(paper.width)} \xD7 ${inches(paper.height)}`;
3009
+ }
3010
+ var COLUMNS_UNSUPPORTED = "Text columns are not available in this editor yet. Documents that already use columns display and save them unchanged.";
3011
+ function RibbonGallery({
3012
+ label,
3013
+ choices,
3014
+ current,
3015
+ onPick,
3016
+ close,
3017
+ testId
3018
+ }) {
3019
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-gallery", role: "menu", "aria-label": label, "data-testid": testId, children: choices.map((choice) => /* @__PURE__ */ jsxRuntime.jsxs(
3020
+ "button",
3021
+ {
3022
+ type: "button",
3023
+ role: "menuitemradio",
3024
+ "aria-checked": current === choice.id,
3025
+ disabled: choice.disabled,
3026
+ title: choice.title,
3027
+ "data-choice": choice.id,
3028
+ onClick: () => {
3029
+ onPick(choice.id);
3030
+ close();
3031
+ },
3032
+ children: [
3033
+ choice.icon,
3034
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "native-docx-gallery-text", children: [
3035
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-gallery-label", children: choice.label }),
3036
+ choice.detail && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-gallery-detail", children: choice.detail })
3037
+ ] })
3038
+ ]
3039
+ },
3040
+ choice.id
3041
+ )) });
3042
+ }
3043
+ var marginDetail = (p) => `Top ${inches(p.top)} \xB7 Bottom ${inches(p.bottom)} \xB7 Left ${inches(p.left)} \xB7 Right ${inches(p.right)}`;
3044
+ function Margins({ setup, apply, openDialog }) {
3045
+ return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label: "Margins", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Scaling, { size: 16 }), testId: "docx-layout-margins", children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3046
+ /* @__PURE__ */ jsxRuntime.jsx(
3047
+ RibbonGallery,
3048
+ {
3049
+ label: "Margins",
3050
+ current: matchMargins(setup),
3051
+ close,
3052
+ choices: MARGIN_PRESETS.map((p) => ({
3053
+ id: p.id,
3054
+ label: p.label,
3055
+ detail: marginDetail(p)
3056
+ })),
3057
+ onPick: (id) => {
3058
+ const p = MARGIN_PRESETS.find((m) => m.id === id);
3059
+ apply({
3060
+ marginTopTwips: p.top,
3061
+ marginRightTwips: p.right,
3062
+ marginBottomTwips: p.bottom,
3063
+ marginLeftTwips: p.left,
3064
+ scope: "section"
3065
+ });
3066
+ }
3067
+ }
3068
+ ),
3069
+ /* @__PURE__ */ jsxRuntime.jsx(
3070
+ "button",
3071
+ {
3072
+ type: "button",
3073
+ className: "native-docx-gallery-more",
3074
+ onClick: () => {
3075
+ close();
3076
+ openDialog();
3077
+ },
3078
+ children: "Custom margins\u2026"
3079
+ }
3080
+ )
3081
+ ] }) });
3082
+ }
3083
+ function Orientation({ setup, apply }) {
3084
+ return /* @__PURE__ */ jsxRuntime.jsx(
3085
+ RibbonMenu,
3086
+ {
3087
+ label: "Orientation",
3088
+ icon: setup?.orientation === "landscape" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RectangleHorizontal, { size: 16 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RectangleVertical, { size: 16 }),
3089
+ testId: "docx-layout-orientation",
3090
+ children: (close) => /* @__PURE__ */ jsxRuntime.jsx(
3091
+ RibbonGallery,
3092
+ {
3093
+ label: "Orientation",
3094
+ current: setup?.orientation,
3095
+ close,
3096
+ choices: [
3097
+ { id: "portrait", label: "Portrait", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RectangleVertical, { size: 16 }) },
3098
+ { id: "landscape", label: "Landscape", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RectangleHorizontal, { size: 16 }) }
3099
+ ],
3100
+ onPick: (id) => apply({ orientation: id, scope: "section" })
3101
+ }
3102
+ )
3103
+ }
3104
+ );
3105
+ }
3106
+ function Size({ setup, apply, openDialog }) {
3107
+ return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label: "Size", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { size: 16 }), testId: "docx-layout-size", children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3108
+ /* @__PURE__ */ jsxRuntime.jsx(
3109
+ RibbonGallery,
3110
+ {
3111
+ label: "Size",
3112
+ current: matchPaper(setup),
3113
+ close,
3114
+ choices: PAPER_SIZES.map((p) => ({
3115
+ id: p.id,
3116
+ label: p.label,
3117
+ detail: paperDescription(p)
3118
+ })),
3119
+ onPick: (id) => apply({
3120
+ ...orientedSize(
3121
+ PAPER_SIZES.find((p) => p.id === id),
3122
+ setup?.orientation
3123
+ ),
3124
+ scope: "section"
3125
+ })
3126
+ }
3127
+ ),
3128
+ /* @__PURE__ */ jsxRuntime.jsx(
3129
+ "button",
3130
+ {
3131
+ type: "button",
3132
+ className: "native-docx-gallery-more",
3133
+ onClick: () => {
3134
+ close();
3135
+ openDialog();
3136
+ },
3137
+ children: "More paper sizes\u2026"
3138
+ }
3139
+ )
3140
+ ] }) });
3141
+ }
3142
+ var COLUMN_BREAK = { type: "insertBreak", kind: "column" };
3143
+ function Breaks() {
3144
+ const page = react.useEditorCommand("insert.pageBreak");
3145
+ const nextPage = react.useEditorCommand("insert.sectionBreakNextPage");
3146
+ const continuous = react.useEditorCommand("insert.sectionBreakContinuous");
3147
+ const column = react.useEditorCommand(COLUMN_BREAK);
3148
+ const rows = [
3149
+ { id: "page", label: "Page", detail: "Start the next page here", command: page },
3150
+ { id: "column", label: "Column", detail: "Start the next column here", command: column },
3151
+ {
3152
+ id: "nextPage",
3153
+ label: "Next Page",
3154
+ detail: "Section break: new section on the next page",
3155
+ command: nextPage
3156
+ },
3157
+ {
3158
+ id: "continuous",
3159
+ label: "Continuous",
3160
+ detail: "Section break: new section on the same page",
3161
+ command: continuous
3162
+ }
3163
+ ];
3164
+ return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label: "Breaks", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SeparatorHorizontal, { size: 16 }), testId: "docx-layout-breaks", children: (close) => /* @__PURE__ */ jsxRuntime.jsx(
3165
+ RibbonGallery,
3166
+ {
3167
+ label: "Breaks",
3168
+ close,
3169
+ choices: rows.map((row) => ({
3170
+ id: row.id,
3171
+ label: row.label,
3172
+ detail: row.detail,
3173
+ disabled: !row.command.isEnabled,
3174
+ title: row.command.disabledReason ?? void 0
3175
+ })),
3176
+ onPick: (id) => void rows.find((row) => row.id === id)?.command.execute()
3177
+ }
3178
+ ) });
3179
+ }
3180
+ function LayoutButtons() {
3181
+ const { pageSetup, apply } = react.usePageSetup();
3182
+ const [dialog, setDialog] = React3.useState(false);
3183
+ const props = { setup: pageSetup, apply, openDialog: () => setDialog(true) };
3184
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3185
+ /* @__PURE__ */ jsxRuntime.jsx(Margins, { ...props }),
3186
+ /* @__PURE__ */ jsxRuntime.jsx(Orientation, { ...props }),
3187
+ /* @__PURE__ */ jsxRuntime.jsx(Size, { ...props }),
3188
+ /* @__PURE__ */ jsxRuntime.jsx(
3189
+ react.DocxEditor.Toolbar.Action,
3190
+ {
3191
+ label: "Columns",
3192
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Columns2, { size: 16 }),
3193
+ disabled: true,
3194
+ disabledReason: COLUMNS_UNSUPPORTED,
3195
+ className: "native-docx-layout-columns"
3196
+ }
3197
+ ),
3198
+ /* @__PURE__ */ jsxRuntime.jsx(Breaks, {}),
3199
+ /* @__PURE__ */ jsxRuntime.jsx(
3200
+ react.DocxEditor.Toolbar.Action,
3201
+ {
3202
+ label: "Page Setup\u2026",
3203
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings2, { size: 16 }),
3204
+ onSelect: () => setDialog(true),
3205
+ className: "native-docx-layout-page-setup"
3206
+ }
3207
+ ),
3208
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.PageSetupDialog, { open: dialog, onClose: () => setDialog(false) })
3209
+ ] });
3210
+ }
3211
+ var ROW_ABOVE = { type: "insertRow", where: "above" };
3212
+ var ROW_BELOW = { type: "insertRow", where: "below" };
3213
+ var COLUMN_LEFT = { type: "insertColumn", where: "left" };
3214
+ var COLUMN_RIGHT = { type: "insertColumn", where: "right" };
3215
+ var MERGE = { type: "mergeCells" };
3216
+ var SPLIT = { type: "splitCell", rows: 1, cols: 2 };
3217
+ var HEADER_ROW = { type: "toggleHeaderRow" };
3218
+ var DELETE_ROW = { type: "deleteRow" };
3219
+ var DELETE_COLUMN = { type: "deleteColumn" };
3220
+ var DELETE_TABLE = { type: "deleteTable" };
3221
+ var ALIGN_TOP = { type: "setTableCellVerticalAlignment", alignment: "top" };
3222
+ var ALIGN_CENTER = { type: "setTableCellVerticalAlignment", alignment: "center" };
3223
+ var ALIGN_BOTTOM = { type: "setTableCellVerticalAlignment", alignment: "bottom" };
3224
+ function useRows(rows) {
3225
+ return rows.map((row) => ({ ...row, state: react.useEditorCommand(row.command) }));
3226
+ }
3227
+ function CommandGallery({
3228
+ label,
3229
+ icon,
3230
+ testId,
3231
+ rows
3232
+ }) {
3233
+ const bound = useRows(rows);
3234
+ return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label, icon, testId, children: (close) => /* @__PURE__ */ jsxRuntime.jsx(
3235
+ RibbonGallery,
3236
+ {
3237
+ label,
3238
+ close,
3239
+ choices: bound.map((row) => ({
3240
+ id: row.id,
3241
+ label: row.label,
3242
+ icon: row.icon,
3243
+ disabled: !row.state.isEnabled,
3244
+ title: row.state.disabledReason ?? void 0
3245
+ })),
3246
+ onPick: (id) => void bound.find((row) => row.id === id)?.state.execute()
3247
+ }
3248
+ ) });
3249
+ }
3250
+ function CommandAction({
3251
+ command,
3252
+ label,
3253
+ icon,
3254
+ testId
3255
+ }) {
3256
+ const state = react.useEditorCommand(command);
3257
+ return /* @__PURE__ */ jsxRuntime.jsx(
3258
+ react.DocxEditor.Toolbar.Action,
3259
+ {
3260
+ label,
3261
+ icon,
3262
+ active: state.isActive,
3263
+ disabled: !state.isEnabled,
3264
+ disabledReason: state.disabledReason ?? void 0,
3265
+ onSelect: () => void state.execute(),
3266
+ className: `native-docx-table-${testId}`
3267
+ }
3268
+ );
3269
+ }
3270
+ function TableButtons() {
3271
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3272
+ /* @__PURE__ */ jsxRuntime.jsx(
3273
+ CommandAction,
3274
+ {
3275
+ command: ROW_ABOVE,
3276
+ label: "Insert row above",
3277
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BetweenHorizontalStart, { size: 16 }),
3278
+ testId: "row-above"
3279
+ }
3280
+ ),
3281
+ /* @__PURE__ */ jsxRuntime.jsx(
3282
+ CommandAction,
3283
+ {
3284
+ command: ROW_BELOW,
3285
+ label: "Insert row below",
3286
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BetweenHorizontalEnd, { size: 16 }),
3287
+ testId: "row-below"
3288
+ }
3289
+ ),
3290
+ /* @__PURE__ */ jsxRuntime.jsx(
3291
+ CommandAction,
3292
+ {
3293
+ command: COLUMN_LEFT,
3294
+ label: "Insert column left",
3295
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BetweenVerticalStart, { size: 16 }),
3296
+ testId: "column-left"
3297
+ }
3298
+ ),
3299
+ /* @__PURE__ */ jsxRuntime.jsx(
3300
+ CommandAction,
3301
+ {
3302
+ command: COLUMN_RIGHT,
3303
+ label: "Insert column right",
3304
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BetweenVerticalEnd, { size: 16 }),
3305
+ testId: "column-right"
3306
+ }
3307
+ ),
3308
+ /* @__PURE__ */ jsxRuntime.jsx(
3309
+ CommandGallery,
3310
+ {
3311
+ label: "Delete",
3312
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 16 }),
3313
+ testId: "docx-table-delete",
3314
+ rows: [
3315
+ { id: "row", label: "Delete row", command: DELETE_ROW },
3316
+ { id: "column", label: "Delete column", command: DELETE_COLUMN },
3317
+ { id: "table", label: "Delete table", command: DELETE_TABLE }
3318
+ ]
3319
+ }
3320
+ ),
3321
+ /* @__PURE__ */ jsxRuntime.jsx(
3322
+ CommandAction,
3323
+ {
3324
+ command: MERGE,
3325
+ label: "Merge cells",
3326
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Merge, { size: 16 }),
3327
+ testId: "merge"
3328
+ }
3329
+ ),
3330
+ /* @__PURE__ */ jsxRuntime.jsx(CommandAction, { command: SPLIT, label: "Split cell", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Split, { size: 16 }), testId: "split" }),
3331
+ /* @__PURE__ */ jsxRuntime.jsx(
3332
+ CommandAction,
3333
+ {
3334
+ command: HEADER_ROW,
3335
+ label: "Repeat header row",
3336
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Heading, { size: 16 }),
3337
+ testId: "header-row"
3338
+ }
3339
+ ),
3340
+ /* @__PURE__ */ jsxRuntime.jsx(
3341
+ CommandGallery,
3342
+ {
3343
+ label: "Cell alignment",
3344
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignVerticalJustifyCenter, { size: 16 }),
3345
+ testId: "docx-table-align",
3346
+ rows: [
3347
+ {
3348
+ id: "top",
3349
+ label: "Top",
3350
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignVerticalJustifyStart, { size: 16 }),
3351
+ command: ALIGN_TOP
3352
+ },
3353
+ {
3354
+ id: "center",
3355
+ label: "Center",
3356
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignVerticalJustifyCenter, { size: 16 }),
3357
+ command: ALIGN_CENTER
3358
+ },
3359
+ {
3360
+ id: "bottom",
3361
+ label: "Bottom",
3362
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignVerticalJustifyEnd, { size: 16 }),
3363
+ command: ALIGN_BOTTOM
3364
+ }
3365
+ ]
3366
+ }
3367
+ ),
3368
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableBorderTarget, {}),
3369
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableBorderStyle, {}),
3370
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableBorderWidth, {}),
3371
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableBorderColor, {}),
3372
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableCellFill, {})
3373
+ ] });
3374
+ }
3375
+ var CAPTION_LABELS = ["Figure", "Table", "Equation"];
3376
+ var CAPTION_STYLES = chunkAOFATOT3_cjs.stylesXml(
3377
+ "",
3378
+ '<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style><w:style w:type="paragraph" w:styleId="Caption"><w:name w:val="caption"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:uiPriority w:val="35"/><w:unhideWhenUsed/><w:qFormat/><w:pPr><w:spacing w:after="200" w:line="240" w:lineRule="auto"/></w:pPr><w:rPr><w:i/><w:iCs/><w:color w:val="44546A"/><w:sz w:val="18"/><w:szCs w:val="18"/></w:rPr></w:style>'
3379
+ );
3380
+ function seqIdentifier(instruction) {
3381
+ const match = /^\s*SEQ\s+("[^"]+"|\S+)/i.exec(instruction);
3382
+ return match ? match[1].replace(/"/g, "") : null;
3383
+ }
3384
+ function countSeqFields(root, label, throughId) {
3385
+ let count = 0;
3386
+ let done = false;
3387
+ const target = label.toLowerCase();
3388
+ const visit = (node) => {
3389
+ if (done) return;
3390
+ if (node.localName === "fldSimple") {
3391
+ const instr = node.attributes?.find((a) => a.localName === "instr")?.value ?? "";
3392
+ if (seqIdentifier(instr)?.toLowerCase() === target) count++;
3393
+ } else if (node.localName === "instrText") {
3394
+ const text = (node.children ?? []).map((c) => c.value ?? "").join("");
3395
+ if (seqIdentifier(text)?.toLowerCase() === target) count++;
3396
+ }
3397
+ node.children?.forEach(visit);
3398
+ if (throughId && node.id === throughId) done = true;
3399
+ };
3400
+ visit(root);
3401
+ return count;
3402
+ }
3403
+ function captionParagraphXml(label, number, text) {
3404
+ const run = (value) => `<w:r><w:t xml:space="preserve">${chunkAOFATOT3_cjs.esc(value)}</w:t></w:r>`;
3405
+ const rest = text.trim() ? `: ${text.trim()}` : "";
3406
+ return `<w:p><w:pPr><w:pStyle w:val="Caption"/></w:pPr>${run(`${label} `)}<w:fldSimple w:instr=" SEQ ${chunkAOFATOT3_cjs.esc(label)} \\* ARABIC "><w:r><w:t>${number}</w:t></w:r></w:fldSimple>${rest ? run(rest) : ""}</w:p>`;
3407
+ }
3408
+ function base642(bytes) {
3409
+ let binary = "";
3410
+ for (let i = 0; i < bytes.length; i += 32768)
3411
+ binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
3412
+ return btoa(binary);
3413
+ }
3414
+ function captionFragmentHtml(label, number, text, revision) {
3415
+ const untracked = chunkAOFATOT3_cjs.docxPackage({
3416
+ document: chunkAOFATOT3_cjs.documentXml(captionParagraphXml(label, number, text)),
3417
+ styles: CAPTION_STYLES,
3418
+ title: "Caption"
3419
+ });
3420
+ const bytes = revision ? template.trackInsertion(untracked, revision, true) : untracked;
3421
+ return `<div data-docx-fragment="${base642(bytes)}" data-docx-fragment-end="covered"></div>`;
3422
+ }
3423
+ var TRANSFORMS = Object.fromEntries(
3424
+ ["rotateCW", "rotateCCW", "flipH", "flipV"].map((action) => [
3425
+ action,
3426
+ { type: "transformImage", action }
3427
+ ])
3428
+ );
3429
+ function TransformAction({
3430
+ action,
3431
+ label,
3432
+ icon
3433
+ }) {
3434
+ const state = react.useEditorCommand(TRANSFORMS[action]);
3435
+ return /* @__PURE__ */ jsxRuntime.jsx(
3436
+ react.DocxEditor.Toolbar.Action,
3437
+ {
3438
+ label,
3439
+ icon,
3440
+ disabled: !state.isEnabled,
3441
+ disabledReason: state.disabledReason ?? void 0,
3442
+ onSelect: () => void state.execute(),
3443
+ className: `native-docx-picture-${action}`
3444
+ }
3445
+ );
3446
+ }
3447
+ function insertCaption(editor, label, text, track) {
3448
+ const surface = editor.surface;
3449
+ const selection = surface?.state().selection;
3450
+ if (!surface || !selection) return null;
3451
+ const { paragraphId } = selection.head;
3452
+ const number = countSeqFields(
3453
+ surface.session.part().root,
3454
+ label,
3455
+ paragraphId
3456
+ ) + 1;
3457
+ const ids = surface.session.paragraphIds();
3458
+ const next = ids[ids.indexOf(paragraphId) + 1];
3459
+ const caption = `${label} ${number}${text.trim() ? `: ${text.trim()}` : ""}`;
3460
+ const outcome = track({
3461
+ label: `Inserted caption: ${caption}`,
3462
+ inserted: (inserted) => inserted !== null,
3463
+ insert: (revision) => {
3464
+ if (next) {
3465
+ surface.setSelection({
3466
+ anchor: { paragraphId: next, offset: 0 },
3467
+ head: { paragraphId: next, offset: 0 }
3468
+ });
3469
+ } else {
3470
+ editor.exec({ type: "selectAll" });
3471
+ const end = surface.state().selection?.head;
3472
+ if (!end) return null;
3473
+ surface.setSelection({ anchor: end, head: end });
3474
+ surface.splitParagraph();
3475
+ }
3476
+ const ok2 = editor.exec({
3477
+ type: "paste",
3478
+ text: caption,
3479
+ html: captionFragmentHtml(label, number, text, revision)
3480
+ }).ok;
3481
+ return ok2 ? number : null;
3482
+ }
3483
+ });
3484
+ return outcome?.result ?? null;
3485
+ }
3486
+ function CaptionButton({ defaultLabel = "Figure" }) {
3487
+ const editor = react.useDocxEditor();
3488
+ const track = useTrackedOrNoted();
3489
+ const [label, setLabel] = React3.useState(defaultLabel);
3490
+ const [text, setText] = React3.useState("");
3491
+ const [error, setError] = React3.useState("");
3492
+ return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label: "Insert caption", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Captions, { size: 16 }), testId: "docx-insert-caption", children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(
3493
+ "form",
3494
+ {
3495
+ className: "native-docx-form",
3496
+ onSubmit: (event) => {
3497
+ event.preventDefault();
3498
+ if (!editor) return;
3499
+ try {
3500
+ if (insertCaption(editor, label, text, track) === null)
3501
+ return setError("The caption could not be inserted here.");
3502
+ setText("");
3503
+ setError("");
3504
+ close();
3505
+ editor.focus();
3506
+ } catch (failure) {
3507
+ setError(failure instanceof Error ? failure.message : String(failure));
3508
+ }
3509
+ },
3510
+ children: [
3511
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
3512
+ "Label",
3513
+ /* @__PURE__ */ jsxRuntime.jsx(
3514
+ "select",
3515
+ {
3516
+ value: label,
3517
+ onChange: (event) => setLabel(event.target.value),
3518
+ children: CAPTION_LABELS.map((value) => /* @__PURE__ */ jsxRuntime.jsx("option", { children: value }, value))
3519
+ }
3520
+ )
3521
+ ] }),
3522
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
3523
+ "Caption",
3524
+ /* @__PURE__ */ jsxRuntime.jsx(
3525
+ "input",
3526
+ {
3527
+ autoFocus: true,
3528
+ value: text,
3529
+ placeholder: "Optional text after the number",
3530
+ "data-testid": "docx-caption-text",
3531
+ onChange: (event) => setText(event.target.value)
3532
+ }
3533
+ )
3534
+ ] }),
3535
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error }),
3536
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", "data-testid": "docx-caption-insert", children: "Insert" })
3537
+ ]
3538
+ }
3539
+ ) });
3540
+ }
3541
+ function PictureButtons() {
3542
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3543
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.ImageWrap, {}),
3544
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.ImageProperties, {}),
3545
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.ImageAltText, {}),
3546
+ /* @__PURE__ */ jsxRuntime.jsx(TransformAction, { action: "rotateCW", label: "Rotate right 90\xB0", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { size: 16 }) }),
3547
+ /* @__PURE__ */ jsxRuntime.jsx(TransformAction, { action: "rotateCCW", label: "Rotate left 90\xB0", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { size: 16 }) }),
3548
+ /* @__PURE__ */ jsxRuntime.jsx(
3549
+ TransformAction,
3550
+ {
3551
+ action: "flipH",
3552
+ label: "Flip horizontal",
3553
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FlipHorizontal2, { size: 16 })
3554
+ }
3555
+ ),
3556
+ /* @__PURE__ */ jsxRuntime.jsx(TransformAction, { action: "flipV", label: "Flip vertical", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FlipVertical2, { size: 16 }) }),
3557
+ /* @__PURE__ */ jsxRuntime.jsx(CaptionButton, {})
3558
+ ] });
3559
+ }
3560
+ var LAYOUT_TAB = "Layout";
3561
+ var TABLE_TAB = "Table";
3562
+ var PICTURE_TAB = "Picture";
3563
+ function useContextualTabs(tab) {
3564
+ const inTable = react.useEditorState((snapshot) => snapshot.table !== null);
3565
+ const onPicture = react.useEditorState((snapshot) => snapshot.image !== null);
3566
+ const tabs = [...inTable ? [TABLE_TAB] : [], ...onPicture ? [PICTURE_TAB] : []];
3567
+ const contextual = tab === TABLE_TAB || tab === PICTURE_TAB;
3568
+ return { tabs, shown: contextual && !tabs.includes(tab) ? "Home" : tab };
3569
+ }
3570
+ function LayoutTabContent({ tab }) {
3571
+ if (tab === LAYOUT_TAB) return /* @__PURE__ */ jsxRuntime.jsx(LayoutButtons, {});
3572
+ if (tab === TABLE_TAB) return /* @__PURE__ */ jsxRuntime.jsx(TableButtons, {});
3573
+ if (tab === PICTURE_TAB) return /* @__PURE__ */ jsxRuntime.jsx(PictureButtons, {});
3574
+ return null;
3575
+ }
3576
+ var contains = (node, id) => node.id === id || (node.children ?? []).some((child) => contains(child, id));
3577
+ function firstParagraph(node) {
3578
+ for (const child of node.children ?? []) {
3579
+ if (child.kind === "paragraph" && child.id) return child.id;
3580
+ if (child.localName === "tbl") continue;
3581
+ const nested = firstParagraph(child);
3582
+ if (nested) return nested;
3583
+ }
3584
+ return null;
3585
+ }
3586
+ function tableCells(root, paragraphId) {
3587
+ let table = null;
3588
+ const find = (node) => {
3589
+ if (node.localName === "tbl" && contains(node, paragraphId)) table = node;
3590
+ for (const child of node.children ?? []) if (contains(child, paragraphId)) find(child);
3591
+ };
3592
+ find(root);
3593
+ if (!table) return null;
3594
+ const cells = [];
3595
+ let index = -1;
3596
+ const rows = (node) => (node.children ?? []).flatMap(
3597
+ (child) => child.localName === "tr" ? [child] : child.localName === "tbl" ? [] : rows(child)
3598
+ );
3599
+ for (const row of rows(table))
3600
+ for (const cell of (row.children ?? []).filter((child) => child.localName === "tc")) {
3601
+ const first = firstParagraph(cell);
3602
+ if (!first) continue;
3603
+ if (contains(cell, paragraphId)) index = cells.length;
3604
+ cells.push(first);
3605
+ }
3606
+ return index < 0 ? null : { cells, index };
3607
+ }
3608
+ function TableTabKeys({ scope }) {
3609
+ const editor = react.useDocxEditor();
3610
+ const latest = React3.useRef(editor);
3611
+ latest.current = editor;
3612
+ React3.useEffect(() => {
3613
+ const element = scope.current;
3614
+ if (!element) return;
3615
+ const onKeyDown = (event) => {
3616
+ if (event.key !== "Tab" || event.ctrlKey || event.metaKey || event.altKey) return;
3617
+ const editor2 = latest.current;
3618
+ const surface = editor2?.surface;
3619
+ const head = surface?.state().selection?.head;
3620
+ if (!editor2 || !surface || !head) return;
3621
+ const root = () => surface.session.part().root;
3622
+ const table = tableCells(root(), head.paragraphId);
3623
+ if (!table) return;
3624
+ event.preventDefault();
3625
+ event.stopPropagation();
3626
+ let target = table.cells[table.index + (event.shiftKey ? -1 : 1)];
3627
+ if (!target && !event.shiftKey && editor2.exec({ type: "insertRow", where: "below" }).ok) {
3628
+ const grown = tableCells(
3629
+ root(),
3630
+ surface.state().selection?.head.paragraphId ?? head.paragraphId
3631
+ );
3632
+ target = grown?.cells[table.cells.length] ?? "";
3633
+ }
3634
+ if (!target) return;
3635
+ const point = { paragraphId: target, offset: 0 };
3636
+ surface.setSelection({ anchor: point, head: point });
3637
+ };
3638
+ element.addEventListener("keydown", onKeyDown, true);
3639
+ return () => element.removeEventListener("keydown", onKeyDown, true);
3640
+ }, [scope]);
3641
+ return null;
3642
+ }
2789
3643
  function QuickParts() {
2790
3644
  const house = useHouseTemplate();
2791
3645
  if (!house || house.blocks.length === 0) return null;
@@ -2956,17 +3810,23 @@ function DefinedTermButtons() {
2956
3810
  }
2957
3811
  function DocxRibbon({
2958
3812
  onSave,
2959
- badge
3813
+ badge,
3814
+ imageGeneration
2960
3815
  }) {
2961
- const [tab, setTab] = React3.useState("Home");
3816
+ const [selected, setTab] = React3.useState("Home");
3817
+ const contextual = useContextualTabs(selected);
3818
+ useGenerateImageTarget();
3819
+ const tab = contextual.shown;
2962
3820
  const t = react.useChromeTranslate();
2963
3821
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon", children: [
2964
3822
  /* @__PURE__ */ jsxRuntime.jsxs("select", { "aria-label": "Ribbon tab", value: tab, onChange: (event) => setTab(event.target.value), children: [
2965
3823
  /* @__PURE__ */ jsxRuntime.jsx("option", { children: "Home" }),
2966
3824
  /* @__PURE__ */ jsxRuntime.jsx("option", { children: "Insert" }),
2967
3825
  /* @__PURE__ */ jsxRuntime.jsx("option", { children: "Design" }),
3826
+ /* @__PURE__ */ jsxRuntime.jsx("option", { children: LAYOUT_TAB }),
2968
3827
  /* @__PURE__ */ jsxRuntime.jsx("option", { children: "References" }),
2969
- /* @__PURE__ */ jsxRuntime.jsx("option", { children: "Review" })
3828
+ /* @__PURE__ */ jsxRuntime.jsx("option", { children: "Review" }),
3829
+ contextual.tabs.map((name) => /* @__PURE__ */ jsxRuntime.jsx("option", { children: name }, name))
2970
3830
  ] }),
2971
3831
  /* @__PURE__ */ jsxRuntime.jsxs(react.DocxEditor.Toolbar, { t, preset: false, onSave, children: [
2972
3832
  /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Undo, {}),
@@ -2997,10 +3857,14 @@ function DocxRibbon({
2997
3857
  tab === "Insert" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2998
3858
  /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableInsert, {}),
2999
3859
  /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.ImageInsert, {}),
3860
+ imageGeneration && /* @__PURE__ */ jsxRuntime.jsx(GenerateImageButton, { generation: imageGeneration }),
3861
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Button, { slotId: "insert.pageBreak" }),
3000
3862
  /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Link, {}),
3001
3863
  /* @__PURE__ */ jsxRuntime.jsx(DefinedTermButtons, {}),
3002
3864
  /* @__PURE__ */ jsxRuntime.jsx(QuickParts, {})
3003
3865
  ] }),
3866
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableCellFill, { hidden: true }),
3867
+ /* @__PURE__ */ jsxRuntime.jsx(LayoutTabContent, { tab }),
3004
3868
  tab === "Design" && /* @__PURE__ */ jsxRuntime.jsx(HouseTemplatePanel, {}),
3005
3869
  tab === "References" && /* @__PURE__ */ jsxRuntime.jsx(NoteButtons, {}),
3006
3870
  tab === "Review" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -3376,6 +4240,10 @@ function NativeDocxEditor({
3376
4240
  DocxRibbon,
3377
4241
  {
3378
4242
  onSave: () => void saveVersion(),
4243
+ imageGeneration: adapter.imageGeneration && {
4244
+ notify: adapter.notify,
4245
+ ...adapter.imageGeneration
4246
+ },
3379
4247
  badge: (
3380
4248
  // Says the document is shared live, in place of a title row above the ribbon.
3381
4249
  ready.room && ready.canEdit && !snapshot ? /* @__PURE__ */ jsxRuntime.jsx("span", { title: "Edits sync live with everyone who has this document open", children: "Co-edit mode" }) : void 0
@@ -3383,6 +4251,7 @@ function NativeDocxEditor({
3383
4251
  }
3384
4252
  ),
3385
4253
  !stream && /* @__PURE__ */ jsxRuntime.jsx(WordShortcuts, { scope: stageRef }),
4254
+ !stream && /* @__PURE__ */ jsxRuntime.jsx(TableTabKeys, { scope: stageRef }),
3386
4255
  /* @__PURE__ */ jsxRuntime.jsxs(
3387
4256
  "div",
3388
4257
  {
@@ -3525,6 +4394,7 @@ exports.DocxEditorReview = DocxEditorReview;
3525
4394
  exports.DocxMentions = DocxMentions;
3526
4395
  exports.DocxParticipants = DocxParticipants;
3527
4396
  exports.DocxRibbon = DocxRibbon;
4397
+ exports.GenerateImageButton = GenerateImageButton;
3528
4398
  exports.HouseTemplateProvider = HouseTemplateProvider;
3529
4399
  exports.NativeDocxEditor = NativeDocxEditor;
3530
4400
  exports.builtinHouseTemplate = builtinHouseTemplate;
@@ -3546,5 +4416,5 @@ exports.useReview = useReview;
3546
4416
  exports.useReviewItem = useReviewItem;
3547
4417
  exports.useTrackedOrNoted = useTrackedOrNoted;
3548
4418
  exports.withDirectEditing = withDirectEditing;
3549
- //# sourceMappingURL=chunk-44TPPPRJ.cjs.map
3550
- //# sourceMappingURL=chunk-44TPPPRJ.cjs.map
4419
+ //# sourceMappingURL=chunk-B7P73VHX.cjs.map
4420
+ //# sourceMappingURL=chunk-B7P73VHX.cjs.map