TemplatePattern.tsx 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import React, { useRef, useEffect } from 'react';
  2. import { renderPattern, simulateLoading } from 'storybook-django';
  3. const getTemplateName = (template?: string, filename?: string): string =>
  4. template ||
  5. filename?.replace(/.+\/templates\//, '').replace(/\.stories\..+$/, '.html') ||
  6. 'template-not-found';
  7. type ContextMapping = { [key: string]: any };
  8. type TagsMapping = { [key: string]: any };
  9. interface TemplatePatternProps {
  10. element?: 'div' | 'span';
  11. // Path to the template file.
  12. template?: string;
  13. // Path to a Storybook `stories` file, which should be placed next to and named the same as the HTML template.
  14. filename?: string;
  15. context?: ContextMapping;
  16. tags?: TagsMapping;
  17. }
  18. const PATTERN_LIBRARY_RENDER_URL = '/pattern-library/api/v1/render-pattern';
  19. /**
  20. * Retrieves a template pattern’s HTML (or error response) from the server.
  21. */
  22. export const getTemplatePattern = (
  23. templateName: string,
  24. context: ContextMapping,
  25. tags: TagsMapping,
  26. callback: (html: string) => void,
  27. ) =>
  28. renderPattern(PATTERN_LIBRARY_RENDER_URL, templateName, context, tags)
  29. .catch(callback)
  30. .then((res) => res.text())
  31. .then(callback);
  32. /**
  33. * Renders one of our Django templates as if it was a React component.
  34. * All props are marked as optional, but either template or filename should be provided.
  35. */
  36. const TemplatePattern = ({
  37. element = 'div',
  38. template,
  39. filename,
  40. context = {},
  41. tags = {},
  42. }: TemplatePatternProps) => {
  43. const ref = useRef(null);
  44. useEffect(() => {
  45. const templateName = getTemplateName(template, filename);
  46. getTemplatePattern(templateName, context, tags, (html) =>
  47. simulateLoading(ref.current, html),
  48. );
  49. });
  50. return React.createElement(element, { ref });
  51. };
  52. export default TemplatePattern;