ooxml-ui 1.8.3 → 1.8.5

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.
@@ -61,6 +61,151 @@ function textStyleFlagsOf(element, selection = null, segments) {
61
61
  }
62
62
  return getSelectionTextStyleFlags(segments ?? element.textSegments, selection, element.textStyle);
63
63
  }
64
+ var BODY_TEXT_STYLE_KEYS = /* @__PURE__ */ new Set([
65
+ // autofit (`a:normAutofit` / `a:spAutoFit`)
66
+ "autoFit",
67
+ "autoFitMode",
68
+ "autoFitFontScale",
69
+ "autoFitLineSpacingReduction",
70
+ // `a:bodyPr` anchoring, direction, rotation
71
+ "vAlign",
72
+ "anchorCenter",
73
+ "textDirection",
74
+ "textBodyRotation",
75
+ "upright",
76
+ // `a:bodyPr` columns, overflow, wrap
77
+ "columnCount",
78
+ "columnSpacing",
79
+ "rtlColumns",
80
+ "hOverflow",
81
+ "vertOverflow",
82
+ "textWrap",
83
+ // `a:bodyPr` insets
84
+ "bodyInsetLeft",
85
+ "bodyInsetTop",
86
+ "bodyInsetRight",
87
+ "bodyInsetBottom",
88
+ // paragraph geometry the block applies body-wide
89
+ "paragraphMarginLeft",
90
+ "paragraphMarginRight",
91
+ "paragraphIndent",
92
+ "paragraphSpacingBefore",
93
+ "paragraphSpacingAfter",
94
+ "lineSpacing",
95
+ "lineSpacingExactPt",
96
+ "tabStops",
97
+ "defaultTabSize",
98
+ "eaLineBreak",
99
+ "latinLineBreak",
100
+ "fontAlignment",
101
+ "hangingPunctuation",
102
+ // `a:bodyPr` flags
103
+ "spaceFirstLastParagraph",
104
+ "fromWordArt",
105
+ "forceAntiAlias",
106
+ "compatibleLineSpacing",
107
+ // warp and 3D scene on the body
108
+ "textWarpPreset",
109
+ "textWarpAdj",
110
+ "textWarpAdj2",
111
+ "text3d",
112
+ "textBodyScene3d",
113
+ "textBodyScene3dXml",
114
+ "flatText",
115
+ "bodyPropertiesExtLstXml"
116
+ ]);
117
+ function isBodyTextStyleKey(key) {
118
+ return BODY_TEXT_STYLE_KEYS.has(key);
119
+ }
120
+ function splitTextStyleUpdate(updates) {
121
+ const body = {};
122
+ const run = {};
123
+ for (const [key, value] of Object.entries(updates)) {
124
+ (isBodyTextStyleKey(key) ? body : run)[key] = value;
125
+ }
126
+ return { body, run };
127
+ }
128
+ function reconcileDecorationFlags(segments, textStyle, flags) {
129
+ const nextStyle = { ...textStyle ?? {} };
130
+ let nextSegments = [...segments];
131
+ for (const flag of flags) {
132
+ const body = nextStyle[flag] ?? false;
133
+ const content = nextSegments.filter(isContentSegment);
134
+ if (content.length === 0) {
135
+ continue;
136
+ }
137
+ if (content.every((segment) => segment.style?.[flag] ?? body)) {
138
+ nextStyle[flag] = true;
139
+ continue;
140
+ }
141
+ if (!body) {
142
+ continue;
143
+ }
144
+ delete nextStyle[flag];
145
+ nextSegments = nextSegments.map(
146
+ (segment) => isContentSegment(segment) && segment.style?.[flag] === void 0 ? { ...segment, style: { ...segment.style, [flag]: true } } : segment
147
+ );
148
+ }
149
+ return { textStyle: nextStyle, textSegments: nextSegments };
150
+ }
151
+ var LINE_SPACING_TWIN = {
152
+ lineSpacing: "lineSpacingExactPt",
153
+ lineSpacingExactPt: "lineSpacing"
154
+ };
155
+ function withExclusiveLineSpacing(updates) {
156
+ const next = { ...updates };
157
+ for (const key of Object.keys(updates)) {
158
+ const twin = LINE_SPACING_TWIN[key];
159
+ if (twin && updates[key] !== void 0 && !(twin in updates)) {
160
+ next[twin] = void 0;
161
+ }
162
+ }
163
+ return next;
164
+ }
165
+ function overrideParagraphProperties(segments, updates) {
166
+ const keys = Object.keys(updates).filter(isBodyTextStyleKey);
167
+ return segments.map((segment) => {
168
+ const own = segment.paragraphProperties;
169
+ const declared = own ? keys.filter((key) => {
170
+ const twin = LINE_SPACING_TWIN[key];
171
+ return key in own || twin !== void 0 && twin in own;
172
+ }) : [];
173
+ if (!own || declared.length === 0) {
174
+ return segment;
175
+ }
176
+ const next = { ...own };
177
+ for (const key of declared) {
178
+ if (updates[key] === void 0) {
179
+ delete next[key];
180
+ } else {
181
+ Object.assign(next, { [key]: updates[key] });
182
+ }
183
+ }
184
+ return { ...segment, paragraphProperties: next };
185
+ });
186
+ }
187
+ function overrideParagraphIndents(element, updates) {
188
+ const { paragraphMarginLeft, paragraphIndent } = updates;
189
+ if (!pptx.hasTextProperties(element) || !element.paragraphIndents || paragraphMarginLeft === void 0 && paragraphIndent === void 0) {
190
+ return {};
191
+ }
192
+ return {
193
+ paragraphIndents: element.paragraphIndents.map((entry) => ({
194
+ ...entry,
195
+ ...paragraphMarginLeft === void 0 ? {} : { marginLeft: paragraphMarginLeft },
196
+ ...paragraphIndent === void 0 ? {} : { indent: paragraphIndent }
197
+ }))
198
+ };
199
+ }
200
+ function paragraphOverridePatch(element, updates) {
201
+ const current = pptx.hasTextProperties(element) ? element.textSegments : void 0;
202
+ const overridden = current && overrideParagraphProperties(current, updates);
203
+ const changed = overridden?.some((segment, index) => segment !== current?.[index]);
204
+ return {
205
+ ...changed ? { textSegments: overridden } : {},
206
+ ...overrideParagraphIndents(element, updates)
207
+ };
208
+ }
64
209
 
65
210
  // src/pptx/render/inspector-helpers.ts
66
211
  var DEFAULT_FILL = "#ffffff";
@@ -112,15 +257,19 @@ function shapeStylePatch(el, changes) {
112
257
  }
113
258
  function textStylePatch(el, changes) {
114
259
  const base = pptx.hasTextProperties(el) ? el.textStyle ?? {} : {};
260
+ const exclusive = withExclusiveLineSpacing(changes);
261
+ const paragraphs = paragraphOverridePatch(el, exclusive);
262
+ const segments = paragraphs.textSegments ?? (pptx.hasTextProperties(el) ? el.textSegments : void 0);
115
263
  return {
116
- ...pptx.hasTextProperties(el) && el.textSegments?.some((segment) => segment.paragraphInsertionStyle) ? {
117
- textSegments: el.textSegments.map(
118
- (segment) => chunkOGJRSAGH_cjs.updateTextSegmentStyle(segment, changes, { updateBodyStyle: false })
264
+ ...paragraphs,
265
+ ...segments?.some((segment) => segment.paragraphInsertionStyle) ? {
266
+ textSegments: segments.map(
267
+ (segment) => chunkOGJRSAGH_cjs.updateTextSegmentStyle(segment, exclusive, { updateBodyStyle: false })
119
268
  )
120
269
  } : {},
121
270
  textStyle: {
122
271
  ...base,
123
- ...changes
272
+ ...exclusive
124
273
  }
125
274
  };
126
275
  }
@@ -187,20 +336,28 @@ Object.defineProperty(exports, "withoutListType", {
187
336
  enumerable: true,
188
337
  get: function () { return bulletToggle.withoutListType; }
189
338
  });
339
+ exports.BODY_TEXT_STYLE_KEYS = BODY_TEXT_STYLE_KEYS;
190
340
  exports.DEFAULT_FONT_SIZE = DEFAULT_FONT_SIZE;
191
341
  exports.TEXT_DECORATION_FLAGS = TEXT_DECORATION_FLAGS;
192
342
  exports.contentSegmentsInSelection = contentSegmentsInSelection;
193
343
  exports.fillColorOf = fillColorOf;
194
344
  exports.fontSizeOf = fontSizeOf;
195
345
  exports.getSelectionTextStyleFlags = getSelectionTextStyleFlags;
346
+ exports.isBodyTextStyleKey = isBodyTextStyleKey;
196
347
  exports.isBold = isBold;
197
348
  exports.isContentSegment = isContentSegment;
198
349
  exports.isItalic = isItalic;
199
350
  exports.isUnderline = isUnderline;
200
351
  exports.nextToggleValue = nextToggleValue;
352
+ exports.overrideParagraphIndents = overrideParagraphIndents;
353
+ exports.overrideParagraphProperties = overrideParagraphProperties;
354
+ exports.paragraphOverridePatch = paragraphOverridePatch;
355
+ exports.reconcileDecorationFlags = reconcileDecorationFlags;
201
356
  exports.shapeStylePatch = shapeStylePatch;
357
+ exports.splitTextStyleUpdate = splitTextStyleUpdate;
202
358
  exports.strokeColorOf = strokeColorOf;
203
359
  exports.textColorOf = textColorOf;
204
360
  exports.textFontSizePatch = textFontSizePatch;
205
361
  exports.textStyleFlagsOf = textStyleFlagsOf;
206
362
  exports.textStylePatch = textStylePatch;
363
+ exports.withExclusiveLineSpacing = withExclusiveLineSpacing;
@@ -1,4 +1,4 @@
1
- import { textStylePatch } from './chunk-VD7HRMTA.mjs';
1
+ import { textStylePatch } from './chunk-SABFKDRM.mjs';
2
2
  import { hasShapeProperties, hasTextProperties } from 'ooxml-core/pptx';
3
3
 
4
4
  function copyFormatFromElement(element) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkSTXGHV25_cjs = require('./chunk-STXGHV25.cjs');
3
+ var chunkHWW2UVUP_cjs = require('./chunk-HWW2UVUP.cjs');
4
4
  var pptx = require('ooxml-core/pptx');
5
5
 
6
6
  function copyFormatFromElement(element) {
@@ -77,7 +77,7 @@ function applyFormatToElement(element, format) {
77
77
  if (format.textStyle && pptx.hasTextProperties(updated)) {
78
78
  updated = {
79
79
  ...updated,
80
- ...chunkSTXGHV25_cjs.textStylePatch(updated, definedEntries(format.textStyle))
80
+ ...chunkHWW2UVUP_cjs.textStylePatch(updated, definedEntries(format.textStyle))
81
81
  };
82
82
  }
83
83
  return updated;
@@ -0,0 +1,286 @@
1
+ import { textFontSizePxToPt } from './chunk-SMSCEGAE.mjs';
2
+ import { updateTextSegmentStyle } from './chunk-CENGE3TZ.mjs';
3
+ import { hasTextProperties, hasShapeProperties } from 'ooxml-core/pptx';
4
+ import { isBulletMarkerSegment } from 'ooxml-core/pptx/editor/render/bullet-toggle';
5
+ export { DEFAULT_AUTONUM_TYPE, DEFAULT_BULLET_CHAR, bulletInfoForKind, elementBulletKind, isBulletMarkerSegment, paragraphBulletKind, paragraphsBulletKind, resolveBulletSegments, setElementBullets, splitBulletParagraphs, toggleElementBullets, toggleParagraphBullet, withoutListType } from 'ooxml-core/pptx/editor/render/bullet-toggle';
6
+
7
+ // src/pptx/render/selection-format-state.ts
8
+ var TEXT_DECORATION_FLAGS = [
9
+ "bold",
10
+ "italic",
11
+ "underline",
12
+ "strikethrough"
13
+ ];
14
+ function isContentSegment(segment) {
15
+ return !segment.isParagraphBreak && segment.text !== "\n" && segment.text.length > 0 && !isBulletMarkerSegment(segment);
16
+ }
17
+ function contentSegmentsInSelection(segments, selection) {
18
+ if (!segments) {
19
+ return [];
20
+ }
21
+ return segments.filter((segment, index) => {
22
+ if (!isContentSegment(segment)) {
23
+ return false;
24
+ }
25
+ if (!selection) {
26
+ return true;
27
+ }
28
+ if (index < selection.startSegIdx || index > selection.endSegIdx) {
29
+ return false;
30
+ }
31
+ if (selection.startSegIdx === selection.endSegIdx && selection.startOffset === selection.endOffset) {
32
+ return true;
33
+ }
34
+ const start = index === selection.startSegIdx ? selection.startOffset : 0;
35
+ const end = index === selection.endSegIdx ? selection.endOffset : segment.text.length;
36
+ return end > start;
37
+ });
38
+ }
39
+ function flagState(values) {
40
+ if (values.every((value) => value)) {
41
+ return "on";
42
+ }
43
+ return values.some((value) => value) ? "mixed" : "off";
44
+ }
45
+ function getSelectionTextStyleFlags(segments, selection, elementTextStyle) {
46
+ const runs = contentSegmentsInSelection(segments, selection);
47
+ const flags = {};
48
+ for (const flag of TEXT_DECORATION_FLAGS) {
49
+ const body = elementTextStyle?.[flag] ?? false;
50
+ flags[flag] = runs.length === 0 ? flagState([body]) : flagState(runs.map((run) => run.style?.[flag] ?? body));
51
+ }
52
+ return flags;
53
+ }
54
+ function nextToggleValue(state) {
55
+ return state !== "on";
56
+ }
57
+ function textStyleFlagsOf(element, selection = null, segments) {
58
+ if (!element || !hasTextProperties(element)) {
59
+ return { bold: "off", italic: "off", underline: "off", strikethrough: "off" };
60
+ }
61
+ return getSelectionTextStyleFlags(segments ?? element.textSegments, selection, element.textStyle);
62
+ }
63
+ var BODY_TEXT_STYLE_KEYS = /* @__PURE__ */ new Set([
64
+ // autofit (`a:normAutofit` / `a:spAutoFit`)
65
+ "autoFit",
66
+ "autoFitMode",
67
+ "autoFitFontScale",
68
+ "autoFitLineSpacingReduction",
69
+ // `a:bodyPr` anchoring, direction, rotation
70
+ "vAlign",
71
+ "anchorCenter",
72
+ "textDirection",
73
+ "textBodyRotation",
74
+ "upright",
75
+ // `a:bodyPr` columns, overflow, wrap
76
+ "columnCount",
77
+ "columnSpacing",
78
+ "rtlColumns",
79
+ "hOverflow",
80
+ "vertOverflow",
81
+ "textWrap",
82
+ // `a:bodyPr` insets
83
+ "bodyInsetLeft",
84
+ "bodyInsetTop",
85
+ "bodyInsetRight",
86
+ "bodyInsetBottom",
87
+ // paragraph geometry the block applies body-wide
88
+ "paragraphMarginLeft",
89
+ "paragraphMarginRight",
90
+ "paragraphIndent",
91
+ "paragraphSpacingBefore",
92
+ "paragraphSpacingAfter",
93
+ "lineSpacing",
94
+ "lineSpacingExactPt",
95
+ "tabStops",
96
+ "defaultTabSize",
97
+ "eaLineBreak",
98
+ "latinLineBreak",
99
+ "fontAlignment",
100
+ "hangingPunctuation",
101
+ // `a:bodyPr` flags
102
+ "spaceFirstLastParagraph",
103
+ "fromWordArt",
104
+ "forceAntiAlias",
105
+ "compatibleLineSpacing",
106
+ // warp and 3D scene on the body
107
+ "textWarpPreset",
108
+ "textWarpAdj",
109
+ "textWarpAdj2",
110
+ "text3d",
111
+ "textBodyScene3d",
112
+ "textBodyScene3dXml",
113
+ "flatText",
114
+ "bodyPropertiesExtLstXml"
115
+ ]);
116
+ function isBodyTextStyleKey(key) {
117
+ return BODY_TEXT_STYLE_KEYS.has(key);
118
+ }
119
+ function splitTextStyleUpdate(updates) {
120
+ const body = {};
121
+ const run = {};
122
+ for (const [key, value] of Object.entries(updates)) {
123
+ (isBodyTextStyleKey(key) ? body : run)[key] = value;
124
+ }
125
+ return { body, run };
126
+ }
127
+ function reconcileDecorationFlags(segments, textStyle, flags) {
128
+ const nextStyle = { ...textStyle ?? {} };
129
+ let nextSegments = [...segments];
130
+ for (const flag of flags) {
131
+ const body = nextStyle[flag] ?? false;
132
+ const content = nextSegments.filter(isContentSegment);
133
+ if (content.length === 0) {
134
+ continue;
135
+ }
136
+ if (content.every((segment) => segment.style?.[flag] ?? body)) {
137
+ nextStyle[flag] = true;
138
+ continue;
139
+ }
140
+ if (!body) {
141
+ continue;
142
+ }
143
+ delete nextStyle[flag];
144
+ nextSegments = nextSegments.map(
145
+ (segment) => isContentSegment(segment) && segment.style?.[flag] === void 0 ? { ...segment, style: { ...segment.style, [flag]: true } } : segment
146
+ );
147
+ }
148
+ return { textStyle: nextStyle, textSegments: nextSegments };
149
+ }
150
+ var LINE_SPACING_TWIN = {
151
+ lineSpacing: "lineSpacingExactPt",
152
+ lineSpacingExactPt: "lineSpacing"
153
+ };
154
+ function withExclusiveLineSpacing(updates) {
155
+ const next = { ...updates };
156
+ for (const key of Object.keys(updates)) {
157
+ const twin = LINE_SPACING_TWIN[key];
158
+ if (twin && updates[key] !== void 0 && !(twin in updates)) {
159
+ next[twin] = void 0;
160
+ }
161
+ }
162
+ return next;
163
+ }
164
+ function overrideParagraphProperties(segments, updates) {
165
+ const keys = Object.keys(updates).filter(isBodyTextStyleKey);
166
+ return segments.map((segment) => {
167
+ const own = segment.paragraphProperties;
168
+ const declared = own ? keys.filter((key) => {
169
+ const twin = LINE_SPACING_TWIN[key];
170
+ return key in own || twin !== void 0 && twin in own;
171
+ }) : [];
172
+ if (!own || declared.length === 0) {
173
+ return segment;
174
+ }
175
+ const next = { ...own };
176
+ for (const key of declared) {
177
+ if (updates[key] === void 0) {
178
+ delete next[key];
179
+ } else {
180
+ Object.assign(next, { [key]: updates[key] });
181
+ }
182
+ }
183
+ return { ...segment, paragraphProperties: next };
184
+ });
185
+ }
186
+ function overrideParagraphIndents(element, updates) {
187
+ const { paragraphMarginLeft, paragraphIndent } = updates;
188
+ if (!hasTextProperties(element) || !element.paragraphIndents || paragraphMarginLeft === void 0 && paragraphIndent === void 0) {
189
+ return {};
190
+ }
191
+ return {
192
+ paragraphIndents: element.paragraphIndents.map((entry) => ({
193
+ ...entry,
194
+ ...paragraphMarginLeft === void 0 ? {} : { marginLeft: paragraphMarginLeft },
195
+ ...paragraphIndent === void 0 ? {} : { indent: paragraphIndent }
196
+ }))
197
+ };
198
+ }
199
+ function paragraphOverridePatch(element, updates) {
200
+ const current = hasTextProperties(element) ? element.textSegments : void 0;
201
+ const overridden = current && overrideParagraphProperties(current, updates);
202
+ const changed = overridden?.some((segment, index) => segment !== current?.[index]);
203
+ return {
204
+ ...changed ? { textSegments: overridden } : {},
205
+ ...overrideParagraphIndents(element, updates)
206
+ };
207
+ }
208
+
209
+ // src/pptx/render/inspector-helpers.ts
210
+ var DEFAULT_FILL = "#ffffff";
211
+ var DEFAULT_STROKE = "#000000";
212
+ var DEFAULT_TEXT_COLOR = "#000000";
213
+ var DEFAULT_FONT_SIZE = 18;
214
+ function fillColorOf(el) {
215
+ if (hasShapeProperties(el)) {
216
+ return el.shapeStyle?.fillColor ?? DEFAULT_FILL;
217
+ }
218
+ return DEFAULT_FILL;
219
+ }
220
+ function strokeColorOf(el) {
221
+ if (hasShapeProperties(el)) {
222
+ return el.shapeStyle?.strokeColor ?? DEFAULT_STROKE;
223
+ }
224
+ return DEFAULT_STROKE;
225
+ }
226
+ function textColorOf(el) {
227
+ if (hasTextProperties(el)) {
228
+ return el.textStyle?.color ?? DEFAULT_TEXT_COLOR;
229
+ }
230
+ return DEFAULT_TEXT_COLOR;
231
+ }
232
+ function fontSizeOf(el, presentationDefault) {
233
+ if (hasTextProperties(el) && el.textStyle?.fontSize !== void 0) {
234
+ return textFontSizePxToPt(el.textStyle.fontSize);
235
+ }
236
+ const deckDefault = presentationDefault?.levelStyles?.[0]?.fontSize;
237
+ return deckDefault === void 0 ? DEFAULT_FONT_SIZE : textFontSizePxToPt(deckDefault);
238
+ }
239
+ function isBold(el) {
240
+ return textStyleFlagsOf(el).bold === "on";
241
+ }
242
+ function isItalic(el) {
243
+ return textStyleFlagsOf(el).italic === "on";
244
+ }
245
+ function isUnderline(el) {
246
+ return textStyleFlagsOf(el).underline === "on";
247
+ }
248
+ function shapeStylePatch(el, changes) {
249
+ const base = hasShapeProperties(el) ? el.shapeStyle ?? {} : {};
250
+ return {
251
+ shapeStyle: {
252
+ ...base,
253
+ ...changes
254
+ }
255
+ };
256
+ }
257
+ function textStylePatch(el, changes) {
258
+ const base = hasTextProperties(el) ? el.textStyle ?? {} : {};
259
+ const exclusive = withExclusiveLineSpacing(changes);
260
+ const paragraphs = paragraphOverridePatch(el, exclusive);
261
+ const segments = paragraphs.textSegments ?? (hasTextProperties(el) ? el.textSegments : void 0);
262
+ return {
263
+ ...paragraphs,
264
+ ...segments?.some((segment) => segment.paragraphInsertionStyle) ? {
265
+ textSegments: segments.map(
266
+ (segment) => updateTextSegmentStyle(segment, exclusive, { updateBodyStyle: false })
267
+ )
268
+ } : {},
269
+ textStyle: {
270
+ ...base,
271
+ ...exclusive
272
+ }
273
+ };
274
+ }
275
+ function textFontSizePatch(el, fontSize) {
276
+ const patch = textStylePatch(el, { fontSize });
277
+ if (!hasTextProperties(el) || !el.textSegments) {
278
+ return patch;
279
+ }
280
+ return {
281
+ ...patch,
282
+ textSegments: el.textSegments.map((segment) => updateTextSegmentStyle(segment, { fontSize }))
283
+ };
284
+ }
285
+
286
+ export { BODY_TEXT_STYLE_KEYS, DEFAULT_FONT_SIZE, TEXT_DECORATION_FLAGS, contentSegmentsInSelection, fillColorOf, fontSizeOf, getSelectionTextStyleFlags, isBodyTextStyleKey, isBold, isContentSegment, isItalic, isUnderline, nextToggleValue, overrideParagraphIndents, overrideParagraphProperties, paragraphOverridePatch, reconcileDecorationFlags, shapeStylePatch, splitTextStyleUpdate, strokeColorOf, textColorOf, textFontSizePatch, textStyleFlagsOf, textStylePatch, withExclusiveLineSpacing };