@blakesteve/roster 5.18.0 → 5.19.1

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.
package/README.md CHANGED
@@ -186,6 +186,72 @@ Tokens Roster never declares, such as the [shape tokens](#shape) and
186
186
  `--roster-elevation-control`, have no such rule to lose to, so `:root` alone
187
187
  covers both schemes.
188
188
 
189
+ #### A region with its own palette
190
+
191
+ Roster's semantic tokens, such as `--roster-tabs-indicator` and
192
+ `--roster-card-bg`, derive from the ramps at `:root`. A custom property resolves
193
+ where it's declared, so they reach the page as finished values, and a ramp
194
+ overridden on a wrapper changes nothing below it: inside that wrapper, tab
195
+ underlines and timeline rails keep the page's color. Add `data-roster-scope` and
196
+ they derive again from the ramps in force on that element:
197
+
198
+ ```css
199
+ .region {
200
+ --roster-primary-400: #a78bfa;
201
+ --roster-primary-500: #7c3aed;
202
+ --roster-primary-600: #6d28d9;
203
+ }
204
+ ```
205
+
206
+ ```tsx
207
+ <section className="region" data-roster-scope>
208
+ <Tabs tabs={tabs} activeTab={active} onChange={setActive} />
209
+ </section>
210
+ ```
211
+
212
+ A page that never sets the attribute computes exactly what it did before.
213
+
214
+ **A scope owns its state.** The attribute matches the light tokens directly, so
215
+ a scope inside a dark page, with no `.dark` of its own, resets to light while
216
+ everything around it stays dark. To stay dark, a scope sets `.dark` too: an
217
+ element with both gets the dark values, from its own ramps.
218
+
219
+ ```tsx
220
+ <section className="region dark" data-roster-scope>
221
+ ```
222
+
223
+ A scope that follows the page's theme has to do that itself, at two costs:
224
+
225
+ - `ThemeToggle` and the blocking script above reach `<html>` and nothing else.
226
+ Until your code sets `.dark` on the scope, a server-rendered scope paints
227
+ light on a dark page.
228
+ - `Select`, `Combobox`, `MultiSelect`, `Sheet` and the `Toaster` read a scoped
229
+ `.dark` once, when they mount. Give the scope a `key` that changes with the
230
+ theme, so they mount again and their panels follow it.
231
+
232
+ A few more things follow from the same rule:
233
+
234
+ - Scopes nest. An inner scope derives from the ramps in force at the inner
235
+ element, its own if it sets any and the outer scope's if it doesn't.
236
+ - A semantic token you set at `:root` stops at a scope, which declares its own.
237
+ Set it on the scope as well. `[data-roster-scope]` weighs the same as a class
238
+ and sits outside any layer, so a class on the scope has to load after Roster's
239
+ stylesheet, unlayered, or it's discarded, as in the rule above.
240
+ - Sheet timing and elevation read no ramp, so a scope doesn't re-declare them.
241
+ It inherits them, so a light scope in a dark page keeps the dark shadows and
242
+ the dark Sheet backdrop.
243
+
244
+ Two things it doesn't do:
245
+
246
+ - **It doesn't cross a portal.** `Select`'s menu, `Menu`, `Dialog` and `Tooltip`
247
+ render at `<body>`, outside the scope, so the scope's ramps don't reach them.
248
+ A `.dark` on the scope is carried across by the five surfaces above and by
249
+ `Menu`, which then open on Roster's own dark tokens rather than your page's.
250
+ `Dialog` and `Tooltip` don't carry it, so they open in the page's scheme.
251
+ - **It doesn't stop `dark:` variants.** They fire under any `.dark` ancestor,
252
+ and a scope can't undo one, so a light scope in a dark page gets light tokens
253
+ and dark variants together.
254
+
189
255
  ### Elevation
190
256
 
191
257
  Three levels, each a themeable box-shadow, and the only way a surface should
@@ -754,8 +820,9 @@ something different in each would not be a token.
754
820
  One caveat worth knowing before you lean on these: like `--roster-card-*`,
755
821
  `--roster-nav-*` and `--roster-footer-*`, they are declared outside
756
822
  `@layer roster` and resolved at `:root`. A host that declares its override
757
- inside `@layer base` is outranked, and an override scoped to a subtree rather
758
- than the document root will not reach them.
823
+ inside `@layer base` is outranked, and a ramp overridden on a subtree rather
824
+ than the document root will not reach them unless that subtree carries
825
+ [`data-roster-scope`](#a-region-with-its-own-palette).
759
826
 
760
827
  ### Floating surface colors
761
828
 
@@ -1435,6 +1502,23 @@ and checks it's visible (Playwright's `toBeVisible`, say) finds it open. In
1435
1502
  read as hidden; `Sheet`'s was too, and is fixed the same way. Nothing on
1436
1503
  screen moves, and a click outside the panel still closes it.
1437
1504
 
1505
+ **One opened as another leaves.** A `Dialog` or `Sheet` opened while another
1506
+ is still leaving holds the page from its first frame, so the other one's focus
1507
+ restore can't move focus out onto the page. An opener in the toast host is the
1508
+ exception: the host stays live, so one opened from a toast still gives focus
1509
+ back to it as it leaves, out of whatever opened in its place. In 5.19.0 and
1510
+ before, a `Sheet` that mounted already
1511
+ open, as one whose code loads on its first open does, never held the part of
1512
+ the page it was written in. That part stayed live behind it, and a sheet or
1513
+ dialog leaving at the same time restored focus onto it as its leave ended. A
1514
+ `Sheet` now opens a render later, before anything is painted, as `Dialog`
1515
+ already did, so on that first open it also slides in rather than appearing in
1516
+ place. Nothing to change in your code.
1517
+
1518
+ Such a sheet may also have no opener to give focus back to: Headless UI keeps
1519
+ the record of what was pressed only once its code has loaded, after the press
1520
+ that opened the sheet. Remember the press and pass it as `returnFocus`.
1521
+
1438
1522
  **Full screen.** `layout="fullscreen"` makes a bare dialog over the whole
1439
1523
  viewport, for a photo viewer or a full-screen card: no box, no padding, and no
1440
1524
  header or close button of Roster's. Everything inside is yours, a close
@@ -2794,7 +2878,7 @@ Output in `dist/`:
2794
2878
  | `tokens.css` | Design token CSS variables |
2795
2879
  | `preflight.css` | Optional global reset (see Setup) |
2796
2880
  | `index.d.ts` | TypeScript definitions |
2797
- | `meta.json` | Test count and version, written when the tarball is built |
2881
+ | `meta.json` | Test count, version and passes on retry, written when the tarball is built |
2798
2882
 
2799
2883
  ### What `meta.json` is for
2800
2884
 
@@ -2828,6 +2912,59 @@ rather than failing, and "live · 0 tests" would look authoritative while being
2828
2912
  the worst possible answer. `src/write-meta.test.ts` pins that guard and the
2829
2913
  field selection, including the one that bit first: `numTotalTestSuites` reads
2830
2914
  like a file count but counts `describe` blocks — 166 against 92 real files.
2915
+ `testFiles` counts each test file that ran, once: vitest's report has an entry
2916
+ for every file in every project and browser that collects it, skipped or not:
2917
+ 699 entries for 219 files on 2 Nov 2026.
2918
+
2919
+ It never writes from a failed run, and vitest's exit code decides what failed.
2920
+ Each failing test gets one retry (`vitest run --retry=1`): a real-browser test
2921
+ can time out once on a busy machine and pass on its second try, and a publish
2922
+ shouldn't stop for that. Anything else that fails the run stops it: a test that
2923
+ fails twice, a file that throws as it loads, an error thrown after its test has
2924
+ passed. Then `prepack` exits non-zero, what failed is printed (vitest's own
2925
+ output is hidden there), and no `meta.json` is written. A test that passed only
2926
+ on its retry is named in the output too, and `meta.json` records how many there
2927
+ were, as `passedOnRetry`.
2928
+
2929
+ ## Discord notices
2930
+
2931
+ `.github/workflows/discord.yml` posts to Roster's channel on Blake's Discord,
2932
+ through the webhook in the `DISCORD_WEBHOOK_URL` repository secret. It's a
2933
+ separate workflow, so nothing it does can fail or delay CI or a deploy. Without
2934
+ the secret, as in a fork, it skips cleanly and posts nothing.
2935
+
2936
+ | Event | Posts when | Which copy of the file runs |
2937
+ | --- | --- | --- |
2938
+ | Storybook deployed, or its deploy failed | `deployment_status`, environment `Production`, state `success`, `failure` or `error` | The one in the deployed commit |
2939
+ | A release | `release: published` | The one in the tagged commit |
2940
+ | CI red | `workflow_run` on `CI`, `failure`, on `main`, from a push | The one on `main` |
2941
+
2942
+ A deploy here is Storybook, at `https://roster-tan.vercel.app`, so the post
2943
+ says Storybook was deployed. The package itself ships on `npm publish`, which
2944
+ isn't a GitHub event, so nothing posts it; the GitHub release made beside it
2945
+ does. Previews and pull requests don't post, and neither does a fork's: CI on a
2946
+ pull request isn't a push. Nor does a CI run that ends canceled, which is how a
2947
+ job stopped at its own time limit ends it. The Storybook job's steps have their
2948
+ own limits, so a stalled step there fails and posts, but Unit Tests and Build
2949
+ have only the job's, so a hung step in either is silent.
2950
+
2951
+ Each post has the version, the commit and a link. With `DETAILS: "on"`, a
2952
+ deploy lists the PRs merged since the last good deploy (not the `release/`
2953
+ PRs), a release carries its notes without the authors and links, and red CI
2954
+ names each failed job and its failed step, such as "Storybook Tests: Run
2955
+ Storybook tests with real input". All of that text is escaped, so a title can't
2956
+ ping anyone or draw a link.
2957
+
2958
+ `src/discord-workflow.test.ts` runs the job's real condition and its real
2959
+ script, with stand-ins for `curl` and `gh`, in the `unit` project. To send each
2960
+ message as a test, from `main`:
2961
+
2962
+ ```bash
2963
+ gh workflow run discord.yml --repo blakesteve/roster -f message=deploy
2964
+ ```
2965
+
2966
+ The other three are `deploy-failed`, `release` and `ci-failed`. A `ci-failed`
2967
+ test names the steps of CI's latest failed push to `main`.
2831
2968
 
2832
2969
  ## Contributing
2833
2970
 
@@ -1 +1 @@
1
- "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),O=require("react"),tt=require("../../../node_modules/@headlessui/react/dist/components/description/description.cjs"),b=require("../../../node_modules/@headlessui/react/dist/components/dialog/dialog.cjs"),et=require("../../../node_modules/@headlessui/react/dist/components/transition/transition.cjs"),f=require("../../../lib/utils.cjs"),rt=require("../../../lib/labels.cjs"),st=require("../../../internal/popup.cjs"),nt=require("../../../internal/motion.cjs"),ot=require("../../../internal/page-inert.cjs"),at=require("../../../internal/leave-watchdog.cjs"),S=require("./sheet-drag.cjs"),it=require("./sheet-title.cjs"),ct=require("../../../internal/key-focus.cjs");function ut(r){const c=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const u in r)if(u!=="default"){const l=Object.getOwnPropertyDescriptor(r,u);Object.defineProperty(c,u,l.get?l:{enumerable:!0,get:()=>r[u]})}}return c.default=r,Object.freeze(c)}const n=ut(O),lt={close:"Close"},dt="rst:transition-transform rst:duration-(--roster-sheet-enter-duration) rst:ease-(--roster-sheet-enter-easing) rst:data-leave:duration-(--roster-sheet-leave-duration) rst:data-leave:ease-(--roster-sheet-leave-easing) rst:data-closed:translate-y-full",ft="rst:transition-opacity rst:duration-(--roster-sheet-fade-duration) rst:ease-out rst:data-closed:opacity-0",pt="rst:transition-opacity rst:duration-(--roster-sheet-enter-duration) rst:ease-out rst:data-leave:duration-(--roster-sheet-leave-duration) rst:data-closed:opacity-0",ht="rst:transition-opacity rst:duration-(--roster-sheet-fade-duration) rst:ease-out rst:data-closed:opacity-0",z={slide:200,fade:150},gt=["input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]):not([type=reset]):not([type=range]):not([type=color]):not([type=file]):not([type=image])","textarea","select","[contenteditable]:not([contenteditable=false])"].join(",");function mt(r){return r?"current"in r?r.current:r:null}function yt({target:r}){const c=n.useRef(r),u=n.useRef(!1);return n.useEffect(()=>{c.current=r}),n.useEffect(()=>(u.current=!1,()=>{u.current=!0,queueMicrotask(()=>{if(!u.current)return;const l=mt(c.current);l?.isConnected&&l.focus()})}),[]),null}function bt(){return s.jsx("svg",{"aria-hidden":"true",focusable:"false",viewBox:"0 0 20 20",className:"rst:h-5 rst:w-5",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",children:s.jsx("path",{d:"M5 5l10 10M15 5L5 15"})})}const xt=({isOpen:r,onClose:c,onAfterClose:u,title:l,hideTitle:B=!1,description:D,actions:N,maxWidth:x=560,initialFocus:v,returnFocus:Y,busy:p=!1,dragToDismiss:j=!0,contentKey:h,labels:V,className:K,children:U})=>{ct.useKeyFocus();const X=rt.withLabels(lt,V),{ref:R,inDarkScope:$}=st.useDarkScope(),E=nt.useReducedMotion(),q=n.useRef(null),i=n.useRef(null),C=at.useLeaveWatchdog(q,i,r,E?z.fade:z.slide,u);n.useLayoutEffect(()=>{if(r)return ot.lockPage(R.current)},[r,R]);const I=n.useRef(null),w=n.useRef(null),k=n.useRef(null),L=n.useRef(null),P=n.useId(),g=it.titleSignature(l),M=n.useRef({signature:g,contentKey:h,open:r,busy:p});n.useEffect(()=>{const t=M.current;if(M.current={signature:g,contentKey:h,open:r,busy:p},!t.open||!r)return;const e=t.contentKey!==h,o=t.signature!==g&&!t.busy;!e&&!o||(w.current?.focus(),L.current&&(L.current.scrollTop=0))},[g,h,r,p]),n.useEffect(()=>{if(!r)return;const t=requestAnimationFrame(()=>{const e=i.current,o=document.activeElement;!e||o&&e.contains(o)||(v?.current??k.current)?.focus()});return()=>cancelAnimationFrame(t)},[r,v]);const[A,F]=n.useState(null);n.useEffect(()=>{if(!r)return;const t=window.visualViewport;if(!t)return;const e=()=>{const o=document.activeElement,d=!!o&&!!i.current?.contains(o)&&o.matches(gt);F(d?Math.round(t.height):null)};return t.addEventListener("resize",e),document.addEventListener("focusin",e),document.addEventListener("focusout",e),()=>{t.removeEventListener("resize",e),document.removeEventListener("focusin",e),document.removeEventListener("focusout",e),F(null)}},[r]);const a=n.useRef(null),m=n.useRef(!1),_=n.useRef(r);n.useEffect(()=>{_.current=r},[r]);const y=t=>{i.current?.style.setProperty("--rst-sheet-drag",`${t}px`)},T=t=>{const e=i.current;a.current=null,e&&(delete e.dataset.dragging,t==="close"?(c(),requestAnimationFrame(()=>{_.current&&!a.current&&y(0)})):y(0))};n.useEffect(()=>{!r&&a.current&&(a.current=null,i.current&&delete i.current.dataset.dragging),r&&!a.current&&y(0)},[r]);const G=t=>{a.current||(m.current=!1,!(!j||!r)&&(t.pointerType==="mouse"&&(t.button!==0||!I.current?.contains(t.target))||(a.current={pointerId:t.pointerId,x0:t.clientX,y0:t.clientY,dy:0,phase:"pending",samples:[{t:t.timeStamp,y:t.clientY}]})))},W=t=>{const e=a.current;if(!e||t.pointerId!==e.pointerId)return;const o=t.clientX-e.x0,d=t.clientY-e.y0;if(e.phase==="pending"){if(!S.exceedsSheetTapSlop(o,d))return;if(Math.abs(o)>Math.abs(d)){e.phase="ignored";return}e.phase="dragging",m.current=!0;try{t.currentTarget.setPointerCapture(t.pointerId)}catch{}i.current&&(i.current.dataset.dragging="")}e.phase==="dragging"&&(e.dy=d,e.samples.push({t:t.timeStamp,y:t.clientY}),e.samples.length>32&&e.samples.shift(),y(Math.max(0,d)))},H=t=>{const e=a.current;if(!e||t.pointerId!==e.pointerId)return;if(e.phase!=="dragging"){a.current=null;return}e.samples.push({t:t.timeStamp,y:t.clientY});const o=t.clientY-e.y0,d=i.current?.getBoundingClientRect().height??0;T(S.sheetDragOutcome(o,d,S.sheetReleaseVelocity(e.samples)))},J=t=>{const e=a.current;!e||t.pointerId!==e.pointerId||(e.phase==="dragging"?T("stay"):a.current=null)},Q=t=>{!m.current||t.detail===0||(m.current=!1,t.preventDefault(),t.stopPropagation())},Z={"--rst-sheet-max-width":typeof x=="number"?`${x}px`:x,...A!==null&&{"--rst-sheet-keyboard-cap":`${A}px`}};return s.jsxs(s.Fragment,{children:[s.jsx("span",{ref:R,hidden:!0}),s.jsxs(b.Dialog,{ref:q,open:r,as:"div",onClose:c,initialFocus:v??k,className:f.cn("rst:font-ui rst:fixed rst:inset-0 rst:z-50 rst:focus:outline-hidden",$&&"dark"),children:[s.jsx(b.DialogBackdrop,{transition:!0,"data-testid":"sheet-backdrop",className:f.cn("rst:fixed rst:inset-0 rst:bg-[var(--roster-backdrop,var(--roster-sheet-backdrop))]",E?ht:pt)}),s.jsx("div",{className:"rst:fixed rst:inset-0 rst:flex rst:items-end rst:justify-center",children:s.jsx(et.TransitionChild,{afterLeave:C.afterLeave,children:s.jsxs(b.DialogPanel,{ref:i,style:Z,"data-testid":"sheet-panel",className:f.cn("rst:relative rst:flex rst:max-h-[min(92dvh,var(--rst-sheet-keyboard-cap,92dvh))] rst:w-full rst:flex-col","rst:md:max-w-(--rst-sheet-max-width)","rst:rounded-t-2xl rst:border rst:border-b-0 rst:elevation-overlay","rst:bg-[var(--roster-popover-bg)] rst:border-[var(--roster-popover-border)] rst:text-[var(--roster-popover-text)]","rst:[--roster-ring-offset:var(--roster-popover-bg)]","rst:pb-[env(safe-area-inset-bottom)]","rst:translate-y-[var(--rst-sheet-drag,0px)]",E?ft:dt,"rst:data-dragging:transition-none",K),children:[s.jsxs("div",{"data-testid":"sheet-drag-zone",className:f.cn("rst:shrink-0",j&&"rst:touch-none"),onPointerDown:G,onPointerMove:W,onPointerUp:H,onPointerCancel:J,onClickCapture:Q,children:[s.jsx("div",{ref:I,"aria-hidden":"true","data-testid":"sheet-handle",className:f.cn("rst:flex rst:h-11 rst:items-start rst:justify-center rst:pt-2",j&&"rst:cursor-grab rst:active:cursor-grabbing"),children:s.jsx("span",{className:"rst:h-1 rst:w-10 rst:rounded-full rst:bg-current rst:opacity-30"})}),s.jsxs("div",{className:"rst:-mt-3 rst:flex rst:items-start rst:gap-2 rst:px-5 rst:pb-4",children:[s.jsxs("div",{className:"rst:min-w-0 rst:flex-1 rst:pt-2",children:[s.jsx(b.DialogTitle,{as:"h2",id:P,ref:w,tabIndex:-1,className:f.cn("rst:text-lg rst:font-semibold rst:text-inherit rst:focus:outline-hidden",B&&"rst:sr-only"),children:l}),D&&s.jsx(tt.Description,{as:"p",className:"rst:mt-1 rst:text-sm rst:text-inherit rst:opacity-75",children:D})]}),N&&s.jsx("div",{className:"rst:flex rst:h-11 rst:shrink-0 rst:items-center rst:gap-1",children:N}),s.jsx("button",{ref:k,type:"button",onClick:c,"aria-label":X.close,className:"rst:inline-flex rst:size-11 rst:shrink-0 rst:-mr-2 rst:cursor-pointer rst:items-center rst:justify-center rst:rounded-md rst:bg-transparent rst:text-inherit rst:opacity-60 rst:transition-opacity rst:hover:opacity-100 rst:focus:outline-hidden rst:focus-visible:opacity-100 rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:ring-offset-background",children:s.jsx(bt,{})})]})]}),s.jsx("div",{ref:L,role:"region","aria-labelledby":P,tabIndex:0,"data-testid":"sheet-content","aria-busy":p||void 0,className:"rst:min-h-0 rst:flex-1 rst:overflow-y-auto rst:overscroll-contain rst:px-5 rst:pb-4 rst:focus:outline-hidden rst:ring-inset rst:focus-visible:ring-2 rst:focus-visible:ring-ring",children:U}),s.jsx(yt,{target:Y})]})})})]},C.key)]})};exports.Sheet=xt;
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react/jsx-runtime"),re=require("react"),se=require("../../../node_modules/@headlessui/react/dist/components/description/description.cjs"),x=require("../../../node_modules/@headlessui/react/dist/components/dialog/dialog.cjs"),ne=require("../../../node_modules/@headlessui/react/dist/components/transition/transition.cjs"),p=require("../../../lib/utils.cjs"),oe=require("../../../lib/labels.cjs"),ie=require("../../../internal/popup.cjs"),ae=require("../../../internal/motion.cjs"),ce=require("../../../internal/page-inert.cjs"),ue=require("../../../internal/leave-watchdog.cjs"),D=require("./sheet-drag.cjs"),le=require("./sheet-title.cjs"),de=require("../../../internal/key-focus.cjs");function fe(o){const u=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(o){for(const l in o)if(l!=="default"){const d=Object.getOwnPropertyDescriptor(o,l);Object.defineProperty(u,l,d.get?d:{enumerable:!0,get:()=>o[l]})}}return u.default=o,Object.freeze(u)}const r=fe(re),pe={close:"Close"},he="rst:transition-transform rst:duration-(--roster-sheet-enter-duration) rst:ease-(--roster-sheet-enter-easing) rst:data-leave:duration-(--roster-sheet-leave-duration) rst:data-leave:ease-(--roster-sheet-leave-easing) rst:data-closed:translate-y-full",ge="rst:transition-opacity rst:duration-(--roster-sheet-fade-duration) rst:ease-out rst:data-closed:opacity-0",me="rst:transition-opacity rst:duration-(--roster-sheet-enter-duration) rst:ease-out rst:data-leave:duration-(--roster-sheet-leave-duration) rst:data-closed:opacity-0",ye="rst:transition-opacity rst:duration-(--roster-sheet-fade-duration) rst:ease-out rst:data-closed:opacity-0",z={slide:200,fade:150},be=["input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]):not([type=reset]):not([type=range]):not([type=color]):not([type=file]):not([type=image])","textarea","select","[contenteditable]:not([contenteditable=false])"].join(",");function xe(o){return o?"current"in o?o.current:o:null}function ve({target:o}){const u=r.useRef(o),l=r.useRef(!1);return r.useEffect(()=>{u.current=o}),r.useEffect(()=>(l.current=!1,()=>{l.current=!0,queueMicrotask(()=>{if(!l.current)return;const d=xe(u.current);d?.isConnected&&d.focus()})}),[]),null}function je(){return s.jsx("svg",{"aria-hidden":"true",focusable:"false",viewBox:"0 0 20 20",className:"rst:h-5 rst:w-5",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",children:s.jsx("path",{d:"M5 5l10 10M15 5L5 15"})})}const Ee=({isOpen:o,onClose:u,onAfterClose:l,title:d,hideTitle:B=!1,description:N,actions:q,maxWidth:v=560,initialFocus:j,returnFocus:Y,busy:h=!1,dragToDismiss:E=!0,contentKey:g,labels:V,className:K,children:U})=>{de.useKeyFocus();const X=oe.withLabels(pe,V),{ref:R,inDarkScope:$}=ie.useDarkScope(),k=ae.useReducedMotion(),[G,W]=r.useState(!1);r.useLayoutEffect(()=>{W(!0)},[]);const n=o&&G,C=r.useRef(null),c=r.useRef(null),I=ue.useLeaveWatchdog(C,c,n,k?z.fade:z.slide,l);r.useLayoutEffect(()=>{if(n)return ce.lockPage(R.current)},[n,R]);const w=r.useRef(null),P=r.useRef(null),L=r.useRef(null),S=r.useRef(null),M=r.useId(),m=le.titleSignature(d),O=r.useRef({signature:m,contentKey:g,open:n,busy:h});r.useEffect(()=>{const e=O.current;if(O.current={signature:m,contentKey:g,open:n,busy:h},!e.open||!n)return;const t=e.contentKey!==g,i=e.signature!==m&&!e.busy;!t&&!i||(P.current?.focus(),S.current&&(S.current.scrollTop=0))},[m,g,n,h]),r.useEffect(()=>{if(!n)return;const e=requestAnimationFrame(()=>{const t=c.current,i=document.activeElement;!t||i&&t.contains(i)||(j?.current??L.current)?.focus()});return()=>cancelAnimationFrame(e)},[n,j]);const[A,F]=r.useState(null);r.useEffect(()=>{if(!n)return;const e=window.visualViewport;if(!e)return;const t=()=>{const i=document.activeElement,f=!!i&&!!c.current?.contains(i)&&i.matches(be);F(f?Math.round(e.height):null)};return e.addEventListener("resize",t),document.addEventListener("focusin",t),document.addEventListener("focusout",t),()=>{e.removeEventListener("resize",t),document.removeEventListener("focusin",t),document.removeEventListener("focusout",t),F(null)}},[n]);const a=r.useRef(null),y=r.useRef(!1),_=r.useRef(n);r.useEffect(()=>{_.current=n},[n]);const b=e=>{c.current?.style.setProperty("--rst-sheet-drag",`${e}px`)},T=e=>{const t=c.current;a.current=null,t&&(delete t.dataset.dragging,e==="close"?(u(),requestAnimationFrame(()=>{_.current&&!a.current&&b(0)})):b(0))};r.useEffect(()=>{!n&&a.current&&(a.current=null,c.current&&delete c.current.dataset.dragging),n&&!a.current&&b(0)},[n]);const H=e=>{a.current||(y.current=!1,!(!E||!n)&&(e.pointerType==="mouse"&&(e.button!==0||!w.current?.contains(e.target))||(a.current={pointerId:e.pointerId,x0:e.clientX,y0:e.clientY,dy:0,phase:"pending",samples:[{t:e.timeStamp,y:e.clientY}]})))},J=e=>{const t=a.current;if(!t||e.pointerId!==t.pointerId)return;const i=e.clientX-t.x0,f=e.clientY-t.y0;if(t.phase==="pending"){if(!D.exceedsSheetTapSlop(i,f))return;if(Math.abs(i)>Math.abs(f)){t.phase="ignored";return}t.phase="dragging",y.current=!0;try{e.currentTarget.setPointerCapture(e.pointerId)}catch{}c.current&&(c.current.dataset.dragging="")}t.phase==="dragging"&&(t.dy=f,t.samples.push({t:e.timeStamp,y:e.clientY}),t.samples.length>32&&t.samples.shift(),b(Math.max(0,f)))},Q=e=>{const t=a.current;if(!t||e.pointerId!==t.pointerId)return;if(t.phase!=="dragging"){a.current=null;return}t.samples.push({t:e.timeStamp,y:e.clientY});const i=e.clientY-t.y0,f=c.current?.getBoundingClientRect().height??0;T(D.sheetDragOutcome(i,f,D.sheetReleaseVelocity(t.samples)))},Z=e=>{const t=a.current;!t||e.pointerId!==t.pointerId||(t.phase==="dragging"?T("stay"):a.current=null)},ee=e=>{!y.current||e.detail===0||(y.current=!1,e.preventDefault(),e.stopPropagation())},te={"--rst-sheet-max-width":typeof v=="number"?`${v}px`:v,...A!==null&&{"--rst-sheet-keyboard-cap":`${A}px`}};return s.jsxs(s.Fragment,{children:[s.jsx("span",{ref:R,hidden:!0}),s.jsxs(x.Dialog,{ref:C,open:n,as:"div",onClose:u,initialFocus:j??L,className:p.cn("rst:font-ui rst:fixed rst:inset-0 rst:z-50 rst:focus:outline-hidden",$&&"dark"),children:[s.jsx(x.DialogBackdrop,{transition:!0,"data-testid":"sheet-backdrop",className:p.cn("rst:fixed rst:inset-0 rst:bg-[var(--roster-backdrop,var(--roster-sheet-backdrop))]",k?ye:me)}),s.jsx("div",{className:"rst:fixed rst:inset-0 rst:flex rst:items-end rst:justify-center",children:s.jsx(ne.TransitionChild,{afterLeave:I.afterLeave,children:s.jsxs(x.DialogPanel,{ref:c,style:te,"data-testid":"sheet-panel",className:p.cn("rst:relative rst:flex rst:max-h-[min(92dvh,var(--rst-sheet-keyboard-cap,92dvh))] rst:w-full rst:flex-col","rst:md:max-w-(--rst-sheet-max-width)","rst:rounded-t-2xl rst:border rst:border-b-0 rst:elevation-overlay","rst:bg-[var(--roster-popover-bg)] rst:border-[var(--roster-popover-border)] rst:text-[var(--roster-popover-text)]","rst:[--roster-ring-offset:var(--roster-popover-bg)]","rst:pb-[env(safe-area-inset-bottom)]","rst:translate-y-[var(--rst-sheet-drag,0px)]",k?ge:he,"rst:data-dragging:transition-none",K),children:[s.jsxs("div",{"data-testid":"sheet-drag-zone",className:p.cn("rst:shrink-0",E&&"rst:touch-none"),onPointerDown:H,onPointerMove:J,onPointerUp:Q,onPointerCancel:Z,onClickCapture:ee,children:[s.jsx("div",{ref:w,"aria-hidden":"true","data-testid":"sheet-handle",className:p.cn("rst:flex rst:h-11 rst:items-start rst:justify-center rst:pt-2",E&&"rst:cursor-grab rst:active:cursor-grabbing"),children:s.jsx("span",{className:"rst:h-1 rst:w-10 rst:rounded-full rst:bg-current rst:opacity-30"})}),s.jsxs("div",{className:"rst:-mt-3 rst:flex rst:items-start rst:gap-2 rst:px-5 rst:pb-4",children:[s.jsxs("div",{className:"rst:min-w-0 rst:flex-1 rst:pt-2",children:[s.jsx(x.DialogTitle,{as:"h2",id:M,ref:P,tabIndex:-1,className:p.cn("rst:text-lg rst:font-semibold rst:text-inherit rst:focus:outline-hidden",B&&"rst:sr-only"),children:d}),N&&s.jsx(se.Description,{as:"p",className:"rst:mt-1 rst:text-sm rst:text-inherit rst:opacity-75",children:N})]}),q&&s.jsx("div",{className:"rst:flex rst:h-11 rst:shrink-0 rst:items-center rst:gap-1",children:q}),s.jsx("button",{ref:L,type:"button",onClick:u,"aria-label":X.close,className:"rst:inline-flex rst:size-11 rst:shrink-0 rst:-mr-2 rst:cursor-pointer rst:items-center rst:justify-center rst:rounded-md rst:bg-transparent rst:text-inherit rst:opacity-60 rst:transition-opacity rst:hover:opacity-100 rst:focus:outline-hidden rst:focus-visible:opacity-100 rst:focus-visible:ring-2 rst:focus-visible:ring-ring rst:focus-visible:ring-offset-2 rst:ring-offset-background",children:s.jsx(je,{})})]})]}),s.jsx("div",{ref:S,role:"region","aria-labelledby":M,tabIndex:0,"data-testid":"sheet-content","aria-busy":h||void 0,className:"rst:min-h-0 rst:flex-1 rst:overflow-y-auto rst:overscroll-contain rst:px-5 rst:pb-4 rst:focus:outline-hidden rst:ring-inset rst:focus-visible:ring-2 rst:focus-visible:ring-ring",children:U}),s.jsx(ve,{target:Y})]})})})]},I.key)]})};exports.Sheet=Ee;
@@ -46,7 +46,10 @@ export interface SheetProps {
46
46
  * Where focus goes on close, over whatever opened the sheet.
47
47
  *
48
48
  * A sheet opened on page load from a deep link has no opener, so without
49
- * this focus falls to `<body>`.
49
+ * this focus falls to `<body>`. A sheet whose code loads on its first open
50
+ * can have none either: Headless UI, which keeps the record of what was
51
+ * pressed, starts keeping it only once its code has loaded, after the press
52
+ * that opened the sheet. Remember the press yourself and pass it here.
50
53
  */
51
54
  returnFocus?: React.RefObject<HTMLElement | null> | HTMLElement | null;
52
55
  /** Sets `aria-busy` on the content region while its content loads. */