ooxml-ui 1.16.0 → 1.17.0
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/custom-elements.json +66 -0
- package/dist/{chunk-QUG6IRQQ.js → chunk-CQ5BMX2Z.js} +3 -2
- package/dist/{chunk-CHFMXUPK.js → chunk-KRQ5T2GX.js} +166 -2
- package/dist/{chunk-JVNIZBG7.js → chunk-VCXKKGQZ.js} +1 -1
- package/dist/{chunk-UIVYZERK.js → chunk-VUSDTDZS.js} +1 -1
- package/dist/controls.d.ts +4 -2
- package/dist/controls.d.ts.map +1 -1
- package/dist/controls.js +1 -1
- package/dist/dialog/chart-picker.d.ts +78 -0
- package/dist/dialog/chart-picker.d.ts.map +1 -0
- package/dist/docx.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/dist/teams.js +2 -2
- package/dist/visio/controller.d.ts +3 -0
- package/dist/visio/ribbon-action.d.ts +1 -1
- package/dist/visio/viewer-insert-chart.d.ts +40 -0
- package/dist/visio/viewer-insert.d.ts +2 -0
- package/dist/visio/viewer-options-categories.d.ts +2 -0
- package/dist/visio/viewer-options.d.ts +14 -1
- package/dist/visio/viewer-screen-tips.d.ts +10 -0
- package/dist/visio.js +291 -25
- package/dist/xlsx/commands/insert.d.ts +1 -0
- package/dist/xlsx.js +54 -87
- package/package.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type OfficeProfile } from '../controls.js';
|
|
2
2
|
import { VISIO_OPTION_CATEGORIES } from './viewer-options-categories.js';
|
|
3
|
+
import { type ScreenTipStyle } from './viewer-screen-tips.js';
|
|
3
4
|
export { VISIO_OPTION_CATEGORIES };
|
|
4
5
|
/** The status bar's look: Visio's product colour ("Colorful") or the neutral suite bar. */
|
|
5
6
|
export type StatusBarTheme = 'colorful' | 'neutral';
|
|
@@ -8,6 +9,14 @@ export declare const isStatusBarTheme: (value: unknown) => value is StatusBarThe
|
|
|
8
9
|
export declare function readStatusBarTheme(): StatusBarTheme | undefined;
|
|
9
10
|
/** Office Theme as Options offers it: the two light looks, or the dark theme. */
|
|
10
11
|
export type OfficeThemeChoice = StatusBarTheme | 'dark';
|
|
12
|
+
/** The Options that change how the viewer behaves, remembered on this device. */
|
|
13
|
+
export interface VisioBehaviour {
|
|
14
|
+
screenTips: ScreenTipStyle;
|
|
15
|
+
undoLevels: number;
|
|
16
|
+
}
|
|
17
|
+
export declare const DEFAULT_BEHAVIOUR: VisioBehaviour;
|
|
18
|
+
/** The behaviour Options saved on this device (storage may be unavailable or hold junk). */
|
|
19
|
+
export declare function readBehaviour(): VisioBehaviour;
|
|
11
20
|
/** The Options dialog element. Built once and appended to the viewer's shadow root. */
|
|
12
21
|
export declare function createOptionsDialog(doc: Document): HTMLElement;
|
|
13
22
|
/**
|
|
@@ -19,12 +28,16 @@ export declare class ViewerProfile {
|
|
|
19
28
|
private readonly onProfile;
|
|
20
29
|
/** Reads and applies the Office Theme on the viewer element. */
|
|
21
30
|
private readonly theme;
|
|
31
|
+
/** Applies the behaviour Options (ScreenTip style, undo depth), now and after each change. */
|
|
32
|
+
private readonly onBehaviour;
|
|
22
33
|
constructor(root: ShadowRoot, onProfile?: (profile: OfficeProfile) => void,
|
|
23
34
|
/** Reads and applies the Office Theme on the viewer element. */
|
|
24
35
|
theme?: {
|
|
25
36
|
get(): OfficeThemeChoice;
|
|
26
37
|
set(theme: OfficeThemeChoice): void;
|
|
27
|
-
}
|
|
38
|
+
},
|
|
39
|
+
/** Applies the behaviour Options (ScreenTip style, undo depth), now and after each change. */
|
|
40
|
+
onBehaviour?: (behaviour: VisioBehaviour) => void);
|
|
28
41
|
get profile(): OfficeProfile;
|
|
29
42
|
/** Open Visio Options, on General as Visio does. */
|
|
30
43
|
showOptions(category?: string): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Office's ScreenTip style: full tips, the name alone, or none. */
|
|
2
|
+
export type ScreenTipStyle = 'descriptions' | 'plain' | 'off';
|
|
3
|
+
export declare const isScreenTipStyle: (value: unknown) => value is ScreenTipStyle;
|
|
4
|
+
/** Put back every tip `applyScreenTips` set aside (before the ribbon is translated again). */
|
|
5
|
+
export declare function restoreScreenTips(root: ParentNode): void;
|
|
6
|
+
/**
|
|
7
|
+
* Applies the ScreenTip style to a ribbon's `title` tooltips: "plain" drops the shortcut hint,
|
|
8
|
+
* "off" removes the tip. The original is kept so the style can change back.
|
|
9
|
+
*/
|
|
10
|
+
export declare function applyScreenTips(root: ParentNode, style: ScreenTipStyle): void;
|
package/dist/visio.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { trackPointerPan, ownsCaptureLoss } from './chunk-GSXOZCAN.js';
|
|
2
|
-
import { syncRibbonAddIns } from './chunk-
|
|
3
|
-
export { RIBBON_ADD_IN_EVENT } from './chunk-
|
|
2
|
+
import { syncRibbonAddIns } from './chunk-VUSDTDZS.js';
|
|
3
|
+
export { RIBBON_ADD_IN_EVENT } from './chunk-VUSDTDZS.js';
|
|
4
4
|
import { themeBridge, installOfficeUiTheme } from './chunk-7E3HU7RL.js';
|
|
5
|
-
import {
|
|
5
|
+
import { personalizeSection, unavailableCategory, userInterfaceSection, attachKeyTips, registerControls, readOfficeProfile, sanitizeOfficeProfile, writeOfficeProfile, attachRibbonGroupOverflow, defineChartPicker, commentInitials } from './chunk-KRQ5T2GX.js';
|
|
6
6
|
import { getIcon, registerIcon } from './chunk-M6GF5ED2.js';
|
|
7
7
|
import { definePresence } from './chunk-KNC2UEUR.js';
|
|
8
8
|
import './chunk-CWBSXK7P.js';
|
|
@@ -11,6 +11,7 @@ import { VISIO_TEXT_LANGUAGES, VISIO_BULLET_STYLES, FOREIGN_VECTOR_SCENE_LIMITS,
|
|
|
11
11
|
export { TEXT_SEARCH_LIMITS, compatibilityNotes, compatibilityText, demoDocument, eventKeys, propertyKeys } from 'ooxml-core/visio/ui';
|
|
12
12
|
import { VISIO_VISIBILITY_LIMITS, VISIO_BASIC_STENCIL, VISIO_STENCILS, visioOutlineShape, VISIO_SNAP, VISIO_GLUE, VISIO_SHADOW_PRESETS, loadVisio, createVsdx, deserializeVisioClipboard, getVisioPageLayers, resolveVisioPageVisibility, visioLineJumpPaths, visioSnapGlue, VISIO_CLIPBOARD_MAX_CHARS, VISIO_GLOW_TRANSPARENCY, VISIO_METADATA_TEXT_LIMIT, VISIO_PICTURE_MAX_BYTES, inspectVisioRasterImage, visioPageLayout, VISIO_BUILT_IN_THEMES, VISIO_CONNECTOR_ROUTES, visioFilledArrow, layoutVisioFilledArrowLine, visioOpenArrowPath, isVisioChangeShapeTarget, VISIO_CONTAINER_STYLES, VISIO_CALLOUT_STYLES, visioBuiltInStencil, visioFallbackQuickStyle, VISIO_GLOW_SIZES, VISIO_SOFT_EDGE_SIZES, VISIO_REFLECTION_PRESETS, VISIO_BACKGROUND_STYLES, visioBackgroundShapes, VISIO_BORDER_STYLES, visioBorderShapes, checkVisioAlternativeText, VISIO_SHAPE_DATA_TYPES, visioShapeDataRowName, VISIO_CLIPBOARD_MAGIC, visioThemeVariantColors, visioPageThemeColors, visioBuiltInMaster, VISIO_QUICK_STYLE_COLORS, isVisioBuiltInThemeId, readVisioStencil, VISIO_SCALE_UNITS } from 'ooxml-core/visio';
|
|
13
13
|
import { normalizeLocale, interpolate } from 'ooxml-core/i18n';
|
|
14
|
+
import { INSERT_CHART_TYPES, GROUPED_CHART_TYPES, gridChartSvg, gridChart, parseChartGrid } from 'ooxml-core/xlsx/ui';
|
|
14
15
|
import { pushRecentColor, normalizePaletteHex } from 'ooxml-core/color';
|
|
15
16
|
import { resolveRotateHandlePlacement, createRotationDrag, snapAngle } from 'ooxml-core/geometry';
|
|
16
17
|
|
|
@@ -542,6 +543,7 @@ var ViewerController = class {
|
|
|
542
543
|
#sourceGeneration = 0;
|
|
543
544
|
#searchIndex = null;
|
|
544
545
|
#history = null;
|
|
546
|
+
#undoLevels;
|
|
545
547
|
#selectionHistory = /* @__PURE__ */ new WeakMap();
|
|
546
548
|
#selectionIntent = 0;
|
|
547
549
|
#viewIntent = 0;
|
|
@@ -792,7 +794,10 @@ var ViewerController = class {
|
|
|
792
794
|
document2 = await this.parser(Uint8Array.from(owned));
|
|
793
795
|
if (this.#destroyed || id !== this.#loadId) return;
|
|
794
796
|
assertViewableDocument(document2);
|
|
795
|
-
history = new DocumentHistory(
|
|
797
|
+
history = new DocumentHistory(
|
|
798
|
+
owned,
|
|
799
|
+
this.#undoLevels === void 0 ? void 0 : this.#undoLevels + 1
|
|
800
|
+
);
|
|
796
801
|
visible = documentVisibility(document2);
|
|
797
802
|
} catch (cause) {
|
|
798
803
|
if (this.#destroyed || id !== this.#loadId) return;
|
|
@@ -1084,6 +1089,16 @@ var ViewerController = class {
|
|
|
1084
1089
|
return void 0;
|
|
1085
1090
|
}
|
|
1086
1091
|
}
|
|
1092
|
+
/** Number of undo steps kept (File > Options > Advanced); applies to the open drawing at once. */
|
|
1093
|
+
get undoLevels() {
|
|
1094
|
+
return this.#undoLevels;
|
|
1095
|
+
}
|
|
1096
|
+
set undoLevels(levels) {
|
|
1097
|
+
this.#undoLevels = levels;
|
|
1098
|
+
if (!this.#history || levels === void 0) return;
|
|
1099
|
+
this.#history.maxEntries = levels + 1;
|
|
1100
|
+
this.#change({ edit: this.#sourceEditState() });
|
|
1101
|
+
}
|
|
1087
1102
|
async undo() {
|
|
1088
1103
|
return this.#mutate("undo");
|
|
1089
1104
|
}
|
|
@@ -1856,7 +1871,7 @@ var text_tool_default = ".viewport[data-tool='text'] {\n cursor: text;\n touch-a
|
|
|
1856
1871
|
var presentation_default = "/* Visio Presentation Mode: the page fitted on a dark backdrop, chrome-free, read only. */\n.presentation {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: grid;\n place-items: center;\n /* Visio presents on a dark backdrop in every theme. */\n background: #111;\n color: rgb(255 255 255 / 0.82);\n outline: none;\n cursor: default;\n}\n.presentation[hidden] {\n display: none;\n}\n.presentation:fullscreen {\n width: 100%;\n height: 100%;\n}\n.presentation-stage {\n position: absolute;\n inset: 2vmin;\n display: grid;\n place-items: center;\n container-type: size;\n}\n.presentation-stage > .paper {\n height: auto;\n max-width: 100%;\n max-height: 100%;\n margin: 0;\n box-shadow: none;\n}\n.presentation-bar {\n position: absolute;\n right: 12px;\n bottom: 12px;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 2px 4px;\n border-radius: 4px;\n background: rgb(0 0 0 / 0.45);\n font: 12px/1.4 var(--office-font-family, 'Segoe UI', system-ui, sans-serif);\n opacity: 0.35;\n transition: opacity 0.2s;\n}\n.presentation-bar:hover,\n.presentation-bar:focus-within {\n opacity: 1;\n}\n.presentation-bar button {\n display: inline-grid;\n place-items: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: 0;\n border-radius: 3px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n}\n.presentation-bar button:hover:not(:disabled) {\n background: rgb(255 255 255 / 0.16);\n}\n.presentation-bar button:focus-visible {\n outline: 2px solid currentColor;\n outline-offset: -2px;\n}\n.presentation-bar button:disabled {\n opacity: 0.35;\n cursor: default;\n}\n.presentation-page {\n min-width: 6em;\n max-width: 40vw;\n padding: 0 6px;\n overflow: hidden;\n text-align: center;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n@media (prefers-reduced-motion: reduce) {\n .presentation-bar {\n transition: none;\n }\n}\n";
|
|
1857
1872
|
|
|
1858
1873
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/insert.css?raw
|
|
1859
|
-
var insert_default = ".link-dialog label,\n.alt-text-dialog label,\n.screen-tip-dialog label {\n display: grid;\n gap: 4px;\n min-width: min(360px, 80vw);\n margin: 0 0 12px;\n}\n.link-dialog input,\n.link-dialog select,\n.alt-text-dialog input,\n.alt-text-dialog textarea,\n.screen-tip-dialog input {\n box-sizing: border-box;\n width: 100%;\n padding: 6px;\n color: inherit;\n background: var(--_vv-surface);\n border: 1px solid var(--_vv-border);\n border-radius: 3px;\n font: inherit;\n}\n.alt-text-dialog textarea {\n resize: vertical;\n min-height: 90px;\n}\n.accessibility-dialog [aria-live] {\n max-height: 50vh;\n overflow: auto;\n}\n.accessibility-dialog [aria-live] > button {\n display: block;\n width: 100%;\n padding: 8px;\n text-align: left;\n color: inherit;\n background: var(--_vv-surface);\n border: 1px solid var(--_vv-border);\n font: inherit;\n cursor: pointer;\n}\n.link-dialog [role='alert'],\n.alt-text-dialog [role='alert'],\n.screen-tip-dialog [role='alert'] {\n margin: 0;\n color: var(--office-error, #b00020);\n}\n";
|
|
1874
|
+
var insert_default = ".link-dialog label,\n.alt-text-dialog label,\n.screen-tip-dialog label {\n display: grid;\n gap: 4px;\n min-width: min(360px, 80vw);\n margin: 0 0 12px;\n}\n.link-dialog input,\n.link-dialog select,\n.alt-text-dialog input,\n.alt-text-dialog textarea,\n.screen-tip-dialog input {\n box-sizing: border-box;\n width: 100%;\n padding: 6px;\n color: inherit;\n background: var(--_vv-surface);\n border: 1px solid var(--_vv-border);\n border-radius: 3px;\n font: inherit;\n}\n.alt-text-dialog textarea {\n resize: vertical;\n min-height: 90px;\n}\n.accessibility-dialog [aria-live] {\n max-height: 50vh;\n overflow: auto;\n}\n.accessibility-dialog [aria-live] > button {\n display: block;\n width: 100%;\n padding: 8px;\n text-align: left;\n color: inherit;\n background: var(--_vv-surface);\n border: 1px solid var(--_vv-border);\n font: inherit;\n cursor: pointer;\n}\n.link-dialog [role='alert'],\n.alt-text-dialog [role='alert'],\n.screen-tip-dialog [role='alert'] {\n margin: 0;\n color: var(--office-error, #b00020);\n}\n\n.chart-dialog {\n --office-dialog-width: min(640px, 94vw);\n --office-dialog-max-width: min(640px, 94vw);\n}\n.chart-dialog [role='alert'] {\n margin: 8px 0 0;\n color: var(--_vv-danger);\n}\n.chart-dialog [role='alert']:empty {\n display: none;\n}\n";
|
|
1860
1875
|
|
|
1861
1876
|
// raw-css:/home/runner/work/ooxml/ooxml/src/ui/src/visio/styles/page-setup.css?raw
|
|
1862
1877
|
var page_setup_default = ".page-setup-dialog .page-setup-tabs {\n display: flex;\n flex-wrap: wrap;\n gap: 2px;\n margin: 0 0 12px;\n border-bottom: 1px solid var(--_vv-border);\n}\n.page-setup-dialog [role='tab'] {\n padding: 6px 10px;\n color: inherit;\n font: inherit;\n background: transparent;\n border: 1px solid transparent;\n border-bottom: none;\n border-radius: 3px 3px 0 0;\n cursor: pointer;\n}\n.page-setup-dialog [role='tab'][aria-selected='true'] {\n background: var(--_vv-surface);\n border-color: var(--_vv-border);\n font-weight: 600;\n}\n.page-setup-dialog [role='tabpanel'] {\n display: grid;\n gap: 10px;\n min-width: min(420px, 80vw);\n}\n.page-setup-dialog [role='tabpanel'][hidden] {\n display: none;\n}\n.page-setup-dialog label {\n display: grid;\n grid-template-columns: minmax(130px, 1fr) minmax(150px, 1.4fr);\n align-items: center;\n gap: 12px;\n}\n.page-setup-dialog input {\n box-sizing: border-box;\n width: 100%;\n padding: 6px;\n color: inherit;\n background: var(--_vv-surface);\n border: 1px solid var(--_vv-border);\n border-radius: 3px;\n}\n.page-setup-dialog .page-setup-hint {\n max-width: 440px;\n margin: 0;\n font-size: 12px;\n}\n.page-setup-dialog [role='alert'] {\n color: var(--office-error, #b00020);\n}\n.paper .page-break {\n fill: none;\n stroke: #7a7a7a;\n stroke-width: 1.25;\n stroke-dasharray: 6 4;\n vector-effect: non-scaling-stroke;\n}\n@media (max-width: 480px) {\n .page-setup-dialog label {\n grid-template-columns: 1fr;\n gap: 5px;\n }\n}\n";
|
|
@@ -2113,6 +2128,8 @@ var visioThemeBridge = themeBridge(":host > *", {
|
|
|
2113
2128
|
"--office-surface": "var(--_vv-accent-soft)",
|
|
2114
2129
|
"--office-border": "var(--_vv-border)",
|
|
2115
2130
|
"--office-accent": "var(--_vv-accent)",
|
|
2131
|
+
// Hover and selected rows: an opaque accent tint over the page, not the shared cool grey.
|
|
2132
|
+
"--office-selected": "color-mix(in srgb, var(--_vv-accent) 12%, var(--_vv-surface))",
|
|
2116
2133
|
"--office-accent-foreground": "var(--_vv-accent-ink)",
|
|
2117
2134
|
"--office-ring": "var(--_vv-focus)",
|
|
2118
2135
|
"--office-font": "'Segoe UI', Arial, sans-serif"
|
|
@@ -5902,10 +5919,12 @@ function buildInsertPanel(doc, panel) {
|
|
|
5902
5919
|
icon: "visioPicture",
|
|
5903
5920
|
action: { type: "insert", item: "picture" }
|
|
5904
5921
|
}),
|
|
5905
|
-
command(
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5922
|
+
command(doc, {
|
|
5923
|
+
id: "chart",
|
|
5924
|
+
label: "Chart",
|
|
5925
|
+
icon: "visioChart",
|
|
5926
|
+
action: { type: "insert", item: "chart" }
|
|
5927
|
+
}),
|
|
5909
5928
|
command(
|
|
5910
5929
|
doc,
|
|
5911
5930
|
unsupported(
|
|
@@ -8428,6 +8447,28 @@ function localizeRibbon(ribbon, value) {
|
|
|
8428
8447
|
return locale;
|
|
8429
8448
|
}
|
|
8430
8449
|
|
|
8450
|
+
// src/visio/viewer-screen-tips.ts
|
|
8451
|
+
var isScreenTipStyle = (value) => value === "descriptions" || value === "plain" || value === "off";
|
|
8452
|
+
var FULL = "data-screen-tip";
|
|
8453
|
+
var isReason = (tip) => tip.includes(": not available yet.");
|
|
8454
|
+
function restoreScreenTips(root) {
|
|
8455
|
+
for (const element of root.querySelectorAll(`[${FULL}]`)) {
|
|
8456
|
+
element.setAttribute("title", element.getAttribute(FULL));
|
|
8457
|
+
element.removeAttribute(FULL);
|
|
8458
|
+
}
|
|
8459
|
+
}
|
|
8460
|
+
function applyScreenTips(root, style2) {
|
|
8461
|
+
restoreScreenTips(root);
|
|
8462
|
+
if (style2 === "descriptions") return;
|
|
8463
|
+
for (const element of root.querySelectorAll("[title]")) {
|
|
8464
|
+
const tip = element.getAttribute("title");
|
|
8465
|
+
if (isReason(tip)) continue;
|
|
8466
|
+
element.setAttribute(FULL, tip);
|
|
8467
|
+
if (style2 === "off") element.removeAttribute("title");
|
|
8468
|
+
else element.setAttribute("title", tip.replace(/ \([^()]*\)$/, ""));
|
|
8469
|
+
}
|
|
8470
|
+
}
|
|
8471
|
+
|
|
8431
8472
|
// src/visio/ribbon-overflow.ts
|
|
8432
8473
|
var GROUP_ICONS = {
|
|
8433
8474
|
Clipboard: "paste",
|
|
@@ -10856,14 +10897,34 @@ var ViewerPanZoom = class {
|
|
|
10856
10897
|
|
|
10857
10898
|
// src/visio/viewer-options-categories.ts
|
|
10858
10899
|
var visio = { product: "Visio", t: (text2) => text2 };
|
|
10900
|
+
var MAX_UNDO_LEVELS = 19;
|
|
10859
10901
|
var disabled = (reason) => ({ disabled: `Not available yet. ${reason}` });
|
|
10902
|
+
function visioUserInterface() {
|
|
10903
|
+
const section2 = userInterfaceSection(visio);
|
|
10904
|
+
return {
|
|
10905
|
+
...section2,
|
|
10906
|
+
controls: section2.controls.map(
|
|
10907
|
+
(control) => control.key === "screenTips" ? {
|
|
10908
|
+
kind: "select",
|
|
10909
|
+
key: "screenTips",
|
|
10910
|
+
label: control.label,
|
|
10911
|
+
info: "Applies to the ribbon. Commands that are not available always say why.",
|
|
10912
|
+
choices: [
|
|
10913
|
+
{ value: "descriptions", label: "Show ScreenTips with shortcut keys" },
|
|
10914
|
+
{ value: "plain", label: "Don't show shortcut keys in ScreenTips" },
|
|
10915
|
+
{ value: "off", label: "Don't show ScreenTips" }
|
|
10916
|
+
]
|
|
10917
|
+
} : control
|
|
10918
|
+
)
|
|
10919
|
+
};
|
|
10920
|
+
}
|
|
10860
10921
|
var VISIO_OPTION_CATEGORIES = [
|
|
10861
10922
|
{
|
|
10862
10923
|
id: "general",
|
|
10863
10924
|
label: "General",
|
|
10864
10925
|
description: "General options for working with Visio.",
|
|
10865
10926
|
sections: [
|
|
10866
|
-
|
|
10927
|
+
visioUserInterface(),
|
|
10867
10928
|
personalizeSection(
|
|
10868
10929
|
visio,
|
|
10869
10930
|
[
|
|
@@ -10909,8 +10970,8 @@ var VISIO_OPTION_CATEGORIES = [
|
|
|
10909
10970
|
key: "undoLevels",
|
|
10910
10971
|
label: "Number of undo levels",
|
|
10911
10972
|
min: 1,
|
|
10912
|
-
max:
|
|
10913
|
-
|
|
10973
|
+
max: MAX_UNDO_LEVELS,
|
|
10974
|
+
info: "Each step keeps a copy of the drawing, so very large drawings may keep fewer."
|
|
10914
10975
|
},
|
|
10915
10976
|
{
|
|
10916
10977
|
kind: "toggle",
|
|
@@ -10948,13 +11009,39 @@ function writeStatusBarTheme(theme) {
|
|
|
10948
11009
|
}
|
|
10949
11010
|
}
|
|
10950
11011
|
var isOfficeThemeChoice = (value) => value === "dark" || isStatusBarTheme(value);
|
|
10951
|
-
|
|
11012
|
+
var DEFAULT_BEHAVIOUR = {
|
|
11013
|
+
screenTips: "descriptions",
|
|
11014
|
+
undoLevels: MAX_UNDO_LEVELS
|
|
11015
|
+
};
|
|
11016
|
+
var BEHAVIOUR_KEY = "ooxml-visio-options";
|
|
11017
|
+
var clampUndo = (value) => {
|
|
11018
|
+
const levels = Math.round(Number(value));
|
|
11019
|
+
return Number.isFinite(levels) ? Math.min(MAX_UNDO_LEVELS, Math.max(1, levels)) : DEFAULT_BEHAVIOUR.undoLevels;
|
|
11020
|
+
};
|
|
11021
|
+
function readBehaviour() {
|
|
11022
|
+
try {
|
|
11023
|
+
const stored = JSON.parse(globalThis.localStorage?.getItem(BEHAVIOUR_KEY) ?? "{}");
|
|
11024
|
+
return {
|
|
11025
|
+
screenTips: isScreenTipStyle(stored.screenTips) ? stored.screenTips : DEFAULT_BEHAVIOUR.screenTips,
|
|
11026
|
+
undoLevels: clampUndo(stored.undoLevels ?? DEFAULT_BEHAVIOUR.undoLevels)
|
|
11027
|
+
};
|
|
11028
|
+
} catch {
|
|
11029
|
+
return { ...DEFAULT_BEHAVIOUR };
|
|
11030
|
+
}
|
|
11031
|
+
}
|
|
11032
|
+
function writeBehaviour(behaviour) {
|
|
11033
|
+
try {
|
|
11034
|
+
globalThis.localStorage?.setItem(BEHAVIOUR_KEY, JSON.stringify(behaviour));
|
|
11035
|
+
} catch {
|
|
11036
|
+
}
|
|
11037
|
+
}
|
|
11038
|
+
function profileValues(profile, officeTheme, behaviour) {
|
|
10952
11039
|
return {
|
|
10953
11040
|
officeTheme,
|
|
10954
11041
|
miniToolbar: false,
|
|
10955
11042
|
livePreview: false,
|
|
10956
|
-
screenTips:
|
|
10957
|
-
undoLevels:
|
|
11043
|
+
screenTips: behaviour.screenTips,
|
|
11044
|
+
undoLevels: behaviour.undoLevels,
|
|
10958
11045
|
autoSizeText: false,
|
|
10959
11046
|
userName: profile.displayName,
|
|
10960
11047
|
userInitials: profile.initial ?? ""
|
|
@@ -10964,7 +11051,12 @@ function createOptionsDialog(doc) {
|
|
|
10964
11051
|
const dialog = doc.createElement("office-ui-options-dialog");
|
|
10965
11052
|
dialog.setAttribute("heading", "Visio Options");
|
|
10966
11053
|
dialog.categories = VISIO_OPTION_CATEGORIES;
|
|
10967
|
-
dialog.defaults = {
|
|
11054
|
+
dialog.defaults = {
|
|
11055
|
+
userName: "",
|
|
11056
|
+
userInitials: "",
|
|
11057
|
+
officeTheme: "neutral",
|
|
11058
|
+
...DEFAULT_BEHAVIOUR
|
|
11059
|
+
};
|
|
10968
11060
|
return dialog;
|
|
10969
11061
|
}
|
|
10970
11062
|
var ViewerProfile = class {
|
|
@@ -10973,16 +11065,21 @@ var ViewerProfile = class {
|
|
|
10973
11065
|
get: () => "neutral",
|
|
10974
11066
|
set: () => {
|
|
10975
11067
|
}
|
|
11068
|
+
}, onBehaviour = () => {
|
|
10976
11069
|
}) {
|
|
10977
11070
|
this.onProfile = onProfile;
|
|
10978
11071
|
this.theme = theme;
|
|
11072
|
+
this.onBehaviour = onBehaviour;
|
|
10979
11073
|
this.#dialog = root.querySelector("office-ui-options-dialog");
|
|
10980
11074
|
this.#account = root.querySelector("office-ui-account");
|
|
10981
11075
|
this.#sync();
|
|
11076
|
+
this.onBehaviour({ ...this.#behaviour });
|
|
10982
11077
|
}
|
|
10983
11078
|
onProfile;
|
|
10984
11079
|
theme;
|
|
11080
|
+
onBehaviour;
|
|
10985
11081
|
#profile = readOfficeProfile();
|
|
11082
|
+
#behaviour = readBehaviour();
|
|
10986
11083
|
#dialog;
|
|
10987
11084
|
#account;
|
|
10988
11085
|
get profile() {
|
|
@@ -10990,7 +11087,7 @@ var ViewerProfile = class {
|
|
|
10990
11087
|
}
|
|
10991
11088
|
/** Open Visio Options, on General as Visio does. */
|
|
10992
11089
|
showOptions(category = "general") {
|
|
10993
|
-
this.#dialog.values = profileValues(this.#profile, this.theme.get());
|
|
11090
|
+
this.#dialog.values = profileValues(this.#profile, this.theme.get(), this.#behaviour);
|
|
10994
11091
|
this.#dialog.category = category;
|
|
10995
11092
|
this.#dialog.show();
|
|
10996
11093
|
}
|
|
@@ -11006,6 +11103,13 @@ var ViewerProfile = class {
|
|
|
11006
11103
|
this.theme.set(values.officeTheme);
|
|
11007
11104
|
if (values.officeTheme !== "dark") writeStatusBarTheme(values.officeTheme);
|
|
11008
11105
|
}
|
|
11106
|
+
const screenTips = isScreenTipStyle(values.screenTips) ? values.screenTips : this.#behaviour.screenTips;
|
|
11107
|
+
const undoLevels = clampUndo(values.undoLevels ?? this.#behaviour.undoLevels);
|
|
11108
|
+
if (screenTips !== this.#behaviour.screenTips || undoLevels !== this.#behaviour.undoLevels) {
|
|
11109
|
+
this.#behaviour = { screenTips, undoLevels };
|
|
11110
|
+
writeBehaviour(this.#behaviour);
|
|
11111
|
+
this.onBehaviour({ ...this.#behaviour });
|
|
11112
|
+
}
|
|
11009
11113
|
const initial = String(values.userInitials ?? "").trim();
|
|
11010
11114
|
this.#update({
|
|
11011
11115
|
displayName: String(values.userName ?? "").trim(),
|
|
@@ -11030,7 +11134,7 @@ var ViewerProfile = class {
|
|
|
11030
11134
|
}
|
|
11031
11135
|
#sync() {
|
|
11032
11136
|
if (this.#account) this.#account.profile = this.#profile;
|
|
11033
|
-
this.#dialog.values = profileValues(this.#profile, this.theme.get());
|
|
11137
|
+
this.#dialog.values = profileValues(this.#profile, this.theme.get(), this.#behaviour);
|
|
11034
11138
|
}
|
|
11035
11139
|
};
|
|
11036
11140
|
|
|
@@ -13871,6 +13975,121 @@ var InsertDialog = class {
|
|
|
13871
13975
|
for (const button of this.buttons.values()) button.disabled = value;
|
|
13872
13976
|
}
|
|
13873
13977
|
};
|
|
13978
|
+
var CHART_SIZE = { width: 640, height: 400 };
|
|
13979
|
+
var SCALE = 2;
|
|
13980
|
+
var SAMPLE = "Category Series 1 Series 2\nA 4 2\nB 3 5\nC 6 4\nD 2 6";
|
|
13981
|
+
var GROUPINGS = [
|
|
13982
|
+
{ id: "clustered", label: "Clustered" },
|
|
13983
|
+
{ id: "stacked", label: "Stacked" },
|
|
13984
|
+
{ id: "percentStacked", label: "100% Stacked" }
|
|
13985
|
+
];
|
|
13986
|
+
var rasterizeSvg = async (doc, svg2, width, height) => {
|
|
13987
|
+
const win = doc.defaultView;
|
|
13988
|
+
if (!win) throw new Error("There is no window to draw the chart in.");
|
|
13989
|
+
const url = win.URL.createObjectURL(new win.Blob([svg2], { type: "image/svg+xml" }));
|
|
13990
|
+
try {
|
|
13991
|
+
const image = new win.Image();
|
|
13992
|
+
image.src = url;
|
|
13993
|
+
await image.decode();
|
|
13994
|
+
const canvas2 = doc.createElement("canvas");
|
|
13995
|
+
canvas2.width = width * SCALE;
|
|
13996
|
+
canvas2.height = height * SCALE;
|
|
13997
|
+
const context = canvas2.getContext("2d");
|
|
13998
|
+
if (!context) throw new Error("This browser cannot draw the chart.");
|
|
13999
|
+
context.fillStyle = "#ffffff";
|
|
14000
|
+
context.fillRect(0, 0, canvas2.width, canvas2.height);
|
|
14001
|
+
context.drawImage(image, 0, 0, canvas2.width, canvas2.height);
|
|
14002
|
+
const blob2 = await new Promise((resolve) => canvas2.toBlob(resolve, "image/png"));
|
|
14003
|
+
if (!blob2) throw new Error("The chart could not be saved as a picture.");
|
|
14004
|
+
return new Uint8Array(await blob2.arrayBuffer());
|
|
14005
|
+
} finally {
|
|
14006
|
+
win.URL.revokeObjectURL(url);
|
|
14007
|
+
}
|
|
14008
|
+
};
|
|
14009
|
+
var InsertChartDialog = class {
|
|
14010
|
+
dialog;
|
|
14011
|
+
picker;
|
|
14012
|
+
error;
|
|
14013
|
+
#insert;
|
|
14014
|
+
#rasterize;
|
|
14015
|
+
#busy = false;
|
|
14016
|
+
constructor(root, insert, rasterize = rasterizeSvg) {
|
|
14017
|
+
this.#insert = insert;
|
|
14018
|
+
this.#rasterize = rasterize;
|
|
14019
|
+
const doc = root.ownerDocument;
|
|
14020
|
+
defineChartPicker(doc.defaultView?.customElements);
|
|
14021
|
+
this.dialog = doc.createElement("office-ui-dialog");
|
|
14022
|
+
this.dialog.className = "chart-dialog";
|
|
14023
|
+
this.dialog.setAttribute("heading", "Insert Chart");
|
|
14024
|
+
this.picker = doc.createElement("office-ui-chart-picker");
|
|
14025
|
+
this.picker.types = INSERT_CHART_TYPES.map(([id, label]) => ({ id, label }));
|
|
14026
|
+
this.picker.groupings = GROUPINGS;
|
|
14027
|
+
this.picker.groupedTypes = [...GROUPED_CHART_TYPES];
|
|
14028
|
+
this.picker.drawPreview = (value, size, tile) => {
|
|
14029
|
+
const grid = this.#grid(value);
|
|
14030
|
+
return grid ? gridChartSvg(grid, size.width, size.height, tile) : "";
|
|
14031
|
+
};
|
|
14032
|
+
this.error = doc.createElement("p");
|
|
14033
|
+
this.error.setAttribute("role", "alert");
|
|
14034
|
+
this.dialog.append(this.picker, this.error);
|
|
14035
|
+
const buttons = /* @__PURE__ */ new Map();
|
|
14036
|
+
for (const name of ["Cancel", "Insert"]) {
|
|
14037
|
+
const button = doc.createElement("office-ui-button");
|
|
14038
|
+
button.slot = "footer";
|
|
14039
|
+
button.setAttribute("label", name);
|
|
14040
|
+
button.setAttribute("command", `chart-dialog-${name.toLowerCase()}`);
|
|
14041
|
+
button.addEventListener("office-command", () => {
|
|
14042
|
+
if (button.disabled) return;
|
|
14043
|
+
if (name === "Cancel") this.dialog.close();
|
|
14044
|
+
else void this.#submit(buttons);
|
|
14045
|
+
});
|
|
14046
|
+
buttons.set(name, button);
|
|
14047
|
+
this.dialog.append(button);
|
|
14048
|
+
}
|
|
14049
|
+
root.append(this.dialog);
|
|
14050
|
+
}
|
|
14051
|
+
#grid(value) {
|
|
14052
|
+
return gridChart(parseChartGrid(value.data ?? ""), value.type, {
|
|
14053
|
+
grouping: value.grouping,
|
|
14054
|
+
...value.title.trim() ? { title: value.title.trim() } : {}
|
|
14055
|
+
});
|
|
14056
|
+
}
|
|
14057
|
+
/** Open with the sample data, ready to be replaced. */
|
|
14058
|
+
open() {
|
|
14059
|
+
this.error.textContent = "";
|
|
14060
|
+
this.picker.value = { type: "column", grouping: "clustered", title: "", data: SAMPLE };
|
|
14061
|
+
this.dialog.show();
|
|
14062
|
+
}
|
|
14063
|
+
close() {
|
|
14064
|
+
this.dialog.close();
|
|
14065
|
+
}
|
|
14066
|
+
async #submit(buttons) {
|
|
14067
|
+
if (this.#busy) return;
|
|
14068
|
+
const grid = this.#grid(this.picker.value);
|
|
14069
|
+
if (!grid || grid.chart.series.length === 0) {
|
|
14070
|
+
this.error.textContent = "Enter a header row and at least one row of numbers, separated by tabs or commas.";
|
|
14071
|
+
return;
|
|
14072
|
+
}
|
|
14073
|
+
this.#busy = true;
|
|
14074
|
+
for (const button of buttons.values()) button.disabled = true;
|
|
14075
|
+
try {
|
|
14076
|
+
const svg2 = gridChartSvg(grid, CHART_SIZE.width, CHART_SIZE.height);
|
|
14077
|
+
const png = await this.#rasterize(
|
|
14078
|
+
this.dialog.ownerDocument,
|
|
14079
|
+
svg2,
|
|
14080
|
+
CHART_SIZE.width,
|
|
14081
|
+
CHART_SIZE.height
|
|
14082
|
+
);
|
|
14083
|
+
await this.#insert(png);
|
|
14084
|
+
this.dialog.close();
|
|
14085
|
+
} catch (error) {
|
|
14086
|
+
this.error.textContent = error instanceof Error ? error.message : "The chart was not inserted.";
|
|
14087
|
+
} finally {
|
|
14088
|
+
this.#busy = false;
|
|
14089
|
+
for (const button of buttons.values()) button.disabled = false;
|
|
14090
|
+
}
|
|
14091
|
+
}
|
|
14092
|
+
};
|
|
13874
14093
|
|
|
13875
14094
|
// src/visio/viewer-insert.ts
|
|
13876
14095
|
var ViewerInsert = class {
|
|
@@ -13903,6 +14122,7 @@ var ViewerInsert = class {
|
|
|
13903
14122
|
["OK", "Remove Link", "Cancel"],
|
|
13904
14123
|
(button) => void this.#applyLink(button)
|
|
13905
14124
|
);
|
|
14125
|
+
this.chart = new InsertChartDialog(root, (png) => this.#insertChart(png));
|
|
13906
14126
|
this.tip = new InsertDialog(
|
|
13907
14127
|
root,
|
|
13908
14128
|
"screen-tip-dialog",
|
|
@@ -13919,6 +14139,7 @@ var ViewerInsert = class {
|
|
|
13919
14139
|
input;
|
|
13920
14140
|
link;
|
|
13921
14141
|
tip;
|
|
14142
|
+
chart;
|
|
13922
14143
|
#target;
|
|
13923
14144
|
#editable(state) {
|
|
13924
14145
|
return state.edit.sourceAvailable && !state.loading && !state.edit.busy;
|
|
@@ -13936,6 +14157,10 @@ var ViewerInsert = class {
|
|
|
13936
14157
|
if (state.document?.pages[state.pageIndex]) this.input.click();
|
|
13937
14158
|
return;
|
|
13938
14159
|
}
|
|
14160
|
+
if (item === "chart") {
|
|
14161
|
+
if (state.document?.pages[state.pageIndex]) this.chart.open();
|
|
14162
|
+
return;
|
|
14163
|
+
}
|
|
13939
14164
|
const shape = this.#shape(state);
|
|
13940
14165
|
const page3 = state.document?.pages[state.pageIndex];
|
|
13941
14166
|
if (!shape || !page3) {
|
|
@@ -13967,6 +14192,28 @@ var ViewerInsert = class {
|
|
|
13967
14192
|
close() {
|
|
13968
14193
|
this.link.dialog.close();
|
|
13969
14194
|
this.tip.dialog.close();
|
|
14195
|
+
this.chart.close();
|
|
14196
|
+
}
|
|
14197
|
+
/** Place the chart dialog's PNG on the page; rejects (so the dialog can say why) when refused. */
|
|
14198
|
+
async #insertChart(png) {
|
|
14199
|
+
const state = this.controller.state;
|
|
14200
|
+
const page3 = state.document?.pages[state.pageIndex];
|
|
14201
|
+
if (!page3 || !this.#editable(state)) throw new Error("Open a .vsdx file to insert a chart.");
|
|
14202
|
+
if (png.byteLength > VISIO_PICTURE_MAX_BYTES)
|
|
14203
|
+
throw new Error("The chart is larger than the 8 MB picture limit.");
|
|
14204
|
+
const token = this.controller.captureCreationToken(page3.id);
|
|
14205
|
+
const command2 = visioPictureInsertCommand(page3, inspectVisioRasterImage(png), png);
|
|
14206
|
+
await new Promise(
|
|
14207
|
+
(resolve, reject) => this.run(async () => {
|
|
14208
|
+
try {
|
|
14209
|
+
await this.controller.applyCreationEdits([command2], token);
|
|
14210
|
+
resolve();
|
|
14211
|
+
} catch (error) {
|
|
14212
|
+
reject(error);
|
|
14213
|
+
throw error;
|
|
14214
|
+
}
|
|
14215
|
+
}, "Inserted chart.")
|
|
14216
|
+
);
|
|
13970
14217
|
}
|
|
13971
14218
|
async #picture(file) {
|
|
13972
14219
|
const state = this.controller.state;
|
|
@@ -14090,6 +14337,11 @@ var ViewerInsert = class {
|
|
|
14090
14337
|
pictures.disabled = !editing || !page3;
|
|
14091
14338
|
pictures.title = editing ? "Insert a PNG, JPEG or GIF picture from this device (up to 8 MB)." : "Open a .vsdx file to insert pictures.";
|
|
14092
14339
|
}
|
|
14340
|
+
const chart = button("chart");
|
|
14341
|
+
if (chart) {
|
|
14342
|
+
chart.disabled = !editing || !page3;
|
|
14343
|
+
chart.title = editing ? "Insert a chart drawn from data you type or paste. It is placed as a picture." : "Open a .vsdx file to insert a chart.";
|
|
14344
|
+
}
|
|
14093
14345
|
for (const [name, label] of [
|
|
14094
14346
|
["link", "Link (Ctrl+K)"],
|
|
14095
14347
|
["ctx-hyperlink", "Hyperlink (Ctrl+K)"],
|
|
@@ -14100,6 +14352,8 @@ var ViewerInsert = class {
|
|
|
14100
14352
|
control.disabled = !shape;
|
|
14101
14353
|
control.title = shape ? label : `${label}: select one shape on an editable drawing.`;
|
|
14102
14354
|
}
|
|
14355
|
+
if (this.chart.dialog.open && (!state.edit.sourceAvailable || state.loading))
|
|
14356
|
+
this.chart.close();
|
|
14103
14357
|
for (const dialog of [this.link, this.tip]) {
|
|
14104
14358
|
if (!dialog.dialog.open) continue;
|
|
14105
14359
|
if (!state.edit.sourceAvailable || state.loading || this.controller.documentGeneration !== this.#target?.generation)
|
|
@@ -22860,6 +23114,7 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
22860
23114
|
#unsubscribe;
|
|
22861
23115
|
#eventUnsubscribe;
|
|
22862
23116
|
#disposed = false;
|
|
23117
|
+
#screenTips = "descriptions";
|
|
22863
23118
|
#suspended = false;
|
|
22864
23119
|
#fontEvents;
|
|
22865
23120
|
#fontsChanged = () => {
|
|
@@ -22952,14 +23207,23 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
22952
23207
|
}
|
|
22953
23208
|
});
|
|
22954
23209
|
const profileChanged = () => renderTitleBar(this.#titleBar, this.controller.state, this.#fileName, this.#profile.profile);
|
|
22955
|
-
this.#profile = new ViewerProfile(
|
|
22956
|
-
|
|
22957
|
-
|
|
22958
|
-
|
|
22959
|
-
|
|
22960
|
-
|
|
23210
|
+
this.#profile = new ViewerProfile(
|
|
23211
|
+
this.#root,
|
|
23212
|
+
profileChanged,
|
|
23213
|
+
{
|
|
23214
|
+
get: () => this.#dark() ? "dark" : this.statusBar,
|
|
23215
|
+
set: (theme) => {
|
|
23216
|
+
if (theme !== "dark") this.statusBar = theme;
|
|
23217
|
+
if (theme === "dark" !== this.#dark())
|
|
23218
|
+
this.#requestScheme(theme === "dark" ? "dark" : "light");
|
|
23219
|
+
}
|
|
23220
|
+
},
|
|
23221
|
+
(behaviour) => {
|
|
23222
|
+
this.#screenTips = behaviour.screenTips;
|
|
23223
|
+
applyScreenTips(this.#toolbar, this.#screenTips);
|
|
23224
|
+
this.controller.undoLevels = behaviour.undoLevels;
|
|
22961
23225
|
}
|
|
22962
|
-
|
|
23226
|
+
);
|
|
22963
23227
|
this.#pointer = new ViewerPointerGestures(this.#viewport, this.controller, {
|
|
22964
23228
|
active: () => this.#commands.tool === "pointer",
|
|
22965
23229
|
announce: (message) => {
|
|
@@ -23291,10 +23555,12 @@ var VisioViewerElement = class extends BaseElement {
|
|
|
23291
23555
|
/** The ribbon speaks the `locale` attribute, else `lang`, else the page's, else the browser's. */
|
|
23292
23556
|
#localizeRibbon() {
|
|
23293
23557
|
if (this.#disposed || !this.#overflow) return;
|
|
23558
|
+
restoreScreenTips(this.#toolbar);
|
|
23294
23559
|
localizeRibbon(
|
|
23295
23560
|
this.#toolbar,
|
|
23296
23561
|
this.getAttribute("locale") || this.lang || this.ownerDocument.documentElement.lang || navigator.language
|
|
23297
23562
|
);
|
|
23563
|
+
applyScreenTips(this.#toolbar, this.#screenTips);
|
|
23298
23564
|
this.#overflow.refit();
|
|
23299
23565
|
}
|
|
23300
23566
|
connectedCallback() {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ChartType } from 'ooxml-core/xlsx';
|
|
2
2
|
import type { Command } from 'ooxml-core/xlsx/ui';
|
|
3
3
|
import type { EditorContext } from 'ooxml-core/xlsx/ui';
|
|
4
|
+
/** The chart types of Insert Chart (shared with other products) with the ribbon glyph of each. */
|
|
4
5
|
export declare const CHART_TYPES: ReadonlyArray<readonly [type: ChartType, label: string, glyph: string]>;
|
|
5
6
|
/** Inserts a picture file at the active cell (scaled to at most 640 px wide, like Excel's fit). */
|
|
6
7
|
export declare function insertPicture(ctx: EditorContext, file: File): Promise<void>;
|