{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "workflow",
  "type": "registry:component",
  "title": "Workflow card",
  "description": "Frames an ordered pipeline. 1px dashed frame, chips, and a ghost add action. Reordering is supplied by SortableList.",
  "registryDependencies": [
    "https://vlak.dev/r/vlak-base.json",
    "https://vlak.dev/r/inter.json",
    "https://vlak.dev/r/vlak-lib.json"
  ],
  "dependencies": [
    "@stylexjs/stylex"
  ],
  "devDependencies": [
    "@stylexjs/babel-plugin"
  ],
  "docs": "Vlak leaves are StyleX. Compile them with @stylexjs/babel-plugin (Vite: @stylexjs/unplugin, Next: @stylexjs/nextjs-plugin). If you would rather not run a compiler, import @noorddev/vlak-react instead: it ships precompiled with one stylesheet.",
  "files": [
    {
      "path": "vlak/workflow.tsx",
      "content": "import * as React from \"react\";\nimport * as stylex from \"@stylexjs/stylex\";\nimport { vlak, mq } from \"./tokens.stylex\";\nimport { rs } from \"./rs\";\n\nexport interface FlowProps extends React.HTMLAttributes<HTMLDivElement> {}\nexport interface FlowStepProps extends React.HTMLAttributes<HTMLDivElement> {}\nexport interface FlowAddProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}\n\nconst at560 = \"@media (min-width: 560px)\";\nconst at940 = \"@media (min-width: 940px)\";\nconst at1280 = \"@media (min-width: 1280px)\";\nconst at1448 = \"@media (min-width: 1448px)\";\n\nconst styles = stylex.create({\n  flow: {\n    display: \"grid\",\n    gridTemplateColumns: {\n      default: \"1fr\",\n      [at560]: \"repeat(2, 184px)\",\n      [at940]: \"repeat(3, 184px)\",\n      [at1280]: \"repeat(4, 184px)\",\n      [at1448]: \"repeat(5, 184px)\",\n    },\n    width: {\n      default: null,\n      [at560]: \"fit-content\",\n    },\n    gap: vlak.gutter,\n  },\n  step: {\n    position: \"relative\",\n    borderWidth: vlak.hairline,\n    borderStyle: \"dashed\",\n    borderColor: {\n      default: vlak.divider,\n      \":hover\": { default: null, [mq.hover]: vlak.accent },\n    },\n    borderRadius: vlak.radiusSm,\n    paddingTop: \"0.875rem\",\n    paddingInlineEnd: \"2.125rem\",\n    paddingBottom: \"1rem\",\n    paddingInlineStart: \"0.875rem\",\n    backgroundColor: \"var(--bg)\",\n    transition: {\n      default: vlak.transition,\n      [mq.reduce]: \"none\",\n    },\n    \"::after\": {\n      content: '\"\"',\n      position: \"absolute\",\n      top: \"0.9375rem\",\n      insetInlineEnd: \"0.8125rem\",\n      width: \"0.5rem\",\n      height: \"0.875rem\",\n      backgroundImage: \"radial-gradient(currentColor 1.1px, transparent 1.3px)\",\n      backgroundSize: \"4px 5px\",\n      color: \"var(--text-secondary)\",\n      opacity: 0.4,\n    },\n  },\n  num: {\n    position: \"relative\",\n    zIndex: 1,\n    display: \"flex\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    width: \"1.875rem\",\n    height: \"1.875rem\",\n    borderRadius: \"50%\",\n    borderWidth: vlak.hairline,\n    borderStyle: \"solid\",\n    borderColor: vlak.divider,\n    backgroundColor: \"var(--bg)\",\n    fontSize: \"0.8125rem\",\n    fontWeight: 600,\n    fontVariantNumeric: \"tabular-nums\",\n    color: \"var(--text)\",\n    marginBottom: \"0.875rem\",\n  },\n  title: {\n    display: \"inline-block\",\n    fontSize: \"0.90625rem\",\n    fontWeight: 600,\n    letterSpacing: \"-0.01em\",\n    color: \"var(--text)\",\n    borderBottomWidth: vlak.hairline,\n    borderBottomStyle: \"dashed\",\n    borderBottomColor: vlak.divider,\n    paddingBottom: 1,\n    marginTop: 0,\n    marginBottom: \"0.5rem\",\n    marginInlineStart: 0,\n    marginInlineEnd: 0,\n  },\n  body: {\n    fontSize: \"0.78125rem\",\n    lineHeight: 1.45,\n    color: vlak.gray,\n    letterSpacing: \"-0.005em\",\n    margin: 0,\n  },\n  subs: {\n    display: \"flex\",\n    flexWrap: \"wrap\",\n    gap: \"0.3125rem\",\n    marginTop: \"0.6875rem\",\n  },\n  sub: {\n    fontSize: \"0.6875rem\",\n    lineHeight: 1,\n    paddingBlock: \"0.1875rem\",\n    paddingInline: \"0.4375rem\",\n    borderWidth: vlak.hairline,\n    borderStyle: \"dashed\",\n    borderColor: vlak.divider,\n    borderRadius: vlak.radiusSm,\n    color: vlak.gray,\n    letterSpacing: \"-0.005em\",\n  },\n  subAdd: {\n    width: \"1.125rem\",\n    paddingTop: \"0.1875rem\",\n    paddingBottom: \"0.1875rem\",\n    paddingInlineStart: 0,\n    paddingInlineEnd: 0,\n    textAlign: \"center\",\n    opacity: 0.7,\n  },\n  add: {\n    display: \"flex\",\n    alignItems: \"center\",\n    gap: \"0.5rem\",\n    marginTop: \"0.875rem\",\n    borderWidth: vlak.hairline,\n    borderStyle: \"dashed\",\n    borderColor: {\n      default: vlak.divider,\n      \":hover\": { default: null, [mq.hover]: vlak.accent },\n    },\n    borderRadius: vlak.radiusSm,\n    paddingTop: \"0.75rem\",\n    paddingBottom: \"0.75rem\",\n    paddingInlineStart: \"0.875rem\",\n    paddingInlineEnd: \"0.875rem\",\n    fontSize: \"0.8125rem\",\n    fontWeight: 600,\n    letterSpacing: \"-0.01em\",\n    color: {\n      default: vlak.gray,\n      \":hover\": { default: null, [mq.hover]: \"var(--text)\" },\n    },\n    backgroundColor: \"transparent\",\n    width: 184,\n    maxWidth: \"100%\",\n    transition: {\n      default: vlak.transition,\n      [mq.reduce]: \"none\",\n    },\n    fontFamily: \"inherit\",\n    cursor: \"pointer\",\n  },\n  plus: {\n    display: \"inline-flex\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    width: \"1.125rem\",\n    height: \"1.125rem\",\n    borderWidth: vlak.hairline,\n    borderStyle: \"solid\",\n    borderColor: \"currentColor\",\n    borderRadius: \"50%\",\n    fontSize: \"0.8125rem\",\n    lineHeight: 1,\n  },\n});\n\n/** Dashed 1px pipeline. */\nexport const Flow = React.forwardRef<HTMLDivElement, FlowProps>(function Flow(\n  { className, style, ...props },\n  ref,\n) {\n  const sx = rs([\"rs-flow\", className], styles.flow);\n  return <div ref={ref} {...props} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n\nexport const FlowStep = React.forwardRef<HTMLDivElement, FlowStepProps>(function FlowStep(\n  { className, style, ...props },\n  ref,\n) {\n  const sx = rs([\"rs-flow-step\", className], styles.step);\n  return <div ref={ref} {...props} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n\nexport const FlowNum = React.forwardRef<HTMLSpanElement, React.HTMLAttributes<HTMLSpanElement>>(function FlowNum(\n  { className, style, ...props },\n  ref,\n) {\n  const sx = rs([\"rs-flow-num\", className], styles.num);\n  return <span ref={ref} {...props} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n\nexport const FlowTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(function FlowTitle(\n  { className, style, ...props },\n  ref,\n) {\n  const sx = rs([className, \"rs-flow-title\"], styles.title);\n  return <h3 ref={ref} {...props} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n\nexport const FlowBody = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(function FlowBody(\n  { className, style, ...props },\n  ref,\n) {\n  const sx = rs([className, \"rs-flow-body\"], styles.body);\n  return <p ref={ref} {...props} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n\nexport const FlowSubs = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(function FlowSubs(\n  { className, style, ...props },\n  ref,\n) {\n  const sx = rs([\"rs-flow-subs\", className], styles.subs);\n  return <div ref={ref} {...props} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n\nexport const FlowSub = React.forwardRef<HTMLSpanElement, React.HTMLAttributes<HTMLSpanElement>>(function FlowSub(\n  { className, style, ...props },\n  ref,\n) {\n  const sx = rs([className, \"rs-flow-sub\"], styles.sub);\n  return <span ref={ref} {...props} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n\nexport const FlowSubAdd = React.forwardRef<HTMLSpanElement, React.HTMLAttributes<HTMLSpanElement>>(function FlowSubAdd(\n  { className, style, ...props },\n  ref,\n) {\n  const sx = rs([\"rs-flow-sub-add\", className], styles.sub, styles.subAdd);\n  return <span ref={ref} {...props} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n\nexport const FlowAdd = React.forwardRef<HTMLButtonElement, FlowAddProps>(function FlowAdd(\n  { className, style, children, ...props },\n  ref,\n) {\n  const sx = rs([\"rs-flow-add\", className], styles.add);\n  const plus = rs([\"rs-flow-plus\"], styles.plus);\n  return (\n    <button ref={ref} type=\"button\" {...props} className={sx.className} style={{ ...sx.style, ...style }}>\n      <span className={plus.className} style={plus.style}>\n        +\n      </span>\n      {children}\n    </button>\n  );\n});\n\nexport const FlowPlus = React.forwardRef<HTMLSpanElement, React.HTMLAttributes<HTMLSpanElement>>(function FlowPlus(\n  { className, style, ...props },\n  ref,\n) {\n  const sx = rs([\"rs-flow-plus\", className], styles.plus);\n  return <span ref={ref} {...props} className={sx.className} style={{ ...sx.style, ...style }} />;\n});\n",
      "type": "registry:component",
      "target": "components/vlak/workflow.tsx"
    },
    {
      "path": "vlak/styles/workflow.css",
      "content": "/* ── workflow: generated from packages/react/src/components/flow.tsx ── */\n.rs-flow{display:grid;grid-template-columns:1fr;gap:var(--gutter)}\n@media (min-width: 560px){.rs-flow{grid-template-columns:repeat(2, 184px);width:fit-content}}\n@media (min-width: 940px){.rs-flow{grid-template-columns:repeat(3, 184px)}}\n@media (min-width: 1280px){.rs-flow{grid-template-columns:repeat(4, 184px)}}\n@media (min-width: 1448px){.rs-flow{grid-template-columns:repeat(5, 184px)}}\n.rs-flow-step{position:relative;border-width:1px;border-style:dashed;border-color:var(--divider);border-radius:var(--radius-sm);padding-top:0.875rem;padding-inline-end:2.125rem;padding-bottom:1rem;padding-inline-start:0.875rem;background-color:var(--bg);transition:var(--transition)}\n.rs-flow-step::after{content:\"\";position:absolute;top:0.9375rem;inset-inline-end:0.8125rem;width:0.5rem;height:0.875rem;background-image:radial-gradient(currentColor 1.1px, transparent 1.3px);background-size:4px 5px;color:var(--text-secondary);opacity:0.4}\n@media (hover: hover) and (pointer: fine){.rs-flow-step:hover{border-color:var(--accent)}}\n@media (prefers-reduced-motion: reduce){.rs-flow-step{transition:none}}\n.rs-flow-num{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;width:1.875rem;height:1.875rem;border-radius:50%;border-width:1px;border-style:solid;border-color:var(--divider);background-color:var(--bg);font-size:0.8125rem;font-weight:600;font-variant-numeric:tabular-nums;color:var(--text);margin-bottom:0.875rem}\n.rs-flow-title{display:inline-block;font-size:0.90625rem;font-weight:600;letter-spacing:-0.01em;color:var(--text);border-bottom-width:1px;border-bottom-style:dashed;border-bottom-color:var(--divider);padding-bottom:1px;margin-top:0;margin-bottom:0.5rem;margin-inline-start:0;margin-inline-end:0}\n.rs-flow-body{font-size:0.78125rem;line-height:1.45;color:var(--text-secondary);letter-spacing:-0.005em;margin:0}\n.rs-flow-subs{display:flex;flex-wrap:wrap;gap:0.3125rem;margin-top:0.6875rem}\n.rs-flow-sub,.rs-flow-sub-add{font-size:0.6875rem;line-height:1;padding-block:0.1875rem;padding-inline:0.4375rem;border-width:1px;border-style:dashed;border-color:var(--divider);border-radius:var(--radius-sm);color:var(--text-secondary);letter-spacing:-0.005em}\n.rs-flow-sub-add{width:1.125rem;padding-top:0.1875rem;padding-bottom:0.1875rem;padding-inline-start:0;padding-inline-end:0;text-align:center;opacity:0.7}\n.rs-flow-add{display:flex;align-items:center;gap:0.5rem;margin-top:0.875rem;border-width:1px;border-style:dashed;border-color:var(--divider);border-radius:var(--radius-sm);padding-top:0.75rem;padding-bottom:0.75rem;padding-inline-start:0.875rem;padding-inline-end:0.875rem;font-size:0.8125rem;font-weight:600;letter-spacing:-0.01em;color:var(--text-secondary);background-color:transparent;width:184px;max-width:100%;transition:var(--transition);font-family:inherit;cursor:pointer}\n@media (hover: hover) and (pointer: fine){.rs-flow-add:hover{border-color:var(--accent);color:var(--text)}}\n@media (prefers-reduced-motion: reduce){.rs-flow-add{transition:none}}\n.rs-flow-plus{display:inline-flex;align-items:center;justify-content:center;width:1.125rem;height:1.125rem;border-width:1px;border-style:solid;border-color:currentColor;border-radius:50%;font-size:0.8125rem;line-height:1}\n",
      "type": "registry:file",
      "target": "styles/vlak/workflow.css"
    }
  ],
  "meta": {
    "vlak": {
      "category": "patterns",
      "classes": [
        "rs-flow",
        "rs-flow-step",
        "rs-flow-num",
        "rs-flow-subs",
        "rs-flow-sub-add",
        "rs-flow-add",
        "rs-flow-plus",
        "rs-flow-body",
        "rs-flow-sub",
        "rs-flow-title"
      ],
      "snippet": "<div class=\"rs-flow\" style=\"grid-template-columns:184px;width:184px\"><div class=\"rs-flow-step\"><span class=\"rs-flow-num\">1</span><h3 class=\"rs-flow-title\">Proposal</h3><p>Scope, timeline, and fee on one page.</p><div class=\"rs-flow-subs\"><span>Brief</span><span>Fee</span><span class=\"rs-flow-sub-add\">+</span></div></div><button type=\"button\" class=\"rs-flow-add\"><span class=\"rs-flow-plus\">+</span> Add a step</button></div>",
      "cssOnly": false,
      "registryDependencies": [
        "vlak-lib"
      ],
      "aliases": [
        "Workflow",
        "Pipeline",
        "Flow card",
        "Process steps"
      ],
      "example": "import { Flow, FlowAdd, FlowBody, FlowNum, FlowStep, FlowSub, FlowSubAdd, FlowSubs, FlowTitle } from \"@noorddev/vlak-react\";\n\n<Flow>\n  <FlowStep>\n    <FlowNum>1</FlowNum>\n    <FlowTitle>Proposal</FlowTitle>\n    <FlowBody>Scope, timeline, and fee on one page.</FlowBody>\n    <FlowSubs>\n      <FlowSub>Brief</FlowSub>\n      <FlowSub>Fee</FlowSub>\n      <FlowSubAdd>+</FlowSubAdd>\n    </FlowSubs>\n  </FlowStep>\n  <FlowAdd onClick={addStep}>Add a step</FlowAdd>\n</Flow>",
      "usage": {
        "use": [
          "Editable pipelines: numbered steps with sub-items and a ghost add action.",
          "Builders, automations, onboarding flows."
        ],
        "avoid": [
          "Read-only progress; use Stepper.",
          "Deep trees; the pipeline is one row."
        ]
      },
      "keyboard": [
        {
          "keys": "Tab",
          "does": "Moves to the add-step button"
        },
        {
          "keys": "Enter, Space",
          "does": "Activates it"
        }
      ],
      "a11y": [
        "FlowAdd is a native <button>; FlowTitle is an <h3>. FlowSubAdd is a <span>: wrap it in a button when it acts. FlowStep is presentational and is not draggable by itself."
      ]
    }
  }
}
