@womp/kookie-ui 0.11.0 → 0.13.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 (55) hide show
  1. package/components.css +182 -192
  2. package/dist/cjs/components/chatbar.d.ts +26 -2
  3. package/dist/cjs/components/chatbar.d.ts.map +1 -1
  4. package/dist/cjs/components/chatbar.js +2 -2
  5. package/dist/cjs/components/chatbar.js.map +3 -3
  6. package/dist/cjs/components/index.js +5 -5
  7. package/dist/cjs/components/index.js.map +3 -3
  8. package/dist/cjs/hooks/appearance-script.d.ts +16 -0
  9. package/dist/cjs/hooks/appearance-script.d.ts.map +1 -0
  10. package/dist/cjs/hooks/appearance-script.js +12 -0
  11. package/dist/cjs/hooks/appearance-script.js.map +7 -0
  12. package/dist/cjs/hooks/index.d.ts +3 -0
  13. package/dist/cjs/hooks/index.d.ts.map +1 -1
  14. package/dist/cjs/hooks/index.js +12 -2
  15. package/dist/cjs/hooks/index.js.map +4 -4
  16. package/dist/cjs/hooks/use-appearance.d.ts +30 -0
  17. package/dist/cjs/hooks/use-appearance.d.ts.map +1 -0
  18. package/dist/cjs/hooks/use-appearance.js +12 -0
  19. package/dist/cjs/hooks/use-appearance.js.map +7 -0
  20. package/dist/cjs/index.js +15 -5
  21. package/dist/cjs/index.js.map +4 -4
  22. package/dist/esm/chunk-2KZ4NI3X.js +1 -0
  23. package/dist/esm/chunk-EGMUQQRW.js +2 -0
  24. package/dist/esm/chunk-EGMUQQRW.js.map +7 -0
  25. package/dist/esm/chunk-HT7RFHLW.js +2 -0
  26. package/dist/esm/chunk-HT7RFHLW.js.map +7 -0
  27. package/dist/esm/chunk-IUER6BNH.js +12 -0
  28. package/dist/esm/chunk-IUER6BNH.js.map +7 -0
  29. package/dist/esm/components/chatbar.d.ts +26 -2
  30. package/dist/esm/components/chatbar.d.ts.map +1 -1
  31. package/dist/esm/components/chatbar.js +1 -1
  32. package/dist/esm/components/index.js +1 -1
  33. package/dist/esm/hooks/appearance-script.d.ts +16 -0
  34. package/dist/esm/hooks/appearance-script.d.ts.map +1 -0
  35. package/dist/esm/hooks/appearance-script.js +2 -0
  36. package/dist/esm/hooks/appearance-script.js.map +7 -0
  37. package/dist/esm/hooks/index.d.ts +3 -0
  38. package/dist/esm/hooks/index.d.ts.map +1 -1
  39. package/dist/esm/hooks/index.js +1 -1
  40. package/dist/esm/hooks/use-appearance.d.ts +30 -0
  41. package/dist/esm/hooks/use-appearance.d.ts.map +1 -0
  42. package/dist/esm/hooks/use-appearance.js +2 -0
  43. package/dist/esm/hooks/use-appearance.js.map +7 -0
  44. package/dist/esm/index.js +1 -1
  45. package/package.json +11 -1
  46. package/src/components/chatbar.css +75 -40
  47. package/src/components/chatbar.tsx +126 -49
  48. package/src/hooks/appearance-script.ts +28 -0
  49. package/src/hooks/index.ts +3 -0
  50. package/src/hooks/use-appearance.ts +119 -0
  51. package/styles.css +182 -192
  52. package/dist/esm/chunk-EL7YGOTY.js +0 -1
  53. package/dist/esm/chunk-ENLFKWYV.js +0 -2
  54. package/dist/esm/chunk-ENLFKWYV.js.map +0 -7
  55. /package/dist/esm/{chunk-EL7YGOTY.js.map → chunk-2KZ4NI3X.js.map} +0 -0
package/dist/esm/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import"./chunk-EL7YGOTY.js";import"./chunk-C7EVYSWK.js";import{a as zo}from"./chunk-UYCPDGWA.js";import{b as Ao,c as Bo,d as Co,e as Do,f as Eo}from"./chunk-XLMTTSRO.js";import"./chunk-ZUOK3KFY.js";import{a as Fo}from"./chunk-CYU6BLZ5.js";import"./chunk-4WVNMGI5.js";import{a as Go}from"./chunk-YWENWZOU.js";import{c as qo}from"./chunk-ALWNS44Q.js";import"./chunk-MN3XALXD.js";import{a as so,b as uo}from"./chunk-D6PHTHF2.js";import{a as yo}from"./chunk-6G3MPL4A.js";import{a as wo}from"./chunk-VK7RNXUO.js";import{a as vo}from"./chunk-EE54S7YV.js";import{c as jo}from"./chunk-K3UAS7RW.js";import"./chunk-AUV6B4AH.js";import{h as ko}from"./chunk-36A5BYCN.js";import"./chunk-BALS3AVM.js";import{e as lo}from"./chunk-VNH7BJOA.js";import"./chunk-TZTUPQYK.js";import{a as no}from"./chunk-EPTYNVCU.js";import"./chunk-CLMOWP5T.js";import{a as go}from"./chunk-VZSQATP6.js";import{a as ho}from"./chunk-43A5GUSI.js";import"./chunk-XI5YXUCK.js";import{a as io}from"./chunk-KJUDZCYK.js";import"./chunk-AF6XKU3W.js";import{h as Io}from"./chunk-MJOXEUBT.js";import"./chunk-2EQWBT2S.js";import{p as Ho}from"./chunk-53SZ4Y23.js";import"./chunk-2CMM7MEL.js";import"./chunk-OJU5GCDZ.js";import{c as xo}from"./chunk-FG7XM7KJ.js";import"./chunk-FC2DBBJ3.js";import{h as bo}from"./chunk-VHECAEUP.js";import"./chunk-EBQZ3Z22.js";import{a as co}from"./chunk-VR7ZAFYN.js";import"./chunk-CRSHBENJ.js";import{g as Jo}from"./chunk-ZK7A2MZZ.js";import"./chunk-ADXZNG4F.js";import{a as ao}from"./chunk-OGXZHAQL.js";import"./chunk-NIX6Z3JG.js";import{c as mo}from"./chunk-2I7QRVJ5.js";import"./chunk-VLTXI4A7.js";import{a as po}from"./chunk-CIYF56YS.js";import"./chunk-STPMPY3X.js";import{a as to}from"./chunk-FHEHX7CE.js";import{a as oo}from"./chunk-XEZXKPLE.js";import{a as ro}from"./chunk-CDG5WH4U.js";import"./chunk-5XV4QEP5.js";import{a as eo}from"./chunk-GLERJXVS.js";import"./chunk-MCQCG6AS.js";import{c as fo}from"./chunk-CRTH5LNU.js";import"./chunk-OWMA6GTG.js";import{a as _}from"./chunk-YBSRX63K.js";import"./chunk-AGSSWWFI.js";import{i as Ko}from"./chunk-OIUCV5HK.js";import{e as $}from"./chunk-7UHKEJ7Q.js";import"./chunk-Y3A6ZU24.js";import{a as Y}from"./chunk-IHK3H2OM.js";import{a as X}from"./chunk-S5C5YRBS.js";import"./chunk-IBF5U4QW.js";import"./chunk-L6UXAITB.js";import"./chunk-GFOSP3PZ.js";import{a as Z}from"./chunk-CSKZZOI2.js";import"./chunk-JAMLW534.js";import{d as W}from"./chunk-MEO7MJMQ.js";import"./chunk-VJSZG35J.js";import{e as R}from"./chunk-RNTCHVFI.js";import{g as T}from"./chunk-7JJT42J2.js";import{a as S}from"./chunk-MHANZINI.js";import{o as U}from"./chunk-MZXHKM4V.js";import"./chunk-WOR3JCLX.js";import{a as V}from"./chunk-7FC7HF76.js";import"./chunk-4JQZUQY7.js";import{a as M}from"./chunk-N4GTDLRD.js";import{l as O}from"./chunk-T4OR62DQ.js";import{g as N}from"./chunk-WHFJ4JUN.js";import"./chunk-72AHPGPN.js";import"./chunk-RDAMYQFF.js";import{a as P}from"./chunk-4ME6O27S.js";import"./chunk-PPNWGWN3.js";import{n as Q}from"./chunk-PQKJNRMR.js";import"./chunk-OA7C34MJ.js";import"./chunk-NIIEIZKQ.js";import{c as J}from"./chunk-METRW4HG.js";import{a as I}from"./chunk-VX6ARMWP.js";import"./chunk-667BKCUG.js";import"./chunk-HAGKI7NA.js";import{c as K}from"./chunk-OMGZG52I.js";import"./chunk-V32EP3S7.js";import"./chunk-5SNHUVDA.js";import{a as L}from"./chunk-KFR3CK24.js";import"./chunk-UICSVJ3B.js";import"./chunk-KZWNGWIM.js";import{a as u}from"./chunk-4YFJWXL2.js";import{d as y}from"./chunk-CKMMUHKE.js";import"./chunk-OGVKSYLL.js";import{l as H}from"./chunk-ENLFKWYV.js";import{b as F,c as G}from"./chunk-L5PID6BU.js";import{a as z}from"./chunk-ISOLUTZF.js";import{a as E}from"./chunk-COWZAUZR.js";import"./chunk-5GXFBLBJ.js";import"./chunk-UBOOUDS4.js";import"./chunk-XPRPYCII.js";import"./chunk-5BWLY27A.js";import{a as A,b as B,c as C,d as D}from"./chunk-IX5HIHVI.js";import{a as w}from"./chunk-3R4YLW4A.js";import{a as v}from"./chunk-2N2AQNJH.js";import{a as k}from"./chunk-Y7LT3F6R.js";import{a as l}from"./chunk-HJU4I34X.js";import"./chunk-PS6NEG5A.js";import"./chunk-QFPHEY77.js";import{a as q}from"./chunk-KMPE7TJ6.js";import{a as n}from"./chunk-OLAWVEAI.js";import"./chunk-BPVVFHYD.js";import"./chunk-QQ62LO3X.js";import{a as s}from"./chunk-MS5J4MF6.js";import"./chunk-FGORMEAO.js";import"./chunk-ROSWI2CL.js";import{a as b}from"./chunk-ERNM3KVF.js";import{f as c}from"./chunk-Y5RCH23Z.js";import"./chunk-EDKQURDU.js";import{h}from"./chunk-IYCPYN4Z.js";import"./chunk-MJJ7XDIP.js";import{a as g}from"./chunk-5WRCK4R7.js";import"./chunk-4XKK32M4.js";import"./chunk-XKBLNVOD.js";import"./chunk-GCUGJXI2.js";import{f as j}from"./chunk-54JFIP5S.js";import{a as i}from"./chunk-JDGJSNWT.js";import"./chunk-OO652UQW.js";import{a as d}from"./chunk-GO7OHBHW.js";import"./chunk-PZ7OYATT.js";import"./chunk-G2CKYO2I.js";import"./chunk-AXUDFYLY.js";import"./chunk-KNQBAOMV.js";import"./chunk-FD2TR343.js";import"./chunk-WYADYDPN.js";import"./chunk-ZE2KAVXW.js";import"./chunk-ZWZGUBL4.js";import"./chunk-7RQNB63F.js";import{a as t,b as x,c as a}from"./chunk-SEY4NA45.js";import"./chunk-WAURCNAS.js";import"./chunk-F22ZRNWL.js";import"./chunk-XYVLQDGR.js";import"./chunk-YAQBIO2B.js";import"./chunk-AGNIFHOE.js";import"./chunk-HCNO7PX6.js";import"./chunk-GMHA5CFH.js";import"./chunk-A2XVR7GL.js";import"./chunk-BZZXXZ3O.js";import"./chunk-2LYX5S7H.js";import"./chunk-HWQ3NTJP.js";import"./chunk-3J6AUDID.js";import"./chunk-4LDVSTXI.js";import{a as f}from"./chunk-HF5WY5YE.js";import"./chunk-3KB2XWBE.js";import{a as m}from"./chunk-AGAQC4HH.js";import"./chunk-5T6K7VPP.js";import{a as e}from"./chunk-FHOCUZDR.js";import"./chunk-SMGDH54W.js";import"./chunk-SNR5VFWG.js";import{b as o,c as r}from"./chunk-FWB47YCH.js";import"./chunk-K53W3ELO.js";import"./chunk-TTFUM47A.js";import"./chunk-VX44UTQ5.js";import"./chunk-ERGJN7FJ.js";import"./chunk-5TXQLK4G.js";import"./chunk-JFWMAYEH.js";import"./chunk-KRJTW535.js";import"./chunk-F6V7GBNQ.js";import"./chunk-3KSGRY6I.js";import"./chunk-ZOY43B55.js";import{a as p}from"./chunk-E67CIG6A.js";import"./chunk-ARIV4AT5.js";import"./chunk-3XSB7YIM.js";import"./chunk-YA5DF67M.js";import"./chunk-GSTOGDAJ.js";import"./chunk-6FLLFCBU.js";import"./chunk-AX5S56DS.js";import"./chunk-E23RKOQJ.js";import"./chunk-JUY7CBSL.js";import"./chunk-WRWNN2NW.js";import"./chunk-QM3RCK5P.js";import"./chunk-RZCX6IBE.js";import"./chunk-NZJGC6ZW.js";import"./chunk-WMGIFPI2.js";import"./chunk-CFNESRYI.js";import"./chunk-ZNK6AH2G.js";import"./chunk-JSW6J6RS.js";import"./chunk-OS3FCYZY.js";export{b as AccessibleIcon,c as Accordion,h as AlertDialog,j as AppBar,k as AspectRatio,l as Avatar,q as Badge,s as Blockquote,u as Box,w as Button,y as Callout,i as Card,H as Chatbar,L as Checkbox,J as CheckboxCards,K as CheckboxGroup,C as ChevronDownIcon,M as Code,O as Combobox,G as Confirmation,P as Container,Q as ContextMenu,R as DataList,T as Dialog,U as DropdownMenu,V as Em,e as Flex,I as Grid,d as Heading,W as HoverCard,z as IconButton,Y as Image,Z as Inset,p as Kbd,_ as Link,Ko as MessageScroller,$ as Navbar,F as Notice,N as Popover,oo as Portal,ro as Progress,eo as Quote,po as Radio,fo as RadioCards,mo as RadioGroup,to as Reset,E as ScrollArea,ao as Section,xo as SegmentedControl,bo as Select,co as Separator,Jo as Sheet,Io as Shell,Ho as Sidebar,X as Skeleton,go as Slider,o as Slot,r as Slottable,f as Spinner,ho as Strong,io as Switch,jo as TabNav,ko as Table,lo as Tabs,g as Text,no as TextArea,qo as TextField,a as Theme,t as ThemeContext,so as ThemePanel,uo as ThemePanelContent,B as ThickCheckIcon,D as ThickChevronRightIcon,A as ThickDividerHorizontalIcon,yo as ToggleButton,zo as ToggleIconButton,Eo as Toolbar,Bo as ToolbarButton,Ao as ToolbarGroup,Co as ToolbarSeparator,Do as ToolbarTitle,n as Tooltip,Fo as UserCard,Go as VirtualMenu,m as VisuallyHidden,S as useBodyPointerEventsCleanup,vo as useLiveAnnouncer,x as useThemeContext,wo as useToggleState,v as useTooltipWrapper};
1
+ import"./chunk-2KZ4NI3X.js";import{a as No,b as Oo}from"./chunk-HT7RFHLW.js";import{a as Lo,b as Mo}from"./chunk-IUER6BNH.js";import"./chunk-C7EVYSWK.js";import{a as zo}from"./chunk-UYCPDGWA.js";import{b as Ao,c as Bo,d as Co,e as Do,f as Eo}from"./chunk-XLMTTSRO.js";import"./chunk-ZUOK3KFY.js";import{a as Fo}from"./chunk-CYU6BLZ5.js";import"./chunk-4WVNMGI5.js";import{a as Go}from"./chunk-YWENWZOU.js";import{c as qo}from"./chunk-ALWNS44Q.js";import"./chunk-MN3XALXD.js";import{a as so,b as uo}from"./chunk-D6PHTHF2.js";import{a as yo}from"./chunk-6G3MPL4A.js";import{a as wo}from"./chunk-VK7RNXUO.js";import{a as vo}from"./chunk-EE54S7YV.js";import{c as jo}from"./chunk-K3UAS7RW.js";import"./chunk-AUV6B4AH.js";import{h as ko}from"./chunk-36A5BYCN.js";import"./chunk-BALS3AVM.js";import{e as lo}from"./chunk-VNH7BJOA.js";import"./chunk-TZTUPQYK.js";import{a as no}from"./chunk-EPTYNVCU.js";import"./chunk-CLMOWP5T.js";import{a as go}from"./chunk-VZSQATP6.js";import{a as ho}from"./chunk-43A5GUSI.js";import"./chunk-XI5YXUCK.js";import{a as io}from"./chunk-KJUDZCYK.js";import"./chunk-AF6XKU3W.js";import{h as Io}from"./chunk-MJOXEUBT.js";import"./chunk-2EQWBT2S.js";import{p as Ho}from"./chunk-53SZ4Y23.js";import"./chunk-2CMM7MEL.js";import"./chunk-OJU5GCDZ.js";import{c as xo}from"./chunk-FG7XM7KJ.js";import"./chunk-FC2DBBJ3.js";import{h as bo}from"./chunk-VHECAEUP.js";import"./chunk-EBQZ3Z22.js";import{a as co}from"./chunk-VR7ZAFYN.js";import"./chunk-CRSHBENJ.js";import{g as Jo}from"./chunk-ZK7A2MZZ.js";import"./chunk-ADXZNG4F.js";import{a as ao}from"./chunk-OGXZHAQL.js";import"./chunk-NIX6Z3JG.js";import{c as mo}from"./chunk-2I7QRVJ5.js";import"./chunk-VLTXI4A7.js";import{a as po}from"./chunk-CIYF56YS.js";import"./chunk-STPMPY3X.js";import{a as to}from"./chunk-FHEHX7CE.js";import{a as oo}from"./chunk-XEZXKPLE.js";import{a as ro}from"./chunk-CDG5WH4U.js";import"./chunk-5XV4QEP5.js";import{a as eo}from"./chunk-GLERJXVS.js";import"./chunk-MCQCG6AS.js";import{c as fo}from"./chunk-CRTH5LNU.js";import"./chunk-OWMA6GTG.js";import{a as _}from"./chunk-YBSRX63K.js";import"./chunk-AGSSWWFI.js";import{i as Ko}from"./chunk-OIUCV5HK.js";import{e as $}from"./chunk-7UHKEJ7Q.js";import"./chunk-Y3A6ZU24.js";import{a as Y}from"./chunk-IHK3H2OM.js";import{a as X}from"./chunk-S5C5YRBS.js";import"./chunk-IBF5U4QW.js";import"./chunk-L6UXAITB.js";import"./chunk-GFOSP3PZ.js";import{a as Z}from"./chunk-CSKZZOI2.js";import"./chunk-JAMLW534.js";import{d as W}from"./chunk-MEO7MJMQ.js";import"./chunk-VJSZG35J.js";import{e as R}from"./chunk-RNTCHVFI.js";import{g as T}from"./chunk-7JJT42J2.js";import{a as S}from"./chunk-MHANZINI.js";import{o as U}from"./chunk-MZXHKM4V.js";import"./chunk-WOR3JCLX.js";import{a as V}from"./chunk-7FC7HF76.js";import"./chunk-4JQZUQY7.js";import{a as M}from"./chunk-N4GTDLRD.js";import{l as O}from"./chunk-T4OR62DQ.js";import{g as N}from"./chunk-WHFJ4JUN.js";import"./chunk-72AHPGPN.js";import"./chunk-RDAMYQFF.js";import{a as P}from"./chunk-4ME6O27S.js";import"./chunk-PPNWGWN3.js";import{n as Q}from"./chunk-PQKJNRMR.js";import"./chunk-OA7C34MJ.js";import"./chunk-NIIEIZKQ.js";import{c as J}from"./chunk-METRW4HG.js";import{a as I}from"./chunk-VX6ARMWP.js";import"./chunk-667BKCUG.js";import"./chunk-HAGKI7NA.js";import{c as K}from"./chunk-OMGZG52I.js";import"./chunk-V32EP3S7.js";import"./chunk-5SNHUVDA.js";import{a as L}from"./chunk-KFR3CK24.js";import"./chunk-UICSVJ3B.js";import"./chunk-KZWNGWIM.js";import{a as u}from"./chunk-4YFJWXL2.js";import{d as y}from"./chunk-CKMMUHKE.js";import"./chunk-OGVKSYLL.js";import{m as H}from"./chunk-EGMUQQRW.js";import{b as F,c as G}from"./chunk-L5PID6BU.js";import{a as z}from"./chunk-ISOLUTZF.js";import{a as E}from"./chunk-COWZAUZR.js";import"./chunk-5GXFBLBJ.js";import"./chunk-UBOOUDS4.js";import"./chunk-XPRPYCII.js";import"./chunk-5BWLY27A.js";import{a as A,b as B,c as C,d as D}from"./chunk-IX5HIHVI.js";import{a as w}from"./chunk-3R4YLW4A.js";import{a as v}from"./chunk-2N2AQNJH.js";import{a as k}from"./chunk-Y7LT3F6R.js";import{a as l}from"./chunk-HJU4I34X.js";import"./chunk-PS6NEG5A.js";import"./chunk-QFPHEY77.js";import{a as q}from"./chunk-KMPE7TJ6.js";import{a as n}from"./chunk-OLAWVEAI.js";import"./chunk-BPVVFHYD.js";import"./chunk-QQ62LO3X.js";import{a as s}from"./chunk-MS5J4MF6.js";import"./chunk-FGORMEAO.js";import"./chunk-ROSWI2CL.js";import{a as b}from"./chunk-ERNM3KVF.js";import{f as c}from"./chunk-Y5RCH23Z.js";import"./chunk-EDKQURDU.js";import{h}from"./chunk-IYCPYN4Z.js";import"./chunk-MJJ7XDIP.js";import{a as g}from"./chunk-5WRCK4R7.js";import"./chunk-4XKK32M4.js";import"./chunk-XKBLNVOD.js";import"./chunk-GCUGJXI2.js";import{f as j}from"./chunk-54JFIP5S.js";import{a as i}from"./chunk-JDGJSNWT.js";import"./chunk-OO652UQW.js";import{a as d}from"./chunk-GO7OHBHW.js";import"./chunk-PZ7OYATT.js";import"./chunk-G2CKYO2I.js";import"./chunk-AXUDFYLY.js";import"./chunk-KNQBAOMV.js";import"./chunk-FD2TR343.js";import"./chunk-WYADYDPN.js";import"./chunk-ZE2KAVXW.js";import"./chunk-ZWZGUBL4.js";import"./chunk-7RQNB63F.js";import{a as t,b as x,c as a}from"./chunk-SEY4NA45.js";import"./chunk-WAURCNAS.js";import"./chunk-F22ZRNWL.js";import"./chunk-XYVLQDGR.js";import"./chunk-YAQBIO2B.js";import"./chunk-AGNIFHOE.js";import"./chunk-HCNO7PX6.js";import"./chunk-GMHA5CFH.js";import"./chunk-A2XVR7GL.js";import"./chunk-BZZXXZ3O.js";import"./chunk-2LYX5S7H.js";import"./chunk-HWQ3NTJP.js";import"./chunk-3J6AUDID.js";import"./chunk-4LDVSTXI.js";import{a as f}from"./chunk-HF5WY5YE.js";import"./chunk-3KB2XWBE.js";import{a as m}from"./chunk-AGAQC4HH.js";import"./chunk-5T6K7VPP.js";import{a as e}from"./chunk-FHOCUZDR.js";import"./chunk-SMGDH54W.js";import"./chunk-SNR5VFWG.js";import{b as o,c as r}from"./chunk-FWB47YCH.js";import"./chunk-K53W3ELO.js";import"./chunk-TTFUM47A.js";import"./chunk-VX44UTQ5.js";import"./chunk-ERGJN7FJ.js";import"./chunk-5TXQLK4G.js";import"./chunk-JFWMAYEH.js";import"./chunk-KRJTW535.js";import"./chunk-F6V7GBNQ.js";import"./chunk-3KSGRY6I.js";import"./chunk-ZOY43B55.js";import{a as p}from"./chunk-E67CIG6A.js";import"./chunk-ARIV4AT5.js";import"./chunk-3XSB7YIM.js";import"./chunk-YA5DF67M.js";import"./chunk-GSTOGDAJ.js";import"./chunk-6FLLFCBU.js";import"./chunk-AX5S56DS.js";import"./chunk-E23RKOQJ.js";import"./chunk-JUY7CBSL.js";import"./chunk-WRWNN2NW.js";import"./chunk-QM3RCK5P.js";import"./chunk-RZCX6IBE.js";import"./chunk-NZJGC6ZW.js";import"./chunk-WMGIFPI2.js";import"./chunk-CFNESRYI.js";import"./chunk-ZNK6AH2G.js";import"./chunk-JSW6J6RS.js";import"./chunk-OS3FCYZY.js";export{Lo as APPEARANCE_STORAGE_KEY,b as AccessibleIcon,c as Accordion,h as AlertDialog,j as AppBar,k as AspectRatio,l as Avatar,q as Badge,s as Blockquote,u as Box,w as Button,y as Callout,i as Card,H as Chatbar,L as Checkbox,J as CheckboxCards,K as CheckboxGroup,C as ChevronDownIcon,M as Code,O as Combobox,G as Confirmation,P as Container,Q as ContextMenu,R as DataList,T as Dialog,U as DropdownMenu,V as Em,e as Flex,I as Grid,d as Heading,W as HoverCard,z as IconButton,Y as Image,Z as Inset,p as Kbd,_ as Link,Ko as MessageScroller,$ as Navbar,F as Notice,N as Popover,oo as Portal,ro as Progress,eo as Quote,po as Radio,fo as RadioCards,mo as RadioGroup,to as Reset,E as ScrollArea,ao as Section,xo as SegmentedControl,bo as Select,co as Separator,Jo as Sheet,Io as Shell,Ho as Sidebar,X as Skeleton,go as Slider,o as Slot,r as Slottable,f as Spinner,ho as Strong,io as Switch,jo as TabNav,ko as Table,lo as Tabs,g as Text,no as TextArea,qo as TextField,a as Theme,t as ThemeContext,so as ThemePanel,uo as ThemePanelContent,B as ThickCheckIcon,D as ThickChevronRightIcon,A as ThickDividerHorizontalIcon,yo as ToggleButton,zo as ToggleIconButton,Eo as Toolbar,Bo as ToolbarButton,Ao as ToolbarGroup,Co as ToolbarSeparator,Do as ToolbarTitle,n as Tooltip,Fo as UserCard,Go as VirtualMenu,m as VisuallyHidden,Mo as appearanceScript,No as setAppearance,Oo as useAppearance,S as useBodyPointerEventsCleanup,vo as useLiveAnnouncer,x as useThemeContext,wo as useToggleState,v as useTooltipWrapper};
2
2
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@womp/kookie-ui",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Kookie UI v1: a React component library with design tokens, flexible theming, a full layout shell, and comprehensive documentation.",
5
5
  "keywords": [
6
6
  "react",
@@ -48,6 +48,16 @@
48
48
  "default": "./dist/esm/components/*.js"
49
49
  }
50
50
  },
51
+ "./appearance-script": {
52
+ "require": {
53
+ "types": "./dist/cjs/hooks/appearance-script.d.ts",
54
+ "default": "./dist/cjs/hooks/appearance-script.js"
55
+ },
56
+ "import": {
57
+ "types": "./dist/esm/hooks/appearance-script.d.ts",
58
+ "default": "./dist/esm/hooks/appearance-script.js"
59
+ }
60
+ },
51
61
  "./helpers": {
52
62
  "require": {
53
63
  "types": "./dist/cjs/helpers/index.d.ts",
@@ -8,7 +8,9 @@
8
8
 
9
9
  /* Defaults */
10
10
  .rt-ChatbarRoot {
11
- --chatbar-attachment-thumb: var(--space-8);
11
+ --chatbar-item-lead: var(--space-5);
12
+ --chatbar-item-lead-radius: var(--radius-2);
13
+ --chatbar-item-padding: var(--space-1);
12
14
  /* A column: notices, then the box (which fills any height the consumer gives the root), then context. */
13
15
  display: flex;
14
16
  flex-direction: column;
@@ -116,58 +118,97 @@
116
118
  --scrollarea-scrollbar-size: 3px;
117
119
  }
118
120
 
119
- /* Attachment tile now uses Card + Flex, no custom layout needed */
121
+ /*
122
+ * Attachments and items are one pill: a lead tile (thumbnail or tinted icon),
123
+ * a label and a remove button. A custom `renderAttachment` keeps only the
124
+ * plain .rt-ChatbarAttachment hook.
125
+ */
126
+ .rt-ChatbarAttachment {
127
+ position: relative;
128
+ }
129
+
130
+ .rt-ChatbarItem {
131
+ display: inline-flex;
132
+ align-items: center;
133
+ gap: var(--space-2);
134
+ flex-shrink: 0;
135
+ box-sizing: border-box;
136
+ max-width: 240px;
137
+ padding: var(--chatbar-item-padding);
138
+ padding-right: calc(var(--chatbar-item-padding) + var(--space-1));
139
+ border: 1px solid var(--gray-a5);
140
+ border-radius: calc(var(--chatbar-item-lead-radius) + var(--chatbar-item-padding));
141
+ background-color: var(--color-panel-solid);
142
+ box-shadow: 0 1px 2px var(--gray-a3);
143
+ color: var(--gray-12);
144
+ }
145
+
146
+ .rt-ChatbarItem:where([data-status='error']) {
147
+ border-color: var(--red-a7);
148
+ }
120
149
 
121
- .rt-ChatbarAttachmentPreview {
122
- height: var(--chatbar-attachment-thumb);
123
- width: var(--chatbar-attachment-thumb);
124
- min-width: var(--chatbar-attachment-thumb);
150
+ .rt-ChatbarItemLead {
151
+ height: var(--chatbar-item-lead);
152
+ width: var(--chatbar-item-lead);
125
153
  flex-shrink: 0;
126
- border-radius: var(--radius-1);
154
+ border-radius: var(--chatbar-item-lead-radius);
127
155
  overflow: hidden;
128
156
  display: inline-flex;
129
157
  align-items: center;
130
158
  justify-content: center;
159
+ background: var(--accent-a3);
160
+ color: var(--accent-11);
161
+
162
+ /* stylelint-disable-next-line selector-max-type */
163
+ & :where(svg) {
164
+ width: calc(var(--chatbar-item-lead) * 0.6);
165
+ height: calc(var(--chatbar-item-lead) * 0.6);
166
+ }
167
+
168
+ &:where([data-kind='image']) {
169
+ background: var(--gray-a3);
170
+ }
171
+ }
172
+
173
+ /* An attachment's file icon and spinner stay neutral */
174
+ .rt-ChatbarAttachment .rt-ChatbarItemLead:where([data-kind='icon']) {
131
175
  background: var(--gray-a3);
176
+ color: var(--gray-11);
132
177
  }
133
178
 
134
179
  .rt-ChatbarAttachmentImage {
180
+ width: 100%;
135
181
  height: 100%;
136
- width: auto;
137
- object-fit: contain;
182
+ object-fit: cover;
138
183
  max-width: none;
139
184
  }
140
185
 
141
- /* PaperclipIcon handles its own sizing via IconButton */
142
-
143
- .rt-ChatbarAttachment {
144
- position: relative;
145
- background-color: var(--gray-1);
146
- border-radius: var(--radius-1);
147
- }
148
-
149
- /* Maximum width for non-image attachments */
150
- .rt-ChatbarAttachment:where([data-kind='file']) {
151
- max-width: 200px;
186
+ .rt-ChatbarItemLabel {
187
+ min-width: 0;
152
188
  }
153
189
 
154
- .rt-ChatbarAttachmentRemove {
155
- position: absolute;
156
- top: var(--chatbar-remove-offset);
157
- right: var(--chatbar-remove-offset);
190
+ .rt-ChatbarItemRemove {
191
+ flex-shrink: 0;
192
+ margin-left: calc(var(--space-1) * -1);
158
193
  }
159
194
 
160
- /* Size-dependent radius for attachment container and preview */
161
195
  @breakpoints {
162
- .rt-ChatbarRoot:where(.rt-r-size-1) :where(.rt-ChatbarAttachment, .rt-ChatbarAttachmentPreview) {
163
- border-radius: var(--radius-1);
164
- /* border-radius: var(--radius-1); */
165
- }
166
- .rt-ChatbarRoot:where(.rt-r-size-2) :where(.rt-ChatbarAttachment, .rt-ChatbarAttachmentPreview) {
167
- border-radius: var(--radius-2);
168
- }
169
- .rt-ChatbarRoot:where(.rt-r-size-3) :where(.rt-ChatbarAttachment, .rt-ChatbarAttachmentPreview) {
170
- border-radius: var(--radius-3);
196
+ .rt-ChatbarRoot {
197
+ &:where(.rt-r-size-1) {
198
+ --chatbar-item-lead: var(--space-4);
199
+ --chatbar-item-lead-radius: var(--radius-1);
200
+ --chatbar-item-padding: var(--space-1);
201
+ }
202
+ &:where(.rt-r-size-2) {
203
+ --chatbar-item-lead: var(--space-5);
204
+ --chatbar-item-lead-radius: var(--radius-2);
205
+ --chatbar-item-padding: var(--space-1);
206
+ }
207
+ &:where(.rt-r-size-3) {
208
+ --chatbar-item-lead: calc(var(--space-5) + var(--space-1));
209
+ --chatbar-item-lead-radius: var(--radius-2);
210
+ --chatbar-item-padding: calc(var(--space-1) * 1.5);
211
+ }
171
212
  }
172
213
  }
173
214
 
@@ -575,24 +616,18 @@
575
616
  &:where(.rt-r-size-1) {
576
617
  font-size: var(--font-size-1);
577
618
  line-height: var(--line-height-1);
578
- --chatbar-attachment-thumb: var(--space-8);
579
- --chatbar-remove-offset: calc(var(--space-1) * 0.5);
580
619
  /* --chatbar-attachments-radius: min(var(--radius-5), calc(var(--radius-1) + var(--space-1))); */
581
620
  --chatbar-attachments-radius: var(--radius-1);
582
621
  }
583
622
  &:where(.rt-r-size-2) {
584
623
  font-size: var(--font-size-2);
585
624
  line-height: var(--line-height-2);
586
- --chatbar-attachment-thumb: var(--space-9);
587
- --chatbar-remove-offset: var(--space-1);
588
625
  /* --chatbar-attachments-radius: min(var(--radius-6), calc(var(--radius-2) + var(--space-2))); */
589
626
  --chatbar-attachments-radius: var(--radius-2);
590
627
  }
591
628
  &:where(.rt-r-size-3) {
592
629
  font-size: var(--font-size-3);
593
630
  line-height: var(--line-height-3);
594
- --chatbar-attachment-thumb: var(--space-9);
595
- --chatbar-remove-offset: var(--space-2);
596
631
  /* --chatbar-attachments-radius: min(var(--radius-7), calc(var(--radius-3) + var(--space-3))); */
597
632
  --chatbar-attachments-radius: var(--radius-3);
598
633
  }
@@ -1030,18 +1030,22 @@ InlineEnd.displayName = 'Chatbar.InlineEnd';
1030
1030
  /**
1031
1031
  * Renders a horizontally scrollable list of attachments above the inline row.
1032
1032
  * Hidden when empty unless `forceMount`. Override per-item with `renderAttachment`.
1033
+ * `Chatbar.Item`s passed as children follow the attachments in the same row.
1033
1034
  */
1034
1035
  interface AttachmentsRowProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> {
1035
1036
  asChild?: boolean;
1036
1037
  forceMount?: boolean;
1037
1038
  /** If provided, custom-render a tile; otherwise default tile is used */
1038
1039
  renderAttachment?: (attachment: ChatbarAttachment) => React.ReactNode;
1040
+ /** `Chatbar.Item`s: things the message refers to that are not files. */
1041
+ children?: React.ReactNode;
1039
1042
  }
1040
1043
 
1041
1044
  const AttachmentsRow = React.forwardRef<HTMLDivElement, AttachmentsRowProps>((props, forwardedRef) => {
1042
- const { asChild, forceMount, renderAttachment, className, ...divProps } = props;
1045
+ const { asChild, forceMount, renderAttachment, className, children, ...divProps } = props;
1043
1046
  const ctx = useChatbarContext();
1044
- if (ctx.attachments.length === 0 && !forceMount) return null;
1047
+ const hasItems = React.Children.toArray(children).length > 0;
1048
+ if (ctx.attachments.length === 0 && !hasItems && !forceMount) return null;
1045
1049
  const Comp = asChild ? Slot : 'div';
1046
1050
  return (
1047
1051
  <m.div layout="position" transition={LAYOUT_TRANSITION}>
@@ -1053,6 +1057,7 @@ const AttachmentsRow = React.forwardRef<HTMLDivElement, AttachmentsRowProps>((pr
1053
1057
  {renderAttachment?.(att)}
1054
1058
  </Attachment>
1055
1059
  ))}
1060
+ {children}
1056
1061
  </Flex>
1057
1062
  </ScrollArea>
1058
1063
  </Comp>
@@ -1061,6 +1066,50 @@ const AttachmentsRow = React.forwardRef<HTMLDivElement, AttachmentsRowProps>((pr
1061
1066
  });
1062
1067
  AttachmentsRow.displayName = 'Chatbar.AttachmentsRow';
1063
1068
 
1069
+ /**
1070
+ * Moves focus off a pill that is about to unmount, to the next pill's remove
1071
+ * button, the previous one's, or the text, so keyboard users are not dropped
1072
+ * to <body>.
1073
+ */
1074
+ function moveFocusOffPill(button: HTMLButtonElement, textareaRef: React.RefObject<HTMLTextAreaElement | null>) {
1075
+ const pill = button.closest('[role="listitem"]');
1076
+ const pills = pill?.parentElement ? Array.from(pill.parentElement.children) : [];
1077
+ const index = pill ? pills.indexOf(pill) : -1;
1078
+ const neighbour = pills[index + 1] ?? pills[index - 1];
1079
+ const nextButton = neighbour?.querySelector<HTMLButtonElement>('.rt-ChatbarItemRemove');
1080
+ if (nextButton) nextButton.focus();
1081
+ else textareaRef.current?.focus({ preventScroll: true });
1082
+ }
1083
+
1084
+ /** The pill an attachment and an item share: a lead tile, a label and ×. */
1085
+ const Pill: React.FC<{
1086
+ lead: React.ReactNode;
1087
+ leadKind: 'image' | 'icon';
1088
+ label: React.ReactNode;
1089
+ /** Read after the label by screen readers only, e.g. a file's size. */
1090
+ detail?: string;
1091
+ removeLabel: string;
1092
+ onRemove?: (event: React.MouseEvent<HTMLButtonElement>) => void;
1093
+ }> = ({ lead, leadKind, label, detail, removeLabel, onRemove }) => {
1094
+ const ctx = useChatbarContext();
1095
+ return (
1096
+ <>
1097
+ <span className="rt-ChatbarItemLead" data-kind={leadKind} aria-hidden>
1098
+ {lead}
1099
+ </span>
1100
+ <Text className="rt-ChatbarItemLabel" size={ctx.size} truncate>
1101
+ {label}
1102
+ {detail ? <VisuallyHidden>, {detail}</VisuallyHidden> : null}
1103
+ </Text>
1104
+ {onRemove && (
1105
+ <IconButton className="rt-ChatbarItemRemove" aria-label={removeLabel} size="1" variant="ghost" color="gray" onClick={onRemove}>
1106
+ <CloseIcon />
1107
+ </IconButton>
1108
+ )}
1109
+ </>
1110
+ );
1111
+ };
1112
+
1064
1113
  /** Default tile renderer for a single attachment. */
1065
1114
  interface AttachmentProps extends React.ComponentPropsWithoutRef<'div'> {
1066
1115
  attachment: ChatbarAttachment;
@@ -1079,71 +1128,98 @@ const Attachment = React.forwardRef<HTMLDivElement, AttachmentProps>((props, for
1079
1128
  const locked = ctx.disabled || ctx.readOnly;
1080
1129
 
1081
1130
  const handleRemove = (event: React.MouseEvent<HTMLButtonElement>) => {
1082
- // Move focus before the tile unmounts so keyboard users are not dropped to <body>
1083
- const tile = event.currentTarget.closest('[role="listitem"]');
1084
- const tiles = tile?.parentElement ? Array.from(tile.parentElement.children) : [];
1085
- const index = tile ? tiles.indexOf(tile) : -1;
1086
- const neighbour = tiles[index + 1] ?? tiles[index - 1];
1087
- const nextButton = neighbour?.querySelector<HTMLButtonElement>('.rt-ChatbarAttachmentRemove');
1088
- if (nextButton) nextButton.focus();
1089
- else ctx.textareaRef.current?.focus({ preventScroll: true });
1131
+ moveFocusOffPill(event.currentTarget, ctx.textareaRef);
1090
1132
  ctx.removeAttachment(attachment.id);
1091
1133
  };
1092
1134
 
1135
+ const lead =
1136
+ attachment.status === 'uploading' ? (
1137
+ <Spinner size="1" />
1138
+ ) : isImage ? (
1139
+ <img className="rt-ChatbarAttachmentImage" src={attachment.url} alt="" />
1140
+ ) : (
1141
+ <FileTextIcon />
1142
+ );
1143
+
1093
1144
  return (
1094
1145
  <Comp
1095
1146
  {...divProps}
1096
1147
  ref={forwardedRef}
1097
- className={classNames('rt-ChatbarAttachment', className)}
1148
+ className={classNames(children ? 'rt-ChatbarAttachment' : 'rt-ChatbarAttachment rt-ChatbarItem', className)}
1098
1149
  role="listitem"
1099
1150
  data-kind={isImage ? 'image' : 'file'}
1100
1151
  data-status={attachment.status}
1101
1152
  title={attachment.name}
1102
1153
  >
1103
1154
  {children ?? (
1104
- <Flex align="center" gap="2" pr={!isImage ? '6' : undefined}>
1105
- <div className="rt-ChatbarAttachmentPreview" aria-hidden>
1106
- {isImage ? <img className="rt-ChatbarAttachmentImage" src={attachment.url} alt="" /> : <FileTextIcon />}
1107
- </div>
1108
- {isImage ? (
1109
- <VisuallyHidden>
1110
- {attachment.name}, {sizeLabel}
1111
- {statusLabel ? `, ${statusLabel}` : ''}
1112
- </VisuallyHidden>
1113
- ) : (
1114
- <Flex direction="column" gap="0" minWidth="0">
1115
- <Text size={ctx.size} weight="medium" truncate>
1116
- {attachment.name}
1117
- </Text>
1118
- <Text
1119
- size="1"
1120
- color={attachment.status === 'error' ? 'red' : undefined}
1121
- emphasis={attachment.status === 'error' ? undefined : 'medium'}
1122
- >
1123
- {sizeLabel}
1124
- {statusLabel ? ` · ${statusLabel}` : ''}
1125
- </Text>
1126
- </Flex>
1127
- )}
1128
- {!locked && (
1129
- <IconButton
1130
- className="rt-ChatbarAttachmentRemove"
1131
- aria-label={`Remove ${attachment.name}`}
1132
- size="1"
1133
- variant="classic"
1134
- color="gray"
1135
- onClick={handleRemove}
1136
- >
1137
- <CloseIcon />
1138
- </IconButton>
1139
- )}
1140
- </Flex>
1155
+ <Pill
1156
+ lead={lead}
1157
+ leadKind={isImage && attachment.status !== 'uploading' ? 'image' : 'icon'}
1158
+ label={attachment.name}
1159
+ detail={statusLabel ? `${sizeLabel}, ${statusLabel}` : sizeLabel}
1160
+ removeLabel={`Remove ${attachment.name}`}
1161
+ onRemove={locked ? undefined : handleRemove}
1162
+ />
1141
1163
  )}
1142
1164
  </Comp>
1143
1165
  );
1144
1166
  });
1145
1167
  Attachment.displayName = 'Chatbar.Attachment';
1146
1168
 
1169
+ /**
1170
+ * Something the message refers to that is not a file: a scene object, a
1171
+ * picked mode, a selection. The same pill as an attachment, placed in
1172
+ * `Chatbar.AttachmentsRow` as a child. The app owns the list, so removing one
1173
+ * calls `onRemove` and nothing else; leave it out for a pill that cannot be
1174
+ * removed.
1175
+ */
1176
+ interface ItemProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children' | 'color'> {
1177
+ /** The label. Also names the remove button: "Remove {label}". */
1178
+ children: string;
1179
+ /** Drawn in the lead tile, tinted with `color`. */
1180
+ icon?: React.ReactNode;
1181
+ /** A thumbnail for the lead tile, in place of the icon. */
1182
+ image?: string;
1183
+ /** Tint of the icon tile. Defaults to gray. */
1184
+ color?: (typeof accentColors)[number];
1185
+ onRemove?: () => void;
1186
+ /** Overrides the remove button's label. */
1187
+ removeLabel?: string;
1188
+ }
1189
+
1190
+ const Item = React.forwardRef<HTMLDivElement, ItemProps>((props, forwardedRef) => {
1191
+ const { children, icon, image, color, onRemove, removeLabel, className, ...divProps } = props;
1192
+ const ctx = useChatbarContext();
1193
+ const locked = ctx.disabled || ctx.readOnly;
1194
+
1195
+ const handleRemove = onRemove
1196
+ ? (event: React.MouseEvent<HTMLButtonElement>) => {
1197
+ moveFocusOffPill(event.currentTarget, ctx.textareaRef);
1198
+ onRemove();
1199
+ }
1200
+ : undefined;
1201
+
1202
+ return (
1203
+ <div
1204
+ {...divProps}
1205
+ ref={forwardedRef}
1206
+ className={classNames('rt-ChatbarItem', className)}
1207
+ role="listitem"
1208
+ data-accent-color={image ? undefined : (color ?? 'gray')}
1209
+ title={children}
1210
+ >
1211
+ <Pill
1212
+ lead={image ? <img className="rt-ChatbarAttachmentImage" src={image} alt="" /> : icon}
1213
+ leadKind={image ? 'image' : 'icon'}
1214
+ label={children}
1215
+ removeLabel={removeLabel ?? `Remove ${children}`}
1216
+ onRemove={locked ? undefined : handleRemove}
1217
+ />
1218
+ </div>
1219
+ );
1220
+ });
1221
+ Item.displayName = 'Chatbar.Item';
1222
+
1147
1223
  interface AttachTriggerProps extends React.ComponentPropsWithoutRef<'button'> {
1148
1224
  asChild?: boolean;
1149
1225
  /** Overrides Root `accept` for files chosen through this trigger */
@@ -1346,13 +1422,14 @@ const Send = React.forwardRef<HTMLButtonElement, SendProps>((props, forwardedRef
1346
1422
  });
1347
1423
  Send.displayName = 'Chatbar.Send';
1348
1424
 
1349
- export { Root, Textarea, InlineStart, InlineEnd, AttachmentsRow, Attachment, AttachTrigger, Row, RowStart, RowEnd, Send };
1425
+ export { Root, Textarea, InlineStart, InlineEnd, AttachmentsRow, Attachment, Item, AttachTrigger, Row, RowStart, RowEnd, Send };
1350
1426
  export type {
1351
1427
  RootProps as ChatbarRootProps,
1352
1428
  TextareaProps as ChatbarTextareaProps,
1353
1429
  InlineSlotProps as ChatbarInlineSlotProps,
1354
1430
  AttachmentsRowProps as ChatbarAttachmentsRowProps,
1355
1431
  AttachmentProps as ChatbarAttachmentProps,
1432
+ ItemProps as ChatbarItemProps,
1356
1433
  AttachTriggerProps as ChatbarAttachTriggerProps,
1357
1434
  RowProps as ChatbarRowProps,
1358
1435
  RowSlotProps as ChatbarRowSlotProps,
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The pre-paint half of light and dark mode (see `use-appearance.ts`). Kept in its own module
3
+ * with no client directive, so a server component such as a Next.js root layout can import the
4
+ * string and inline it in `<head>`.
5
+ */
6
+
7
+ const APPEARANCE_STORAGE_KEY = 'kookie-appearance';
8
+
9
+ /**
10
+ * Inline this in `<head>`, before any stylesheet paints, e.g.
11
+ * `<script dangerouslySetInnerHTML={{ __html: appearanceScript }} />`.
12
+ *
13
+ * Storage is read inside its own try/catch: browsers that block site data throw on access,
14
+ * and that must not skip the stamp. `matchMedia` always answers.
15
+ */
16
+ const appearanceScript = `(function () {
17
+ var e = document.documentElement;
18
+ var a = null;
19
+ try { a = localStorage.getItem(${JSON.stringify(APPEARANCE_STORAGE_KEY)}); } catch (err) {}
20
+ var dark = a === "light" ? false : a === "dark" ? true : matchMedia("(prefers-color-scheme: dark)").matches;
21
+ var mode = dark ? "dark" : "light";
22
+ e.classList.remove("light", "dark");
23
+ e.classList.add(mode);
24
+ e.setAttribute("data-appearance", mode);
25
+ e.style.colorScheme = mode;
26
+ })();`;
27
+
28
+ export { appearanceScript, APPEARANCE_STORAGE_KEY };
@@ -2,3 +2,6 @@ export { useLiveAnnouncer } from './use-live-announcer.js';
2
2
  export { useBodyPointerEventsCleanup } from './use-body-pointer-events-cleanup.js';
3
3
  export { useTooltipWrapper } from './use-tooltip-wrapper.js';
4
4
  export { useToggleState } from './use-toggle-state.js';
5
+ export { useAppearance, setAppearance } from './use-appearance.js';
6
+ export { appearanceScript, APPEARANCE_STORAGE_KEY } from './appearance-script.js';
7
+ export type { AppearanceChoice, ResolvedAppearance } from './use-appearance.js';
@@ -0,0 +1,119 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { APPEARANCE_STORAGE_KEY } from './appearance-script.js';
5
+
6
+ /**
7
+ * Light and dark mode, decided before the first paint and kept on `<html>`.
8
+ *
9
+ * The server cannot know the visitor's mode, so `appearanceScript` runs synchronously in
10
+ * `<head>`: the stored choice first, `prefers-color-scheme` otherwise. It writes the `light`
11
+ * or `dark` class (which every token and component stylesheet already keys off) and
12
+ * `data-appearance` on `<html>`. The root `<Theme>` keeps `appearance="inherit"`, so it
13
+ * writes no class of its own and `<html>` is the one source of truth. Nested themes and
14
+ * portals inherit it from there.
15
+ *
16
+ * `useAppearance` is the client half: an external store over `<html>` and the same storage
17
+ * key. It never mirrors the mode into React state that could disagree with the DOM.
18
+ */
19
+
20
+ type AppearanceChoice = 'system' | 'light' | 'dark';
21
+ type ResolvedAppearance = 'light' | 'dark';
22
+
23
+ const listeners = new Set<() => void>();
24
+
25
+ function emit() {
26
+ for (const listener of listeners) listener();
27
+ }
28
+
29
+ function readChoice(): AppearanceChoice {
30
+ try {
31
+ const value = globalThis.localStorage?.getItem(APPEARANCE_STORAGE_KEY);
32
+ return value === 'light' || value === 'dark' ? value : 'system';
33
+ } catch {
34
+ return 'system';
35
+ }
36
+ }
37
+
38
+ function systemAppearance(): ResolvedAppearance {
39
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
40
+ }
41
+
42
+ function stamp(mode: ResolvedAppearance) {
43
+ const root = document.documentElement;
44
+ root.classList.remove('light', 'dark');
45
+ root.classList.add(mode);
46
+ root.setAttribute('data-appearance', mode);
47
+ root.style.colorScheme = mode;
48
+ }
49
+
50
+ function readResolved(): ResolvedAppearance {
51
+ const root = document.documentElement;
52
+ if (root.classList.contains('dark') || root.classList.contains('dark-theme')) return 'dark';
53
+ if (root.classList.contains('light') || root.classList.contains('light-theme')) return 'light';
54
+ return systemAppearance();
55
+ }
56
+
57
+ let snapshot: { choice: AppearanceChoice; resolved: ResolvedAppearance } | null = null;
58
+
59
+ function getSnapshot() {
60
+ const choice = readChoice();
61
+ const resolved = readResolved();
62
+ if (!snapshot || snapshot.choice !== choice || snapshot.resolved !== resolved) {
63
+ snapshot = { choice, resolved };
64
+ }
65
+ return snapshot;
66
+ }
67
+
68
+ const serverSnapshot = { choice: 'system' as AppearanceChoice, resolved: 'light' as ResolvedAppearance };
69
+
70
+ function subscribe(listener: () => void) {
71
+ listeners.add(listener);
72
+ const media = window.matchMedia('(prefers-color-scheme: dark)');
73
+ // With no stored choice, follow the system as it changes.
74
+ const onSystemChange = () => {
75
+ if (readChoice() === 'system') {
76
+ stamp(systemAppearance());
77
+ emit();
78
+ }
79
+ };
80
+ // Another tab changed the choice.
81
+ const onStorage = (event: StorageEvent) => {
82
+ if (event.key !== APPEARANCE_STORAGE_KEY) return;
83
+ const choice = readChoice();
84
+ stamp(choice === 'system' ? systemAppearance() : choice);
85
+ emit();
86
+ };
87
+ media.addEventListener('change', onSystemChange);
88
+ window.addEventListener('storage', onStorage);
89
+ return () => {
90
+ listeners.delete(listener);
91
+ media.removeEventListener('change', onSystemChange);
92
+ window.removeEventListener('storage', onStorage);
93
+ };
94
+ }
95
+
96
+ /** Applies a choice to `<html>` and stores it. The change applies even if storage is blocked. */
97
+ function setAppearance(choice: AppearanceChoice) {
98
+ try {
99
+ if (choice === 'system') localStorage.removeItem(APPEARANCE_STORAGE_KEY);
100
+ else localStorage.setItem(APPEARANCE_STORAGE_KEY, choice);
101
+ } catch {
102
+ // Storage is blocked: the mode still changes for this page.
103
+ }
104
+ stamp(choice === 'system' ? systemAppearance() : choice);
105
+ emit();
106
+ }
107
+
108
+ /**
109
+ * The page's light or dark mode. `choice` is what the person picked (`system` when they
110
+ * haven't); `appearance` is what is showing. On the server and in the first client render it
111
+ * reports `system` / `light`, then corrects without a hydration mismatch.
112
+ */
113
+ function useAppearance() {
114
+ const { choice, resolved } = React.useSyncExternalStore(subscribe, getSnapshot, () => serverSnapshot);
115
+ return { choice, appearance: resolved, setAppearance } as const;
116
+ }
117
+
118
+ export { useAppearance, setAppearance };
119
+ export type { AppearanceChoice, ResolvedAppearance };