diff-ssr.tsx 2.6 KB

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