@makeswift/runtime 0.28.9 → 0.28.10-canary.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.
Files changed (41) hide show
  1. package/dist/cjs/api/graphql-api-client.js +1 -1
  2. package/dist/cjs/api/rest-api-client.js +1 -1
  3. package/dist/cjs/api-handler/handlers/manifest.js +1 -1
  4. package/dist/cjs/next/components/tests/controls/page-control-prop-rendering.js +24 -2
  5. package/dist/cjs/next/components/tests/controls/page-control-prop-rendering.js.map +1 -1
  6. package/dist/cjs/runtimes/react/controls/rich-text/EditableText/editable-text.js +3 -1
  7. package/dist/cjs/runtimes/react/controls/rich-text/EditableText/editable-text.js.map +1 -1
  8. package/dist/cjs/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.js +3 -0
  9. package/dist/cjs/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.js.map +1 -1
  10. package/dist/cjs/runtimes/react/controls/use-slate-reset.js +37 -0
  11. package/dist/cjs/runtimes/react/controls/use-slate-reset.js.map +1 -0
  12. package/dist/cjs/runtimes/react/hooks/use-element-data.js +35 -0
  13. package/dist/cjs/runtimes/react/hooks/use-element-data.js.map +1 -0
  14. package/dist/cjs/runtimes/react/hooks/use-element.js +40 -0
  15. package/dist/cjs/runtimes/react/hooks/use-element.js.map +1 -0
  16. package/dist/esm/api/graphql-api-client.js +1 -1
  17. package/dist/esm/api/rest-api-client.js +1 -1
  18. package/dist/esm/api-handler/handlers/manifest.js +1 -1
  19. package/dist/esm/next/components/tests/controls/page-control-prop-rendering.js +24 -2
  20. package/dist/esm/next/components/tests/controls/page-control-prop-rendering.js.map +1 -1
  21. package/dist/esm/runtimes/react/controls/rich-text/EditableText/editable-text.js +3 -1
  22. package/dist/esm/runtimes/react/controls/rich-text/EditableText/editable-text.js.map +1 -1
  23. package/dist/esm/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.js +3 -0
  24. package/dist/esm/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.js.map +1 -1
  25. package/dist/esm/runtimes/react/controls/use-slate-reset.js +13 -0
  26. package/dist/esm/runtimes/react/controls/use-slate-reset.js.map +1 -0
  27. package/dist/esm/runtimes/react/hooks/use-element-data.js +11 -0
  28. package/dist/esm/runtimes/react/hooks/use-element-data.js.map +1 -0
  29. package/dist/esm/runtimes/react/hooks/use-element.js +16 -0
  30. package/dist/esm/runtimes/react/hooks/use-element.js.map +1 -0
  31. package/dist/types/next/components/tests/controls/page-control-prop-rendering.d.ts +2 -1
  32. package/dist/types/next/components/tests/controls/page-control-prop-rendering.d.ts.map +1 -1
  33. package/dist/types/runtimes/react/controls/rich-text/EditableText/editable-text.d.ts.map +1 -1
  34. package/dist/types/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.d.ts.map +1 -1
  35. package/dist/types/runtimes/react/controls/use-slate-reset.d.ts +35 -0
  36. package/dist/types/runtimes/react/controls/use-slate-reset.d.ts.map +1 -0
  37. package/dist/types/runtimes/react/hooks/use-element-data.d.ts +5 -0
  38. package/dist/types/runtimes/react/hooks/use-element-data.d.ts.map +1 -0
  39. package/dist/types/runtimes/react/hooks/use-element.d.ts +5 -0
  40. package/dist/types/runtimes/react/hooks/use-element.d.ts.map +1 -0
  41. package/package.json +3 -3
@@ -27,7 +27,7 @@ class MakeswiftGraphQLApiClient {
27
27
  graphqlClient;
28
28
  constructor({ endpoint }) {
29
29
  this.graphqlClient = new import_client.GraphQLClient(endpoint, {
30
- "makeswift-runtime-version": "0.28.9"
30
+ "makeswift-runtime-version": "0.28.10-canary.0"
31
31
  });
32
32
  }
33
33
  async createTableRecord(tableId, columns) {
@@ -172,7 +172,7 @@ class MakeswiftRestAPIClient {
172
172
  const requestHeaders = new Headers({
173
173
  "x-api-key": this.apiKey,
174
174
  "makeswift-site-api-key": this.apiKey,
175
- "makeswift-runtime-version": "0.28.9"
175
+ "makeswift-runtime-version": "0.28.10-canary.0"
176
176
  });
177
177
  if (siteVersion?.token) {
178
178
  requestUrl.searchParams.set("version", siteVersion.version);
@@ -28,7 +28,7 @@ async function manifestHandler(req, { apiKey, manifest }) {
28
28
  return import_request_response.ApiResponse.json({ message: "Unauthorized" }, { status: 401 });
29
29
  }
30
30
  return import_request_response.ApiResponse.json({
31
- version: "0.28.9",
31
+ version: "0.28.10-canary.0",
32
32
  interactionMode: true,
33
33
  clientSideNavigation: false,
34
34
  elementFromPoint: false,
@@ -77,6 +77,22 @@ async function serverSideRender(children) {
77
77
  );
78
78
  return dom.window.document;
79
79
  }
80
+ function stubBuilderMessageChannel() {
81
+ const postMessageSpy = jest.spyOn(window, "postMessage").mockImplementation(() => {
82
+ });
83
+ const originalMessageChannel = window.MessageChannel;
84
+ const stubPort = () => ({ onmessage: null, postMessage: () => {
85
+ }, close: () => {
86
+ } });
87
+ window.MessageChannel = class {
88
+ port1 = stubPort();
89
+ port2 = stubPort();
90
+ };
91
+ return () => {
92
+ postMessageSpy.mockRestore();
93
+ window.MessageChannel = originalMessageChannel;
94
+ };
95
+ }
80
96
  async function testPageControlPropRendering(controlDefinition, {
81
97
  toData,
82
98
  value,
@@ -86,7 +102,8 @@ async function testPageControlPropRendering(controlDefinition, {
86
102
  registerComponents,
87
103
  action,
88
104
  rootElements = [],
89
- isInBuilder = false
105
+ isInBuilder = false,
106
+ isReadOnly = true
90
107
  }) {
91
108
  const controlData = value !== void 0 ? toData ? toData(value) : controlDefinition.toData(value) : void 0;
92
109
  const testComponentMeta = {
@@ -121,8 +138,12 @@ async function testPageControlPropRendering(controlDefinition, {
121
138
  }
122
139
  }
123
140
  );
124
- const testElementTree = (component) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Testing.ReactProvider, { runtime, children: component });
141
+ const testElementTree = (component) => {
142
+ const siteVersion = isReadOnly ? null : { token: "test-token", version: "draft" };
143
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Testing.ReactProvider, { runtime, siteVersion, children: component });
144
+ };
125
145
  if (!(0, import_is_server.isServer)()) {
146
+ const restoreMessageChannel = isReadOnly ? null : stubBuilderMessageChannel();
126
147
  const rootElementData = Testing.createRootComponent(
127
148
  [elementData, ...rootElements],
128
149
  ROOT_ID
@@ -139,6 +160,7 @@ async function testPageControlPropRendering(controlDefinition, {
139
160
  if (expectedRenders != null) {
140
161
  expect(Number(import_react2.screen.getByTestId(renderCountTestId).textContent)).toBe(expectedRenders);
141
162
  }
163
+ restoreMessageChannel?.();
142
164
  } else {
143
165
  console.assert(action == null);
144
166
  console.assert(rootElements.length === 0);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/next/components/tests/controls/page-control-prop-rendering.tsx"],"sourcesContent":["import { type ReactNode, Fragment, forwardRef, useRef, isValidElement, act } from 'react'\nimport { renderToReadableStream } from 'react-dom/server'\nimport { JSDOM } from 'jsdom'\nimport { render, screen } from '@testing-library/react'\nimport '@testing-library/jest-dom'\nimport { ServerInsertedHTMLContext } from 'next/navigation'\n\nimport { type Data, type ValueType, type DataType, ControlDefinition } from '@makeswift/controls'\n\nimport { type CacheData } from '../../../../api/api-resources-client'\nimport { ElementData } from '../../../../state/read-only-state'\nimport { setIsInBuilder } from '../../../../state/actions/internal/read-only-actions'\nimport { ReactRuntime } from '../../../../runtimes/react/react-runtime'\nimport { MakeswiftComponent } from '../../../../runtimes/react/components/MakeswiftComponent'\nimport { Page } from '../../page'\nimport { isServer } from '../../../../utils/is-server'\nimport * as Testing from '../../../testing'\n\nconst ROOT_ID = '00000000-0000-0000-0000-000000000000'\nconst ELEMENT_ID = '11111111-1111-1111-1111-111111111111'\n\nconst renderProp = (prop: any) =>\n prop === undefined ? 'undefined' : isValidElement(prop) ? prop : JSON.stringify(prop)\n\nconst propSnapshot = (prop: HTMLElement | null) =>\n prop?.childElementCount ? prop.childNodes : parseStringifiedProp(prop?.textContent ?? '')\n\nconst parseStringifiedProp = (prop: string) => (prop === 'undefined' ? undefined : JSON.parse(prop))\n\nasync function streamToString(stream: ReadableStream) {\n const reader = stream.getReader()\n const decoder = new TextDecoder()\n\n let result = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n result += decoder.decode(value, { stream: true })\n }\n\n return result\n}\n\nasync function renderToString(element: ReactNode) {\n return await streamToString(await renderToReadableStream(element))\n}\n\nasync function serverSideRender(children: ReactNode) {\n // wrap the children in a context provider to capture server-inserted HTML, see\n // https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/server-inserted-html.tsx\n const serverInsertedCallbacks: (() => React.ReactNode)[] = []\n\n const elementTree = (\n <ServerInsertedHTMLContext.Provider value={handler => serverInsertedCallbacks.push(handler)}>\n {children}\n </ServerInsertedHTMLContext.Provider>\n )\n\n const elementsHTML = await renderToString(elementTree)\n\n const serverInsertedNodes = serverInsertedCallbacks.map((callback, index) => (\n <Fragment key={'__next_server_inserted__' + index}>{callback()}</Fragment>\n ))\n\n const headHTML = await renderToString(serverInsertedNodes)\n\n const dom = new JSDOM(\n `<!DOCTYPE html><head>${headHTML}</head><body><div id=\"root\">${elementsHTML}</div></body></div>`,\n {\n runScripts: 'dangerously',\n },\n )\n\n return dom.window.document\n}\n\nexport async function testPageControlPropRendering<D extends ControlDefinition>(\n controlDefinition: D,\n {\n toData,\n value,\n locale,\n cacheData,\n expectedRenders,\n registerComponents,\n action,\n rootElements = [],\n isInBuilder = false,\n }: {\n toData?: (value: ValueType<D>) => DataType<D>\n value: ValueType<D> | undefined\n locale?: string | null\n cacheData?: Partial<CacheData>\n expectedRenders?: number\n registerComponents?: (runtime: ReactRuntime) => void\n action?: (element: HTMLElement) => Promise<void>\n rootElements?: ElementData[]\n isInBuilder?: boolean\n },\n) {\n // Arrange\n const controlData: DataType<D> | Data =\n value !== undefined ? (toData ? toData(value) : controlDefinition.toData(value)) : undefined\n\n const testComponentMeta = {\n type: 'TestComponent',\n label: 'Test Component',\n }\n\n const testId = 'test-id'\n const renderCountTestId = 'render-count-test-id'\n const elementData: ElementData = {\n key: ELEMENT_ID,\n type: testComponentMeta.type,\n props: {\n propKey: controlData,\n },\n }\n\n const runtime = Testing.createReactRuntime()\n runtime.protoStore.dispatch(setIsInBuilder(isInBuilder))\n registerComponents?.(runtime)\n\n // Act\n runtime.registerComponent(\n forwardRef<HTMLDivElement, { propKey?: any }>(({ propKey }, ref) => {\n const renderCount = useRef(0)\n ++renderCount.current\n\n return (\n <div ref={ref}>\n <div data-testid={renderCountTestId}>{renderCount.current}</div>\n <div data-testid={testId}>{renderProp(propKey)}</div>\n </div>\n )\n }),\n {\n ...testComponentMeta,\n props: {\n propKey: controlDefinition as any,\n },\n },\n )\n\n const testElementTree = (component: ReactNode) => (\n <Testing.ReactProvider runtime={runtime}>{component}</Testing.ReactProvider>\n )\n\n if (!isServer()) {\n const rootElementData: ElementData = Testing.createRootComponent(\n [elementData, ...rootElements],\n ROOT_ID,\n )\n\n const snapshot = Testing.createMakeswiftPageSnapshot(rootElementData, { locale, cacheData })\n\n // Assert\n await act(async () => render(testElementTree(<Page snapshot={snapshot} />)))\n\n if (action) {\n await act(async () => {\n await action(screen.getByTestId(testId))\n })\n }\n\n expect(snapshot).toMatchSnapshot('snapshot')\n expect(propSnapshot(screen.getByTestId(testId))).toMatchSnapshot('resolvedValue')\n\n if (expectedRenders != null) {\n expect(Number(screen.getByTestId(renderCountTestId).textContent)).toBe(expectedRenders)\n }\n } else {\n // test server-side rendering using a component snapshot\n console.assert(action == null)\n console.assert(rootElements.length === 0)\n\n const snapshot = Testing.createMakeswiftComponentSnapshot(elementData, { locale, cacheData })\n const elementTree = testElementTree(\n <MakeswiftComponent snapshot={snapshot} {...testComponentMeta} />,\n )\n\n const document = await serverSideRender(elementTree)\n const getByTestId = (id: string): HTMLElement | null =>\n document.querySelector(`[data-testid=\"${id}\"]`)\n\n expect(propSnapshot(getByTestId(testId))).toMatchSnapshot('resolvedValue')\n expect([...document.querySelectorAll('style')].map(n => n.textContent)).toMatchSnapshot(\n 'component styles',\n )\n expect(Number(getByTestId(renderCountTestId)?.textContent)).toBe(1)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAsDI;AAtDJ,mBAAkF;AAClF,oBAAuC;AACvC,mBAAsB;AACtB,IAAAA,gBAA+B;AAC/B,sBAAO;AACP,wBAA0C;AAM1C,+BAA+B;AAE/B,gCAAmC;AACnC,kBAAqB;AACrB,uBAAyB;AACzB,cAAyB;AAEzB,MAAM,UAAU;AAChB,MAAM,aAAa;AAEnB,MAAM,aAAa,CAAC,SAClB,SAAS,SAAY,kBAAc,6BAAe,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI;AAEtF,MAAM,eAAe,CAAC,SACpB,MAAM,oBAAoB,KAAK,aAAa,qBAAqB,MAAM,eAAe,EAAE;AAE1F,MAAM,uBAAuB,CAAC,SAAkB,SAAS,cAAc,SAAY,KAAK,MAAM,IAAI;AAElG,eAAe,eAAe,QAAwB;AACpD,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,IAAI,YAAY;AAEhC,MAAI,SAAS;AAEb,SAAO,MAAM;AACX,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI;AAAM;AACV,cAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAAA,EAClD;AAEA,SAAO;AACT;AAEA,eAAe,eAAe,SAAoB;AAChD,SAAO,MAAM,eAAe,UAAM,sCAAuB,OAAO,CAAC;AACnE;AAEA,eAAe,iBAAiB,UAAqB;AAGnD,QAAM,0BAAqD,CAAC;AAE5D,QAAM,cACJ,4CAAC,4CAA0B,UAA1B,EAAmC,OAAO,aAAW,wBAAwB,KAAK,OAAO,GACvF,UACH;AAGF,QAAM,eAAe,MAAM,eAAe,WAAW;AAErD,QAAM,sBAAsB,wBAAwB,IAAI,CAAC,UAAU,UACjE,4CAAC,yBAAmD,mBAAS,KAA9C,6BAA6B,KAAmB,CAChE;AAED,QAAM,WAAW,MAAM,eAAe,mBAAmB;AAEzD,QAAM,MAAM,IAAI;AAAA,IACd,wBAAwB,QAAQ,+BAA+B,YAAY;AAAA,IAC3E;AAAA,MACE,YAAY;AAAA,IACd;AAAA,EACF;AAEA,SAAO,IAAI,OAAO;AACpB;AAEA,eAAsB,6BACpB,mBACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe,CAAC;AAAA,EAChB,cAAc;AAChB,GAWA;AAEA,QAAM,cACJ,UAAU,SAAa,SAAS,OAAO,KAAK,IAAI,kBAAkB,OAAO,KAAK,IAAK;AAErF,QAAM,oBAAoB;AAAA,IACxB,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAEA,QAAM,SAAS;AACf,QAAM,oBAAoB;AAC1B,QAAM,cAA2B;AAAA,IAC/B,KAAK;AAAA,IACL,MAAM,kBAAkB;AAAA,IACxB,OAAO;AAAA,MACL,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,UAAU,QAAQ,mBAAmB;AAC3C,UAAQ,WAAW,aAAS,yCAAe,WAAW,CAAC;AACvD,uBAAqB,OAAO;AAG5B,UAAQ;AAAA,QACN,yBAA8C,CAAC,EAAE,QAAQ,GAAG,QAAQ;AAClE,YAAM,kBAAc,qBAAO,CAAC;AAC5B,QAAE,YAAY;AAEd,aACE,6CAAC,SAAI,KACH;AAAA,oDAAC,SAAI,eAAa,mBAAoB,sBAAY,SAAQ;AAAA,QAC1D,4CAAC,SAAI,eAAa,QAAS,qBAAW,OAAO,GAAE;AAAA,SACjD;AAAA,IAEJ,CAAC;AAAA,IACD;AAAA,MACE,GAAG;AAAA,MACH,OAAO;AAAA,QACL,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAEA,QAAM,kBAAkB,CAAC,cACvB,4CAAC,QAAQ,eAAR,EAAsB,SAAmB,qBAAU;AAGtD,MAAI,KAAC,2BAAS,GAAG;AACf,UAAM,kBAA+B,QAAQ;AAAA,MAC3C,CAAC,aAAa,GAAG,YAAY;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,WAAW,QAAQ,4BAA4B,iBAAiB,EAAE,QAAQ,UAAU,CAAC;AAG3F,cAAM,kBAAI,gBAAY,sBAAO,gBAAgB,4CAAC,oBAAK,UAAoB,CAAE,CAAC,CAAC;AAE3E,QAAI,QAAQ;AACV,gBAAM,kBAAI,YAAY;AACpB,cAAM,OAAO,qBAAO,YAAY,MAAM,CAAC;AAAA,MACzC,CAAC;AAAA,IACH;AAEA,WAAO,QAAQ,EAAE,gBAAgB,UAAU;AAC3C,WAAO,aAAa,qBAAO,YAAY,MAAM,CAAC,CAAC,EAAE,gBAAgB,eAAe;AAEhF,QAAI,mBAAmB,MAAM;AAC3B,aAAO,OAAO,qBAAO,YAAY,iBAAiB,EAAE,WAAW,CAAC,EAAE,KAAK,eAAe;AAAA,IACxF;AAAA,EACF,OAAO;AAEL,YAAQ,OAAO,UAAU,IAAI;AAC7B,YAAQ,OAAO,aAAa,WAAW,CAAC;AAExC,UAAM,WAAW,QAAQ,iCAAiC,aAAa,EAAE,QAAQ,UAAU,CAAC;AAC5F,UAAM,cAAc;AAAA,MAClB,4CAAC,gDAAmB,UAAqB,GAAG,mBAAmB;AAAA,IACjE;AAEA,UAAM,WAAW,MAAM,iBAAiB,WAAW;AACnD,UAAM,cAAc,CAAC,OACnB,SAAS,cAAc,iBAAiB,EAAE,IAAI;AAEhD,WAAO,aAAa,YAAY,MAAM,CAAC,CAAC,EAAE,gBAAgB,eAAe;AACzE,WAAO,CAAC,GAAG,SAAS,iBAAiB,OAAO,CAAC,EAAE,IAAI,OAAK,EAAE,WAAW,CAAC,EAAE;AAAA,MACtE;AAAA,IACF;AACA,WAAO,OAAO,YAAY,iBAAiB,GAAG,WAAW,CAAC,EAAE,KAAK,CAAC;AAAA,EACpE;AACF;","names":["import_react"]}
1
+ {"version":3,"sources":["../../../../../../src/next/components/tests/controls/page-control-prop-rendering.tsx"],"sourcesContent":["import { type ReactNode, Fragment, forwardRef, useRef, isValidElement, act } from 'react'\nimport { renderToReadableStream } from 'react-dom/server'\nimport { JSDOM } from 'jsdom'\nimport { render, screen } from '@testing-library/react'\nimport '@testing-library/jest-dom'\nimport { ServerInsertedHTMLContext } from 'next/navigation'\n\nimport { type Data, type ValueType, type DataType, ControlDefinition } from '@makeswift/controls'\n\nimport { type CacheData } from '../../../../api/api-resources-client'\nimport { ElementData } from '../../../../state/read-only-state'\nimport { setIsInBuilder } from '../../../../state/actions/internal/read-only-actions'\nimport { ReactRuntime } from '../../../../runtimes/react/react-runtime'\nimport { MakeswiftComponent } from '../../../../runtimes/react/components/MakeswiftComponent'\nimport { Page } from '../../page'\nimport { isServer } from '../../../../utils/is-server'\nimport * as Testing from '../../../testing'\n\nconst ROOT_ID = '00000000-0000-0000-0000-000000000000'\nconst ELEMENT_ID = '11111111-1111-1111-1111-111111111111'\n\nconst renderProp = (prop: any) =>\n prop === undefined ? 'undefined' : isValidElement(prop) ? prop : JSON.stringify(prop)\n\nconst propSnapshot = (prop: HTMLElement | null) =>\n prop?.childElementCount ? prop.childNodes : parseStringifiedProp(prop?.textContent ?? '')\n\nconst parseStringifiedProp = (prop: string) => (prop === 'undefined' ? undefined : JSON.parse(prop))\n\nasync function streamToString(stream: ReadableStream) {\n const reader = stream.getReader()\n const decoder = new TextDecoder()\n\n let result = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n result += decoder.decode(value, { stream: true })\n }\n\n return result\n}\n\nasync function renderToString(element: ReactNode) {\n return await streamToString(await renderToReadableStream(element))\n}\n\nasync function serverSideRender(children: ReactNode) {\n // wrap the children in a context provider to capture server-inserted HTML, see\n // https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/server-inserted-html.tsx\n const serverInsertedCallbacks: (() => React.ReactNode)[] = []\n\n const elementTree = (\n <ServerInsertedHTMLContext.Provider value={handler => serverInsertedCallbacks.push(handler)}>\n {children}\n </ServerInsertedHTMLContext.Provider>\n )\n\n const elementsHTML = await renderToString(elementTree)\n\n const serverInsertedNodes = serverInsertedCallbacks.map((callback, index) => (\n <Fragment key={'__next_server_inserted__' + index}>{callback()}</Fragment>\n ))\n\n const headHTML = await renderToString(serverInsertedNodes)\n\n const dom = new JSDOM(\n `<!DOCTYPE html><head>${headHTML}</head><body><div id=\"root\">${elementsHTML}</div></body></div>`,\n {\n runScripts: 'dangerously',\n },\n )\n\n return dom.window.document\n}\n\n/**\n * In read-write mode, the runtime opens a `MessageChannel` to the builder\n * parent frame; jsdom doesn't implement `MessageChannel`, so stub them to keep\n * the read-write setup from throwing.\n */\nfunction stubBuilderMessageChannel(): () => void {\n const postMessageSpy = jest.spyOn(window, 'postMessage').mockImplementation(() => {})\n\n const originalMessageChannel = window.MessageChannel\n const stubPort = () => ({ onmessage: null, postMessage: () => {}, close: () => {} })\n window.MessageChannel = class {\n port1 = stubPort()\n port2 = stubPort()\n } as unknown as typeof MessageChannel\n\n return () => {\n postMessageSpy.mockRestore()\n window.MessageChannel = originalMessageChannel\n }\n}\n\nexport async function testPageControlPropRendering<D extends ControlDefinition>(\n controlDefinition: D,\n {\n toData,\n value,\n locale,\n cacheData,\n expectedRenders,\n registerComponents,\n action,\n rootElements = [],\n isInBuilder = false,\n isReadOnly = true,\n }: {\n toData?: (value: ValueType<D>) => DataType<D>\n value: ValueType<D> | undefined\n locale?: string | null\n cacheData?: Partial<CacheData>\n expectedRenders?: number\n registerComponents?: (runtime: ReactRuntime) => void\n action?: (element: HTMLElement) => Promise<void>\n rootElements?: ElementData[]\n isInBuilder?: boolean\n isReadOnly?: boolean\n },\n) {\n // Arrange\n const controlData: DataType<D> | Data =\n value !== undefined ? (toData ? toData(value) : controlDefinition.toData(value)) : undefined\n\n const testComponentMeta = {\n type: 'TestComponent',\n label: 'Test Component',\n }\n\n const testId = 'test-id'\n const renderCountTestId = 'render-count-test-id'\n const elementData: ElementData = {\n key: ELEMENT_ID,\n type: testComponentMeta.type,\n props: {\n propKey: controlData,\n },\n }\n\n const runtime = Testing.createReactRuntime()\n runtime.protoStore.dispatch(setIsInBuilder(isInBuilder))\n registerComponents?.(runtime)\n\n // Act\n runtime.registerComponent(\n forwardRef<HTMLDivElement, { propKey?: any }>(({ propKey }, ref) => {\n const renderCount = useRef(0)\n ++renderCount.current\n\n return (\n <div ref={ref}>\n <div data-testid={renderCountTestId}>{renderCount.current}</div>\n <div data-testid={testId}>{renderProp(propKey)}</div>\n </div>\n )\n }),\n {\n ...testComponentMeta,\n props: {\n propKey: controlDefinition as any,\n },\n },\n )\n\n const testElementTree = (component: ReactNode) => {\n // The runtime enters the read-write state when a non-null site version is\n // passed\n const siteVersion = isReadOnly ? null : { token: 'test-token', version: 'draft' }\n return (\n <Testing.ReactProvider runtime={runtime} siteVersion={siteVersion}>\n {component}\n </Testing.ReactProvider>\n )\n }\n\n if (!isServer()) {\n const restoreMessageChannel = isReadOnly ? null : stubBuilderMessageChannel()\n\n const rootElementData: ElementData = Testing.createRootComponent(\n [elementData, ...rootElements],\n ROOT_ID,\n )\n\n const snapshot = Testing.createMakeswiftPageSnapshot(rootElementData, { locale, cacheData })\n\n // Assert\n await act(async () => render(testElementTree(<Page snapshot={snapshot} />)))\n\n if (action) {\n await act(async () => {\n await action(screen.getByTestId(testId))\n })\n }\n\n expect(snapshot).toMatchSnapshot('snapshot')\n expect(propSnapshot(screen.getByTestId(testId))).toMatchSnapshot('resolvedValue')\n\n if (expectedRenders != null) {\n expect(Number(screen.getByTestId(renderCountTestId).textContent)).toBe(expectedRenders)\n }\n\n restoreMessageChannel?.()\n } else {\n // test server-side rendering using a component snapshot\n console.assert(action == null)\n console.assert(rootElements.length === 0)\n\n const snapshot = Testing.createMakeswiftComponentSnapshot(elementData, { locale, cacheData })\n const elementTree = testElementTree(\n <MakeswiftComponent snapshot={snapshot} {...testComponentMeta} />,\n )\n\n const document = await serverSideRender(elementTree)\n const getByTestId = (id: string): HTMLElement | null =>\n document.querySelector(`[data-testid=\"${id}\"]`)\n\n expect(propSnapshot(getByTestId(testId))).toMatchSnapshot('resolvedValue')\n expect([...document.querySelectorAll('style')].map(n => n.textContent)).toMatchSnapshot(\n 'component styles',\n )\n expect(Number(getByTestId(renderCountTestId)?.textContent)).toBe(1)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAsDI;AAtDJ,mBAAkF;AAClF,oBAAuC;AACvC,mBAAsB;AACtB,IAAAA,gBAA+B;AAC/B,sBAAO;AACP,wBAA0C;AAM1C,+BAA+B;AAE/B,gCAAmC;AACnC,kBAAqB;AACrB,uBAAyB;AACzB,cAAyB;AAEzB,MAAM,UAAU;AAChB,MAAM,aAAa;AAEnB,MAAM,aAAa,CAAC,SAClB,SAAS,SAAY,kBAAc,6BAAe,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI;AAEtF,MAAM,eAAe,CAAC,SACpB,MAAM,oBAAoB,KAAK,aAAa,qBAAqB,MAAM,eAAe,EAAE;AAE1F,MAAM,uBAAuB,CAAC,SAAkB,SAAS,cAAc,SAAY,KAAK,MAAM,IAAI;AAElG,eAAe,eAAe,QAAwB;AACpD,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,IAAI,YAAY;AAEhC,MAAI,SAAS;AAEb,SAAO,MAAM;AACX,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI;AAAM;AACV,cAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAAA,EAClD;AAEA,SAAO;AACT;AAEA,eAAe,eAAe,SAAoB;AAChD,SAAO,MAAM,eAAe,UAAM,sCAAuB,OAAO,CAAC;AACnE;AAEA,eAAe,iBAAiB,UAAqB;AAGnD,QAAM,0BAAqD,CAAC;AAE5D,QAAM,cACJ,4CAAC,4CAA0B,UAA1B,EAAmC,OAAO,aAAW,wBAAwB,KAAK,OAAO,GACvF,UACH;AAGF,QAAM,eAAe,MAAM,eAAe,WAAW;AAErD,QAAM,sBAAsB,wBAAwB,IAAI,CAAC,UAAU,UACjE,4CAAC,yBAAmD,mBAAS,KAA9C,6BAA6B,KAAmB,CAChE;AAED,QAAM,WAAW,MAAM,eAAe,mBAAmB;AAEzD,QAAM,MAAM,IAAI;AAAA,IACd,wBAAwB,QAAQ,+BAA+B,YAAY;AAAA,IAC3E;AAAA,MACE,YAAY;AAAA,IACd;AAAA,EACF;AAEA,SAAO,IAAI,OAAO;AACpB;AAOA,SAAS,4BAAwC;AAC/C,QAAM,iBAAiB,KAAK,MAAM,QAAQ,aAAa,EAAE,mBAAmB,MAAM;AAAA,EAAC,CAAC;AAEpF,QAAM,yBAAyB,OAAO;AACtC,QAAM,WAAW,OAAO,EAAE,WAAW,MAAM,aAAa,MAAM;AAAA,EAAC,GAAG,OAAO,MAAM;AAAA,EAAC,EAAE;AAClF,SAAO,iBAAiB,MAAM;AAAA,IAC5B,QAAQ,SAAS;AAAA,IACjB,QAAQ,SAAS;AAAA,EACnB;AAEA,SAAO,MAAM;AACX,mBAAe,YAAY;AAC3B,WAAO,iBAAiB;AAAA,EAC1B;AACF;AAEA,eAAsB,6BACpB,mBACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe,CAAC;AAAA,EAChB,cAAc;AAAA,EACd,aAAa;AACf,GAYA;AAEA,QAAM,cACJ,UAAU,SAAa,SAAS,OAAO,KAAK,IAAI,kBAAkB,OAAO,KAAK,IAAK;AAErF,QAAM,oBAAoB;AAAA,IACxB,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAEA,QAAM,SAAS;AACf,QAAM,oBAAoB;AAC1B,QAAM,cAA2B;AAAA,IAC/B,KAAK;AAAA,IACL,MAAM,kBAAkB;AAAA,IACxB,OAAO;AAAA,MACL,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,UAAU,QAAQ,mBAAmB;AAC3C,UAAQ,WAAW,aAAS,yCAAe,WAAW,CAAC;AACvD,uBAAqB,OAAO;AAG5B,UAAQ;AAAA,QACN,yBAA8C,CAAC,EAAE,QAAQ,GAAG,QAAQ;AAClE,YAAM,kBAAc,qBAAO,CAAC;AAC5B,QAAE,YAAY;AAEd,aACE,6CAAC,SAAI,KACH;AAAA,oDAAC,SAAI,eAAa,mBAAoB,sBAAY,SAAQ;AAAA,QAC1D,4CAAC,SAAI,eAAa,QAAS,qBAAW,OAAO,GAAE;AAAA,SACjD;AAAA,IAEJ,CAAC;AAAA,IACD;AAAA,MACE,GAAG;AAAA,MACH,OAAO;AAAA,QACL,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAEA,QAAM,kBAAkB,CAAC,cAAyB;AAGhD,UAAM,cAAc,aAAa,OAAO,EAAE,OAAO,cAAc,SAAS,QAAQ;AAChF,WACE,4CAAC,QAAQ,eAAR,EAAsB,SAAkB,aACtC,qBACH;AAAA,EAEJ;AAEA,MAAI,KAAC,2BAAS,GAAG;AACf,UAAM,wBAAwB,aAAa,OAAO,0BAA0B;AAE5E,UAAM,kBAA+B,QAAQ;AAAA,MAC3C,CAAC,aAAa,GAAG,YAAY;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,WAAW,QAAQ,4BAA4B,iBAAiB,EAAE,QAAQ,UAAU,CAAC;AAG3F,cAAM,kBAAI,gBAAY,sBAAO,gBAAgB,4CAAC,oBAAK,UAAoB,CAAE,CAAC,CAAC;AAE3E,QAAI,QAAQ;AACV,gBAAM,kBAAI,YAAY;AACpB,cAAM,OAAO,qBAAO,YAAY,MAAM,CAAC;AAAA,MACzC,CAAC;AAAA,IACH;AAEA,WAAO,QAAQ,EAAE,gBAAgB,UAAU;AAC3C,WAAO,aAAa,qBAAO,YAAY,MAAM,CAAC,CAAC,EAAE,gBAAgB,eAAe;AAEhF,QAAI,mBAAmB,MAAM;AAC3B,aAAO,OAAO,qBAAO,YAAY,iBAAiB,EAAE,WAAW,CAAC,EAAE,KAAK,eAAe;AAAA,IACxF;AAEA,4BAAwB;AAAA,EAC1B,OAAO;AAEL,YAAQ,OAAO,UAAU,IAAI;AAC7B,YAAQ,OAAO,aAAa,WAAW,CAAC;AAExC,UAAM,WAAW,QAAQ,iCAAiC,aAAa,EAAE,QAAQ,UAAU,CAAC;AAC5F,UAAM,cAAc;AAAA,MAClB,4CAAC,gDAAmB,UAAqB,GAAG,mBAAmB;AAAA,IACjE;AAEA,UAAM,WAAW,MAAM,iBAAiB,WAAW;AACnD,UAAM,cAAc,CAAC,OACnB,SAAS,cAAc,iBAAiB,EAAE,IAAI;AAEhD,WAAO,aAAa,YAAY,MAAM,CAAC,CAAC,EAAE,gBAAgB,eAAe;AACzE,WAAO,CAAC,GAAG,SAAS,iBAAiB,OAAO,CAAC,EAAE,IAAI,OAAK,EAAE,WAAW,CAAC,EAAE;AAAA,MACtE;AAAA,IACF;AACA,WAAO,OAAO,YAAY,iBAAiB,GAAG,WAAW,CAAC,EAAE,KAAK,CAAC;AAAA,EACpE;AACF;","names":["import_react"]}
@@ -42,6 +42,7 @@ var import_slate = require("slate");
42
42
  var import_slate_react = require("slate-react");
43
43
  var import_controls = require("@makeswift/controls");
44
44
  var import__ = require("../../..");
45
+ var import_use_slate_reset = require("../../use-slate-reset");
45
46
  var import_slate2 = require("../../../../../slate");
46
47
  var import_builder_edit_mode = require("../../../../../state/modules/builder-edit-mode");
47
48
  var import_poll_box_model = require("../../../poll-box-model");
@@ -101,6 +102,7 @@ const EditableText = (0, import_react.forwardRef)(function EditableText2({ id, t
101
102
  },
102
103
  [controller, editor]
103
104
  );
105
+ const slateReset = (0, import_use_slate_reset.useSlateReset)();
104
106
  const handleBlur = (0, import_react.useCallback)((e) => {
105
107
  if (e.relatedTarget == null)
106
108
  return;
@@ -116,7 +118,7 @@ const EditableText = (0, import_react.forwardRef)(function EditableText2({ id, t
116
118
  onFocus: handleFocus,
117
119
  onKeyDown: handleKeyDown,
118
120
  onBlur: handleBlur,
119
- className: (0, import_css.cx)(width, margin),
121
+ className: (0, import_css.cx)(slateReset, width, margin),
120
122
  readOnly: editMode !== import_builder_edit_mode.BuilderEditMode.CONTENT,
121
123
  placeholder: "Write some text..."
122
124
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/runtimes/react/controls/rich-text/EditableText/editable-text.tsx"],"sourcesContent":["'use client'\n\nimport { cx } from '@emotion/css'\nimport { getBox } from 'css-box-model'\nimport isHotkey from 'is-hotkey'\nimport {\n FocusEvent,\n forwardRef,\n KeyboardEvent,\n Ref,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\n\nimport { createEditor } from 'slate'\nimport { Slate as SlateReact, Editable, withReact, ReactEditor } from 'slate-react'\n\nimport { Slate, richTextDTOtoDAO, type RichTextValue } from '@makeswift/controls'\n\nimport { useBuilderEditMode } from '../../..'\nimport { DescriptorsPropControllers } from '../../../../../prop-controllers/instances'\nimport { withBlock, withTypography, withBuilder, onKeyDown } from '../../../../../slate'\nimport { BuilderEditMode } from '../../../../../state/modules/builder-edit-mode'\nimport { PropControllersHandle } from '../../../../../state/modules/read-write/prop-controllers'\nimport { pollBoxModel } from '../../../poll-box-model'\nimport { Element, Leaf } from '../components'\nimport { Descriptors } from '../rich-text'\nimport { useSyncDOMSelection } from './useSyncDOMSelection'\nimport { useSyncWithBuilder } from './useSyncWithBuilder'\n\ntype Props = {\n id?: string\n text?: RichTextValue\n width?: string\n margin?: string\n}\n\nconst defaultText: Slate.RichTextDAO = [\n { type: Slate.BlockType.Paragraph, children: [{ text: '' }] },\n]\n\nexport const EditableText = forwardRef(function EditableText(\n { id, text, width, margin }: Props,\n ref: Ref<PropControllersHandle<Descriptors>>,\n) {\n const [editor] = useState(() => withBlock(withTypography(withBuilder(withReact(createEditor())))))\n const [isPreservingDOMSElection, setIsPreservingDOMSelection] = useState(false)\n useSyncDOMSelection(editor, isPreservingDOMSElection)\n const delaySync = useSyncWithBuilder(editor, text)\n const editMode = useBuilderEditMode()\n\n const [propControllers, setPropControllers] =\n useState<DescriptorsPropControllers<Descriptors> | null>(null)\n const controller = propControllers?.text\n\n useEffect(() => {\n if (controller == null) return\n\n const element = ReactEditor.toDOMNode(editor, editor)\n\n return pollBoxModel({\n element,\n onBoxModelChange: boxModel => controller.changeBoxModel(boxModel),\n })\n }, [editor, controller])\n\n useImperativeHandle(\n ref,\n () => ({\n getDomNode() {\n return ReactEditor.toDOMNode(editor, editor)\n },\n getBoxModel() {\n return getBox(ReactEditor.toDOMNode(editor, editor))\n },\n setPropControllers,\n }),\n [editor, setPropControllers],\n )\n\n const initialValue = useMemo(() => (text ? richTextDTOtoDAO(text) : defaultText), [text])\n\n useEffect(() => {\n controller?.setSlateEditor(editor)\n }, [controller, editor])\n\n const handleFocus = useCallback(() => {\n controller?.focus()\n setIsPreservingDOMSelection(true)\n }, [controller])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isHotkey('mod+shift+z', e)) return controller?.redo()\n if (isHotkey('mod+z', e)) return controller?.undo()\n if (isHotkey('escape')(e)) return controller?.blur()\n onKeyDown(e, editor)\n },\n [controller, editor],\n )\n\n const handleBlur = useCallback((e: FocusEvent) => {\n // When clicking outside of the iframe (`relatedTarget` is null) we want to preserve the DOM selection.\n if (e.relatedTarget == null) return\n // Otherwise we want to deselect on blur and stop preserving selection.\n setIsPreservingDOMSelection(false)\n ReactEditor.deselect(editor)\n }, [])\n\n return (\n <SlateReact editor={editor} value={initialValue} onChange={delaySync}>\n <Editable\n id={id}\n renderLeaf={Leaf}\n renderElement={Element}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n className={cx(width, margin)}\n readOnly={editMode !== BuilderEditMode.CONTENT}\n placeholder=\"Write some text...\"\n />\n </SlateReact>\n )\n})\n\nexport default EditableText\n"],"mappings":"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","names":["import_slate","EditableText","isHotkey","SlateReact"]}
1
+ {"version":3,"sources":["../../../../../../../src/runtimes/react/controls/rich-text/EditableText/editable-text.tsx"],"sourcesContent":["'use client'\n\nimport { cx } from '@emotion/css'\nimport { getBox } from 'css-box-model'\nimport isHotkey from 'is-hotkey'\nimport {\n FocusEvent,\n forwardRef,\n KeyboardEvent,\n Ref,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\n\nimport { createEditor } from 'slate'\nimport { Slate as SlateReact, Editable, withReact, ReactEditor } from 'slate-react'\n\nimport { Slate, richTextDTOtoDAO, type RichTextValue } from '@makeswift/controls'\n\nimport { useBuilderEditMode } from '../../..'\nimport { useSlateReset } from '../../use-slate-reset'\nimport { DescriptorsPropControllers } from '../../../../../prop-controllers/instances'\nimport { withBlock, withTypography, withBuilder, onKeyDown } from '../../../../../slate'\nimport { BuilderEditMode } from '../../../../../state/modules/builder-edit-mode'\nimport { PropControllersHandle } from '../../../../../state/modules/read-write/prop-controllers'\nimport { pollBoxModel } from '../../../poll-box-model'\nimport { Element, Leaf } from '../components'\nimport { Descriptors } from '../rich-text'\nimport { useSyncDOMSelection } from './useSyncDOMSelection'\nimport { useSyncWithBuilder } from './useSyncWithBuilder'\n\ntype Props = {\n id?: string\n text?: RichTextValue\n width?: string\n margin?: string\n}\n\nconst defaultText: Slate.RichTextDAO = [\n { type: Slate.BlockType.Paragraph, children: [{ text: '' }] },\n]\n\nexport const EditableText = forwardRef(function EditableText(\n { id, text, width, margin }: Props,\n ref: Ref<PropControllersHandle<Descriptors>>,\n) {\n const [editor] = useState(() => withBlock(withTypography(withBuilder(withReact(createEditor())))))\n const [isPreservingDOMSElection, setIsPreservingDOMSelection] = useState(false)\n useSyncDOMSelection(editor, isPreservingDOMSElection)\n const delaySync = useSyncWithBuilder(editor, text)\n const editMode = useBuilderEditMode()\n\n const [propControllers, setPropControllers] =\n useState<DescriptorsPropControllers<Descriptors> | null>(null)\n const controller = propControllers?.text\n\n useEffect(() => {\n if (controller == null) return\n\n const element = ReactEditor.toDOMNode(editor, editor)\n\n return pollBoxModel({\n element,\n onBoxModelChange: boxModel => controller.changeBoxModel(boxModel),\n })\n }, [editor, controller])\n\n useImperativeHandle(\n ref,\n () => ({\n getDomNode() {\n return ReactEditor.toDOMNode(editor, editor)\n },\n getBoxModel() {\n return getBox(ReactEditor.toDOMNode(editor, editor))\n },\n setPropControllers,\n }),\n [editor, setPropControllers],\n )\n\n const initialValue = useMemo(() => (text ? richTextDTOtoDAO(text) : defaultText), [text])\n\n useEffect(() => {\n controller?.setSlateEditor(editor)\n }, [controller, editor])\n\n const handleFocus = useCallback(() => {\n controller?.focus()\n setIsPreservingDOMSelection(true)\n }, [controller])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isHotkey('mod+shift+z', e)) return controller?.redo()\n if (isHotkey('mod+z', e)) return controller?.undo()\n if (isHotkey('escape')(e)) return controller?.blur()\n onKeyDown(e, editor)\n },\n [controller, editor],\n )\n\n const slateReset = useSlateReset()\n\n const handleBlur = useCallback((e: FocusEvent) => {\n // When clicking outside of the iframe (`relatedTarget` is null) we want to preserve the DOM selection.\n if (e.relatedTarget == null) return\n // Otherwise we want to deselect on blur and stop preserving selection.\n setIsPreservingDOMSelection(false)\n ReactEditor.deselect(editor)\n }, [])\n\n return (\n <SlateReact editor={editor} value={initialValue} onChange={delaySync}>\n <Editable\n id={id}\n renderLeaf={Leaf}\n renderElement={Element}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n className={cx(slateReset, width, margin)}\n readOnly={editMode !== BuilderEditMode.CONTENT}\n placeholder=\"Write some text...\"\n />\n </SlateReact>\n )\n})\n\nexport default EditableText\n"],"mappings":"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","names":["import_slate","EditableText","isHotkey","SlateReact"]}
@@ -40,6 +40,7 @@ var import_is_hotkey = __toESM(require("is-hotkey"));
40
40
  var import_slate_react = require("slate-react");
41
41
  var import_rich_text_v2 = require("../../../../../controls/rich-text-v2");
42
42
  var import__ = require("../../..");
43
+ var import_use_slate_reset = require("../../use-slate-reset");
43
44
  var import_builder_edit_mode = require("../../../../../state/modules/builder-edit-mode");
44
45
  var import_poll_box_model = require("../../../poll-box-model");
45
46
  var import_slate2 = require("../../../../../slate");
@@ -147,9 +148,11 @@ function EditableTextV2({ text, definition, control }) {
147
148
  if (e.relatedTarget?.getAttribute("contenteditable") === "true")
148
149
  isPreservingFocus.current = false;
149
150
  }, []);
151
+ const slateReset = (0, import_use_slate_reset.useSlateReset)();
150
152
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_slate_react.Slate, { editor, value: initialValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
151
153
  import_slate_react.Editable,
152
154
  {
155
+ className: slateReset,
153
156
  renderLeaf,
154
157
  renderElement,
155
158
  onFocus: handleFocus,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.tsx"],"sourcesContent":["'use client'\n\nimport {\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { createEditor } from 'slate'\nimport isHotkey from 'is-hotkey'\nimport {\n withReact,\n ReactEditor,\n RenderElementProps,\n RenderLeafProps,\n Slate,\n Editable,\n} from 'slate-react'\n\nimport {\n RichTextV2Definition,\n RichText,\n RichTextV2Control,\n type RichTextDataV2,\n} from '../../../../../controls/rich-text-v2'\n\nimport { useBuilderEditMode } from '../../..'\nimport { BuilderEditMode } from '../../../../../state/modules/builder-edit-mode'\nimport { pollBoxModel } from '../../../poll-box-model'\nimport { withBuilder, withLocalChanges } from '../../../../../slate'\nimport { useSyncDOMSelection } from './useSyncDOMSelection'\nimport { RichTextV2Element } from './render-element'\nimport { RichTextV2Leaf } from './render-leaf'\nimport { useSyncRemoteChanges } from './useRemoteChanges'\nimport { defaultValue, usePresetValue } from './usePresetValue'\n\nexport type RichTextV2ControlValue = ReactNode\n\nexport type Descriptors = { text?: RichTextV2Definition }\n\ntype Props = {\n text?: RichTextDataV2\n definition: RichTextV2Definition\n control: RichTextV2Control | null\n}\n\nexport function EditableTextV2({ text, definition, control }: Props) {\n const plugins = useMemo(() => definition.config.plugins, [definition])\n\n const [editor] = useState(() =>\n plugins.reduceRight(\n (editor, plugin) => plugin?.withPlugin?.(editor) ?? editor,\n withLocalChanges(withBuilder(withReact(createEditor()))),\n ),\n )\n\n useEffect(() => {\n if (control == null) return\n\n const element = ReactEditor.toDOMNode(editor, editor)\n return pollBoxModel({\n element,\n onBoxModelChange: boxModel => control.changeBoxModel(boxModel),\n })\n }, [editor, control])\n\n // ------ Preserving selection ------\n\n const isPreservingFocus = useRef(false)\n useSyncDOMSelection(editor, isPreservingFocus)\n const editMode = useBuilderEditMode()\n\n useEffect(() => {\n /**\n * This is required because clicking on the overlay has `relatedTarget` null just like the sidebar, but\n * - in the case of the overlay we switch to BUILD mode\n * - in the case of the sidebar we preserve the selection\n */\n if (editMode !== BuilderEditMode.CONTENT) {\n isPreservingFocus.current = false\n ReactEditor.deselect(editor)\n }\n }, [editMode])\n\n // ------ Syncing remote changes ------\n\n useSyncRemoteChanges(editor, text)\n\n // ------ Default value ------\n\n const presetValue = usePresetValue(definition)\n\n const initialValue = useMemo(\n () => (text && RichText.dataToNodes(text)) ?? presetValue,\n [text, presetValue],\n )\n\n useEffect(() => {\n control?.setEditor(editor)\n control?.setDefaultValue(defaultValue)\n }, [control, editor])\n\n /**\n * When initialValue is set to the default value we need to trigger an local change so that the sidebar updates and so the data is saved\n */\n useEffect(() => {\n if (initialValue === presetValue) {\n control?.onLocalUserChange()\n }\n }, [control, initialValue, presetValue])\n\n // ------ Rendering ------\n\n const renderElement = useCallback(\n (props: RenderElementProps) => {\n return <RichTextV2Element {...props} definition={definition} plugins={plugins} />\n },\n [plugins, definition],\n )\n\n const renderLeaf = useCallback(\n (props: RenderLeafProps) => {\n return <RichTextV2Leaf {...props} definition={definition} plugins={plugins} />\n },\n [plugins, definition],\n )\n\n // ------ Event handlers ------\n\n const handleFocus = useCallback(() => {\n isPreservingFocus.current = true\n control?.select()\n }, [control])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isHotkey('mod+shift+z', e)) return control?.redo()\n if (isHotkey('mod+z', e)) return control?.undo()\n if (isHotkey('escape')(e)) {\n isPreservingFocus.current = false\n ReactEditor.blur(editor)\n control?.switchToBuildMode()\n }\n\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n }\n\n plugins.forEach(plugin => plugin?.onKeyDown?.(e, editor))\n },\n [control, plugins, editor, editMode],\n )\n\n const handleKeyUp = useCallback(\n (e: KeyboardEvent) => {\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n e.preventDefault()\n }\n },\n [control, editor, editMode],\n )\n\n const handleClick = useCallback(\n (e: MouseEvent) => {\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n e.preventDefault()\n }\n },\n [editMode],\n )\n\n const handleBlur = useCallback((e: FocusEvent) => {\n // outside of iframe (overlay, sidebar, etc)\n if (e.relatedTarget == null) return\n // another text\n if (e.relatedTarget?.getAttribute('contenteditable') === 'true')\n isPreservingFocus.current = false\n }, [])\n\n return (\n <Slate editor={editor} value={initialValue}>\n <Editable\n renderLeaf={renderLeaf}\n renderElement={renderElement}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n onClick={handleClick}\n onBlur={handleBlur}\n readOnly={editMode !== BuilderEditMode.CONTENT}\n placeholder=\"Write some text...\"\n />\n </Slate>\n )\n}\n\nexport default EditableTextV2\n"],"mappings":"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","names":["import_slate","editor","isHotkey"]}
1
+ {"version":3,"sources":["../../../../../../../src/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.tsx"],"sourcesContent":["'use client'\n\nimport {\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { createEditor } from 'slate'\nimport isHotkey from 'is-hotkey'\nimport {\n withReact,\n ReactEditor,\n RenderElementProps,\n RenderLeafProps,\n Slate,\n Editable,\n} from 'slate-react'\n\nimport {\n RichTextV2Definition,\n RichText,\n RichTextV2Control,\n type RichTextDataV2,\n} from '../../../../../controls/rich-text-v2'\n\nimport { useBuilderEditMode } from '../../..'\nimport { useSlateReset } from '../../use-slate-reset'\nimport { BuilderEditMode } from '../../../../../state/modules/builder-edit-mode'\nimport { pollBoxModel } from '../../../poll-box-model'\nimport { withBuilder, withLocalChanges } from '../../../../../slate'\nimport { useSyncDOMSelection } from './useSyncDOMSelection'\nimport { RichTextV2Element } from './render-element'\nimport { RichTextV2Leaf } from './render-leaf'\nimport { useSyncRemoteChanges } from './useRemoteChanges'\nimport { defaultValue, usePresetValue } from './usePresetValue'\n\nexport type RichTextV2ControlValue = ReactNode\n\nexport type Descriptors = { text?: RichTextV2Definition }\n\ntype Props = {\n text?: RichTextDataV2\n definition: RichTextV2Definition\n control: RichTextV2Control | null\n}\n\nexport function EditableTextV2({ text, definition, control }: Props) {\n const plugins = useMemo(() => definition.config.plugins, [definition])\n\n const [editor] = useState(() =>\n plugins.reduceRight(\n (editor, plugin) => plugin?.withPlugin?.(editor) ?? editor,\n withLocalChanges(withBuilder(withReact(createEditor()))),\n ),\n )\n\n useEffect(() => {\n if (control == null) return\n\n const element = ReactEditor.toDOMNode(editor, editor)\n return pollBoxModel({\n element,\n onBoxModelChange: boxModel => control.changeBoxModel(boxModel),\n })\n }, [editor, control])\n\n // ------ Preserving selection ------\n\n const isPreservingFocus = useRef(false)\n useSyncDOMSelection(editor, isPreservingFocus)\n const editMode = useBuilderEditMode()\n\n useEffect(() => {\n /**\n * This is required because clicking on the overlay has `relatedTarget` null just like the sidebar, but\n * - in the case of the overlay we switch to BUILD mode\n * - in the case of the sidebar we preserve the selection\n */\n if (editMode !== BuilderEditMode.CONTENT) {\n isPreservingFocus.current = false\n ReactEditor.deselect(editor)\n }\n }, [editMode])\n\n // ------ Syncing remote changes ------\n\n useSyncRemoteChanges(editor, text)\n\n // ------ Default value ------\n\n const presetValue = usePresetValue(definition)\n\n const initialValue = useMemo(\n () => (text && RichText.dataToNodes(text)) ?? presetValue,\n [text, presetValue],\n )\n\n useEffect(() => {\n control?.setEditor(editor)\n control?.setDefaultValue(defaultValue)\n }, [control, editor])\n\n /**\n * When initialValue is set to the default value we need to trigger an local change so that the sidebar updates and so the data is saved\n */\n useEffect(() => {\n if (initialValue === presetValue) {\n control?.onLocalUserChange()\n }\n }, [control, initialValue, presetValue])\n\n // ------ Rendering ------\n\n const renderElement = useCallback(\n (props: RenderElementProps) => {\n return <RichTextV2Element {...props} definition={definition} plugins={plugins} />\n },\n [plugins, definition],\n )\n\n const renderLeaf = useCallback(\n (props: RenderLeafProps) => {\n return <RichTextV2Leaf {...props} definition={definition} plugins={plugins} />\n },\n [plugins, definition],\n )\n\n // ------ Event handlers ------\n\n const handleFocus = useCallback(() => {\n isPreservingFocus.current = true\n control?.select()\n }, [control])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isHotkey('mod+shift+z', e)) return control?.redo()\n if (isHotkey('mod+z', e)) return control?.undo()\n if (isHotkey('escape')(e)) {\n isPreservingFocus.current = false\n ReactEditor.blur(editor)\n control?.switchToBuildMode()\n }\n\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n }\n\n plugins.forEach(plugin => plugin?.onKeyDown?.(e, editor))\n },\n [control, plugins, editor, editMode],\n )\n\n const handleKeyUp = useCallback(\n (e: KeyboardEvent) => {\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n e.preventDefault()\n }\n },\n [control, editor, editMode],\n )\n\n const handleClick = useCallback(\n (e: MouseEvent) => {\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n e.preventDefault()\n }\n },\n [editMode],\n )\n\n const handleBlur = useCallback((e: FocusEvent) => {\n // outside of iframe (overlay, sidebar, etc)\n if (e.relatedTarget == null) return\n // another text\n if (e.relatedTarget?.getAttribute('contenteditable') === 'true')\n isPreservingFocus.current = false\n }, [])\n\n const slateReset = useSlateReset()\n\n return (\n <Slate editor={editor} value={initialValue}>\n <Editable\n className={slateReset}\n renderLeaf={renderLeaf}\n renderElement={renderElement}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n onClick={handleClick}\n onBlur={handleBlur}\n readOnly={editMode !== BuilderEditMode.CONTENT}\n placeholder=\"Write some text...\"\n />\n </Slate>\n )\n}\n\nexport default EditableTextV2\n"],"mappings":"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","names":["import_slate","editor","isHotkey"]}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var use_slate_reset_exports = {};
20
+ __export(use_slate_reset_exports, {
21
+ useSlateReset: () => useSlateReset
22
+ });
23
+ module.exports = __toCommonJS(use_slate_reset_exports);
24
+ var import_use_style = require("../use-style");
25
+ function useSlateReset() {
26
+ return (0, import_use_style.useStyle)({
27
+ // @ts-expect-error: csstype's `all` doesn't accept `!important` annotations
28
+ "& [data-slate-string], & [data-slate-zero-width]": {
29
+ all: "revert !important"
30
+ }
31
+ });
32
+ }
33
+ // Annotate the CommonJS export names for ESM import in node:
34
+ 0 && (module.exports = {
35
+ useSlateReset
36
+ });
37
+ //# sourceMappingURL=use-slate-reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/runtimes/react/controls/use-slate-reset.ts"],"sourcesContent":["import { useStyle } from '../use-style'\n\n/**\n * `slate-react` renders read-only rich-text within a `<p>` tag containing\n * multiple spans. Makeswift text-styles are applied to these spans via a class\n * on the span tags directly:\n *\n * <p class=\"...\">\n * <span class=\"mswft-12345\">My text</span>\n * </p>\n *\n * HOWEVER: in the builder, `slate-react` renders the same content as editable\n * text with additional DOM structure; namely, intermediate nested spans (with\n * data attributes like `data-slate-string`, `data-slate-zero-width`) between\n * the `<span>` that carries Makeswift's typography class and the text content:\n *\n * <p data-slate-node=\"element\" class=\"...\">\n * <span data-slate-node=\"text\">\n * <span class=\"mswft-12345\" data-slate-leaf=\"true\">\n * <span data-slate-string=\"true\">My text</span>\n * </span>\n * </span>\n * </p>\n *\n * If the host contains CSS that matches spans directly (ex: a global `span {\n * color: ... }` rule), the host CSS applies to the innermost spans and beats\n * the Makeswift text styles in terms of specificity. Therefore, setting text\n * styles won't work in the builder: the top-level host styles will win. On the\n * live page, the Makeswift styles win since the intermediate DOM elements are\n * not present.\n *\n * These style updates address this by reverting base styles on these spans,\n * restoring inheritance from Makeswift defined styles, thus matching the live\n * page where the text is a direct child of the classed leaf span.\n */\nexport function useSlateReset(): string {\n return useStyle({\n // @ts-expect-error: csstype's `all` doesn't accept `!important` annotations\n '& [data-slate-string], & [data-slate-zero-width]': {\n all: 'revert !important',\n },\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAyB;AAmClB,SAAS,gBAAwB;AACtC,aAAO,2BAAS;AAAA;AAAA,IAEd,oDAAoD;AAAA,MAClD,KAAK;AAAA,IACP;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var use_element_data_exports = {};
21
+ __export(use_element_data_exports, {
22
+ useElementData: () => useElementData
23
+ });
24
+ module.exports = __toCommonJS(use_element_data_exports);
25
+ var import_read_only_state = require("../../../state/read-only-state");
26
+ var import_use_element = require("./use-element");
27
+ const useElementData = ({ elementKey }) => {
28
+ const element = (0, import_use_element.useElement)({ elementKey });
29
+ return element && !(0, import_read_only_state.isElementReference)(element) ? element : null;
30
+ };
31
+ // Annotate the CommonJS export names for ESM import in node:
32
+ 0 && (module.exports = {
33
+ useElementData
34
+ });
35
+ //# sourceMappingURL=use-element-data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/runtimes/react/hooks/use-element-data.tsx"],"sourcesContent":["'use client'\n\nimport { type ElementData, isElementReference } from '../../../state/read-only-state'\n\nimport { useElement } from './use-element'\n\nexport const useElementData = ({ elementKey }: { elementKey: string }): ElementData | null => {\n const element = useElement({ elementKey })\n return element && !isElementReference(element) ? element : null\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,6BAAqD;AAErD,yBAA2B;AAEpB,MAAM,iBAAiB,CAAC,EAAE,WAAW,MAAkD;AAC5F,QAAM,cAAU,+BAAW,EAAE,WAAW,CAAC;AACzC,SAAO,WAAW,KAAC,2CAAmB,OAAO,IAAI,UAAU;AAC7D;","names":[]}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var use_element_exports = {};
21
+ __export(use_element_exports, {
22
+ useElement: () => useElement
23
+ });
24
+ module.exports = __toCommonJS(use_element_exports);
25
+ var import_read_only_state = require("../../../state/read-only-state");
26
+ var import_use_selector = require("./use-selector");
27
+ var import_use_document_context = require("./use-document-context");
28
+ const useElement = ({ elementKey }) => {
29
+ const documentKey = (0, import_use_document_context.useDocumentKey)();
30
+ return (0, import_use_selector.useSelector)((state) => {
31
+ if (documentKey == null)
32
+ return null;
33
+ return (0, import_read_only_state.getElement)(state, documentKey, elementKey);
34
+ });
35
+ };
36
+ // Annotate the CommonJS export names for ESM import in node:
37
+ 0 && (module.exports = {
38
+ useElement
39
+ });
40
+ //# sourceMappingURL=use-element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/runtimes/react/hooks/use-element.tsx"],"sourcesContent":["'use client'\n\nimport { type Element, getElement } from '../../../state/read-only-state'\n\nimport { useSelector } from './use-selector'\nimport { useDocumentKey } from './use-document-context'\n\nexport const useElement = ({ elementKey }: { elementKey: string }): Element | null => {\n const documentKey = useDocumentKey()\n\n return useSelector(state => {\n if (documentKey == null) return null\n\n return getElement(state, documentKey, elementKey)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,6BAAyC;AAEzC,0BAA4B;AAC5B,kCAA+B;AAExB,MAAM,aAAa,CAAC,EAAE,WAAW,MAA8C;AACpF,QAAM,kBAAc,4CAAe;AAEnC,aAAO,iCAAY,WAAS;AAC1B,QAAI,eAAe;AAAM,aAAO;AAEhC,eAAO,mCAAW,OAAO,aAAa,UAAU;AAAA,EAClD,CAAC;AACH;","names":[]}
@@ -9,7 +9,7 @@ class MakeswiftGraphQLApiClient {
9
9
  graphqlClient;
10
10
  constructor({ endpoint }) {
11
11
  this.graphqlClient = new GraphQLClient(endpoint, {
12
- "makeswift-runtime-version": "0.28.9"
12
+ "makeswift-runtime-version": "0.28.10-canary.0"
13
13
  });
14
14
  }
15
15
  async createTableRecord(tableId, columns) {
@@ -137,7 +137,7 @@ class MakeswiftRestAPIClient {
137
137
  const requestHeaders = new Headers({
138
138
  "x-api-key": this.apiKey,
139
139
  "makeswift-site-api-key": this.apiKey,
140
- "makeswift-runtime-version": "0.28.9"
140
+ "makeswift-runtime-version": "0.28.10-canary.0"
141
141
  });
142
142
  if (siteVersion?.token) {
143
143
  requestUrl.searchParams.set("version", siteVersion.version);
@@ -8,7 +8,7 @@ async function manifestHandler(req, { apiKey, manifest }) {
8
8
  return ApiResponse.json({ message: "Unauthorized" }, { status: 401 });
9
9
  }
10
10
  return ApiResponse.json({
11
- version: "0.28.9",
11
+ version: "0.28.10-canary.0",
12
12
  interactionMode: true,
13
13
  clientSideNavigation: false,
14
14
  elementFromPoint: false,
@@ -44,6 +44,22 @@ async function serverSideRender(children) {
44
44
  );
45
45
  return dom.window.document;
46
46
  }
47
+ function stubBuilderMessageChannel() {
48
+ const postMessageSpy = jest.spyOn(window, "postMessage").mockImplementation(() => {
49
+ });
50
+ const originalMessageChannel = window.MessageChannel;
51
+ const stubPort = () => ({ onmessage: null, postMessage: () => {
52
+ }, close: () => {
53
+ } });
54
+ window.MessageChannel = class {
55
+ port1 = stubPort();
56
+ port2 = stubPort();
57
+ };
58
+ return () => {
59
+ postMessageSpy.mockRestore();
60
+ window.MessageChannel = originalMessageChannel;
61
+ };
62
+ }
47
63
  async function testPageControlPropRendering(controlDefinition, {
48
64
  toData,
49
65
  value,
@@ -53,7 +69,8 @@ async function testPageControlPropRendering(controlDefinition, {
53
69
  registerComponents,
54
70
  action,
55
71
  rootElements = [],
56
- isInBuilder = false
72
+ isInBuilder = false,
73
+ isReadOnly = true
57
74
  }) {
58
75
  const controlData = value !== void 0 ? toData ? toData(value) : controlDefinition.toData(value) : void 0;
59
76
  const testComponentMeta = {
@@ -88,8 +105,12 @@ async function testPageControlPropRendering(controlDefinition, {
88
105
  }
89
106
  }
90
107
  );
91
- const testElementTree = (component) => /* @__PURE__ */ jsx(Testing.ReactProvider, { runtime, children: component });
108
+ const testElementTree = (component) => {
109
+ const siteVersion = isReadOnly ? null : { token: "test-token", version: "draft" };
110
+ return /* @__PURE__ */ jsx(Testing.ReactProvider, { runtime, siteVersion, children: component });
111
+ };
92
112
  if (!isServer()) {
113
+ const restoreMessageChannel = isReadOnly ? null : stubBuilderMessageChannel();
93
114
  const rootElementData = Testing.createRootComponent(
94
115
  [elementData, ...rootElements],
95
116
  ROOT_ID
@@ -106,6 +127,7 @@ async function testPageControlPropRendering(controlDefinition, {
106
127
  if (expectedRenders != null) {
107
128
  expect(Number(screen.getByTestId(renderCountTestId).textContent)).toBe(expectedRenders);
108
129
  }
130
+ restoreMessageChannel?.();
109
131
  } else {
110
132
  console.assert(action == null);
111
133
  console.assert(rootElements.length === 0);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/next/components/tests/controls/page-control-prop-rendering.tsx"],"sourcesContent":["import { type ReactNode, Fragment, forwardRef, useRef, isValidElement, act } from 'react'\nimport { renderToReadableStream } from 'react-dom/server'\nimport { JSDOM } from 'jsdom'\nimport { render, screen } from '@testing-library/react'\nimport '@testing-library/jest-dom'\nimport { ServerInsertedHTMLContext } from 'next/navigation'\n\nimport { type Data, type ValueType, type DataType, ControlDefinition } from '@makeswift/controls'\n\nimport { type CacheData } from '../../../../api/api-resources-client'\nimport { ElementData } from '../../../../state/read-only-state'\nimport { setIsInBuilder } from '../../../../state/actions/internal/read-only-actions'\nimport { ReactRuntime } from '../../../../runtimes/react/react-runtime'\nimport { MakeswiftComponent } from '../../../../runtimes/react/components/MakeswiftComponent'\nimport { Page } from '../../page'\nimport { isServer } from '../../../../utils/is-server'\nimport * as Testing from '../../../testing'\n\nconst ROOT_ID = '00000000-0000-0000-0000-000000000000'\nconst ELEMENT_ID = '11111111-1111-1111-1111-111111111111'\n\nconst renderProp = (prop: any) =>\n prop === undefined ? 'undefined' : isValidElement(prop) ? prop : JSON.stringify(prop)\n\nconst propSnapshot = (prop: HTMLElement | null) =>\n prop?.childElementCount ? prop.childNodes : parseStringifiedProp(prop?.textContent ?? '')\n\nconst parseStringifiedProp = (prop: string) => (prop === 'undefined' ? undefined : JSON.parse(prop))\n\nasync function streamToString(stream: ReadableStream) {\n const reader = stream.getReader()\n const decoder = new TextDecoder()\n\n let result = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n result += decoder.decode(value, { stream: true })\n }\n\n return result\n}\n\nasync function renderToString(element: ReactNode) {\n return await streamToString(await renderToReadableStream(element))\n}\n\nasync function serverSideRender(children: ReactNode) {\n // wrap the children in a context provider to capture server-inserted HTML, see\n // https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/server-inserted-html.tsx\n const serverInsertedCallbacks: (() => React.ReactNode)[] = []\n\n const elementTree = (\n <ServerInsertedHTMLContext.Provider value={handler => serverInsertedCallbacks.push(handler)}>\n {children}\n </ServerInsertedHTMLContext.Provider>\n )\n\n const elementsHTML = await renderToString(elementTree)\n\n const serverInsertedNodes = serverInsertedCallbacks.map((callback, index) => (\n <Fragment key={'__next_server_inserted__' + index}>{callback()}</Fragment>\n ))\n\n const headHTML = await renderToString(serverInsertedNodes)\n\n const dom = new JSDOM(\n `<!DOCTYPE html><head>${headHTML}</head><body><div id=\"root\">${elementsHTML}</div></body></div>`,\n {\n runScripts: 'dangerously',\n },\n )\n\n return dom.window.document\n}\n\nexport async function testPageControlPropRendering<D extends ControlDefinition>(\n controlDefinition: D,\n {\n toData,\n value,\n locale,\n cacheData,\n expectedRenders,\n registerComponents,\n action,\n rootElements = [],\n isInBuilder = false,\n }: {\n toData?: (value: ValueType<D>) => DataType<D>\n value: ValueType<D> | undefined\n locale?: string | null\n cacheData?: Partial<CacheData>\n expectedRenders?: number\n registerComponents?: (runtime: ReactRuntime) => void\n action?: (element: HTMLElement) => Promise<void>\n rootElements?: ElementData[]\n isInBuilder?: boolean\n },\n) {\n // Arrange\n const controlData: DataType<D> | Data =\n value !== undefined ? (toData ? toData(value) : controlDefinition.toData(value)) : undefined\n\n const testComponentMeta = {\n type: 'TestComponent',\n label: 'Test Component',\n }\n\n const testId = 'test-id'\n const renderCountTestId = 'render-count-test-id'\n const elementData: ElementData = {\n key: ELEMENT_ID,\n type: testComponentMeta.type,\n props: {\n propKey: controlData,\n },\n }\n\n const runtime = Testing.createReactRuntime()\n runtime.protoStore.dispatch(setIsInBuilder(isInBuilder))\n registerComponents?.(runtime)\n\n // Act\n runtime.registerComponent(\n forwardRef<HTMLDivElement, { propKey?: any }>(({ propKey }, ref) => {\n const renderCount = useRef(0)\n ++renderCount.current\n\n return (\n <div ref={ref}>\n <div data-testid={renderCountTestId}>{renderCount.current}</div>\n <div data-testid={testId}>{renderProp(propKey)}</div>\n </div>\n )\n }),\n {\n ...testComponentMeta,\n props: {\n propKey: controlDefinition as any,\n },\n },\n )\n\n const testElementTree = (component: ReactNode) => (\n <Testing.ReactProvider runtime={runtime}>{component}</Testing.ReactProvider>\n )\n\n if (!isServer()) {\n const rootElementData: ElementData = Testing.createRootComponent(\n [elementData, ...rootElements],\n ROOT_ID,\n )\n\n const snapshot = Testing.createMakeswiftPageSnapshot(rootElementData, { locale, cacheData })\n\n // Assert\n await act(async () => render(testElementTree(<Page snapshot={snapshot} />)))\n\n if (action) {\n await act(async () => {\n await action(screen.getByTestId(testId))\n })\n }\n\n expect(snapshot).toMatchSnapshot('snapshot')\n expect(propSnapshot(screen.getByTestId(testId))).toMatchSnapshot('resolvedValue')\n\n if (expectedRenders != null) {\n expect(Number(screen.getByTestId(renderCountTestId).textContent)).toBe(expectedRenders)\n }\n } else {\n // test server-side rendering using a component snapshot\n console.assert(action == null)\n console.assert(rootElements.length === 0)\n\n const snapshot = Testing.createMakeswiftComponentSnapshot(elementData, { locale, cacheData })\n const elementTree = testElementTree(\n <MakeswiftComponent snapshot={snapshot} {...testComponentMeta} />,\n )\n\n const document = await serverSideRender(elementTree)\n const getByTestId = (id: string): HTMLElement | null =>\n document.querySelector(`[data-testid=\"${id}\"]`)\n\n expect(propSnapshot(getByTestId(testId))).toMatchSnapshot('resolvedValue')\n expect([...document.querySelectorAll('style')].map(n => n.textContent)).toMatchSnapshot(\n 'component styles',\n )\n expect(Number(getByTestId(renderCountTestId)?.textContent)).toBe(1)\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../../src/next/components/tests/controls/page-control-prop-rendering.tsx"],"sourcesContent":["import { type ReactNode, Fragment, forwardRef, useRef, isValidElement, act } from 'react'\nimport { renderToReadableStream } from 'react-dom/server'\nimport { JSDOM } from 'jsdom'\nimport { render, screen } from '@testing-library/react'\nimport '@testing-library/jest-dom'\nimport { ServerInsertedHTMLContext } from 'next/navigation'\n\nimport { type Data, type ValueType, type DataType, ControlDefinition } from '@makeswift/controls'\n\nimport { type CacheData } from '../../../../api/api-resources-client'\nimport { ElementData } from '../../../../state/read-only-state'\nimport { setIsInBuilder } from '../../../../state/actions/internal/read-only-actions'\nimport { ReactRuntime } from '../../../../runtimes/react/react-runtime'\nimport { MakeswiftComponent } from '../../../../runtimes/react/components/MakeswiftComponent'\nimport { Page } from '../../page'\nimport { isServer } from '../../../../utils/is-server'\nimport * as Testing from '../../../testing'\n\nconst ROOT_ID = '00000000-0000-0000-0000-000000000000'\nconst ELEMENT_ID = '11111111-1111-1111-1111-111111111111'\n\nconst renderProp = (prop: any) =>\n prop === undefined ? 'undefined' : isValidElement(prop) ? prop : JSON.stringify(prop)\n\nconst propSnapshot = (prop: HTMLElement | null) =>\n prop?.childElementCount ? prop.childNodes : parseStringifiedProp(prop?.textContent ?? '')\n\nconst parseStringifiedProp = (prop: string) => (prop === 'undefined' ? undefined : JSON.parse(prop))\n\nasync function streamToString(stream: ReadableStream) {\n const reader = stream.getReader()\n const decoder = new TextDecoder()\n\n let result = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n result += decoder.decode(value, { stream: true })\n }\n\n return result\n}\n\nasync function renderToString(element: ReactNode) {\n return await streamToString(await renderToReadableStream(element))\n}\n\nasync function serverSideRender(children: ReactNode) {\n // wrap the children in a context provider to capture server-inserted HTML, see\n // https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/server-inserted-html.tsx\n const serverInsertedCallbacks: (() => React.ReactNode)[] = []\n\n const elementTree = (\n <ServerInsertedHTMLContext.Provider value={handler => serverInsertedCallbacks.push(handler)}>\n {children}\n </ServerInsertedHTMLContext.Provider>\n )\n\n const elementsHTML = await renderToString(elementTree)\n\n const serverInsertedNodes = serverInsertedCallbacks.map((callback, index) => (\n <Fragment key={'__next_server_inserted__' + index}>{callback()}</Fragment>\n ))\n\n const headHTML = await renderToString(serverInsertedNodes)\n\n const dom = new JSDOM(\n `<!DOCTYPE html><head>${headHTML}</head><body><div id=\"root\">${elementsHTML}</div></body></div>`,\n {\n runScripts: 'dangerously',\n },\n )\n\n return dom.window.document\n}\n\n/**\n * In read-write mode, the runtime opens a `MessageChannel` to the builder\n * parent frame; jsdom doesn't implement `MessageChannel`, so stub them to keep\n * the read-write setup from throwing.\n */\nfunction stubBuilderMessageChannel(): () => void {\n const postMessageSpy = jest.spyOn(window, 'postMessage').mockImplementation(() => {})\n\n const originalMessageChannel = window.MessageChannel\n const stubPort = () => ({ onmessage: null, postMessage: () => {}, close: () => {} })\n window.MessageChannel = class {\n port1 = stubPort()\n port2 = stubPort()\n } as unknown as typeof MessageChannel\n\n return () => {\n postMessageSpy.mockRestore()\n window.MessageChannel = originalMessageChannel\n }\n}\n\nexport async function testPageControlPropRendering<D extends ControlDefinition>(\n controlDefinition: D,\n {\n toData,\n value,\n locale,\n cacheData,\n expectedRenders,\n registerComponents,\n action,\n rootElements = [],\n isInBuilder = false,\n isReadOnly = true,\n }: {\n toData?: (value: ValueType<D>) => DataType<D>\n value: ValueType<D> | undefined\n locale?: string | null\n cacheData?: Partial<CacheData>\n expectedRenders?: number\n registerComponents?: (runtime: ReactRuntime) => void\n action?: (element: HTMLElement) => Promise<void>\n rootElements?: ElementData[]\n isInBuilder?: boolean\n isReadOnly?: boolean\n },\n) {\n // Arrange\n const controlData: DataType<D> | Data =\n value !== undefined ? (toData ? toData(value) : controlDefinition.toData(value)) : undefined\n\n const testComponentMeta = {\n type: 'TestComponent',\n label: 'Test Component',\n }\n\n const testId = 'test-id'\n const renderCountTestId = 'render-count-test-id'\n const elementData: ElementData = {\n key: ELEMENT_ID,\n type: testComponentMeta.type,\n props: {\n propKey: controlData,\n },\n }\n\n const runtime = Testing.createReactRuntime()\n runtime.protoStore.dispatch(setIsInBuilder(isInBuilder))\n registerComponents?.(runtime)\n\n // Act\n runtime.registerComponent(\n forwardRef<HTMLDivElement, { propKey?: any }>(({ propKey }, ref) => {\n const renderCount = useRef(0)\n ++renderCount.current\n\n return (\n <div ref={ref}>\n <div data-testid={renderCountTestId}>{renderCount.current}</div>\n <div data-testid={testId}>{renderProp(propKey)}</div>\n </div>\n )\n }),\n {\n ...testComponentMeta,\n props: {\n propKey: controlDefinition as any,\n },\n },\n )\n\n const testElementTree = (component: ReactNode) => {\n // The runtime enters the read-write state when a non-null site version is\n // passed\n const siteVersion = isReadOnly ? null : { token: 'test-token', version: 'draft' }\n return (\n <Testing.ReactProvider runtime={runtime} siteVersion={siteVersion}>\n {component}\n </Testing.ReactProvider>\n )\n }\n\n if (!isServer()) {\n const restoreMessageChannel = isReadOnly ? null : stubBuilderMessageChannel()\n\n const rootElementData: ElementData = Testing.createRootComponent(\n [elementData, ...rootElements],\n ROOT_ID,\n )\n\n const snapshot = Testing.createMakeswiftPageSnapshot(rootElementData, { locale, cacheData })\n\n // Assert\n await act(async () => render(testElementTree(<Page snapshot={snapshot} />)))\n\n if (action) {\n await act(async () => {\n await action(screen.getByTestId(testId))\n })\n }\n\n expect(snapshot).toMatchSnapshot('snapshot')\n expect(propSnapshot(screen.getByTestId(testId))).toMatchSnapshot('resolvedValue')\n\n if (expectedRenders != null) {\n expect(Number(screen.getByTestId(renderCountTestId).textContent)).toBe(expectedRenders)\n }\n\n restoreMessageChannel?.()\n } else {\n // test server-side rendering using a component snapshot\n console.assert(action == null)\n console.assert(rootElements.length === 0)\n\n const snapshot = Testing.createMakeswiftComponentSnapshot(elementData, { locale, cacheData })\n const elementTree = testElementTree(\n <MakeswiftComponent snapshot={snapshot} {...testComponentMeta} />,\n )\n\n const document = await serverSideRender(elementTree)\n const getByTestId = (id: string): HTMLElement | null =>\n document.querySelector(`[data-testid=\"${id}\"]`)\n\n expect(propSnapshot(getByTestId(testId))).toMatchSnapshot('resolvedValue')\n expect([...document.querySelectorAll('style')].map(n => n.textContent)).toMatchSnapshot(\n 'component styles',\n )\n expect(Number(getByTestId(renderCountTestId)?.textContent)).toBe(1)\n }\n}\n"],"mappings":"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","names":[]}
@@ -15,6 +15,7 @@ import { createEditor } from "slate";
15
15
  import { Slate as SlateReact, Editable, withReact, ReactEditor } from "slate-react";
16
16
  import { Slate, richTextDTOtoDAO } from "@makeswift/controls";
17
17
  import { useBuilderEditMode } from "../../..";
18
+ import { useSlateReset } from "../../use-slate-reset";
18
19
  import { withBlock, withTypography, withBuilder, onKeyDown } from "../../../../../slate";
19
20
  import { BuilderEditMode } from "../../../../../state/modules/builder-edit-mode";
20
21
  import { pollBoxModel } from "../../../poll-box-model";
@@ -74,6 +75,7 @@ const EditableText = forwardRef(function EditableText2({ id, text, width, margin
74
75
  },
75
76
  [controller, editor]
76
77
  );
78
+ const slateReset = useSlateReset();
77
79
  const handleBlur = useCallback((e) => {
78
80
  if (e.relatedTarget == null)
79
81
  return;
@@ -89,7 +91,7 @@ const EditableText = forwardRef(function EditableText2({ id, text, width, margin
89
91
  onFocus: handleFocus,
90
92
  onKeyDown: handleKeyDown,
91
93
  onBlur: handleBlur,
92
- className: cx(width, margin),
94
+ className: cx(slateReset, width, margin),
93
95
  readOnly: editMode !== BuilderEditMode.CONTENT,
94
96
  placeholder: "Write some text..."
95
97
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/runtimes/react/controls/rich-text/EditableText/editable-text.tsx"],"sourcesContent":["'use client'\n\nimport { cx } from '@emotion/css'\nimport { getBox } from 'css-box-model'\nimport isHotkey from 'is-hotkey'\nimport {\n FocusEvent,\n forwardRef,\n KeyboardEvent,\n Ref,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\n\nimport { createEditor } from 'slate'\nimport { Slate as SlateReact, Editable, withReact, ReactEditor } from 'slate-react'\n\nimport { Slate, richTextDTOtoDAO, type RichTextValue } from '@makeswift/controls'\n\nimport { useBuilderEditMode } from '../../..'\nimport { DescriptorsPropControllers } from '../../../../../prop-controllers/instances'\nimport { withBlock, withTypography, withBuilder, onKeyDown } from '../../../../../slate'\nimport { BuilderEditMode } from '../../../../../state/modules/builder-edit-mode'\nimport { PropControllersHandle } from '../../../../../state/modules/read-write/prop-controllers'\nimport { pollBoxModel } from '../../../poll-box-model'\nimport { Element, Leaf } from '../components'\nimport { Descriptors } from '../rich-text'\nimport { useSyncDOMSelection } from './useSyncDOMSelection'\nimport { useSyncWithBuilder } from './useSyncWithBuilder'\n\ntype Props = {\n id?: string\n text?: RichTextValue\n width?: string\n margin?: string\n}\n\nconst defaultText: Slate.RichTextDAO = [\n { type: Slate.BlockType.Paragraph, children: [{ text: '' }] },\n]\n\nexport const EditableText = forwardRef(function EditableText(\n { id, text, width, margin }: Props,\n ref: Ref<PropControllersHandle<Descriptors>>,\n) {\n const [editor] = useState(() => withBlock(withTypography(withBuilder(withReact(createEditor())))))\n const [isPreservingDOMSElection, setIsPreservingDOMSelection] = useState(false)\n useSyncDOMSelection(editor, isPreservingDOMSElection)\n const delaySync = useSyncWithBuilder(editor, text)\n const editMode = useBuilderEditMode()\n\n const [propControllers, setPropControllers] =\n useState<DescriptorsPropControllers<Descriptors> | null>(null)\n const controller = propControllers?.text\n\n useEffect(() => {\n if (controller == null) return\n\n const element = ReactEditor.toDOMNode(editor, editor)\n\n return pollBoxModel({\n element,\n onBoxModelChange: boxModel => controller.changeBoxModel(boxModel),\n })\n }, [editor, controller])\n\n useImperativeHandle(\n ref,\n () => ({\n getDomNode() {\n return ReactEditor.toDOMNode(editor, editor)\n },\n getBoxModel() {\n return getBox(ReactEditor.toDOMNode(editor, editor))\n },\n setPropControllers,\n }),\n [editor, setPropControllers],\n )\n\n const initialValue = useMemo(() => (text ? richTextDTOtoDAO(text) : defaultText), [text])\n\n useEffect(() => {\n controller?.setSlateEditor(editor)\n }, [controller, editor])\n\n const handleFocus = useCallback(() => {\n controller?.focus()\n setIsPreservingDOMSelection(true)\n }, [controller])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isHotkey('mod+shift+z', e)) return controller?.redo()\n if (isHotkey('mod+z', e)) return controller?.undo()\n if (isHotkey('escape')(e)) return controller?.blur()\n onKeyDown(e, editor)\n },\n [controller, editor],\n )\n\n const handleBlur = useCallback((e: FocusEvent) => {\n // When clicking outside of the iframe (`relatedTarget` is null) we want to preserve the DOM selection.\n if (e.relatedTarget == null) return\n // Otherwise we want to deselect on blur and stop preserving selection.\n setIsPreservingDOMSelection(false)\n ReactEditor.deselect(editor)\n }, [])\n\n return (\n <SlateReact editor={editor} value={initialValue} onChange={delaySync}>\n <Editable\n id={id}\n renderLeaf={Leaf}\n renderElement={Element}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n className={cx(width, margin)}\n readOnly={editMode !== BuilderEditMode.CONTENT}\n placeholder=\"Write some text...\"\n />\n </SlateReact>\n )\n})\n\nexport default EditableText\n"],"mappings":"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","names":["EditableText"]}
1
+ {"version":3,"sources":["../../../../../../../src/runtimes/react/controls/rich-text/EditableText/editable-text.tsx"],"sourcesContent":["'use client'\n\nimport { cx } from '@emotion/css'\nimport { getBox } from 'css-box-model'\nimport isHotkey from 'is-hotkey'\nimport {\n FocusEvent,\n forwardRef,\n KeyboardEvent,\n Ref,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react'\n\nimport { createEditor } from 'slate'\nimport { Slate as SlateReact, Editable, withReact, ReactEditor } from 'slate-react'\n\nimport { Slate, richTextDTOtoDAO, type RichTextValue } from '@makeswift/controls'\n\nimport { useBuilderEditMode } from '../../..'\nimport { useSlateReset } from '../../use-slate-reset'\nimport { DescriptorsPropControllers } from '../../../../../prop-controllers/instances'\nimport { withBlock, withTypography, withBuilder, onKeyDown } from '../../../../../slate'\nimport { BuilderEditMode } from '../../../../../state/modules/builder-edit-mode'\nimport { PropControllersHandle } from '../../../../../state/modules/read-write/prop-controllers'\nimport { pollBoxModel } from '../../../poll-box-model'\nimport { Element, Leaf } from '../components'\nimport { Descriptors } from '../rich-text'\nimport { useSyncDOMSelection } from './useSyncDOMSelection'\nimport { useSyncWithBuilder } from './useSyncWithBuilder'\n\ntype Props = {\n id?: string\n text?: RichTextValue\n width?: string\n margin?: string\n}\n\nconst defaultText: Slate.RichTextDAO = [\n { type: Slate.BlockType.Paragraph, children: [{ text: '' }] },\n]\n\nexport const EditableText = forwardRef(function EditableText(\n { id, text, width, margin }: Props,\n ref: Ref<PropControllersHandle<Descriptors>>,\n) {\n const [editor] = useState(() => withBlock(withTypography(withBuilder(withReact(createEditor())))))\n const [isPreservingDOMSElection, setIsPreservingDOMSelection] = useState(false)\n useSyncDOMSelection(editor, isPreservingDOMSElection)\n const delaySync = useSyncWithBuilder(editor, text)\n const editMode = useBuilderEditMode()\n\n const [propControllers, setPropControllers] =\n useState<DescriptorsPropControllers<Descriptors> | null>(null)\n const controller = propControllers?.text\n\n useEffect(() => {\n if (controller == null) return\n\n const element = ReactEditor.toDOMNode(editor, editor)\n\n return pollBoxModel({\n element,\n onBoxModelChange: boxModel => controller.changeBoxModel(boxModel),\n })\n }, [editor, controller])\n\n useImperativeHandle(\n ref,\n () => ({\n getDomNode() {\n return ReactEditor.toDOMNode(editor, editor)\n },\n getBoxModel() {\n return getBox(ReactEditor.toDOMNode(editor, editor))\n },\n setPropControllers,\n }),\n [editor, setPropControllers],\n )\n\n const initialValue = useMemo(() => (text ? richTextDTOtoDAO(text) : defaultText), [text])\n\n useEffect(() => {\n controller?.setSlateEditor(editor)\n }, [controller, editor])\n\n const handleFocus = useCallback(() => {\n controller?.focus()\n setIsPreservingDOMSelection(true)\n }, [controller])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isHotkey('mod+shift+z', e)) return controller?.redo()\n if (isHotkey('mod+z', e)) return controller?.undo()\n if (isHotkey('escape')(e)) return controller?.blur()\n onKeyDown(e, editor)\n },\n [controller, editor],\n )\n\n const slateReset = useSlateReset()\n\n const handleBlur = useCallback((e: FocusEvent) => {\n // When clicking outside of the iframe (`relatedTarget` is null) we want to preserve the DOM selection.\n if (e.relatedTarget == null) return\n // Otherwise we want to deselect on blur and stop preserving selection.\n setIsPreservingDOMSelection(false)\n ReactEditor.deselect(editor)\n }, [])\n\n return (\n <SlateReact editor={editor} value={initialValue} onChange={delaySync}>\n <Editable\n id={id}\n renderLeaf={Leaf}\n renderElement={Element}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n className={cx(slateReset, width, margin)}\n readOnly={editMode !== BuilderEditMode.CONTENT}\n placeholder=\"Write some text...\"\n />\n </SlateReact>\n )\n})\n\nexport default EditableText\n"],"mappings":"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","names":["EditableText"]}
@@ -19,6 +19,7 @@ import {
19
19
  RichText
20
20
  } from "../../../../../controls/rich-text-v2";
21
21
  import { useBuilderEditMode } from "../../..";
22
+ import { useSlateReset } from "../../use-slate-reset";
22
23
  import { BuilderEditMode } from "../../../../../state/modules/builder-edit-mode";
23
24
  import { pollBoxModel } from "../../../poll-box-model";
24
25
  import { withBuilder, withLocalChanges } from "../../../../../slate";
@@ -126,9 +127,11 @@ function EditableTextV2({ text, definition, control }) {
126
127
  if (e.relatedTarget?.getAttribute("contenteditable") === "true")
127
128
  isPreservingFocus.current = false;
128
129
  }, []);
130
+ const slateReset = useSlateReset();
129
131
  return /* @__PURE__ */ jsx(Slate, { editor, value: initialValue, children: /* @__PURE__ */ jsx(
130
132
  Editable,
131
133
  {
134
+ className: slateReset,
132
135
  renderLeaf,
133
136
  renderElement,
134
137
  onFocus: handleFocus,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.tsx"],"sourcesContent":["'use client'\n\nimport {\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { createEditor } from 'slate'\nimport isHotkey from 'is-hotkey'\nimport {\n withReact,\n ReactEditor,\n RenderElementProps,\n RenderLeafProps,\n Slate,\n Editable,\n} from 'slate-react'\n\nimport {\n RichTextV2Definition,\n RichText,\n RichTextV2Control,\n type RichTextDataV2,\n} from '../../../../../controls/rich-text-v2'\n\nimport { useBuilderEditMode } from '../../..'\nimport { BuilderEditMode } from '../../../../../state/modules/builder-edit-mode'\nimport { pollBoxModel } from '../../../poll-box-model'\nimport { withBuilder, withLocalChanges } from '../../../../../slate'\nimport { useSyncDOMSelection } from './useSyncDOMSelection'\nimport { RichTextV2Element } from './render-element'\nimport { RichTextV2Leaf } from './render-leaf'\nimport { useSyncRemoteChanges } from './useRemoteChanges'\nimport { defaultValue, usePresetValue } from './usePresetValue'\n\nexport type RichTextV2ControlValue = ReactNode\n\nexport type Descriptors = { text?: RichTextV2Definition }\n\ntype Props = {\n text?: RichTextDataV2\n definition: RichTextV2Definition\n control: RichTextV2Control | null\n}\n\nexport function EditableTextV2({ text, definition, control }: Props) {\n const plugins = useMemo(() => definition.config.plugins, [definition])\n\n const [editor] = useState(() =>\n plugins.reduceRight(\n (editor, plugin) => plugin?.withPlugin?.(editor) ?? editor,\n withLocalChanges(withBuilder(withReact(createEditor()))),\n ),\n )\n\n useEffect(() => {\n if (control == null) return\n\n const element = ReactEditor.toDOMNode(editor, editor)\n return pollBoxModel({\n element,\n onBoxModelChange: boxModel => control.changeBoxModel(boxModel),\n })\n }, [editor, control])\n\n // ------ Preserving selection ------\n\n const isPreservingFocus = useRef(false)\n useSyncDOMSelection(editor, isPreservingFocus)\n const editMode = useBuilderEditMode()\n\n useEffect(() => {\n /**\n * This is required because clicking on the overlay has `relatedTarget` null just like the sidebar, but\n * - in the case of the overlay we switch to BUILD mode\n * - in the case of the sidebar we preserve the selection\n */\n if (editMode !== BuilderEditMode.CONTENT) {\n isPreservingFocus.current = false\n ReactEditor.deselect(editor)\n }\n }, [editMode])\n\n // ------ Syncing remote changes ------\n\n useSyncRemoteChanges(editor, text)\n\n // ------ Default value ------\n\n const presetValue = usePresetValue(definition)\n\n const initialValue = useMemo(\n () => (text && RichText.dataToNodes(text)) ?? presetValue,\n [text, presetValue],\n )\n\n useEffect(() => {\n control?.setEditor(editor)\n control?.setDefaultValue(defaultValue)\n }, [control, editor])\n\n /**\n * When initialValue is set to the default value we need to trigger an local change so that the sidebar updates and so the data is saved\n */\n useEffect(() => {\n if (initialValue === presetValue) {\n control?.onLocalUserChange()\n }\n }, [control, initialValue, presetValue])\n\n // ------ Rendering ------\n\n const renderElement = useCallback(\n (props: RenderElementProps) => {\n return <RichTextV2Element {...props} definition={definition} plugins={plugins} />\n },\n [plugins, definition],\n )\n\n const renderLeaf = useCallback(\n (props: RenderLeafProps) => {\n return <RichTextV2Leaf {...props} definition={definition} plugins={plugins} />\n },\n [plugins, definition],\n )\n\n // ------ Event handlers ------\n\n const handleFocus = useCallback(() => {\n isPreservingFocus.current = true\n control?.select()\n }, [control])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isHotkey('mod+shift+z', e)) return control?.redo()\n if (isHotkey('mod+z', e)) return control?.undo()\n if (isHotkey('escape')(e)) {\n isPreservingFocus.current = false\n ReactEditor.blur(editor)\n control?.switchToBuildMode()\n }\n\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n }\n\n plugins.forEach(plugin => plugin?.onKeyDown?.(e, editor))\n },\n [control, plugins, editor, editMode],\n )\n\n const handleKeyUp = useCallback(\n (e: KeyboardEvent) => {\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n e.preventDefault()\n }\n },\n [control, editor, editMode],\n )\n\n const handleClick = useCallback(\n (e: MouseEvent) => {\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n e.preventDefault()\n }\n },\n [editMode],\n )\n\n const handleBlur = useCallback((e: FocusEvent) => {\n // outside of iframe (overlay, sidebar, etc)\n if (e.relatedTarget == null) return\n // another text\n if (e.relatedTarget?.getAttribute('contenteditable') === 'true')\n isPreservingFocus.current = false\n }, [])\n\n return (\n <Slate editor={editor} value={initialValue}>\n <Editable\n renderLeaf={renderLeaf}\n renderElement={renderElement}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n onClick={handleClick}\n onBlur={handleBlur}\n readOnly={editMode !== BuilderEditMode.CONTENT}\n placeholder=\"Write some text...\"\n />\n </Slate>\n )\n}\n\nexport default EditableTextV2\n"],"mappings":";AAwHa;AAtHb;AAAA,EAKE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,OAAO,cAAc;AACrB;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,OACK;AAEP;AAAA,EAEE;AAAA,OAGK;AAEP,SAAS,0BAA0B;AACnC,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,aAAa,wBAAwB;AAC9C,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B,SAAS,4BAA4B;AACrC,SAAS,cAAc,sBAAsB;AAYtC,SAAS,eAAe,EAAE,MAAM,YAAY,QAAQ,GAAU;AACnE,QAAM,UAAU,QAAQ,MAAM,WAAW,OAAO,SAAS,CAAC,UAAU,CAAC;AAErE,QAAM,CAAC,MAAM,IAAI;AAAA,IAAS,MACxB,QAAQ;AAAA,MACN,CAACA,SAAQ,WAAW,QAAQ,aAAaA,OAAM,KAAKA;AAAA,MACpD,iBAAiB,YAAY,UAAU,aAAa,CAAC,CAAC,CAAC;AAAA,IACzD;AAAA,EACF;AAEA,YAAU,MAAM;AACd,QAAI,WAAW;AAAM;AAErB,UAAM,UAAU,YAAY,UAAU,QAAQ,MAAM;AACpD,WAAO,aAAa;AAAA,MAClB;AAAA,MACA,kBAAkB,cAAY,QAAQ,eAAe,QAAQ;AAAA,IAC/D,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,OAAO,CAAC;AAIpB,QAAM,oBAAoB,OAAO,KAAK;AACtC,sBAAoB,QAAQ,iBAAiB;AAC7C,QAAM,WAAW,mBAAmB;AAEpC,YAAU,MAAM;AAMd,QAAI,aAAa,gBAAgB,SAAS;AACxC,wBAAkB,UAAU;AAC5B,kBAAY,SAAS,MAAM;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAIb,uBAAqB,QAAQ,IAAI;AAIjC,QAAM,cAAc,eAAe,UAAU;AAE7C,QAAM,eAAe;AAAA,IACnB,OAAO,QAAQ,SAAS,YAAY,IAAI,MAAM;AAAA,IAC9C,CAAC,MAAM,WAAW;AAAA,EACpB;AAEA,YAAU,MAAM;AACd,aAAS,UAAU,MAAM;AACzB,aAAS,gBAAgB,YAAY;AAAA,EACvC,GAAG,CAAC,SAAS,MAAM,CAAC;AAKpB,YAAU,MAAM;AACd,QAAI,iBAAiB,aAAa;AAChC,eAAS,kBAAkB;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,SAAS,cAAc,WAAW,CAAC;AAIvC,QAAM,gBAAgB;AAAA,IACpB,CAAC,UAA8B;AAC7B,aAAO,oBAAC,qBAAmB,GAAG,OAAO,YAAwB,SAAkB;AAAA,IACjF;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,EACtB;AAEA,QAAM,aAAa;AAAA,IACjB,CAAC,UAA2B;AAC1B,aAAO,oBAAC,kBAAgB,GAAG,OAAO,YAAwB,SAAkB;AAAA,IAC9E;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,EACtB;AAIA,QAAM,cAAc,YAAY,MAAM;AACpC,sBAAkB,UAAU;AAC5B,aAAS,OAAO;AAAA,EAClB,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,gBAAgB;AAAA,IACpB,CAAC,MAAqB;AACpB,UAAI,SAAS,eAAe,CAAC;AAAG,eAAO,SAAS,KAAK;AACrD,UAAI,SAAS,SAAS,CAAC;AAAG,eAAO,SAAS,KAAK;AAC/C,UAAI,SAAS,QAAQ,EAAE,CAAC,GAAG;AACzB,0BAAkB,UAAU;AAC5B,oBAAY,KAAK,MAAM;AACvB,iBAAS,kBAAkB;AAAA,MAC7B;AAEA,UAAI,aAAa,gBAAgB,SAAS;AACxC,UAAE,gBAAgB;AAAA,MACpB;AAEA,cAAQ,QAAQ,YAAU,QAAQ,YAAY,GAAG,MAAM,CAAC;AAAA,IAC1D;AAAA,IACA,CAAC,SAAS,SAAS,QAAQ,QAAQ;AAAA,EACrC;AAEA,QAAM,cAAc;AAAA,IAClB,CAAC,MAAqB;AACpB,UAAI,aAAa,gBAAgB,SAAS;AACxC,UAAE,gBAAgB;AAClB,UAAE,eAAe;AAAA,MACnB;AAAA,IACF;AAAA,IACA,CAAC,SAAS,QAAQ,QAAQ;AAAA,EAC5B;AAEA,QAAM,cAAc;AAAA,IAClB,CAAC,MAAkB;AACjB,UAAI,aAAa,gBAAgB,SAAS;AACxC,UAAE,gBAAgB;AAClB,UAAE,eAAe;AAAA,MACnB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,QAAM,aAAa,YAAY,CAAC,MAAkB;AAEhD,QAAI,EAAE,iBAAiB;AAAM;AAE7B,QAAI,EAAE,eAAe,aAAa,iBAAiB,MAAM;AACvD,wBAAkB,UAAU;AAAA,EAChC,GAAG,CAAC,CAAC;AAEL,SACE,oBAAC,SAAM,QAAgB,OAAO,cAC5B;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,UAAU,aAAa,gBAAgB;AAAA,MACvC,aAAY;AAAA;AAAA,EACd,GACF;AAEJ;AAEA,IAAO,2BAAQ;","names":["editor"]}
1
+ {"version":3,"sources":["../../../../../../../src/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.tsx"],"sourcesContent":["'use client'\n\nimport {\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { createEditor } from 'slate'\nimport isHotkey from 'is-hotkey'\nimport {\n withReact,\n ReactEditor,\n RenderElementProps,\n RenderLeafProps,\n Slate,\n Editable,\n} from 'slate-react'\n\nimport {\n RichTextV2Definition,\n RichText,\n RichTextV2Control,\n type RichTextDataV2,\n} from '../../../../../controls/rich-text-v2'\n\nimport { useBuilderEditMode } from '../../..'\nimport { useSlateReset } from '../../use-slate-reset'\nimport { BuilderEditMode } from '../../../../../state/modules/builder-edit-mode'\nimport { pollBoxModel } from '../../../poll-box-model'\nimport { withBuilder, withLocalChanges } from '../../../../../slate'\nimport { useSyncDOMSelection } from './useSyncDOMSelection'\nimport { RichTextV2Element } from './render-element'\nimport { RichTextV2Leaf } from './render-leaf'\nimport { useSyncRemoteChanges } from './useRemoteChanges'\nimport { defaultValue, usePresetValue } from './usePresetValue'\n\nexport type RichTextV2ControlValue = ReactNode\n\nexport type Descriptors = { text?: RichTextV2Definition }\n\ntype Props = {\n text?: RichTextDataV2\n definition: RichTextV2Definition\n control: RichTextV2Control | null\n}\n\nexport function EditableTextV2({ text, definition, control }: Props) {\n const plugins = useMemo(() => definition.config.plugins, [definition])\n\n const [editor] = useState(() =>\n plugins.reduceRight(\n (editor, plugin) => plugin?.withPlugin?.(editor) ?? editor,\n withLocalChanges(withBuilder(withReact(createEditor()))),\n ),\n )\n\n useEffect(() => {\n if (control == null) return\n\n const element = ReactEditor.toDOMNode(editor, editor)\n return pollBoxModel({\n element,\n onBoxModelChange: boxModel => control.changeBoxModel(boxModel),\n })\n }, [editor, control])\n\n // ------ Preserving selection ------\n\n const isPreservingFocus = useRef(false)\n useSyncDOMSelection(editor, isPreservingFocus)\n const editMode = useBuilderEditMode()\n\n useEffect(() => {\n /**\n * This is required because clicking on the overlay has `relatedTarget` null just like the sidebar, but\n * - in the case of the overlay we switch to BUILD mode\n * - in the case of the sidebar we preserve the selection\n */\n if (editMode !== BuilderEditMode.CONTENT) {\n isPreservingFocus.current = false\n ReactEditor.deselect(editor)\n }\n }, [editMode])\n\n // ------ Syncing remote changes ------\n\n useSyncRemoteChanges(editor, text)\n\n // ------ Default value ------\n\n const presetValue = usePresetValue(definition)\n\n const initialValue = useMemo(\n () => (text && RichText.dataToNodes(text)) ?? presetValue,\n [text, presetValue],\n )\n\n useEffect(() => {\n control?.setEditor(editor)\n control?.setDefaultValue(defaultValue)\n }, [control, editor])\n\n /**\n * When initialValue is set to the default value we need to trigger an local change so that the sidebar updates and so the data is saved\n */\n useEffect(() => {\n if (initialValue === presetValue) {\n control?.onLocalUserChange()\n }\n }, [control, initialValue, presetValue])\n\n // ------ Rendering ------\n\n const renderElement = useCallback(\n (props: RenderElementProps) => {\n return <RichTextV2Element {...props} definition={definition} plugins={plugins} />\n },\n [plugins, definition],\n )\n\n const renderLeaf = useCallback(\n (props: RenderLeafProps) => {\n return <RichTextV2Leaf {...props} definition={definition} plugins={plugins} />\n },\n [plugins, definition],\n )\n\n // ------ Event handlers ------\n\n const handleFocus = useCallback(() => {\n isPreservingFocus.current = true\n control?.select()\n }, [control])\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (isHotkey('mod+shift+z', e)) return control?.redo()\n if (isHotkey('mod+z', e)) return control?.undo()\n if (isHotkey('escape')(e)) {\n isPreservingFocus.current = false\n ReactEditor.blur(editor)\n control?.switchToBuildMode()\n }\n\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n }\n\n plugins.forEach(plugin => plugin?.onKeyDown?.(e, editor))\n },\n [control, plugins, editor, editMode],\n )\n\n const handleKeyUp = useCallback(\n (e: KeyboardEvent) => {\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n e.preventDefault()\n }\n },\n [control, editor, editMode],\n )\n\n const handleClick = useCallback(\n (e: MouseEvent) => {\n if (editMode === BuilderEditMode.CONTENT) {\n e.stopPropagation()\n e.preventDefault()\n }\n },\n [editMode],\n )\n\n const handleBlur = useCallback((e: FocusEvent) => {\n // outside of iframe (overlay, sidebar, etc)\n if (e.relatedTarget == null) return\n // another text\n if (e.relatedTarget?.getAttribute('contenteditable') === 'true')\n isPreservingFocus.current = false\n }, [])\n\n const slateReset = useSlateReset()\n\n return (\n <Slate editor={editor} value={initialValue}>\n <Editable\n className={slateReset}\n renderLeaf={renderLeaf}\n renderElement={renderElement}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onKeyUp={handleKeyUp}\n onClick={handleClick}\n onBlur={handleBlur}\n readOnly={editMode !== BuilderEditMode.CONTENT}\n placeholder=\"Write some text...\"\n />\n </Slate>\n )\n}\n\nexport default EditableTextV2\n"],"mappings":"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","names":["editor"]}
@@ -0,0 +1,13 @@
1
+ import { useStyle } from "../use-style";
2
+ function useSlateReset() {
3
+ return useStyle({
4
+ // @ts-expect-error: csstype's `all` doesn't accept `!important` annotations
5
+ "& [data-slate-string], & [data-slate-zero-width]": {
6
+ all: "revert !important"
7
+ }
8
+ });
9
+ }
10
+ export {
11
+ useSlateReset
12
+ };
13
+ //# sourceMappingURL=use-slate-reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/runtimes/react/controls/use-slate-reset.ts"],"sourcesContent":["import { useStyle } from '../use-style'\n\n/**\n * `slate-react` renders read-only rich-text within a `<p>` tag containing\n * multiple spans. Makeswift text-styles are applied to these spans via a class\n * on the span tags directly:\n *\n * <p class=\"...\">\n * <span class=\"mswft-12345\">My text</span>\n * </p>\n *\n * HOWEVER: in the builder, `slate-react` renders the same content as editable\n * text with additional DOM structure; namely, intermediate nested spans (with\n * data attributes like `data-slate-string`, `data-slate-zero-width`) between\n * the `<span>` that carries Makeswift's typography class and the text content:\n *\n * <p data-slate-node=\"element\" class=\"...\">\n * <span data-slate-node=\"text\">\n * <span class=\"mswft-12345\" data-slate-leaf=\"true\">\n * <span data-slate-string=\"true\">My text</span>\n * </span>\n * </span>\n * </p>\n *\n * If the host contains CSS that matches spans directly (ex: a global `span {\n * color: ... }` rule), the host CSS applies to the innermost spans and beats\n * the Makeswift text styles in terms of specificity. Therefore, setting text\n * styles won't work in the builder: the top-level host styles will win. On the\n * live page, the Makeswift styles win since the intermediate DOM elements are\n * not present.\n *\n * These style updates address this by reverting base styles on these spans,\n * restoring inheritance from Makeswift defined styles, thus matching the live\n * page where the text is a direct child of the classed leaf span.\n */\nexport function useSlateReset(): string {\n return useStyle({\n // @ts-expect-error: csstype's `all` doesn't accept `!important` annotations\n '& [data-slate-string], & [data-slate-zero-width]': {\n all: 'revert !important',\n },\n })\n}\n"],"mappings":"AAAA,SAAS,gBAAgB;AAmClB,SAAS,gBAAwB;AACtC,SAAO,SAAS;AAAA;AAAA,IAEd,oDAAoD;AAAA,MAClD,KAAK;AAAA,IACP;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -0,0 +1,11 @@
1
+ "use client";
2
+ import { isElementReference } from "../../../state/read-only-state";
3
+ import { useElement } from "./use-element";
4
+ const useElementData = ({ elementKey }) => {
5
+ const element = useElement({ elementKey });
6
+ return element && !isElementReference(element) ? element : null;
7
+ };
8
+ export {
9
+ useElementData
10
+ };
11
+ //# sourceMappingURL=use-element-data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/runtimes/react/hooks/use-element-data.tsx"],"sourcesContent":["'use client'\n\nimport { type ElementData, isElementReference } from '../../../state/read-only-state'\n\nimport { useElement } from './use-element'\n\nexport const useElementData = ({ elementKey }: { elementKey: string }): ElementData | null => {\n const element = useElement({ elementKey })\n return element && !isElementReference(element) ? element : null\n}\n"],"mappings":";AAEA,SAA2B,0BAA0B;AAErD,SAAS,kBAAkB;AAEpB,MAAM,iBAAiB,CAAC,EAAE,WAAW,MAAkD;AAC5F,QAAM,UAAU,WAAW,EAAE,WAAW,CAAC;AACzC,SAAO,WAAW,CAAC,mBAAmB,OAAO,IAAI,UAAU;AAC7D;","names":[]}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { getElement } from "../../../state/read-only-state";
3
+ import { useSelector } from "./use-selector";
4
+ import { useDocumentKey } from "./use-document-context";
5
+ const useElement = ({ elementKey }) => {
6
+ const documentKey = useDocumentKey();
7
+ return useSelector((state) => {
8
+ if (documentKey == null)
9
+ return null;
10
+ return getElement(state, documentKey, elementKey);
11
+ });
12
+ };
13
+ export {
14
+ useElement
15
+ };
16
+ //# sourceMappingURL=use-element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/runtimes/react/hooks/use-element.tsx"],"sourcesContent":["'use client'\n\nimport { type Element, getElement } from '../../../state/read-only-state'\n\nimport { useSelector } from './use-selector'\nimport { useDocumentKey } from './use-document-context'\n\nexport const useElement = ({ elementKey }: { elementKey: string }): Element | null => {\n const documentKey = useDocumentKey()\n\n return useSelector(state => {\n if (documentKey == null) return null\n\n return getElement(state, documentKey, elementKey)\n })\n}\n"],"mappings":";AAEA,SAAuB,kBAAkB;AAEzC,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAExB,MAAM,aAAa,CAAC,EAAE,WAAW,MAA8C;AACpF,QAAM,cAAc,eAAe;AAEnC,SAAO,YAAY,WAAS;AAC1B,QAAI,eAAe;AAAM,aAAO;AAEhC,WAAO,WAAW,OAAO,aAAa,UAAU;AAAA,EAClD,CAAC;AACH;","names":[]}
@@ -3,7 +3,7 @@ import { type ValueType, type DataType, ControlDefinition } from '@makeswift/con
3
3
  import { type CacheData } from '../../../../api/api-resources-client';
4
4
  import { ElementData } from '../../../../state/read-only-state';
5
5
  import { ReactRuntime } from '../../../../runtimes/react/react-runtime';
6
- export declare function testPageControlPropRendering<D extends ControlDefinition>(controlDefinition: D, { toData, value, locale, cacheData, expectedRenders, registerComponents, action, rootElements, isInBuilder, }: {
6
+ export declare function testPageControlPropRendering<D extends ControlDefinition>(controlDefinition: D, { toData, value, locale, cacheData, expectedRenders, registerComponents, action, rootElements, isInBuilder, isReadOnly, }: {
7
7
  toData?: (value: ValueType<D>) => DataType<D>;
8
8
  value: ValueType<D> | undefined;
9
9
  locale?: string | null;
@@ -13,5 +13,6 @@ export declare function testPageControlPropRendering<D extends ControlDefinition
13
13
  action?: (element: HTMLElement) => Promise<void>;
14
14
  rootElements?: ElementData[];
15
15
  isInBuilder?: boolean;
16
+ isReadOnly?: boolean;
16
17
  }): Promise<void>;
17
18
  //# sourceMappingURL=page-control-prop-rendering.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"page-control-prop-rendering.d.ts","sourceRoot":"","sources":["../../../../../../src/next/components/tests/controls/page-control-prop-rendering.tsx"],"names":[],"mappings":"AAIA,OAAO,2BAA2B,CAAA;AAGlC,OAAO,EAAa,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEjG,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,sCAAsC,CAAA;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAA;AAiEvE,wBAAsB,4BAA4B,CAAC,CAAC,SAAS,iBAAiB,EAC5E,iBAAiB,EAAE,CAAC,EACpB,EACE,MAAM,EACN,KAAK,EACL,MAAM,EACN,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,MAAM,EACN,YAAiB,EACjB,WAAmB,GACpB,EAAE;IACD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAA;IAC7C,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAA;IACpD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAChD,YAAY,CAAC,EAAE,WAAW,EAAE,CAAA;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,iBA6FF"}
1
+ {"version":3,"file":"page-control-prop-rendering.d.ts","sourceRoot":"","sources":["../../../../../../src/next/components/tests/controls/page-control-prop-rendering.tsx"],"names":[],"mappings":"AAIA,OAAO,2BAA2B,CAAA;AAGlC,OAAO,EAAa,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEjG,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,sCAAsC,CAAA;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAA;AAsFvE,wBAAsB,4BAA4B,CAAC,CAAC,SAAS,iBAAiB,EAC5E,iBAAiB,EAAE,CAAC,EACpB,EACE,MAAM,EACN,KAAK,EACL,MAAM,EACN,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,MAAM,EACN,YAAiB,EACjB,WAAmB,EACnB,UAAiB,GAClB,EAAE;IACD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAA;IAC7C,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAA;IACpD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAChD,YAAY,CAAC,EAAE,WAAW,EAAE,CAAA;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,iBAwGF"}
@@ -1 +1 @@
1
- {"version":3,"file":"editable-text.d.ts","sourceRoot":"","sources":["../../../../../../../src/runtimes/react/controls/rich-text/EditableText/editable-text.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAA2B,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAMjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0DAA0D,CAAA;AAGhG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAI1C,KAAK,KAAK,GAAG;IACX,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAMD,eAAO,MAAM,YAAY,sHAmFvB,CAAA;AAEF,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"editable-text.d.ts","sourceRoot":"","sources":["../../../../../../../src/runtimes/react/controls/rich-text/EditableText/editable-text.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAA2B,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAOjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0DAA0D,CAAA;AAGhG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAI1C,KAAK,KAAK,GAAG;IACX,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAMD,eAAO,MAAM,YAAY,sHAqFvB,CAAA;AAEF,eAAe,YAAY,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"editable-text-v2.d.ts","sourceRoot":"","sources":["../../../../../../../src/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,SAAS,EAMV,MAAM,OAAO,CAAA;AAYd,OAAO,EACL,oBAAoB,EAEpB,iBAAiB,EACjB,KAAK,cAAc,EACpB,MAAM,sCAAsC,CAAA;AAY7C,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAAA;AAE9C,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,CAAC,EAAE,oBAAoB,CAAA;CAAE,CAAA;AAEzD,KAAK,KAAK,GAAG;IACX,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,UAAU,EAAE,oBAAoB,CAAA;IAChC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAClC,CAAA;AAED,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,KAAK,2CAsJlE;AAED,eAAe,cAAc,CAAA"}
1
+ {"version":3,"file":"editable-text-v2.d.ts","sourceRoot":"","sources":["../../../../../../../src/runtimes/react/controls/rich-text-v2/EditableTextV2/editable-text-v2.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,SAAS,EAMV,MAAM,OAAO,CAAA;AAYd,OAAO,EACL,oBAAoB,EAEpB,iBAAiB,EACjB,KAAK,cAAc,EACpB,MAAM,sCAAsC,CAAA;AAa7C,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAAA;AAE9C,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,CAAC,EAAE,oBAAoB,CAAA;CAAE,CAAA;AAEzD,KAAK,KAAK,GAAG;IACX,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,UAAU,EAAE,oBAAoB,CAAA;IAChC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAClC,CAAA;AAED,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,KAAK,2CAyJlE;AAED,eAAe,cAAc,CAAA"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `slate-react` renders read-only rich-text within a `<p>` tag containing
3
+ * multiple spans. Makeswift text-styles are applied to these spans via a class
4
+ * on the span tags directly:
5
+ *
6
+ * <p class="...">
7
+ * <span class="mswft-12345">My text</span>
8
+ * </p>
9
+ *
10
+ * HOWEVER: in the builder, `slate-react` renders the same content as editable
11
+ * text with additional DOM structure; namely, intermediate nested spans (with
12
+ * data attributes like `data-slate-string`, `data-slate-zero-width`) between
13
+ * the `<span>` that carries Makeswift's typography class and the text content:
14
+ *
15
+ * <p data-slate-node="element" class="...">
16
+ * <span data-slate-node="text">
17
+ * <span class="mswft-12345" data-slate-leaf="true">
18
+ * <span data-slate-string="true">My text</span>
19
+ * </span>
20
+ * </span>
21
+ * </p>
22
+ *
23
+ * If the host contains CSS that matches spans directly (ex: a global `span {
24
+ * color: ... }` rule), the host CSS applies to the innermost spans and beats
25
+ * the Makeswift text styles in terms of specificity. Therefore, setting text
26
+ * styles won't work in the builder: the top-level host styles will win. On the
27
+ * live page, the Makeswift styles win since the intermediate DOM elements are
28
+ * not present.
29
+ *
30
+ * These style updates address this by reverting base styles on these spans,
31
+ * restoring inheritance from Makeswift defined styles, thus matching the live
32
+ * page where the text is a direct child of the classed leaf span.
33
+ */
34
+ export declare function useSlateReset(): string;
35
+ //# sourceMappingURL=use-slate-reset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-slate-reset.d.ts","sourceRoot":"","sources":["../../../../../src/runtimes/react/controls/use-slate-reset.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAOtC"}
@@ -0,0 +1,5 @@
1
+ import { type ElementData } from '../../../state/read-only-state';
2
+ export declare const useElementData: ({ elementKey }: {
3
+ elementKey: string;
4
+ }) => ElementData | null;
5
+ //# sourceMappingURL=use-element-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-element-data.d.ts","sourceRoot":"","sources":["../../../../../src/runtimes/react/hooks/use-element-data.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAsB,MAAM,gCAAgC,CAAA;AAIrF,eAAO,MAAM,cAAc,GAAI,gBAAgB;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,KAAG,WAAW,GAAG,IAGrF,CAAA"}
@@ -0,0 +1,5 @@
1
+ import { type Element } from '../../../state/read-only-state';
2
+ export declare const useElement: ({ elementKey }: {
3
+ elementKey: string;
4
+ }) => Element | null;
5
+ //# sourceMappingURL=use-element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-element.d.ts","sourceRoot":"","sources":["../../../../../src/runtimes/react/hooks/use-element.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAc,MAAM,gCAAgC,CAAA;AAKzE,eAAO,MAAM,UAAU,GAAI,gBAAgB;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,GAAG,IAQ7E,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makeswift/runtime",
3
- "version": "0.28.9",
3
+ "version": "0.28.10-canary.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "url": "makeswift/makeswift",
@@ -239,9 +239,9 @@
239
239
  "use-sync-external-store": "^1.5.0",
240
240
  "uuid": "^9.0.0",
241
241
  "zod": "^3.21.4",
242
+ "@makeswift/controls": "0.1.21",
242
243
  "@makeswift/next-plugin": "0.6.1",
243
- "@makeswift/prop-controllers": "0.4.15",
244
- "@makeswift/controls": "0.1.21"
244
+ "@makeswift/prop-controllers": "0.4.15"
245
245
  },
246
246
  "devDependencies": {
247
247
  "@emotion/jest": "^11.11.0",