@blakesteve/roster 5.3.0 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +177 -1
  2. package/dist/components/atoms/Button/Button.cjs +1 -1
  3. package/dist/components/atoms/Button/Button.d.ts +11 -0
  4. package/dist/components/atoms/Button/Button.js +42 -32
  5. package/dist/components/atoms/Button/button-variants.cjs +1 -1
  6. package/dist/components/atoms/Button/button-variants.js +3 -1
  7. package/dist/components/molecules/FileUpload/FileUpload.cjs +1 -0
  8. package/dist/components/molecules/FileUpload/FileUpload.d.ts +111 -0
  9. package/dist/components/molecules/FileUpload/FileUpload.js +403 -0
  10. package/dist/components/molecules/FileUpload/file-rules.cjs +1 -0
  11. package/dist/components/molecules/FileUpload/file-rules.d.ts +22 -0
  12. package/dist/components/molecules/FileUpload/file-rules.js +43 -0
  13. package/dist/components/molecules/MediaPreview/MediaPreview.cjs +1 -0
  14. package/dist/components/molecules/MediaPreview/MediaPreview.d.ts +27 -0
  15. package/dist/components/molecules/MediaPreview/MediaPreview.js +55 -0
  16. package/dist/components/organisms/Dialog/Dialog.cjs +1 -1
  17. package/dist/components/organisms/Dialog/Dialog.d.ts +9 -1
  18. package/dist/components/organisms/Dialog/Dialog.js +26 -24
  19. package/dist/components/organisms/ModerationQueue/ModerationQueue.cjs +1 -0
  20. package/dist/components/organisms/ModerationQueue/ModerationQueue.d.ts +73 -0
  21. package/dist/components/organisms/ModerationQueue/ModerationQueue.js +428 -0
  22. package/dist/components/organisms/ModerationQueue/QueueEditDialog.cjs +1 -0
  23. package/dist/components/organisms/ModerationQueue/QueueEditDialog.d.ts +8 -0
  24. package/dist/components/organisms/ModerationQueue/QueueEditDialog.js +37 -0
  25. package/dist/components/organisms/ModerationQueue/QueueEditSheet.cjs +1 -0
  26. package/dist/components/organisms/ModerationQueue/QueueEditSheet.d.ts +12 -0
  27. package/dist/components/organisms/ModerationQueue/QueueEditSheet.js +30 -0
  28. package/dist/components/organisms/ModerationQueue/queue-actions.cjs +1 -0
  29. package/dist/components/organisms/ModerationQueue/queue-actions.d.ts +157 -0
  30. package/dist/components/organisms/ModerationQueue/queue-actions.js +6 -0
  31. package/dist/components/organisms/Navbar/Navbar.cjs +1 -1
  32. package/dist/components/organisms/Navbar/Navbar.d.ts +2 -0
  33. package/dist/components/organisms/Navbar/Navbar.js +49 -49
  34. package/dist/index.d.ts +6 -0
  35. package/dist/meta.json +3 -3
  36. package/dist/roster.cjs +1 -1
  37. package/dist/roster.css +1 -1
  38. package/dist/roster.js +123 -111
  39. package/package.json +4 -3
@@ -1,14 +1,14 @@
1
1
  "use client";
2
- import { jsxs as t, Fragment as h, jsx as r } from "react/jsx-runtime";
3
- import { useState as k, useLayoutEffect as c, useRef as w, Fragment as d } from "react";
4
- import { FontAwesomeIcon as N } from "../../../node_modules/@fortawesome/react-fontawesome/dist/index.js";
5
- import { faXmark as _ } from "../../../node_modules/@fortawesome/free-solid-svg-icons/index.js";
2
+ import { jsxs as t, Fragment as k, jsx as r } from "react/jsx-runtime";
3
+ import { useState as w, useLayoutEffect as c, useRef as N, Fragment as d } from "react";
4
+ import { FontAwesomeIcon as _ } from "../../../node_modules/@fortawesome/react-fontawesome/dist/index.js";
5
+ import { faXmark as F } from "../../../node_modules/@fortawesome/free-solid-svg-icons/index.js";
6
6
  import { cva as a } from "../../../node_modules/class-variance-authority/dist/index.js";
7
7
  import { cn as s } from "../../../lib/utils.js";
8
- import { lockPage as F } from "../../../internal/page-inert.js";
9
- import { Dialog as T, DialogBackdrop as j, DialogPanel as z, DialogTitle as D } from "../../../node_modules/@headlessui/react/dist/components/dialog/dialog.js";
8
+ import { lockPage as T } from "../../../internal/page-inert.js";
9
+ import { Dialog as j, DialogBackdrop as z, DialogPanel as D, DialogTitle as V } from "../../../node_modules/@headlessui/react/dist/components/dialog/dialog.js";
10
10
  import { TransitionChild as m } from "../../../node_modules/@headlessui/react/dist/components/transition/transition.js";
11
- const V = /* @__PURE__ */ a(
11
+ const L = /* @__PURE__ */ a(
12
12
  "rst:relative rst:w-full rst:transform rst:overflow-hidden rst:rounded-2xl rst:p-6 rst:text-left rst:align-middle rst:elevation-overlay rst:transition-all rst:border",
13
13
  {
14
14
  variants: {
@@ -77,9 +77,9 @@ const V = /* @__PURE__ */ a(
77
77
  status: "default"
78
78
  }
79
79
  }
80
- ), C = /* @__PURE__ */ a("rst:text-xl rst:font-bold rst:leading-6 rst:text-inherit"), L = /* @__PURE__ */ a("rst:mt-1 rst:text-sm rst:text-inherit rst:opacity-75"), P = /* @__PURE__ */ a(
80
+ ), C = /* @__PURE__ */ a("rst:text-xl rst:font-bold rst:leading-6 rst:text-inherit"), P = /* @__PURE__ */ a("rst:mt-1 rst:text-sm rst:text-inherit rst:opacity-75"), R = /* @__PURE__ */ a(
81
81
  "rst:inline-flex rst:size-11 rst:shrink-0 rst:items-center rst:justify-center rst:-m-3 rst:cursor-pointer rst:rounded-md rst:bg-transparent rst:text-inherit rst:opacity-50 rst:hover:opacity-100 rst:focus:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:ring-offset-background rst:transition-opacity"
82
- ), X = ({
82
+ ), $ = ({
83
83
  isOpen: f,
84
84
  onClose: o,
85
85
  title: p,
@@ -88,20 +88,21 @@ const V = /* @__PURE__ */ a(
88
88
  variant: n,
89
89
  status: g,
90
90
  children: v,
91
- className: u
91
+ className: u,
92
+ onAfterClose: x
92
93
  }) => {
93
- const [x, y] = k(!1);
94
+ const [y, h] = w(!1);
94
95
  c(() => {
95
- y(!0);
96
+ h(!0);
96
97
  }, []);
97
- const e = f && x, l = w(null);
98
+ const e = f && y, l = N(null);
98
99
  return c(() => {
99
100
  if (e)
100
- return F(l.current);
101
- }, [e]), /* @__PURE__ */ t(h, { children: [
101
+ return T(l.current);
102
+ }, [e]), /* @__PURE__ */ t(k, { children: [
102
103
  e && /* @__PURE__ */ r("span", { ref: l, hidden: !0 }),
103
104
  /* @__PURE__ */ t(
104
- T,
105
+ j,
105
106
  {
106
107
  open: e,
107
108
  as: "div",
@@ -119,7 +120,7 @@ const V = /* @__PURE__ */ a(
119
120
  leaveFrom: "rst:opacity-100",
120
121
  leaveTo: "rst:opacity-0",
121
122
  children: /* @__PURE__ */ r(
122
- j,
123
+ z,
123
124
  {
124
125
  className: s(
125
126
  "rst:fixed rst:inset-0 rst:transition-opacity",
@@ -139,27 +140,28 @@ const V = /* @__PURE__ */ a(
139
140
  leave: "rst:ease-in rst:duration-200",
140
141
  leaveFrom: "rst:opacity-100 rst:scale-100",
141
142
  leaveTo: "rst:opacity-0 rst:scale-95",
143
+ afterLeave: x,
142
144
  children: /* @__PURE__ */ t(
143
- z,
145
+ D,
144
146
  {
145
147
  className: s(
146
- V({ size: b, variant: n, status: g }),
148
+ L({ size: b, variant: n, status: g }),
147
149
  u
148
150
  ),
149
151
  children: [
150
152
  /* @__PURE__ */ t("div", { className: "rst:flex rst:items-start rst:justify-between", children: [
151
153
  /* @__PURE__ */ t("div", { children: [
152
- /* @__PURE__ */ r(D, { as: "h2", className: s(C()), children: p }),
153
- i && /* @__PURE__ */ r("p", { className: s(L()), children: i })
154
+ /* @__PURE__ */ r(V, { as: "h2", className: s(C()), children: p }),
155
+ i && /* @__PURE__ */ r("p", { className: s(P()), children: i })
154
156
  ] }),
155
157
  /* @__PURE__ */ r("div", { className: "rst:ml-4 rst:flex rst:shrink-0", children: /* @__PURE__ */ r(
156
158
  "button",
157
159
  {
158
160
  type: "button",
159
161
  onClick: o,
160
- className: s(P()),
162
+ className: s(R()),
161
163
  "aria-label": "Close dialog",
162
- children: /* @__PURE__ */ r(N, { icon: _, className: "rst:h-5 rst:w-5" })
164
+ children: /* @__PURE__ */ r(_, { icon: F, className: "rst:h-5 rst:w-5" })
163
165
  }
164
166
  ) })
165
167
  ] }),
@@ -175,5 +177,5 @@ const V = /* @__PURE__ */ a(
175
177
  ] });
176
178
  };
177
179
  export {
178
- X as Dialog
180
+ $ as Dialog
179
181
  };
@@ -0,0 +1 @@
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react/jsx-runtime"),a=require("react"),P=require("../../../lib/utils.cjs"),ge=require("../../atoms/Button/Button.cjs"),Le=require("../../atoms/Card/Card.cjs"),Oe=require("../../atoms/Spinner/Spinner.cjs"),Pe=require("../../atoms/Textarea/Textarea.cjs"),Y=require("../../molecules/Alert/Alert.cjs"),ze=require("../../molecules/EmptyState/EmptyState.cjs"),De=require("../../molecules/RadioGroup/RadioGroup.cjs"),He=require("./queue-actions.cjs"),me={primary:{colorScheme:"primary",variant:"solid"},success:{colorScheme:"success",variant:"solid"},danger:{colorScheme:"error",variant:"soft"},neutral:{colorScheme:"neutral",variant:"outline"}},Ke={edit:He.editAction},R=c=>c.edit?c:null,Qe=c=>c===0?"None left.":`${c} left.`,Ge=c=>Math.min(6,Math.max(1,c)),We=c=>c instanceof Error&&c.message?c.message:"Something went wrong.";function B(c,d){const p={...c};return delete p[d],p}function Z({busy:c=!1,blocked:d=!1,onClick:p,children:j,className:v,...y}){return n.jsx(ge.Button,{size:"lg",...y,isLoading:c,"aria-disabled":d||void 0,className:P.cn(d&&!c&&"rst:cursor-not-allowed rst:opacity-50",v),onClick:g=>{if(d){g.preventDefault();return}p?.(g)},children:j})}function Je({label:c,hideLabel:d=!1,headingLevel:p=2,itemHeadingLevel:j,items:v,getKey:y,itemLabel:g,renderMeta:xe,renderContent:he,actions:z,status:_="ready",error:ve,onRetry:ee,empty:te={title:"Nothing waiting"},density:re="comfortable",footer:be,className:ye}){const Se=typeof z=="function"?z(Ke):z,N=a.useId(),q=a.useRef(null),k=v.map(y),T=a.useRef(new Map);T.current=new Map(v.map((e,t)=>[k[t],e]));const[D,je]=a.useState({}),$=a.useRef({}),ne=e=>{$.current=e($.current),je($.current)},[se,E]=a.useState({}),[oe,qe]=a.useState({}),x=a.useRef({}),h=(e,t)=>{x.current=t?{...x.current,[e]:t}:B(x.current,e),qe(x.current)},[H,ke]=a.useState({text:"",n:0}),K=a.useRef([]),w=a.useRef(null),ce=a.useCallback(e=>{K.current.push(e),!w.current&&(w.current=setTimeout(()=>{w.current=null;const t=K.current.join(" ");K.current=[],ke(r=>({text:t,n:r.n+1}))},0))},[]);a.useLayoutEffect(()=>()=>{w.current&&clearTimeout(w.current)},[]);const[$e,Re]=a.useState(0),Q=a.useRef(null),S=a.useCallback(e=>{Q.current=e,Re(t=>t+1)},[]),ie=a.useCallback(e=>{const t=q.current;if(!t)return null;const r="key"in e?CSS.escape(e.key):"";switch(e.kind){case"item":return t.querySelector(`[data-queue-item="${r}"]`);case"empty":return t.querySelector("[data-queue-empty]");case"trigger":return t.querySelector(`[data-queue-item="${r}"] [data-queue-action="${CSS.escape(e.actionId)}"]`);case"step":return t.querySelector(`[data-queue-item="${r}"] [data-queue-step]`)}},[]);a.useLayoutEffect(()=>{const e=Q.current;if(!e)return;Q.current=null,(ie(e)??q.current?.querySelector("[data-queue-item]")??q.current?.querySelector("[data-queue-empty]"))?.focus()},[$e,ie]);const G=a.useRef(null),Ne=e=>()=>{G.current=e},we=e=>{e.relatedTarget&&!q.current?.contains(e.relatedTarget)&&(G.current=null)},F=e=>{if(G.current!==e)return!1;const t=document.activeElement;return!t||t===document.body?!0:q.current?.contains(t)?!!t.closest(`[data-queue-item="${CSS.escape(e)}"]`):!1},C=a.useRef(null),A=(e,t)=>{C.current=t,h(e.key,{...e,open:!1})},ae=a.useRef(k),W=a.useRef(new Map),[,Ce]=a.useState(0),J=a.useRef(new Set),ue=(e,t,r)=>{const o=t.indexOf(e),f=t.slice(o+1).find(i=>r.has(i));if(f)return{kind:"item",key:f};const s=t.slice(0,o).reverse().find(i=>r.has(i));return s?{kind:"item",key:s}:{kind:"empty"}};a.useLayoutEffect(()=>{const e=ae.current;ae.current=k;const t=new Set(k),r=W.current;W.current=new Map;const o=[];let f=!1;for(const[s,i]of r){const u=t.has(s);o.push(i.announce??i.sentence),u||(f=!0),J.current.delete(s);const l=u?{kind:"trigger",key:s,actionId:i.actionId}:e.includes(s)?ue(s,e,t):null,m=x.current[s];if(m?.surface)A(m,l??{kind:"empty"});else{const I=F(s);m&&h(s,null),l&&I&&S(l)}}for(const s of e.filter(i=>!t.has(i))){if(r.has(s))continue;E(m=>s in m?B(m,s):m);const i=ue(s,e,t),u=C.current;if(u&&"key"in u&&u.key===s&&(C.current=i),$.current[s]){J.current.add(s),F(s)&&S(i);continue}const l=x.current[s];if(l&&!(l.surface&&!l.open))if(o.push(`${l.label} was decided elsewhere.`),f=!0,l.surface)A(l,i);else{const m=F(s);h(s,null),m&&S(i)}else!l&&F(s)&&S(i)}o.length&&ce(`${o.join(" ")}${f?` ${Qe(k.length)}`:""}`)});const M=async(e,t,r,o)=>{const f=T.current.get(e)??t,s=g(f),i=r.edit?R(r).run:r.run;ne(u=>({...u,[e]:r.id})),E(u=>B(u,e));try{const u=await i(f,o);W.current.set(e,{actionId:r.id,sentence:`${r.done??r.label}: ${s}.`,announce:u?u.announce:void 0}),Ce(l=>l+1)}catch(u){const l=We(u);ce(`${r.label} didn't go through for ${s}. ${l}`);const m=x.current[e];J.current.delete(e)?m?.surface?A(m,{kind:"empty"}):m&&h(e,null):m?h(e,{...m,error:l}):E(I=>({...I,[e]:l}))}finally{ne(u=>B(u,e))}},Ie=(e,t)=>{const r=y(e),o=R(t);if(!t.confirm&&!t.reason&&!o){M(r,e,t,{});return}E(f=>B(f,r)),h(r,{key:r,label:g(e),item:e,action:t,draft:o?o.edit.initial(e):void 0,reason:{},surface:!!o?.edit.surface,open:!0}),o?.edit.surface||S({kind:"step",key:r})},U=e=>{const t=x.current[e];if(!t||$.current[e])return;const r={kind:"trigger",key:e,actionId:t.action.id};t.surface?A(t,r):(h(e,null),S(r))},Be=e=>{const t=x.current[e];!t||$.current[e]||pe(t,T.current.get(e)??t.item)||(t.action.edit?M(e,t.item,t.action,{draft:t.draft}):t.action.reason?M(e,t.item,t.action,{reason:Ue(t.reason)}):M(e,t.item,t.action,{}))},Te=e=>{const t=C.current;C.current=null,h(e,null),t&&S(t)},Ee=`h${p}`,le=j??Ge(p+1),Fe=`h${le}`,V=`${N}-label`,de=(e,t)=>{const{action:r}=e,o=R(r),f=T.current.get(e.key)??e.item,s=!!D[e.key],i=pe(e,f),u=`${N}-step-${t}-message`,l=n.jsx(Z,{...me[r.tone??"neutral"],busy:s,blocked:!!i,"aria-describedby":i?u:void 0,onClick:()=>Be(e.key),"data-queue-submit":"",children:o?o.edit.submitLabel:r.label}),m=n.jsx(Z,{variant:"ghost",colorScheme:"neutral",blocked:s,onClick:()=>U(e.key),children:"Cancel"}),I=n.jsxs(n.Fragment,{children:[r.reason&&n.jsx(Ve,{id:`${N}-step-${t}`,step:r.reason,value:e.reason,disabled:s,onChange:X=>h(e.key,{...x.current[e.key],reason:X})}),o&&n.jsx(o.edit.Form,{item:f,value:e.draft,onChange:X=>h(e.key,{...x.current[e.key],draft:X})}),i&&n.jsx("p",{id:u,className:"rst:text-sm rst:text-error-600 rst:dark:text-error-400","data-queue-validation":"",children:i}),e.error&&n.jsx(Y.Alert,{colorScheme:"error",role:"group","aria-live":"off",children:e.error})]});return{submitButton:l,cancelButton:m,fields:I}},Ae=(e,t)=>{const{submitButton:r,cancelButton:o,fields:f}=de(e,t),s=`${N}-step-${t}-prompt`,i=R(e.action),u=e.action.confirm?.prompt??e.action.reason?.prompt??i?.edit.title;return n.jsxs("div",{role:"group","aria-labelledby":s,tabIndex:-1,"data-queue-step":"",onKeyDown:l=>{l.key==="Escape"&&(l.stopPropagation(),U(e.key))},className:"rst:flex rst:flex-col rst:gap-3 rst:rounded-lg rst:border rst:border-[var(--roster-card-border)] rst:p-4 rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring",children:[n.jsx("p",{id:s,className:"rst:text-sm rst:font-medium rst:text-[var(--roster-control-text)]",children:u}),i?.edit.description&&n.jsx("p",{className:"rst:text-sm rst:text-gray-600 rst:dark:text-gray-300",children:i.edit.description}),f,n.jsxs("div",{className:"rst:flex rst:flex-wrap rst:gap-2",children:[r,o]})]})},Me=(e,t)=>{const r=D[t];return n.jsx("div",{role:"group","aria-label":`Decide: ${g(e)}`,className:"rst:flex rst:flex-wrap rst:gap-2",children:Se.filter(o=>!o.hidden?.(e)).map(o=>n.jsx(Z,{...me[o.tone??"neutral"],"data-queue-action":o.id,busy:r===o.id,blocked:!!r&&r!==o.id,onClick:()=>Ie(e,o),children:o.label},o.id))})},b=Object.values(oe).find(e=>e.surface)??null,L=b?R(b.action):null,fe=L?.edit.surface,O=b?de(b,-1):null;return n.jsxs("section",{ref:q,"aria-labelledby":V,onBlur:we,className:P.cn("rst:font-ui rst:flex rst:flex-col rst:gap-4",ye),children:[n.jsx(Ee,{id:V,className:P.cn("rst:text-lg rst:font-semibold rst:text-[var(--roster-control-text)]",d&&"rst:sr-only"),children:c}),n.jsxs("div",{role:"status","aria-live":"polite","aria-atomic":"true",className:"rst:sr-only","data-queue-live":"","data-queue-live-n":H.n,children:[H.text,H.n%2?" ":""]}),_==="loading"?n.jsx("div",{className:"rst:flex rst:justify-center rst:py-12","aria-busy":"true",children:n.jsx(Oe.Spinner,{size:"lg",label:`Loading ${c}`})}):_==="error"?n.jsx(Y.Alert,{colorScheme:"error",children:n.jsxs("div",{className:"rst:flex rst:flex-col rst:items-start rst:gap-3",children:[n.jsx("div",{children:ve??"The queue couldn't load."}),ee&&n.jsx(ge.Button,{size:"lg",variant:"outline",colorScheme:"neutral",onClick:ee,children:"Retry"})]})}):v.length===0?n.jsx(ze.EmptyState,{title:te.title,description:te.description,headingLevel:le,tabIndex:-1,"data-queue-empty":"",className:"rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring"}):n.jsx("ul",{role:"list","aria-labelledby":V,className:"rst:m-0 rst:flex rst:list-none rst:flex-col rst:gap-3 rst:p-0",children:v.map((e,t)=>{const r=k[t],o=`${N}-item-${t}`,f=xe?.(e),s=oe[r];return n.jsx("li",{children:n.jsx("article",{"data-queue-item":r,tabIndex:-1,"aria-labelledby":o,onFocus:Ne(r),className:"rst:rounded-xl rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:ring-offset-background",children:n.jsx(Le.Card,{padding:re==="compact"?"sm":"md",children:n.jsxs("div",{className:P.cn("rst:flex rst:flex-col",re==="compact"?"rst:gap-3":"rst:gap-4"),children:[n.jsxs("div",{className:"rst:flex rst:flex-wrap rst:items-baseline rst:gap-x-3 rst:gap-y-1",children:[n.jsx(Fe,{id:o,className:"rst:text-base rst:font-semibold",children:g(e)}),f&&n.jsx("div",{className:"rst:flex rst:flex-wrap rst:items-center rst:gap-2 rst:text-sm rst:text-gray-600 rst:dark:text-gray-300",children:f})]}),n.jsx("div",{className:"rst:min-w-0",children:he(e)}),se[r]&&n.jsx(Y.Alert,{colorScheme:"error",role:"group","aria-live":"off",children:se[r]}),s&&!s.surface?Ae(s,t):Me(e,r)]})})})},r)})}),be,fe&&b&&L&&O&&n.jsx(fe,{open:b.open,title:L.edit.title,description:L.edit.description,busy:!!D[b.key],onCancel:()=>U(b.key),onAfterClose:()=>Te(b.key),submitButton:O.submitButton,cancelButton:O.cancelButton,children:n.jsx("div",{className:"rst:flex rst:flex-col rst:gap-4",children:O.fields})})]})}function pe(c,d){const p=R(c.action);if(p)return p.edit.validate?.(c.draft,d);if(c.action.reason){if(c.action.reason.required&&!c.reason.value)return"Pick a reason.";if(c.action.reason.note==="required"&&!c.reason.note?.trim())return"Add a note."}}function Ue(c){const d=c.note?.trim();return{...c.value?{value:c.value}:{},...d?{note:d}:{}}}function Ve({id:c,step:d,value:p,disabled:j,onChange:v}){const y=d.note??"optional";return n.jsxs(n.Fragment,{children:[d.options&&d.options.length>0&&n.jsx(De.RadioGroup,{label:d.required?"Reason":"Reason (optional)",options:d.options,value:p.value??"",onChange:g=>v({...p,value:g}),disabled:j}),y!=="none"&&n.jsx(Pe.Textarea,{id:`${c}-note`,label:d.noteLabel??(y==="required"?"Note":"Note (optional)"),rows:3,value:p.note??"",onChange:g=>v({...p,note:g.target.value}),disabled:j})]})}exports.ModerationQueue=Je;
@@ -0,0 +1,73 @@
1
+ import { ReactNode } from 'react';
2
+ import { QueueAction, QueueActionKit, QueueCheckedEditAction, QueueHeadingLevel } from './queue-actions';
3
+ export interface ModerationQueueProps<T> {
4
+ /** The queue's heading, and the list's accessible name. */
5
+ label: string;
6
+ /** Keep the heading for assistive technology only, when the page already titles the queue. */
7
+ hideLabel?: boolean;
8
+ /** The queue heading's level. `2` by default. */
9
+ headingLevel?: QueueHeadingLevel;
10
+ /** Each item's heading level. One below `headingLevel` by default. */
11
+ itemHeadingLevel?: QueueHeadingLevel;
12
+ /** What's waiting. Remove an item once its decision lands; the queue notices. */
13
+ items: readonly T[];
14
+ getKey: (item: T) => string;
15
+ /** The item's heading, and what announcements call it: "Recipe from Dana". */
16
+ itemLabel: (item: T) => string;
17
+ /** Beside the heading: badges, a time, who sent it. */
18
+ renderMeta?: (item: T) => ReactNode;
19
+ /** The item's body: its text, its previews, links out. */
20
+ renderContent: (item: T) => ReactNode;
21
+ /**
22
+ * What a reviewer can decide. A list, or a function returning one: the
23
+ * function form is handed `edit`, which types an edit action's draft, and
24
+ * is the one to use inline in JSX.
25
+ *
26
+ * actions={(a) => [
27
+ * { id: "approve", label: "Approve", run: (r) => approve(r.id) },
28
+ * a.edit({ id: "edit", label: "Edit", edit: { initial: (r) => ({ … }), … },
29
+ * run: (r, { draft }) => save(r.id, draft) }),
30
+ * ]}
31
+ */
32
+ actions: readonly QueueAction<T>[] | ((kit: QueueActionKit<T>) => readonly QueueAction<T>[]);
33
+ /** `"loading"` before the first answer, `"error"` when the queue itself can't load. */
34
+ status?: "ready" | "loading" | "error";
35
+ /** The whole-queue error, shown with a Retry when `onRetry` is passed. */
36
+ error?: ReactNode;
37
+ onRetry?: () => void;
38
+ empty?: {
39
+ title: string;
40
+ description?: string;
41
+ };
42
+ density?: "comfortable" | "compact";
43
+ /** After the list: "Load more", if the app pages. */
44
+ footer?: ReactNode;
45
+ className?: string;
46
+ }
47
+ /**
48
+ * A queue of things waiting for a decision: submissions to approve, reports to
49
+ * resolve, claims to check before they publish.
50
+ *
51
+ * The app owns the data and every request; this owns the layout, the states,
52
+ * the steps and the keyboard. It never fetches. An action's `run` is the only
53
+ * path from a decision to the network, and the app says whether the item has
54
+ * left by removing it from `items`.
55
+ *
56
+ * What it promises, each pinned in ModerationQueue.checks.stories.tsx:
57
+ * - Only the clicked action is busy, and it keeps focus while it is. That
58
+ * item's other actions wait; every other item stays live.
59
+ * - A decision that lands and removes the item is announced with how many
60
+ * are left, and focus moves to the next item, the previous one, or the
61
+ * empty state. Never to the page.
62
+ * - A decision that fails leaves the item where it was, says why, and leaves
63
+ * focus on the button that tried. A step stays open with its draft.
64
+ * - Confirm, reason and edit steps open in place (an edit may open in a
65
+ * Dialog or Sheet instead), take focus, and give it back on Escape.
66
+ * - An item that disappears for any other reason, with its step open,
67
+ * closes the step without deciding and is announced once as decided
68
+ * elsewhere. Focus moves only if it was inside the item.
69
+ * - Several outcomes in one render are said in one sentence.
70
+ */
71
+ declare function ModerationQueue<T>({ label, hideLabel, headingLevel, itemHeadingLevel, items, getKey, itemLabel, renderMeta, renderContent, actions: actionsProp, status, error, onRetry, empty, density, footer, className, }: ModerationQueueProps<T>): import("react/jsx-runtime").JSX.Element;
72
+ export type { QueueCheckedEditAction };
73
+ export { ModerationQueue };
@@ -0,0 +1,428 @@
1
+ "use client";
2
+ import { jsxs as y, jsx as c, Fragment as xe } from "react/jsx-runtime";
3
+ import { useId as He, useRef as p, useState as C, useCallback as _, useLayoutEffect as ee } from "react";
4
+ import { cn as D } from "../../../lib/utils.js";
5
+ import { Button as ye } from "../../atoms/Button/Button.js";
6
+ import { Card as Ke } from "../../atoms/Card/Card.js";
7
+ import { Spinner as Qe } from "../../atoms/Spinner/Spinner.js";
8
+ import { Textarea as Ge } from "../../atoms/Textarea/Textarea.js";
9
+ import { Alert as te } from "../../molecules/Alert/Alert.js";
10
+ import { EmptyState as We } from "../../molecules/EmptyState/EmptyState.js";
11
+ import { RadioGroup as Je } from "../../molecules/RadioGroup/RadioGroup.js";
12
+ import { editAction as Ue } from "./queue-actions.js";
13
+ const ve = {
14
+ primary: { colorScheme: "primary", variant: "solid" },
15
+ success: { colorScheme: "success", variant: "solid" },
16
+ danger: { colorScheme: "error", variant: "soft" },
17
+ neutral: { colorScheme: "neutral", variant: "outline" }
18
+ }, Ve = { edit: Ue }, I = (o) => o.edit ? o : null, Xe = (o) => o === 0 ? "None left." : `${o} left.`, Ye = (o) => Math.min(6, Math.max(1, o)), Ze = (o) => o instanceof Error && o.message ? o.message : "Something went wrong.";
19
+ function E(o, u) {
20
+ const m = { ...o };
21
+ return delete m[u], m;
22
+ }
23
+ function re({
24
+ busy: o = !1,
25
+ blocked: u = !1,
26
+ onClick: m,
27
+ children: q,
28
+ className: b,
29
+ ...S
30
+ }) {
31
+ return /* @__PURE__ */ c(
32
+ ye,
33
+ {
34
+ size: "lg",
35
+ ...S,
36
+ isLoading: o,
37
+ "aria-disabled": u || void 0,
38
+ className: D(u && !o && "rst:cursor-not-allowed rst:opacity-50", b),
39
+ onClick: (g) => {
40
+ if (u) {
41
+ g.preventDefault();
42
+ return;
43
+ }
44
+ m?.(g);
45
+ },
46
+ children: q
47
+ }
48
+ );
49
+ }
50
+ function ft({
51
+ label: o,
52
+ hideLabel: u = !1,
53
+ headingLevel: m = 2,
54
+ itemHeadingLevel: q,
55
+ items: b,
56
+ getKey: S,
57
+ itemLabel: g,
58
+ renderMeta: Se,
59
+ renderContent: ke,
60
+ actions: H,
61
+ status: ne = "ready",
62
+ error: qe,
63
+ onRetry: se,
64
+ empty: oe = { title: "Nothing waiting" },
65
+ density: ce = "comfortable",
66
+ footer: $e,
67
+ className: Ne
68
+ }) {
69
+ const we = typeof H == "function" ? H(Ve) : H, B = He(), $ = p(null), N = b.map(S), j = p(/* @__PURE__ */ new Map());
70
+ j.current = new Map(b.map((e, t) => [N[t], e]));
71
+ const [K, Ce] = C({}), w = p({}), ie = (e) => {
72
+ w.current = e(w.current), Ce(w.current);
73
+ }, [ae, M] = C({}), [le, Ie] = C({}), h = p({}), v = (e, t) => {
74
+ h.current = t ? { ...h.current, [e]: t } : E(h.current, e), Ie(h.current);
75
+ }, [Q, Be] = C({ text: "", n: 0 }), G = p([]), R = p(null), ue = _((e) => {
76
+ G.current.push(e), !R.current && (R.current = setTimeout(() => {
77
+ R.current = null;
78
+ const t = G.current.join(" ");
79
+ G.current = [], Be((r) => ({ text: t, n: r.n + 1 }));
80
+ }, 0));
81
+ }, []);
82
+ ee(
83
+ () => () => {
84
+ R.current && clearTimeout(R.current);
85
+ },
86
+ []
87
+ );
88
+ const [Re, Te] = C(0), W = p(null), k = _((e) => {
89
+ W.current = e, Te((t) => t + 1);
90
+ }, []), de = _((e) => {
91
+ const t = $.current;
92
+ if (!t) return null;
93
+ const r = "key" in e ? CSS.escape(e.key) : "";
94
+ switch (e.kind) {
95
+ case "item":
96
+ return t.querySelector(`[data-queue-item="${r}"]`);
97
+ case "empty":
98
+ return t.querySelector("[data-queue-empty]");
99
+ case "trigger":
100
+ return t.querySelector(`[data-queue-item="${r}"] [data-queue-action="${CSS.escape(e.actionId)}"]`);
101
+ case "step":
102
+ return t.querySelector(`[data-queue-item="${r}"] [data-queue-step]`);
103
+ }
104
+ }, []);
105
+ ee(() => {
106
+ const e = W.current;
107
+ if (!e) return;
108
+ W.current = null, (de(e) ?? $.current?.querySelector("[data-queue-item]") ?? $.current?.querySelector("[data-queue-empty]"))?.focus();
109
+ }, [Re, de]);
110
+ const J = p(null), Fe = (e) => () => {
111
+ J.current = e;
112
+ }, Ee = (e) => {
113
+ e.relatedTarget && !$.current?.contains(e.relatedTarget) && (J.current = null);
114
+ }, A = (e) => {
115
+ if (J.current !== e) return !1;
116
+ const t = document.activeElement;
117
+ return !t || t === document.body ? !0 : $.current?.contains(t) ? !!t.closest(`[data-queue-item="${CSS.escape(e)}"]`) : !1;
118
+ }, T = p(null), L = (e, t) => {
119
+ T.current = t, v(e.key, { ...e, open: !1 });
120
+ }, fe = p(N), U = p(/* @__PURE__ */ new Map()), [, je] = C(0), V = p(/* @__PURE__ */ new Set()), me = (e, t, r) => {
121
+ const s = t.indexOf(e), d = t.slice(s + 1).find((i) => r.has(i));
122
+ if (d) return { kind: "item", key: d };
123
+ const n = t.slice(0, s).reverse().find((i) => r.has(i));
124
+ return n ? { kind: "item", key: n } : { kind: "empty" };
125
+ };
126
+ ee(() => {
127
+ const e = fe.current;
128
+ fe.current = N;
129
+ const t = new Set(N), r = U.current;
130
+ U.current = /* @__PURE__ */ new Map();
131
+ const s = [];
132
+ let d = !1;
133
+ for (const [n, i] of r) {
134
+ const a = t.has(n);
135
+ s.push(i.announce ?? i.sentence), a || (d = !0), V.current.delete(n);
136
+ const l = a ? { kind: "trigger", key: n, actionId: i.actionId } : e.includes(n) ? me(n, e, t) : null, f = h.current[n];
137
+ if (f?.surface)
138
+ L(f, l ?? { kind: "empty" });
139
+ else {
140
+ const F = A(n);
141
+ f && v(n, null), l && F && k(l);
142
+ }
143
+ }
144
+ for (const n of e.filter((i) => !t.has(i))) {
145
+ if (r.has(n)) continue;
146
+ M((f) => n in f ? E(f, n) : f);
147
+ const i = me(n, e, t), a = T.current;
148
+ if (a && "key" in a && a.key === n && (T.current = i), w.current[n]) {
149
+ V.current.add(n), A(n) && k(i);
150
+ continue;
151
+ }
152
+ const l = h.current[n];
153
+ if (l && !(l.surface && !l.open))
154
+ if (s.push(`${l.label} was decided elsewhere.`), d = !0, l.surface) L(l, i);
155
+ else {
156
+ const f = A(n);
157
+ v(n, null), f && k(i);
158
+ }
159
+ else !l && A(n) && k(i);
160
+ }
161
+ s.length && ue(`${s.join(" ")}${d ? ` ${Xe(N.length)}` : ""}`);
162
+ });
163
+ const O = async (e, t, r, s) => {
164
+ const d = j.current.get(e) ?? t, n = g(d), i = r.edit ? I(r).run : r.run;
165
+ ie((a) => ({ ...a, [e]: r.id })), M((a) => E(a, e));
166
+ try {
167
+ const a = await i(d, s);
168
+ U.current.set(e, {
169
+ actionId: r.id,
170
+ sentence: `${r.done ?? r.label}: ${n}.`,
171
+ announce: a ? a.announce : void 0
172
+ }), je((l) => l + 1);
173
+ } catch (a) {
174
+ const l = Ze(a);
175
+ ue(`${r.label} didn't go through for ${n}. ${l}`);
176
+ const f = h.current[e];
177
+ V.current.delete(e) ? f?.surface ? L(f, { kind: "empty" }) : f && v(e, null) : f ? v(e, { ...f, error: l }) : M((F) => ({ ...F, [e]: l }));
178
+ } finally {
179
+ ie((a) => E(a, e));
180
+ }
181
+ }, Me = (e, t) => {
182
+ const r = S(e), s = I(t);
183
+ if (!t.confirm && !t.reason && !s) {
184
+ O(r, e, t, {});
185
+ return;
186
+ }
187
+ M((d) => E(d, r)), v(r, {
188
+ key: r,
189
+ label: g(e),
190
+ item: e,
191
+ action: t,
192
+ draft: s ? s.edit.initial(e) : void 0,
193
+ reason: {},
194
+ surface: !!s?.edit.surface,
195
+ open: !0
196
+ }), s?.edit.surface || k({ kind: "step", key: r });
197
+ }, X = (e) => {
198
+ const t = h.current[e];
199
+ if (!t || w.current[e]) return;
200
+ const r = { kind: "trigger", key: e, actionId: t.action.id };
201
+ t.surface ? L(t, r) : (v(e, null), k(r));
202
+ }, Ae = (e) => {
203
+ const t = h.current[e];
204
+ !t || w.current[e] || be(t, j.current.get(e) ?? t.item) || (t.action.edit ? O(e, t.item, t.action, { draft: t.draft }) : t.action.reason ? O(e, t.item, t.action, { reason: _e(t.reason) }) : O(e, t.item, t.action, {}));
205
+ }, Le = (e) => {
206
+ const t = T.current;
207
+ T.current = null, v(e, null), t && k(t);
208
+ }, Oe = `h${m}`, pe = q ?? Ye(m + 1), Pe = `h${pe}`, Y = `${B}-label`, ge = (e, t) => {
209
+ const { action: r } = e, s = I(r), d = j.current.get(e.key) ?? e.item, n = !!K[e.key], i = be(e, d), a = `${B}-step-${t}-message`, l = /* @__PURE__ */ c(
210
+ re,
211
+ {
212
+ ...ve[r.tone ?? "neutral"],
213
+ busy: n,
214
+ blocked: !!i,
215
+ "aria-describedby": i ? a : void 0,
216
+ onClick: () => Ae(e.key),
217
+ "data-queue-submit": "",
218
+ children: s ? s.edit.submitLabel : r.label
219
+ }
220
+ ), f = /* @__PURE__ */ c(re, { variant: "ghost", colorScheme: "neutral", blocked: n, onClick: () => X(e.key), children: "Cancel" }), F = /* @__PURE__ */ y(xe, { children: [
221
+ r.reason && /* @__PURE__ */ c(
222
+ et,
223
+ {
224
+ id: `${B}-step-${t}`,
225
+ step: r.reason,
226
+ value: e.reason,
227
+ disabled: n,
228
+ onChange: (Z) => v(e.key, { ...h.current[e.key], reason: Z })
229
+ }
230
+ ),
231
+ s && /* @__PURE__ */ c(
232
+ s.edit.Form,
233
+ {
234
+ item: d,
235
+ value: e.draft,
236
+ onChange: (Z) => v(e.key, { ...h.current[e.key], draft: Z })
237
+ }
238
+ ),
239
+ i && /* @__PURE__ */ c("p", { id: a, className: "rst:text-sm rst:text-error-600 rst:dark:text-error-400", "data-queue-validation": "", children: i }),
240
+ e.error && /* @__PURE__ */ c(te, { colorScheme: "error", role: "group", "aria-live": "off", children: e.error })
241
+ ] });
242
+ return { submitButton: l, cancelButton: f, fields: F };
243
+ }, ze = (e, t) => {
244
+ const { submitButton: r, cancelButton: s, fields: d } = ge(e, t), n = `${B}-step-${t}-prompt`, i = I(e.action), a = e.action.confirm?.prompt ?? e.action.reason?.prompt ?? i?.edit.title;
245
+ return /* @__PURE__ */ y(
246
+ "div",
247
+ {
248
+ role: "group",
249
+ "aria-labelledby": n,
250
+ tabIndex: -1,
251
+ "data-queue-step": "",
252
+ onKeyDown: (l) => {
253
+ l.key === "Escape" && (l.stopPropagation(), X(e.key));
254
+ },
255
+ className: "rst:flex rst:flex-col rst:gap-3 rst:rounded-lg rst:border rst:border-[var(--roster-card-border)] rst:p-4 rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring",
256
+ children: [
257
+ /* @__PURE__ */ c("p", { id: n, className: "rst:text-sm rst:font-medium rst:text-[var(--roster-control-text)]", children: a }),
258
+ i?.edit.description && /* @__PURE__ */ c("p", { className: "rst:text-sm rst:text-gray-600 rst:dark:text-gray-300", children: i.edit.description }),
259
+ d,
260
+ /* @__PURE__ */ y("div", { className: "rst:flex rst:flex-wrap rst:gap-2", children: [
261
+ r,
262
+ s
263
+ ] })
264
+ ]
265
+ }
266
+ );
267
+ }, De = (e, t) => {
268
+ const r = K[t];
269
+ return /* @__PURE__ */ c("div", { role: "group", "aria-label": `Decide: ${g(e)}`, className: "rst:flex rst:flex-wrap rst:gap-2", children: we.filter((s) => !s.hidden?.(e)).map((s) => /* @__PURE__ */ c(
270
+ re,
271
+ {
272
+ ...ve[s.tone ?? "neutral"],
273
+ "data-queue-action": s.id,
274
+ busy: r === s.id,
275
+ blocked: !!r && r !== s.id,
276
+ onClick: () => Me(e, s),
277
+ children: s.label
278
+ },
279
+ s.id
280
+ )) });
281
+ }, x = Object.values(le).find((e) => e.surface) ?? null, P = x ? I(x.action) : null, he = P?.edit.surface, z = x ? ge(x, -1) : null;
282
+ return /* @__PURE__ */ y(
283
+ "section",
284
+ {
285
+ ref: $,
286
+ "aria-labelledby": Y,
287
+ onBlur: Ee,
288
+ className: D("rst:font-ui rst:flex rst:flex-col rst:gap-4", Ne),
289
+ children: [
290
+ /* @__PURE__ */ c(
291
+ Oe,
292
+ {
293
+ id: Y,
294
+ className: D(
295
+ "rst:text-lg rst:font-semibold rst:text-[var(--roster-control-text)]",
296
+ u && "rst:sr-only"
297
+ ),
298
+ children: o
299
+ }
300
+ ),
301
+ /* @__PURE__ */ y(
302
+ "div",
303
+ {
304
+ role: "status",
305
+ "aria-live": "polite",
306
+ "aria-atomic": "true",
307
+ className: "rst:sr-only",
308
+ "data-queue-live": "",
309
+ "data-queue-live-n": Q.n,
310
+ children: [
311
+ Q.text,
312
+ Q.n % 2 ? " " : ""
313
+ ]
314
+ }
315
+ ),
316
+ ne === "loading" ? /* @__PURE__ */ c("div", { className: "rst:flex rst:justify-center rst:py-12", "aria-busy": "true", children: /* @__PURE__ */ c(Qe, { size: "lg", label: `Loading ${o}` }) }) : ne === "error" ? /* @__PURE__ */ c(te, { colorScheme: "error", children: /* @__PURE__ */ y("div", { className: "rst:flex rst:flex-col rst:items-start rst:gap-3", children: [
317
+ /* @__PURE__ */ c("div", { children: qe ?? "The queue couldn't load." }),
318
+ se && /* @__PURE__ */ c(ye, { size: "lg", variant: "outline", colorScheme: "neutral", onClick: se, children: "Retry" })
319
+ ] }) }) : b.length === 0 ? /* @__PURE__ */ c(
320
+ We,
321
+ {
322
+ title: oe.title,
323
+ description: oe.description,
324
+ headingLevel: pe,
325
+ tabIndex: -1,
326
+ "data-queue-empty": "",
327
+ className: "rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring"
328
+ }
329
+ ) : (
330
+ /* `role="list"` is restated because Safari drops a list's role once
331
+ its markers are styled away. */
332
+ /* @__PURE__ */ c(
333
+ "ul",
334
+ {
335
+ role: "list",
336
+ "aria-labelledby": Y,
337
+ className: "rst:m-0 rst:flex rst:list-none rst:flex-col rst:gap-3 rst:p-0",
338
+ children: b.map((e, t) => {
339
+ const r = N[t], s = `${B}-item-${t}`, d = Se?.(e), n = le[r];
340
+ return /* @__PURE__ */ c("li", { children: /* @__PURE__ */ c(
341
+ "article",
342
+ {
343
+ "data-queue-item": r,
344
+ tabIndex: -1,
345
+ "aria-labelledby": s,
346
+ onFocus: Fe(r),
347
+ className: "rst:rounded-xl rst:focus-visible:outline-hidden rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:ring-offset-background",
348
+ children: /* @__PURE__ */ c(Ke, { padding: ce === "compact" ? "sm" : "md", children: /* @__PURE__ */ y("div", { className: D("rst:flex rst:flex-col", ce === "compact" ? "rst:gap-3" : "rst:gap-4"), children: [
349
+ /* @__PURE__ */ y("div", { className: "rst:flex rst:flex-wrap rst:items-baseline rst:gap-x-3 rst:gap-y-1", children: [
350
+ /* @__PURE__ */ c(Pe, { id: s, className: "rst:text-base rst:font-semibold", children: g(e) }),
351
+ d && /* @__PURE__ */ c("div", { className: "rst:flex rst:flex-wrap rst:items-center rst:gap-2 rst:text-sm rst:text-gray-600 rst:dark:text-gray-300", children: d })
352
+ ] }),
353
+ /* @__PURE__ */ c("div", { className: "rst:min-w-0", children: ke(e) }),
354
+ ae[r] && /* @__PURE__ */ c(te, { colorScheme: "error", role: "group", "aria-live": "off", children: ae[r] }),
355
+ n && !n.surface ? ze(n, t) : De(e, r)
356
+ ] }) })
357
+ }
358
+ ) }, r);
359
+ })
360
+ }
361
+ )
362
+ ),
363
+ $e,
364
+ he && x && P && z && /* @__PURE__ */ c(
365
+ he,
366
+ {
367
+ open: x.open,
368
+ title: P.edit.title,
369
+ description: P.edit.description,
370
+ busy: !!K[x.key],
371
+ onCancel: () => X(x.key),
372
+ onAfterClose: () => Le(x.key),
373
+ submitButton: z.submitButton,
374
+ cancelButton: z.cancelButton,
375
+ children: /* @__PURE__ */ c("div", { className: "rst:flex rst:flex-col rst:gap-4", children: z.fields })
376
+ }
377
+ )
378
+ ]
379
+ }
380
+ );
381
+ }
382
+ function be(o, u) {
383
+ const m = I(o.action);
384
+ if (m) return m.edit.validate?.(o.draft, u);
385
+ if (o.action.reason) {
386
+ if (o.action.reason.required && !o.reason.value) return "Pick a reason.";
387
+ if (o.action.reason.note === "required" && !o.reason.note?.trim()) return "Add a note.";
388
+ }
389
+ }
390
+ function _e(o) {
391
+ const u = o.note?.trim();
392
+ return { ...o.value ? { value: o.value } : {}, ...u ? { note: u } : {} };
393
+ }
394
+ function et({
395
+ id: o,
396
+ step: u,
397
+ value: m,
398
+ disabled: q,
399
+ onChange: b
400
+ }) {
401
+ const S = u.note ?? "optional";
402
+ return /* @__PURE__ */ y(xe, { children: [
403
+ u.options && u.options.length > 0 && /* @__PURE__ */ c(
404
+ Je,
405
+ {
406
+ label: u.required ? "Reason" : "Reason (optional)",
407
+ options: u.options,
408
+ value: m.value ?? "",
409
+ onChange: (g) => b({ ...m, value: g }),
410
+ disabled: q
411
+ }
412
+ ),
413
+ S !== "none" && /* @__PURE__ */ c(
414
+ Ge,
415
+ {
416
+ id: `${o}-note`,
417
+ label: u.noteLabel ?? (S === "required" ? "Note" : "Note (optional)"),
418
+ rows: 3,
419
+ value: m.note ?? "",
420
+ onChange: (g) => b({ ...m, note: g.target.value }),
421
+ disabled: q
422
+ }
423
+ )
424
+ ] });
425
+ }
426
+ export {
427
+ ft as ModerationQueue
428
+ };
@@ -0,0 +1 @@
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),c=require("../Dialog/Dialog.cjs");function d({open:s,title:i,description:t,busy:r,onCancel:l,onAfterClose:n,children:o,submitButton:u,cancelButton:a}){return e.jsx(c.Dialog,{isOpen:s,onClose:r?()=>{}:l,title:i,description:t,size:"lg",onAfterClose:n,children:e.jsxs("div",{className:"rst:flex rst:flex-col rst:gap-6",children:[o,e.jsxs("div",{className:"rst:flex rst:flex-wrap rst:justify-end rst:gap-2",children:[a,u]})]})})}exports.QueueEditDialog=d;
@@ -0,0 +1,8 @@
1
+ import { QueueSurfaceProps } from './queue-actions';
2
+ /**
3
+ * Shows a queue's edit step in a Dialog, for a form with more than a field or
4
+ * two. Pass it as the edit's `surface`. A separate export, so a queue that
5
+ * never edits in a Dialog never ships one.
6
+ */
7
+ declare function QueueEditDialog({ open, title, description, busy, onCancel, onAfterClose, children, submitButton, cancelButton, }: QueueSurfaceProps): import("react/jsx-runtime").JSX.Element;
8
+ export { QueueEditDialog };