@arbidocs/blocks 0.5.115 → 0.5.116
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.
- package/dist/{ConnectedNativeDocxComparison-YXMYJWXY.cjs → ConnectedNativeDocxComparison-546ILGLW.cjs} +8 -8
- package/dist/{ConnectedNativeDocxComparison-YXMYJWXY.cjs.map → ConnectedNativeDocxComparison-546ILGLW.cjs.map} +1 -1
- package/dist/{ConnectedStreamedWordArtifact-2RTCHVPI.cjs → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs} +8 -8
- package/dist/{ConnectedStreamedWordArtifact-2RTCHVPI.cjs.map → ConnectedStreamedWordArtifact-S2ZFZLZQ.cjs.map} +1 -1
- package/dist/{FilesViewerDialog-I5QIHQZT.cjs → FilesViewerDialog-6UKR5WEF.cjs} +6 -6
- package/dist/{FilesViewerDialog-I5QIHQZT.cjs.map → FilesViewerDialog-6UKR5WEF.cjs.map} +1 -1
- package/dist/{NativeDocxEditor-H6TAEVGY.cjs → NativeDocxEditor-2LQY2CTV.cjs} +6 -6
- package/dist/{NativeDocxEditor-H6TAEVGY.cjs.map → NativeDocxEditor-2LQY2CTV.cjs.map} +1 -1
- package/dist/{chunk-M6IKVKU5.cjs → chunk-2CSLFAGF.cjs} +392 -149
- package/dist/chunk-2CSLFAGF.cjs.map +1 -0
- package/dist/{chunk-24EDG4PC.cjs → chunk-B2HNNG25.cjs} +5 -5
- package/dist/{chunk-24EDG4PC.cjs.map → chunk-B2HNNG25.cjs.map} +1 -1
- package/dist/{chunk-IW7CDJTA.cjs → chunk-COD5ENHK.cjs} +4 -4
- package/dist/{chunk-IW7CDJTA.cjs.map → chunk-COD5ENHK.cjs.map} +1 -1
- package/dist/chunk-HB2O4THB.cjs +18 -0
- package/dist/{chunk-CIHERNDO.cjs.map → chunk-HB2O4THB.cjs.map} +1 -1
- package/dist/{chunk-WR2SF44W.cjs → chunk-NIE3N6OM.cjs} +4 -4
- package/dist/{chunk-WR2SF44W.cjs.map → chunk-NIE3N6OM.cjs.map} +1 -1
- package/dist/{chunk-ZTXQIIFV.cjs → chunk-QHOHDNBU.cjs} +6 -6
- package/dist/{chunk-ZTXQIIFV.cjs.map → chunk-QHOHDNBU.cjs.map} +1 -1
- package/dist/{chunk-A3T3IC3K.cjs → chunk-SB4M3ITT.cjs} +190 -36
- package/dist/chunk-SB4M3ITT.cjs.map +1 -0
- package/dist/{chunk-X5LANJDZ.cjs → chunk-VGCTYTEW.cjs} +14 -6
- package/dist/chunk-VGCTYTEW.cjs.map +1 -0
- package/dist/{chunk-3A7QWUAW.cjs → chunk-VKH3BEZE.cjs} +3 -3
- package/dist/{chunk-3A7QWUAW.cjs.map → chunk-VKH3BEZE.cjs.map} +1 -1
- package/dist/{chunk-42TURFHF.cjs → chunk-YGBHY67W.cjs} +5 -5
- package/dist/{chunk-42TURFHF.cjs.map → chunk-YGBHY67W.cjs.map} +1 -1
- package/dist/connect/docx.cjs +12 -12
- package/dist/connect/index.cjs +78 -78
- package/dist/connect/viewer.cjs +4 -4
- package/dist/connection/docx/ConnectedNativeDocxEditor.js +10 -2
- package/dist/connection/docx/ConnectedNativeDocxEditor.js.map +2 -2
- package/dist/connection/viewer/ConnectedDocumentViewer.js +124 -21
- package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
- package/dist/connection/viewer/VersionDropdown.d.ts +9 -0
- package/dist/connection/viewer/VersionDropdown.js +39 -0
- package/dist/connection/viewer/VersionDropdown.js.map +7 -0
- package/dist/connection/viewer/ViewerPdfPane.js +4 -1
- package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
- package/dist/connection/viewer/useViewerBlobs.d.ts +3 -1
- package/dist/connection/viewer/useViewerBlobs.js +14 -8
- package/dist/connection/viewer/useViewerBlobs.js.map +2 -2
- package/dist/connection/viewer/useViewerTabs.js +10 -0
- package/dist/connection/viewer/useViewerTabs.js.map +2 -2
- package/dist/docx/DocxCommandMenu.d.ts +8 -0
- package/dist/docx/DocxCommandMenu.js +202 -0
- package/dist/docx/DocxCommandMenu.js.map +7 -0
- package/dist/docx/NativeDocxEditor.d.ts +4 -2
- package/dist/docx/NativeDocxEditor.js +51 -12
- package/dist/docx/NativeDocxEditor.js.map +2 -2
- package/dist/docx/RibbonMenu.d.ts +3 -1
- package/dist/docx/RibbonMenu.js +10 -3
- package/dist/docx/RibbonMenu.js.map +2 -2
- package/dist/docx/RibbonOverflow.d.ts +3 -0
- package/dist/docx/RibbonOverflow.js +24 -1
- package/dist/docx/RibbonOverflow.js.map +2 -2
- package/dist/docx/index.cjs +38 -38
- package/dist/docx/signatures/SignatureFields.d.ts +3 -1
- package/dist/docx/signatures/SignatureFields.js +17 -8
- package/dist/docx/signatures/SignatureFields.js.map +2 -2
- package/dist/index.cjs +50 -50
- package/dist/styles.css +1 -1
- package/dist/workflow-canvas/index.cjs +9 -9
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +5 -5
- package/src/docx/styles.css +94 -0
- package/dist/chunk-A3T3IC3K.cjs.map +0 -1
- package/dist/chunk-CIHERNDO.cjs +0 -18
- package/dist/chunk-M6IKVKU5.cjs.map +0 -1
- package/dist/chunk-X5LANJDZ.cjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/docx/RibbonMenu.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, { useEffect, useRef, useState } from 'react'\n\n/**\n * A ribbon button that opens a panel under the ribbon (Font, More formatting, the style gallery).\n * Pressing the trigger never takes the caret out of the document; the panel closes on Escape or a\n * press outside it. `children` may be a function that receives `close`, for panels that close\n * themselves once the user has picked something.\n */\nexport function RibbonMenu({\n label,\n icon,\n children,\n className,\n testId,\n title,\n keepMounted = false,\n popoverClassName,\n}: {\n label: string\n /** Tooltip; defaults to `label`. */\n title?: string\n /** Trigger content: an icon, or a short text label with a `className` that widens it. */\n icon: React.ReactNode\n children: React.ReactNode | ((close: () => void) => React.ReactNode)\n className?: string\n testId?: string\n /** Keep the panel's content mounted (hidden) while closed, so its controls keep their state. */\n keepMounted?: boolean\n popoverClassName?: string\n}) {\n const [open, setOpen] = useState(false)\n const element = useRef<HTMLDivElement>(null)\n useEffect(() => {\n if (!open) return\n const dismiss = (event: PointerEvent) => {\n if (!element.current?.contains(event.target as Node)) setOpen(false)\n }\n const escape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') setOpen(false)\n }\n document.addEventListener('pointerdown', dismiss)\n document.addEventListener('keydown', escape)\n return () => {\n document.removeEventListener('pointerdown', dismiss)\n document.removeEventListener('keydown', escape)\n }\n }, [open])\n return (\n <div className=\"native-docx-ribbon-menu\" ref={element}>\n <button\n type=\"button\"\n className={['native-docx-ribbon-trigger', className].filter(Boolean).join(' ')}\n aria-label={label}\n title={title ?? label}\n aria-expanded={open}\n data-testid={testId}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => setOpen((value) => !value)}\n >\n {icon}\n </button>\n {(open || keepMounted) && (\n <div\n className={['native-docx-ribbon-popover', popoverClassName].filter(Boolean).join(' ')}\n role=\"group\"\n aria-label={label}\n hidden={!open}\n onMouseDown={(event) => {\n if (!(\n event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement\n ))\n event.preventDefault()\n }}\n >\n {typeof children === 'function' ? children(() => setOpen(false)) : children}\n </div>\n )}\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["import React, { useEffect, useRef, useState } from 'react'\n\n/**\n * A ribbon button that opens a panel under the ribbon (Font, More formatting, the style gallery).\n * Pressing the trigger never takes the caret out of the document; the panel closes on Escape or a\n * press outside it. `children` may be a function that receives `close`, for panels that close\n * themselves once the user has picked something.\n */\nexport function RibbonMenu({\n label,\n icon,\n children,\n className,\n testId,\n title,\n keepMounted = false,\n popoverClassName,\n restoreFocus = false,\n}: {\n label: string\n /** Tooltip; defaults to `label`. */\n title?: string\n /** Trigger content: an icon, or a short text label with a `className` that widens it. */\n icon: React.ReactNode\n children: React.ReactNode | ((close: () => void) => React.ReactNode)\n className?: string\n testId?: string\n /** Keep the panel's content mounted (hidden) while closed, so its controls keep their state. */\n keepMounted?: boolean\n popoverClassName?: string\n /** Return keyboard focus to the trigger when Escape closes this menu. */\n restoreFocus?: boolean\n}) {\n const [open, setOpen] = useState(false)\n const element = useRef<HTMLDivElement>(null)\n const trigger = useRef<HTMLButtonElement>(null)\n useEffect(() => {\n if (!open) return\n const dismiss = (event: PointerEvent) => {\n if (!element.current?.contains(event.target as Node)) setOpen(false)\n }\n const escape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n if (restoreFocus && element.current?.contains(document.activeElement))\n trigger.current?.focus()\n setOpen(false)\n }\n }\n document.addEventListener('pointerdown', dismiss)\n document.addEventListener('keydown', escape)\n return () => {\n document.removeEventListener('pointerdown', dismiss)\n document.removeEventListener('keydown', escape)\n }\n }, [open, restoreFocus])\n return (\n <div className=\"native-docx-ribbon-menu\" ref={element}>\n <button\n type=\"button\"\n ref={trigger}\n className={['native-docx-ribbon-trigger', className].filter(Boolean).join(' ')}\n aria-label={label}\n title={title ?? label}\n aria-expanded={open}\n data-testid={testId}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => setOpen((value) => !value)}\n >\n {icon}\n </button>\n {(open || keepMounted) && (\n <div\n className={['native-docx-ribbon-popover', popoverClassName].filter(Boolean).join(' ')}\n role=\"group\"\n aria-label={label}\n hidden={!open}\n onMouseDown={(event) => {\n if (!(\n event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement\n ))\n event.preventDefault()\n }}\n >\n {typeof children === 'function' ? children(() => setOpen(false)) : children}\n </div>\n )}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAwDI,SACE,KADF;AAxDJ,SAAgB,WAAW,QAAQ,gBAAgB;AAQ5C,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA,eAAe;AACjB,GAcG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,UAAU,OAAuB,IAAI;AAC3C,QAAM,UAAU,OAA0B,IAAI;AAC9C,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,UAAM,UAAU,CAAC,UAAwB;AACvC,UAAI,CAAC,QAAQ,SAAS,SAAS,MAAM,MAAc,EAAG,SAAQ,KAAK;AAAA,IACrE;AACA,UAAM,SAAS,CAAC,UAAyB;AACvC,UAAI,MAAM,QAAQ,UAAU;AAC1B,YAAI,gBAAgB,QAAQ,SAAS,SAAS,SAAS,aAAa;AAClE,kBAAQ,SAAS,MAAM;AACzB,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AACA,aAAS,iBAAiB,eAAe,OAAO;AAChD,aAAS,iBAAiB,WAAW,MAAM;AAC3C,WAAO,MAAM;AACX,eAAS,oBAAoB,eAAe,OAAO;AACnD,eAAS,oBAAoB,WAAW,MAAM;AAAA,IAChD;AAAA,EACF,GAAG,CAAC,MAAM,YAAY,CAAC;AACvB,SACE,qBAAC,SAAI,WAAU,2BAA0B,KAAK,SAC5C;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,KAAK;AAAA,QACL,WAAW,CAAC,8BAA8B,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,QAC7E,cAAY;AAAA,QACZ,OAAO,SAAS;AAAA,QAChB,iBAAe;AAAA,QACf,eAAa;AAAA,QACb,aAAa,CAAC,UAAU,MAAM,eAAe;AAAA,QAC7C,SAAS,MAAM,QAAQ,CAAC,UAAU,CAAC,KAAK;AAAA,QAEvC;AAAA;AAAA,IACH;AAAA,KACE,QAAQ,gBACR;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,CAAC,8BAA8B,gBAAgB,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,QACpF,MAAK;AAAA,QACL,cAAY;AAAA,QACZ,QAAQ,CAAC;AAAA,QACT,aAAa,CAAC,UAAU;AACtB,cAAI,EACF,MAAM,kBAAkB,oBAAoB,MAAM,kBAAkB;AAEpE,kBAAM,eAAe;AAAA,QACzB;AAAA,QAEC,iBAAO,aAAa,aAAa,SAAS,MAAM,QAAQ,KAAK,CAAC,IAAI;AAAA;AAAA,IACrE;AAAA,KAEJ;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
* state while the menu is closed).
|
|
8
8
|
*/
|
|
9
9
|
import React from 'react';
|
|
10
|
+
export declare function NamedCommandList({ children }: {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}): React.JSX.Element;
|
|
10
13
|
/**
|
|
11
14
|
* The row of one ribbon tab. `tab` names the tab shown, so the More menu closes and the row is
|
|
12
15
|
* measured afresh when it changes.
|
|
@@ -15,6 +15,10 @@ import { Ellipsis } from "lucide-react";
|
|
|
15
15
|
import { RibbonMenu } from "./RibbonMenu.js";
|
|
16
16
|
import { planOverflow } from "./overflowPlan.js";
|
|
17
17
|
const Overflow = createContext(null);
|
|
18
|
+
const NamedCommands = createContext(false);
|
|
19
|
+
function NamedCommandList({ children }) {
|
|
20
|
+
return /* @__PURE__ */ jsx(NamedCommands.Provider, { value: true, children });
|
|
21
|
+
}
|
|
18
22
|
const MORE_WIDTH = 32;
|
|
19
23
|
const sameSet = (a, b) => a.size === b.size && [...a].every((id) => b.has(id));
|
|
20
24
|
function RibbonOverflow({ tab, children }) {
|
|
@@ -136,13 +140,31 @@ function RibbonItem({
|
|
|
136
140
|
children
|
|
137
141
|
}) {
|
|
138
142
|
const context = useContext(Overflow);
|
|
143
|
+
const named = useContext(NamedCommands);
|
|
139
144
|
const element = useRef(null);
|
|
140
145
|
const register = context?.register;
|
|
141
146
|
useLayoutEffect(() => {
|
|
142
147
|
if (!register || !element.current) return;
|
|
143
148
|
return register(id, { label, priority, element: element.current });
|
|
144
149
|
}, [register, id, label, priority]);
|
|
145
|
-
if (!context)
|
|
150
|
+
if (!context) {
|
|
151
|
+
if (!named) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
152
|
+
return /* @__PURE__ */ jsxs(
|
|
153
|
+
"span",
|
|
154
|
+
{
|
|
155
|
+
className: "native-docx-command-item",
|
|
156
|
+
"data-ribbon-item": id,
|
|
157
|
+
onClick: (event) => {
|
|
158
|
+
if (event.target.classList.contains("native-docx-command-label"))
|
|
159
|
+
event.currentTarget.querySelector("button:not([disabled])")?.click();
|
|
160
|
+
},
|
|
161
|
+
children: [
|
|
162
|
+
/* @__PURE__ */ jsx("span", { className: "native-docx-command-control", children }),
|
|
163
|
+
/* @__PURE__ */ jsx("span", { className: "native-docx-command-label", children: label })
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
}
|
|
146
168
|
const collapsed = context.collapsed.has(id);
|
|
147
169
|
const slot = context.slots[id];
|
|
148
170
|
return /* @__PURE__ */ jsx(
|
|
@@ -157,6 +179,7 @@ function RibbonItem({
|
|
|
157
179
|
);
|
|
158
180
|
}
|
|
159
181
|
export {
|
|
182
|
+
NamedCommandList,
|
|
160
183
|
RibbonItem,
|
|
161
184
|
RibbonOverflow
|
|
162
185
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/docx/RibbonOverflow.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * A ribbon tab's row of controls that never crowds: what does not fit collapses into a trailing\n * \"\u2026\" (More) menu, as Word's ribbon does. Each control is a `RibbonItem` with a label and a\n * priority; the row measures the controls (ResizeObserver) and collapses the lowest priority\n * first, the rightmost first among equals. A collapsed control is the same component, moved by a\n * portal into its row of the More menu, beside its label, so it keeps working (and keeps its\n * state while the menu is closed).\n */\n\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { Ellipsis } from 'lucide-react'\nimport { RibbonMenu } from './RibbonMenu'\nimport { planOverflow } from './overflowPlan'\n\ninterface Registered {\n label: string\n priority: number\n element: HTMLElement\n}\n\ninterface OverflowContext {\n collapsed: ReadonlySet<string>\n slots: Readonly<Record<string, HTMLElement>>\n register: (id: string, item: Registered) => () => void\n}\n\nconst Overflow = createContext<OverflowContext | null>(null)\n\n/** Room for the More trigger: its 28 px button and the row's gap. */\nconst MORE_WIDTH = 32\n\nconst sameSet = (a: ReadonlySet<string>, b: ReadonlySet<string>) =>\n a.size === b.size && [...a].every((id) => b.has(id))\n\n/**\n * The row of one ribbon tab. `tab` names the tab shown, so the More menu closes and the row is\n * measured afresh when it changes.\n */\nexport function RibbonOverflow({ tab, children }: { tab: string; children: React.ReactNode }) {\n const row = useRef<HTMLDivElement>(null)\n const items = useRef(new Map<string, Registered>())\n const widths = useRef(new Map<string, number>())\n const [version, setVersion] = useState(0)\n const [collapsed, setCollapsed] = useState<ReadonlySet<string>>(() => new Set())\n const [slots, setSlots] = useState<Record<string, HTMLElement>>({})\n // In ribbon order, with their labels, for the More menu's rows.\n const [menu, setMenu] = useState<readonly { id: string; label: string }[]>([])\n\n const register = useCallback((id: string, item: Registered) => {\n items.current.set(id, item)\n setVersion((v) => v + 1)\n return () => {\n if (items.current.get(id) === item) items.current.delete(id)\n setVersion((v) => v + 1)\n }\n }, [])\n\n const plan = useCallback(() => {\n const element = row.current\n if (!element) return\n const gap = parseFloat(getComputedStyle(element).columnGap) || 0\n const ordered = Array.from(element.querySelectorAll<HTMLElement>('[data-ribbon-item]'))\n .map((node) => node.dataset.ribbonItem!)\n .filter((id) => items.current.has(id))\n const measured = ordered.map((id) => {\n const { element: node, priority } = items.current.get(id)!\n if (!node.hidden) {\n const width = node.getBoundingClientRect().width\n // A control that draws nothing (an action the host does not offer) takes no room.\n widths.current.set(id, width ? width + gap : 0)\n }\n return { id, priority, width: widths.current.get(id) ?? 0 }\n })\n const next = planOverflow(measured, element.clientWidth, MORE_WIDTH)\n setCollapsed((current) => (sameSet(current, next) ? current : next))\n const entries = ordered\n .filter((id) => next.has(id))\n .map((id) => ({ id, label: items.current.get(id)!.label }))\n setMenu((current) =>\n current.length === entries.length &&\n current.every((entry, i) => entry.id === entries[i].id && entry.label === entries[i].label)\n ? current\n : entries\n )\n }, [])\n\n useLayoutEffect(plan, [plan, version, tab, collapsed])\n\n useLayoutEffect(() => {\n const element = row.current\n if (!element) return\n const observer = new ResizeObserver(() => plan())\n observer.observe(element)\n for (const item of items.current.values()) observer.observe(item.element)\n return () => observer.disconnect()\n }, [plan, version])\n\n const slotRef = useCallback(\n (id: string) => (node: HTMLElement | null) =>\n setSlots((current) => {\n if (node ? current[id] === node : !(id in current)) return current\n const next = { ...current }\n if (node) next[id] = node\n else delete next[id]\n return next\n }),\n []\n )\n\n const context = useMemo(() => ({ collapsed, slots, register }), [collapsed, slots, register])\n const shown = menu.filter((entry) => collapsed.has(entry.id))\n\n return (\n <Overflow.Provider value={context}>\n <div className=\"native-docx-ribbon-row\" ref={row} data-testid=\"docx-ribbon-row\">\n {children}\n {shown.length > 0 && (\n <RibbonMenu\n key={tab}\n label=\"More\"\n title=\"More commands\"\n icon={<Ellipsis size={16} />}\n testId=\"docx-ribbon-more\"\n keepMounted\n popoverClassName=\"native-docx-ribbon-more\"\n >\n {(close) => <MoreRows entries={shown} slotRef={slotRef} close={close} />}\n </RibbonMenu>\n )}\n </div>\n </Overflow.Provider>\n )\n}\n\nfunction MoreRows({\n entries,\n slotRef,\n close,\n}: {\n entries: readonly { id: string; label: string }[]\n slotRef: (id: string) => (node: HTMLElement | null) => void\n close: () => void\n}) {\n // One stable ref callback per id, so React does not detach and reattach the slots each render.\n const refs = useRef(new Map<string, (node: HTMLElement | null) => void>())\n const refFor = (id: string) => {\n let ref = refs.current.get(id)\n if (!ref) refs.current.set(id, (ref = slotRef(id)))\n return ref\n }\n // A DOM listener, not a React one: the controls are portalled in, so React would route their\n // clicks through the ribbon row they belong to, not through this list. Capture, because an\n // engine control may stop its click from bubbling.\n const list = useRef<HTMLDivElement>(null)\n const latest = useRef(close)\n latest.current = close\n useEffect(() => {\n const element = list.current\n if (!element) return\n const onClick = (event: MouseEvent) => {\n const target = event.target as HTMLElement\n const row = target.closest<HTMLElement>('.native-docx-ribbon-more-row')\n if (!row) return\n const control = row.querySelector<HTMLElement>('.native-docx-ribbon-more-control')!\n if (!control.contains(target)) {\n // The label is part of the row: it presses the control.\n control.querySelector<HTMLElement>('button:not([disabled])')?.click()\n return\n }\n // A plain command closes the menu, as Word's does; a control that opens its own panel (a\n // gallery, a picker) keeps it open.\n const button = target.closest('button')\n if (\n button &&\n !button.disabled &&\n !control.querySelector('.native-docx-ribbon-popover')?.contains(button) &&\n !button.hasAttribute('aria-expanded') &&\n !button.hasAttribute('aria-haspopup')\n )\n latest.current()\n }\n element.addEventListener('click', onClick, true)\n return () => element.removeEventListener('click', onClick, true)\n }, [])\n return (\n <div className=\"native-docx-ribbon-more-list\" ref={list}>\n {entries.map((entry) => (\n <div className=\"native-docx-ribbon-more-row\" key={entry.id} data-ribbon-more={entry.id}>\n <span className=\"native-docx-ribbon-more-control\" ref={refFor(entry.id)} />\n <span className=\"native-docx-ribbon-more-label\">{entry.label}</span>\n </div>\n ))}\n </div>\n )\n}\n\n/**\n * One control of a ribbon row. `label` names it in the More menu; `priority` (default 0) decides\n * what collapses first. Outside a `RibbonOverflow` it renders its children as they are.\n */\nexport function RibbonItem({\n id,\n label,\n priority = 0,\n children,\n}: {\n id: string\n label: string\n priority?: number\n children: React.ReactNode\n}) {\n const context = useContext(Overflow)\n const element = useRef<HTMLSpanElement>(null)\n const register = context?.register\n useLayoutEffect(() => {\n if (!register || !element.current) return\n return register(id, { label, priority, element: element.current })\n }, [register, id, label, priority])\n if (!context) return <>{children}</>\n const collapsed = context.collapsed.has(id)\n const slot = context.slots[id]\n return (\n <span\n ref={element}\n className=\"native-docx-ribbon-item\"\n data-ribbon-item={id}\n hidden={collapsed || undefined}\n >\n {collapsed ? (slot ? createPortal(children, slot) : null) : children}\n </span>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["/**\n * A ribbon tab's row of controls that never crowds: what does not fit collapses into a trailing\n * \"\u2026\" (More) menu, as Word's ribbon does. Each control is a `RibbonItem` with a label and a\n * priority; the row measures the controls (ResizeObserver) and collapses the lowest priority\n * first, the rightmost first among equals. A collapsed control is the same component, moved by a\n * portal into its row of the More menu, beside its label, so it keeps working (and keeps its\n * state while the menu is closed).\n */\n\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { Ellipsis } from 'lucide-react'\nimport { RibbonMenu } from './RibbonMenu'\nimport { planOverflow } from './overflowPlan'\n\ninterface Registered {\n label: string\n priority: number\n element: HTMLElement\n}\n\ninterface OverflowContext {\n collapsed: ReadonlySet<string>\n slots: Readonly<Record<string, HTMLElement>>\n register: (id: string, item: Registered) => () => void\n}\n\nconst Overflow = createContext<OverflowContext | null>(null)\n\n/** Render the same command controls with their visible names in the editor menu. */\nconst NamedCommands = createContext(false)\nexport function NamedCommandList({ children }: { children: React.ReactNode }) {\n return <NamedCommands.Provider value>{children}</NamedCommands.Provider>\n}\n\n/** Room for the More trigger: its 28 px button and the row's gap. */\nconst MORE_WIDTH = 32\n\nconst sameSet = (a: ReadonlySet<string>, b: ReadonlySet<string>) =>\n a.size === b.size && [...a].every((id) => b.has(id))\n\n/**\n * The row of one ribbon tab. `tab` names the tab shown, so the More menu closes and the row is\n * measured afresh when it changes.\n */\nexport function RibbonOverflow({ tab, children }: { tab: string; children: React.ReactNode }) {\n const row = useRef<HTMLDivElement>(null)\n const items = useRef(new Map<string, Registered>())\n const widths = useRef(new Map<string, number>())\n const [version, setVersion] = useState(0)\n const [collapsed, setCollapsed] = useState<ReadonlySet<string>>(() => new Set())\n const [slots, setSlots] = useState<Record<string, HTMLElement>>({})\n // In ribbon order, with their labels, for the More menu's rows.\n const [menu, setMenu] = useState<readonly { id: string; label: string }[]>([])\n\n const register = useCallback((id: string, item: Registered) => {\n items.current.set(id, item)\n setVersion((v) => v + 1)\n return () => {\n if (items.current.get(id) === item) items.current.delete(id)\n setVersion((v) => v + 1)\n }\n }, [])\n\n const plan = useCallback(() => {\n const element = row.current\n if (!element) return\n const gap = parseFloat(getComputedStyle(element).columnGap) || 0\n const ordered = Array.from(element.querySelectorAll<HTMLElement>('[data-ribbon-item]'))\n .map((node) => node.dataset.ribbonItem!)\n .filter((id) => items.current.has(id))\n const measured = ordered.map((id) => {\n const { element: node, priority } = items.current.get(id)!\n if (!node.hidden) {\n const width = node.getBoundingClientRect().width\n // A control that draws nothing (an action the host does not offer) takes no room.\n widths.current.set(id, width ? width + gap : 0)\n }\n return { id, priority, width: widths.current.get(id) ?? 0 }\n })\n const next = planOverflow(measured, element.clientWidth, MORE_WIDTH)\n setCollapsed((current) => (sameSet(current, next) ? current : next))\n const entries = ordered\n .filter((id) => next.has(id))\n .map((id) => ({ id, label: items.current.get(id)!.label }))\n setMenu((current) =>\n current.length === entries.length &&\n current.every((entry, i) => entry.id === entries[i].id && entry.label === entries[i].label)\n ? current\n : entries\n )\n }, [])\n\n useLayoutEffect(plan, [plan, version, tab, collapsed])\n\n useLayoutEffect(() => {\n const element = row.current\n if (!element) return\n const observer = new ResizeObserver(() => plan())\n observer.observe(element)\n for (const item of items.current.values()) observer.observe(item.element)\n return () => observer.disconnect()\n }, [plan, version])\n\n const slotRef = useCallback(\n (id: string) => (node: HTMLElement | null) =>\n setSlots((current) => {\n if (node ? current[id] === node : !(id in current)) return current\n const next = { ...current }\n if (node) next[id] = node\n else delete next[id]\n return next\n }),\n []\n )\n\n const context = useMemo(() => ({ collapsed, slots, register }), [collapsed, slots, register])\n const shown = menu.filter((entry) => collapsed.has(entry.id))\n\n return (\n <Overflow.Provider value={context}>\n <div className=\"native-docx-ribbon-row\" ref={row} data-testid=\"docx-ribbon-row\">\n {children}\n {shown.length > 0 && (\n <RibbonMenu\n key={tab}\n label=\"More\"\n title=\"More commands\"\n icon={<Ellipsis size={16} />}\n testId=\"docx-ribbon-more\"\n keepMounted\n popoverClassName=\"native-docx-ribbon-more\"\n >\n {(close) => <MoreRows entries={shown} slotRef={slotRef} close={close} />}\n </RibbonMenu>\n )}\n </div>\n </Overflow.Provider>\n )\n}\n\nfunction MoreRows({\n entries,\n slotRef,\n close,\n}: {\n entries: readonly { id: string; label: string }[]\n slotRef: (id: string) => (node: HTMLElement | null) => void\n close: () => void\n}) {\n // One stable ref callback per id, so React does not detach and reattach the slots each render.\n const refs = useRef(new Map<string, (node: HTMLElement | null) => void>())\n const refFor = (id: string) => {\n let ref = refs.current.get(id)\n if (!ref) refs.current.set(id, (ref = slotRef(id)))\n return ref\n }\n // A DOM listener, not a React one: the controls are portalled in, so React would route their\n // clicks through the ribbon row they belong to, not through this list. Capture, because an\n // engine control may stop its click from bubbling.\n const list = useRef<HTMLDivElement>(null)\n const latest = useRef(close)\n latest.current = close\n useEffect(() => {\n const element = list.current\n if (!element) return\n const onClick = (event: MouseEvent) => {\n const target = event.target as HTMLElement\n const row = target.closest<HTMLElement>('.native-docx-ribbon-more-row')\n if (!row) return\n const control = row.querySelector<HTMLElement>('.native-docx-ribbon-more-control')!\n if (!control.contains(target)) {\n // The label is part of the row: it presses the control.\n control.querySelector<HTMLElement>('button:not([disabled])')?.click()\n return\n }\n // A plain command closes the menu, as Word's does; a control that opens its own panel (a\n // gallery, a picker) keeps it open.\n const button = target.closest('button')\n if (\n button &&\n !button.disabled &&\n !control.querySelector('.native-docx-ribbon-popover')?.contains(button) &&\n !button.hasAttribute('aria-expanded') &&\n !button.hasAttribute('aria-haspopup')\n )\n latest.current()\n }\n element.addEventListener('click', onClick, true)\n return () => element.removeEventListener('click', onClick, true)\n }, [])\n return (\n <div className=\"native-docx-ribbon-more-list\" ref={list}>\n {entries.map((entry) => (\n <div className=\"native-docx-ribbon-more-row\" key={entry.id} data-ribbon-more={entry.id}>\n <span className=\"native-docx-ribbon-more-control\" ref={refFor(entry.id)} />\n <span className=\"native-docx-ribbon-more-label\">{entry.label}</span>\n </div>\n ))}\n </div>\n )\n}\n\n/**\n * One control of a ribbon row. `label` names it in the More menu; `priority` (default 0) decides\n * what collapses first. Outside a `RibbonOverflow` it renders its children as they are.\n */\nexport function RibbonItem({\n id,\n label,\n priority = 0,\n children,\n}: {\n id: string\n label: string\n priority?: number\n children: React.ReactNode\n}) {\n const context = useContext(Overflow)\n const named = useContext(NamedCommands)\n const element = useRef<HTMLSpanElement>(null)\n const register = context?.register\n useLayoutEffect(() => {\n if (!register || !element.current) return\n return register(id, { label, priority, element: element.current })\n }, [register, id, label, priority])\n if (!context) {\n if (!named) return <>{children}</>\n return (\n <span\n className=\"native-docx-command-item\"\n data-ribbon-item={id}\n onClick={(event) => {\n if ((event.target as HTMLElement).classList.contains('native-docx-command-label'))\n event.currentTarget.querySelector<HTMLButtonElement>('button:not([disabled])')?.click()\n }}\n >\n <span className=\"native-docx-command-control\">{children}</span>\n <span className=\"native-docx-command-label\">{label}</span>\n </span>\n )\n }\n const collapsed = context.collapsed.has(id)\n const slot = context.slots[id]\n return (\n <span\n ref={element}\n className=\"native-docx-ribbon-item\"\n data-ribbon-item={id}\n hidden={collapsed || undefined}\n >\n {collapsed ? (slot ? createPortal(children, slot) : null) : children}\n </span>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/docx/index.cjs
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var chunk2BOTSU23_cjs = require('../chunk-2BOTSU23.cjs');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
5
|
+
var chunkYGBHY67W_cjs = require('../chunk-YGBHY67W.cjs');
|
|
6
|
+
var chunkCOD5ENHK_cjs = require('../chunk-COD5ENHK.cjs');
|
|
7
|
+
var chunk2CSLFAGF_cjs = require('../chunk-2CSLFAGF.cjs');
|
|
8
8
|
var chunkGA5ZO4YA_cjs = require('../chunk-GA5ZO4YA.cjs');
|
|
9
9
|
var chunkVG5XNE4H_cjs = require('../chunk-VG5XNE4H.cjs');
|
|
10
10
|
require('../chunk-DDWLMYRO.cjs');
|
|
@@ -27,143 +27,143 @@ Object.defineProperty(exports, "loadDocxFonts", {
|
|
|
27
27
|
});
|
|
28
28
|
Object.defineProperty(exports, "StreamedWordArtifact", {
|
|
29
29
|
enumerable: true,
|
|
30
|
-
get: function () { return
|
|
30
|
+
get: function () { return chunkYGBHY67W_cjs.StreamedWordArtifact; }
|
|
31
31
|
});
|
|
32
32
|
Object.defineProperty(exports, "NativeDocxComparison", {
|
|
33
33
|
enumerable: true,
|
|
34
|
-
get: function () { return
|
|
34
|
+
get: function () { return chunkCOD5ENHK_cjs.NativeDocxComparison; }
|
|
35
35
|
});
|
|
36
36
|
Object.defineProperty(exports, "CrossReferencesProvider", {
|
|
37
37
|
enumerable: true,
|
|
38
|
-
get: function () { return
|
|
38
|
+
get: function () { return chunk2CSLFAGF_cjs.CrossReferencesProvider; }
|
|
39
39
|
});
|
|
40
40
|
Object.defineProperty(exports, "DEFAULT_CROSS_REFERENCES_LABELS", {
|
|
41
41
|
enumerable: true,
|
|
42
|
-
get: function () { return
|
|
42
|
+
get: function () { return chunk2CSLFAGF_cjs.DEFAULT_CROSS_REFERENCES_LABELS; }
|
|
43
43
|
});
|
|
44
44
|
Object.defineProperty(exports, "DEFAULT_DEFINED_TERMS_LABELS", {
|
|
45
45
|
enumerable: true,
|
|
46
|
-
get: function () { return
|
|
46
|
+
get: function () { return chunk2CSLFAGF_cjs.DEFAULT_DEFINED_TERMS_LABELS; }
|
|
47
47
|
});
|
|
48
48
|
Object.defineProperty(exports, "DEFINED_TERM_TRIGGER", {
|
|
49
49
|
enumerable: true,
|
|
50
|
-
get: function () { return
|
|
50
|
+
get: function () { return chunk2CSLFAGF_cjs.DEFINED_TERM_TRIGGER; }
|
|
51
51
|
});
|
|
52
52
|
Object.defineProperty(exports, "DefinedTermsProvider", {
|
|
53
53
|
enumerable: true,
|
|
54
|
-
get: function () { return
|
|
54
|
+
get: function () { return chunk2CSLFAGF_cjs.DefinedTermsProvider; }
|
|
55
55
|
});
|
|
56
56
|
Object.defineProperty(exports, "DocxCommentActivity", {
|
|
57
57
|
enumerable: true,
|
|
58
|
-
get: function () { return
|
|
58
|
+
get: function () { return chunk2CSLFAGF_cjs.DocxCommentActivity; }
|
|
59
59
|
});
|
|
60
60
|
Object.defineProperty(exports, "DocxEditorReview", {
|
|
61
61
|
enumerable: true,
|
|
62
|
-
get: function () { return
|
|
62
|
+
get: function () { return chunk2CSLFAGF_cjs.DocxEditorReview; }
|
|
63
63
|
});
|
|
64
64
|
Object.defineProperty(exports, "DocxMentions", {
|
|
65
65
|
enumerable: true,
|
|
66
|
-
get: function () { return
|
|
66
|
+
get: function () { return chunk2CSLFAGF_cjs.DocxMentions; }
|
|
67
67
|
});
|
|
68
68
|
Object.defineProperty(exports, "DocxParticipants", {
|
|
69
69
|
enumerable: true,
|
|
70
|
-
get: function () { return
|
|
70
|
+
get: function () { return chunk2CSLFAGF_cjs.DocxParticipants; }
|
|
71
71
|
});
|
|
72
72
|
Object.defineProperty(exports, "DocxRibbon", {
|
|
73
73
|
enumerable: true,
|
|
74
|
-
get: function () { return
|
|
74
|
+
get: function () { return chunk2CSLFAGF_cjs.DocxRibbon; }
|
|
75
75
|
});
|
|
76
76
|
Object.defineProperty(exports, "GenerateImageButton", {
|
|
77
77
|
enumerable: true,
|
|
78
|
-
get: function () { return
|
|
78
|
+
get: function () { return chunk2CSLFAGF_cjs.GenerateImageButton; }
|
|
79
79
|
});
|
|
80
80
|
Object.defineProperty(exports, "LinkHoverCard", {
|
|
81
81
|
enumerable: true,
|
|
82
|
-
get: function () { return
|
|
82
|
+
get: function () { return chunk2CSLFAGF_cjs.LinkHoverCard; }
|
|
83
83
|
});
|
|
84
84
|
Object.defineProperty(exports, "NativeDocxEditor", {
|
|
85
85
|
enumerable: true,
|
|
86
|
-
get: function () { return
|
|
86
|
+
get: function () { return chunk2CSLFAGF_cjs.NativeDocxEditor; }
|
|
87
87
|
});
|
|
88
88
|
Object.defineProperty(exports, "SignatureFieldMenu", {
|
|
89
89
|
enumerable: true,
|
|
90
|
-
get: function () { return
|
|
90
|
+
get: function () { return chunk2CSLFAGF_cjs.SignatureFieldMenu; }
|
|
91
91
|
});
|
|
92
92
|
Object.defineProperty(exports, "SignatureFieldsProvider", {
|
|
93
93
|
enumerable: true,
|
|
94
|
-
get: function () { return
|
|
94
|
+
get: function () { return chunk2CSLFAGF_cjs.SignatureFieldsProvider; }
|
|
95
95
|
});
|
|
96
96
|
Object.defineProperty(exports, "editorPort", {
|
|
97
97
|
enumerable: true,
|
|
98
|
-
get: function () { return
|
|
98
|
+
get: function () { return chunk2CSLFAGF_cjs.editorPort; }
|
|
99
99
|
});
|
|
100
100
|
Object.defineProperty(exports, "findDefinitionsSection", {
|
|
101
101
|
enumerable: true,
|
|
102
|
-
get: function () { return
|
|
102
|
+
get: function () { return chunk2CSLFAGF_cjs.findDefinitionsSection; }
|
|
103
103
|
});
|
|
104
104
|
Object.defineProperty(exports, "insertCrossReference", {
|
|
105
105
|
enumerable: true,
|
|
106
|
-
get: function () { return
|
|
106
|
+
get: function () { return chunk2CSLFAGF_cjs.insertCrossReference; }
|
|
107
107
|
});
|
|
108
108
|
Object.defineProperty(exports, "insertDefinedTerm", {
|
|
109
109
|
enumerable: true,
|
|
110
|
-
get: function () { return
|
|
110
|
+
get: function () { return chunk2CSLFAGF_cjs.insertDefinedTerm; }
|
|
111
111
|
});
|
|
112
112
|
Object.defineProperty(exports, "insertDocumentReference", {
|
|
113
113
|
enumerable: true,
|
|
114
|
-
get: function () { return
|
|
114
|
+
get: function () { return chunk2CSLFAGF_cjs.insertDocumentReference; }
|
|
115
115
|
});
|
|
116
116
|
Object.defineProperty(exports, "insertSignatureField", {
|
|
117
117
|
enumerable: true,
|
|
118
|
-
get: function () { return
|
|
118
|
+
get: function () { return chunk2CSLFAGF_cjs.insertSignatureField; }
|
|
119
119
|
});
|
|
120
120
|
Object.defineProperty(exports, "listTargets", {
|
|
121
121
|
enumerable: true,
|
|
122
|
-
get: function () { return
|
|
122
|
+
get: function () { return chunk2CSLFAGF_cjs.listTargets; }
|
|
123
123
|
});
|
|
124
124
|
Object.defineProperty(exports, "normalizeDocxExport", {
|
|
125
125
|
enumerable: true,
|
|
126
|
-
get: function () { return
|
|
126
|
+
get: function () { return chunk2CSLFAGF_cjs.normalizeDocxExport; }
|
|
127
127
|
});
|
|
128
128
|
Object.defineProperty(exports, "paragraphNumber", {
|
|
129
129
|
enumerable: true,
|
|
130
|
-
get: function () { return
|
|
130
|
+
get: function () { return chunk2CSLFAGF_cjs.paragraphNumber; }
|
|
131
131
|
});
|
|
132
132
|
Object.defineProperty(exports, "referenceText", {
|
|
133
133
|
enumerable: true,
|
|
134
|
-
get: function () { return
|
|
134
|
+
get: function () { return chunk2CSLFAGF_cjs.referenceText; }
|
|
135
135
|
});
|
|
136
136
|
Object.defineProperty(exports, "referencesPort", {
|
|
137
137
|
enumerable: true,
|
|
138
|
-
get: function () { return
|
|
138
|
+
get: function () { return chunk2CSLFAGF_cjs.referencesPort; }
|
|
139
139
|
});
|
|
140
140
|
Object.defineProperty(exports, "reviewModule", {
|
|
141
141
|
enumerable: true,
|
|
142
|
-
get: function () { return
|
|
142
|
+
get: function () { return chunk2CSLFAGF_cjs.reviewModule; }
|
|
143
143
|
});
|
|
144
144
|
Object.defineProperty(exports, "shortTitle", {
|
|
145
145
|
enumerable: true,
|
|
146
|
-
get: function () { return
|
|
146
|
+
get: function () { return chunk2CSLFAGF_cjs.shortTitle; }
|
|
147
147
|
});
|
|
148
148
|
Object.defineProperty(exports, "useCrossReferences", {
|
|
149
149
|
enumerable: true,
|
|
150
|
-
get: function () { return
|
|
150
|
+
get: function () { return chunk2CSLFAGF_cjs.useCrossReferences; }
|
|
151
151
|
});
|
|
152
152
|
Object.defineProperty(exports, "useDefinedTerms", {
|
|
153
153
|
enumerable: true,
|
|
154
|
-
get: function () { return
|
|
154
|
+
get: function () { return chunk2CSLFAGF_cjs.useDefinedTerms; }
|
|
155
155
|
});
|
|
156
156
|
Object.defineProperty(exports, "useReview", {
|
|
157
157
|
enumerable: true,
|
|
158
|
-
get: function () { return
|
|
158
|
+
get: function () { return chunk2CSLFAGF_cjs.useReview; }
|
|
159
159
|
});
|
|
160
160
|
Object.defineProperty(exports, "useReviewItem", {
|
|
161
161
|
enumerable: true,
|
|
162
|
-
get: function () { return
|
|
162
|
+
get: function () { return chunk2CSLFAGF_cjs.useReviewItem; }
|
|
163
163
|
});
|
|
164
164
|
Object.defineProperty(exports, "withDirectEditing", {
|
|
165
165
|
enumerable: true,
|
|
166
|
-
get: function () { return
|
|
166
|
+
get: function () { return chunk2CSLFAGF_cjs.withDirectEditing; }
|
|
167
167
|
});
|
|
168
168
|
Object.defineProperty(exports, "DocxAuthorContext", {
|
|
169
169
|
enumerable: true,
|
|
@@ -45,5 +45,7 @@ export declare function SignatureFieldContextItem(): React.JSX.Element | null;
|
|
|
45
45
|
type Editor = NonNullable<ReturnType<typeof useDocxEditor>>;
|
|
46
46
|
/** Insert the field at the caret, directly (a payload cannot be a tracked change). */
|
|
47
47
|
export declare function insertSignatureField(editor: Editor, spec: SignatureFieldSpec): string | null;
|
|
48
|
-
export declare function SignatureFieldMenu(
|
|
48
|
+
export declare function SignatureFieldMenu({ onInserted }?: {
|
|
49
|
+
onInserted?: () => void;
|
|
50
|
+
}): React.JSX.Element | null;
|
|
49
51
|
export {};
|
|
@@ -27,13 +27,21 @@ function SignatureFieldsProvider({
|
|
|
27
27
|
mySignature,
|
|
28
28
|
children
|
|
29
29
|
}) {
|
|
30
|
+
const [pending, setPending] = useState(null);
|
|
30
31
|
return /* @__PURE__ */ jsxs(
|
|
31
32
|
SignatureFieldsContext.Provider,
|
|
32
33
|
{
|
|
33
|
-
value: signers || mySignature ? {
|
|
34
|
+
value: signers || mySignature ? {
|
|
35
|
+
fields: !!signers,
|
|
36
|
+
signers: signers ?? [],
|
|
37
|
+
editable,
|
|
38
|
+
notify,
|
|
39
|
+
mySignature,
|
|
40
|
+
openAdopt: setPending
|
|
41
|
+
} : null,
|
|
34
42
|
children: [
|
|
35
43
|
children,
|
|
36
|
-
mySignature && /* @__PURE__ */ jsx(MySignatureDialog, {})
|
|
44
|
+
mySignature && /* @__PURE__ */ jsx(MySignatureDialog, { pending, setPending })
|
|
37
45
|
]
|
|
38
46
|
}
|
|
39
47
|
);
|
|
@@ -60,12 +68,12 @@ async function insertSavedMark(editor, saved, mark) {
|
|
|
60
68
|
});
|
|
61
69
|
if (!result.ok) throw new Error(result.reason || "The picture could not be inserted here.");
|
|
62
70
|
}
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
function MySignatureDialog({
|
|
72
|
+
pending,
|
|
73
|
+
setPending
|
|
74
|
+
}) {
|
|
65
75
|
const context = useContext(SignatureFieldsContext);
|
|
66
76
|
const editor = useDocxEditor();
|
|
67
|
-
const [pending, setPending] = useState(null);
|
|
68
|
-
openAdopt = setPending;
|
|
69
77
|
const mine = context?.mySignature;
|
|
70
78
|
if (!mine) return null;
|
|
71
79
|
return /* @__PURE__ */ jsx(
|
|
@@ -99,7 +107,7 @@ function useInsertMySignature() {
|
|
|
99
107
|
return async (mark) => {
|
|
100
108
|
try {
|
|
101
109
|
const saved = await mine.load();
|
|
102
|
-
if (!saved) return openAdopt
|
|
110
|
+
if (!saved) return context?.openAdopt(mark);
|
|
103
111
|
await insertSavedMark(editor, saved, mark);
|
|
104
112
|
} catch (failure) {
|
|
105
113
|
context?.notify?.(
|
|
@@ -223,7 +231,7 @@ function insertSignatureField(editor, spec) {
|
|
|
223
231
|
}
|
|
224
232
|
return tag;
|
|
225
233
|
}
|
|
226
|
-
function SignatureFieldMenu() {
|
|
234
|
+
function SignatureFieldMenu({ onInserted } = {}) {
|
|
227
235
|
const context = useContext(SignatureFieldsContext);
|
|
228
236
|
const editor = useDocxEditor();
|
|
229
237
|
const [kind, setKind] = useState("signature");
|
|
@@ -247,6 +255,7 @@ function SignatureFieldMenu() {
|
|
|
247
255
|
required
|
|
248
256
|
});
|
|
249
257
|
close();
|
|
258
|
+
onInserted?.();
|
|
250
259
|
setEmail("");
|
|
251
260
|
setName("");
|
|
252
261
|
} catch (failure) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/docx/signatures/SignatureFields.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * Insert \u203A Signature field: a field where a signature request will ask someone to sign, initial,\n * date or print their name, placed at the caret. The field is a locked chip (\"Signature \u2014 Priya\n * Shah\") whose hidden payload names the signer by email; when the version is saved, its PDF\n * carries an invisible anchor there, and Request signatures places the field exactly on it, for\n * that signer. A field with no signer is assigned when the request is made. See\n * `@arbidocs/coedit/commands` (`signatureFieldWrite`).\n *\n * Insert \u203A My signature puts one's own saved signature or initials (Account settings \u203A Your\n * signature, sealed with one's own key) at the cursor as an inline picture, through the editor's\n * picture insert (a tracked insertion while suggesting). Nothing saved yet: the adopt dialog opens\n * first. That is an informal signature; verified signing is Request signatures.\n */\n\nimport React, { createContext, useContext, useState } from 'react'\nimport { Signature, PenLine, Trash2 } from 'lucide-react'\nimport { DocxEditor, useContextMenuTarget, useDocxEditor } from '@docx-editor.dev/react'\nimport { executeImageCommand } from '@docx-editor.dev/core/editor'\nimport {\n INFORMAL_SIGNATURE_NOTE,\n pngBytes,\n pngSize,\n type SavedSignature,\n} from '@arbidocs/react/document-tools'\nimport { AdoptSignatureDialog } from '../../document-tools/AdoptSignatureDialog'\nimport {\n SIGNATURE_FIELD_KINDS,\n SIGNATURE_FIELD_LABELS,\n isSignerEmail,\n parseSignatureFieldTag,\n signatureFieldWrite,\n type SignatureFieldKind,\n type SignatureFieldSpec,\n} from '@arbidocs/coedit/commands'\nimport { RibbonMenu } from '../RibbonMenu'\nimport { withDirectEditing } from '../definitions/port'\n\n/** Someone who may be asked to sign: a workspace member, offered first in the signer picker. */\nexport interface DocxSigner {\n email: string\n name: string\n}\n\n/** One's own saved signature (sealed with one's own key), for Insert \u203A My signature. */\nexport interface DocxSavedSignature {\n load: () => Promise<SavedSignature | null>\n save: (signature: SavedSignature) => Promise<void>\n /** The name the adopt dialog starts from when nothing is saved yet. */\n defaultName: string\n}\n\ninterface SignatureFieldsValue {\n /** Signature fields are offered (a workspace document). */\n fields: boolean\n signers: readonly DocxSigner[]\n editable: boolean\n notify?: (message: string, kind: 'success' | 'error') => void\n mySignature?: DocxSavedSignature\n}\n\nconst SignatureFieldsContext = createContext<SignatureFieldsValue | null>(null)\n\nexport function SignatureFieldsProvider({\n signers,\n editable,\n notify,\n mySignature,\n children,\n}: {\n /** Absent: the Insert tab offers no signature field (not a workspace document). */\n signers?: readonly DocxSigner[]\n editable: boolean\n notify?: (message: string, kind: 'success' | 'error') => void\n /** Present: Insert offers My signature / My initials. */\n mySignature?: DocxSavedSignature\n children: React.ReactNode\n}) {\n return (\n <SignatureFieldsContext.Provider\n value={\n signers || mySignature\n ? { fields: !!signers, signers: signers ?? [], editable, notify, mySignature }\n : null\n }\n >\n {children}\n {mySignature && <MySignatureDialog />}\n </SignatureFieldsContext.Provider>\n )\n}\n\ntype Mark = 'signature' | 'initials'\n\n/** Insert one's saved signature (or initials) at the caret as an inline picture. */\nasync function insertSavedMark(editor: Editor, saved: SavedSignature, mark: Mark) {\n const png = mark === 'signature' ? saved.signature_png : saved.initials_png\n const { width, height } = pngSize(png)\n // A signature about a line and a half high, initials a little smaller; never wider than 200 pt.\n const heightPoints = mark === 'signature' ? 36 : 24\n let widthPoints = (width / Math.max(1, height)) * heightPoints\n let h = heightPoints\n if (widthPoints > 200) {\n h = (heightPoints * 200) / widthPoints\n widthPoints = 200\n }\n editor.focus()\n const result = await executeImageCommand(editor, {\n type: 'insertImage',\n data: pngBytes(png),\n mime: 'image/png',\n widthPoints,\n heightPoints: h,\n description: mark === 'signature' ? `Signature of ${saved.name}` : `Initials of ${saved.name}`,\n title: mark === 'signature' ? 'Signature' : 'Initials',\n })\n if (!result.ok) throw new Error(result.reason || 'The picture could not be inserted here.')\n}\n\n/** Asks for a signature when nothing is saved yet (opened by `useInsertMySignature`). */\nlet openAdopt: ((mark: Mark) => void) | null = null\n\nfunction MySignatureDialog() {\n const context = useContext(SignatureFieldsContext)\n const editor = useDocxEditor()\n const [pending, setPending] = useState<Mark | null>(null)\n openAdopt = setPending\n const mine = context?.mySignature\n if (!mine) return null\n return (\n <AdoptSignatureDialog\n open={!!pending}\n onOpenChange={(open) => !open && setPending(null)}\n mode=\"save\"\n defaultName={mine.defaultName}\n onSave={mine.save}\n onAdopt={async () => {\n const mark = pending\n setPending(null)\n const saved = await mine.load()\n if (editor && saved && mark) {\n try {\n await insertSavedMark(editor, saved, mark)\n } catch (failure) {\n context?.notify?.(failure instanceof Error ? failure.message : String(failure), 'error')\n }\n }\n }}\n />\n )\n}\n\n/** Insert one's saved signature or initials; nothing saved: the adopt dialog first. */\nfunction useInsertMySignature() {\n const context = useContext(SignatureFieldsContext)\n const editor = useDocxEditor()\n const mine = context?.mySignature\n if (!mine || !editor) return null\n return async (mark: Mark) => {\n try {\n const saved = await mine.load()\n if (!saved) return openAdopt?.(mark)\n await insertSavedMark(editor, saved, mark)\n } catch (failure) {\n context?.notify?.(\n failure instanceof Error ? failure.message : 'The signature could not be inserted.',\n 'error'\n )\n }\n }\n}\n\n/** Insert tab: My signature (insert my signature / initials). */\nexport function MySignatureMenu() {\n const insert = useInsertMySignature()\n const context = useContext(SignatureFieldsContext)\n if (!insert) return null\n return (\n <RibbonMenu label=\"My signature\" icon={<Signature size={16} />} testId=\"docx-my-signature\">\n {(close) => (\n <div className=\"native-docx-signature-field\" data-testid=\"docx-my-signature-panel\">\n <button\n type=\"button\"\n disabled={!context?.editable}\n onClick={() => {\n close()\n void insert('signature')\n }}\n data-testid=\"docx-insert-my-signature\"\n >\n Insert my signature\n </button>\n <button\n type=\"button\"\n disabled={!context?.editable}\n onClick={() => {\n close()\n void insert('initials')\n }}\n data-testid=\"docx-insert-my-initials\"\n >\n Insert my initials\n </button>\n <p>{INFORMAL_SIGNATURE_NOTE}</p>\n </div>\n )}\n </RibbonMenu>\n )\n}\n\n/** Right-click menu rows: Insert my signature / Insert my initials. */\nexport function MySignatureContextItems() {\n const insert = useInsertMySignature()\n if (!insert) return null\n return (\n <>\n <DocxEditor.ContextMenu.Separator />\n <DocxEditor.ContextMenu.Item\n label=\"Insert my signature\"\n icon={<Signature size={14} />}\n onSelect={() => void insert('signature')}\n />\n <DocxEditor.ContextMenu.Item\n label=\"Insert my initials\"\n icon={<Signature size={14} />}\n onSelect={() => void insert('initials')}\n />\n </>\n )\n}\n\n/** Remove the unsigned placeholder and its signer payload, not a completed signature. */\nexport function SignatureFieldContextItem() {\n const context = useContext(SignatureFieldsContext)\n const editor = useDocxEditor()\n const target = useContextMenuTarget()\n const surface = editor?.surface\n const head = surface?.state().selection?.head\n // Right-click does not move the caret; only offer removal over its rendered text run.\n const run = target?.closest<HTMLElement>('[data-paragraph-id][data-start][data-end]')\n const start = Number(run?.dataset.start)\n const end = Number(run?.dataset.end)\n const onSelectedRun =\n run &&\n head &&\n run.dataset.paragraphId === head.paragraphId &&\n head.offset >= start &&\n head.offset <= end\n const control = onSelectedRun && surface?.contentControls.atCaret()\n if (!context?.fields || !control || !parseSignatureFieldTag(control.tag)) return null\n\n return (\n <>\n <DocxEditor.ContextMenu.Separator />\n <DocxEditor.ContextMenu.Item\n label=\"Remove selected signature field\"\n icon={<Trash2 size={14} />}\n disabled={\n !context.editable ||\n control.effectiveLock === 'sdtLocked' ||\n control.effectiveLock === 'sdtContentLocked'\n }\n onSelect={() => {\n try {\n if (!editor || !surface) return\n const result = withDirectEditing(editor, () =>\n surface.session.removeCustomNode(control.id)\n )\n if (!result.ok) throw new Error('The signature field could not be removed.')\n } catch (failure) {\n context.notify?.(failure instanceof Error ? failure.message : String(failure), 'error')\n }\n }}\n />\n </>\n )\n}\n\nconst OTHER = '__other__'\nconst NONE = ''\n\ntype Editor = NonNullable<ReturnType<typeof useDocxEditor>>\n\n/** Insert the field at the caret, directly (a payload cannot be a tracked change). */\nexport function insertSignatureField(editor: Editor, spec: SignatureFieldSpec): string | null {\n const surface = editor.surface\n const selection = surface?.state().selection\n if (!surface || !selection) throw new Error('Place the cursor where the field goes.')\n const { head } = selection\n const { tag, write } = signatureFieldWrite(spec, head)\n const result = withDirectEditing(editor, () => surface.session.insertCustomNode(write))\n if (!result.ok) {\n throw new Error(\n result.reason === 'locked'\n ? 'A field cannot go inside a locked part of the document.'\n : 'The field could not be inserted here.'\n )\n }\n // Go on typing after the field, not before it.\n const after = { paragraphId: head.paragraphId, offset: head.offset + write.text.length }\n try {\n surface.setSelection({ anchor: after, head: after })\n } catch {\n /* the paragraph was renumbered: the caret stays where the engine put it */\n }\n return tag\n}\n\nexport function SignatureFieldMenu() {\n const context = useContext(SignatureFieldsContext)\n const editor = useDocxEditor()\n const [kind, setKind] = useState<SignatureFieldKind>('signature')\n const [who, setWho] = useState<string>(NONE)\n const [email, setEmail] = useState('')\n const [name, setName] = useState('')\n const [required, setRequired] = useState(true)\n const [error, setError] = useState('')\n if (!context?.fields) return null\n const other = who === OTHER\n const chosen = context.signers.find((s) => s.email === who)\n const ready = !other || isSignerEmail(email)\n\n const insert = (close: () => void) => {\n if (!editor || !ready) return\n setError('')\n try {\n insertSignatureField(editor, {\n kind,\n email: other ? email : (chosen?.email ?? null),\n name: other ? name : (chosen?.name ?? null),\n required,\n })\n close()\n setEmail('')\n setName('')\n } catch (failure) {\n setError(failure instanceof Error ? failure.message : 'The field could not be inserted.')\n }\n }\n\n return (\n <RibbonMenu\n label=\"Signature field\"\n icon={<PenLine size={16} />}\n testId=\"docx-signature-field\"\n keepMounted\n >\n {(close) => (\n <form\n className=\"native-docx-signature-field\"\n data-testid=\"docx-signature-field-panel\"\n onSubmit={(event) => {\n event.preventDefault()\n insert(close)\n }}\n >\n <label>\n Field\n <select\n value={kind}\n onChange={(event) => setKind(event.target.value as SignatureFieldKind)}\n data-testid=\"docx-signature-field-kind\"\n >\n {SIGNATURE_FIELD_KINDS.map((k) => (\n <option key={k} value={k}>\n {SIGNATURE_FIELD_LABELS[k]}\n </option>\n ))}\n </select>\n </label>\n <label>\n Signer\n <select\n value={who}\n onChange={(event) => setWho(event.target.value)}\n data-testid=\"docx-signature-field-signer\"\n >\n <option value={NONE}>Choose when sending</option>\n {context.signers.map((s) => (\n <option key={s.email} value={s.email}>\n {s.name || s.email} ({s.email})\n </option>\n ))}\n <option value={OTHER}>Someone else, by email\u2026</option>\n </select>\n </label>\n {other && (\n <>\n <label>\n Email\n <input\n type=\"email\"\n value={email}\n required\n autoComplete=\"off\"\n onChange={(event) => setEmail(event.target.value)}\n data-testid=\"docx-signature-field-email\"\n />\n </label>\n <label>\n Name\n <input\n value={name}\n maxLength={200}\n autoComplete=\"off\"\n onChange={(event) => setName(event.target.value)}\n data-testid=\"docx-signature-field-name\"\n />\n </label>\n </>\n )}\n <label className=\"native-docx-signature-field-check\">\n <input\n type=\"checkbox\"\n checked={required}\n onChange={(event) => setRequired(event.target.checked)}\n />\n Required\n </label>\n {error && <p role=\"alert\">{error}</p>}\n <button\n type=\"submit\"\n disabled={!context.editable || !ready}\n data-testid=\"docx-signature-field-insert\"\n >\n Insert field\n </button>\n </form>\n )}\n </RibbonMenu>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["/**\n * Insert \u203A Signature field: a field where a signature request will ask someone to sign, initial,\n * date or print their name, placed at the caret. The field is a locked chip (\"Signature \u2014 Priya\n * Shah\") whose hidden payload names the signer by email; when the version is saved, its PDF\n * carries an invisible anchor there, and Request signatures places the field exactly on it, for\n * that signer. A field with no signer is assigned when the request is made. See\n * `@arbidocs/coedit/commands` (`signatureFieldWrite`).\n *\n * Insert \u203A My signature puts one's own saved signature or initials (Account settings \u203A Your\n * signature, sealed with one's own key) at the cursor as an inline picture, through the editor's\n * picture insert (a tracked insertion while suggesting). Nothing saved yet: the adopt dialog opens\n * first. That is an informal signature; verified signing is Request signatures.\n */\n\nimport React, { createContext, useContext, useState } from 'react'\nimport { Signature, PenLine, Trash2 } from 'lucide-react'\nimport { DocxEditor, useContextMenuTarget, useDocxEditor } from '@docx-editor.dev/react'\nimport { executeImageCommand } from '@docx-editor.dev/core/editor'\nimport {\n INFORMAL_SIGNATURE_NOTE,\n pngBytes,\n pngSize,\n type SavedSignature,\n} from '@arbidocs/react/document-tools'\nimport { AdoptSignatureDialog } from '../../document-tools/AdoptSignatureDialog'\nimport {\n SIGNATURE_FIELD_KINDS,\n SIGNATURE_FIELD_LABELS,\n isSignerEmail,\n parseSignatureFieldTag,\n signatureFieldWrite,\n type SignatureFieldKind,\n type SignatureFieldSpec,\n} from '@arbidocs/coedit/commands'\nimport { RibbonMenu } from '../RibbonMenu'\nimport { withDirectEditing } from '../definitions/port'\n\n/** Someone who may be asked to sign: a workspace member, offered first in the signer picker. */\nexport interface DocxSigner {\n email: string\n name: string\n}\n\n/** One's own saved signature (sealed with one's own key), for Insert \u203A My signature. */\nexport interface DocxSavedSignature {\n load: () => Promise<SavedSignature | null>\n save: (signature: SavedSignature) => Promise<void>\n /** The name the adopt dialog starts from when nothing is saved yet. */\n defaultName: string\n}\n\ninterface SignatureFieldsValue {\n /** Signature fields are offered (a workspace document). */\n fields: boolean\n signers: readonly DocxSigner[]\n editable: boolean\n notify?: (message: string, kind: 'success' | 'error') => void\n mySignature?: DocxSavedSignature\n openAdopt: (mark: Mark) => void\n}\n\nconst SignatureFieldsContext = createContext<SignatureFieldsValue | null>(null)\n\nexport function SignatureFieldsProvider({\n signers,\n editable,\n notify,\n mySignature,\n children,\n}: {\n /** Absent: the Insert tab offers no signature field (not a workspace document). */\n signers?: readonly DocxSigner[]\n editable: boolean\n notify?: (message: string, kind: 'success' | 'error') => void\n /** Present: Insert offers My signature / My initials. */\n mySignature?: DocxSavedSignature\n children: React.ReactNode\n}) {\n const [pending, setPending] = useState<Mark | null>(null)\n return (\n <SignatureFieldsContext.Provider\n value={\n signers || mySignature\n ? {\n fields: !!signers,\n signers: signers ?? [],\n editable,\n notify,\n mySignature,\n openAdopt: setPending,\n }\n : null\n }\n >\n {children}\n {mySignature && <MySignatureDialog pending={pending} setPending={setPending} />}\n </SignatureFieldsContext.Provider>\n )\n}\n\ntype Mark = 'signature' | 'initials'\n\n/** Insert one's saved signature (or initials) at the caret as an inline picture. */\nasync function insertSavedMark(editor: Editor, saved: SavedSignature, mark: Mark) {\n const png = mark === 'signature' ? saved.signature_png : saved.initials_png\n const { width, height } = pngSize(png)\n // A signature about a line and a half high, initials a little smaller; never wider than 200 pt.\n const heightPoints = mark === 'signature' ? 36 : 24\n let widthPoints = (width / Math.max(1, height)) * heightPoints\n let h = heightPoints\n if (widthPoints > 200) {\n h = (heightPoints * 200) / widthPoints\n widthPoints = 200\n }\n editor.focus()\n const result = await executeImageCommand(editor, {\n type: 'insertImage',\n data: pngBytes(png),\n mime: 'image/png',\n widthPoints,\n heightPoints: h,\n description: mark === 'signature' ? `Signature of ${saved.name}` : `Initials of ${saved.name}`,\n title: mark === 'signature' ? 'Signature' : 'Initials',\n })\n if (!result.ok) throw new Error(result.reason || 'The picture could not be inserted here.')\n}\n\n/** Asks for a signature when nothing is saved yet (opened by `useInsertMySignature`). */\nfunction MySignatureDialog({\n pending,\n setPending,\n}: {\n pending: Mark | null\n setPending: (mark: Mark | null) => void\n}) {\n const context = useContext(SignatureFieldsContext)\n const editor = useDocxEditor()\n const mine = context?.mySignature\n if (!mine) return null\n return (\n <AdoptSignatureDialog\n open={!!pending}\n onOpenChange={(open) => !open && setPending(null)}\n mode=\"save\"\n defaultName={mine.defaultName}\n onSave={mine.save}\n onAdopt={async () => {\n const mark = pending\n setPending(null)\n const saved = await mine.load()\n if (editor && saved && mark) {\n try {\n await insertSavedMark(editor, saved, mark)\n } catch (failure) {\n context?.notify?.(failure instanceof Error ? failure.message : String(failure), 'error')\n }\n }\n }}\n />\n )\n}\n\n/** Insert one's saved signature or initials; nothing saved: the adopt dialog first. */\nfunction useInsertMySignature() {\n const context = useContext(SignatureFieldsContext)\n const editor = useDocxEditor()\n const mine = context?.mySignature\n if (!mine || !editor) return null\n return async (mark: Mark) => {\n try {\n const saved = await mine.load()\n if (!saved) return context?.openAdopt(mark)\n await insertSavedMark(editor, saved, mark)\n } catch (failure) {\n context?.notify?.(\n failure instanceof Error ? failure.message : 'The signature could not be inserted.',\n 'error'\n )\n }\n }\n}\n\n/** Insert tab: My signature (insert my signature / initials). */\nexport function MySignatureMenu() {\n const insert = useInsertMySignature()\n const context = useContext(SignatureFieldsContext)\n if (!insert) return null\n return (\n <RibbonMenu label=\"My signature\" icon={<Signature size={16} />} testId=\"docx-my-signature\">\n {(close) => (\n <div className=\"native-docx-signature-field\" data-testid=\"docx-my-signature-panel\">\n <button\n type=\"button\"\n disabled={!context?.editable}\n onClick={() => {\n close()\n void insert('signature')\n }}\n data-testid=\"docx-insert-my-signature\"\n >\n Insert my signature\n </button>\n <button\n type=\"button\"\n disabled={!context?.editable}\n onClick={() => {\n close()\n void insert('initials')\n }}\n data-testid=\"docx-insert-my-initials\"\n >\n Insert my initials\n </button>\n <p>{INFORMAL_SIGNATURE_NOTE}</p>\n </div>\n )}\n </RibbonMenu>\n )\n}\n\n/** Right-click menu rows: Insert my signature / Insert my initials. */\nexport function MySignatureContextItems() {\n const insert = useInsertMySignature()\n if (!insert) return null\n return (\n <>\n <DocxEditor.ContextMenu.Separator />\n <DocxEditor.ContextMenu.Item\n label=\"Insert my signature\"\n icon={<Signature size={14} />}\n onSelect={() => void insert('signature')}\n />\n <DocxEditor.ContextMenu.Item\n label=\"Insert my initials\"\n icon={<Signature size={14} />}\n onSelect={() => void insert('initials')}\n />\n </>\n )\n}\n\n/** Remove the unsigned placeholder and its signer payload, not a completed signature. */\nexport function SignatureFieldContextItem() {\n const context = useContext(SignatureFieldsContext)\n const editor = useDocxEditor()\n const target = useContextMenuTarget()\n const surface = editor?.surface\n const head = surface?.state().selection?.head\n // Right-click does not move the caret; only offer removal over its rendered text run.\n const run = target?.closest<HTMLElement>('[data-paragraph-id][data-start][data-end]')\n const start = Number(run?.dataset.start)\n const end = Number(run?.dataset.end)\n const onSelectedRun =\n run &&\n head &&\n run.dataset.paragraphId === head.paragraphId &&\n head.offset >= start &&\n head.offset <= end\n const control = onSelectedRun && surface?.contentControls.atCaret()\n if (!context?.fields || !control || !parseSignatureFieldTag(control.tag)) return null\n\n return (\n <>\n <DocxEditor.ContextMenu.Separator />\n <DocxEditor.ContextMenu.Item\n label=\"Remove selected signature field\"\n icon={<Trash2 size={14} />}\n disabled={\n !context.editable ||\n control.effectiveLock === 'sdtLocked' ||\n control.effectiveLock === 'sdtContentLocked'\n }\n onSelect={() => {\n try {\n if (!editor || !surface) return\n const result = withDirectEditing(editor, () =>\n surface.session.removeCustomNode(control.id)\n )\n if (!result.ok) throw new Error('The signature field could not be removed.')\n } catch (failure) {\n context.notify?.(failure instanceof Error ? failure.message : String(failure), 'error')\n }\n }}\n />\n </>\n )\n}\n\nconst OTHER = '__other__'\nconst NONE = ''\n\ntype Editor = NonNullable<ReturnType<typeof useDocxEditor>>\n\n/** Insert the field at the caret, directly (a payload cannot be a tracked change). */\nexport function insertSignatureField(editor: Editor, spec: SignatureFieldSpec): string | null {\n const surface = editor.surface\n const selection = surface?.state().selection\n if (!surface || !selection) throw new Error('Place the cursor where the field goes.')\n const { head } = selection\n const { tag, write } = signatureFieldWrite(spec, head)\n const result = withDirectEditing(editor, () => surface.session.insertCustomNode(write))\n if (!result.ok) {\n throw new Error(\n result.reason === 'locked'\n ? 'A field cannot go inside a locked part of the document.'\n : 'The field could not be inserted here.'\n )\n }\n // Go on typing after the field, not before it.\n const after = { paragraphId: head.paragraphId, offset: head.offset + write.text.length }\n try {\n surface.setSelection({ anchor: after, head: after })\n } catch {\n /* the paragraph was renumbered: the caret stays where the engine put it */\n }\n return tag\n}\n\nexport function SignatureFieldMenu({ onInserted }: { onInserted?: () => void } = {}) {\n const context = useContext(SignatureFieldsContext)\n const editor = useDocxEditor()\n const [kind, setKind] = useState<SignatureFieldKind>('signature')\n const [who, setWho] = useState<string>(NONE)\n const [email, setEmail] = useState('')\n const [name, setName] = useState('')\n const [required, setRequired] = useState(true)\n const [error, setError] = useState('')\n if (!context?.fields) return null\n const other = who === OTHER\n const chosen = context.signers.find((s) => s.email === who)\n const ready = !other || isSignerEmail(email)\n\n const insert = (close: () => void) => {\n if (!editor || !ready) return\n setError('')\n try {\n insertSignatureField(editor, {\n kind,\n email: other ? email : (chosen?.email ?? null),\n name: other ? name : (chosen?.name ?? null),\n required,\n })\n close()\n onInserted?.()\n setEmail('')\n setName('')\n } catch (failure) {\n setError(failure instanceof Error ? failure.message : 'The field could not be inserted.')\n }\n }\n\n return (\n <RibbonMenu\n label=\"Signature field\"\n icon={<PenLine size={16} />}\n testId=\"docx-signature-field\"\n keepMounted\n >\n {(close) => (\n <form\n className=\"native-docx-signature-field\"\n data-testid=\"docx-signature-field-panel\"\n onSubmit={(event) => {\n event.preventDefault()\n insert(close)\n }}\n >\n <label>\n Field\n <select\n value={kind}\n onChange={(event) => setKind(event.target.value as SignatureFieldKind)}\n data-testid=\"docx-signature-field-kind\"\n >\n {SIGNATURE_FIELD_KINDS.map((k) => (\n <option key={k} value={k}>\n {SIGNATURE_FIELD_LABELS[k]}\n </option>\n ))}\n </select>\n </label>\n <label>\n Signer\n <select\n value={who}\n onChange={(event) => setWho(event.target.value)}\n data-testid=\"docx-signature-field-signer\"\n >\n <option value={NONE}>Choose when sending</option>\n {context.signers.map((s) => (\n <option key={s.email} value={s.email}>\n {s.name || s.email} ({s.email})\n </option>\n ))}\n <option value={OTHER}>Someone else, by email\u2026</option>\n </select>\n </label>\n {other && (\n <>\n <label>\n Email\n <input\n type=\"email\"\n value={email}\n required\n autoComplete=\"off\"\n onChange={(event) => setEmail(event.target.value)}\n data-testid=\"docx-signature-field-email\"\n />\n </label>\n <label>\n Name\n <input\n value={name}\n maxLength={200}\n autoComplete=\"off\"\n onChange={(event) => setName(event.target.value)}\n data-testid=\"docx-signature-field-name\"\n />\n </label>\n </>\n )}\n <label className=\"native-docx-signature-field-check\">\n <input\n type=\"checkbox\"\n checked={required}\n onChange={(event) => setRequired(event.target.checked)}\n />\n Required\n </label>\n {error && <p role=\"alert\">{error}</p>}\n <button\n type=\"submit\"\n disabled={!context.editable || !ready}\n data-testid=\"docx-signature-field-insert\"\n >\n Insert field\n </button>\n </form>\n )}\n </RibbonMenu>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|