@blinkk/root-cms 3.0.1-alpha.1 → 3.0.1-beta.2

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/dist/richtext.js CHANGED
@@ -1,70 +1,99 @@
1
1
  import "./chunk-MLKGABMK.js";
2
2
 
3
3
  // core/richtext.tsx
4
- import { useTranslations } from "@blinkk/root";
5
- import { createContext } from "preact";
4
+ import { StringParamsProvider, useTranslations } from "@blinkk/root";
5
+ import { Component, createContext } from "preact";
6
6
  import { useContext } from "preact/hooks";
7
- import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
7
+ import { renderToString } from "preact-render-to-string";
8
+ import { jsx, jsxs } from "preact/jsx-runtime";
8
9
  var RichTextContext = createContext({});
9
10
  function useRichTextContext() {
10
11
  return useContext(RichTextContext);
11
12
  }
13
+ var RichTextComponentMapContext = createContext({});
14
+ function useRichTextContextComponentMap() {
15
+ return useContext(RichTextComponentMapContext);
16
+ }
17
+ function useRichTextTranslations() {
18
+ const ctx = useRichTextContext();
19
+ if (ctx.t) {
20
+ return ctx.t;
21
+ }
22
+ return useTranslations();
23
+ }
12
24
  function RichText(props) {
25
+ const blocks = props.data?.blocks || [];
26
+ if (blocks.length === 0) {
27
+ return null;
28
+ }
13
29
  const richTextContext = useRichTextContext();
14
- const components = {
15
- delimiter: RichText.DelimiterBlock,
30
+ const componentMap = {
16
31
  heading: RichText.HeadingBlock,
17
32
  html: RichText.HtmlBlock,
18
33
  image: RichText.ImageBlock,
19
34
  orderedList: RichText.ListBlock,
20
35
  paragraph: RichText.ParagraphBlock,
21
- quote: RichText.QuoteBlock,
22
36
  table: RichText.TableBlock,
23
37
  unorderedList: RichText.ListBlock,
24
38
  ...richTextContext.components,
25
39
  ...props.components
26
40
  };
27
- const blocks = (props.data?.blocks || []).filter((block) => {
28
- const blockType = block?.type;
29
- if (!blockType) {
30
- return false;
31
- }
32
- if (!(blockType in components)) {
33
- console.warn(`ignoring unknown richtext type: "${blockType}"`);
34
- return false;
35
- }
36
- return true;
37
- });
38
- return /* @__PURE__ */ jsx(Fragment, { children: blocks.map((block) => {
39
- const Block = components[block.type];
40
- return /* @__PURE__ */ jsx(Block, { ...block });
41
- }) });
41
+ return /* @__PURE__ */ jsx(RichTextComponentMapContext.Provider, { value: componentMap, children: blocks.map((block) => {
42
+ return /* @__PURE__ */ jsx(RichText.Block, { ...block });
43
+ }).filter((value) => !!value) });
42
44
  }
43
- RichText.ParagraphBlock = (props) => {
44
- if (!props.data?.text) {
45
+ RichText.Block = (props) => {
46
+ const block = props;
47
+ const blockType = block?.type;
48
+ if (!blockType) {
45
49
  return null;
46
50
  }
47
- const t = useTranslations();
48
- return /* @__PURE__ */ jsx("p", { dangerouslySetInnerHTML: { __html: t(props.data.text) } });
51
+ const componentMap = useRichTextContextComponentMap();
52
+ const BlockComponent = componentMap[blockType];
53
+ if (!BlockComponent) {
54
+ console.warn(`[RichText] ignoring unknown richtext type: "${blockType}"`);
55
+ return null;
56
+ }
57
+ return /* @__PURE__ */ jsx(
58
+ InlineComponentRenderer,
59
+ {
60
+ block,
61
+ componentMap,
62
+ BlockComponent
63
+ }
64
+ );
49
65
  };
50
- RichText.DelimiterBlock = () => {
51
- return /* @__PURE__ */ jsx("hr", {});
66
+ var InlineComponentRenderer = class extends Component {
67
+ render() {
68
+ const { block, componentMap, BlockComponent } = this.props;
69
+ const stringParams = collectInlineComponentParams(
70
+ block,
71
+ componentMap,
72
+ this.context
73
+ );
74
+ if (stringParams) {
75
+ return /* @__PURE__ */ jsx(StringParamsProvider, { value: stringParams, children: /* @__PURE__ */ jsx(BlockComponent, { ...block }) });
76
+ }
77
+ return /* @__PURE__ */ jsx(BlockComponent, { ...block });
78
+ }
52
79
  };
53
- RichText.HeadingBlock = (props) => {
80
+ RichText.ParagraphBlock = (props) => {
54
81
  if (!props.data?.text) {
55
82
  return null;
56
83
  }
57
- const t = useTranslations();
58
- const level = props.data.level || 2;
59
- const Component = `h${level}`;
60
- return /* @__PURE__ */ jsx(Component, { dangerouslySetInnerHTML: { __html: t(props.data.text) } });
84
+ const t = useRichTextTranslations();
85
+ const html = t(props.data.text);
86
+ return /* @__PURE__ */ jsx("p", { dangerouslySetInnerHTML: { __html: html } });
61
87
  };
62
- RichText.QuoteBlock = (props) => {
88
+ RichText.HeadingBlock = (props) => {
63
89
  if (!props.data?.text) {
64
90
  return null;
65
91
  }
66
- const t = useTranslations();
67
- return /* @__PURE__ */ jsx("blockquote", { dangerouslySetInnerHTML: { __html: t(props.data.text) } });
92
+ const t = useRichTextTranslations();
93
+ const level = props.data.level || 2;
94
+ const Component2 = `h${level}`;
95
+ const html = t(props.data.text);
96
+ return /* @__PURE__ */ jsx(Component2, { dangerouslySetInnerHTML: { __html: html } });
68
97
  };
69
98
  RichText.ListBlock = (props) => {
70
99
  if (!props.data?.items?.length) {
@@ -74,20 +103,20 @@ RichText.ListBlock = (props) => {
74
103
  if (!style) {
75
104
  style = props.type === "orderedList" ? "ordered" : "unordered";
76
105
  }
77
- const Component = style === "ordered" ? "ol" : "ul";
106
+ const Component2 = style === "ordered" ? "ol" : "ul";
78
107
  const items = props.data.items;
79
- return /* @__PURE__ */ jsx(Component, { children: items.map((item) => {
108
+ return /* @__PURE__ */ jsx(Component2, { children: items.map((item) => {
80
109
  if (item.content || item.items?.length) {
81
110
  return /* @__PURE__ */ jsxs("li", { children: [
82
111
  item.content && /* @__PURE__ */ jsx(
83
- RichText.ParagraphBlock,
112
+ RichText.Block,
84
113
  {
85
114
  type: "paragraph",
86
- data: { text: item.content }
115
+ data: { text: item.content, components: item.components }
87
116
  }
88
117
  ),
89
118
  item.items && item.items.length > 0 && /* @__PURE__ */ jsx(
90
- RichText.ListBlock,
119
+ RichText.Block,
91
120
  {
92
121
  type: props.type,
93
122
  data: { style, items: item.items }
@@ -109,7 +138,8 @@ RichText.ImageBlock = (props) => {
109
138
  return /* @__PURE__ */ jsx("img", { src: imageUrl, width, height, alt });
110
139
  };
111
140
  RichText.HtmlBlock = (props) => {
112
- const html = props.data?.html || "";
141
+ const t = useRichTextTranslations();
142
+ const html = t(props.data?.html || "");
113
143
  if (!html) {
114
144
  return null;
115
145
  }
@@ -122,8 +152,7 @@ RichText.TableBlock = (props) => {
122
152
  return null;
123
153
  }
124
154
  return /* @__PURE__ */ jsx("table", { children: /* @__PURE__ */ jsx("tbody", { children: rows.map((row, rowIndex) => /* @__PURE__ */ jsx("tr", { children: row.cells.map((cell, cellIndex) => {
125
- const isHeader = cell.type === "header";
126
- const Cell = isHeader ? "th" : "td";
155
+ const Cell = cell.type === "header" ? "th" : "td";
127
156
  return /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsx(
128
157
  RichText,
129
158
  {
@@ -146,8 +175,34 @@ function toNumber(input) {
146
175
  }
147
176
  return parsedNumber;
148
177
  }
178
+ function testContent(data) {
179
+ return data?.blocks?.length > 0;
180
+ }
181
+ function collectInlineComponentParams(block, componentMap, renderContext) {
182
+ const components = block?.data?.components || {};
183
+ if (Object.keys(components).length === 0) {
184
+ return null;
185
+ }
186
+ const params = {};
187
+ for (const [componentId, component] of Object.entries(components)) {
188
+ const Component2 = componentMap[component.type];
189
+ if (Component2) {
190
+ const key = `${component.type}:${componentId}`;
191
+ params[key] = renderToString(
192
+ /* @__PURE__ */ jsx(Component2, { ...component.data }),
193
+ renderContext
194
+ );
195
+ } else {
196
+ console.warn(
197
+ `[RichText] could not find inline component for type: "${component.type}"`
198
+ );
199
+ }
200
+ }
201
+ return params;
202
+ }
149
203
  export {
150
204
  RichText,
151
205
  RichTextContext,
206
+ testContent,
152
207
  useRichTextContext
153
208
  };
@@ -155,6 +155,11 @@ type ArrayField = CommonFieldProps & {
155
155
  * Label to use for the "add item" button. Defaults to `Add`.
156
156
  */
157
157
  buttonLabel?: string;
158
+ /**
159
+ * Whether array items should be open (expanded) by default. Defaults to
160
+ * `false`, meaning items start collapsed.
161
+ */
162
+ defaultOpen?: boolean;
158
163
  };
159
164
  declare function array(field: Omit<ArrayField, 'type'>): ArrayField;
160
165
  /**
@@ -1 +1 @@
1
- :root{--font-family-default: "Inter", sans-serif;--font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;--color-text-default: #333333;--color-border: #EFEFEF;--button-background-hover: #F5F5F5;--button-background-active: #E5E5E5}html{box-sizing:border-box;overflow-x:hidden;font-size:16px;line-height:1.5}*,*:before,*:after{box-sizing:inherit}html,body{font-family:var(--font-family-default);color:var(--color-text-default);height:100%;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;scroll-behavior:smooth}img,picture,figure,video,canvas,svg,iframe{display:block;max-width:100%;height:auto;margin:0}a{color:inherit}select{color-scheme:light}h1,h2,h3,h4,h5,p{margin:0}body.menu\:open{overflow:hidden}#root{margin:0 auto;min-height:100vh;position:relative}.bootstrap{font-size:48px;font-weight:900;width:100%;height:100vh;display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;padding:40px;gap:36px;position:relative}.bootstrap-error{font-size:14px;font-weight:400;line-height:20px;position:absolute;bottom:100px;left:0;right:0;text-align:center;animation:.5s forwards bootstrap-loading-error;animation-delay:1s;opacity:0;padding:0 24px}@keyframes bootstrap-loading-error{0%{opacity:0}to{opacity:1}}.signin{font-family:Google Sans,arial,sans-serif;text-align:center;padding:48px 20px;color:#3c4043}.signin__headline{margin-bottom:40px}.signin__headline__title{font-size:36px;line-height:1.3;font-weight:500;margin-bottom:20px}.signin__headline__body{font-size:18px;line-height:1.5;font-weight:500}.signin__button{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:inline-flex;align-items:center;text-align:center;gap:12px;background:#fff;border:1px solid #dadce0;border-radius:4px;cursor:pointer;font-family:inherit;padding:0 12px;height:40px;box-sizing:border-box;transition:all .218s ease}.signin__warning{max-width:520px;margin:0 auto 40px;padding:12px;border:1px solid #fbbc04;border-radius:8px;background:#fff9db;color:#5f370e;font-size:14px;line-height:1.5}.signin__button:hover{border-color:#d2e3fc;background-color:#4285f40a}.signin__button__icon{width:18px;height:18px;background-color:#fff}.signin__button__label{font-size:14px;line-height:1;letter-spacing:.25px;font-weight:500;color:#3c4043}.signin__error{color:red;font-weight:700;text-align:center;max-width:60ch;margin:20px auto 0}
1
+ :root{--font-family-default: "Inter", sans-serif;--font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;--color-text-default: #333333;--color-border: #EFEFEF;--button-background-hover: #F5F5F5;--button-background-active: #E5E5E5}html{box-sizing:border-box;overflow-x:hidden;font-size:16px;line-height:1.5}*,*:before,*:after{box-sizing:inherit}html,body{font-family:var(--font-family-default);color:var(--color-text-default);height:100%;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;scroll-behavior:smooth}img,picture,figure,video,canvas,svg,iframe{display:block;max-width:100%;height:auto;margin:0}a{color:inherit}select{color-scheme:light}h1,h2,h3,h4,h5,p{margin:0}body.menu\:open{overflow:hidden}#root{margin:0 auto;min-height:100vh;position:relative}.bootstrap{font-size:48px;font-weight:900;width:100%;height:100vh;display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;padding:40px;gap:36px;position:relative}.bootstrap-error{font-size:14px;font-weight:400;line-height:20px;position:absolute;bottom:100px;left:0;right:0;text-align:center;animation:.5s forwards bootstrap-loading-error;animation-delay:1s;opacity:0;padding:0 24px}.bootstrap--error{gap:16px}.bootstrap__error-title{font-size:48px;font-weight:900;line-height:1.1;margin:0}.bootstrap__error-message{color:#b00020;font-size:16px;font-weight:500;line-height:1.5;margin:0;max-width:640px}@keyframes bootstrap-loading-error{0%{opacity:0}to{opacity:1}}.signin{font-family:Google Sans,arial,sans-serif;text-align:center;padding:48px 20px;color:#3c4043}.signin__headline{margin-bottom:40px}.signin__headline__title{font-size:36px;line-height:1.3;font-weight:500;margin-bottom:20px}.signin__headline__body{font-size:18px;line-height:1.5;font-weight:500}.signin__button{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:inline-flex;align-items:center;text-align:center;gap:12px;background:#fff;border:1px solid #dadce0;border-radius:4px;cursor:pointer;font-family:inherit;padding:0 12px;height:40px;box-sizing:border-box;transition:all .218s ease}.signin__warning{max-width:520px;margin:0 auto 40px;padding:12px;border:1px solid #fbbc04;border-radius:8px;background:#fff9db;color:#5f370e;font-size:14px;line-height:1.5}.signin__button:hover{border-color:#d2e3fc;background-color:#4285f40a}.signin__button__icon{width:18px;height:18px;background-color:#fff}.signin__button__label{font-size:14px;line-height:1;letter-spacing:.25px;font-weight:500;color:#3c4043}.signin__button--busy{cursor:default;opacity:.85;border-color:#d2e3fc;background-color:#4285f40a}.signin__button--busy:hover{background-color:#4285f40a}.signin__spinner{width:18px;height:18px;color:#4285f4;animation:signin-spin .7s linear infinite}@keyframes signin-spin{to{transform:rotate(360deg)}}.signin__error{color:red;font-weight:700;text-align:center;max-width:60ch;margin:20px auto 0}