@docmentis/udoc-editor 0.0.1 → 0.8.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/LICENSE-APACHE +202 -0
- package/LICENSE-MIT +21 -0
- package/README.md +48 -0
- package/dist/arrange.d.ts +37 -0
- package/dist/arrange.d.ts.map +1 -0
- package/dist/arrange.js +431 -0
- package/dist/arrange.js.map +1 -0
- package/dist/clipboard.d.ts +12 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +101 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/commands.d.ts +12 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +225 -0
- package/dist/commands.js.map +1 -0
- package/dist/components/ComboBox.d.ts +38 -0
- package/dist/components/ComboBox.d.ts.map +1 -0
- package/dist/components/ComboBox.js +57 -0
- package/dist/components/ComboBox.js.map +1 -0
- package/dist/components/ModeSwitch.d.ts +15 -0
- package/dist/components/ModeSwitch.d.ts.map +1 -0
- package/dist/components/ModeSwitch.js +94 -0
- package/dist/components/ModeSwitch.js.map +1 -0
- package/dist/components/NewSlideModal.d.ts +41 -0
- package/dist/components/NewSlideModal.d.ts.map +1 -0
- package/dist/components/NewSlideModal.js +136 -0
- package/dist/components/NewSlideModal.js.map +1 -0
- package/dist/components/PageControls.d.ts +78 -0
- package/dist/components/PageControls.d.ts.map +1 -0
- package/dist/components/PageControls.js +201 -0
- package/dist/components/PageControls.js.map +1 -0
- package/dist/components/PageSettingsModal.d.ts +27 -0
- package/dist/components/PageSettingsModal.d.ts.map +1 -0
- package/dist/components/PageSettingsModal.js +273 -0
- package/dist/components/PageSettingsModal.js.map +1 -0
- package/dist/components/PaintOptionsModal.d.ts +19 -0
- package/dist/components/PaintOptionsModal.d.ts.map +1 -0
- package/dist/components/PaintOptionsModal.js +103 -0
- package/dist/components/PaintOptionsModal.js.map +1 -0
- package/dist/components/TextControls.d.ts +49 -0
- package/dist/components/TextControls.d.ts.map +1 -0
- package/dist/components/TextControls.js +452 -0
- package/dist/components/TextControls.js.map +1 -0
- package/dist/context-menu.d.ts +46 -0
- package/dist/context-menu.d.ts.map +1 -0
- package/dist/context-menu.js +144 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/edit-client.d.ts +121 -0
- package/dist/edit-client.d.ts.map +1 -0
- package/dist/edit-client.js +154 -0
- package/dist/edit-client.js.map +1 -0
- package/dist/edit-command.d.ts +7 -0
- package/dist/edit-command.d.ts.map +1 -0
- package/dist/edit-command.js +18 -0
- package/dist/edit-command.js.map +1 -0
- package/dist/edit-mode.d.ts +19 -0
- package/dist/edit-mode.d.ts.map +1 -0
- package/dist/edit-mode.js +214 -0
- package/dist/edit-mode.js.map +1 -0
- package/dist/editor.d.ts +101 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +101 -0
- package/dist/editor.js.map +1 -0
- package/dist/fonts/faces.d.ts +28 -0
- package/dist/fonts/faces.d.ts.map +1 -0
- package/dist/fonts/faces.js +38 -0
- package/dist/fonts/faces.js.map +1 -0
- package/dist/fonts/preview.d.ts +98 -0
- package/dist/fonts/preview.d.ts.map +1 -0
- package/dist/fonts/preview.js +149 -0
- package/dist/fonts/preview.js.map +1 -0
- package/dist/formatting-marks.d.ts +23 -0
- package/dist/formatting-marks.d.ts.map +1 -0
- package/dist/formatting-marks.js +55 -0
- package/dist/formatting-marks.js.map +1 -0
- package/dist/grips.d.ts +14 -0
- package/dist/grips.d.ts.map +1 -0
- package/dist/grips.js +459 -0
- package/dist/grips.js.map +1 -0
- package/dist/i18n/ar.d.ts +4 -0
- package/dist/i18n/ar.d.ts.map +1 -0
- package/dist/i18n/ar.js +175 -0
- package/dist/i18n/ar.js.map +1 -0
- package/dist/i18n/de.d.ts +4 -0
- package/dist/i18n/de.d.ts.map +1 -0
- package/dist/i18n/de.js +175 -0
- package/dist/i18n/de.js.map +1 -0
- package/dist/i18n/en.d.ts +5 -0
- package/dist/i18n/en.d.ts.map +1 -0
- package/dist/i18n/en.js +176 -0
- package/dist/i18n/en.js.map +1 -0
- package/dist/i18n/es.d.ts +4 -0
- package/dist/i18n/es.d.ts.map +1 -0
- package/dist/i18n/es.js +175 -0
- package/dist/i18n/es.js.map +1 -0
- package/dist/i18n/fr.d.ts +4 -0
- package/dist/i18n/fr.d.ts.map +1 -0
- package/dist/i18n/fr.js +175 -0
- package/dist/i18n/fr.js.map +1 -0
- package/dist/i18n/index.d.ts +21 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +42 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/ja.d.ts +4 -0
- package/dist/i18n/ja.d.ts.map +1 -0
- package/dist/i18n/ja.js +175 -0
- package/dist/i18n/ja.js.map +1 -0
- package/dist/i18n/ko.d.ts +4 -0
- package/dist/i18n/ko.d.ts.map +1 -0
- package/dist/i18n/ko.js +175 -0
- package/dist/i18n/ko.js.map +1 -0
- package/dist/i18n/messages.d.ts +316 -0
- package/dist/i18n/messages.d.ts.map +1 -0
- package/dist/i18n/messages.js +2 -0
- package/dist/i18n/messages.js.map +1 -0
- package/dist/i18n/pt-BR.d.ts +4 -0
- package/dist/i18n/pt-BR.d.ts.map +1 -0
- package/dist/i18n/pt-BR.js +175 -0
- package/dist/i18n/pt-BR.js.map +1 -0
- package/dist/i18n/ru.d.ts +4 -0
- package/dist/i18n/ru.d.ts.map +1 -0
- package/dist/i18n/ru.js +175 -0
- package/dist/i18n/ru.js.map +1 -0
- package/dist/i18n/zh-CN.d.ts +4 -0
- package/dist/i18n/zh-CN.d.ts.map +1 -0
- package/dist/i18n/zh-CN.js +175 -0
- package/dist/i18n/zh-CN.js.map +1 -0
- package/dist/i18n/zh-TW.d.ts +4 -0
- package/dist/i18n/zh-TW.d.ts.map +1 -0
- package/dist/i18n/zh-TW.js +175 -0
- package/dist/i18n/zh-TW.js.map +1 -0
- package/dist/icons.d.ts +97 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +103 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/insert.d.ts +21 -0
- package/dist/insert.d.ts.map +1 -0
- package/dist/insert.js +129 -0
- package/dist/insert.js.map +1 -0
- package/dist/menu-action.d.ts +73 -0
- package/dist/menu-action.d.ts.map +1 -0
- package/dist/menu-action.js +89 -0
- package/dist/menu-action.js.map +1 -0
- package/dist/mode.d.ts +21 -0
- package/dist/mode.d.ts.map +1 -0
- package/dist/mode.js +17 -0
- package/dist/mode.js.map +1 -0
- package/dist/new-slide.d.ts +21 -0
- package/dist/new-slide.d.ts.map +1 -0
- package/dist/new-slide.js +63 -0
- package/dist/new-slide.js.map +1 -0
- package/dist/page-controls.d.ts +20 -0
- package/dist/page-controls.d.ts.map +1 -0
- package/dist/page-controls.js +99 -0
- package/dist/page-controls.js.map +1 -0
- package/dist/paint.d.ts +52 -0
- package/dist/paint.d.ts.map +1 -0
- package/dist/paint.js +262 -0
- package/dist/paint.js.map +1 -0
- package/dist/ruler.d.ts +10 -0
- package/dist/ruler.d.ts.map +1 -0
- package/dist/ruler.js +97 -0
- package/dist/ruler.js.map +1 -0
- package/dist/state.d.ts +85 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +28 -0
- package/dist/state.js.map +1 -0
- package/dist/styles.d.ts +2 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +758 -0
- package/dist/styles.js.map +1 -0
- package/dist/tabs.d.ts +11 -0
- package/dist/tabs.d.ts.map +1 -0
- package/dist/tabs.js +153 -0
- package/dist/tabs.js.map +1 -0
- package/dist/text-format.d.ts +114 -0
- package/dist/text-format.d.ts.map +1 -0
- package/dist/text-format.js +315 -0
- package/dist/text-format.js.map +1 -0
- package/dist/tools.d.ts +35 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +41 -0
- package/dist/tools.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/dist/worker/handlers.d.ts +11 -0
- package/dist/worker/handlers.d.ts.map +1 -0
- package/dist/worker/handlers.js +127 -0
- package/dist/worker/handlers.js.map +1 -0
- package/dist/worker/protocol.d.ts +190 -0
- package/dist/worker/protocol.d.ts.map +1 -0
- package/dist/worker/protocol.js +2 -0
- package/dist/worker/protocol.js.map +1 -0
- package/dist/worker/worker-source.d.ts +3 -0
- package/dist/worker/worker-source.d.ts.map +1 -0
- package/dist/worker/worker-source.js +11 -0
- package/dist/worker/worker.d.ts +2 -0
- package/dist/worker/worker.d.ts.map +1 -0
- package/dist/worker/worker.js +6 -0
- package/dist/worker/worker.js.map +1 -0
- package/package.json +68 -5
package/dist/commands.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// The Text, Shape and Object tabs' commands: character and paragraph formatting
|
|
2
|
+
// over the text selection, and the Fill / Line / Arrange controls over a
|
|
3
|
+
// drawing's shapes or a PDF's page objects.
|
|
4
|
+
import { allowsEdit, ICON_FILL, ICON_STROKE, ICON_TEXT_HIGHLIGHT } from "@docmentis/udoc-ui/internal";
|
|
5
|
+
import { OBJECT_ARRANGE_MENU, SHAPE_ARRANGE_MENU } from "./arrange.js";
|
|
6
|
+
import { fontFamilyControl, fontSizeControl, listControl, textFormatControl } from "./components/TextControls.js";
|
|
7
|
+
import { ICON_ARRANGE, ICON_BOLD, ICON_FONT_SIZE, ICON_FONTS, ICON_ITALIC, ICON_LINE_SPACING, ICON_LIST_BULLET, ICON_LIST_NUMBER, ICON_PARAGRAPH_LEFT, ICON_STRIKETHROUGH, ICON_SUBSCRIPT, ICON_SUPERSCRIPT, ICON_TEXT_FILL, ICON_UNDERLINE, ICON_WIDTH_SCALE, } from "./icons.js";
|
|
8
|
+
import { paintControl } from "./paint.js";
|
|
9
|
+
import { LINE_SPACING_MENU, PARAGRAPH_ALIGN_MENU, whenParagraphFormat, whenTextFormat, whenWidthScale, WIDTH_SCALE_MENU, } from "./text-format.js";
|
|
10
|
+
/**
|
|
11
|
+
* The format commands, their controls built over `tools` — read when the ribbon
|
|
12
|
+
* builds a control, which it does only on an open document's strip, so after
|
|
13
|
+
* edit mode is mounted.
|
|
14
|
+
*/
|
|
15
|
+
export function formatCommands(tools) {
|
|
16
|
+
// A character toggle: lit while the selection carries `property`.
|
|
17
|
+
const textFormat = (id, label, icon, property) => ({
|
|
18
|
+
id,
|
|
19
|
+
label,
|
|
20
|
+
icon,
|
|
21
|
+
group: "textStyle",
|
|
22
|
+
run: {
|
|
23
|
+
kind: "control",
|
|
24
|
+
cluster: "toggle",
|
|
25
|
+
create: (env) => textFormatControl(env, { id, icon, property }, tools()),
|
|
26
|
+
},
|
|
27
|
+
enabledWhen: whenTextFormat,
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
// Text tab — the font picker, the point-size field, then the Bold /
|
|
31
|
+
// Italic toggles. Each mirrors the selection's resolved format and
|
|
32
|
+
// lowers to a character-property text edit, so all gate on the engine's
|
|
33
|
+
// text `setCharacterProperties` capability (`whenTextFormat`): live over
|
|
34
|
+
// a non-empty text range, greyed on a bare caret or a non-text selection.
|
|
35
|
+
fontFamily: {
|
|
36
|
+
id: "fontFamily",
|
|
37
|
+
label: "command.fontFamily",
|
|
38
|
+
icon: ICON_FONTS,
|
|
39
|
+
group: "font",
|
|
40
|
+
run: { kind: "control", create: (env) => fontFamilyControl(env, "fontFamily", tools()) },
|
|
41
|
+
enabledWhen: whenTextFormat,
|
|
42
|
+
},
|
|
43
|
+
fontSize: {
|
|
44
|
+
id: "fontSize",
|
|
45
|
+
label: "command.fontSize",
|
|
46
|
+
icon: ICON_FONT_SIZE,
|
|
47
|
+
group: "font",
|
|
48
|
+
run: { kind: "control", create: (env) => fontSizeControl(env, "fontSize", tools()) },
|
|
49
|
+
enabledWhen: whenTextFormat,
|
|
50
|
+
},
|
|
51
|
+
// The character-format toggles are their own group ("textStyle"), split
|
|
52
|
+
// from the font fields above so a divider fences the toggle cluster off
|
|
53
|
+
// from the value-fields — the fields hold a value (bordered), the toggles
|
|
54
|
+
// don't (flat), and the divider is what marks that boundary now that
|
|
55
|
+
// neither wears a box.
|
|
56
|
+
bold: textFormat("bold", "command.bold", ICON_BOLD, "bold"),
|
|
57
|
+
italic: textFormat("italic", "command.italic", ICON_ITALIC, "italic"),
|
|
58
|
+
underline: textFormat("underline", "command.underline", ICON_UNDERLINE, "underline"),
|
|
59
|
+
strikethrough: textFormat("strikethrough", "command.strikethrough", ICON_STRIKETHROUGH, "strikethrough"),
|
|
60
|
+
superscript: textFormat("superscript", "command.superscript", ICON_SUPERSCRIPT, "superscript"),
|
|
61
|
+
subscript: textFormat("subscript", "command.subscript", ICON_SUBSCRIPT, "subscript"),
|
|
62
|
+
// Scale — the horizontal glyph stretch (`w:w`), as a dropdown of Word's
|
|
63
|
+
// presets. Word keeps it in its Font dialog; with no dialog here it rides
|
|
64
|
+
// the band beside the toggles.
|
|
65
|
+
widthScale: {
|
|
66
|
+
id: "widthScale",
|
|
67
|
+
label: "command.widthScale",
|
|
68
|
+
icon: ICON_WIDTH_SCALE,
|
|
69
|
+
group: "textStyle",
|
|
70
|
+
run: { kind: "menu", menu: WIDTH_SCALE_MENU },
|
|
71
|
+
enabledWhen: whenWidthScale,
|
|
72
|
+
},
|
|
73
|
+
// Text color + highlight — dropdowns mirroring the selection's span color
|
|
74
|
+
// over the shared color picker (the Fill / Line machinery, `text` /
|
|
75
|
+
// `highlight` channels). A span color is a character property, so they
|
|
76
|
+
// gate with the sibling text controls on `setCharacterProperties`
|
|
77
|
+
// (`whenTextFormat`).
|
|
78
|
+
textFill: {
|
|
79
|
+
id: "textFill",
|
|
80
|
+
label: "command.textFill",
|
|
81
|
+
icon: ICON_TEXT_FILL,
|
|
82
|
+
group: "font",
|
|
83
|
+
run: {
|
|
84
|
+
kind: "control",
|
|
85
|
+
cluster: "paint",
|
|
86
|
+
create: (env) => paintControl(env, { id: "textFill", icon: ICON_TEXT_FILL, channel: "text" }, tools()),
|
|
87
|
+
},
|
|
88
|
+
enabledWhen: whenTextFormat,
|
|
89
|
+
},
|
|
90
|
+
textHighlight: {
|
|
91
|
+
id: "textHighlight",
|
|
92
|
+
label: "command.textHighlight",
|
|
93
|
+
icon: ICON_TEXT_HIGHLIGHT,
|
|
94
|
+
group: "font",
|
|
95
|
+
run: {
|
|
96
|
+
kind: "control",
|
|
97
|
+
cluster: "paint",
|
|
98
|
+
create: (env) => paintControl(env, { id: "textHighlight", icon: ICON_TEXT_HIGHLIGHT, channel: "highlight" }, tools()),
|
|
99
|
+
},
|
|
100
|
+
enabledWhen: whenTextFormat,
|
|
101
|
+
},
|
|
102
|
+
// The paragraph half of the Text tab — its own group ("paragraph"), so a
|
|
103
|
+
// divider fences it off from the character controls above: those act on
|
|
104
|
+
// the spans a selection *covers*, these on the paragraphs it *touches*,
|
|
105
|
+
// and a bare caret lights the second set while greying the first. Four
|
|
106
|
+
// controls butted into one cluster, each with its long tail inside its
|
|
107
|
+
// own menu.
|
|
108
|
+
paragraphAlign: {
|
|
109
|
+
id: "paragraphAlign",
|
|
110
|
+
label: "command.paragraphAlign",
|
|
111
|
+
icon: ICON_PARAGRAPH_LEFT,
|
|
112
|
+
group: "paragraph",
|
|
113
|
+
run: { kind: "menu", menu: PARAGRAPH_ALIGN_MENU, cluster: "paragraph" },
|
|
114
|
+
enabledWhen: whenParagraphFormat,
|
|
115
|
+
},
|
|
116
|
+
lineSpacing: {
|
|
117
|
+
id: "lineSpacing",
|
|
118
|
+
label: "command.lineSpacing",
|
|
119
|
+
icon: ICON_LINE_SPACING,
|
|
120
|
+
group: "paragraph",
|
|
121
|
+
run: { kind: "menu", menu: LINE_SPACING_MENU, cluster: "paragraph" },
|
|
122
|
+
enabledWhen: whenParagraphFormat,
|
|
123
|
+
},
|
|
124
|
+
bulletList: {
|
|
125
|
+
id: "bulletList",
|
|
126
|
+
label: "command.bulletList",
|
|
127
|
+
icon: ICON_LIST_BULLET,
|
|
128
|
+
group: "paragraph",
|
|
129
|
+
run: {
|
|
130
|
+
kind: "control",
|
|
131
|
+
cluster: "paragraph",
|
|
132
|
+
create: (env) => listControl(env, { id: "bulletList", icon: ICON_LIST_BULLET, list: "bulleted" }, tools()),
|
|
133
|
+
},
|
|
134
|
+
enabledWhen: whenParagraphFormat,
|
|
135
|
+
},
|
|
136
|
+
numberList: {
|
|
137
|
+
id: "numberList",
|
|
138
|
+
label: "command.numberList",
|
|
139
|
+
icon: ICON_LIST_NUMBER,
|
|
140
|
+
group: "paragraph",
|
|
141
|
+
run: {
|
|
142
|
+
kind: "control",
|
|
143
|
+
cluster: "paragraph",
|
|
144
|
+
create: (env) => listControl(env, { id: "numberList", icon: ICON_LIST_NUMBER, list: "numbered" }, tools()),
|
|
145
|
+
},
|
|
146
|
+
enabledWhen: whenParagraphFormat,
|
|
147
|
+
},
|
|
148
|
+
// Shape tab — the Fill / Line dropdowns. The color bar reflects the
|
|
149
|
+
// selection's color; the caret opens the picker. Enabled when the
|
|
150
|
+
// selection accepts the paint edit — a drawing shape's `setShapeFill` /
|
|
151
|
+
// `setShapeLine`.
|
|
152
|
+
shapeFillColor: {
|
|
153
|
+
id: "shapeFillColor",
|
|
154
|
+
label: "command.shapeFillColor",
|
|
155
|
+
icon: ICON_FILL,
|
|
156
|
+
group: "paint",
|
|
157
|
+
run: {
|
|
158
|
+
kind: "control",
|
|
159
|
+
cluster: "paint",
|
|
160
|
+
create: (env) => paintControl(env, { id: "shapeFillColor", icon: ICON_FILL, channel: "fill" }, tools()),
|
|
161
|
+
},
|
|
162
|
+
enabledWhen: (c) => allowsEdit(c.selection, "setShapeFill"),
|
|
163
|
+
},
|
|
164
|
+
shapeStrokeColor: {
|
|
165
|
+
id: "shapeStrokeColor",
|
|
166
|
+
label: "command.shapeStrokeColor",
|
|
167
|
+
icon: ICON_STROKE,
|
|
168
|
+
group: "paint",
|
|
169
|
+
run: {
|
|
170
|
+
kind: "control",
|
|
171
|
+
cluster: "paint",
|
|
172
|
+
create: (env) => paintControl(env, { id: "shapeStrokeColor", icon: ICON_STROKE, channel: "stroke" }, tools()),
|
|
173
|
+
},
|
|
174
|
+
enabledWhen: (c) => allowsEdit(c.selection, "setShapeLine"),
|
|
175
|
+
},
|
|
176
|
+
// The Shape tab's one arrangement button. Its dropdown nests Order /
|
|
177
|
+
// Align / Rotate submenus plus Group / Ungroup; it greys out exactly when
|
|
178
|
+
// the whole menu would be dead (nothing selected, or a lone shape that
|
|
179
|
+
// can't move, align, rotate, or (un)group).
|
|
180
|
+
shapeArrange: {
|
|
181
|
+
id: "shapeArrange",
|
|
182
|
+
label: "command.shapeArrange",
|
|
183
|
+
icon: ICON_ARRANGE,
|
|
184
|
+
group: "arrange",
|
|
185
|
+
run: { kind: "menu", menu: SHAPE_ARRANGE_MENU },
|
|
186
|
+
enabledWhen: (c) => SHAPE_ARRANGE_MENU.some((i) => i.enabledWhen(c)),
|
|
187
|
+
},
|
|
188
|
+
// Object tab — the PDF twins of the Shape tab's three: Fill / Line gated
|
|
189
|
+
// on a page object's `setNonstrokingStyle` / `setStrokingStyle`, and
|
|
190
|
+
// Arrange over its own menu of object edits.
|
|
191
|
+
objectFillColor: {
|
|
192
|
+
id: "objectFillColor",
|
|
193
|
+
label: "command.objectFillColor",
|
|
194
|
+
icon: ICON_FILL,
|
|
195
|
+
group: "paint",
|
|
196
|
+
run: {
|
|
197
|
+
kind: "control",
|
|
198
|
+
cluster: "paint",
|
|
199
|
+
create: (env) => paintControl(env, { id: "objectFillColor", icon: ICON_FILL, channel: "fill" }, tools()),
|
|
200
|
+
},
|
|
201
|
+
enabledWhen: (c) => allowsEdit(c.selection, "setNonstrokingStyle"),
|
|
202
|
+
},
|
|
203
|
+
objectStrokeColor: {
|
|
204
|
+
id: "objectStrokeColor",
|
|
205
|
+
label: "command.objectStrokeColor",
|
|
206
|
+
icon: ICON_STROKE,
|
|
207
|
+
group: "paint",
|
|
208
|
+
run: {
|
|
209
|
+
kind: "control",
|
|
210
|
+
cluster: "paint",
|
|
211
|
+
create: (env) => paintControl(env, { id: "objectStrokeColor", icon: ICON_STROKE, channel: "stroke" }, tools()),
|
|
212
|
+
},
|
|
213
|
+
enabledWhen: (c) => allowsEdit(c.selection, "setStrokingStyle"),
|
|
214
|
+
},
|
|
215
|
+
objectArrange: {
|
|
216
|
+
id: "objectArrange",
|
|
217
|
+
label: "command.objectArrange",
|
|
218
|
+
icon: ICON_ARRANGE,
|
|
219
|
+
group: "arrange",
|
|
220
|
+
run: { kind: "menu", menu: OBJECT_ARRANGE_MENU },
|
|
221
|
+
enabledWhen: (c) => OBJECT_ARRANGE_MENU.some((i) => i.enabledWhen(c)),
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { MenuController, MenuControllerOptions } from "@docmentis/udoc-ui/internal";
|
|
2
|
+
/** A combobox's field content — a typeable value paired with a dropdown list. */
|
|
3
|
+
export interface ComboBoxContent {
|
|
4
|
+
/** Accessible name + tooltip for the field and its list toggle. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Extra class names appended to the field wrapper (e.g. a width class). */
|
|
7
|
+
className?: string;
|
|
8
|
+
/** The input's `inputmode` hint — e.g. `"decimal"` for a numeric field. */
|
|
9
|
+
inputMode?: "text" | "numeric" | "decimal";
|
|
10
|
+
}
|
|
11
|
+
export interface ComboBox {
|
|
12
|
+
/** The positioned field wrapper — the input, caret, and menu live inside it. */
|
|
13
|
+
readonly el: HTMLElement;
|
|
14
|
+
/** The typeable value field — the combobox's keyboard entry point. */
|
|
15
|
+
readonly input: HTMLInputElement;
|
|
16
|
+
/** The caret that opens the list. A mouse affordance, not a tab stop; the
|
|
17
|
+
* input is the field's single keyboard focus. */
|
|
18
|
+
readonly caret: HTMLButtonElement;
|
|
19
|
+
/** The floating `.udoc-menu` listbox to fill with options. */
|
|
20
|
+
readonly menu: HTMLElement;
|
|
21
|
+
readonly controller: MenuController;
|
|
22
|
+
destroy(): void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A combobox: a bordered field pairing a typeable {@link HTMLInputElement} with a
|
|
26
|
+
* caret that opens a `.udoc-menu` listbox — the editable analogue of
|
|
27
|
+
* {@link createDropdownButton}. The caller fills `menu` on open (as with a
|
|
28
|
+
* dropdown) and wires the input's commit / mirror behavior; both picking a value
|
|
29
|
+
* from the list and typing one that isn't in it are first-class. The outline is
|
|
30
|
+
* the shared field signal (see `.udoc-btn--field`).
|
|
31
|
+
*
|
|
32
|
+
* The caret is the menu's trigger, so a click on the input (also inside the
|
|
33
|
+
* wrapper) leaves an open list open — you can open the list and then type.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createComboBox(content: ComboBoxContent, options?: {
|
|
36
|
+
menuLabel?: string;
|
|
37
|
+
} & MenuControllerOptions): ComboBox;
|
|
38
|
+
//# sourceMappingURL=ComboBox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComboBox.d.ts","sourceRoot":"","sources":["../../src/components/ComboBox.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEzF,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC5B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;CAC9C;AAED,MAAM,WAAW,QAAQ;IACrB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC;sDACkD;IAClD,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,OAAO,IAAI,IAAI,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC1B,OAAO,EAAE,eAAe,EACxB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,qBAA0B,GAC7D,QAAQ,CA2CV"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// A combobox — a typeable value field paired with a dropdown list: the Text
|
|
2
|
+
// tab's font and size fields.
|
|
3
|
+
import { alignMenuToBounds, createMenuController, ICON_CHEVRON_DOWN } from "@docmentis/udoc-ui/internal";
|
|
4
|
+
/**
|
|
5
|
+
* A combobox: a bordered field pairing a typeable {@link HTMLInputElement} with a
|
|
6
|
+
* caret that opens a `.udoc-menu` listbox — the editable analogue of
|
|
7
|
+
* {@link createDropdownButton}. The caller fills `menu` on open (as with a
|
|
8
|
+
* dropdown) and wires the input's commit / mirror behavior; both picking a value
|
|
9
|
+
* from the list and typing one that isn't in it are first-class. The outline is
|
|
10
|
+
* the shared field signal (see `.udoc-btn--field`).
|
|
11
|
+
*
|
|
12
|
+
* The caret is the menu's trigger, so a click on the input (also inside the
|
|
13
|
+
* wrapper) leaves an open list open — you can open the list and then type.
|
|
14
|
+
*/
|
|
15
|
+
export function createComboBox(content, options = {}) {
|
|
16
|
+
const el = document.createElement("div");
|
|
17
|
+
el.className = content.className ? `udoc-combobox ${content.className}` : "udoc-combobox";
|
|
18
|
+
const input = document.createElement("input");
|
|
19
|
+
input.className = "udoc-combobox__input";
|
|
20
|
+
input.type = "text";
|
|
21
|
+
input.title = content.label;
|
|
22
|
+
input.setAttribute("aria-label", content.label);
|
|
23
|
+
// No native autofill dropdown — it would fight our own listbox panel.
|
|
24
|
+
input.setAttribute("autocomplete", "off");
|
|
25
|
+
if (content.inputMode)
|
|
26
|
+
input.inputMode = content.inputMode;
|
|
27
|
+
const caret = document.createElement("button");
|
|
28
|
+
caret.className = "udoc-combobox__caret";
|
|
29
|
+
caret.innerHTML = ICON_CHEVRON_DOWN;
|
|
30
|
+
// The input carries the field's keyboard focus; the caret is click-only so it
|
|
31
|
+
// doesn't add a second tab stop for one control.
|
|
32
|
+
caret.tabIndex = -1;
|
|
33
|
+
caret.title = content.label;
|
|
34
|
+
caret.setAttribute("aria-label", content.label);
|
|
35
|
+
caret.setAttribute("aria-haspopup", "listbox");
|
|
36
|
+
const menu = document.createElement("div");
|
|
37
|
+
menu.className = "udoc-menu";
|
|
38
|
+
menu.setAttribute("role", "listbox");
|
|
39
|
+
if (options.menuLabel)
|
|
40
|
+
menu.setAttribute("aria-label", options.menuLabel);
|
|
41
|
+
el.append(input, caret, menu);
|
|
42
|
+
// Compose the caller's onOpen (which fills the list) with the collision flip,
|
|
43
|
+
// running the flip last so it measures the built panel at its real width —
|
|
44
|
+
// mirrors createDropdownButton. `isInside` spans the whole wrapper so clicking
|
|
45
|
+
// the input doesn't dismiss an open list.
|
|
46
|
+
const userOnOpen = options.onOpen;
|
|
47
|
+
const controller = createMenuController(caret, menu, {
|
|
48
|
+
isInside: (t) => el.contains(t),
|
|
49
|
+
...options,
|
|
50
|
+
onOpen: () => {
|
|
51
|
+
userOnOpen?.();
|
|
52
|
+
alignMenuToBounds(caret, menu);
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
return { el, input, caret, menu, controller, destroy: () => controller.destroy() };
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=ComboBox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComboBox.js","sourceRoot":"","sources":["../../src/components/ComboBox.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,8BAA8B;AAC9B,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AA2BzG;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAC1B,OAAwB,EACxB,UAA0D,EAAE;IAE5D,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACzC,EAAE,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;IAE1F,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,SAAS,GAAG,sBAAsB,CAAC;IACzC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,sEAAsE;IACtE,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IAC1C,IAAI,OAAO,CAAC,SAAS;QAAE,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IAE3D,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC/C,KAAK,CAAC,SAAS,GAAG,sBAAsB,CAAC;IACzC,KAAK,CAAC,SAAS,GAAG,iBAAiB,CAAC;IACpC,8EAA8E;IAC9E,iDAAiD;IACjD,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IACpB,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;IAE/C,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC;IAC7B,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,SAAS;QAAE,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAE1E,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC9B,8EAA8E;IAC9E,2EAA2E;IAC3E,+EAA+E;IAC/E,0CAA0C;IAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IAClC,MAAM,UAAU,GAAG,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE;QACjD,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/B,GAAG,OAAO;QACV,MAAM,EAAE,GAAG,EAAE;YACT,UAAU,EAAE,EAAE,CAAC;YACf,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC;KACJ,CAAC,CAAC;IACH,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;AACvF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Action, Store, UIState } from "@docmentis/udoc-ui/internal";
|
|
2
|
+
import type { I18n } from "../i18n/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* The mode switcher — sits in the toolbar's right cluster, governing the
|
|
5
|
+
* commands to its left. Rendered only when `showModeSwitch` and more than one
|
|
6
|
+
* mode is offered — allowed by the host and entitled (the common embedded case
|
|
7
|
+
* fixes the mode up front, so this is usually absent). A standard {@link createDropdownButton} (bordered field
|
|
8
|
+
* trigger), so it matches every other dropdown by construction.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createModeSwitch(i18n: I18n): {
|
|
11
|
+
el: HTMLDivElement;
|
|
12
|
+
mount: (container: HTMLElement, store: Store<UIState, Action>) => void;
|
|
13
|
+
destroy: () => void;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=ModeSwitch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModeSwitch.d.ts","sourceRoot":"","sources":["../../src/components/ModeSwitch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAA2B,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACnG,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,kBAAkB,CAAC;AAsCzD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI;;uBAyDb,WAAW,SAAS,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,KAAG,IAAI;mBAOvD,IAAI;EAO3B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { createDropdownButton, createMenuItem, subscribeSelector } from "@docmentis/udoc-ui/internal";
|
|
2
|
+
import { modeEntitled } from "../mode.js";
|
|
3
|
+
import { editState } from "../state.js";
|
|
4
|
+
/** Human labels for each mode. */
|
|
5
|
+
const MODE_LABELS = {
|
|
6
|
+
view: "mode.view",
|
|
7
|
+
edit: "mode.edit",
|
|
8
|
+
};
|
|
9
|
+
function sliceEqual(a, b) {
|
|
10
|
+
return (a.mode === b.mode &&
|
|
11
|
+
a.allowedModes === b.allowedModes &&
|
|
12
|
+
a.features === b.features &&
|
|
13
|
+
a.showModeSwitch === b.showModeSwitch);
|
|
14
|
+
}
|
|
15
|
+
function selectSlice(s) {
|
|
16
|
+
const { allowedModes, showModeSwitch } = editState(s);
|
|
17
|
+
return { mode: s.mode, allowedModes, features: s.features, showModeSwitch };
|
|
18
|
+
}
|
|
19
|
+
/** The modes the switcher offers: the host's, less those the session is not
|
|
20
|
+
* entitled to. */
|
|
21
|
+
function offeredModes(slice) {
|
|
22
|
+
return slice.allowedModes.filter((mode) => modeEntitled(mode, slice.features));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The mode switcher — sits in the toolbar's right cluster, governing the
|
|
26
|
+
* commands to its left. Rendered only when `showModeSwitch` and more than one
|
|
27
|
+
* mode is offered — allowed by the host and entitled (the common embedded case
|
|
28
|
+
* fixes the mode up front, so this is usually absent). A standard {@link createDropdownButton} (bordered field
|
|
29
|
+
* trigger), so it matches every other dropdown by construction.
|
|
30
|
+
*/
|
|
31
|
+
export function createModeSwitch(i18n) {
|
|
32
|
+
const el = document.createElement("div");
|
|
33
|
+
el.className = "udoc-mode-switch";
|
|
34
|
+
let storeRef = null;
|
|
35
|
+
let unsub = null;
|
|
36
|
+
let dropdown = null;
|
|
37
|
+
// Signature of what's currently built, to avoid rebuilding identical DOM.
|
|
38
|
+
let builtKey = "";
|
|
39
|
+
function setMode(mode) {
|
|
40
|
+
storeRef?.dispatch({ type: "SET_MODE", mode });
|
|
41
|
+
}
|
|
42
|
+
function clearDropdown() {
|
|
43
|
+
dropdown?.destroy();
|
|
44
|
+
dropdown = null;
|
|
45
|
+
el.innerHTML = "";
|
|
46
|
+
}
|
|
47
|
+
function buildDropdown(slice) {
|
|
48
|
+
clearDropdown();
|
|
49
|
+
dropdown = createDropdownButton({ text: i18n.t(MODE_LABELS[slice.mode]), label: i18n.t("modeSwitch.label"), field: true }, { menuLabel: i18n.t("modeSwitch.label"), menuRole: "listbox" });
|
|
50
|
+
for (const mode of offeredModes(slice)) {
|
|
51
|
+
const item = createMenuItem({ text: i18n.t(MODE_LABELS[mode]), role: "option" });
|
|
52
|
+
const active = mode === slice.mode;
|
|
53
|
+
item.classList.toggle("udoc-menu__item--selected", active);
|
|
54
|
+
item.setAttribute("aria-selected", String(active));
|
|
55
|
+
item.addEventListener("click", (e) => {
|
|
56
|
+
e.stopPropagation();
|
|
57
|
+
setMode(mode);
|
|
58
|
+
dropdown?.controller.close();
|
|
59
|
+
});
|
|
60
|
+
dropdown.menu.appendChild(item);
|
|
61
|
+
}
|
|
62
|
+
el.appendChild(dropdown.el);
|
|
63
|
+
}
|
|
64
|
+
function applyState(slice) {
|
|
65
|
+
const modes = offeredModes(slice);
|
|
66
|
+
const visible = slice.showModeSwitch && modes.length > 1;
|
|
67
|
+
el.style.display = visible ? "" : "none";
|
|
68
|
+
if (!visible) {
|
|
69
|
+
clearDropdown();
|
|
70
|
+
builtKey = "";
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Rebuild structure only when the mode set or active mode changes.
|
|
74
|
+
const key = `${slice.mode}:${modes.join(",")}`;
|
|
75
|
+
if (key === builtKey)
|
|
76
|
+
return;
|
|
77
|
+
builtKey = key;
|
|
78
|
+
buildDropdown(slice);
|
|
79
|
+
}
|
|
80
|
+
function mount(container, store) {
|
|
81
|
+
storeRef = store;
|
|
82
|
+
container.appendChild(el);
|
|
83
|
+
applyState(selectSlice(store.getState()));
|
|
84
|
+
unsub = subscribeSelector(store, selectSlice, applyState, { equality: sliceEqual });
|
|
85
|
+
}
|
|
86
|
+
function destroy() {
|
|
87
|
+
if (unsub)
|
|
88
|
+
unsub();
|
|
89
|
+
clearDropdown();
|
|
90
|
+
el.remove();
|
|
91
|
+
}
|
|
92
|
+
return { el, mount, destroy };
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=ModeSwitch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModeSwitch.js","sourceRoot":"","sources":["../../src/components/ModeSwitch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { I18n } from "../i18n/index.js";
|
|
2
|
+
/** One pickable slide layout: the id a slide is created on, plus where its
|
|
3
|
+
* preview renders — the plane (a slide master's, `1..`) and the page within it
|
|
4
|
+
* (`1 + its index`; page 0 of that plane is the master). */
|
|
5
|
+
export interface LayoutOption {
|
|
6
|
+
/** The slide-layout id (hex key) — passed to `createSlide(index, layout)`. */
|
|
7
|
+
layout: string;
|
|
8
|
+
/** The layout plane the preview renders on (`1..`). */
|
|
9
|
+
plane: number;
|
|
10
|
+
/** The page index within that plane (`1..`; page 0 is the master). */
|
|
11
|
+
page: number;
|
|
12
|
+
/** The name the file gives the slide layout ("Title Slide"), or null for
|
|
13
|
+
* none. */
|
|
14
|
+
name: string | null;
|
|
15
|
+
}
|
|
16
|
+
/** What `open` needs: where the slide lands, the layouts to choose from, how to
|
|
17
|
+
* render a preview, and what a pick does. */
|
|
18
|
+
export interface NewSlideContext {
|
|
19
|
+
/** 0-based index the new slide is inserted at. */
|
|
20
|
+
insertIndex: number;
|
|
21
|
+
/** The layouts to offer, in roster order. */
|
|
22
|
+
options: LayoutOption[];
|
|
23
|
+
/** Render a one-shot preview of a page on a plane, at `scale` output px per
|
|
24
|
+
* point — resolves with a bitmap the caller owns. */
|
|
25
|
+
renderPreview: (plane: number, page: number, scale: number) => Promise<ImageBitmap>;
|
|
26
|
+
/** Create a new slide on `layout` at `insertIndex` and close. */
|
|
27
|
+
onPick: (layout: string) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the New-Slide picker modal. The returned handle is mounted once by the
|
|
31
|
+
* shell; `open` re-seeds it with the current layout roster each time.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createNewSlideModal(i18n: I18n): {
|
|
34
|
+
el: HTMLDivElement;
|
|
35
|
+
mount: (parent: HTMLElement) => void;
|
|
36
|
+
open: (context: NewSlideContext) => void;
|
|
37
|
+
close: () => void;
|
|
38
|
+
destroy: () => void;
|
|
39
|
+
};
|
|
40
|
+
export type NewSlideModal = ReturnType<typeof createNewSlideModal>;
|
|
41
|
+
//# sourceMappingURL=NewSlideModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NewSlideModal.d.ts","sourceRoot":"","sources":["../../src/components/NewSlideModal.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAM7C;;6DAE6D;AAC7D,MAAM,WAAW,YAAY;IACzB,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb;gBACY;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;8CAC8C;AAC9C,MAAM,WAAW,eAAe;IAC5B,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB;0DACsD;IACtD,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IACpF,iEAAiE;IACjE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI;;oBA4GnB,WAAW,KAAG,IAAI;oBAzBlB,eAAe,KAAG,IAAI;iBAa3B,IAAI;mBAwBF,IAAI;EAM3B;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// The New-Slide layout picker — a modal grid of slide-layout thumbnails, opened
|
|
2
|
+
// from the presentation Home tab's "New Slide" button. Picking a layout inserts
|
|
3
|
+
// a new slide built on it (its content placeholders seeded); the thumbnail *is*
|
|
4
|
+
// the layout's identity, since layouts carry no name/type in the model.
|
|
5
|
+
//
|
|
6
|
+
// Storeless and imperative, like the other modals (PageSettingsModal): mounted
|
|
7
|
+
// once by the shell and reused. `open(ctx)` seeds it with the layout roster, the
|
|
8
|
+
// preview renderer, and the pick callback that turns a click into a createSlide
|
|
9
|
+
// command; it owns no document state of its own.
|
|
10
|
+
//
|
|
11
|
+
// Layout previews render off a non-current plane (each slide master's own layout
|
|
12
|
+
// plane) via the plane-aware paged render path, so opening the picker never
|
|
13
|
+
// disturbs the slide plane the user is editing.
|
|
14
|
+
import { ICON_CLEAR, on } from "@docmentis/udoc-ui/internal";
|
|
15
|
+
/** Output pixels per document point for a layout preview — a modest raster
|
|
16
|
+
* (a 960-pt slide → 240 px), downscaled by CSS into its grid cell. */
|
|
17
|
+
const PREVIEW_SCALE = 0.25;
|
|
18
|
+
/**
|
|
19
|
+
* Build the New-Slide picker modal. The returned handle is mounted once by the
|
|
20
|
+
* shell; `open` re-seeds it with the current layout roster each time.
|
|
21
|
+
*/
|
|
22
|
+
export function createNewSlideModal(i18n) {
|
|
23
|
+
const el = document.createElement("div");
|
|
24
|
+
el.className = "udoc-slide-picker";
|
|
25
|
+
el.style.display = "none";
|
|
26
|
+
const backdrop = document.createElement("div");
|
|
27
|
+
backdrop.className = "udoc-slide-picker__backdrop";
|
|
28
|
+
const dialog = document.createElement("div");
|
|
29
|
+
dialog.className = "udoc-slide-picker__dialog";
|
|
30
|
+
dialog.setAttribute("role", "dialog");
|
|
31
|
+
dialog.setAttribute("aria-modal", "true");
|
|
32
|
+
dialog.setAttribute("aria-label", i18n.t("newSlide.label"));
|
|
33
|
+
const header = document.createElement("div");
|
|
34
|
+
header.className = "udoc-slide-picker__header";
|
|
35
|
+
const heading = document.createElement("h2");
|
|
36
|
+
heading.className = "udoc-slide-picker__heading";
|
|
37
|
+
heading.textContent = i18n.t("command.createSlide");
|
|
38
|
+
const closeBtn = document.createElement("button");
|
|
39
|
+
closeBtn.type = "button";
|
|
40
|
+
closeBtn.className = "udoc-slide-picker__close";
|
|
41
|
+
closeBtn.setAttribute("aria-label", i18n.t("common.close"));
|
|
42
|
+
closeBtn.title = i18n.t("common.close");
|
|
43
|
+
closeBtn.innerHTML = ICON_CLEAR;
|
|
44
|
+
header.append(heading, closeBtn);
|
|
45
|
+
const grid = document.createElement("div");
|
|
46
|
+
grid.className = "udoc-slide-picker__grid";
|
|
47
|
+
grid.setAttribute("role", "listbox");
|
|
48
|
+
grid.setAttribute("aria-label", i18n.t("newSlide.layouts"));
|
|
49
|
+
dialog.append(header, grid);
|
|
50
|
+
el.append(backdrop, dialog);
|
|
51
|
+
let isOpen = false;
|
|
52
|
+
let ctx = null;
|
|
53
|
+
// Bumped on every open/close so a preview that resolves after the picker
|
|
54
|
+
// moved on is discarded (its bitmap closed) instead of drawn stale.
|
|
55
|
+
let epoch = 0;
|
|
56
|
+
const unsubEvents = [];
|
|
57
|
+
function pick(layout) {
|
|
58
|
+
const chosen = ctx;
|
|
59
|
+
close();
|
|
60
|
+
chosen?.onPick(layout);
|
|
61
|
+
}
|
|
62
|
+
/** Build one layout cell: a button holding a canvas the preview draws into. */
|
|
63
|
+
function buildCell(option, index, myEpoch) {
|
|
64
|
+
const cell = document.createElement("button");
|
|
65
|
+
cell.type = "button";
|
|
66
|
+
cell.className = "udoc-slide-picker__cell";
|
|
67
|
+
cell.setAttribute("role", "option");
|
|
68
|
+
const name = option.name ?? i18n.t("newSlide.layout", { index: index + 1 });
|
|
69
|
+
cell.title = name;
|
|
70
|
+
cell.setAttribute("aria-label", name);
|
|
71
|
+
const canvas = document.createElement("canvas");
|
|
72
|
+
canvas.className = "udoc-slide-picker__canvas";
|
|
73
|
+
cell.appendChild(canvas);
|
|
74
|
+
on(cell, "click", () => pick(option.layout));
|
|
75
|
+
void ctx
|
|
76
|
+
?.renderPreview(option.plane, option.page, PREVIEW_SCALE)
|
|
77
|
+
.then((bitmap) => {
|
|
78
|
+
// The picker closed / reopened while this rendered — drop it.
|
|
79
|
+
if (myEpoch !== epoch) {
|
|
80
|
+
bitmap.close();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
canvas.width = bitmap.width;
|
|
84
|
+
canvas.height = bitmap.height;
|
|
85
|
+
canvas.getContext("2d")?.drawImage(bitmap, 0, 0);
|
|
86
|
+
bitmap.close();
|
|
87
|
+
cell.classList.add("udoc-slide-picker__cell--ready");
|
|
88
|
+
})
|
|
89
|
+
.catch(() => {
|
|
90
|
+
// A preview that fails to render just stays blank — the cell is
|
|
91
|
+
// still pickable (the layout id is valid regardless).
|
|
92
|
+
});
|
|
93
|
+
return cell;
|
|
94
|
+
}
|
|
95
|
+
function open(context) {
|
|
96
|
+
ctx = context;
|
|
97
|
+
epoch++;
|
|
98
|
+
const myEpoch = epoch;
|
|
99
|
+
grid.replaceChildren();
|
|
100
|
+
context.options.forEach((option, index) => {
|
|
101
|
+
grid.appendChild(buildCell(option, index, myEpoch));
|
|
102
|
+
});
|
|
103
|
+
isOpen = true;
|
|
104
|
+
el.style.display = "";
|
|
105
|
+
grid.querySelector(".udoc-slide-picker__cell")?.focus();
|
|
106
|
+
}
|
|
107
|
+
function close() {
|
|
108
|
+
if (!isOpen)
|
|
109
|
+
return;
|
|
110
|
+
isOpen = false;
|
|
111
|
+
ctx = null;
|
|
112
|
+
epoch++;
|
|
113
|
+
grid.replaceChildren();
|
|
114
|
+
el.style.display = "none";
|
|
115
|
+
}
|
|
116
|
+
on(closeBtn, "click", () => close());
|
|
117
|
+
on(backdrop, "click", () => close());
|
|
118
|
+
function mount(parent) {
|
|
119
|
+
parent.appendChild(el);
|
|
120
|
+
const onKeydown = (e) => {
|
|
121
|
+
if (isOpen && e.key === "Escape") {
|
|
122
|
+
e.stopPropagation();
|
|
123
|
+
close();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
document.addEventListener("keydown", onKeydown);
|
|
127
|
+
unsubEvents.push(() => document.removeEventListener("keydown", onKeydown));
|
|
128
|
+
}
|
|
129
|
+
function destroy() {
|
|
130
|
+
for (const off of unsubEvents)
|
|
131
|
+
off();
|
|
132
|
+
el.remove();
|
|
133
|
+
}
|
|
134
|
+
return { el, mount, open, close, destroy };
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=NewSlideModal.js.map
|