{"version":3,"file":"remote.mjs","names":[],"sources":["../../../../../../../src/lib/react/remote.ts"],"sourcesContent":["import type {\n  RemoteComponentRendererProps,\n  RemoteTextRendererProps,\n} from \"@mittwald/remote-dom-react/host\";\nimport { isNumber, isObjectType, isString } from \"remeda\";\nimport {\n  Children,\n  Fragment,\n  isValidElement,\n  type PropsWithChildren,\n  type ReactNode,\n} from \"react\";\n\nexport function isRemoteComponentRendererProps(\n  props: unknown,\n): props is RemoteComponentRendererProps {\n  return (\n    isObjectType(props) &&\n    \"element\" in props &&\n    \"components\" in props &&\n    \"receiver\" in props\n  );\n}\n\n/**\n * The text `children` are _themselves_ — plain strings and numbers locally,\n * `RemoteTextRenderer` elements remotely — joined and trimmed. `undefined` when\n * there is none.\n *\n * Text inside an element child is deliberately left out, because it belongs to\n * that element rather than to the component being described:\n * `<Option>Millennium Falcon <Badge>Latest</Badge></Option>` is the option\n * \"Millennium Falcon\", not \"Millennium Falcon Latest\". A fragment is grouping\n * rather than rendered output, so this looks through it.\n *\n * Use this over {@link extractTextFromFirstChild} when the question is \"what\n * does this read as\", not \"are the children one single text node\".\n */\nexport const extractTextFromChildren = (\n  children: ReactNode,\n): string | undefined => {\n  const text = joinTextChildren(children).trim();\n\n  return text === \"\" ? undefined : text;\n};\n\nconst joinTextChildren = (children: ReactNode): string =>\n  Children.toArray(children)\n    .map((child) => {\n      if (isString(child) || isNumber(child)) {\n        return String(child);\n      }\n\n      if (!isValidElement(child)) {\n        return \"\";\n      }\n\n      if (isRemoteTextRenderProps(child.props)) {\n        return child.props.remote.data;\n      }\n\n      return child.type === Fragment\n        ? joinTextChildren((child.props as PropsWithChildren).children)\n        : \"\";\n    })\n    .join(\"\");\n\n/**\n * Whether `children` render any text of their own — what `Button` and `Link`\n * ask to tell a labelled control from an icon-only one. The same reading as\n * {@link extractTextFromChildren}, so fragments are transparent and children\n * that are only whitespace do not count as a label.\n */\nexport const containsTextChild = (children: ReactNode): boolean =>\n  extractTextFromChildren(children) !== undefined;\n\n/**\n * The text of `children` when they are exactly one text node — locally a\n * string, remotely a `RemoteTextRenderer` element. `undefined` for anything\n * else, including a single string next to anything at all.\n *\n * That strictness is the point for its callers: `Markdown` takes it as the\n * markdown source, and `Initials` and `Truncate` operate on the whole content.\n * For \"what does this read as\", use {@link extractTextFromChildren}.\n */\nexport const extractTextFromFirstChild = (children: ReactNode) => {\n  if (Children.count(children) !== 1) {\n    return undefined;\n  }\n\n  const firstChild = Children.toArray(children)[0];\n\n  return typeof firstChild === \"string\"\n    ? firstChild\n    : isValidElement(firstChild) && isRemoteTextRenderProps(firstChild.props)\n      ? firstChild.props.remote.data\n      : undefined;\n};\n\nexport function isRemoteTextRenderProps(\n  props: unknown,\n): props is RemoteTextRendererProps {\n  return (\n    isObjectType(props) &&\n    \"remote\" in props &&\n    isObjectType(props.remote) &&\n    \"data\" in props.remote &&\n    isString(props.remote.data)\n  );\n}\n"],"mappings":";;;;;AAaA,SAAgB,+BACd,OACuC;CACvC,OACE,aAAa,KAAK,KAClB,aAAa,SACb,gBAAgB,SAChB,cAAc;AAElB;;;;;;;;;;;;;;;AAgBA,IAAa,2BACX,aACuB;CACvB,MAAM,OAAO,iBAAiB,QAAQ,CAAC,CAAC,KAAK;CAE7C,OAAO,SAAS,KAAK,KAAA,IAAY;AACnC;AAEA,IAAM,oBAAoB,aACxB,SAAS,QAAQ,QAAQ,CAAC,CACvB,KAAK,UAAU;CACd,IAAI,SAAS,KAAK,KAAK,SAAS,KAAK,GACnC,OAAO,OAAO,KAAK;CAGrB,IAAI,CAAC,eAAe,KAAK,GACvB,OAAO;CAGT,IAAI,wBAAwB,MAAM,KAAK,GACrC,OAAO,MAAM,MAAM,OAAO;CAG5B,OAAO,MAAM,SAAS,WAClB,iBAAkB,MAAM,MAA4B,QAAQ,IAC5D;AACN,CAAC,CAAC,CACD,KAAK,EAAE;;;;;;;AAQZ,IAAa,qBAAqB,aAChC,wBAAwB,QAAQ,MAAM,KAAA;;;;;;;;;;AAWxC,IAAa,6BAA6B,aAAwB;CAChE,IAAI,SAAS,MAAM,QAAQ,MAAM,GAC/B;CAGF,MAAM,aAAa,SAAS,QAAQ,QAAQ,CAAC,CAAC;CAE9C,OAAO,OAAO,eAAe,WACzB,aACA,eAAe,UAAU,KAAK,wBAAwB,WAAW,KAAK,IACpE,WAAW,MAAM,OAAO,OACxB,KAAA;AACR;AAEA,SAAgB,wBACd,OACkC;CAClC,OACE,aAAa,KAAK,KAClB,YAAY,SACZ,aAAa,MAAM,MAAM,KACzB,UAAU,MAAM,UAChB,SAAS,MAAM,OAAO,IAAI;AAE9B"}