@openpresentation/opf-editor 0.17.0 → 0.18.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.
- package/README.md +74 -42
- package/dist/assets.js +1 -1
- package/dist/canvas.d.ts +7 -5
- package/dist/canvas.js +17 -5
- package/dist/data-grid.js +3 -2
- package/dist/data.d.ts +3 -3
- package/dist/data.js +3 -3
- package/dist/design-controls.js +157 -44
- package/dist/design-options.d.ts +78 -22
- package/dist/design-options.js +240 -110
- package/dist/export.d.ts +49 -42
- package/dist/export.js +169 -89
- package/dist/find-panel.js +3 -2
- package/dist/font-gate.js +1 -1
- package/dist/review-panel.js +8 -5
- package/dist/review.d.ts +6 -1
- package/dist/review.js +37 -1
- package/dist/slide-manager.js +13 -8
- package/dist/template-panel.d.ts +1 -1
- package/dist/template-panel.js +7 -4
- package/dist/templates.js +1 -1
- package/package.json +15 -14
package/dist/design-controls.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Design controls (RR-06): the DOM panel for the dimension switches, the design options, block
|
|
2
2
|
// conversion, chart type and table style/merge. Every control commits one validated, undoable
|
|
3
|
-
// change through the session (switchDimension, setDesignOption,
|
|
4
|
-
// setHeaderFooterZone, convertBlock, setTableStyle, mergeTableCells, ...), so a host that already
|
|
3
|
+
// change through the session (switchDimension, setDesignOption, setOrganizationLogo,
|
|
4
|
+
// setHeaderFooterZone, insertZoneLogo, convertBlock, setTableStyle, mergeTableCells, ...), so a host that already
|
|
5
5
|
// subscribes to the session redraws on every change, on Undo and on Redo. The panel owns no
|
|
6
6
|
// document state: it reads the session, mirrors it into native form controls, and reports
|
|
7
7
|
// problems in a live region. Importing this module does not need a DOM; mounting does.
|
|
@@ -20,20 +20,26 @@ import { BLOCK_KIND_LABELS, blockConversionTargets, blockPathForSelection, readB
|
|
|
20
20
|
import {
|
|
21
21
|
DATE_FORMAT_TOKENS,
|
|
22
22
|
HEADER_FOOTER_ZONES,
|
|
23
|
-
|
|
23
|
+
LOGO_BACKGROUNDS,
|
|
24
|
+
LOGO_SHAPES,
|
|
24
25
|
ZONE_VALUES,
|
|
25
26
|
designWarnings,
|
|
26
27
|
getDesignOption,
|
|
27
28
|
headerFooterState,
|
|
29
|
+
insertZoneLogo,
|
|
28
30
|
insertZoneValue,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
listOrganizations,
|
|
32
|
+
logoReference,
|
|
33
|
+
parseLogoReference,
|
|
31
34
|
prepareDesignOption,
|
|
35
|
+
prepareHeaderFooterZone,
|
|
36
|
+
prepareOrganizationLogo,
|
|
32
37
|
readHeaderFooterZone,
|
|
33
|
-
|
|
38
|
+
readLogoChoice,
|
|
39
|
+
readOrganizationLogo,
|
|
34
40
|
setDesignOption,
|
|
35
41
|
setHeaderFooterZone,
|
|
36
|
-
|
|
42
|
+
setOrganizationLogo,
|
|
37
43
|
} from "./design-options.js";
|
|
38
44
|
import { createContentControls } from "./content-controls.js";
|
|
39
45
|
import { IMAGE_EDGES, IMAGE_FITS, IMAGE_SHAPES, readImageTreatments, setImageTreatment } from "./image-options.js";
|
|
@@ -57,19 +63,18 @@ const SECTION_TITLES = {
|
|
|
57
63
|
"slide-content": "Slide structure",
|
|
58
64
|
};
|
|
59
65
|
const OPEN_BY_DEFAULT = new Set(["look", "selection", "image", "table"]);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
stacked: "Stacked",
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
wordmarkDark: "Wordmark, dark",
|
|
66
|
+
// RR-71: the four shapes of an organization's logo, and the two backgrounds a shape can be split by.
|
|
67
|
+
const LOGO_SHAPE_LABELS = {
|
|
68
|
+
all: "All shapes (one image)",
|
|
69
|
+
full: "Full (mark and name side by side)",
|
|
70
|
+
stacked: "Stacked (mark above the name)",
|
|
71
|
+
icon: "Icon (the mark alone)",
|
|
72
|
+
wordmark: "Wordmark (the name alone)",
|
|
73
|
+
};
|
|
74
|
+
const LOGO_BACKGROUND_LABELS = {
|
|
75
|
+
both: "Both backgrounds",
|
|
76
|
+
onLight: "Light backgrounds (usually dark artwork)",
|
|
77
|
+
onDark: "Dark backgrounds (usually light artwork)",
|
|
73
78
|
};
|
|
74
79
|
const CELL_FILLS = [
|
|
75
80
|
["", "No fill"],
|
|
@@ -667,7 +672,7 @@ export function createDesignControls(container, options = {}) {
|
|
|
667
672
|
{ value: "footer", label: "Footer" },
|
|
668
673
|
]);
|
|
669
674
|
furniture.set(pick.which);
|
|
670
|
-
const zoneSelect = selectField("hf-zone", "Zone", { help: "
|
|
675
|
+
const zoneSelect = selectField("hf-zone", "Zone", { help: "A zone lays its parts out side by side, from the edge it sits on: image (or logo), text, social profiles, date." });
|
|
671
676
|
zoneSelect.setOptions(HEADER_FOOTER_ZONES.map((value) => ({ value, label: titleCase(value) })));
|
|
672
677
|
zoneSelect.set(pick.zone);
|
|
673
678
|
furniture.select.addEventListener("change", () => {
|
|
@@ -720,12 +725,25 @@ export function createDesignControls(container, options = {}) {
|
|
|
720
725
|
box.focus();
|
|
721
726
|
box.setSelectionRange?.(caret, caret);
|
|
722
727
|
});
|
|
723
|
-
const logo = checkField("hf-logo", "Show the logo", { onChange: (checked) => edit({ logo: checked }, `${where()} logo ${checked ? "shown" : "removed"}.`) });
|
|
724
728
|
const image = imageCluster("hf-image", "Image", {
|
|
725
729
|
apply: (ref) => setHeaderFooterZone(editor, which(), zone(), { image: ref }, scoped()),
|
|
726
730
|
build: (ref, doc) => prepareHeaderFooterZone(doc, which(), zone(), { image: ref }, scoped()),
|
|
727
|
-
help: "A picture in this zone, such as a partner mark or badge
|
|
731
|
+
help: "A picture in this zone, such as a partner mark or badge: an asset reference, a web address or a data address, or an organization logo (Insert logo, below). Press Enter to apply; clear the field to remove it.",
|
|
728
732
|
});
|
|
733
|
+
// RR-71: a logo is the zone's image, written as a reference to the organization's logo (var:organization.logo.icon). Which artwork is drawn (light or dark) follows each slide's background.
|
|
734
|
+
const logoShape = selectField("hf-logo-shape", "Logo shape", { help: "Icon is the mark alone and fits a zone best." });
|
|
735
|
+
logoShape.setOptions(LOGO_SHAPES.map((value) => ({ value, label: LOGO_SHAPE_LABELS[value] })));
|
|
736
|
+
logoShape.set("icon");
|
|
737
|
+
const logoOrganization = selectField("hf-logo-organization", "Logo of", { empty: "Primary organization", help: "Choose another organization when the deck has several." });
|
|
738
|
+
const insertLogoButton = button("Insert logo", () => {
|
|
739
|
+
const shape = logoShape.select.value;
|
|
740
|
+
const organization = logoOrganization.select.value || undefined;
|
|
741
|
+
run(() => insertZoneLogo(editor, which(), zone(), { ...scoped(), shape, ...(organization ? { organization } : {}) }), `${where()} now shows the ${shape} logo (${logoReference({ ...(organization ? { organization } : {}), ...(shape !== "full" ? { shape } : {}) })}), replacing any image.`);
|
|
742
|
+
});
|
|
743
|
+
insertLogoButton.dataset.action = "insert-logo";
|
|
744
|
+
const logoHelp = h("p", { class: "opf-dc-help", id: `${uid}-hf-logo-help` }, "Puts the organization's logo in this zone as its image. The logo comes from the organization's logo settings; add it under Logo, watermark and bullets.");
|
|
745
|
+
insertLogoButton.setAttribute("aria-describedby", logoHelp.id);
|
|
746
|
+
const logo = { wrap: h("fieldset", { class: "opf-dc-fieldset", "data-role": "hf-logo" }, h("legend", {}, "Logo"), logoShape.wrap, logoOrganization.wrap, h("div", { class: "opf-dc-actions" }, insertLogoButton), logoHelp) };
|
|
729
747
|
const dateNow = checkField("hf-date-now", "Show the current date", {
|
|
730
748
|
help: "Needs the host to supply today's date when it renders or exports; otherwise the part is reported as unresolved.",
|
|
731
749
|
onChange: (checked) => edit({ date: checked }, `${where()} date ${checked ? "shown" : "removed"}.`),
|
|
@@ -764,14 +782,24 @@ export function createDesignControls(container, options = {}) {
|
|
|
764
782
|
text.input.value = textValue;
|
|
765
783
|
}
|
|
766
784
|
text.set(textValue);
|
|
767
|
-
logo.set(fields.logo === true);
|
|
768
785
|
image.set(stringOf(fields.image), "", `${target()}:${which()}:${zone()}`);
|
|
786
|
+
// The logo menus follow the organizations, and show the logo the zone already has.
|
|
787
|
+
const organizations = listOrganizations(editor.presentation);
|
|
788
|
+
logoOrganization.setOptions(organizations.filter((entry) => entry.id).map((entry) => ({ value: entry.id, label: entry.name ? `${entry.name} (${entry.id})` : entry.id })));
|
|
789
|
+
logoOrganization.wrap.hidden = organizations.length < 2;
|
|
790
|
+
const shown = parseLogoReference(fields.image);
|
|
791
|
+
if (shown) {
|
|
792
|
+
logoShape.set(shown.shape ?? "full");
|
|
793
|
+
logoOrganization.set(shown.organization ?? "");
|
|
794
|
+
}
|
|
795
|
+
|
|
769
796
|
dateNow.set(fields.date === true);
|
|
770
797
|
dateFixed.set(typeof fields.date === "string" ? fields.date : "");
|
|
771
798
|
dateFormat.set(typeof fields.dateFormat === "string" ? fields.dateFormat : "");
|
|
772
799
|
socials.set(fields.socials === true);
|
|
773
800
|
insertValue.set("");
|
|
774
801
|
for (const control of controls) for (const input of control.wrap.querySelectorAll("input,select,textarea,button")) input.disabled = state.hidden;
|
|
802
|
+
insertLogoButton.disabled = state.hidden || !listOrganizations(editor.presentation).length;
|
|
775
803
|
summary.replaceChildren(
|
|
776
804
|
...HEADER_FOOTER_ZONES.map((name) => {
|
|
777
805
|
const zoneFields = readHeaderFooterZone(editor.presentation, which(), name, scoped());
|
|
@@ -786,20 +814,109 @@ export function createDesignControls(container, options = {}) {
|
|
|
786
814
|
|
|
787
815
|
if (built.brand) {
|
|
788
816
|
const { body } = built.brand;
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
817
|
+
// RR-71: logos live on the organization. One image serves every shape, or each of the four shapes (full, stacked, icon,
|
|
818
|
+
// wordmark) has its own, optionally split by the background it is drawn on (light or dark).
|
|
819
|
+
const logoOrganizationPick = selectField("org-logo-organization", "Organization to edit", {
|
|
820
|
+
help: "Whose logo to edit. The primary organization's full logo is drawn on cover and section slides.",
|
|
821
|
+
onChange: () => sync(),
|
|
822
|
+
});
|
|
823
|
+
const logoShapePick = selectField("org-logo-shape", "Shape to edit", {
|
|
824
|
+
help: "All shapes sets one image for every place the logo is drawn. Set a shape to give it its own image; a missing shape falls back to the full logo.",
|
|
825
|
+
onChange: () => sync(),
|
|
796
826
|
});
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
827
|
+
logoShapePick.setOptions(["all", ...LOGO_SHAPES].map((value) => ({ value, label: LOGO_SHAPE_LABELS[value] })));
|
|
828
|
+
logoShapePick.set("all");
|
|
829
|
+
const logoBackgroundPick = selectField("org-logo-background", "Background to edit", {
|
|
830
|
+
help: "Use a different image on light and on dark backgrounds. Each slide draws the one that suits its background; a missing one uses the other.",
|
|
831
|
+
onChange: () => sync(),
|
|
802
832
|
});
|
|
833
|
+
logoBackgroundPick.setOptions(LOGO_BACKGROUNDS.map((value) => ({ value, label: LOGO_BACKGROUND_LABELS[value] })));
|
|
834
|
+
logoBackgroundPick.set("both");
|
|
835
|
+
const logoTarget = () => ({ shape: logoShapePick.select.value, background: logoShapePick.select.value === "all" ? "both" : logoBackgroundPick.select.value, organization: Number(logoOrganizationPick.select.value || 0) });
|
|
836
|
+
const orgLogo = imageCluster("org-logo", "Organization logo", {
|
|
837
|
+
apply: (ref) => {
|
|
838
|
+
const { shape, ...rest } = logoTarget();
|
|
839
|
+
return setOrganizationLogo(editor, shape, ref, rest);
|
|
840
|
+
},
|
|
841
|
+
build: (ref, doc) => {
|
|
842
|
+
const { shape, ...rest } = logoTarget();
|
|
843
|
+
return prepareOrganizationLogo(doc, shape, ref, rest);
|
|
844
|
+
},
|
|
845
|
+
help: "An asset reference, a web address or a data address for the chosen shape and background. Press Enter to apply; clear the field to remove it.",
|
|
846
|
+
});
|
|
847
|
+
const logoSummary = h("ul", { class: "opf-dc-summary", "aria-label": "Logo shapes set" });
|
|
848
|
+
const organizationLogoGroup = h("fieldset", { class: "opf-dc-fieldset", "data-role": "organization-logo" }, h("legend", {}, "Organization logo"), logoOrganizationPick.wrap, logoShapePick.wrap, logoBackgroundPick.wrap, orgLogo.wrap, logoSummary);
|
|
849
|
+
const logoSummaryText = (state) => {
|
|
850
|
+
if (!state) return ["No organization yet: add one to give it a logo."];
|
|
851
|
+
if (state.all !== undefined) return ["One image for every shape."];
|
|
852
|
+
const rows = LOGO_SHAPES.filter((shape) => state.shapes[shape]).map((shape) => {
|
|
853
|
+
const entry = state.shapes[shape];
|
|
854
|
+
return `${titleCase(shape)}: ${entry.both !== undefined ? "both backgrounds" : [entry.onLight !== undefined ? "light backgrounds" : "", entry.onDark !== undefined ? "dark backgrounds" : ""].filter(Boolean).join(" and ")}`;
|
|
855
|
+
});
|
|
856
|
+
return rows.length ? rows : ["No logo yet."];
|
|
857
|
+
};
|
|
858
|
+
const syncOrganizationLogo = () => {
|
|
859
|
+
const organizations = listOrganizations(editor.presentation);
|
|
860
|
+
const wanted = logoOrganizationPick.select.value;
|
|
861
|
+
logoOrganizationPick.setOptions(organizations.map((entry) => ({ value: String(entry.index), label: `${entry.name ?? entry.id ?? `Organization ${entry.index + 1}`}${entry.primary ? " (primary)" : ""}` })));
|
|
862
|
+
const fallback = organizations.find((entry) => entry.primary) ?? organizations[0];
|
|
863
|
+
logoOrganizationPick.set(organizations.some((entry) => String(entry.index) === wanted) ? wanted : String(fallback?.index ?? ""));
|
|
864
|
+
logoOrganizationPick.wrap.hidden = organizations.length < 2;
|
|
865
|
+
const all = logoShapePick.select.value === "all";
|
|
866
|
+
logoBackgroundPick.wrap.hidden = all;
|
|
867
|
+
const state = organizations.length ? readOrganizationLogo(editor.presentation, { organization: Number(logoOrganizationPick.select.value) }) : null;
|
|
868
|
+
const { shape, background } = logoTarget();
|
|
869
|
+
const entry = shape === "all" ? undefined : state?.shapes[shape];
|
|
870
|
+
let value = "";
|
|
871
|
+
let note = "";
|
|
872
|
+
if (shape === "all") value = stringOf(state?.all);
|
|
873
|
+
else if (entry) value = stringOf(background === "both" ? entry.both : entry[background]);
|
|
874
|
+
else if (state?.all !== undefined) note = "uses the image for all shapes";
|
|
875
|
+
if (shape !== "all" && entry?.both !== undefined && background !== "both") note = "uses the image for both backgrounds";
|
|
876
|
+
if (shape !== "all" && background === "both" && entry && entry.both === undefined) note = "set per background";
|
|
877
|
+
orgLogo.set(value, note, `logo:${logoOrganizationPick.select.value}:${shape}:${background}`);
|
|
878
|
+
for (const input of [...orgLogo.wrap.querySelectorAll("input"), ...logoShapePick.wrap.querySelectorAll("select"), ...logoBackgroundPick.wrap.querySelectorAll("select")]) input.disabled = !organizations.length;
|
|
879
|
+
logoSummary.replaceChildren(...logoSummaryText(state).map((line) => h("li", {}, line)));
|
|
880
|
+
};
|
|
881
|
+
// The logo that covers, sections and picture bullets draw: the primary organization's by default, another organization's or shape, or none.
|
|
882
|
+
const choiceOrganizationPick = selectField("design-logo-organization", "Logo for covers, sections and bullets", {
|
|
883
|
+
empty: "Primary organization",
|
|
884
|
+
help: "Which organization's logo covers and sections draw, and picture bullets use. Choose None to draw no logo.",
|
|
885
|
+
onChange: () => applyLogoChoice(),
|
|
886
|
+
});
|
|
887
|
+
const choiceShapePick = selectField("design-logo-shape", "Shape to draw", {
|
|
888
|
+
empty: "Default (full; icon for bullets)",
|
|
889
|
+
help: "Choose a shape to draw it instead of the default for that place. A missing shape falls back to the full logo.",
|
|
890
|
+
onChange: () => applyLogoChoice(),
|
|
891
|
+
});
|
|
892
|
+
choiceShapePick.setOptions(LOGO_SHAPES.map((value) => ({ value, label: LOGO_SHAPE_LABELS[value] })));
|
|
893
|
+
const logoChoiceGroup = h("fieldset", { class: "opf-dc-fieldset", "data-role": "design-logo" }, h("legend", {}, "Which logo to draw"), choiceOrganizationPick.wrap, choiceShapePick.wrap);
|
|
894
|
+
const applyLogoChoice = () => {
|
|
895
|
+
const organization = choiceOrganizationPick.select.value;
|
|
896
|
+
const shape = choiceShapePick.select.value || undefined;
|
|
897
|
+
let value;
|
|
898
|
+
if (organization === "none") value = false;
|
|
899
|
+
else if (organization === "" && shape === undefined) value = null;
|
|
900
|
+
else value = logoReference({ ...(organization !== "" && organization !== "primary" ? { organization } : {}), ...(shape ? { shape } : {}) });
|
|
901
|
+
run(() => setDesignOption(editor, "logo", value, scoped()), value === null ? "Logo set to the primary organization's." : value === false ? "No logo is drawn." : `Logo set to ${value}.`);
|
|
902
|
+
};
|
|
903
|
+
const syncLogoChoice = () => {
|
|
904
|
+
const choice = readLogoChoice(editor.presentation, scoped());
|
|
905
|
+
const entries = listOrganizations(editor.presentation)
|
|
906
|
+
.filter((entry) => entry.id)
|
|
907
|
+
.map((entry) => ({ value: entry.id, label: `${entry.name ?? entry.id}${entry.primary ? " (primary)" : ""}` }));
|
|
908
|
+
// On a slide, an explicit reference to the primary organization overrides a logo setting the presentation made.
|
|
909
|
+
if (state.scope === "slide" && editor.presentation.design?.logo !== undefined) entries.unshift({ value: "primary", label: "Primary organization (instead of the presentation's setting)" });
|
|
910
|
+
entries.push({ value: "none", label: "None" });
|
|
911
|
+
choiceOrganizationPick.setOptions(entries);
|
|
912
|
+
let organization = "";
|
|
913
|
+
if (choice.mode === "none") organization = "none";
|
|
914
|
+
else if (choice.mode === "custom") organization = String(choice.value);
|
|
915
|
+
else if (choice.mode === "reference") organization = choice.organization ?? (state.scope === "slide" && choice.shape === undefined ? "primary" : "");
|
|
916
|
+
choiceOrganizationPick.set(organization, sourceNote(choice.scope, choice.value !== undefined));
|
|
917
|
+
choiceShapePick.set(choice.mode === "reference" ? (choice.shape ?? "") : "");
|
|
918
|
+
for (const input of choiceShapePick.wrap.querySelectorAll("select")) input.disabled = choice.mode === "none";
|
|
919
|
+
};
|
|
803
920
|
const bullet = selectField("list-bullet", "List bullets", {
|
|
804
921
|
empty: "Default (character)",
|
|
805
922
|
help: "Picture bullets draw the logo as the marker and need a logo.",
|
|
@@ -839,16 +956,12 @@ export function createDesignControls(container, options = {}) {
|
|
|
839
956
|
const watermarkOff = checkField("watermark-off", "Hide the inherited watermark", {
|
|
840
957
|
onChange: (checked) => run(() => setDesignOption(editor, "watermark", checked ? false : null, scoped()), checked ? "Watermark hidden." : "Watermark restored."),
|
|
841
958
|
});
|
|
842
|
-
body.append(
|
|
959
|
+
body.append(organizationLogoGroup, logoChoiceGroup, bullet.wrap, accent.wrap, watermarkSource.wrap, watermarkText.wrap, watermarkOpacity.wrap, watermarkOff.wrap);
|
|
843
960
|
const warningList = h("ul", { class: "opf-dc-warnings", "aria-label": "Logo warnings" });
|
|
844
961
|
body.append(warningList);
|
|
845
962
|
syncs.push(() => {
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
const organization = editor.presentation.organization;
|
|
849
|
-
const owner = Array.isArray(organization) ? organization[0] : organization;
|
|
850
|
-
orgLogo.set(stringOf(owner?.logo), "", "org");
|
|
851
|
-
for (const input of orgLogo.wrap.querySelectorAll("input")) input.disabled = !owner;
|
|
963
|
+
syncOrganizationLogo();
|
|
964
|
+
syncLogoChoice();
|
|
852
965
|
const bulletOption = getDesignOption(editor.presentation, "listBullet", scoped());
|
|
853
966
|
bullet.set(bulletOption.value ?? "", sourceNote(bulletOption.scope, bulletOption.value !== undefined));
|
|
854
967
|
const accentOption = getDesignOption(editor.presentation, "accentFont", scoped());
|
|
@@ -863,7 +976,7 @@ export function createDesignControls(container, options = {}) {
|
|
|
863
976
|
const own = scopeIndex() === undefined ? editor.presentation.design?.watermark : editor.presentation.slides?.[scopeIndex()]?.design?.watermark;
|
|
864
977
|
watermarkOff.set(own === false);
|
|
865
978
|
watermarkOff.wrap.hidden = state.scope !== "slide";
|
|
866
|
-
warningList.replaceChildren(...designWarnings(editor.presentation, getSlide()).filter((warning) => warning.path === "design.listBullet").map((warning) => h("li", {}, warning.message)));
|
|
979
|
+
warningList.replaceChildren(...designWarnings(editor.presentation, getSlide()).filter((warning) => warning.path === "design.listBullet" || /^(slides\.\d+\.)?design\.logo$/.test(warning.path)).map((warning) => h("li", {}, warning.message)));
|
|
867
980
|
});
|
|
868
981
|
}
|
|
869
982
|
|
package/dist/design-options.d.ts
CHANGED
|
@@ -10,22 +10,25 @@ export type DesignOptionId =
|
|
|
10
10
|
| "imageFit"
|
|
11
11
|
| "accentFont"
|
|
12
12
|
| "logo"
|
|
13
|
-
| "organizationLogo"
|
|
14
13
|
| "watermark";
|
|
15
14
|
export interface DesignOptionDescriptor {
|
|
16
15
|
id: DesignOptionId;
|
|
17
16
|
label: string;
|
|
18
|
-
type: "enum" | "boolean" | "font" | "logo" | "
|
|
17
|
+
type: "enum" | "boolean" | "font" | "logo" | "watermark";
|
|
19
18
|
/** Allowed values of an enum option. */
|
|
20
19
|
values?: readonly string[];
|
|
21
20
|
scopes: ("deck" | "slide")[];
|
|
22
21
|
path: string;
|
|
23
22
|
}
|
|
24
23
|
export declare const DESIGN_OPTIONS: readonly DesignOptionDescriptor[];
|
|
25
|
-
|
|
26
|
-
export
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
/** The shapes an organization's logo can have (core's `LOGO_SHAPES`). */
|
|
25
|
+
export declare const LOGO_SHAPES: readonly ["full", "stacked", "icon", "wordmark"];
|
|
26
|
+
export type LogoShape = (typeof LOGO_SHAPES)[number];
|
|
27
|
+
/** The backgrounds a logo shape can be split by: one image for `both`, or one for `onLight` and one for `onDark` backgrounds. */
|
|
28
|
+
export declare const LOGO_BACKGROUNDS: readonly ["both", "onLight", "onDark"];
|
|
29
|
+
export type LogoBackground = (typeof LOGO_BACKGROUNDS)[number];
|
|
30
|
+
/** Every field a header or footer zone can hold. The logo is the zone's `image` (`var:organization.logo.icon`, see `insertZoneLogo`). */
|
|
31
|
+
export declare const ZONE_FIELDS: readonly ["text", "image", "date", "dateFormat", "socials"];
|
|
29
32
|
/** One entry of a zone's "Insert value" menu: the built-in variable `name`, its menu `label` and the `token` (`{{name}}`) that lands in the zone's `text`. */
|
|
30
33
|
export interface ZoneValue {
|
|
31
34
|
readonly name: "slide.number" | "deck.slideCount" | "slide.section" | "organization.name" | "speaker.name" | "deck.name";
|
|
@@ -40,12 +43,10 @@ export declare const HEADER_FOOTER_ZONES: readonly ["left", "center", "right"];
|
|
|
40
43
|
export type HeaderFooterZone = (typeof HEADER_FOOTER_ZONES)[number];
|
|
41
44
|
|
|
42
45
|
export interface DesignOptionOptions {
|
|
43
|
-
/** One slide instead of the deck.
|
|
46
|
+
/** One slide instead of the deck. */
|
|
44
47
|
slideIndex?: number;
|
|
45
48
|
/** Deck scope: also remove slide-level values that would hide the change. */
|
|
46
49
|
clearSlideOverrides?: boolean;
|
|
47
|
-
/** organizationLogo with several organizations (default 0). */
|
|
48
|
-
index?: number;
|
|
49
50
|
/** Session change metadata (session forms only). */
|
|
50
51
|
meta?: Record<string, unknown>;
|
|
51
52
|
}
|
|
@@ -58,15 +59,14 @@ export interface PreparedDesignOption {
|
|
|
58
59
|
option: string;
|
|
59
60
|
scope: "deck" | "slide";
|
|
60
61
|
slideIndex?: number;
|
|
61
|
-
/** The
|
|
62
|
-
variant?: string;
|
|
62
|
+
/** The header/footer zone an edit named. */
|
|
63
63
|
zone?: string;
|
|
64
64
|
presentation: unknown;
|
|
65
65
|
patches: JsonPatchOperation[];
|
|
66
66
|
changed: boolean;
|
|
67
67
|
/** Slides whose own design hides a deck-level change. */
|
|
68
68
|
shadowed: number[];
|
|
69
|
-
/** Settings that need a logo the document does not have. */
|
|
69
|
+
/** Settings that need a logo or other content the document does not have. */
|
|
70
70
|
warnings: DesignWarning[];
|
|
71
71
|
}
|
|
72
72
|
export interface DesignOptionChange extends Omit<EditorChange, "presentation" | "patches"> {
|
|
@@ -85,14 +85,60 @@ export declare function prepareDesignOption(presentation: unknown, option: Desig
|
|
|
85
85
|
/** Set one option as a single undoable transaction. */
|
|
86
86
|
export declare function setDesignOption(editor: EditorSession, option: DesignOptionId, value: unknown, options?: DesignOptionOptions): DesignOptionChange;
|
|
87
87
|
/** `{ value, scope, inherited }`; scope is "slide", "deck" or "default". */
|
|
88
|
-
export declare function getDesignOption(presentation: unknown, option: DesignOptionId, options?: Pick<DesignOptionOptions, "slideIndex"
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
export declare function getDesignOption(presentation: unknown, option: DesignOptionId, options?: Pick<DesignOptionOptions, "slideIndex">): { value: unknown; scope: "slide" | "deck" | "default"; inherited: boolean };
|
|
89
|
+
/** A parsed `var:organization(.<id>)?.logo(.<shape>)?` reference: the organization's id (absent: the primary organization) and the shape when the reference names one. */
|
|
90
|
+
export interface LogoReference {
|
|
91
|
+
organization?: string;
|
|
92
|
+
shape?: LogoShape;
|
|
93
|
+
}
|
|
94
|
+
/** Parse a logo reference, or null for any other string. */
|
|
95
|
+
export declare function parseLogoReference(text: unknown): LogoReference | null;
|
|
96
|
+
/** Write a logo reference: `logoReference({ organization: "beta", shape: "icon" })` is `"var:organization.beta.logo.icon"`. */
|
|
97
|
+
export declare function logoReference(reference?: LogoReference): string;
|
|
98
|
+
/** What `design.logo` takes: `null` (unset: the primary organization's logo), `false` (no logo), a reference, or the organization and shape to write as one. */
|
|
99
|
+
export type LogoChoice = null | false | string | LogoReference;
|
|
100
|
+
export interface OrganizationEntry {
|
|
101
|
+
index: number;
|
|
102
|
+
/** What a `var:` reference addresses; an organization without one is only reachable as the primary organization. */
|
|
103
|
+
id?: string;
|
|
104
|
+
name?: string;
|
|
105
|
+
/** The organization the unset logo and `var:organization.logo` mean (`role: "primary"`, else the first). */
|
|
106
|
+
primary: boolean;
|
|
107
|
+
hasLogo: boolean;
|
|
108
|
+
}
|
|
109
|
+
/** The deck's organizations (a single organization object is a list of one). */
|
|
110
|
+
export declare function listOrganizations(presentation: unknown): OrganizationEntry[];
|
|
111
|
+
export interface OrganizationLogoOptions extends Omit<DesignOptionOptions, "slideIndex" | "clearSlideOverrides"> {
|
|
112
|
+
/** The organization's index or id (default: the primary organization). */
|
|
113
|
+
organization?: number | string;
|
|
114
|
+
/** `both` (default): one image for the shape. `onLight` or `onDark`: the image for that background only. Not with shape `all`. */
|
|
115
|
+
background?: LogoBackground;
|
|
116
|
+
}
|
|
117
|
+
/** Compute the patch that sets or clears (`null`) the organization's logo: `all` is one image for every shape, otherwise one shape (for one background or both). */
|
|
118
|
+
export declare function prepareOrganizationLogo(presentation: unknown, shape: "all" | LogoShape, source: string | Record<string, unknown> | null, options?: Omit<OrganizationLogoOptions, "meta">): PreparedDesignOption & { shape: "all" | LogoShape; background: LogoBackground; organization: number };
|
|
119
|
+
/** Set or clear the organization's logo as a single undoable transaction. */
|
|
120
|
+
export declare function setOrganizationLogo(editor: EditorSession, shape: "all" | LogoShape, source: string | Record<string, unknown> | null, options?: OrganizationLogoOptions): DesignOptionChange;
|
|
121
|
+
export interface OrganizationLogoState {
|
|
122
|
+
organization: OrganizationEntry;
|
|
123
|
+
/** The bare image when one image serves every shape. */
|
|
124
|
+
all?: unknown;
|
|
125
|
+
/** The shapes the logo sets: `{ both }` for one image, or `{ onLight?, onDark? }`. */
|
|
126
|
+
shapes: Partial<Record<LogoShape, { both?: unknown; onLight?: unknown; onDark?: unknown }>>;
|
|
127
|
+
}
|
|
128
|
+
/** An organization's logo as a panel shows it; null when the deck has no organization. */
|
|
129
|
+
export declare function readOrganizationLogo(presentation: unknown, options?: Pick<OrganizationLogoOptions, "organization">): OrganizationLogoState | null;
|
|
130
|
+
export interface LogoChoiceState {
|
|
131
|
+
/** "primary" (unset), "none" (false), "reference" (a logo reference) or "custom" (any other value). */
|
|
132
|
+
mode: "primary" | "none" | "reference" | "custom";
|
|
133
|
+
organization?: string;
|
|
134
|
+
shape?: LogoShape;
|
|
135
|
+
value: unknown;
|
|
136
|
+
scope: "slide" | "deck" | "default";
|
|
137
|
+
inherited: boolean;
|
|
138
|
+
}
|
|
139
|
+
/** The `design.logo` choice at a scope. */
|
|
140
|
+
export declare function readLogoChoice(presentation: unknown, options?: Pick<DesignOptionOptions, "slideIndex">): LogoChoiceState;
|
|
94
141
|
export interface HeaderFooterZoneFields {
|
|
95
|
-
logo?: boolean | null;
|
|
96
142
|
text?: string | null;
|
|
97
143
|
image?: string | Record<string, unknown> | null;
|
|
98
144
|
date?: boolean | string | null;
|
|
@@ -113,11 +159,21 @@ export interface ZoneValueOptions extends DesignOptionOptions {
|
|
|
113
159
|
export declare function prepareZoneValue(presentation: unknown, which: "header" | "footer", zone: HeaderFooterZone, name: ZoneValue["name"], options?: ZoneValueOptions): PreparedDesignOption;
|
|
114
160
|
/** Insert a value's token into one zone's `text` as a single undoable transaction. */
|
|
115
161
|
export declare function insertZoneValue(editor: EditorSession, which: "header" | "footer", zone: HeaderFooterZone, name: ZoneValue["name"], options?: ZoneValueOptions): DesignOptionChange;
|
|
162
|
+
export interface ZoneLogoOptions extends DesignOptionOptions {
|
|
163
|
+
/** The shape to show (default `icon`). */
|
|
164
|
+
shape?: LogoShape;
|
|
165
|
+
/** The organization's id (default: the primary organization). */
|
|
166
|
+
organization?: string;
|
|
167
|
+
}
|
|
168
|
+
/** The patch that makes a zone show an organization's logo: its `image` becomes `var:organization.logo.<shape>` (`var:organization.<id>.logo.<shape>` for a named organization). */
|
|
169
|
+
export declare function prepareZoneLogo(presentation: unknown, which: "header" | "footer", zone: HeaderFooterZone, options?: ZoneLogoOptions): PreparedDesignOption;
|
|
170
|
+
/** Make a zone show an organization's logo as a single undoable transaction. */
|
|
171
|
+
export declare function insertZoneLogo(editor: EditorSession, which: "header" | "footer", zone: HeaderFooterZone, options?: ZoneLogoOptions): DesignOptionChange;
|
|
116
172
|
/** One zone's fields as they apply at a scope: the slide's own header or footer when it has one, else the deck's. */
|
|
117
173
|
export declare function readHeaderFooterZone(presentation: unknown, which: "header" | "footer", zone: HeaderFooterZone, options?: Pick<DesignOptionOptions, "slideIndex">): HeaderFooterZoneFields;
|
|
118
174
|
/** Whether the scope sets the header or footer itself (`own`), shows the deck's (`inherited`) or hides it with `false` (`hidden`). */
|
|
119
175
|
export declare function headerFooterState(presentation: unknown, which: "header" | "footer", options?: Pick<DesignOptionOptions, "slideIndex">): { own: boolean; inherited: boolean; hidden: boolean };
|
|
120
|
-
/** Whether a logo resolves for the slide:
|
|
121
|
-
export declare function hasResolvableLogo(presentation: unknown, slideIndex: number): boolean;
|
|
122
|
-
/** Settings that need content the document does not have: a logo (
|
|
176
|
+
/** Whether a logo resolves for the slide: its `design.logo`, then the deck's, then the primary organization's (`shape`: the shape asked for, default full). */
|
|
177
|
+
export declare function hasResolvableLogo(presentation: unknown, slideIndex: number, options?: { shape?: LogoShape }): boolean;
|
|
178
|
+
/** Settings that need content the document does not have: a logo (a zone image or `design.logo` that names a logo no organization has, picture bullets), the organization's social profiles, or a value a zone's `text` asks for (`{{organization.name}}` without an organization, `{{slide.section}}` on a slide without a section). */
|
|
123
179
|
export declare function designWarnings(presentation: unknown, slideIndex?: number): DesignWarning[];
|