diff-ssr.tsx 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { DIFFS_TAG_NAME, FileDiff } from "@pierre/diffs"
  2. import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
  3. import { onCleanup, onMount, Show, splitProps } from "solid-js"
  4. import { Dynamic, isServer } from "solid-js/web"
  5. import { createDefaultOptions, styleVariables, type DiffProps } from "../pierre"
  6. import { useWorkerPool } from "../context/worker-pool"
  7. export type SSRDiffProps<T = {}> = DiffProps<T> & {
  8. preloadedDiff: PreloadMultiFileDiffResult<T>
  9. }
  10. export function Diff<T>(props: SSRDiffProps<T>) {
  11. let container!: HTMLDivElement
  12. let fileDiffRef!: HTMLElement
  13. const [local, others] = splitProps(props, ["before", "after", "class", "classList", "annotations"])
  14. const workerPool = useWorkerPool()
  15. let fileDiffInstance: FileDiff<T> | undefined
  16. const cleanupFunctions: Array<() => void> = []
  17. onMount(() => {
  18. if (isServer || !props.preloadedDiff) return
  19. fileDiffInstance = new FileDiff<T>(
  20. {
  21. ...createDefaultOptions(props.diffStyle),
  22. ...others,
  23. ...props.preloadedDiff,
  24. },
  25. workerPool,
  26. )
  27. // @ts-expect-error - fileContainer is private but needed for SSR hydration
  28. fileDiffInstance.fileContainer = fileDiffRef
  29. fileDiffInstance.hydrate({
  30. oldFile: local.before,
  31. newFile: local.after,
  32. lineAnnotations: local.annotations,
  33. fileContainer: fileDiffRef,
  34. containerWrapper: container,
  35. })
  36. // Hydrate annotation slots with interactive SolidJS components
  37. // if (props.annotations.length > 0 && props.renderAnnotation != null) {
  38. // for (const annotation of props.annotations) {
  39. // const slotName = `annotation-${annotation.side}-${annotation.lineNumber}`;
  40. // const slotElement = fileDiffRef.querySelector(
  41. // `[slot="${slotName}"]`
  42. // ) as HTMLElement;
  43. //
  44. // if (slotElement != null) {
  45. // // Clear the static server-rendered content from the slot
  46. // slotElement.innerHTML = '';
  47. //
  48. // // Mount a fresh SolidJS component into this slot using render().
  49. // // This enables full SolidJS reactivity (signals, effects, etc.)
  50. // const dispose = render(
  51. // () => props.renderAnnotation!(annotation),
  52. // slotElement
  53. // );
  54. // cleanupFunctions.push(dispose);
  55. // }
  56. // }
  57. // }
  58. })
  59. onCleanup(() => {
  60. // Clean up FileDiff event handlers and dispose SolidJS components
  61. fileDiffInstance?.cleanUp()
  62. cleanupFunctions.forEach((dispose) => dispose())
  63. })
  64. return (
  65. <div data-component="diff" style={styleVariables} ref={container}>
  66. <Dynamic component={DIFFS_TAG_NAME} ref={fileDiffRef} id="ssr-diff">
  67. <Show when={isServer}>
  68. <template shadowrootmode="open" innerHTML={props.preloadedDiff.prerenderedHTML} />
  69. </Show>
  70. </Dynamic>
  71. </div>
  72. )
  73. }