@wix/ricos-editor-elements 0.0.0-stage → 11.21.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/README.md CHANGED
@@ -1,3 +1,31 @@
1
- # Temporary Holding Version
1
+ # ricos-editor-elements
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ This project was bootstrapped with [Create Wix App](https://www.npmjs.com/package/@wix/create-app).
4
+ Read more about it in the [Wix CLI for Apps
5
+ documentation](https://dev.wix.com/docs/build-apps/developer-tools/cli/get-started/about-the-wix-cli-for-apps).
6
+
7
+ ## Setup 🔧
8
+
9
+ ##### Install dependencies:
10
+
11
+ ```console
12
+ yarn install
13
+ ```
14
+
15
+ ##### Pull environment variables:
16
+
17
+ ```console
18
+ yarn wix env pull
19
+ ```
20
+
21
+ This creates a `.env.local` file containing your app's credentials (client ID, secret, public key, etc.).
22
+ This file is required for `dev` and `build` to work, but is excluded from version control via `.gitignore`
23
+ because it contains secrets specific to your app. Each developer must run this command after cloning the repo.
24
+
25
+ ## Available Scripts
26
+
27
+ In the project directory, you can run:
28
+
29
+ ```console
30
+ yarn dev
31
+ ```
@@ -0,0 +1,4 @@
1
+ .root__bW8lC {
2
+ box-sizing: border-box;
3
+ background-color: var(--editor-ricos-palette-00-bgColor, var(--wst-base-1-color));
4
+ }
@@ -0,0 +1,602 @@
1
+ import { truncateContent, RicosViewer, pluginEmojiViewer, pluginHashtagViewer, pluginLinkViewer, pluginMentionsViewer, pluginTextColorViewer, pluginTextHighlightViewer, pluginSpoilerViewer } from "@wix/ricos";
2
+ import { pluginCollapsibleListLazy, pluginDividerLazy, pluginGiphyLazy, pluginImageLazy, pluginGalleryLazy, pluginVideoLazy, pluginAudioLazy, pluginFileUploadLazy, pluginTableLazy, pluginHtmlLazy, pluginLinkPreviewLazy, pluginVerticalEmbedLazy, pluginPollLazy, pluginLinkButtonLazy, pluginTocLazy } from "@wix/ricos/lazy";
3
+ import { useService } from "@wix/services-manager-react";
4
+ import { DeviceInfoDefinition } from "@wix/site-service-device-info/definition";
5
+ import { EditorContextDefinition } from "@wix/site-service-editor-context/definition";
6
+ import { LocaleDefinition } from "@wix/site-service-locale/definition";
7
+ import { SiteInfoDefinition } from "@wix/site-service-site-info/definition";
8
+ import { UrlDefinition } from "@wix/site-service-url/definition";
9
+ import "@wix/ricos/css/ricos-viewer.global.css";
10
+ import "@wix/ricos/css/plugin-hashtag-viewer.global.css";
11
+ import "@wix/ricos/css/plugin-mentions-viewer.global.css";
12
+ import "@wix/ricos/css/plugin-spoiler-viewer.global.css";
13
+ import "@wix/ricos/css/plugin-button-viewer.global.css";
14
+ import "@wix/ricos/css/plugin-divider-viewer.global.css";
15
+ import "@wix/ricos/css/plugin-vertical-embed-viewer.global.css";
16
+ import "@wix/ricos/css/plugin-collapsible-list-viewer.global.css";
17
+ import "@wix/ricos/css/plugin-file-upload-viewer.global.css";
18
+ import "@wix/ricos/css/plugin-gallery-viewer.global.css";
19
+ import "@wix/ricos/css/plugin-giphy-viewer.global.css";
20
+ import "@wix/ricos/css/plugin-html-viewer.global.css";
21
+ import "@wix/ricos/css/plugin-image-viewer.global.css";
22
+ import "@wix/ricos/css/plugin-link-viewer.global.css";
23
+ import "@wix/ricos/css/plugin-link-preview-viewer.global.css";
24
+ import "@wix/ricos/css/plugin-social-polls-viewer.global.css";
25
+ import "@wix/ricos/css/plugin-table-viewer.global.css";
26
+ import "@wix/ricos/css/plugin-video-viewer.global.css";
27
+ import "@wix/ricos/css/plugin-audio-viewer.global.css";
28
+ import "@wix/ricos/css/plugin-toc-viewer.global.css";
29
+ import React, { useState } from "react";
30
+ import { CSS_PROPERTIES, DISPLAY_GROUPS, ELEMENTS, DATA } from "@wix/react-component-schema";
31
+ import './Viewer.css';const customPropKey = (tag, cssVar) => `editor-ricos-${tag}-${cssVar}`;
32
+ const CONTENT_VIEWER_SELECTOR = '[data-id="content-viewer"]';
33
+ const TEXT_LEVELS = [
34
+ { tag: "h1", displayName: "Heading 1", siteFont: "--wst-heading-1-font" },
35
+ { tag: "h2", displayName: "Heading 2", siteFont: "--wst-heading-2-font" },
36
+ { tag: "h3", displayName: "Heading 3", siteFont: "--wst-heading-3-font" },
37
+ { tag: "h4", displayName: "Heading 4", siteFont: "--wst-heading-4-font" },
38
+ { tag: "h5", displayName: "Heading 5", siteFont: "--wst-heading-5-font" },
39
+ { tag: "h6", displayName: "Heading 6", siteFont: "--wst-heading-6-font" },
40
+ { tag: "p", displayName: "Paragraph", siteFont: "--wst-paragraph-2-font" }
41
+ ];
42
+ const siteFontOf = (tag) => {
43
+ var _a;
44
+ return `var(${(_a = TEXT_LEVELS.find((level) => level.tag === tag)) == null ? void 0 : _a.siteFont})`;
45
+ };
46
+ const FONT_PROPS = [
47
+ {
48
+ cssVar: "font",
49
+ styleProp: "font",
50
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.font,
51
+ displayName: "Font"
52
+ },
53
+ {
54
+ cssVar: "letter-spacing",
55
+ styleProp: "letterSpacing",
56
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.letterSpacing,
57
+ displayName: "Letter spacing"
58
+ },
59
+ {
60
+ cssVar: "color",
61
+ styleProp: "color",
62
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.color,
63
+ displayName: "Color"
64
+ }
65
+ ];
66
+ const fontCssCustomProperties = (tag) => Object.fromEntries(
67
+ FONT_PROPS.map(({ cssVar, type, displayName }) => [
68
+ customPropKey(tag, cssVar),
69
+ {
70
+ cssPropertyType: type,
71
+ displayName,
72
+ ...cssVar === "font" ? { defaultValue: siteFontOf(tag) } : {}
73
+ }
74
+ ])
75
+ );
76
+ const fontTextGroup = (tag, displayName) => ({
77
+ displayName,
78
+ groupType: DISPLAY_GROUPS.GROUP_TYPE.text,
79
+ text: Object.fromEntries(
80
+ FONT_PROPS.map(({ styleProp, cssVar }) => [styleProp, customPropKey(tag, cssVar)])
81
+ )
82
+ });
83
+ const fontElement = (tag, displayName) => ({
84
+ elementType: ELEMENTS.ELEMENT_TYPE.inlineElement,
85
+ inlineElement: {
86
+ selector: CONTENT_VIEWER_SELECTOR,
87
+ displayName,
88
+ behaviors: { selectable: false },
89
+ cssCustomProperties: fontCssCustomProperties(tag),
90
+ displayGroups: { [tag]: fontTextGroup(tag, displayName) }
91
+ }
92
+ });
93
+ Object.fromEntries(
94
+ TEXT_LEVELS.map(({ tag, displayName }) => [tag, fontElement(tag, displayName)])
95
+ );
96
+ ({
97
+ groupType: DISPLAY_GROUPS.GROUP_TYPE.elements,
98
+ elements: { items: TEXT_LEVELS.map(({ tag }) => tag) }
99
+ });
100
+ const fontVarsForTag = (tag) => Object.fromEntries(
101
+ FONT_PROPS.map(({ styleProp, cssVar }) => [
102
+ styleProp,
103
+ cssVar === "font" ? `var(--${customPropKey(tag, cssVar)}, ${siteFontOf(tag)})` : `var(--${customPropKey(tag, cssVar)})`
104
+ ])
105
+ );
106
+ const viewerCustomStyles = {
107
+ h1: fontVarsForTag("h1"),
108
+ h2: fontVarsForTag("h2"),
109
+ h3: fontVarsForTag("h3"),
110
+ h4: fontVarsForTag("h4"),
111
+ h5: fontVarsForTag("h5"),
112
+ h6: fontVarsForTag("h6"),
113
+ p: fontVarsForTag("p")
114
+ };
115
+ const viewerEllipsisStyle = {
116
+ color: "var(--wst-links-and-actions-color)",
117
+ font: `var(--${customPropKey("p", "font")}, ${siteFontOf("p")})`,
118
+ lineHeight: "1.5em",
119
+ textDecoration: "underline",
120
+ cursor: "pointer",
121
+ marginTop: "1em"
122
+ };
123
+ const FORMATTING_NODE_TYPES = /* @__PURE__ */ new Set([
124
+ "PARAGRAPH",
125
+ "HEADING",
126
+ "BLOCKQUOTE",
127
+ "ORDERED_LIST",
128
+ "BULLETED_LIST",
129
+ "CODE_BLOCK"
130
+ ]);
131
+ const excludePlugins = (content) => {
132
+ const nodes = content.nodes.filter((node) => FORMATTING_NODE_TYPES.has(node.type));
133
+ const isTruncated = nodes.length !== content.nodes.length;
134
+ return { content: isTruncated ? { ...content, nodes } : content, isTruncated };
135
+ };
136
+ const trimByWords = (content, wordsCount) => {
137
+ const withoutPlugins = excludePlugins(content);
138
+ const truncated = truncateContent(withoutPlugins.content, { wordsCount });
139
+ return {
140
+ content: truncated.content,
141
+ isTruncated: truncated.isTruncated || withoutPlugins.isTruncated
142
+ };
143
+ };
144
+ const trimByBlocks = (content, blocksCount, trimPlugins) => {
145
+ const base = trimPlugins ? excludePlugins(content) : { content, isTruncated: false };
146
+ const truncated = truncateContent(base.content, { blocksCount });
147
+ return {
148
+ content: truncated.content,
149
+ isTruncated: truncated.isTruncated || base.isTruncated
150
+ };
151
+ };
152
+ const trimTrailingEmptyParagraph = (content) => {
153
+ var _a;
154
+ const last = content.nodes[content.nodes.length - 1];
155
+ if ((last == null ? void 0 : last.type) === "PARAGRAPH" && !((_a = last.nodes) == null ? void 0 : _a.length)) {
156
+ return { ...content, nodes: content.nodes.slice(0, -1) };
157
+ }
158
+ return content;
159
+ };
160
+ const defaultEllipsisStyle = {
161
+ display: "inline-block",
162
+ padding: 0,
163
+ border: "none",
164
+ background: "none",
165
+ ...viewerEllipsisStyle
166
+ };
167
+ const ContentTrimmer = ({
168
+ content,
169
+ trimEnabled,
170
+ trimMode,
171
+ trimLengthParagraph,
172
+ trimLengthWord,
173
+ trimExclude,
174
+ trimEllipsisEnabled,
175
+ trimEllipsisExpandText,
176
+ trimEllipsisCollapseText,
177
+ ellipsisStyle,
178
+ children
179
+ }) => {
180
+ const [collapsed, setCollapsed] = useState(true);
181
+ if (!trimEnabled) {
182
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children(content));
183
+ }
184
+ const { content: truncated, isTruncated } = trimMode === "word" ? trimByWords(content, trimLengthWord) : trimByBlocks(content, trimLengthParagraph, trimExclude === "plugins");
185
+ const shownContent = isTruncated && collapsed ? trimTrailingEmptyParagraph(truncated) : content;
186
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children(shownContent), isTruncated && trimEllipsisEnabled ? /* @__PURE__ */ React.createElement(
187
+ "button",
188
+ {
189
+ type: "button",
190
+ style: { ...defaultEllipsisStyle, ...ellipsisStyle },
191
+ onClick: () => setCollapsed((isCollapsed) => !isCollapsed),
192
+ "data-hook": "trim-ellipsis-button"
193
+ },
194
+ collapsed ? trimEllipsisExpandText : trimEllipsisCollapseText
195
+ ) : null);
196
+ };
197
+ const DEFAULT_CONTENT_TEXT = "No content provided";
198
+ const DEFAULT_CONTENT_NODE_ID = "ricos-viewer-default-content";
199
+ const isContentProvided = (content) => {
200
+ var _a, _b, _c;
201
+ if (!((_a = content == null ? void 0 : content.nodes) == null ? void 0 : _a.length)) {
202
+ return false;
203
+ }
204
+ const [firstNode, ...restNodes] = content.nodes;
205
+ const [textNode, ...restTextNodes] = firstNode.nodes ?? [];
206
+ const isPlaceholder = restNodes.length === 0 && restTextNodes.length === 0 && firstNode.type === "PARAGRAPH" && firstNode.id === DEFAULT_CONTENT_NODE_ID && (textNode == null ? void 0 : textNode.type) === "TEXT" && ((_b = textNode.textData) == null ? void 0 : _b.text) === DEFAULT_CONTENT_TEXT && !((_c = textNode.textData.decorations) == null ? void 0 : _c.length);
207
+ return !isPlaceholder;
208
+ };
209
+ const BUTTON_TAG = "button";
210
+ const BUTTON_PROPS = [
211
+ {
212
+ varKey: "fill",
213
+ themeField: "backgroundColor",
214
+ group: "normal",
215
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.color,
216
+ displayName: "Normal fill color",
217
+ defaultValue: "var(--wst-accent-1-color)"
218
+ },
219
+ {
220
+ varKey: "text",
221
+ themeField: "color",
222
+ group: "normal",
223
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.color,
224
+ displayName: "Normal text color",
225
+ defaultValue: "var(--wst-base-1-color)"
226
+ },
227
+ // Our single radius/width props map to ricos's all-sides borderRadius/borderWidth,
228
+ // while the theme exposes per-side/per-corner vars — default to a representative
229
+ // corner/side of the primary button variant (values are uniform across sides).
230
+ {
231
+ varKey: "border-radius",
232
+ themeField: "borderRadius",
233
+ group: "normal",
234
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.borderRadius,
235
+ displayName: "Corners",
236
+ defaultValue: "var(--wst-button-primary-border-top-left-radius)"
237
+ },
238
+ {
239
+ varKey: "border-width",
240
+ themeField: "borderWidth",
241
+ group: "normal",
242
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.borderWidth,
243
+ displayName: "Border width",
244
+ defaultValue: "var(--wst-button-primary-border-top-width)"
245
+ },
246
+ {
247
+ varKey: "border-color",
248
+ themeField: "borderColor",
249
+ group: "normal",
250
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.color,
251
+ displayName: "Normal border color",
252
+ defaultValue: "var(--wst-accent-1-color)"
253
+ },
254
+ {
255
+ varKey: "fill-hover",
256
+ themeField: "backgroundColorHover",
257
+ group: "hover",
258
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.color,
259
+ displayName: "Hover fill color",
260
+ defaultValue: "var(--wst-accent-2-color)"
261
+ },
262
+ {
263
+ varKey: "text-hover",
264
+ themeField: "colorHover",
265
+ group: "hover",
266
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.color,
267
+ displayName: "Hover text color",
268
+ defaultValue: "var(--wst-base-1-color)"
269
+ },
270
+ {
271
+ varKey: "border-color-hover",
272
+ themeField: "borderColorHover",
273
+ group: "hover",
274
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.color,
275
+ displayName: "Hover border color",
276
+ defaultValue: "var(--wst-accent-2-color)"
277
+ }
278
+ ];
279
+ const BUTTON_SIZE_DATA_KEY = "buttonSize";
280
+ const BUTTON_SIZES = [
281
+ { value: "small", displayName: "Small" },
282
+ { value: "medium", displayName: "Medium" },
283
+ { value: "large", displayName: "Large" }
284
+ ];
285
+ ({
286
+ [BUTTON_SIZE_DATA_KEY]: {
287
+ dataType: DATA.DATA_TYPE.textEnum,
288
+ textEnum: {
289
+ options: BUTTON_SIZES.map(({ value, displayName }) => ({ value, displayName }))
290
+ }
291
+ }
292
+ });
293
+ const buttonCssCustomProperties = () => Object.fromEntries(
294
+ BUTTON_PROPS.map(({ varKey, type, displayName, defaultValue }) => [
295
+ customPropKey(BUTTON_TAG, varKey),
296
+ { cssPropertyType: type, displayName, ...defaultValue ? { defaultValue } : {} }
297
+ ])
298
+ );
299
+ const buttonColorGroup = (group) => ({
300
+ items: BUTTON_PROPS.filter(
301
+ (prop) => prop.group === group && prop.type === CSS_PROPERTIES.CSS_PROPERTY_TYPE.color
302
+ ).map((prop) => customPropKey(BUTTON_TAG, prop.varKey))
303
+ });
304
+ const buttonDisplayGroups = () => ({
305
+ buttonNormal: {
306
+ displayName: "Buttons (Normal)",
307
+ groupType: DISPLAY_GROUPS.GROUP_TYPE.cssCustomProperties,
308
+ cssCustomProperties: buttonColorGroup("normal")
309
+ },
310
+ buttonHover: {
311
+ displayName: "Buttons (Hover)",
312
+ groupType: DISPLAY_GROUPS.GROUP_TYPE.cssCustomProperties,
313
+ cssCustomProperties: buttonColorGroup("hover")
314
+ }
315
+ });
316
+ ({
317
+ elementType: ELEMENTS.ELEMENT_TYPE.inlineElement,
318
+ inlineElement: {
319
+ cssCustomProperties: buttonCssCustomProperties(),
320
+ displayGroups: buttonDisplayGroups()
321
+ }
322
+ });
323
+ const viewerButtonStyle = Object.fromEntries(
324
+ BUTTON_PROPS.map(({ varKey, themeField, defaultValue }) => [
325
+ themeField,
326
+ defaultValue ? `var(--${customPropKey(BUTTON_TAG, varKey)}, ${defaultValue})` : `var(--${customPropKey(BUTTON_TAG, varKey)})`
327
+ ])
328
+ );
329
+ const IMAGE_TAG = "image";
330
+ const IMAGE_PROPS = [
331
+ {
332
+ varKey: "border-radius",
333
+ themeField: "borderRadius",
334
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.borderRadius,
335
+ displayName: "Corners",
336
+ defaultValue: "0px"
337
+ },
338
+ {
339
+ varKey: "border-width",
340
+ themeField: "borderWidth",
341
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.borderWidth,
342
+ displayName: "Border width",
343
+ defaultValue: "0px"
344
+ },
345
+ {
346
+ varKey: "border-color",
347
+ themeField: "borderColor",
348
+ type: CSS_PROPERTIES.CSS_PROPERTY_TYPE.color,
349
+ displayName: "Border color",
350
+ defaultValue: "var(--wst-base-2-color)"
351
+ }
352
+ ];
353
+ const imageCssCustomProperties = () => Object.fromEntries(
354
+ IMAGE_PROPS.map(({ varKey, type, displayName, defaultValue }) => [
355
+ customPropKey(IMAGE_TAG, varKey),
356
+ { cssPropertyType: type, displayName, ...defaultValue ? { defaultValue } : {} }
357
+ ])
358
+ );
359
+ ({
360
+ elementType: ELEMENTS.ELEMENT_TYPE.inlineElement,
361
+ inlineElement: {
362
+ cssCustomProperties: imageCssCustomProperties()
363
+ }
364
+ });
365
+ const viewerImageStyle = Object.fromEntries(
366
+ IMAGE_PROPS.map(({ varKey, themeField, defaultValue }) => [
367
+ themeField,
368
+ defaultValue ? `var(--${customPropKey(IMAGE_TAG, varKey)}, ${defaultValue})` : `var(--${customPropKey(IMAGE_TAG, varKey)})`
369
+ ])
370
+ );
371
+ const PALETTE_SECTIONS = [
372
+ { key: "base", displayName: "Base" },
373
+ { key: "shade", displayName: "Shades" },
374
+ { key: "accent", displayName: "Accent" }
375
+ ];
376
+ const PALETTE_PROPS = [
377
+ {
378
+ paletteKey: "bgColor",
379
+ section: "base",
380
+ platformVar: "--wst-base-1-color",
381
+ displayName: "Background"
382
+ },
383
+ {
384
+ paletteKey: "textColor",
385
+ section: "base",
386
+ platformVar: "--wst-base-2-color",
387
+ displayName: "Text"
388
+ },
389
+ {
390
+ paletteKey: "shade1",
391
+ section: "shade",
392
+ platformVar: "--wst-shade-1-color",
393
+ displayName: "Shade 1"
394
+ },
395
+ {
396
+ paletteKey: "shade2",
397
+ section: "shade",
398
+ platformVar: "--wst-shade-2-color",
399
+ displayName: "Shade 2"
400
+ },
401
+ {
402
+ paletteKey: "shade3",
403
+ section: "shade",
404
+ platformVar: "--wst-shade-3-color",
405
+ displayName: "Shade 3"
406
+ },
407
+ {
408
+ paletteKey: "accent1",
409
+ section: "accent",
410
+ platformVar: "--wst-accent-1-color",
411
+ displayName: "Accent 1"
412
+ },
413
+ {
414
+ paletteKey: "accent2",
415
+ section: "accent",
416
+ platformVar: "--wst-accent-2-color",
417
+ displayName: "Accent 2"
418
+ },
419
+ {
420
+ paletteKey: "accent3",
421
+ section: "accent",
422
+ platformVar: "--wst-accent-3-color",
423
+ displayName: "Accent 3"
424
+ },
425
+ {
426
+ paletteKey: "accent4",
427
+ section: "accent",
428
+ platformVar: "--wst-accent-4-color",
429
+ displayName: "Accent 4"
430
+ }
431
+ ];
432
+ const PALETTE_TAG = "palette";
433
+ const paletteVarKey = (paletteKey) => {
434
+ const index = PALETTE_PROPS.findIndex((prop) => prop.paletteKey === paletteKey);
435
+ return customPropKey(PALETTE_TAG, `${String(index).padStart(2, "0")}-${paletteKey}`);
436
+ };
437
+ Object.fromEntries(
438
+ PALETTE_PROPS.map(({ paletteKey, platformVar, displayName }) => [
439
+ paletteVarKey(paletteKey),
440
+ {
441
+ cssPropertyType: CSS_PROPERTIES.CSS_PROPERTY_TYPE.color,
442
+ displayName,
443
+ defaultValue: `var(${platformVar})`
444
+ }
445
+ ])
446
+ );
447
+ Object.fromEntries(
448
+ PALETTE_SECTIONS.map(({ key, displayName }) => [
449
+ key,
450
+ {
451
+ displayName,
452
+ groupType: DISPLAY_GROUPS.GROUP_TYPE.cssDataType,
453
+ cssDataType: {
454
+ items: PALETTE_PROPS.filter((prop) => prop.section === key).map(
455
+ (prop) => paletteVarKey(prop.paletteKey)
456
+ )
457
+ }
458
+ }
459
+ ])
460
+ );
461
+ const viewerColorPalette = {
462
+ format: "color",
463
+ ...Object.fromEntries(
464
+ PALETTE_PROPS.map(({ paletteKey, platformVar }) => [
465
+ paletteKey,
466
+ `var(--${paletteVarKey(paletteKey)}, var(${platformVar}))`
467
+ ])
468
+ )
469
+ };
470
+ const TRIM_DEFAULTS = {
471
+ trimEnabled: false,
472
+ trimMode: "paragraph",
473
+ trimLengthParagraph: 3,
474
+ trimLengthWord: 10,
475
+ trimExclude: "plugins",
476
+ trimEllipsisEnabled: true,
477
+ trimEllipsisExpandText: "Show More",
478
+ trimEllipsisCollapseText: "Show Less"
479
+ };
480
+ ({
481
+ trimEnabled: {
482
+ dataType: DATA.DATA_TYPE.booleanValue
483
+ },
484
+ trimMode: {
485
+ dataType: DATA.DATA_TYPE.textEnum
486
+ },
487
+ trimLengthParagraph: {
488
+ dataType: DATA.DATA_TYPE.number
489
+ },
490
+ trimLengthWord: {
491
+ dataType: DATA.DATA_TYPE.number
492
+ },
493
+ trimExclude: {
494
+ dataType: DATA.DATA_TYPE.textEnum
495
+ },
496
+ trimEllipsisEnabled: {
497
+ dataType: DATA.DATA_TYPE.booleanValue
498
+ },
499
+ trimEllipsisExpandText: {
500
+ dataType: DATA.DATA_TYPE.text
501
+ },
502
+ trimEllipsisCollapseText: {
503
+ dataType: DATA.DATA_TYPE.text
504
+ }
505
+ });
506
+ const root = "root__bW8lC";
507
+ const s = {
508
+ root
509
+ };
510
+ const ViewerContent = ({
511
+ id,
512
+ content,
513
+ className,
514
+ resolveFileUrl,
515
+ buttonSize = "medium",
516
+ trimEnabled = TRIM_DEFAULTS.trimEnabled,
517
+ trimMode = TRIM_DEFAULTS.trimMode,
518
+ trimLengthParagraph = TRIM_DEFAULTS.trimLengthParagraph,
519
+ trimLengthWord = TRIM_DEFAULTS.trimLengthWord,
520
+ trimExclude = TRIM_DEFAULTS.trimExclude,
521
+ trimEllipsisEnabled = TRIM_DEFAULTS.trimEllipsisEnabled,
522
+ trimEllipsisExpandText = TRIM_DEFAULTS.trimEllipsisExpandText,
523
+ trimEllipsisCollapseText = TRIM_DEFAULTS.trimEllipsisCollapseText
524
+ }) => {
525
+ const { deviceType } = useService(DeviceInfoDefinition);
526
+ const { editorName } = useService(EditorContextDefinition);
527
+ const { language } = useService(LocaleDefinition);
528
+ const { siteId: metaSiteId } = useService(SiteInfoDefinition);
529
+ const { siteUrl } = useService(UrlDefinition);
530
+ return /* @__PURE__ */ React.createElement("div", { className: `${s.root} ${className}`, id }, /* @__PURE__ */ React.createElement(
531
+ ContentTrimmer,
532
+ {
533
+ content,
534
+ trimEnabled,
535
+ trimMode,
536
+ trimLengthParagraph,
537
+ trimLengthWord,
538
+ trimExclude,
539
+ trimEllipsisEnabled,
540
+ trimEllipsisExpandText,
541
+ trimEllipsisCollapseText
542
+ },
543
+ (trimmedContent) => /* @__PURE__ */ React.createElement(
544
+ RicosViewer,
545
+ {
546
+ firstFoldNodeCount: 8,
547
+ responsiveBehavior: "viewport",
548
+ isMobile: deviceType === "Smartphone",
549
+ locale: language,
550
+ biSettings: {
551
+ consumer: editorName,
552
+ platform: "Livesite",
553
+ postId: "",
554
+ containerId: ""
555
+ },
556
+ msid: metaSiteId,
557
+ baseUrl: siteUrl,
558
+ content: trimmedContent,
559
+ theme: {
560
+ colorPalette: viewerColorPalette,
561
+ customStyles: {
562
+ ...viewerCustomStyles,
563
+ button: { ...viewerButtonStyle, buttonSize },
564
+ image: viewerImageStyle
565
+ }
566
+ },
567
+ plugins: [
568
+ pluginCollapsibleListLazy(),
569
+ pluginDividerLazy(),
570
+ pluginEmojiViewer(),
571
+ pluginGiphyLazy(),
572
+ pluginHashtagViewer(),
573
+ pluginImageLazy(),
574
+ pluginGalleryLazy(),
575
+ pluginVideoLazy(),
576
+ pluginAudioLazy(),
577
+ pluginFileUploadLazy({ resolveFileUrl }),
578
+ pluginLinkViewer(),
579
+ pluginMentionsViewer(),
580
+ pluginTableLazy(),
581
+ pluginTextColorViewer(),
582
+ pluginTextHighlightViewer(),
583
+ pluginHtmlLazy(),
584
+ pluginLinkPreviewLazy(),
585
+ pluginVerticalEmbedLazy(),
586
+ pluginSpoilerViewer(),
587
+ pluginPollLazy(),
588
+ pluginLinkButtonLazy(),
589
+ pluginTocLazy()
590
+ ]
591
+ }
592
+ )
593
+ ));
594
+ };
595
+ const Viewer = ({ content, ...props }) => isContentProvided(content) ? /* @__PURE__ */ React.createElement(ViewerContent, { ...props, content }) : (
596
+ // Keep the root so the platform still finds the component node.
597
+ /* @__PURE__ */ React.createElement("div", { className: `${s.root} ${props.className}`, id: props.id })
598
+ );
599
+ export {
600
+ ViewerContent,
601
+ Viewer as default
602
+ };
@@ -0,0 +1,10 @@
1
+ import { RicosDocument } from '@wix/ricos';
2
+ import { CSSProperties, FC, ReactNode } from 'react';
3
+ import { TrimSettings } from './manifest/trim.js';
4
+ type ContentTrimmerProps = TrimSettings & {
5
+ content: RicosDocument;
6
+ ellipsisStyle?: CSSProperties;
7
+ children: (content: RicosDocument) => ReactNode;
8
+ };
9
+ export declare const ContentTrimmer: FC<ContentTrimmerProps>;
10
+ export {};
@@ -0,0 +1,9 @@
1
+ import { RicosDocument } from '@wix/ricos';
2
+ /** Default content shown in the editor before the consumer binds their own `content`. */
3
+ export declare const defaultContent: RicosDocument;
4
+ /**
5
+ * False when no content is bound. The manifest uses `defaultContent` as the data item's
6
+ * `defaultValue`, so the platform can pass it back as `content` — match its marker id and
7
+ * shape rather than its reference.
8
+ */
9
+ export declare const isContentProvided: (content?: RicosDocument) => content is RicosDocument;
@@ -0,0 +1,24 @@
1
+ import { EditorElement, ElementItem } from '@wix/react-component-schema';
2
+ import { RicosCustomStyles } from '@wix/ricos';
3
+ /** ricos's per-button style overrides — `theme.customStyles.button`. */
4
+ type ButtonStyle = NonNullable<RicosCustomStyles['button']>;
5
+ /** Allowed `buttonSize` values. Exposed as a `textEnum` data item (a prop), not
6
+ * a CSS var: `buttonSize` is a ricos enum resolved at render, so it must reach
7
+ * the component as a prop (SSR + client) rather than a paint-time CSS variable. */
8
+ export declare const BUTTON_SIZE_DATA_KEY = "buttonSize";
9
+ /** The `buttonSize` data item — becomes the component's `buttonSize` prop. */
10
+ export declare const buttonSizeData: NonNullable<EditorElement['data']>;
11
+ /**
12
+ * Dedicated (non-selectable) "Button" element so the global button controls get
13
+ * their own labeled panel section instead of sitting on the root Viewer element.
14
+ * Shares the content selector so its vars cascade to the rendered buttons, which
15
+ * read them via `theme.customStyles.button`.
16
+ */
17
+ export declare const buttonElement: ElementItem;
18
+ /**
19
+ * `theme.customStyles.button` for `RicosViewer`. Each color/length field
20
+ * references its editor var with the platform default as fallback. `buttonSize`
21
+ * is omitted — it is a data prop passed to the component in viewer.tsx.
22
+ */
23
+ export declare const viewerButtonStyle: ButtonStyle;
24
+ export {};
@@ -0,0 +1,10 @@
1
+ import { ElementItem } from '@wix/react-component-schema';
2
+ import { RicosCustomStyles } from '@wix/ricos';
3
+ /** ricos per-image style overrides — `theme.customStyles.image`. */
4
+ type ImageStyle = NonNullable<RicosCustomStyles['image']>;
5
+ /** Dedicated (non-selectable) "Image" element for the global image-frame controls. */
6
+ export declare const imageElement: ElementItem;
7
+ /** `theme.customStyles.image` for `RicosViewer` — each field references its editor
8
+ * var with the default as fallback. */
9
+ export declare const viewerImageStyle: ImageStyle;
10
+ export {};
@@ -0,0 +1,16 @@
1
+ import { CssCustomPropertyItem, DisplayGroupItem } from '@wix/react-component-schema';
2
+ import { RicosPalette } from '@wix/ricos';
3
+ /** Component-wide color controls, one per palette slot. Each defaults to its
4
+ * platform palette color (`--wst-*-color`) so the editor control opens on the
5
+ * theme color rather than empty. */
6
+ export declare const paletteCssCustomProperties: Record<string, CssCustomPropertyItem>;
7
+ /** One display group per palette section (Base / Shades / Accent), so the panel
8
+ * shows the colors under labeled sub-sections. Within each, item order follows
9
+ * `PALETTE_PROPS`; section order follows `PALETTE_SECTIONS`. */
10
+ export declare const paletteDisplayGroups: Record<string, DisplayGroupItem>;
11
+ /**
12
+ * `theme.colorPalette` for `RicosViewer`. Each slot references the editor-set
13
+ * `--editor-ricos-palette-<key>` custom property, falling back to the platform
14
+ * `--wst-*-color` default so untouched colors match the platform theme.
15
+ */
16
+ export declare const viewerColorPalette: RicosPalette;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared primitives for the viewer manifest's style/settings modules.
3
+ */
4
+ /** `editor-ricos-<tag>-<suffix>` — the custom-property key the editor writes to;
5
+ * the viewer reads `--<key>` back via `theme.customStyles` / `theme.colorPalette`. */
6
+ export declare const customPropKey: (tag: string, cssVar: string) => string;
7
+ /**
8
+ * The ricos content wrapper. Inner elements scope their custom properties to it
9
+ * so they cascade to the rendered content.
10
+ */
11
+ export declare const CONTENT_VIEWER_SELECTOR = "[data-id=\"content-viewer\"]";
@@ -0,0 +1,21 @@
1
+ import { DisplayGroupItem, ElementItem } from '@wix/react-component-schema';
2
+ import { RicosCustomStyles } from '@wix/ricos';
3
+ import { CSSProperties } from 'react';
4
+ /** One inner element per text level (`h1`…`h6`, `p`), keyed by tag. */
5
+ export declare const textElements: Record<string, ElementItem>;
6
+ /** `elements` display group pinning the text levels' panel order (h1→…→p). */
7
+ export declare const textLevelsDisplayGroup: DisplayGroupItem;
8
+ /**
9
+ * `theme.customStyles` for `RicosViewer` — the runtime counterpart of the manifest's
10
+ * `cssCustomProperties`. The editor writes `--editor-ricos-<tag>-<prop>` custom properties;
11
+ * these references pull them into ricos's per-tag styling so panel edits restyle the content.
12
+ */
13
+ export declare const viewerCustomStyles: RicosCustomStyles;
14
+ /**
15
+ * Style for the trim expand/collapse toggle, an exact port of the
16
+ * editor-elements RichContentViewer ellipsis style: paragraph typography
17
+ * (`getTextThemeForTag('p')`) + the site link/action color, underlined.
18
+ * `--wst-links-and-actions-color` is the canonical equivalent of the
19
+ * reference's `actionColor` (`--linkColor` / `--color_18`).
20
+ */
21
+ export declare const viewerEllipsisStyle: CSSProperties;
@@ -0,0 +1,21 @@
1
+ import { EditorElement } from '@wix/react-component-schema';
2
+ /**
3
+ * Content-trimming settings (replicating the editor-elements RichContentViewer).
4
+ * All are data items → component props (render-time, SSR-safe), consumed by the
5
+ * `ContentTrimmer` in viewer.tsx. Shared with the component as prop defaults.
6
+ */
7
+ export type TrimMode = 'paragraph' | 'word';
8
+ export type TrimSettings = {
9
+ trimEnabled: boolean;
10
+ trimMode: TrimMode;
11
+ trimLengthParagraph: number;
12
+ trimLengthWord: number;
13
+ /** `'plugins'` drops plugin nodes (image/video/…) when trimming; `'none'` keeps them. */
14
+ trimExclude: 'none' | 'plugins';
15
+ trimEllipsisEnabled: boolean;
16
+ trimEllipsisExpandText: string;
17
+ trimEllipsisCollapseText: string;
18
+ };
19
+ export declare const TRIM_DEFAULTS: TrimSettings;
20
+ /** The content-trimming data items — become the component's trim props. */
21
+ export declare const trimData: NonNullable<EditorElement['data']>;
@@ -0,0 +1,23 @@
1
+ import { RicosDocument } from '@wix/ricos';
2
+ import { FC } from 'react';
3
+ import { TrimSettings } from './manifest/trim.js';
4
+ type ButtonSize = 'small' | 'medium' | 'large';
5
+ export type ViewerProps = {
6
+ id: string;
7
+ className: string;
8
+ content?: RicosDocument;
9
+ resolveFileUrl?: (file: FileUploadPluginFile) => Promise<string>;
10
+ buttonSize?: ButtonSize;
11
+ } & Partial<TrimSettings>;
12
+ type FileUploadPluginFile = {
13
+ id?: string;
14
+ path?: string;
15
+ mimeType?: string;
16
+ };
17
+ /** Renders the given document; `Viewer` and `ViewerPreview` decide what to pass. */
18
+ export declare const ViewerContent: FC<ViewerProps & {
19
+ content: RicosDocument;
20
+ }>;
21
+ /** Site entry: renders nothing until content is bound. The editor placeholder lives in `viewer.preview.tsx`. */
22
+ declare const Viewer: FC<ViewerProps>;
23
+ export default Viewer;
@@ -0,0 +1,5 @@
1
+ import { FC } from 'react';
2
+ import { ViewerProps } from './viewer.js';
3
+ /** Editor entry: hints that `content` isn't bound yet; preview mode renders like the site. */
4
+ declare const ViewerPreview: FC<ViewerProps>;
5
+ export default ViewerPreview;
package/package.json CHANGED
@@ -1,6 +1,111 @@
1
1
  {
2
2
  "name": "@wix/ricos-editor-elements",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "11.21.0",
4
+ "files": [
5
+ "dist/lib/**"
6
+ ],
7
+ "type": "module",
8
+ "exports": {
9
+ "./Viewer": {
10
+ "types": "./dist/lib/viewer.d.ts",
11
+ "default": "./dist/lib/Viewer.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "publishConfig": {
16
+ "registry": "https://registry.npmjs.org/",
17
+ "access": "public"
18
+ },
19
+ "scripts": {
20
+ "test": "vitest",
21
+ "build": "yarn generate-translation-keys && yarn typecheck && wix build && yarn build:lib",
22
+ "build:lib": "vite build --config vite.lib.config.ts",
23
+ "dev": "wix dev",
24
+ "preview": "wix preview",
25
+ "logs": "wix logs",
26
+ "lint": "oxlint",
27
+ "lint:fix": "oxlint --fix",
28
+ "format": "oxfmt",
29
+ "format:check": "oxfmt --check",
30
+ "typecheck": "tsc --noEmit",
31
+ "test:e2e": "yarn dlx @wix/sled-playwright test",
32
+ "env": "wix env pull",
33
+ "generate": "yarn create @wix/fed-app",
34
+ "storybook": "storybook dev -p 6006",
35
+ "storybook:build": "storybook build",
36
+ "generate-translation-keys": "babel-cli"
37
+ },
38
+ "dependencies": {
39
+ "@wix/astro": "^2.75.3",
40
+ "@wix/dashboard": "^1.3.48",
41
+ "@wix/design-system": "^1.338.0",
42
+ "@wix/editor": "^1.956.0",
43
+ "@wix/essentials": "^1.0.15",
44
+ "@wix/fed-cli-i18next": "^1.7.0",
45
+ "@wix/react-component-schema": "^1.10.0",
46
+ "@wix/ricos": "11.21.0",
47
+ "@wix/services-manager": "^1.0.7",
48
+ "@wix/services-manager-react": "^1.0.8",
49
+ "@wix/site-service-device-info": "^1.0.8",
50
+ "@wix/site-service-editor-context": "^1.0.7",
51
+ "@wix/site-service-locale": "^1.0.10",
52
+ "@wix/site-service-site-info": "^1.0.8",
53
+ "@wix/site-service-url": "^1.0.9",
54
+ "@wix/wix-ui-icons-common": "^3.190.8",
55
+ "astro": "^5.18.1",
56
+ "lodash": "^4.17.15"
57
+ },
58
+ "devDependencies": {
59
+ "@astrojs/cloudflare": "^12.6.13",
60
+ "@astrojs/react": "^4.4.2",
61
+ "@playwright/test": "~1.51.0",
62
+ "@storybook/react-vite": "^10.4.1",
63
+ "@testing-library/dom": "^10.4.1",
64
+ "@testing-library/react": "^16.0.1",
65
+ "@types/lodash": "^4.14.149",
66
+ "@types/react": "^18.2.56",
67
+ "@types/react-dom": "^18.2.19",
68
+ "@wix/babel-cli": "^1.20.0",
69
+ "@wix/cli": "^1.1.263",
70
+ "@wix/fed-cli-oxlint": "^1.0.6",
71
+ "@wix/fed-cli-sled": "^1.0.39",
72
+ "@wix/fed-cli-vitest": "^1.0.17",
73
+ "@wix/sdk-types": "^1.17.12",
74
+ "@wix/sled-playwright": "^1.398.0",
75
+ "oxfmt": "^0.19.0",
76
+ "oxlint": "^1.34.0",
77
+ "react": "^18.2.0",
78
+ "react-dom": "^18.2.0",
79
+ "regenerator-runtime": "^0.14.0",
80
+ "storybook": "^10.4.1",
81
+ "typescript": "5.8.3",
82
+ "vite": "^6.4.3",
83
+ "vite-plugin-dts": "^4.5.0",
84
+ "vite-plugin-lib-inject-css": "^2.2.0",
85
+ "vitest": "^4.0.0"
86
+ },
87
+ "peerDependencies": {
88
+ "react": "^18.2.0",
89
+ "react-dom": "^18.2.0"
90
+ },
91
+ "wix": {
92
+ "framework": {
93
+ "type": "WIX_CLI"
94
+ },
95
+ "artifact": {
96
+ "groupId": "com.wixpress",
97
+ "artifactId": "ricos-editor-elements",
98
+ "targets": {
99
+ "devcenter": true,
100
+ "static": true
101
+ }
102
+ },
103
+ "validations": {
104
+ "sourceOnly": [
105
+ "lint",
106
+ "format:check"
107
+ ]
108
+ }
109
+ },
110
+ "falconPackageHash": "cf3505f5c008bd6bce0924f9643683c33221498f8463d1267bc558c2"
6
111
  }