{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "attachment",
  "title": "Attachment",
  "description": "A file's extension is its picture; a ring counts it in and fills to a dot when it's safe.",
  "registryDependencies": [
    "https://thedirectors.agency/ui/r/0nlytype.json",
    "https://thedirectors.agency/ui/r/button.json"
  ],
  "files": [
    {
      "path": "registry/0nlytype/ui/attachment.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\n\ntype AttachmentListProps = React.ComponentProps<\"ul\"> & {\n  /**\n   * reverse: the extension is reversed out of an ink block that prints across it as the file arrives.\n   * enclosure: the files written as a letter's enclosure line, \"Encl. (2)\", run on in one sentence.\n   */\n  variant?: \"default\" | \"reverse\" | \"enclosure\"\n  /** The word before the enclosure count. */\n  enclosureLabel?: string\n}\n\n/** The list the files sit in. */\nfunction AttachmentList({ variant = \"default\", enclosureLabel = \"Encl.\", className, children, ...props }: AttachmentListProps) {\n  return (\n    <ul\n      data-slot=\"attachment-list\"\n      data-variant={variant === \"default\" ? undefined : variant}\n      data-count={variant === \"enclosure\" ? React.Children.count(children) : undefined}\n      data-enclosure-label={variant === \"enclosure\" ? enclosureLabel : undefined}\n      aria-label={variant === \"enclosure\" ? \"Enclosures\" : undefined}\n      className={cn(\"ot-attachments\", className)}\n      {...props}\n    >\n      {children}\n    </ul>\n  )\n}\n\ntype AttachmentProps = Omit<React.ComponentProps<\"li\">, \"children\"> & {\n  name: string\n  /** The size, as it should read: \"2.4 MB\". Set in tabular figures. */\n  size?: string\n  /** Says what is happening or what went wrong, in place of the size: \"Checking\", \"The connection dropped.\" */\n  status?: string\n  state?: \"idle\" | \"uploading\" | \"processing\" | \"done\" | \"error\"\n  /** How far an upload has got, 0 to 1. The ring counts it in. */\n  progress?: number\n  /** Shows a Remove button, labelled with the file's name. */\n  onRemove?: () => void\n  /** The button's word, also followed by the file name in its accessible name. */\n  removeLabel?: string\n}\n\n/** A file: its extension is its picture, a ring counts it in and fills to a dot when it's safe. */\nfunction Attachment({ name, size, status, state = \"done\", progress, onRemove, removeLabel = \"Remove\", className, style, ...props }: AttachmentProps) {\n  const ext = name.includes(\".\") ? name.slice(name.lastIndexOf(\".\") + 1) : \"\"\n  return (\n    <li\n      data-slot=\"attachment\"\n      data-state={state}\n      className={cn(\"ot-attach\", className)}\n      style={progress === undefined ? style : ({ \"--p\": progress, ...style } as React.CSSProperties)}\n      {...props}\n    >\n      <span className=\"ot-attach-ext\" data-ext={ext} aria-hidden=\"true\">{ext}</span>\n      <span className=\"ot-attach-body\">\n        <span className=\"ot-attach-name\">{name}</span>{\" \"}\n        <span className=\"ot-attach-meta\">{status ?? size}</span>\n      </span>\n      <svg className=\"ot-attach-ring\" viewBox=\"0 0 22 22\" aria-hidden=\"true\">\n        <circle className=\"ot-attach-track\" cx=\"11\" cy=\"11\" r=\"9.5\" />\n        <circle className=\"ot-attach-arc\" cx=\"11\" cy=\"11\" r=\"9.5\" pathLength=\"1\" />\n        <circle className=\"ot-attach-fill\" cx=\"11\" cy=\"11\" />\n      </svg>\n      {onRemove ? (\n        <Button variant=\"bracket\" aria-label={`${removeLabel} ${name}`} onClick={onRemove}>\n          {removeLabel}\n        </Button>\n      ) : null}\n    </li>\n  )\n}\n\nexport { Attachment, AttachmentList, type AttachmentProps, type AttachmentListProps }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/0nlytype/styles/attachment.css",
      "content": "@layer components {\n  /* ── ot-attach ── a file: its extension is its picture; a ring counts it in */\n  .ot-attachments { list-style: none; margin: 0; padding: 0; border-top: var(--ot-hairline) solid var(--ot-rule); }\n  .ot-attach { display: grid; grid-template-columns: 4.5rem minmax(0, 1fr) auto auto; align-items: center; column-gap: var(--ot-space-4); padding-block: var(--ot-space-3); border-bottom: var(--ot-hairline) solid var(--ot-rule); }\n  .ot-attach-ext { font-size: var(--ot-mf); line-height: 1; font-weight: 200; font-stretch: 125%; color: var(--ot-ink); text-transform: lowercase; }\n  .ot-attach-body { display: grid; min-width: 0; }\n  .ot-attach-name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-family: var(--ot-expression); font-style: italic; font-size: calc(var(--ot-expression-scale) * 1em); line-height: 1.3; color: var(--ot-ink); }\n  .ot-attach-meta { font-size: var(--ot-pp); line-height: var(--ot-pp-lh); color: var(--ot-pencil); font-variant-numeric: tabular-nums; }\n  .ot-attach-ring { width: 22px; height: 22px; overflow: visible; rotate: -90deg; }\n  .ot-attach-ring circle { fill: none; stroke-width: 1.5; }\n  .ot-attach-track { stroke: var(--ot-rule); transition: stroke-opacity var(--ot-moderato) var(--ot-breath) var(--ot-moderato); }\n  .ot-attach-arc { stroke: var(--ot-ink); stroke-dasharray: 1; stroke-dashoffset: calc(1 - var(--p, 0)); transition: stroke-dashoffset var(--ot-moderato) var(--ot-breath), stroke var(--ot-allegro), stroke-opacity var(--ot-moderato) var(--ot-breath) var(--ot-moderato); }\n  .ot-attach-ring .ot-attach-fill { fill: var(--ot-ink); stroke: none; r: 0; transition: r var(--ot-moderato) var(--ot-spiccato) var(--ot-moderato); }\n  .ot-attach[data-state=\"processing\"] .ot-attach-arc { --p: 1; stroke: var(--ot-pencil); }\n  .ot-attach[data-state=\"done\"] .ot-attach-arc { --p: 1; }\n  /* Safe, the ring closes and gives way to a full stop: a ring round a dot would read as a chosen radio. */\n  .ot-attach[data-state=\"done\"] :is(.ot-attach-track, .ot-attach-arc) { stroke-opacity: 0; }\n  .ot-attach[data-state=\"done\"] .ot-attach-fill { r: calc(var(--ot-dot) / 2); }\n  .ot-attach[data-state=\"error\"] .ot-attach-arc { stroke: var(--ot-signal); }\n  .ot-attach[data-state=\"error\"] .ot-attach-meta { color: var(--ot-signal); }\n  .ot-attach > .ot-btn { font-size: var(--ot-pp); }\n  @media (max-width: 30rem) {\n    .ot-attach { grid-template-columns: 3.4rem minmax(0, 1fr) auto auto; }\n    .ot-attach-ext { font-size: var(--ot-mp); }\n    /* Narrow, Remove steps down under the name, so the name keeps the width. */\n    .ot-attach > .ot-btn { grid-column: 2 / -1; justify-self: start; }\n  }\n\n  /* ── reverse ── after \"the uncreative\": the extension reversed out of an ink block. The block prints across the\n     letters as the file arrives (--p), so each letter turns from ink on paper to paper on ink. Checking, the block\n     is pencil; safe, it is ink; failed, it stops in crimson where the connection dropped. */\n  .ot-attachments[data-variant=\"reverse\"] .ot-attach { grid-template-columns: 4.5rem minmax(0, 1fr) auto; }\n  .ot-attachments[data-variant=\"reverse\"] .ot-attach-ring { display: none; }\n  .ot-attachments[data-variant=\"reverse\"] .ot-attach-ext {\n    position: relative; justify-self: start; padding: 0.06em 0.12em 0.12em;\n    font-weight: 700; font-stretch: 100%; letter-spacing: -0.04em;\n  }\n  .ot-attachments[data-variant=\"reverse\"] .ot-attach-ext::after {\n    content: attr(data-ext) / \"\"; position: absolute; inset: 0; padding: inherit; background: var(--ot-ink); color: var(--ot-paper);\n    clip-path: inset(0 calc((1 - var(--p, 0)) * 100%) 0 0); transition: clip-path var(--ot-moderato) var(--ot-breath), background-color var(--ot-moderato);\n  }\n  :is([dir=\"rtl\"], [dir=\"rtl\"] *) .ot-attachments[data-variant=\"reverse\"] .ot-attach-ext::after { clip-path: inset(0 0 0 calc((1 - var(--p, 0)) * 100%)); }\n  .ot-attachments[data-variant=\"reverse\"] .ot-attach:is([data-state=\"processing\"], [data-state=\"done\"]) { --p: 1; }\n  .ot-attachments[data-variant=\"reverse\"] .ot-attach[data-state=\"processing\"] .ot-attach-ext::after { background: var(--ot-pencil); }\n  .ot-attachments[data-variant=\"reverse\"] .ot-attach[data-state=\"error\"] .ot-attach-ext::after { background: var(--ot-signal); }\n  @media (max-width: 30rem) {\n    .ot-attachments[data-variant=\"reverse\"] .ot-attach { grid-template-columns: 3.4rem minmax(0, 1fr); }\n  }\n  @media (forced-colors: active) {\n    .ot-attachments[data-variant=\"reverse\"] .ot-attach-ext::after { forced-color-adjust: none; background: CanvasText; color: Canvas; }\n  }\n\n  /* ── enclosure ── the letter's enclosure line: \"Encl. (2)\", then each file run on in one sentence, the name yours in\n     italic and its size in parentheses, a semicolon between and a full stop at the end. The ring stays only while a\n     file is on its way. */\n  .ot-attachments[data-variant=\"enclosure\"] { border-top: 0; font-size: var(--ot-p); line-height: var(--ot-p-lh); color: var(--ot-pencil); }\n  .ot-attachments[data-variant=\"enclosure\"]::before { content: attr(data-enclosure-label) \"\\00a0(\" attr(data-count) \")\\00a0\\00a0\" / \"\"; color: var(--ot-graphite); }\n  .ot-attachments[data-variant=\"enclosure\"] > .ot-attach { display: inline; padding: 0; border: 0; }\n  .ot-attachments[data-variant=\"enclosure\"] > .ot-attach:not(:last-child)::after { content: \";\" / \"\"; margin-inline-end: 0.3em; }\n  .ot-attachments[data-variant=\"enclosure\"] > .ot-attach:last-child::after { content: \".\" / \"\"; }\n  .ot-attachments[data-variant=\"enclosure\"] :is(.ot-attach-ext, .ot-attach[data-state=\"done\"] .ot-attach-ring) { display: none; }\n  .ot-attachments[data-variant=\"enclosure\"] :is(.ot-attach-body, .ot-attach-name, .ot-attach-meta) { display: inline; font-size: inherit; line-height: inherit; }\n  .ot-attachments[data-variant=\"enclosure\"] .ot-attach-name { white-space: normal; overflow-wrap: anywhere; font-size: calc(var(--ot-expression-scale) * 1em); line-height: 1; }\n  .ot-attachments[data-variant=\"enclosure\"] .ot-attach-meta { white-space: normal; overflow-wrap: anywhere; }\n  .ot-attachments[data-variant=\"enclosure\"] .ot-attach-meta::before { content: \"(\" / \"\"; }\n  .ot-attachments[data-variant=\"enclosure\"] .ot-attach-meta::after { content: \")\" / \"\"; }\n  .ot-attachments[data-variant=\"enclosure\"] .ot-attach-ring { display: inline; width: 0.7em; height: 0.7em; margin-inline-start: 0.35em; vertical-align: -0.05em; }\n  .ot-attachments[data-variant=\"enclosure\"] .ot-attach > .ot-btn { display: inline-flex; margin-inline-start: 0.35em; vertical-align: baseline; }\n}\n",
      "type": "registry:file",
      "target": "styles/0nlytype/attachment.css"
    }
  ],
  "css": {
    "@import \"../styles/0nlytype/attachment.css\"": {}
  },
  "meta": {
    "movement": "XI",
    "underneath": "native",
    "contract": "ot-attach"
  },
  "type": "registry:ui"
}
