summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/storybook/scaffold.tsx
blob: 2512aa09be560d6fd65dac319fc61f7dae714c54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { ErrorBoundary, type ValidComponent } from "solid-js"
import { Dynamic } from "solid-js/web"

function fn(value: unknown): value is (...args: never[]) => unknown {
  return typeof value === "function"
}

function pick(mod: Record<string, unknown>, name?: string) {
  if (name && fn(mod[name])) return mod[name]
  if (fn(mod.default)) return mod.default

  const preferred = Object.keys(mod)
    .filter((k) => k[0] && k[0] === k[0].toUpperCase())
    .find((k) => fn(mod[k]))
  if (preferred) return mod[preferred]

  const first = Object.keys(mod).find((k) => fn(mod[k]))
  if (first) return mod[first]

  return () => {
    return (
      <div data-component="storybook-missing">
        <div>Missing component export.</div>
        <div style="opacity:0.7;font-size:12px">Exports: {Object.keys(mod).join(", ") || "(none)"}</div>
      </div>
    )
  }
}

export function create(input: {
  title: string
  mod: Record<string, unknown>
  name?: string
  args?: Record<string, unknown>
}) {
  const component = pick(input.mod, input.name) as unknown as ValidComponent

  return {
    meta: {
      title: input.title,
      component,
    },
    Basic: {
      args: input.args ?? {},
      render: (args: Record<string, unknown>) => {
        return (
          <ErrorBoundary
            fallback={(err) => {
              return (
                <pre data-component="storybook-error" style="white-space:pre-wrap">
                  {String(err)}
                </pre>
              )
            }}
          >
            <Dynamic component={component} {...args} />
          </ErrorBoundary>
        )
      },
    },
  }
}