tmp/webapp-docs/frontend/components/ProviderPicker.js

/**
 * A rich, grouped provider picker — a custom dropdown (not a native combo) with a leading label, a
 * one-line description per option, and a "key" badge for BYOK ones. Reused for both rows of the
 * header Providers menu (the image provider and the text/rewrite provider). The parent owns the
 * selection: pass `value` + grouped `groups` and get `onPick(id)`.
 * @module gui/components/ProviderPicker
 */
import { useState } from "react";
import { useIntl, defineMessages } from "react-intl";
import { lockedHint, openFullVersion } from "../lib/online.js";
import { jsxDEV as _jsxDEV, Fragment as _Fragment } from "react/jsx-dev-runtime";
const msgs = defineMessages({
  providerTitle: {
    id: "providerPicker.title",
    defaultMessage: "{label} provider",
    description: "Tooltip on the provider dropdown trigger (label = Image/Text)"
  },
  lockBadge: {
    id: "providerPicker.lockBadge",
    defaultMessage: "🔒 full version",
    description: "Badge on a provider only available in the full desktop version"
  },
  keyBadge: {
    id: "providerPicker.keyBadge",
    defaultMessage: "key",
    description: "Badge marking a provider that needs a bring-your-own API key"
  },
  softLock: {
    id: "providerPicker.softLock",
    defaultMessage: "NSFW mode is on — {label} is a safe-for-work service",
    description: "Neutral soft-lock tooltip (never says the user can't use it)"
  }
});

/**
 * @param {object} props
 * @param {string} props.label Leading label shown on the trigger (e.g. "Image" / "Text").
 * @param {string} props.value The selected option id.
 * @param {Array<{title:string, items:Array<{id:string,label:string,needsKey?:boolean,description?:string,locked?:boolean}>}>} props.groups
 *   Grouped options. A `locked` option is shown greyed and, when clicked, opens the full version
 *   instead of being selected.
 * @param {Function} props.onPick `(id)` — called when an option is chosen.
 * @returns {JSX.Element}
 */
export default function ProviderPicker({
  label,
  value,
  groups,
  onPick,
  locked,
  lockReason,
  hint
}) {
  const intl = useIntl();
  const [open, setOpen] = useState(false);
  const all = groups.flatMap(g => g.items);
  const current = all.find(it => it.id === value) || all[0];
  const choose = id => {
    onPick(id);
    setOpen(false);
  };
  return /*#__PURE__*/_jsxDEV("div", {
    className: "provider-select provider-picker",
    children: [/*#__PURE__*/_jsxDEV("button", {
      className: `ps-trigger${locked ? " is-locked" : ""}`,
      onClick: () => locked ? openFullVersion() : setOpen(o => !o),
      title: locked ? lockedHint(intl, label, lockReason) : hint || intl.formatMessage(msgs.providerTitle, {
        label
      }),
      "aria-haspopup": "listbox",
      "aria-expanded": locked ? false : open,
      "aria-disabled": locked || undefined,
      children: [/*#__PURE__*/_jsxDEV("span", {
        className: "provider-select-label",
        children: label
      }, void 0, false), /*#__PURE__*/_jsxDEV("span", {
        className: "ps-current",
        children: current?.label
      }, void 0, false), locked ? /*#__PURE__*/_jsxDEV("span", {
        className: "ps-lock",
        "aria-hidden": "true",
        children: "🔒"
      }, void 0, false) : /*#__PURE__*/_jsxDEV("span", {
        className: "ps-caret",
        children: "▾"
      }, void 0, false)]
    }, void 0, true), !locked && open && /*#__PURE__*/_jsxDEV(_Fragment, {
      children: [/*#__PURE__*/_jsxDEV("div", {
        className: "ps-scrim",
        onClick: () => setOpen(false)
      }, void 0, false), /*#__PURE__*/_jsxDEV("div", {
        className: "ps-pop",
        role: "listbox",
        children: groups.filter(g => g.items.length).map(g => /*#__PURE__*/_jsxDEV("div", {
          className: "ps-group",
          children: [/*#__PURE__*/_jsxDEV("div", {
            className: "ps-group-title",
            children: g.title
          }, void 0, false), g.items.map(it => /*#__PURE__*/_jsxDEV("button", {
            className: `ps-item${it.id === value ? " on" : ""}${it.locked ? " is-locked" : ""}${it.softLock ? " is-soft" : ""}`,
            "aria-disabled": it.locked || undefined,
            title: it.locked ? lockedHint(intl, it.label, it.lockReason) : it.softLock ? intl.formatMessage(msgs.softLock, {
              label: it.label
            }) : undefined,
            onClick: () => it.locked ? openFullVersion() : choose(it.id),
            children: [/*#__PURE__*/_jsxDEV("span", {
              className: "ps-item-head",
              children: [/*#__PURE__*/_jsxDEV("span", {
                className: "ps-item-label",
                children: [it.softLock && /*#__PURE__*/_jsxDEV("span", {
                  className: "ps-soft",
                  "aria-hidden": "true",
                  title: intl.formatMessage(msgs.softLock, {
                    label: it.label
                  }),
                  children: "🔒"
                }, void 0, false), it.label]
              }, void 0, true), it.locked ? /*#__PURE__*/_jsxDEV("span", {
                className: "ps-lock",
                children: intl.formatMessage(msgs.lockBadge)
              }, void 0, false) : it.needsKey && /*#__PURE__*/_jsxDEV("span", {
                className: "ps-key",
                children: intl.formatMessage(msgs.keyBadge)
              }, void 0, false)]
            }, void 0, true), it.description && /*#__PURE__*/_jsxDEV("span", {
              className: "ps-item-desc",
              children: it.description
            }, void 0, false)]
          }, it.id, true))]
        }, g.title, true))
      }, void 0, false)]
    }, void 0, true)]
  }, void 0, true);
}