superdoc 2.18.1-next.5 → 2.19.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/chunks/{create-super-doc-ui-C3HDE1IE.es.js → create-super-doc-ui-BFJ9Y0YV.cjs} +1396 -1
  2. package/dist/chunks/{create-super-doc-ui-Gxk1m05U.cjs → create-super-doc-ui-Dfw1b6h_.es.js} +1318 -66
  3. package/dist/collaboration-upgrade-engine.cjs +1 -1
  4. package/dist/collaboration-upgrade-engine.es.js +1 -1
  5. package/dist/document-api/src/contract/command-catalog.d.ts +1 -1
  6. package/dist/document-api/src/contract/operation-definitions.d.ts +9 -0
  7. package/dist/document-api/src/index.d.ts +1 -0
  8. package/dist/document-api/src/validation-primitives.d.ts +1 -1
  9. package/dist/document-api/src/watermarks/watermarks.d.ts +4 -1
  10. package/dist/document-api/src/watermarks/watermarks.types.d.ts +34 -0
  11. package/dist/layout-engine/painters/dom/src/index.d.ts +2 -0
  12. package/dist/public/ui-react.cjs +1 -1
  13. package/dist/public/ui-react.es.js +1 -1
  14. package/dist/public/ui-vue.cjs +1 -1
  15. package/dist/public/ui-vue.es.js +1 -1
  16. package/dist/public/ui.cjs +1 -1
  17. package/dist/public/ui.es.js +1 -1
  18. package/dist/style.css +596 -80
  19. package/dist/style.layered.css +597 -81
  20. package/dist/superdoc/src/components/surfaces/WatermarkSurface.vue.d.ts +16 -0
  21. package/dist/superdoc/src/components/surfaces/watermark-surface-runtime.d.ts +8 -0
  22. package/dist/superdoc/src/core/types/index.d.ts +4 -4
  23. package/dist/superdoc/src/internal/toolbar/built-in/OverflowMenu.vue.d.ts +93 -1
  24. package/dist/superdoc/src/internal/toolbar/built-in/Toolbar.vue.d.ts +3 -1
  25. package/dist/superdoc/src/internal/toolbar/built-in/ToolbarDropdown.vue.d.ts +1 -0
  26. package/dist/superdoc/src/internal/toolbar/built-in/toolbarIcons.d.ts +1 -0
  27. package/dist/superdoc/src/internal/toolbar/built-in/toolbarTexts.d.ts +1 -0
  28. package/dist/superdoc/src/internal/toolbar/built-in-toolbar.d.ts +3 -0
  29. package/dist/superdoc/src/public/ui/types.d.ts +10 -1
  30. package/dist/superdoc/src/public/ui/watermark-controller.d.ts +32 -0
  31. package/dist/superdoc/src/public/ui/watermark-dialog-state.d.ts +66 -0
  32. package/dist/superdoc/src/public/ui/watermark-draft.d.ts +6 -0
  33. package/dist/superdoc/src/public/ui.d.cts +12 -0
  34. package/dist/superdoc/src/public/ui.d.ts +1 -1
  35. package/dist/superdoc.cjs +107 -171
  36. package/dist/superdoc.es.js +105 -169
  37. package/dist-cdn/style.layered.css +1 -1
  38. package/dist-cdn/superdoc.min.css +1 -1
  39. package/dist-cdn/superdoc.min.js +38 -37
  40. package/package.json +2 -2
@@ -1,3 +1,5 @@
1
+ const require__plugin_vue_export_helper = require("./_plugin-vue_export-helper-SDR04tiH.cjs");
2
+ let vue = require("vue");
1
3
  //#region src/internal/diagnostics/interaction-history.ts
2
4
  var recorders = /* @__PURE__ */ new WeakMap();
3
5
  var nextSession = 0;
@@ -534,6 +536,1311 @@ function shallowEqual(a, b) {
534
536
  return true;
535
537
  }
536
538
  //#endregion
539
+ //#region src/internal/toolbar/image-upload.js
540
+ /**
541
+ * Interactive image acquisition for the built-in toolbar (SD-3567).
542
+ *
543
+ * The toolbar image button routes through the shared controller command
544
+ * `image` → `create.image`, which requires a base64 PNG/JPEG data-URI `src`.
545
+ * This module owns the browser file picker and the File → data-URI
546
+ * conversion; the toolbar dispatches the resulting payload through the
547
+ * normal controller command path.
548
+ */
549
+ /** Accept filter for the picker: PNG and JPEG only (V1 parity; OOXML-native formats). */
550
+ var IMAGE_PICKER_ACCEPT = ".png,.jpg,.jpeg,image/png,image/jpeg";
551
+ var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
552
+ "image/png",
553
+ "image/jpeg",
554
+ "image/jpg"
555
+ ]);
556
+ var SUPPORTED_IMAGE_EXTENSIONS = /\.(png|jpe?g)$/i;
557
+ /**
558
+ * Whether a picked/dropped file is an insertable image (PNG/JPEG). Falls back
559
+ * to the file extension when the browser reports no MIME type.
560
+ * @param {File | null | undefined} file
561
+ * @returns {boolean}
562
+ */
563
+ function isSupportedImageFile(file) {
564
+ if (!file) return false;
565
+ const type = typeof file.type === "string" ? file.type.toLowerCase() : "";
566
+ if (type) return SUPPORTED_IMAGE_MIME_TYPES.has(type);
567
+ return SUPPORTED_IMAGE_EXTENSIONS.test(String(file.name ?? ""));
568
+ }
569
+ /**
570
+ * Read a File/Blob into a base64 data URI.
571
+ *
572
+ * Some browsers/OSes deliver picked files with an empty `type`; the picker
573
+ * accepts those by extension, but `readAsDataURL` would then produce an
574
+ * `application/octet-stream` data URI that `create.image` rejects. Rewrite
575
+ * the media type from the filename so extension-accepted files still insert.
576
+ * @param {Blob & { name?: string }} file
577
+ * @returns {Promise<string>}
578
+ */
579
+ function fileToDataUri(file) {
580
+ return new Promise((resolve, reject) => {
581
+ const reader = new FileReader();
582
+ reader.onload = () => resolve(normalizeImageDataUri(String(reader.result), file));
583
+ reader.onerror = () => reject(reader.error ?? /* @__PURE__ */ new Error("image-read-failed"));
584
+ reader.readAsDataURL(file);
585
+ });
586
+ }
587
+ /**
588
+ * Ensure a data URI read from a supported file carries a PNG/JPEG media type.
589
+ * Leaves URIs already typed as a supported image (or uninferable ones) alone.
590
+ * @param {string} dataUri
591
+ * @param {(Blob & { name?: string }) | null | undefined} file
592
+ * @returns {string}
593
+ */
594
+ function normalizeImageDataUri(dataUri, file) {
595
+ const match = /^data:([^;,]*);base64,/.exec(dataUri);
596
+ if (!match) return dataUri;
597
+ const mime = match[1].toLowerCase();
598
+ if (SUPPORTED_IMAGE_MIME_TYPES.has(mime)) return dataUri;
599
+ const name = String(file?.name ?? "");
600
+ const inferred = /\.jpe?g$/i.test(name) ? "image/jpeg" : /\.png$/i.test(name) ? "image/png" : null;
601
+ if (!inferred) return dataUri;
602
+ return `data:${inferred};base64,${dataUri.slice(match[0].length)}`;
603
+ }
604
+ /**
605
+ * Resolve the `create.image` src for a picked file. Uses the consumer's
606
+ * `handleImageUpload` callback when configured (V1 contract:
607
+ * `(file: File) => Promise<string>`). A returned non-data URL is fetched and
608
+ * embedded, because `create.image` requires an embedded base64 data URI.
609
+ * @param {File} file
610
+ * @param {((file: File) => Promise<string>) | null | undefined} handleImageUpload
611
+ * @returns {Promise<string>}
612
+ */
613
+ async function resolveImageSrc(file, handleImageUpload) {
614
+ if (typeof handleImageUpload === "function") {
615
+ const result = await handleImageUpload(file);
616
+ if (typeof result !== "string" || result.trim() === "") throw new Error("handleImageUpload returned an empty result");
617
+ if (result.startsWith("data:")) return result;
618
+ return embedRemoteImage(result, file);
619
+ }
620
+ return fileToDataUri(file);
621
+ }
622
+ /**
623
+ * Fetch a remote image URL and embed it as a data URI. Object-store /
624
+ * presigned URLs often respond `application/octet-stream`, so keep a filename
625
+ * hint (URL path, falling back to the originally picked file) for the media
626
+ * type normalization in `fileToDataUri`.
627
+ * @param {string} url
628
+ * @param {File | null | undefined} pickedFile
629
+ * @returns {Promise<string>}
630
+ */
631
+ async function embedRemoteImage(url, pickedFile) {
632
+ const response = await fetch(url);
633
+ if (!response.ok) throw new Error(`image fetch failed: ${response.status}`);
634
+ const blob = await response.blob();
635
+ const name = (/\.(?:png|jpe?g)(?:$|[?#])/i.test(url) ? url.split(/[?#]/)[0] : "") || pickedFile?.name || "";
636
+ return fileToDataUri(name ? Object.assign(blob, { name }) : blob);
637
+ }
638
+ /**
639
+ * Hidden `<input type=file>` picker bound to one toolbar instance. The input
640
+ * stays attached (hidden) so automation and tests can drive it; `destroy()`
641
+ * removes it. Picking a file calls `onPick(file)`; an unsupported type or a
642
+ * failed pick routes through `onError(error)`.
643
+ *
644
+ * @param {{
645
+ * ownerDocument?: Document,
646
+ * onPick?: (file: File) => unknown,
647
+ * onError?: (error: Error) => void,
648
+ * }} options
649
+ * @returns {{ input: HTMLInputElement, open: () => void, destroy: () => void }}
650
+ */
651
+ function createImageFilePicker({ ownerDocument = document, onPick, onError } = {}) {
652
+ const input = ownerDocument.createElement("input");
653
+ input.type = "file";
654
+ input.accept = IMAGE_PICKER_ACCEPT;
655
+ input.hidden = true;
656
+ input.tabIndex = -1;
657
+ input.setAttribute("data-superdoc-image-picker", "true");
658
+ input.setAttribute("aria-hidden", "true");
659
+ input.addEventListener("change", () => {
660
+ const file = input.files && input.files[0];
661
+ input.value = "";
662
+ if (!file) return;
663
+ if (!isSupportedImageFile(file)) {
664
+ onError?.(/* @__PURE__ */ new Error(`unsupported image type: ${file.type || file.name}`));
665
+ return;
666
+ }
667
+ try {
668
+ const result = onPick?.(file);
669
+ if (result && typeof result.then === "function") result.catch((error) => onError?.(error));
670
+ } catch (error) {
671
+ onError?.(error);
672
+ }
673
+ });
674
+ ownerDocument.body?.appendChild(input);
675
+ return {
676
+ input,
677
+ open() {
678
+ input.click();
679
+ },
680
+ destroy() {
681
+ input.remove();
682
+ }
683
+ };
684
+ }
685
+ //#endregion
686
+ //#region src/components/surfaces/WatermarkSurface.vue?vue&type=script&setup=true&lang.ts
687
+ var _hoisted_1 = { class: "sd-watermark__body" };
688
+ var _hoisted_2 = { class: "sd-watermark__settings" };
689
+ var _hoisted_3 = ["disabled"];
690
+ var _hoisted_4 = { class: "sd-watermark__field" };
691
+ var _hoisted_5 = ["value"];
692
+ var _hoisted_6 = ["value"];
693
+ var _hoisted_7 = { class: "sd-watermark__field" };
694
+ var _hoisted_8 = ["value"];
695
+ var _hoisted_9 = ["disabled"];
696
+ var _hoisted_10 = { class: "sd-watermark__selection-list" };
697
+ var _hoisted_11 = [
698
+ "value",
699
+ "checked",
700
+ "onChange"
701
+ ];
702
+ var _hoisted_12 = ["disabled"];
703
+ var _hoisted_13 = {
704
+ key: 0,
705
+ class: "sd-watermark__notice"
706
+ };
707
+ var _hoisted_14 = {
708
+ key: 1,
709
+ class: "sd-watermark__notice"
710
+ };
711
+ var _hoisted_15 = ["disabled"];
712
+ var _hoisted_16 = { class: "sd-watermark__types" };
713
+ var _hoisted_17 = [
714
+ "name",
715
+ "value",
716
+ "checked",
717
+ "onChange"
718
+ ];
719
+ var _hoisted_18 = { class: "sd-watermark__field" };
720
+ var _hoisted_19 = ["value"];
721
+ var _hoisted_20 = {
722
+ class: "sd-watermark__presets",
723
+ "aria-label": "Text presets"
724
+ };
725
+ var _hoisted_21 = ["onClick"];
726
+ var _hoisted_22 = { class: "sd-watermark__font-row" };
727
+ var _hoisted_23 = { class: "sd-watermark__field" };
728
+ var _hoisted_24 = ["value"];
729
+ var _hoisted_25 = ["value"];
730
+ var _hoisted_26 = { class: "sd-watermark__field sd-watermark__size" };
731
+ var _hoisted_27 = ["list", "value"];
732
+ var _hoisted_28 = ["id"];
733
+ var _hoisted_29 = ["value"];
734
+ var _hoisted_30 = { class: "sd-watermark__styles" };
735
+ var _hoisted_31 = ["aria-pressed"];
736
+ var _hoisted_32 = ["aria-pressed"];
737
+ var _hoisted_33 = { class: "sd-watermark__field sd-watermark__font-color" };
738
+ var _hoisted_34 = { class: "sd-watermark__color" };
739
+ var _hoisted_35 = ["value"];
740
+ var _hoisted_36 = ["value"];
741
+ var _hoisted_37 = { class: "sd-watermark__picture" };
742
+ var _hoisted_38 = ["src"];
743
+ var _hoisted_39 = ["accept"];
744
+ var _hoisted_40 = { class: "sd-watermark__field" };
745
+ var _hoisted_41 = ["value"];
746
+ var _hoisted_42 = {
747
+ key: 0,
748
+ value: "custom",
749
+ disabled: ""
750
+ };
751
+ var _hoisted_43 = ["value"];
752
+ var _hoisted_44 = { class: "sd-watermark__check" };
753
+ var _hoisted_45 = ["checked"];
754
+ var _hoisted_46 = { class: "sd-watermark__check" };
755
+ var _hoisted_47 = ["checked"];
756
+ var _hoisted_48 = {
757
+ key: 2,
758
+ class: "sd-watermark__field sd-watermark__transparency"
759
+ };
760
+ var _hoisted_49 = ["for"];
761
+ var _hoisted_50 = { class: "sd-watermark__range" };
762
+ var _hoisted_51 = ["id", "value"];
763
+ var _hoisted_52 = ["value"];
764
+ var _hoisted_53 = {
765
+ key: 3,
766
+ class: "sd-watermark__orientation"
767
+ };
768
+ var _hoisted_54 = [
769
+ "name",
770
+ "value",
771
+ "checked",
772
+ "onChange"
773
+ ];
774
+ var _hoisted_55 = {
775
+ key: 4,
776
+ class: "sd-watermark__notice"
777
+ };
778
+ var _hoisted_56 = {
779
+ key: 5,
780
+ class: "sd-watermark__notice"
781
+ };
782
+ var _hoisted_57 = ["aria-busy"];
783
+ var _hoisted_58 = { class: "sd-watermark__page" };
784
+ var _hoisted_59 = [
785
+ "src",
786
+ "width",
787
+ "height"
788
+ ];
789
+ var _hoisted_60 = { key: 1 };
790
+ var _hoisted_61 = { class: "sd-watermark__impact" };
791
+ var _hoisted_62 = {
792
+ key: 0,
793
+ class: "sd-watermark__impact-details"
794
+ };
795
+ var _hoisted_63 = {
796
+ key: 0,
797
+ class: "sd-watermark__error",
798
+ role: "alert"
799
+ };
800
+ var _hoisted_64 = ["disabled"];
801
+ var _hoisted_65 = { class: "sd-watermark__footer sd-dialog-footer" };
802
+ var _hoisted_66 = {
803
+ role: "status",
804
+ "aria-live": "polite"
805
+ };
806
+ var _hoisted_67 = { class: "sd-watermark__actions" };
807
+ var _hoisted_68 = ["disabled"];
808
+ var WatermarkSurface_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0, vue.defineComponent)({
809
+ __name: "WatermarkSurface",
810
+ props: {
811
+ model: {},
812
+ surfaceId: { default: "" },
813
+ mode: {},
814
+ request: {},
815
+ resolve: {},
816
+ close: {
817
+ type: Function,
818
+ default: () => {}
819
+ }
820
+ },
821
+ setup(__props) {
822
+ const props = __props;
823
+ const snapshot = (0, vue.shallowRef)(props.model.getSnapshot());
824
+ const fileInput = (0, vue.ref)(null);
825
+ const filePending = (0, vue.ref)(false);
826
+ const localError = (0, vue.ref)("");
827
+ let fileGeneration = 0;
828
+ let unsubscribe;
829
+ const presets = [
830
+ "DRAFT",
831
+ "CONFIDENTIAL",
832
+ "DO NOT COPY"
833
+ ];
834
+ const types = [
835
+ {
836
+ value: "none",
837
+ label: "No watermark"
838
+ },
839
+ {
840
+ value: "text",
841
+ label: "Text"
842
+ },
843
+ {
844
+ value: "picture",
845
+ label: "Picture"
846
+ }
847
+ ];
848
+ const busy = (0, vue.computed)(() => snapshot.value.phase === "loading" || snapshot.value.phase === "applying");
849
+ const editable = (0, vue.computed)(() => !busy.value && !snapshot.value.readonlyReason);
850
+ const canApply = (0, vue.computed)(() => snapshot.value.canApply && !busy.value && !filePending.value && !snapshot.value.stale);
851
+ const error = (0, vue.computed)(() => localError.value || snapshot.value.error);
852
+ const status = (0, vue.computed)(() => {
853
+ if (filePending.value) return "Preparing picture…";
854
+ if (snapshot.value.phase === "loading") return "Loading watermarks…";
855
+ if (snapshot.value.phase === "applying") return "Applying changes; closing will not cancel them.";
856
+ if (snapshot.value.phase === "previewing") return "Updating preview…";
857
+ return snapshot.value.dirty ? "Changes apply when you choose Apply" : "No changes";
858
+ });
859
+ const fontOptions = (0, vue.computed)(() => {
860
+ const { fonts, draft } = snapshot.value;
861
+ return fonts.some((font) => font.value === draft.fontFamily) ? fonts : [{
862
+ value: draft.fontFamily,
863
+ label: draft.fontFamily
864
+ }, ...fonts];
865
+ });
866
+ function cancelPreparation() {
867
+ fileGeneration += 1;
868
+ filePending.value = false;
869
+ }
870
+ function patch(patch) {
871
+ if (!editable.value) return;
872
+ localError.value = "";
873
+ props.model.patchDraft(patch);
874
+ }
875
+ function changeScope(event, field) {
876
+ const value = event.target.value;
877
+ cancelPreparation();
878
+ props.model.setScope(field === "section" ? value || null : snapshot.value.sectionId, field === "variant" ? value : snapshot.value.variant);
879
+ }
880
+ function selectWatermark(id, event) {
881
+ cancelPreparation();
882
+ const selected = new Set(snapshot.value.selectedIds);
883
+ if (event.target.checked) selected.add(id);
884
+ else selected.delete(id);
885
+ props.model.selectWatermarks([...selected]);
886
+ }
887
+ async function choosePicture(event) {
888
+ const input = event.target;
889
+ const file = input.files?.[0];
890
+ input.value = "";
891
+ if (!file || !editable.value) return;
892
+ cancelPreparation();
893
+ localError.value = "";
894
+ if (!isSupportedImageFile(file)) {
895
+ localError.value = "Choose a PNG or JPEG picture.";
896
+ return;
897
+ }
898
+ const generation = fileGeneration;
899
+ filePending.value = true;
900
+ try {
901
+ const src = await fileToDataUri(file);
902
+ if (generation !== fileGeneration) return;
903
+ patch({
904
+ src,
905
+ pictureName: file.name,
906
+ kind: "picture"
907
+ });
908
+ } catch {
909
+ if (generation === fileGeneration) localError.value = "The picture could not be read. Choose it again.";
910
+ } finally {
911
+ if (generation === fileGeneration) filePending.value = false;
912
+ }
913
+ }
914
+ async function apply() {
915
+ if (!canApply.value) return;
916
+ try {
917
+ await props.model.apply();
918
+ } catch {
919
+ localError.value = "The watermark could not be applied. Try again.";
920
+ }
921
+ }
922
+ async function reload() {
923
+ cancelPreparation();
924
+ localError.value = "";
925
+ try {
926
+ await props.model.reload();
927
+ } catch {
928
+ localError.value = "Watermarks could not be loaded. Try again.";
929
+ }
930
+ }
931
+ function close() {
932
+ cancelPreparation();
933
+ props.close("user-cancelled");
934
+ }
935
+ (0, vue.watch)([
936
+ () => snapshot.value.draft.kind,
937
+ () => snapshot.value.sectionId,
938
+ () => snapshot.value.variant,
939
+ () => snapshot.value.selectedIds.join("\0")
940
+ ], cancelPreparation);
941
+ (0, vue.onMounted)(() => {
942
+ unsubscribe = props.model.subscribe((value) => {
943
+ snapshot.value = value;
944
+ });
945
+ snapshot.value = props.model.getSnapshot();
946
+ });
947
+ (0, vue.onBeforeUnmount)(() => {
948
+ cancelPreparation();
949
+ unsubscribe?.();
950
+ });
951
+ return (_ctx, _cache) => {
952
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("form", {
953
+ class: "sd-watermark sd-dialog-content",
954
+ onSubmit: (0, vue.withModifiers)(apply, ["prevent"])
955
+ }, [
956
+ (0, vue.createElementVNode)("header", { class: "sd-watermark__header sd-dialog-header" }, [_cache[17] || (_cache[17] = (0, vue.createElementVNode)("h2", null, "Watermark", -1)), (0, vue.createElementVNode)("button", {
957
+ type: "button",
958
+ class: "sd-dialog-close",
959
+ "aria-label": "Close watermark dialog",
960
+ onClick: close
961
+ }, [..._cache[16] || (_cache[16] = [(0, vue.createElementVNode)("svg", {
962
+ width: "16",
963
+ height: "16",
964
+ viewBox: "0 0 16 16",
965
+ "aria-hidden": "true"
966
+ }, [(0, vue.createElementVNode)("path", {
967
+ d: "m4 4 8 8m0-8-8 8",
968
+ fill: "none",
969
+ stroke: "currentColor",
970
+ "stroke-width": "1.5",
971
+ "stroke-linecap": "round"
972
+ })], -1)])])]),
973
+ (0, vue.createElementVNode)("div", _hoisted_1, [(0, vue.createElementVNode)("div", _hoisted_2, [
974
+ (0, vue.createElementVNode)("fieldset", {
975
+ class: "sd-watermark__scope",
976
+ disabled: busy.value
977
+ }, [
978
+ _cache[22] || (_cache[22] = (0, vue.createElementVNode)("legend", { class: "sd-watermark__sr-only" }, "Watermark scope", -1)),
979
+ (0, vue.createElementVNode)("label", _hoisted_4, [_cache[19] || (_cache[19] = (0, vue.createElementVNode)("span", null, "Apply to", -1)), (0, vue.createElementVNode)("select", {
980
+ "aria-label": "Apply to",
981
+ value: snapshot.value.sectionId ?? "",
982
+ onChange: _cache[0] || (_cache[0] = ($event) => changeScope($event, "section"))
983
+ }, [_cache[18] || (_cache[18] = (0, vue.createElementVNode)("option", { value: "" }, "Entire document", -1)), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(snapshot.value.sections, (section) => {
984
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
985
+ key: section.id,
986
+ value: section.id
987
+ }, (0, vue.toDisplayString)(section.label), 9, _hoisted_6);
988
+ }), 128))], 40, _hoisted_5)]),
989
+ (0, vue.createElementVNode)("label", _hoisted_7, [_cache[21] || (_cache[21] = (0, vue.createElementVNode)("span", null, "Page type", -1)), (0, vue.createElementVNode)("select", {
990
+ "aria-label": "Page type",
991
+ value: snapshot.value.variant,
992
+ onChange: _cache[1] || (_cache[1] = ($event) => changeScope($event, "variant"))
993
+ }, [..._cache[20] || (_cache[20] = [
994
+ (0, vue.createElementVNode)("option", { value: "all" }, "All applicable", -1),
995
+ (0, vue.createElementVNode)("option", { value: "default" }, "Default", -1),
996
+ (0, vue.createElementVNode)("option", { value: "first" }, "First", -1),
997
+ (0, vue.createElementVNode)("option", { value: "even" }, "Even", -1)
998
+ ])], 40, _hoisted_8)])
999
+ ], 8, _hoisted_3),
1000
+ snapshot.value.items.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("fieldset", {
1001
+ key: 0,
1002
+ class: "sd-watermark__selection",
1003
+ disabled: busy.value
1004
+ }, [
1005
+ _cache[23] || (_cache[23] = (0, vue.createElementVNode)("legend", null, "Watermarks to edit", -1)),
1006
+ (0, vue.createElementVNode)("div", _hoisted_10, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(snapshot.value.items, (item) => {
1007
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("label", {
1008
+ key: item.id,
1009
+ class: "sd-watermark__check"
1010
+ }, [(0, vue.createElementVNode)("input", {
1011
+ type: "checkbox",
1012
+ value: item.id,
1013
+ checked: snapshot.value.selectedIds.includes(item.id),
1014
+ onChange: ($event) => selectWatermark(item.id, $event)
1015
+ }, null, 40, _hoisted_11), (0, vue.createElementVNode)("span", null, [(0, vue.createTextVNode)((0, vue.toDisplayString)(item.label), 1), (0, vue.createElementVNode)("small", null, (0, vue.toDisplayString)(item.locations), 1)])]);
1016
+ }), 128))]),
1017
+ (0, vue.createElementVNode)("button", {
1018
+ type: "button",
1019
+ disabled: !editable.value,
1020
+ onClick: _cache[2] || (_cache[2] = ($event) => __props.model.selectWatermarks([]))
1021
+ }, "Add watermark", 8, _hoisted_12),
1022
+ snapshot.value.selectedIds.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_13, " Applying uses the settings below for all " + (0, vue.toDisplayString)(snapshot.value.selectedIds.length) + " selected copies. ", 1)) : (0, vue.createCommentVNode)("", true)
1023
+ ], 8, _hoisted_9)) : (0, vue.createCommentVNode)("", true),
1024
+ snapshot.value.readonlyReason ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_14, (0, vue.toDisplayString)(snapshot.value.readonlyReason), 1)) : (0, vue.createCommentVNode)("", true),
1025
+ (0, vue.createElementVNode)("fieldset", {
1026
+ class: (0, vue.normalizeClass)(["sd-watermark__draft", { "sd-watermark__draft--text": snapshot.value.draft.kind === "text" }]),
1027
+ disabled: !editable.value
1028
+ }, [
1029
+ _cache[40] || (_cache[40] = (0, vue.createElementVNode)("legend", { class: "sd-watermark__sr-only" }, "Watermark settings", -1)),
1030
+ (0, vue.createElementVNode)("fieldset", _hoisted_16, [_cache[24] || (_cache[24] = (0, vue.createElementVNode)("legend", { class: "sd-watermark__sr-only" }, "Watermark type", -1)), ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(types, (type) => {
1031
+ return (0, vue.createElementVNode)("label", {
1032
+ key: type.value,
1033
+ class: (0, vue.normalizeClass)({ "is-selected": snapshot.value.draft.kind === type.value })
1034
+ }, [(0, vue.createElementVNode)("input", {
1035
+ type: "radio",
1036
+ name: `watermark-type-${__props.surfaceId}`,
1037
+ value: type.value,
1038
+ checked: snapshot.value.draft.kind === type.value,
1039
+ onChange: ($event) => patch({ kind: type.value })
1040
+ }, null, 40, _hoisted_17), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(type.value === "none" && snapshot.value.items.length > 1 && snapshot.value.selectedIds.length ? "Remove selected" : type.label), 1)], 2);
1041
+ }), 64))]),
1042
+ snapshot.value.draft.kind === "text" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [
1043
+ (0, vue.createElementVNode)("label", _hoisted_18, [_cache[25] || (_cache[25] = (0, vue.createElementVNode)("span", null, "Text", -1)), (0, vue.createElementVNode)("input", {
1044
+ "aria-label": "Watermark text",
1045
+ type: "text",
1046
+ value: snapshot.value.draft.text,
1047
+ onInput: _cache[3] || (_cache[3] = ($event) => patch({ text: $event.target.value }))
1048
+ }, null, 40, _hoisted_19)]),
1049
+ (0, vue.createElementVNode)("div", _hoisted_20, [((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(presets, (preset) => {
1050
+ return (0, vue.createElementVNode)("button", {
1051
+ key: preset,
1052
+ type: "button",
1053
+ onClick: ($event) => patch({ text: preset })
1054
+ }, (0, vue.toDisplayString)(preset), 9, _hoisted_21);
1055
+ }), 64))]),
1056
+ (0, vue.createElementVNode)("div", _hoisted_22, [
1057
+ (0, vue.createElementVNode)("label", _hoisted_23, [_cache[26] || (_cache[26] = (0, vue.createElementVNode)("span", null, "Font", -1)), (0, vue.createElementVNode)("select", {
1058
+ "aria-label": "Font",
1059
+ value: snapshot.value.draft.fontFamily,
1060
+ onChange: _cache[4] || (_cache[4] = ($event) => patch({ fontFamily: $event.target.value }))
1061
+ }, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(fontOptions.value, (font) => {
1062
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
1063
+ key: font.value,
1064
+ value: font.value
1065
+ }, (0, vue.toDisplayString)(font.label), 9, _hoisted_25);
1066
+ }), 128))], 40, _hoisted_24)]),
1067
+ (0, vue.createElementVNode)("label", _hoisted_26, [
1068
+ _cache[28] || (_cache[28] = (0, vue.createElementVNode)("span", null, "Size (pt)", -1)),
1069
+ (0, vue.createElementVNode)("input", {
1070
+ "aria-label": "Font size",
1071
+ list: `watermark-sizes-${__props.surfaceId}`,
1072
+ value: snapshot.value.draft.fontSize === "auto" ? "Auto" : snapshot.value.draft.fontSize,
1073
+ onChange: _cache[5] || (_cache[5] = ($event) => patch({ fontSize: $event.target.value.toLowerCase() === "auto" ? "auto" : Number($event.target.value) }))
1074
+ }, null, 40, _hoisted_27),
1075
+ (0, vue.createElementVNode)("datalist", { id: `watermark-sizes-${__props.surfaceId}` }, [_cache[27] || (_cache[27] = (0, vue.createElementVNode)("option", { value: "Auto" }, null, -1)), ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)([
1076
+ 24,
1077
+ 36,
1078
+ 48,
1079
+ 72,
1080
+ 96
1081
+ ], (size) => {
1082
+ return (0, vue.createElementVNode)("option", {
1083
+ key: size,
1084
+ value: size
1085
+ }, null, 8, _hoisted_29);
1086
+ }), 64))], 8, _hoisted_28)
1087
+ ]),
1088
+ (0, vue.createElementVNode)("div", _hoisted_30, [(0, vue.createElementVNode)("button", {
1089
+ type: "button",
1090
+ "aria-label": "Bold",
1091
+ "aria-pressed": snapshot.value.draft.bold,
1092
+ onClick: _cache[6] || (_cache[6] = ($event) => patch({ bold: !snapshot.value.draft.bold }))
1093
+ }, [..._cache[29] || (_cache[29] = [(0, vue.createElementVNode)("b", null, "B", -1)])], 8, _hoisted_31), (0, vue.createElementVNode)("button", {
1094
+ type: "button",
1095
+ "aria-label": "Italic",
1096
+ "aria-pressed": snapshot.value.draft.italic,
1097
+ onClick: _cache[7] || (_cache[7] = ($event) => patch({ italic: !snapshot.value.draft.italic }))
1098
+ }, [..._cache[30] || (_cache[30] = [(0, vue.createElementVNode)("i", null, "I", -1)])], 8, _hoisted_32)])
1099
+ ]),
1100
+ (0, vue.createElementVNode)("label", _hoisted_33, [_cache[31] || (_cache[31] = (0, vue.createElementVNode)("span", null, "Font color", -1)), (0, vue.createElementVNode)("span", _hoisted_34, [(0, vue.createElementVNode)("input", {
1101
+ type: "color",
1102
+ "aria-label": "Choose font color",
1103
+ value: snapshot.value.draft.color,
1104
+ onInput: _cache[8] || (_cache[8] = ($event) => patch({ color: $event.target.value }))
1105
+ }, null, 40, _hoisted_35), (0, vue.createElementVNode)("input", {
1106
+ type: "text",
1107
+ "aria-label": "Font color",
1108
+ value: snapshot.value.draft.color,
1109
+ spellcheck: "false",
1110
+ onInput: _cache[9] || (_cache[9] = ($event) => patch({ color: $event.target.value }))
1111
+ }, null, 40, _hoisted_36)])])
1112
+ ], 64)) : (0, vue.createCommentVNode)("", true),
1113
+ snapshot.value.draft.kind === "picture" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [
1114
+ (0, vue.createElementVNode)("div", _hoisted_37, [
1115
+ snapshot.value.draft.src ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", {
1116
+ key: 0,
1117
+ src: snapshot.value.draft.src,
1118
+ alt: "Selected picture"
1119
+ }, null, 8, _hoisted_38)) : (0, vue.createCommentVNode)("", true),
1120
+ (0, vue.createElementVNode)("div", null, [(0, vue.createElementVNode)("strong", null, (0, vue.toDisplayString)(snapshot.value.draft.pictureName || "No picture selected"), 1), _cache[32] || (_cache[32] = (0, vue.createElementVNode)("small", null, "PNG or JPEG", -1))]),
1121
+ (0, vue.createElementVNode)("button", {
1122
+ type: "button",
1123
+ onClick: _cache[10] || (_cache[10] = ($event) => fileInput.value?.click())
1124
+ }, (0, vue.toDisplayString)(snapshot.value.draft.pictureName ? "Replace picture" : "Choose picture"), 1),
1125
+ (0, vue.createElementVNode)("input", {
1126
+ ref_key: "fileInput",
1127
+ ref: fileInput,
1128
+ type: "file",
1129
+ accept: (0, vue.unref)(IMAGE_PICKER_ACCEPT),
1130
+ "aria-label": "Choose watermark picture",
1131
+ hidden: "",
1132
+ onChange: choosePicture
1133
+ }, null, 40, _hoisted_39)
1134
+ ]),
1135
+ (0, vue.createElementVNode)("label", _hoisted_40, [_cache[34] || (_cache[34] = (0, vue.createElementVNode)("span", null, "Scale", -1)), (0, vue.createElementVNode)("select", {
1136
+ "aria-label": "Picture scale",
1137
+ value: snapshot.value.draft.customSize ? "custom" : snapshot.value.draft.scalePercent,
1138
+ onChange: _cache[11] || (_cache[11] = ($event) => patch({ scalePercent: $event.target.value === "auto" ? "auto" : Number($event.target.value) }))
1139
+ }, [
1140
+ snapshot.value.draft.customSize ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("option", _hoisted_42, "Custom size retained")) : (0, vue.createCommentVNode)("", true),
1141
+ _cache[33] || (_cache[33] = (0, vue.createElementVNode)("option", { value: "auto" }, "Auto", -1)),
1142
+ ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)([
1143
+ 50,
1144
+ 100,
1145
+ 150,
1146
+ 200,
1147
+ 500
1148
+ ], (scale) => {
1149
+ return (0, vue.createElementVNode)("option", {
1150
+ key: scale,
1151
+ value: scale
1152
+ }, (0, vue.toDisplayString)(scale) + "%", 9, _hoisted_43);
1153
+ }), 64))
1154
+ ], 40, _hoisted_41)]),
1155
+ (0, vue.createElementVNode)("label", _hoisted_44, [(0, vue.createElementVNode)("input", {
1156
+ type: "checkbox",
1157
+ checked: snapshot.value.draft.lockAspectRatio,
1158
+ onChange: _cache[12] || (_cache[12] = ($event) => patch({ lockAspectRatio: $event.target.checked }))
1159
+ }, null, 40, _hoisted_45), _cache[35] || (_cache[35] = (0, vue.createElementVNode)("span", null, "Preserve aspect ratio", -1))]),
1160
+ (0, vue.createElementVNode)("label", _hoisted_46, [(0, vue.createElementVNode)("input", {
1161
+ type: "checkbox",
1162
+ checked: snapshot.value.draft.washout,
1163
+ onChange: _cache[13] || (_cache[13] = ($event) => patch({ washout: $event.target.checked }))
1164
+ }, null, 40, _hoisted_47), _cache[36] || (_cache[36] = (0, vue.createElementVNode)("span", null, [(0, vue.createTextVNode)("Washout"), (0, vue.createElementVNode)("small", null, "Lighten the picture's colors.")], -1))])
1165
+ ], 64)) : (0, vue.createCommentVNode)("", true),
1166
+ snapshot.value.draft.kind !== "none" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_48, [
1167
+ (0, vue.createElementVNode)("label", { for: `watermark-transparency-${__props.surfaceId}` }, "Transparency", 8, _hoisted_49),
1168
+ (0, vue.createElementVNode)("div", _hoisted_50, [(0, vue.createElementVNode)("input", {
1169
+ id: `watermark-transparency-${__props.surfaceId}`,
1170
+ type: "range",
1171
+ min: "0",
1172
+ max: "100",
1173
+ step: "1",
1174
+ "aria-label": "Transparency",
1175
+ value: snapshot.value.draft.transparency,
1176
+ onInput: _cache[14] || (_cache[14] = ($event) => patch({ transparency: Number($event.target.value) }))
1177
+ }, null, 40, _hoisted_51), (0, vue.createElementVNode)("label", null, [(0, vue.createElementVNode)("input", {
1178
+ type: "number",
1179
+ min: "0",
1180
+ max: "100",
1181
+ step: "any",
1182
+ "aria-label": "Transparency percentage",
1183
+ value: snapshot.value.draft.transparency,
1184
+ onInput: _cache[15] || (_cache[15] = ($event) => patch({ transparency: Number($event.target.value) }))
1185
+ }, null, 40, _hoisted_52), _cache[37] || (_cache[37] = (0, vue.createElementVNode)("span", null, "%", -1))])]),
1186
+ _cache[38] || (_cache[38] = (0, vue.createElementVNode)("small", null, "0% opaque, 100% transparent", -1))
1187
+ ])) : (0, vue.createCommentVNode)("", true),
1188
+ snapshot.value.draft.kind !== "none" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("fieldset", _hoisted_53, [_cache[39] || (_cache[39] = (0, vue.createElementVNode)("legend", null, "Orientation", -1)), ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(["horizontal", "diagonal"], (orientation) => {
1189
+ return (0, vue.createElementVNode)("label", { key: orientation }, [(0, vue.createElementVNode)("input", {
1190
+ type: "radio",
1191
+ name: `watermark-orientation-${__props.surfaceId}`,
1192
+ value: orientation,
1193
+ checked: !snapshot.value.draft.customOrientation && snapshot.value.draft.orientation === orientation,
1194
+ onChange: ($event) => patch({ orientation })
1195
+ }, null, 40, _hoisted_54), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(orientation === "horizontal" ? "Horizontal" : "Diagonal"), 1)]);
1196
+ }), 64))])) : (0, vue.createCommentVNode)("", true),
1197
+ snapshot.value.draft.customPlacement ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_55, "Custom placement retained.")) : (0, vue.createCommentVNode)("", true),
1198
+ snapshot.value.draft.kind === "none" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_56, (0, vue.toDisplayString)(snapshot.value.selectedIds.length ? "The selected watermark will be removed when you apply." : "Choose Text or Picture to add a watermark."), 1)) : (0, vue.createCommentVNode)("", true)
1199
+ ], 10, _hoisted_15)
1200
+ ]), (0, vue.createElementVNode)("aside", {
1201
+ class: "sd-watermark__preview",
1202
+ "aria-label": "Watermark preview",
1203
+ "aria-busy": snapshot.value.phase === "previewing"
1204
+ }, [
1205
+ _cache[41] || (_cache[41] = (0, vue.createElementVNode)("h3", null, "Preview", -1)),
1206
+ (0, vue.createElementVNode)("div", _hoisted_58, [snapshot.value.preview ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", {
1207
+ key: 0,
1208
+ src: snapshot.value.preview.url,
1209
+ width: snapshot.value.preview.width,
1210
+ height: snapshot.value.preview.height,
1211
+ alt: "Watermark on a sample page"
1212
+ }, null, 8, _hoisted_59)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_60, (0, vue.toDisplayString)(snapshot.value.phase === "loading" || snapshot.value.phase === "previewing" ? "Preparing preview…" : snapshot.value.draft.kind === "none" ? "No watermark in this preview" : "Preview unavailable"), 1))]),
1213
+ _cache[42] || (_cache[42] = (0, vue.createElementVNode)("p", { class: "sd-watermark__caption" }, "Preview at the selected page size", -1)),
1214
+ (0, vue.createElementVNode)("p", _hoisted_61, (0, vue.toDisplayString)(snapshot.value.impact), 1),
1215
+ snapshot.value.impactDetails?.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("details", _hoisted_62, [(0, vue.createElementVNode)("summary", null, "View " + (0, vue.toDisplayString)(snapshot.value.impactDetails.length) + " affected locations", 1), (0, vue.createElementVNode)("ul", null, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(snapshot.value.impactDetails, (location) => {
1216
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("li", { key: location }, (0, vue.toDisplayString)(location), 1);
1217
+ }), 128))])])) : (0, vue.createCommentVNode)("", true)
1218
+ ], 8, _hoisted_57)]),
1219
+ error.value || snapshot.value.stale ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_63, [(0, vue.createElementVNode)("p", null, (0, vue.toDisplayString)(error.value || "The document changed. Review the latest state before applying."), 1), snapshot.value.stale || snapshot.value.error ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
1220
+ key: 0,
1221
+ type: "button",
1222
+ disabled: busy.value,
1223
+ onClick: reload
1224
+ }, " Review latest state ", 8, _hoisted_64)) : (0, vue.createCommentVNode)("", true)])) : (0, vue.createCommentVNode)("", true),
1225
+ (0, vue.createElementVNode)("footer", _hoisted_65, [(0, vue.createElementVNode)("p", _hoisted_66, (0, vue.toDisplayString)(status.value), 1), (0, vue.createElementVNode)("div", _hoisted_67, [(0, vue.createElementVNode)("button", {
1226
+ type: "button",
1227
+ class: "sd-dialog-secondary",
1228
+ onClick: close
1229
+ }, "Cancel"), (0, vue.createElementVNode)("button", {
1230
+ type: "submit",
1231
+ class: "sd-watermark__apply sd-dialog-primary",
1232
+ disabled: !canApply.value
1233
+ }, (0, vue.toDisplayString)(snapshot.value.phase === "applying" ? "Applying…" : snapshot.value.draft.kind === "none" ? snapshot.value.items.length > 1 ? "Remove selected watermark" : "Remove watermark" : "Apply watermark"), 9, _hoisted_68)])])
1234
+ ], 32);
1235
+ };
1236
+ }
1237
+ });
1238
+ //#endregion
1239
+ //#region src/components/surfaces/WatermarkSurface.vue
1240
+ var WatermarkSurface_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(WatermarkSurface_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-df56c82c"]]);
1241
+ //#endregion
1242
+ //#region src/components/surfaces/watermark-surface-runtime.js
1243
+ /**
1244
+ * Keeps Vue rendering and post-dismissal announcements outside the public type graph.
1245
+ * @param {(() => HTMLElement | null) | undefined} getContainer
1246
+ */
1247
+ function createWatermarkSurfaceRuntime(getContainer) {
1248
+ /** @type {HTMLDivElement | null} */
1249
+ let status = null;
1250
+ let disposed = false;
1251
+ return {
1252
+ component: WatermarkSurface_default,
1253
+ captureFocusReturn() {
1254
+ const document = getContainer?.()?.ownerDocument;
1255
+ const opener = document?.activeElement;
1256
+ const item = opener?.closest("[data-sd-part=\"toolbar-item\"]") ?? opener?.querySelector("[data-sd-part=\"toolbar-item\"]");
1257
+ const container = (item?.closest("[data-sd-part=\"toolbar\"]"))?.parentElement;
1258
+ const isWatermarkEntry = item?.querySelector("[data-item=\"btn-watermark\"], [data-item=\"btn-overflow\"]");
1259
+ /** @param {() => boolean} isCurrent */
1260
+ return async (isCurrent) => {
1261
+ await (0, vue.nextTick)();
1262
+ if (disposed || !isCurrent() || !isWatermarkEntry || opener?.isConnected || !container?.isConnected) return;
1263
+ if (document?.activeElement !== document?.body) return;
1264
+ const currentToolbar = container.querySelector("[data-sd-part=\"toolbar\"]");
1265
+ for (const name of ["watermark", "overflow"]) {
1266
+ const target = currentToolbar?.querySelector(`[data-item="btn-${name}"]`)?.closest("[data-sd-part=\"toolbar-item\"]");
1267
+ if (target instanceof HTMLElement && target.getClientRects().length && target.getAttribute("aria-disabled") !== "true") {
1268
+ target.focus({ preventScroll: true });
1269
+ return;
1270
+ }
1271
+ }
1272
+ };
1273
+ },
1274
+ mount() {
1275
+ const container = getContainer?.();
1276
+ if (disposed || status || !container?.ownerDocument) return;
1277
+ status = container.ownerDocument.createElement("div");
1278
+ status.setAttribute("role", "status");
1279
+ status.setAttribute("aria-live", "polite");
1280
+ status.setAttribute("aria-atomic", "true");
1281
+ Object.assign(status.style, {
1282
+ position: "absolute",
1283
+ width: "1px",
1284
+ height: "1px",
1285
+ overflow: "hidden",
1286
+ clipPath: "inset(50%)",
1287
+ whiteSpace: "nowrap"
1288
+ });
1289
+ container.appendChild(status);
1290
+ },
1291
+ /** @param {string} message */
1292
+ announce(message) {
1293
+ if (!disposed && status) status.textContent = message;
1294
+ },
1295
+ destroy() {
1296
+ disposed = true;
1297
+ status?.remove();
1298
+ status = null;
1299
+ }
1300
+ };
1301
+ }
1302
+ //#endregion
1303
+ //#region src/public/ui/watermark-draft.ts
1304
+ function placementState(placement) {
1305
+ const customOrientation = placement?.rotationDegrees != null && ![0, 315].includes(placement.rotationDegrees);
1306
+ return {
1307
+ customOrientation,
1308
+ customPlacement: Boolean(customOrientation || placement?.behindText === false || placement?.horizontal && (placement.horizontal.alignment !== "center" || placement.horizontal.offsetPt) || placement?.vertical && (placement.vertical.alignment !== "center" || placement.vertical.offsetPt))
1309
+ };
1310
+ }
1311
+ function createWatermarkDraft(item) {
1312
+ const value = item?.watermark;
1313
+ const placement = value?.placement ? structuredClone(value.placement) : void 0;
1314
+ const picture = value?.kind === "picture" ? value : void 0;
1315
+ const text = value?.kind === "text" ? value : void 0;
1316
+ const rotation = placement?.rotationDegrees ?? (picture ? 0 : text?.orientation === "horizontal" ? 0 : 315);
1317
+ return {
1318
+ kind: value?.kind ?? "none",
1319
+ geometryKind: value?.kind ?? null,
1320
+ text: text?.text ?? "DRAFT",
1321
+ fontFamily: text?.fontFamily ?? "Calibri",
1322
+ fontSize: text?.fontSizePt ?? "auto",
1323
+ bold: text?.bold ?? false,
1324
+ italic: text?.italic ?? false,
1325
+ color: text?.color ?? "#C0C0C0",
1326
+ transparency: (1 - (value?.opacity ?? .5)) * 100,
1327
+ orientation: rotation === 0 ? "horizontal" : "diagonal",
1328
+ scalePercent: picture?.scalePercent ?? "auto",
1329
+ washout: picture?.washout ?? true,
1330
+ lockAspectRatio: picture?.lockAspectRatio ?? true,
1331
+ pictureName: picture ? "Image in this document" : "",
1332
+ sourceWatermarkId: picture ? item?.watermarkId : void 0,
1333
+ widthPt: picture?.widthPt,
1334
+ heightPt: picture?.heightPt,
1335
+ placement,
1336
+ ...placementState(placement),
1337
+ customSize: Boolean(picture && (placement?.widthPt != null || picture.widthPt != null))
1338
+ };
1339
+ }
1340
+ function patchWatermarkDraft(draft, patch) {
1341
+ const next = {
1342
+ ...draft,
1343
+ ...patch
1344
+ };
1345
+ if (patch.kind && patch.kind !== "none") {
1346
+ if (patch.kind !== draft.geometryKind) {
1347
+ next.placement = void 0;
1348
+ next.widthPt = void 0;
1349
+ next.heightPt = void 0;
1350
+ next.customSize = false;
1351
+ next.orientation = patch.kind === "picture" ? "horizontal" : "diagonal";
1352
+ }
1353
+ next.geometryKind = patch.kind;
1354
+ }
1355
+ if (patch.orientation !== void 0) next.placement = {
1356
+ ...next.placement,
1357
+ rotationDegrees: patch.orientation === "diagonal" ? 315 : 0
1358
+ };
1359
+ if (patch.scalePercent !== void 0 || patch.src !== void 0) {
1360
+ const { widthPt: _width, heightPt: _height, ...placement } = next.placement ?? {};
1361
+ next.placement = Object.keys(placement).length ? placement : void 0;
1362
+ next.widthPt = void 0;
1363
+ next.heightPt = void 0;
1364
+ next.customSize = false;
1365
+ }
1366
+ return {
1367
+ ...next,
1368
+ ...placementState(next.placement)
1369
+ };
1370
+ }
1371
+ function getWatermarkDraftError(draft) {
1372
+ if (draft.kind === "none") return null;
1373
+ if (!Number.isFinite(draft.transparency) || draft.transparency < 0 || draft.transparency > 100) return "Transparency must be between 0 and 100%.";
1374
+ if (draft.kind === "picture") return draft.src || draft.sourceWatermarkId ? null : "Choose a picture.";
1375
+ if (!draft.text.trim()) return "Enter watermark text.";
1376
+ if (draft.fontSize !== "auto" && (!Number.isFinite(draft.fontSize) || draft.fontSize <= 0)) return "Enter a positive font size or choose Auto.";
1377
+ if (!/^#[\da-f]{6}$/i.test(draft.color)) return "Enter a six-digit hex color.";
1378
+ if (!draft.fontFamily.trim()) return "Choose a font.";
1379
+ return null;
1380
+ }
1381
+ function toWatermarkInput(draft) {
1382
+ const shared = {
1383
+ opacity: 1 - draft.transparency / 100,
1384
+ ...draft.placement ? { placement: draft.placement } : {}
1385
+ };
1386
+ if (draft.kind === "text") return {
1387
+ kind: "text",
1388
+ text: draft.text,
1389
+ fontFamily: draft.fontFamily,
1390
+ fontSizePt: draft.fontSize,
1391
+ bold: draft.bold,
1392
+ italic: draft.italic,
1393
+ color: draft.color,
1394
+ orientation: draft.orientation,
1395
+ ...shared
1396
+ };
1397
+ if (draft.kind !== "picture") throw new Error("A removal has no watermark input.");
1398
+ return {
1399
+ kind: "picture",
1400
+ ...draft.src ? { src: draft.src } : { source: {
1401
+ kind: "existing",
1402
+ watermarkId: draft.sourceWatermarkId
1403
+ } },
1404
+ scalePercent: draft.scalePercent,
1405
+ washout: draft.washout,
1406
+ lockAspectRatio: draft.lockAspectRatio,
1407
+ ...draft.widthPt != null ? { widthPt: draft.widthPt } : {},
1408
+ ...draft.heightPt != null ? { heightPt: draft.heightPt } : {},
1409
+ ...shared
1410
+ };
1411
+ }
1412
+ //#endregion
1413
+ //#region src/public/ui/watermark-controller.ts
1414
+ var PAGE_TYPES = {
1415
+ default: "Default pages",
1416
+ first: "First page",
1417
+ even: "Even pages"
1418
+ };
1419
+ var STALE_MESSAGE = "The document changed while this dialog was open. Review the latest watermark before applying.";
1420
+ function scopeSlots(sections, sectionId, variant) {
1421
+ return sections.filter((section) => sectionId == null || section.address.sectionId === sectionId).flatMap((section) => {
1422
+ return (variant === "all" ? [
1423
+ "default",
1424
+ ...section.titlePage ? ["first"] : [],
1425
+ ...section.oddEvenHeadersFooters ? ["even"] : []
1426
+ ] : [variant]).map((variant) => ({
1427
+ kind: "headerFooterSlot",
1428
+ section: section.address,
1429
+ headerFooterKind: "header",
1430
+ variant
1431
+ }));
1432
+ });
1433
+ }
1434
+ function slotKey(slot) {
1435
+ return `${slot.section.sectionId}:${slot.variant}`;
1436
+ }
1437
+ function failureMessage(error) {
1438
+ return error instanceof Error ? error.message : "The watermark could not be updated. Try again.";
1439
+ }
1440
+ function createWatermarkController(options) {
1441
+ const surface = createWatermarkSurfaceRuntime(options.getContainer);
1442
+ const workflowOptions = {
1443
+ ...options,
1444
+ announce: (message) => {
1445
+ surface.announce(message);
1446
+ options.announce?.(message);
1447
+ }
1448
+ };
1449
+ let active = null;
1450
+ let destroyed = false;
1451
+ let openGeneration = 0;
1452
+ function close() {
1453
+ const previous = active;
1454
+ active = null;
1455
+ previous?.dispose();
1456
+ previous?.handle.close();
1457
+ }
1458
+ function open() {
1459
+ if (destroyed) return {
1460
+ ok: false,
1461
+ reason: "not-ready"
1462
+ };
1463
+ const editor = options.getEditor();
1464
+ if (!editor) return {
1465
+ ok: false,
1466
+ reason: "not-ready"
1467
+ };
1468
+ if (!editor.doc?.watermarks?.list || !editor.doc.sections?.list) return {
1469
+ ok: false,
1470
+ reason: "document-api-unavailable"
1471
+ };
1472
+ if (!options.openSurface || !editor.doc.watermarks.apply || !editor.host?.watermarkPreview) return {
1473
+ ok: false,
1474
+ reason: "operation-unavailable"
1475
+ };
1476
+ const generation = ++openGeneration;
1477
+ const restoreFocus = surface.captureFocusReturn();
1478
+ close();
1479
+ surface.mount();
1480
+ const workflow = createDialogWorkflow(editor, workflowOptions, () => {
1481
+ if (active?.handle === handle) close();
1482
+ });
1483
+ let handle;
1484
+ try {
1485
+ handle = options.openSurface({
1486
+ mode: "dialog",
1487
+ ariaLabel: "Watermark",
1488
+ component: surface.component,
1489
+ props: { model: workflow.model },
1490
+ dialog: { maxWidth: 700 }
1491
+ });
1492
+ } catch {
1493
+ workflow.dispose();
1494
+ return {
1495
+ ok: false,
1496
+ reason: "operation-unavailable"
1497
+ };
1498
+ }
1499
+ active = {
1500
+ handle,
1501
+ dispose: workflow.dispose
1502
+ };
1503
+ handle.result.then((outcome) => {
1504
+ workflow.dispose();
1505
+ if (active?.handle === handle) active = null;
1506
+ if (outcome.status === "closed" || outcome.status === "submitted") restoreFocus(() => !destroyed && generation === openGeneration && active === null);
1507
+ });
1508
+ workflow.model.reload();
1509
+ return { ok: true };
1510
+ }
1511
+ return {
1512
+ open,
1513
+ close,
1514
+ destroy() {
1515
+ destroyed = true;
1516
+ close();
1517
+ surface.destroy();
1518
+ }
1519
+ };
1520
+ }
1521
+ function createDialogWorkflow(editor, options, onSuccess) {
1522
+ const listeners = /* @__PURE__ */ new Set();
1523
+ let alive = true;
1524
+ let generation = 0;
1525
+ let timer;
1526
+ let catalog = [];
1527
+ let sections = [];
1528
+ let revision = "";
1529
+ let originalDraft = JSON.stringify(createWatermarkDraft());
1530
+ let preparedInput = null;
1531
+ let snapshot = {
1532
+ phase: "loading",
1533
+ draft: createWatermarkDraft(),
1534
+ sections: [],
1535
+ sectionId: null,
1536
+ variant: "all",
1537
+ items: [],
1538
+ selectedIds: [],
1539
+ fonts: [...options.getFonts()],
1540
+ dirty: false,
1541
+ canApply: false,
1542
+ error: null,
1543
+ stale: false,
1544
+ readonlyReason: null,
1545
+ impact: "",
1546
+ impactDetails: [],
1547
+ preview: null
1548
+ };
1549
+ const current = (token) => alive && token === generation && options.getEditor() === editor;
1550
+ const editable = () => options.getMode() === "editing";
1551
+ function publish(patch) {
1552
+ if (!alive) return;
1553
+ snapshot = {
1554
+ ...snapshot,
1555
+ ...patch
1556
+ };
1557
+ for (const listener of listeners) listener(snapshot);
1558
+ }
1559
+ function invalidate() {
1560
+ clearTimeout(timer);
1561
+ preparedInput = null;
1562
+ return ++generation;
1563
+ }
1564
+ function location(slot) {
1565
+ const section = sections.find((item) => item.address.sectionId === slot.section.sectionId);
1566
+ const inactive = slot.variant === "first" ? !section?.titlePage : slot.variant === "even" ? !section?.oddEvenHeadersFooters : false;
1567
+ return `Section ${(section?.index ?? 0) + 1}, ${PAGE_TYPES[slot.variant].toLowerCase()}${inactive ? " (inactive)" : ""}`;
1568
+ }
1569
+ function scopedItems() {
1570
+ if (snapshot.sectionId == null && snapshot.variant === "all") return catalog;
1571
+ const keys = new Set(scopeSlots(sections, snapshot.sectionId, snapshot.variant).map(slotKey));
1572
+ return catalog.filter((item) => item.effectiveIn.some((slot) => keys.has(slotKey(slot))));
1573
+ }
1574
+ function publishCatalog() {
1575
+ publish({ items: scopedItems().map((item) => ({
1576
+ id: item.watermarkId,
1577
+ label: item.watermark.kind === "text" ? item.watermark.text : "Picture watermark",
1578
+ locations: item.effectiveIn.map(location).join("; ")
1579
+ })) });
1580
+ }
1581
+ function buildInput() {
1582
+ const target = snapshot.sectionId == null && snapshot.variant === "all" ? { kind: "document" } : {
1583
+ kind: "headerFooterSlots",
1584
+ slots: scopeSlots(sections, snapshot.sectionId, snapshot.variant)
1585
+ };
1586
+ if (snapshot.draft.kind === "none") return {
1587
+ target,
1588
+ action: "remove",
1589
+ watermarkIds: snapshot.selectedIds
1590
+ };
1591
+ const watermark = toWatermarkInput(snapshot.draft);
1592
+ if (snapshot.selectedIds.length) return {
1593
+ target,
1594
+ action: "replace",
1595
+ watermarkIds: snapshot.selectedIds,
1596
+ watermark
1597
+ };
1598
+ if ("source" in watermark) throw new Error("Select the existing picture watermark in this scope, or choose a new picture.");
1599
+ return {
1600
+ target,
1601
+ action: "insert",
1602
+ watermark
1603
+ };
1604
+ }
1605
+ function rejectReceipt(result) {
1606
+ if (result.success) return false;
1607
+ const stale = result.failure?.code === "REVISION_MISMATCH";
1608
+ publish({
1609
+ stale,
1610
+ phase: "editing",
1611
+ canApply: false,
1612
+ error: stale ? STALE_MESSAGE : result.failure?.message ?? "The watermark could not be updated."
1613
+ });
1614
+ return true;
1615
+ }
1616
+ async function prepare(token) {
1617
+ try {
1618
+ const error = getWatermarkDraftError(snapshot.draft);
1619
+ if (error) {
1620
+ publish({
1621
+ phase: "editing",
1622
+ error,
1623
+ canApply: false,
1624
+ preview: null
1625
+ });
1626
+ return;
1627
+ }
1628
+ const input = snapshot.draft.kind === "none" && !snapshot.selectedIds.length ? null : buildInput();
1629
+ const preview = snapshot.draft.kind === "none" ? null : await editor.host.watermarkPreview({
1630
+ watermark: toWatermarkInput(snapshot.draft),
1631
+ sectionId: snapshot.sectionId ?? sections[0]?.address.sectionId,
1632
+ expectedRevision: revision
1633
+ });
1634
+ if (!current(token)) return;
1635
+ if (!input || !snapshot.dirty || !editable()) {
1636
+ publish({
1637
+ phase: "editing",
1638
+ preview,
1639
+ canApply: false,
1640
+ error: null
1641
+ });
1642
+ return;
1643
+ }
1644
+ const receipt = await editor.doc.watermarks.apply(input, {
1645
+ expectedRevision: revision,
1646
+ dryRun: true
1647
+ });
1648
+ if (!current(token)) return;
1649
+ if (!receipt.success) {
1650
+ rejectReceipt(receipt);
1651
+ return;
1652
+ }
1653
+ preparedInput = input;
1654
+ const affected = receipt.affectedSlots.map(location);
1655
+ publish({
1656
+ phase: "editing",
1657
+ preview,
1658
+ error: null,
1659
+ canApply: affected.length > 0 && !snapshot.stale && editable(),
1660
+ impact: affected.length ? `Changes: ${affected.length > 3 ? `${affected.length} page locations` : affected.join("; ")}. Other locations stay as they are.` : "No matching watermark will change.",
1661
+ impactDetails: affected.length > 3 ? affected : []
1662
+ });
1663
+ } catch (error) {
1664
+ if (current(token)) publish({
1665
+ phase: "editing",
1666
+ error: failureMessage(error),
1667
+ canApply: false,
1668
+ preview: null
1669
+ });
1670
+ }
1671
+ }
1672
+ function schedulePreview() {
1673
+ const token = invalidate();
1674
+ publish({
1675
+ phase: "previewing",
1676
+ canApply: false,
1677
+ error: null,
1678
+ impact: "",
1679
+ impactDetails: [],
1680
+ preview: null
1681
+ });
1682
+ timer = setTimeout(() => {
1683
+ prepare(token);
1684
+ }, 120);
1685
+ }
1686
+ const model = {
1687
+ getSnapshot: () => snapshot,
1688
+ subscribe(listener) {
1689
+ listeners.add(listener);
1690
+ listener(snapshot);
1691
+ return () => {
1692
+ listeners.delete(listener);
1693
+ };
1694
+ },
1695
+ async reload() {
1696
+ const token = invalidate();
1697
+ publish({
1698
+ phase: "loading",
1699
+ canApply: false,
1700
+ stale: false,
1701
+ error: null,
1702
+ impactDetails: [],
1703
+ preview: null
1704
+ });
1705
+ try {
1706
+ const [marks, sectionList] = await Promise.all([editor.doc.watermarks.list(), editor.doc.sections.list()]);
1707
+ if (!current(token)) return;
1708
+ if (marks.items.length !== marks.total || sectionList.items.length !== sectionList.total) throw new Error("The complete watermark scope could not be loaded.");
1709
+ if (sectionList.evaluatedRevision && sectionList.evaluatedRevision !== marks.evaluatedRevision) throw new Error(STALE_MESSAGE);
1710
+ catalog = marks.items;
1711
+ sections = sectionList.items;
1712
+ revision = marks.evaluatedRevision;
1713
+ const available = scopedItems();
1714
+ const selected = available.length === 1 ? available[0] : void 0;
1715
+ const draft = createWatermarkDraft(selected);
1716
+ originalDraft = JSON.stringify(draft);
1717
+ publish({
1718
+ draft,
1719
+ dirty: false,
1720
+ selectedIds: selected ? [selected.watermarkId] : [],
1721
+ sections: sections.map((item) => ({
1722
+ id: item.address.sectionId,
1723
+ label: `Section ${item.index + 1}`
1724
+ })),
1725
+ readonlyReason: editable() ? null : options.getMode() === "suggesting" ? "Watermarks cannot be changed in Suggesting mode." : "This document is read-only.",
1726
+ impact: available.length > 1 ? "Select the watermark copies you want to edit, or add a new watermark." : ""
1727
+ });
1728
+ publishCatalog();
1729
+ await prepare(token);
1730
+ } catch (error) {
1731
+ if (current(token)) publish({
1732
+ phase: "editing",
1733
+ error: failureMessage(error),
1734
+ canApply: false
1735
+ });
1736
+ }
1737
+ },
1738
+ patchDraft(patch) {
1739
+ if (!alive || snapshot.phase === "loading" || snapshot.phase === "applying" || !editable()) return;
1740
+ const draft = patchWatermarkDraft(snapshot.draft, patch);
1741
+ publish({
1742
+ draft,
1743
+ dirty: JSON.stringify(draft) !== originalDraft
1744
+ });
1745
+ schedulePreview();
1746
+ },
1747
+ setScope(sectionId, variant) {
1748
+ if (!alive || snapshot.phase === "loading" || snapshot.phase === "applying") return;
1749
+ if (sectionId != null && !sections.some((item) => item.address.sectionId === sectionId)) return;
1750
+ publish({
1751
+ sectionId,
1752
+ variant
1753
+ });
1754
+ publishCatalog();
1755
+ const available = scopedItems();
1756
+ const visible = new Set(available.map((item) => item.watermarkId));
1757
+ let selectedIds = snapshot.selectedIds.filter((id) => visible.has(id));
1758
+ if (snapshot.dirty && snapshot.draft.kind === "none" && !selectedIds.length && available.length === 1) selectedIds = [available[0].watermarkId];
1759
+ publish({ selectedIds });
1760
+ if (!snapshot.dirty) model.selectWatermarks(available.length === 1 ? [available[0].watermarkId] : []);
1761
+ else schedulePreview();
1762
+ },
1763
+ selectWatermarks(ids) {
1764
+ if (!alive || snapshot.phase === "loading" || snapshot.phase === "applying") return;
1765
+ const available = scopedItems();
1766
+ const selectedIds = [...new Set(ids)].filter((id) => available.some((item) => item.watermarkId === id));
1767
+ const draft = createWatermarkDraft(available.find((item) => item.watermarkId === selectedIds[0]));
1768
+ originalDraft = JSON.stringify(draft);
1769
+ publish({
1770
+ selectedIds,
1771
+ draft,
1772
+ dirty: false
1773
+ });
1774
+ schedulePreview();
1775
+ },
1776
+ async apply() {
1777
+ if (!alive || !snapshot.canApply || !preparedInput || !editable() || options.getEditor() !== editor) return;
1778
+ const input = preparedInput;
1779
+ const token = invalidate();
1780
+ publish({
1781
+ phase: "applying",
1782
+ canApply: false,
1783
+ error: null
1784
+ });
1785
+ options.announce?.("Applying watermark changes. Closing the dialog will not cancel them.");
1786
+ try {
1787
+ const receipt = await editor.doc.watermarks.apply(input, { expectedRevision: revision });
1788
+ if (!current(token)) {
1789
+ options.announce?.(receipt.success ? "Watermark updated." : "The watermark could not be updated.");
1790
+ return;
1791
+ }
1792
+ if (rejectReceipt(receipt)) return;
1793
+ options.announce?.(input.action === "remove" ? "Watermark removed." : "Watermark updated.");
1794
+ onSuccess();
1795
+ } catch (error) {
1796
+ if (current(token)) publish({
1797
+ phase: "editing",
1798
+ error: failureMessage(error),
1799
+ canApply: false
1800
+ });
1801
+ else options.announce?.(failureMessage(error));
1802
+ }
1803
+ }
1804
+ };
1805
+ const stopEvents = editor.host?.events?.subscribe((event) => {
1806
+ if (!alive || snapshot.phase === "applying") return;
1807
+ if (event.type === "collaboration:document-replaced") {
1808
+ invalidate();
1809
+ publish({
1810
+ phase: "editing",
1811
+ stale: true,
1812
+ canApply: false,
1813
+ error: STALE_MESSAGE
1814
+ });
1815
+ return;
1816
+ }
1817
+ if (![
1818
+ "document:mutated",
1819
+ "mutation:committed",
1820
+ "collaboration:remote-changed"
1821
+ ].includes(event.type)) return;
1822
+ invalidate();
1823
+ if (snapshot.dirty) publish({
1824
+ phase: "editing",
1825
+ stale: true,
1826
+ canApply: false,
1827
+ error: STALE_MESSAGE
1828
+ });
1829
+ else timer = setTimeout(() => {
1830
+ model.reload();
1831
+ }, 120);
1832
+ });
1833
+ return {
1834
+ model,
1835
+ dispose() {
1836
+ alive = false;
1837
+ invalidate();
1838
+ stopEvents?.();
1839
+ listeners.clear();
1840
+ }
1841
+ };
1842
+ }
1843
+ //#endregion
537
1844
  //#region src/public/ui/format-painter-helpers.js
538
1845
  /**
539
1846
  * Maps SDRunProps field names to InlineRunPatch field names.
@@ -11563,6 +12870,15 @@ function createSuperDocUI(options) {
11563
12870
  getQuickGallery: () => stylesSub.get().quickGallery,
11564
12871
  getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style
11565
12872
  };
12873
+ const watermark = createWatermarkController({
12874
+ getEditor,
12875
+ getMode: readDocumentMode,
12876
+ getFonts: () => fonts.getFamilyOptions(),
12877
+ getContainer: () => superdoc.element ?? null,
12878
+ openSurface: typeof superdoc.openSurface === "function" ? (request) => superdoc.openSurface(request) : null
12879
+ });
12880
+ documentResetHooks.push(watermark.close);
12881
+ documentModeChangeHooks.push(watermark.close);
11566
12882
  const createScope = () => {
11567
12883
  const scopeUnsubs = [];
11568
12884
  return {
@@ -11584,6 +12900,7 @@ function createSuperDocUI(options) {
11584
12900
  };
11585
12901
  const destroy = () => {
11586
12902
  if (disposed) return;
12903
+ watermark.destroy();
11587
12904
  clearContentControlHighlight();
11588
12905
  disposed = true;
11589
12906
  releaseSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost, uiTrackedChangesCatalogState);
@@ -11666,6 +12983,7 @@ function createSuperDocUI(options) {
11666
12983
  tables,
11667
12984
  search,
11668
12985
  contextMenu,
12986
+ watermark,
11669
12987
  styles,
11670
12988
  formatPainter: {
11671
12989
  setPointerSelecting(flag) {
@@ -11878,4 +13196,81 @@ function commandIsActive(descriptor, selection) {
11878
13196
  return descriptor.activeMark ? selection.activeMarks.includes(descriptor.activeMark) : false;
11879
13197
  }
11880
13198
  //#endregion
11881
- export { applyV2CommentInvalidationFromMutation as a, DOM_CLASS_NAMES as c, recordInteraction as d, BUILT_IN_COMMAND_IDS as i, closeInteractionHistory as l, executeFirstPartyCommandAsync as n, getV2TrackedChangeMutationImpact as o, registerFirstPartyCommandMutation as r, shallowEqual as s, createSuperDocUI as t, createInteractionHistory as u };
13199
+ Object.defineProperty(exports, "BUILT_IN_COMMAND_IDS", {
13200
+ enumerable: true,
13201
+ get: function() {
13202
+ return BUILT_IN_COMMAND_IDS;
13203
+ }
13204
+ });
13205
+ Object.defineProperty(exports, "DOM_CLASS_NAMES", {
13206
+ enumerable: true,
13207
+ get: function() {
13208
+ return DOM_CLASS_NAMES;
13209
+ }
13210
+ });
13211
+ Object.defineProperty(exports, "applyV2CommentInvalidationFromMutation", {
13212
+ enumerable: true,
13213
+ get: function() {
13214
+ return applyV2CommentInvalidationFromMutation;
13215
+ }
13216
+ });
13217
+ Object.defineProperty(exports, "closeInteractionHistory", {
13218
+ enumerable: true,
13219
+ get: function() {
13220
+ return closeInteractionHistory;
13221
+ }
13222
+ });
13223
+ Object.defineProperty(exports, "createImageFilePicker", {
13224
+ enumerable: true,
13225
+ get: function() {
13226
+ return createImageFilePicker;
13227
+ }
13228
+ });
13229
+ Object.defineProperty(exports, "createInteractionHistory", {
13230
+ enumerable: true,
13231
+ get: function() {
13232
+ return createInteractionHistory;
13233
+ }
13234
+ });
13235
+ Object.defineProperty(exports, "createSuperDocUI", {
13236
+ enumerable: true,
13237
+ get: function() {
13238
+ return createSuperDocUI;
13239
+ }
13240
+ });
13241
+ Object.defineProperty(exports, "executeFirstPartyCommandAsync", {
13242
+ enumerable: true,
13243
+ get: function() {
13244
+ return executeFirstPartyCommandAsync;
13245
+ }
13246
+ });
13247
+ Object.defineProperty(exports, "getV2TrackedChangeMutationImpact", {
13248
+ enumerable: true,
13249
+ get: function() {
13250
+ return getV2TrackedChangeMutationImpact;
13251
+ }
13252
+ });
13253
+ Object.defineProperty(exports, "recordInteraction", {
13254
+ enumerable: true,
13255
+ get: function() {
13256
+ return recordInteraction;
13257
+ }
13258
+ });
13259
+ Object.defineProperty(exports, "registerFirstPartyCommandMutation", {
13260
+ enumerable: true,
13261
+ get: function() {
13262
+ return registerFirstPartyCommandMutation;
13263
+ }
13264
+ });
13265
+ Object.defineProperty(exports, "resolveImageSrc", {
13266
+ enumerable: true,
13267
+ get: function() {
13268
+ return resolveImageSrc;
13269
+ }
13270
+ });
13271
+ Object.defineProperty(exports, "shallowEqual", {
13272
+ enumerable: true,
13273
+ get: function() {
13274
+ return shallowEqual;
13275
+ }
13276
+ });