nfx-ui 0.1.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.
- package/README.md +235 -0
- package/dist/animations.cjs +3 -0
- package/dist/animations.d.ts +102 -0
- package/dist/animations.mjs +14 -0
- package/dist/apis.cjs +5 -0
- package/dist/apis.cjs.map +1 -0
- package/dist/apis.d.ts +7 -0
- package/dist/apis.mjs +18 -0
- package/dist/apis.mjs.map +1 -0
- package/dist/chunk-BounceLoading-B54QEw0n.mjs +244 -0
- package/dist/chunk-BounceLoading-B54QEw0n.mjs.map +1 -0
- package/dist/chunk-BounceLoading-C6n4BZVJ.cjs +11 -0
- package/dist/chunk-BounceLoading-C6n4BZVJ.cjs.map +1 -0
- package/dist/chunk-animations-Brp-bsaE.mjs +1243 -0
- package/dist/chunk-animations-Brp-bsaE.mjs.map +1 -0
- package/dist/chunk-animations-e2F3zuP9.cjs +190 -0
- package/dist/chunk-animations-e2F3zuP9.cjs.map +1 -0
- package/dist/chunk-chunk-BFrxaqQT.cjs +1 -0
- package/dist/chunk-i18n-Bp6pPM9n.mjs +207 -0
- package/dist/chunk-i18n-Bp6pPM9n.mjs.map +1 -0
- package/dist/chunk-i18n-_7W7guSV.cjs +3 -0
- package/dist/chunk-i18n-_7W7guSV.cjs.map +1 -0
- package/dist/chunk-lstorage-BVCD00Ow.mjs +27 -0
- package/dist/chunk-lstorage-BVCD00Ow.mjs.map +1 -0
- package/dist/chunk-lstorage-BnxLXHgH.cjs +3 -0
- package/dist/chunk-lstorage-BnxLXHgH.cjs.map +1 -0
- package/dist/chunk-lucide-BhgnmTNo.mjs +158 -0
- package/dist/chunk-lucide-BhgnmTNo.mjs.map +1 -0
- package/dist/chunk-lucide-CP2lvOPY.cjs +3 -0
- package/dist/chunk-lucide-CP2lvOPY.cjs.map +1 -0
- package/dist/chunk-preference-CYl68oeU.cjs +3 -0
- package/dist/chunk-preference-CYl68oeU.cjs.map +1 -0
- package/dist/chunk-preference-DImtu5jI.mjs +51 -0
- package/dist/chunk-preference-DImtu5jI.mjs.map +1 -0
- package/dist/chunk-types-BE3JCLff.cjs +3 -0
- package/dist/chunk-types-BE3JCLff.cjs.map +1 -0
- package/dist/chunk-types-BkFxelHl.mjs +20 -0
- package/dist/chunk-types-BkFxelHl.mjs.map +1 -0
- package/dist/chunk-types-C_opkZGr.cjs +3 -0
- package/dist/chunk-types-C_opkZGr.cjs.map +1 -0
- package/dist/chunk-types-CkbZrFqZ.cjs +3 -0
- package/dist/chunk-types-CkbZrFqZ.cjs.map +1 -0
- package/dist/chunk-types-DNPBKfmx.mjs +11 -0
- package/dist/chunk-types-DNPBKfmx.mjs.map +1 -0
- package/dist/chunk-types-SD4MzUGp.mjs +11 -0
- package/dist/chunk-types-SD4MzUGp.mjs.map +1 -0
- package/dist/chunk-useLayout-BAJHOIL3.cjs +3 -0
- package/dist/chunk-useLayout-BAJHOIL3.cjs.map +1 -0
- package/dist/chunk-useLayout-DPxlynT-.mjs +12 -0
- package/dist/chunk-useLayout-DPxlynT-.mjs.map +1 -0
- package/dist/chunk-useTheme-DgleVMMh.cjs +3 -0
- package/dist/chunk-useTheme-DgleVMMh.cjs.map +1 -0
- package/dist/chunk-useTheme-oHcq3d0o.mjs +13 -0
- package/dist/chunk-useTheme-oHcq3d0o.mjs.map +1 -0
- package/dist/components.cjs +8 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.d.ts +411 -0
- package/dist/components.mjs +1688 -0
- package/dist/components.mjs.map +1 -0
- package/dist/constants.cjs +5 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.ts +130 -0
- package/dist/constants.mjs +85 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/events.cjs +5 -0
- package/dist/events.cjs.map +1 -0
- package/dist/events.d.ts +66 -0
- package/dist/events.mjs +31 -0
- package/dist/events.mjs.map +1 -0
- package/dist/hooks.cjs +5 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.ts +316 -0
- package/dist/hooks.mjs +107 -0
- package/dist/hooks.mjs.map +1 -0
- package/dist/icons.cjs +3 -0
- package/dist/icons.d.ts +218 -0
- package/dist/icons.mjs +76 -0
- package/dist/languages.cjs +5 -0
- package/dist/languages.cjs.map +1 -0
- package/dist/languages.d.ts +174 -0
- package/dist/languages.mjs +112 -0
- package/dist/languages.mjs.map +1 -0
- package/dist/layouts.cjs +5 -0
- package/dist/layouts.cjs.map +1 -0
- package/dist/layouts.d.ts +209 -0
- package/dist/layouts.mjs +460 -0
- package/dist/layouts.mjs.map +1 -0
- package/dist/navigations.cjs +5 -0
- package/dist/navigations.cjs.map +1 -0
- package/dist/navigations.d.ts +72 -0
- package/dist/navigations.mjs +30 -0
- package/dist/navigations.mjs.map +1 -0
- package/dist/preference.cjs +3 -0
- package/dist/preference.d.ts +94 -0
- package/dist/preference.mjs +14 -0
- package/dist/services.cjs +5 -0
- package/dist/services.cjs.map +1 -0
- package/dist/services.d.ts +8 -0
- package/dist/services.mjs +26 -0
- package/dist/services.mjs.map +1 -0
- package/dist/stores.cjs +5 -0
- package/dist/stores.cjs.map +1 -0
- package/dist/stores.d.ts +101 -0
- package/dist/stores.mjs +167 -0
- package/dist/stores.mjs.map +1 -0
- package/dist/themes.cjs +5 -0
- package/dist/themes.cjs.map +1 -0
- package/dist/themes.d.ts +229 -0
- package/dist/themes.mjs +894 -0
- package/dist/themes.mjs.map +1 -0
- package/dist/types.cjs +2 -0
- package/dist/types.d.ts +147 -0
- package/dist/types.mjs +2 -0
- package/dist/utils.cjs +5 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.ts +374 -0
- package/dist/utils.mjs +293 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +196 -0
package/dist/events.mjs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
(function(){try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode(`.styles-module__loading___bgEAk{justify-content:center;align-items:center;display:inline-flex}.styles-module__loading___bgEAk svg polyline{fill:none;stroke-width:3px;stroke-linecap:round;stroke-linejoin:round}.styles-module__loading___bgEAk svg polyline.styles-module__back___XLPvD{fill:none;stroke:var(--color-primary-alpha,#ff4d5033)}.styles-module__loading___bgEAk svg polyline.styles-module__front___hSxig{fill:none;stroke:var(--color-primary,#ff4d4f);stroke-dasharray:48 144;stroke-dashoffset:192px;animation:1.4s linear infinite styles-module__dash_682___AQzo6}@keyframes styles-module__dash_682___AQzo6{72.5%{opacity:0}to{stroke-dashoffset:0}}.styles-module__loader___E7OIM{justify-content:center;align-items:center;width:fit-content;height:fit-content;display:flex}.styles-module__truckWrapper___Sk4zX{flex-direction:column;justify-content:flex-end;align-items:center;width:100%;height:100%;display:flex;position:relative;overflow-x:hidden}.styles-module__truckBody___j7w2C{width:65%;height:fit-content;margin-bottom:6px;animation:1s linear infinite styles-module__motion___IiNlW}@keyframes styles-module__motion___IiNlW{0%{transform:translateY(0)}50%{transform:translateY(3px)}to{transform:translateY(0)}}.styles-module__truckTires___4ncTl{justify-content:space-between;align-items:center;width:65%;height:fit-content;padding:0 10px 0 15px;display:flex;position:absolute;bottom:0}.styles-module__tiresvg___IBQcN{width:24px}.styles-module__road___sxx-E{background-color:var(--color-fg-heading);border-radius:3px;align-self:flex-end;width:100%;height:1.5px;position:relative;bottom:0}.styles-module__road___sxx-E:before{content:"";background-color:var(--color-fg-heading);border-left:10px solid var(--color-bg);border-radius:3px;width:20px;height:100%;animation:1.4s linear infinite styles-module__roadAnimation___yvrHP;position:absolute;right:-50%}.styles-module__road___sxx-E:after{content:"";background-color:var(--color-fg-heading);border-left:4px solid var(--color-bg);border-radius:3px;width:10px;height:100%;animation:1.4s linear infinite styles-module__roadAnimation___yvrHP;position:absolute;right:-65%}.styles-module__lampPost___okcN5{height:45%;animation:1.4s linear infinite styles-module__roadAnimation___yvrHP;position:absolute;bottom:0;right:-90%}@keyframes styles-module__roadAnimation___yvrHP{0%{transform:translate(0)}to{transform:translate(-350px)}}.styles-module__loader___pFUzL{justify-content:center;align-items:center;display:inline-flex;position:relative}.styles-module__loader___pFUzL:before{content:"";background:var(--color-primary);opacity:.3;border-radius:50%;width:100%;height:5px;animation:.5s linear infinite styles-module__shadow324___sutUe;position:absolute;top:calc(100% + 12px);left:0}.styles-module__loader___pFUzL:after{content:"";background:var(--color-primary);width:100%;height:100%;position:absolute;top:0;left:0}.styles-module__square___GKjhm:after{border-radius:4px;animation:.5s linear infinite styles-module__jump7456Square___Z-D9b}.styles-module__circle___bUpSN:after{border-radius:50%;animation:.5s linear infinite styles-module__jump7456Circle___2AfF7}@keyframes styles-module__jump7456Square___Z-D9b{15%{border-bottom-right-radius:3px}25%{transform:translateY(9px)rotate(22.5deg)}50%{border-bottom-right-radius:40px;transform:translateY(18px)scaleY(.9)rotate(45deg)}75%{transform:translateY(9px)rotate(67.5deg)}to{transform:translateY(0)rotate(90deg)}}@keyframes styles-module__jump7456Circle___2AfF7{15%{border-bottom-right-radius:50%}25%{transform:translateY(9px)rotate(22.5deg)}50%{border-bottom-right-radius:40px;transform:translateY(18px)scaleY(.9)rotate(45deg)}75%{transform:translateY(9px)rotate(67.5deg)}to{transform:translateY(0)rotate(90deg)}}@keyframes styles-module__shadow324___sutUe{0%,to{transform:scale(1)}50%{transform:scaleX(1.2)}}.style-module__waves___oR3u7{width:100%;height:100%;margin:0;padding:0;position:absolute;top:0;left:0;overflow:hidden}.style-module__waves___oR3u7:before{content:"";width:.5rem;height:.5rem;transform:translate3d(calc(var(--x) - 50%), calc(var(--y) - 50%), 0);will-change:transform;background:#160000;border-radius:50%;position:absolute;top:0;left:0}.style-module__wavesCanvas___zkhTC{width:100%;height:100%;display:block}.style-module__squaresCanvas___22kMc{border:none;width:100%;height:100%;display:block}.style-module__container___HkxIe{background-color:#000;width:100%;height:100%;position:relative;overflow:hidden}.style-module__canvas___MR9JX{width:100%;height:100%;display:block}.style-module__outerVignette___i75nw{pointer-events:none;background:radial-gradient(circle,#0000 60%,#000 100%);width:100%;height:100%;position:absolute;top:0;left:0}.style-module__centerVignette___n9uVG{pointer-events:none;background:radial-gradient(circle,#000c 0%,#0000 60%);width:100%;height:100%;position:absolute;top:0;left:0}.style-module__container___Hh3-c{width:100%;height:100%;position:relative;overflow:hidden}.styles-module__button___RbliA{cursor:pointer;border:1px solid #0000;border-radius:.5rem;outline:none;justify-content:center;align-items:center;gap:.5rem;font-family:inherit;font-weight:500;transition:all .2s;display:inline-flex;position:relative}.styles-module__button___RbliA:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.styles-module__button___RbliA:disabled{cursor:not-allowed;opacity:.6}.styles-module__button___RbliA.styles-module__small___yK0Yp{min-height:2rem;padding:.5rem 1rem;font-size:.8125rem}.styles-module__button___RbliA.styles-module__medium___eBTch{min-height:2.5rem;padding:.75rem 1.5rem;font-size:.875rem}.styles-module__button___RbliA.styles-module__large___pIZkl{min-height:3rem;padding:1rem 2rem;font-size:1rem}.styles-module__button___RbliA.styles-module__primary___qsZpA{background:var(--color-primary);border-color:var(--color-primary);color:var(--color-primary-fg,#fff)}.styles-module__button___RbliA.styles-module__primary___qsZpA:hover:not(:disabled){background:var(--color-primary-light);border-color:var(--color-primary-light);transform:translateY(-1px)}.styles-module__button___RbliA.styles-module__primary___qsZpA:active:not(:disabled){transform:translateY(0)}.styles-module__button___RbliA.styles-module__secondary___SCpPv{background:var(--color-bg-2);border-color:var(--color-border-4);color:var(--color-fg-text)}.styles-module__button___RbliA.styles-module__secondary___SCpPv:hover:not(:disabled){background:var(--color-bg-3);border-color:var(--color-primary)}.styles-module__button___RbliA.styles-module__outline___rrlk9{border-color:var(--color-border-4);color:var(--color-fg-text);background:0 0}.styles-module__button___RbliA.styles-module__outline___rrlk9:hover:not(:disabled){background:var(--color-bg-2);border-color:var(--color-primary)}.styles-module__button___RbliA.styles-module__ghost___QMoiH{color:var(--color-fg-text);background:0 0;border-color:#0000}.styles-module__button___RbliA.styles-module__ghost___QMoiH:hover:not(:disabled){background:var(--color-bg-2)}.styles-module__button___RbliA.styles-module__danger___MW-pg{background:var(--color-danger);border-color:var(--color-danger);color:#fff}.styles-module__button___RbliA.styles-module__danger___MW-pg:hover:not(:disabled){background:var(--color-danger-light);border-color:var(--color-danger-light);transform:translateY(-1px)}.styles-module__button___RbliA.styles-module__danger___MW-pg:active:not(:disabled){transform:translateY(0)}.styles-module__button___RbliA.styles-module__fullWidth___-dXBR{width:100%}.styles-module__button___RbliA.styles-module__loading___UWw6V{pointer-events:none}.styles-module__spinner___KpJ-L{border:2px solid;border-top-color:#0000;border-radius:50%;flex-shrink:0;width:1rem;height:1rem;animation:.6s linear infinite styles-module__spin___ntZKM}@keyframes styles-module__spin___ntZKM{to{transform:rotate(360deg)}}.styles-module__button___RbliA.styles-module__small___yK0Yp .styles-module__spinner___KpJ-L{border-width:1.5px;width:.875rem;height:.875rem}.styles-module__button___RbliA.styles-module__large___pIZkl .styles-module__spinner___KpJ-L{border-width:2.5px;width:1.25rem;height:1.25rem}.styles-module__content___oyZRO{align-items:center;display:flex}.styles-module__leftIcon___cDktv,.styles-module__rightIcon___1mpk0{flex-shrink:0;align-items:center;display:flex}.styles-module__leftIcon___cDktv{margin-right:-.25rem}.styles-module__rightIcon___1mpk0{margin-left:-.25rem}.styles-module__button___RbliA.styles-module__iconOnly___iOv-U{aspect-ratio:1;min-width:2.5rem;min-height:2.5rem;padding:0}.styles-module__button___RbliA.styles-module__iconOnly___iOv-U.styles-module__small___yK0Yp{min-width:2rem;min-height:2rem}.styles-module__button___RbliA.styles-module__iconOnly___iOv-U.styles-module__large___pIZkl{min-width:3rem;min-height:3rem}.styles-module__iconContainer___bwvE3{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.styles-module__layout___WaGy9{flex-direction:column;justify-content:center;align-items:center;gap:.25rem;width:100%;display:flex}.styles-module__horizontal___lKpGq{justify-content:center;align-items:center;gap:.5rem;width:100%;display:flex}.styles-module__topIcon___bzw6s,.styles-module__bottomIcon___suPfa{flex-shrink:0;justify-content:center;align-items:center;display:flex}.styles-module__iconOnly___iOv-U .styles-module__iconContainer___bwvE3 .styles-module__leftIcon___cDktv,.styles-module__iconOnly___iOv-U .styles-module__iconContainer___bwvE3 .styles-module__rightIcon___1mpk0{margin:0}.Dropdown-module__dropdown___c9wIp{width:100%;display:inline-block;position:relative}.Dropdown-module__dropdownButton___suNh-{border:1px solid var(--color-separator);cursor:pointer;text-align:left;background:var(--color-bg-2);width:100%;color:var(--color-fg-text);border-radius:8px;outline:none;justify-content:space-between;align-items:center;padding:.75rem 2.5rem .75rem 1rem;font-family:inherit;font-size:1rem;font-weight:400;line-height:1.5rem;transition:all .2s ease-in-out;display:flex;position:relative}.Dropdown-module__dropdownButton___suNh-:hover:not(:disabled){border-color:var(--color-primary);background:var(--color-bg-1)}.Dropdown-module__dropdownButton___suNh-:focus{border-color:var(--color-primary);background:var(--color-bg-1);box-shadow:0 0 0 2px var(--color-primary-transparent)}.Dropdown-module__dropdownButton___suNh-.Dropdown-module__disabled___Rz0pX{cursor:not-allowed;opacity:.6;background:var(--color-bg-3)}.Dropdown-module__dropdownButton___suNh-.Dropdown-module__error___F7dDu{border-color:#ef4444}.Dropdown-module__buttonText___D2zxn{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.Dropdown-module__chevronIcon___uyawp{color:var(--color-fg-highlight);flex-shrink:0;transition:transform .15s;position:absolute;right:1rem}.Dropdown-module__chevronIcon___uyawp.Dropdown-module__open___APoXd{transform:rotate(180deg)}.Dropdown-module__dropdownMenu___WJ-QO{background:var(--color-bg);border:1px solid var(--color-border-4);z-index:1000;border-radius:8px;min-width:100%;animation:.15s ease-out Dropdown-module__slideDown___sRCmO;position:absolute;top:calc(100% + .5rem);left:0;right:0;overflow:hidden;box-shadow:0 .5rem 1rem #0000002d}@keyframes Dropdown-module__slideDown___sRCmO{0%{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:translateY(0)}}.Dropdown-module__optionsList___Be6RN{margin:0;padding:.5rem 0;list-style:none}.Dropdown-module__option___q-NgT{cursor:pointer;color:var(--color-fg-text);align-items:center;padding:.75rem 1rem;font-size:.875rem;transition:all .15s;display:flex}.Dropdown-module__option___q-NgT:hover{background-color:var(--color-bg-2)}.Dropdown-module__option___q-NgT.Dropdown-module__selected___-OTW-{background-color:var(--color-bg-3);color:var(--color-fg-highlight);font-weight:600}@media (width<=768px){.Dropdown-module__dropdownButton___suNh-{padding:.625rem 2.25rem .625rem .875rem;font-size:.875rem}.Dropdown-module__chevronIcon___uyawp{right:.875rem}.Dropdown-module__option___q-NgT{padding:.625rem .875rem;font-size:.8125rem}}.styles-module__wrapper___COeGm{flex-direction:column;gap:.5rem;display:flex}.styles-module__wrapper___COeGm.styles-module__fullWidth___lVU49{width:100%}.styles-module__label___gfOA7{color:var(--color-fg-heading);align-items:center;gap:.25rem;font-size:.875rem;font-weight:500;display:flex}.styles-module__required___-zOy5{color:var(--color-danger)}.styles-module__inputContainer___wXY53{align-items:center;width:100%;display:flex;position:relative}.styles-module__input___IZDc3{border:1px solid var(--color-border-4);background:var(--color-bg);width:100%;color:var(--color-fg-text);border-radius:.5rem;outline:none;font-family:inherit;font-size:.875rem;transition:all .2s}.styles-module__input___IZDc3[type=password]::-webkit-credentials-auto-fill-button{visibility:hidden!important;opacity:0!important;pointer-events:none!important;appearance:none!important;display:none!important;position:absolute!important;left:-9999px!important}.styles-module__input___IZDc3[type=password]::-webkit-strong-password-toggle-button{visibility:hidden!important;opacity:0!important;pointer-events:none!important;appearance:none!important;width:0!important;height:0!important;margin:0!important;padding:0!important;display:none!important;position:absolute!important;left:-9999px!important}.styles-module__input___IZDc3[type=password]::-ms-reveal{visibility:hidden!important;opacity:0!important;pointer-events:none!important;width:0!important;height:0!important;display:none!important;position:absolute!important;left:-9999px!important}.styles-module__input___IZDc3[type=password]::-ms-clear{visibility:hidden!important;opacity:0!important;pointer-events:none!important;width:0!important;height:0!important;display:none!important;position:absolute!important;left:-9999px!important}.styles-module__input___IZDc3:focus{border-color:var(--color-primary);box-shadow:0 0 0 3px rgba(var(--color-primary-rgb,102, 126, 234), .1)}.styles-module__input___IZDc3::placeholder{color:var(--color-fg-muted,var(--color-fg-text));opacity:.5}.styles-module__input___IZDc3.styles-module__small___cuGyE{padding:.5rem .75rem;font-size:.8125rem}.styles-module__input___IZDc3.styles-module__medium___JdDPu{padding:.75rem;font-size:.875rem}.styles-module__input___IZDc3.styles-module__large___fMmiG{padding:1rem;font-size:1rem}.styles-module__input___IZDc3.styles-module__default___-eZTG{background:var(--color-bg);border-color:var(--color-border-4)}.styles-module__input___IZDc3.styles-module__filled___EQ5PQ{background:var(--color-bg-2);border-color:var(--color-border-3)}.styles-module__inputContainer___wXY53.styles-module__withLeftIcon___NFn6- .styles-module__input___IZDc3{padding-left:2.5rem}.styles-module__inputContainer___wXY53.styles-module__withRightIcon___mz-hn .styles-module__input___IZDc3{padding-right:2.5rem}.styles-module__inputContainer___wXY53.styles-module__withLeftIcon___NFn6- .styles-module__input___IZDc3.styles-module__small___cuGyE{padding-left:2rem}.styles-module__inputContainer___wXY53.styles-module__withRightIcon___mz-hn .styles-module__input___IZDc3.styles-module__small___cuGyE{padding-right:2rem}.styles-module__inputContainer___wXY53.styles-module__withLeftIcon___NFn6- .styles-module__input___IZDc3.styles-module__large___fMmiG{padding-left:3rem}.styles-module__inputContainer___wXY53.styles-module__withRightIcon___mz-hn .styles-module__input___IZDc3.styles-module__large___fMmiG{padding-right:3rem}.styles-module__leftIcon___jEW5H,.styles-module__rightIcon___bA3Eo{color:var(--color-fg-muted,var(--color-fg-text));pointer-events:none;z-index:1;justify-content:center;align-items:center;display:flex;position:absolute}.styles-module__leftIcon___jEW5H{left:.75rem}.styles-module__rightIcon___bA3Eo{right:.75rem}.styles-module__rightIcon___bA3Eo.styles-module__rightIconInteractive___ccypw{pointer-events:auto}.styles-module__inputContainer___wXY53.styles-module__containerSmall___20ICq .styles-module__leftIcon___jEW5H{left:.5rem}.styles-module__inputContainer___wXY53.styles-module__containerSmall___20ICq .styles-module__rightIcon___bA3Eo{right:.5rem}.styles-module__inputContainer___wXY53.styles-module__containerLarge___IztuN .styles-module__leftIcon___jEW5H{left:1rem}.styles-module__inputContainer___wXY53.styles-module__containerLarge___IztuN .styles-module__rightIcon___bA3Eo{right:1rem}.styles-module__input___IZDc3.styles-module__error___946qV{border-color:var(--color-danger)}.styles-module__input___IZDc3.styles-module__error___946qV:focus{border-color:var(--color-danger);box-shadow:0 0 0 3px rgba(var(--color-danger-rgb,244, 67, 54), .1)}.styles-module__input___IZDc3.styles-module__disabled___sJvLd{background:var(--color-bg-3);border-color:var(--color-border-5);color:var(--color-fg-muted);cursor:not-allowed;opacity:.6}.styles-module__errorMessage___5Mn22{color:var(--color-danger);margin:0;font-size:.75rem}.styles-module__helperText___T2eui{color:var(--color-fg-muted);margin:0;font-size:.75rem}.styles-module__container___xeg8O{flex-direction:column;gap:1rem;display:flex}.styles-module__label___qhbKe{color:var(--color-fg-text);font-size:.875rem;font-weight:500}.styles-module__error___O-7AY{color:var(--color-error);font-size:.875rem}.styles-module__pairs___owGV3{flex-direction:column;gap:.75rem;display:flex}.styles-module__pair___G4WFY{grid-template-columns:1fr 2fr auto;align-items:start;gap:.75rem;display:grid}.styles-module__keyInput___wl1M1,.styles-module__valueInput___HiwJ5{flex:1}.styles-module__removeButton___4-X0b{min-width:auto;color:var(--color-error);padding:.5rem}.styles-module__removeButton___4-X0b:hover{background-color:var(--color-error);color:#fff}.styles-module__addButton___QFljt{align-self:flex-start}@media (width<=768px){.styles-module__pair___G4WFY{grid-template-columns:1fr}.styles-module__removeButton___4-X0b{align-self:flex-end}}.styles-module__searchContainer___86TGN{width:100%;max-width:400px;position:relative}.styles-module__searchIcon___ZInry{color:var(--color-fg-muted);pointer-events:none;position:absolute;top:50%;left:1rem;transform:translateY(-50%)}.styles-module__searchInput___SqZXQ{border:1px solid var(--color-border);width:100%;color:var(--color-fg-text);background:var(--color-bg-2);border-radius:.5rem;padding:.75rem 3rem;font-size:1rem;transition:all .2s}.styles-module__searchInput___SqZXQ:focus{border-color:var(--color-primary);box-shadow:0 0 0 3px var(--color-primary-bg);outline:none}.styles-module__searchInput___SqZXQ::placeholder{color:var(--color-fg-muted)}.styles-module__clearBtn___7jExr{width:1.5rem;height:1.5rem;color:var(--color-fg-muted);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;padding:0;transition:all .2s;display:flex;position:absolute;top:50%;right:.75rem;transform:translateY(-50%)}.styles-module__clearBtn___7jExr:hover{color:var(--color-fg-text)}@media (width<=768px){.styles-module__searchContainer___86TGN{max-width:100%}}.styles-module__container___nGxdM{flex-direction:column;gap:.75rem;display:flex}.styles-module__toggleContainer___VrsKI{align-items:center;display:flex}.styles-module__toggleButton___IzD6Z{border:1px solid var(--color-border-4);background:var(--color-bg);color:var(--color-fg-muted);cursor:pointer;border-radius:.5rem;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.875rem;transition:all .2s;display:flex}.styles-module__toggleButton___IzD6Z:hover{background:var(--color-bg-2);border-color:var(--color-border-3)}.styles-module__toggleButton___IzD6Z.styles-module__enabled___cao0G{background:var(--color-primary);color:#fff;border-color:var(--color-primary)}.styles-module__toggleButton___IzD6Z.styles-module__enabled___cao0G:hover{background:var(--color-primary-hover);border-color:var(--color-primary-hover)}.styles-module__optionsContainer___LOzlO{background:var(--color-bg-2);border:1px solid var(--color-border-4);border-radius:.5rem;gap:.5rem;padding:.5rem;display:flex}.styles-module__option___abhnC{border:1px solid var(--color-border-4);background:var(--color-bg);color:var(--color-fg);cursor:pointer;border-radius:.375rem;flex:1;justify-content:center;align-items:center;gap:.375rem;padding:.5rem .875rem;font-size:.875rem;font-weight:500;transition:all .2s;display:flex}.styles-module__option___abhnC:hover{background:var(--color-bg-3);border-color:var(--color-border-3)}.styles-module__option___abhnC.styles-module__active___pqmSi{background:var(--color-primary);color:#fff;border-color:var(--color-primary)}.styles-module__option___abhnC.styles-module__active___pqmSi:hover{background:var(--color-primary-hover);border-color:var(--color-primary-hover)}.styles-module__nbSelect___KjxSc{font-family:inherit;font-size:.9375rem;font-weight:600;line-height:1.5rem;display:inline-block;position:relative}.styles-module__selectButton___AKZe4{cursor:pointer;text-align:left;width:100%;min-width:8rem;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;appearance:none;border:1px solid;border-radius:.25rem;outline:none;justify-content:space-between;align-items:center;padding:.4375rem 2.2rem .4375rem 1.125rem;transition:all .15s ease-in-out;display:flex;position:relative}.styles-module__selectButton___AKZe4.styles-module__primary___HU36a{background-color:var(--color-primary);border-color:var(--color-primary);color:var(--color-primary-fg)}.styles-module__selectButton___AKZe4.styles-module__primary___HU36a:hover:not(:disabled){background-color:var(--color-primary-light);border-color:var(--color-primary-light)}.styles-module__selectButton___AKZe4.styles-module__primary___HU36a:focus,.styles-module__selectButton___AKZe4.styles-module__primary___HU36a.styles-module__open___9AKMb{background-color:var(--color-primary-light);border-color:var(--color-primary-light);box-shadow:0 0 0 .125rem #8f9bb340}.styles-module__selectButton___AKZe4.styles-module__default___LedYP{background-color:var(--color-bg);border-color:var(--color-border-4);color:var(--color-fg-text)}.styles-module__selectButton___AKZe4.styles-module__default___LedYP:hover:not(:disabled){background-color:var(--color-bg-2);border-color:var(--color-primary)}.styles-module__selectButton___AKZe4.styles-module__default___LedYP:focus,.styles-module__selectButton___AKZe4.styles-module__default___LedYP.styles-module__open___9AKMb{background-color:var(--color-bg-2);border-color:var(--color-primary);box-shadow:0 0 0 .125rem #8f9bb340}.styles-module__selectButton___AKZe4:disabled{cursor:not-allowed;opacity:.6}.styles-module__buttonText___QSLO1{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.styles-module__chevronIcon___qAHaD{flex-shrink:0;width:1.5rem;height:1.5rem;transition:transform .15s;position:absolute;right:.41rem}.styles-module__selectButton___AKZe4.styles-module__primary___HU36a .styles-module__chevronIcon___qAHaD{color:var(--color-primary-fg)}.styles-module__selectButton___AKZe4.styles-module__default___LedYP .styles-module__chevronIcon___qAHaD{color:var(--color-fg)}.styles-module__chevronIcon___qAHaD.styles-module__open___9AKMb{transform:rotate(180deg)}.styles-module__optionsPanel___NWAp3{background-color:var(--color-bg);border:1px solid var(--color-border-4);z-index:1000;transform-origin:top;visibility:hidden;pointer-events:none;border-radius:.25rem;min-width:100%;position:absolute;top:calc(100% + .5rem);left:0;right:0;overflow:hidden;box-shadow:0 .5rem 1rem #00000026}.styles-module__optionsPanel___NWAp3.styles-module__open___9AKMb{visibility:visible;pointer-events:auto;animation:.25s ease-out styles-module__expandDown___eD4lh}.styles-module__optionsPanel___NWAp3.styles-module__closed___bez-q{visibility:hidden;pointer-events:none;animation:.25s ease-out styles-module__collapseUp___dt1E7}@keyframes styles-module__expandDown___eD4lh{0%{opacity:0;transform:scaleY(0)}to{opacity:1;transform:scaleY(1)}}@keyframes styles-module__collapseUp___dt1E7{0%{opacity:1;transform:scaleY(1)}to{opacity:0;transform:scaleY(0)}}.styles-module__optionsPanel___NWAp3.styles-module__primary___HU36a{border-color:var(--color-primary)}.styles-module__optionsPanel___NWAp3.styles-module__default___LedYP{border-color:var(--color-border-4)}.styles-module__optionsList___AxhVp{margin:0;padding:.5rem 0;list-style:none}.styles-module__option___t1SSw{cursor:pointer;color:var(--color-fg-text);justify-content:space-between;align-items:center;padding:.75rem 1.125rem;transition:all .15s;display:flex}.styles-module__option___t1SSw:hover{background-color:var(--color-bg-2)}.styles-module__option___t1SSw.styles-module__selected___azD4A{background-color:var(--color-primary);color:var(--color-primary-fg);font-weight:700}@media (prefers-color-scheme:dark){.styles-module__optionsPanel___NWAp3{box-shadow:0 .5rem 1rem #0000004d}}.styles-module__sliderContainer___lgpaD{flex-direction:column;gap:.5rem;display:flex}.styles-module__sliderContainer___lgpaD.styles-module__fullWidth___ZS8W5{width:100%}.styles-module__labelRow___dkVVM{justify-content:space-between;align-items:center;min-height:1.5rem;margin-bottom:.5rem;display:flex}.styles-module__label___bXGZs{color:var(--color-fg-text);font-size:.875rem;font-weight:500}.styles-module__required___FuyfE{color:var(--color-danger);margin-left:.25rem}.styles-module__sliderWrapper___1Wdti{touch-action:none;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;gap:.75rem;width:100%;display:flex}.styles-module__sliderRoot___yzOjR{cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none;flex-grow:1;align-items:center;width:100%;padding:.75rem 0;display:flex;position:relative}.styles-module__sliderRoot___yzOjR:active{cursor:grabbing}.styles-module__sliderTrackWrapper___N72WQ{flex-grow:1;display:flex;position:relative}.styles-module__sliderTrack___AltcD{background-color:var(--color-bg-3);border-radius:9999px;width:100%;height:.375rem;position:relative;overflow:hidden}.styles-module__sliderRange___U3g0-{background-color:var(--color-primary);border-radius:9999px;height:100%;position:absolute}.styles-module__valueIndicator___aLf0I{color:var(--color-primary);text-align:center;flex-shrink:0;min-width:2rem;font-size:.875rem;font-weight:600;line-height:1}.styles-module__iconWrapper___wL-b8{flex-shrink:0;justify-content:center;align-items:center;display:flex}.styles-module__icon___vHsID{width:20px;height:20px;color:var(--color-fg-muted)}.styles-module__errorMessage___qFgGe{color:var(--color-danger);margin:0;font-size:.75rem}.styles-module__helperText___tgBGl{color:var(--color-fg-muted);margin:0;font-size:.75rem}.styles-module__loadingContainer___OMgwS{flex-direction:column;justify-content:center;align-items:center;gap:1.5rem;min-height:60vh;display:flex}.styles-module__loadingText___KRZqR{color:var(--color-fg-muted);font-size:1rem}.styles-module__errorContainer___qhAg2{text-align:center;min-height:60vh;color:var(--color-fg-text);flex-direction:column;justify-content:center;align-items:center;gap:2rem;padding:3rem 2rem;display:flex}.styles-module__errorIconWrapper___IHZrN{background:linear-gradient(135deg, rgba(var(--color-error-rgb,239, 68, 68), .1), rgba(var(--color-error-rgb,239, 68, 68), .05));border:2px solid rgba(var(--color-error-rgb,239, 68, 68), .2);border-radius:50%;justify-content:center;align-items:center;width:120px;height:120px;animation:2s ease-in-out infinite styles-module__pulse___Lju-z;display:flex}@keyframes styles-module__pulse___Lju-z{0%,to{opacity:1;transform:scale(1)}50%{opacity:.9;transform:scale(1.05)}}.styles-module__errorIcon___oGDIP{color:var(--color-error,#ef4444);stroke-width:1.5px}.styles-module__errorContent___F55rQ{flex-direction:column;align-items:center;gap:1rem;width:100%;max-width:600px;display:flex}.styles-module__errorTitle___hC8D-{color:var(--color-fg-heading);letter-spacing:-.02em;margin:0;font-size:1.75rem;font-weight:700;line-height:1.2}.styles-module__errorDescription___hZtuP{color:var(--color-fg-muted);max-width:480px;margin:0;font-size:1rem;line-height:1.6}.styles-module__errorDetailsWrapper___-sp8b{width:100%;max-width:600px;margin-top:.5rem}.styles-module__errorDetailsContainer___eywMo{text-align:left;border:1px solid var(--color-border,#0000001a);background:var(--color-bg-2,#00000005);border-radius:.75rem;width:100%;transition:all .2s;overflow:hidden}.styles-module__errorDetailsContainer___eywMo:hover{border-color:var(--color-border-hover,#00000026);background:var(--color-bg-3,#00000008)}.styles-module__errorDetailsSummary___hGEoD{cursor:pointer;color:var(--color-fg-muted);-webkit-user-select:none;user-select:none;padding:.875rem 1.25rem;font-size:.875rem;font-weight:500;list-style:none;transition:color .2s}.styles-module__errorDetailsSummary___hGEoD:hover{color:var(--color-fg-text)}.styles-module__errorDetailsSummary___hGEoD::-webkit-details-marker{display:none}.styles-module__errorDetailsSummary___hGEoD:before{content:"▶";margin-right:.5rem;font-size:.75rem;transition:transform .2s;display:inline-block}.styles-module__errorDetailsContainer___eywMo[open] .styles-module__errorDetailsSummary___hGEoD:before{transform:rotate(90deg)}.styles-module__errorDetails___tzCT-{background:var(--color-bg-3,#00000008);border-top:1px solid var(--color-border,#0000001a);max-width:100%;color:var(--color-fg-muted);white-space:pre-wrap;word-break:break-word;margin:0;padding:1rem 1.25rem;font-family:Monaco,Menlo,Ubuntu Mono,Consolas,source-code-pro,monospace;font-size:.8125rem;line-height:1.6;overflow-x:auto}.styles-module__errorActions___gtqYw{flex-wrap:wrap;justify-content:center;align-items:center;gap:.75rem;margin-top:1rem;display:flex}.styles-module__retryButton___TA4jm{background:var(--color-primary);color:var(--color-primary-fg);cursor:pointer;border:none;border-radius:.5rem;justify-content:center;align-items:center;gap:.5rem;padding:.75rem 2rem;font-size:.9375rem;font-weight:500;transition:all .2s;display:inline-flex;box-shadow:0 2px 8px #00000014}.styles-module__retryButton___TA4jm:hover{background:var(--color-primary-hover,var(--color-primary));transform:translateY(-2px);box-shadow:0 4px 16px #0000001f}.styles-module__retryButton___TA4jm:active{transform:translateY(0);box-shadow:0 2px 8px #00000014}.styles-module__retryButtonIcon___vzfp-{font-size:1.125rem;line-height:1;transition:transform .3s;display:inline-block}.styles-module__retryButton___TA4jm:hover .styles-module__retryButtonIcon___vzfp-{transform:rotate(180deg)}.styles-module__clearLocalDataButton___T3B-K{color:var(--color-fg-muted);border:1px solid var(--color-border-4);cursor:pointer;background:0 0;border-radius:.5rem;justify-content:center;align-items:center;padding:.75rem 1.5rem;font-size:.9375rem;font-weight:500;transition:all .2s;display:inline-flex}.styles-module__clearLocalDataButton___T3B-K:hover{color:var(--color-fg-text);border-color:var(--color-border-3);background:var(--color-bg-secondary)}.styles-module__wrapper___jXPV3{flex-direction:column;gap:.5rem;display:flex}.styles-module__wrapper___jXPV3.styles-module__fullWidth___eKyGB{width:100%}.styles-module__label___MyTeo{color:var(--color-fg-heading);align-items:center;gap:.25rem;font-size:.875rem;font-weight:500;display:flex}.styles-module__required___TV-m8{color:var(--color-danger)}.styles-module__inputContainer___VvGBl{align-items:flex-start;width:100%;display:flex;position:relative}.styles-module__textarea___AjX9N{border:1px solid var(--color-border-4);background:var(--color-bg);width:100%;color:var(--color-fg-text);resize:vertical;border-radius:.5rem;outline:none;min-height:4rem;font-family:inherit;font-size:.875rem;transition:all .2s}.styles-module__textarea___AjX9N:focus{border-color:var(--color-primary);box-shadow:0 0 0 3px rgba(var(--color-primary-rgb,102, 126, 234), .1)}.styles-module__textarea___AjX9N::placeholder{color:var(--color-fg-muted,var(--color-fg-text));opacity:.5}.styles-module__textarea___AjX9N.styles-module__small___zMx0G{min-height:3rem;padding:.5rem .75rem;font-size:.8125rem}.styles-module__textarea___AjX9N.styles-module__medium___tO2Lb{min-height:4rem;padding:.75rem;font-size:.875rem}.styles-module__textarea___AjX9N.styles-module__large___3eU2g{min-height:5rem;padding:1rem;font-size:1rem}.styles-module__textarea___AjX9N.styles-module__default___vsSxX{background:var(--color-bg);border-color:var(--color-border-4)}.styles-module__textarea___AjX9N.styles-module__filled___TPQgI{background:var(--color-bg-2);border-color:var(--color-border-3)}.styles-module__inputContainer___VvGBl .styles-module__leftIcon___FHp2R{color:var(--color-fg-muted,var(--color-fg-text));pointer-events:none;z-index:1;justify-content:center;align-items:center;display:flex;position:absolute;top:.75rem;left:.75rem}.styles-module__inputContainer___VvGBl .styles-module__rightIcon___dkyvP{color:var(--color-fg-muted,var(--color-fg-text));pointer-events:none;z-index:1;justify-content:center;align-items:center;display:flex;position:absolute;top:.75rem;right:.75rem}.styles-module__inputContainer___VvGBl .styles-module__textarea___AjX9N.styles-module__small___zMx0G+.styles-module__leftIcon___FHp2R,.styles-module__inputContainer___VvGBl .styles-module__textarea___AjX9N.styles-module__small___zMx0G+.styles-module__rightIcon___dkyvP{top:.5rem}.styles-module__inputContainer___VvGBl .styles-module__textarea___AjX9N.styles-module__large___3eU2g+.styles-module__leftIcon___FHp2R,.styles-module__inputContainer___VvGBl .styles-module__textarea___AjX9N.styles-module__large___3eU2g+.styles-module__rightIcon___dkyvP{top:1rem}.styles-module__textarea___AjX9N.styles-module__error___d8gLK{border-color:var(--color-danger)}.styles-module__textarea___AjX9N.styles-module__error___d8gLK:focus{border-color:var(--color-danger);box-shadow:0 0 0 3px rgba(var(--color-danger-rgb,244, 67, 54), .1)}.styles-module__textarea___AjX9N.styles-module__disabled___IzbfE{background:var(--color-bg-3);border-color:var(--color-border-5);color:var(--color-fg-muted);cursor:not-allowed;opacity:.6}.styles-module__errorText___Nom7x{color:var(--color-danger);margin:0;font-size:.75rem}.styles-module__helperText___97Def{color:var(--color-fg-muted);margin:0;font-size:.75rem}.styles-module__virtualList___pM6rN{contain:strict;width:100%;padding-bottom:300px;position:relative;overflow:auto}.styles-module__emptyContainer___rm938{height:100%;color:var(--color-fg-muted);justify-content:center;align-items:center;display:flex}.styles-module__virtualListInner___HxRzc{width:100%;position:relative}.styles-module__virtualListItems___p19-a{width:100%;position:absolute;top:0;left:0}.styles-module__loadingMore___zAdLM{color:var(--color-fg-muted);justify-content:center;align-items:center;gap:.75rem;padding:2rem 0;font-size:.875rem;display:flex}.styles-module__endOfList___5cYFh{color:var(--color-fg-muted);border-top:1px solid var(--color-border-3);justify-content:center;margin-top:1rem;padding:2rem 0;font-size:.875rem;display:flex}.styles-module__endOfList___5cYFh span{background-color:var(--color-bg-2);border-radius:.25rem;padding:.5rem 1rem}.styles-module__virtualList___xmj2v{width:100%;padding-bottom:300px;position:relative;overflow:visible}.styles-module__virtualListInner___quD74{width:100%;position:relative}.styles-module__virtualListItems___-Muml{width:100%;position:absolute;top:0;left:0}.styles-module__virtualListRow___h3pzX{width:100%}.styles-module__emptyContainer___LIy8r{color:var(--color-fg-muted);justify-content:center;align-items:center;padding:2rem 0;display:flex}.styles-module__loadingMore___Mzf-p{color:var(--color-fg-muted);justify-content:center;align-items:center;padding:1.5rem 0;display:flex}.styles-module__endOfList___g5G--{color:var(--color-fg-muted);border-top:1px solid var(--color-border-3);justify-content:center;padding:1.5rem 0;display:flex}.styles-module__sidebar___BMt0j{flex-direction:column;height:100%;min-height:0;display:flex;overflow:hidden}.styles-module__sidebarContent___iAwiw{flex-direction:column;height:100%;min-height:0;padding-top:1rem;display:flex;overflow:hidden}.styles-module__menuWrapper___DKuEv{flex:1;min-height:0;overflow:hidden auto}.styles-module__sidebarContent___iAwiw::-webkit-scrollbar{width:0}.styles-module__sidebarContent___iAwiw::-webkit-scrollbar-track{background:0 0}.styles-module__sidebarContent___iAwiw::-webkit-scrollbar-thumb{background:0 0}.styles-module__sidebarContent___iAwiw::-webkit-scrollbar-thumb:hover{background:0 0}.styles-module__sidebar___BMt0j a{margin-left:0}.styles-module__sidebar___BMt0j .ps-sidebar-root{background-color:var(--color-bg-2)!important;border-right:1px solid var(--color-separator)!important;flex-direction:column!important;height:100%!important;min-height:0!important;display:flex!important;overflow:hidden!important}.styles-module__sidebar___BMt0j .ps-sidebar-container{background-color:var(--color-bg-2)!important;height:100%!important;min-height:0!important;color:var(--color-fg-text)!important;flex-direction:column!important;flex:1!important;display:flex!important;overflow:hidden!important}.styles-module__sidebar___BMt0j .ps-menu-button{color:var(--color-fg-text)!important;border-radius:.375rem!important;margin:.125rem .5rem!important;padding:.5rem .75rem!important;font-size:.875rem!important;transition:all .2s!important}.styles-module__sidebar___BMt0j .ps-menu-button:hover{background-color:var(--color-bg-3)!important;color:var(--color-fg-text)!important}.styles-module__sidebar___BMt0j .ps-menu-button.ps-active{background-color:var(--color-primary)!important;color:#fff!important}.styles-module__sidebar___BMt0j .ps-menu-button.ps-active *,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active .ps-menu-icon,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active .ps-menu-label{color:#fff!important}.styles-module__sidebar___BMt0j .ps-menu-icon{width:1.25rem!important;height:1.25rem!important;color:var(--color-fg-text)!important;margin-right:.5rem!important}.styles-module__sidebar___BMt0j .ps-submenu-content{background-color:var(--color-bg-3)!important;padding-left:.5rem!important;overflow:hidden!important}.styles-module__sidebar___BMt0j .ps-submenu-content .ps-menu-button{margin:.125rem .25rem!important;padding:.375rem .5rem!important;font-size:.8125rem!important;transition:all .2s!important}.styles-module__sidebar___BMt0j .ps-menu-label{color:var(--color-fg-text)!important;font-weight:500!important}.styles-module__sidebar___BMt0j .ps-menu-button.ps-active,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active span,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active div,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active .ps-menu-icon,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active .ps-menu-label{color:#fff!important}.styles-module__logoutContainer___7NwBL{border-top:1px solid var(--color-separator);writing-mode:horizontal-tb;text-orientation:mixed;flex-shrink:0;margin-top:auto;padding:.5rem}.styles-module__logoutButton___rfD6u{width:100%;color:var(--color-fg-text);cursor:pointer;white-space:nowrap;writing-mode:horizontal-tb;text-orientation:mixed;direction:ltr;background:0 0;border:none;border-radius:.375rem;justify-content:flex-start;align-items:center;gap:.5rem;padding:.5rem .75rem;font-size:.875rem;transition:background-color .2s,color .2s;display:flex;overflow:hidden}.styles-module__logoutButton___rfD6u span{opacity:1;max-width:200px;transition:opacity .3s,max-width .3s;display:inline-block;writing-mode:horizontal-tb!important;text-orientation:mixed!important;direction:ltr!important;transform:none!important}.styles-module__logoutButton___rfD6u .styles-module__hiddenText___z183T{opacity:0;width:0;max-width:0;overflow:hidden}.styles-module__logoutButton___rfD6u .styles-module__visibleText___lfsv-{opacity:1;width:auto;max-width:200px}.styles-module__logoutButton___rfD6u:hover{background-color:var(--color-bg-3)}.styles-module__logoutButton___rfD6u:active{transform:scale(.98)}.styles-module__logoutButton___rfD6u svg{color:inherit;flex-shrink:0}.styles-module__footer___g-hY7{background:var(--color-bg-2);width:100%;padding:0 2rem}.styles-module__footerContent___Oen5n{justify-content:space-between;align-items:center;max-width:100%;margin:0 auto;display:flex}.styles-module__copyright___1R2o3{color:var(--color-fg-text);font-size:.875rem}.styles-module__links___dQyvB{gap:1.5rem;display:flex}.styles-module__link___UWfyK{color:var(--color-fg-text);font-size:.875rem;text-decoration:none;transition:color .3s}.styles-module__link___UWfyK:hover{color:var(--color-primary)}@media (width<=768px){.styles-module__footerContent___Oen5n{flex-direction:column;gap:1rem}.styles-module__links___dQyvB{gap:1rem}}.styles-module__header___4Uc8h{width:100%;padding:.5rem 2rem;display:flex}.styles-module__header___4Uc8h>:first-child{flex:1;justify-content:flex-start;align-items:center;display:flex}.styles-module__header___4Uc8h>:last-child{flex:1;justify-content:flex-end;align-items:center;display:flex}.styles-module__layout___ZQKU7{background:var(--color-bg);flex-direction:column;width:100%;height:100vh;display:flex;position:relative}.styles-module__header___XIaFb{z-index:100;background:var(--color-bg);width:100%;position:fixed;top:0;box-shadow:0 .125rem .25rem #2c33491a}.styles-module__footer___r8ASO{z-index:100;width:100%;position:fixed;bottom:0}.styles-module__mainWrapper___i4tEI{flex:1;display:flex;position:relative}.styles-module__sidebar___ij-8-{position:fixed;top:0}.styles-module__content___mTgUr{background:var(--color-bg);flex:1;min-height:calc(100vh - 10rem);margin:0;padding-top:0;padding-bottom:0;overflow:hidden auto}@media (width<=768px){.styles-module__content___mTgUr{width:100%}.styles-module__sidebar___ij-8-{z-index:999;height:100vh;position:fixed;top:0;left:0}}.styles-module__mainWrapper___AiTAw{flex-direction:row;flex:1;display:flex;position:relative}.styles-module__sidebarContainer___X4yj8{z-index:99;flex-direction:column;display:flex;position:fixed;left:0;overflow:hidden}.styles-module__sidebar___VQTlH{flex-shrink:0;top:0;left:0}.styles-module__content___htJlH{background:var(--color-bg);flex:1;margin:0;padding-top:0;padding-bottom:0;overflow:hidden auto}@media (width<=1024px){.styles-module__content___htJlH{padding:1.5rem}}@media (width<=768px){.styles-module__content___htJlH{width:100%}.styles-module__sidebar___VQTlH{z-index:999;height:100vh;position:fixed;top:0;left:0}}.styles-module__wavesWrapper___TK7DI{pointer-events:none;z-index:0;width:100vw;height:100vh;position:fixed;inset:0;overflow:hidden}.styles-module__wavesWrapper___TK7DI>*{pointer-events:auto}.styles-module__squaresWrapper___P25uF{pointer-events:none;z-index:0;width:100vw;height:100vh;position:fixed;inset:0;overflow:hidden}.styles-module__squaresWrapper___P25uF>*{pointer-events:auto}.styles-module__letterGlitchWrapper___KWtWU{pointer-events:none;z-index:0;width:100vw;height:100vh;position:fixed;inset:0;overflow:hidden}.styles-module__letterGlitchWrapper___KWtWU>*{pointer-events:auto}.styles-module__pixelBlastWrapper___YptHh{pointer-events:none;z-index:0;width:100vw;height:100vh;position:fixed;inset:0;overflow:hidden}.styles-module__pixelBlastWrapper___YptHh>*{pointer-events:auto}
|
|
2
|
+
/*$vite$:1*/`)),document.head.appendChild(e)}}catch(o){console.error("vite-plugin-css-injected-by-js",o)}})();
|
|
3
|
+
function r(e) {
|
|
4
|
+
return e;
|
|
5
|
+
}
|
|
6
|
+
function n(e) {
|
|
7
|
+
const t = {};
|
|
8
|
+
for (const s of e) t[s] = /* @__PURE__ */ new Set();
|
|
9
|
+
return t;
|
|
10
|
+
}
|
|
11
|
+
var i = class {
|
|
12
|
+
listeners;
|
|
13
|
+
constructor(e) {
|
|
14
|
+
this.listeners = n(Object.values(e));
|
|
15
|
+
}
|
|
16
|
+
on(e, t) {
|
|
17
|
+
this.listeners[e].add(t);
|
|
18
|
+
}
|
|
19
|
+
off(e, t) {
|
|
20
|
+
this.listeners[e].delete(t);
|
|
21
|
+
}
|
|
22
|
+
emit(e, ...t) {
|
|
23
|
+
this.listeners[e].forEach((s) => s(...t));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
export {
|
|
27
|
+
i as EventEmitter,
|
|
28
|
+
r as defineEvents
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=events.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.mjs","names":[],"sources":["../src/events/EventEmitter.ts"],"sourcesContent":["/**\n * 通用事件发射器(按事件名注册/注销/触发)\n * Generic event emitter: subscribe, unsubscribe, and emit by event name.\n *\n * @example\n * ```ts\n * import { EventEmitter, defineEvents, type EventNamesOf } from \"@/events\";\n * const events = defineEvents({ FOO: \"MY:FOO\", BAR: \"MY:BAR\" });\n * type MyEvent = EventNamesOf<typeof events>;\n * class MyEmitter extends EventEmitter<MyEvent> { constructor() { super(events); } }\n * const em = new MyEmitter();\n * em.on(events.FOO, (x) => console.log(x));\n * em.emit(events.FOO, \"hello\");\n * ```\n */\n\nimport type { Defined } from \"@/types\";\n\n/** 事件回调类型:用于 on / off。Callback for on / off. */\ntype EventCallback = (...args: unknown[]) => void;\n\n/** 由 defineEvents 返回的「已规范事件名对象」类型;constructor 只接受此类型。 */\ntype DefinedEvents<T extends Record<string, string>> = Defined<T, \"events\">;\n\n/** 从 events 对象推导出事件名联合类型。Event name union from an events key-value object. */\ntype EventNamesOf<T> = T extends Defined<infer O, \"events\"> ? O[keyof O] : T extends Record<string, string> ? T[keyof T] : never;\n\n/**\n * 规范创建「一级 key-value」事件名对象:仅允许 key → 字符串 value,禁止嵌套(类型约束)。\n * 返回 DefinedEvents<T>,供 EventEmitter 构造使用。\n * Define events object: one-level key-value (string values), no nested objects (type-only). Returns DefinedEvents<T> for EventEmitter.\n *\n * @param events - 事件名 key-value 对象。Event name key-value object (e.g. { FOO: \"DOMAIN:FOO\" }).\n * @returns DefinedEvents<E>,仅此类型可传入 EventEmitter 构造。DefinedEvents<E>; only this type is accepted by EventEmitter constructor.\n * @example\n * ```ts\n * const routerEvents = defineEvents({ NAVIGATE: \"ROUTER:NAVIGATE\", NAVIGATE_BACK: \"ROUTER:NAVIGATE_BACK\" });\n * class RouterEmitter extends EventEmitter<EventNamesOf<typeof routerEvents>> { constructor() { super(routerEvents); } }\n * ```\n */\nfunction defineEvents<E extends Record<string, string>>(events: E): DefinedEvents<E> {\n return events as DefinedEvents<E>;\n}\n\nfunction createListenersMap<E extends string>(eventNames: readonly E[]): Record<E, Set<EventCallback>> {\n const map = {} as Record<E, Set<EventCallback>>;\n for (const e of eventNames) {\n map[e] = new Set();\n }\n return map;\n}\n\n/**\n * 泛型 EventEmitter:构造函数仅接受 defineEvents 返回的 DefinedEvents 类型,提供 on / off / emit。\n * Generic EventEmitter: constructor accepts only DefinedEvents (returned by defineEvents), provides on / off / emit.\n *\n * @param events - 须为 defineEvents(...) 的返回值(DefinedEvents)。Must be the return value of defineEvents(...) (DefinedEvents).\n */\nclass EventEmitter<E extends string> {\n private listeners: Record<E, Set<EventCallback>>;\n\n constructor(events: DefinedEvents<Record<string, E>>) {\n this.listeners = createListenersMap(Object.values(events as Record<string, E>));\n }\n\n /**\n * 注册事件监听。Register a listener for an event.\n *\n * @param event - 事件名。Event name.\n * @param callback - 回调。Callback (...args) => void.\n */\n on(event: E, callback: EventCallback): void {\n this.listeners[event].add(callback);\n }\n\n /**\n * 移除事件监听。Remove a listener for an event.\n *\n * @param event - 事件名。Event name.\n * @param callback - 要移除的回调(需与 on 时同一引用)。Callback to remove (same reference as passed to on).\n */\n off(event: E, callback: EventCallback): void {\n this.listeners[event].delete(callback);\n }\n\n /**\n * 触发事件,同步调用该事件所有监听器。Emit an event; synchronously invoke all listeners.\n *\n * @param event - 事件名。Event name.\n * @param args - 传给监听器的参数。Arguments passed to listeners.\n */\n emit(event: E, ...args: unknown[]): void {\n this.listeners[event].forEach((cb) => cb(...args));\n }\n}\n\nexport { EventEmitter, defineEvents };\nexport type { EventCallback, DefinedEvents, EventNamesOf };\n"],"mappings":"AAwCA,SAAS,EAA+C,GAA6B;AACnF,SAAO;;AAGT,SAAS,EAAqC,GAAyD;AACrG,QAAM,IAAM,CAAA;AACZ,aAAW,KAAK,EACd,CAAA,EAAI,CAAA,IAAK,oBAAI,IAAA;AAEf,SAAO;;AAST,IAAM,IAAN,MAAqC;AAAA,EACnC;AAAA,EAEA,YAAY,GAA0C;AACpD,SAAK,YAAY,EAAmB,OAAO,OAAO,CAAA,CAA4B;AAAA;EAShF,GAAG,GAAU,GAA+B;AAC1C,SAAK,UAAU,CAAA,EAAO,IAAI,CAAA;AAAA;EAS5B,IAAI,GAAU,GAA+B;AAC3C,SAAK,UAAU,CAAA,EAAO,OAAO,CAAA;AAAA;EAS/B,KAAK,MAAa,GAAuB;AACvC,SAAK,UAAU,CAAA,EAAO,QAAA,CAAS,MAAO,EAAG,GAAG,CAAA,CAAK;AAAA"}
|
package/dist/hooks.cjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
(function(){try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode(`.styles-module__loading___bgEAk{justify-content:center;align-items:center;display:inline-flex}.styles-module__loading___bgEAk svg polyline{fill:none;stroke-width:3px;stroke-linecap:round;stroke-linejoin:round}.styles-module__loading___bgEAk svg polyline.styles-module__back___XLPvD{fill:none;stroke:var(--color-primary-alpha,#ff4d5033)}.styles-module__loading___bgEAk svg polyline.styles-module__front___hSxig{fill:none;stroke:var(--color-primary,#ff4d4f);stroke-dasharray:48 144;stroke-dashoffset:192px;animation:1.4s linear infinite styles-module__dash_682___AQzo6}@keyframes styles-module__dash_682___AQzo6{72.5%{opacity:0}to{stroke-dashoffset:0}}.styles-module__loader___E7OIM{justify-content:center;align-items:center;width:fit-content;height:fit-content;display:flex}.styles-module__truckWrapper___Sk4zX{flex-direction:column;justify-content:flex-end;align-items:center;width:100%;height:100%;display:flex;position:relative;overflow-x:hidden}.styles-module__truckBody___j7w2C{width:65%;height:fit-content;margin-bottom:6px;animation:1s linear infinite styles-module__motion___IiNlW}@keyframes styles-module__motion___IiNlW{0%{transform:translateY(0)}50%{transform:translateY(3px)}to{transform:translateY(0)}}.styles-module__truckTires___4ncTl{justify-content:space-between;align-items:center;width:65%;height:fit-content;padding:0 10px 0 15px;display:flex;position:absolute;bottom:0}.styles-module__tiresvg___IBQcN{width:24px}.styles-module__road___sxx-E{background-color:var(--color-fg-heading);border-radius:3px;align-self:flex-end;width:100%;height:1.5px;position:relative;bottom:0}.styles-module__road___sxx-E:before{content:"";background-color:var(--color-fg-heading);border-left:10px solid var(--color-bg);border-radius:3px;width:20px;height:100%;animation:1.4s linear infinite styles-module__roadAnimation___yvrHP;position:absolute;right:-50%}.styles-module__road___sxx-E:after{content:"";background-color:var(--color-fg-heading);border-left:4px solid var(--color-bg);border-radius:3px;width:10px;height:100%;animation:1.4s linear infinite styles-module__roadAnimation___yvrHP;position:absolute;right:-65%}.styles-module__lampPost___okcN5{height:45%;animation:1.4s linear infinite styles-module__roadAnimation___yvrHP;position:absolute;bottom:0;right:-90%}@keyframes styles-module__roadAnimation___yvrHP{0%{transform:translate(0)}to{transform:translate(-350px)}}.styles-module__loader___pFUzL{justify-content:center;align-items:center;display:inline-flex;position:relative}.styles-module__loader___pFUzL:before{content:"";background:var(--color-primary);opacity:.3;border-radius:50%;width:100%;height:5px;animation:.5s linear infinite styles-module__shadow324___sutUe;position:absolute;top:calc(100% + 12px);left:0}.styles-module__loader___pFUzL:after{content:"";background:var(--color-primary);width:100%;height:100%;position:absolute;top:0;left:0}.styles-module__square___GKjhm:after{border-radius:4px;animation:.5s linear infinite styles-module__jump7456Square___Z-D9b}.styles-module__circle___bUpSN:after{border-radius:50%;animation:.5s linear infinite styles-module__jump7456Circle___2AfF7}@keyframes styles-module__jump7456Square___Z-D9b{15%{border-bottom-right-radius:3px}25%{transform:translateY(9px)rotate(22.5deg)}50%{border-bottom-right-radius:40px;transform:translateY(18px)scaleY(.9)rotate(45deg)}75%{transform:translateY(9px)rotate(67.5deg)}to{transform:translateY(0)rotate(90deg)}}@keyframes styles-module__jump7456Circle___2AfF7{15%{border-bottom-right-radius:50%}25%{transform:translateY(9px)rotate(22.5deg)}50%{border-bottom-right-radius:40px;transform:translateY(18px)scaleY(.9)rotate(45deg)}75%{transform:translateY(9px)rotate(67.5deg)}to{transform:translateY(0)rotate(90deg)}}@keyframes styles-module__shadow324___sutUe{0%,to{transform:scale(1)}50%{transform:scaleX(1.2)}}.style-module__waves___oR3u7{width:100%;height:100%;margin:0;padding:0;position:absolute;top:0;left:0;overflow:hidden}.style-module__waves___oR3u7:before{content:"";width:.5rem;height:.5rem;transform:translate3d(calc(var(--x) - 50%), calc(var(--y) - 50%), 0);will-change:transform;background:#160000;border-radius:50%;position:absolute;top:0;left:0}.style-module__wavesCanvas___zkhTC{width:100%;height:100%;display:block}.style-module__squaresCanvas___22kMc{border:none;width:100%;height:100%;display:block}.style-module__container___HkxIe{background-color:#000;width:100%;height:100%;position:relative;overflow:hidden}.style-module__canvas___MR9JX{width:100%;height:100%;display:block}.style-module__outerVignette___i75nw{pointer-events:none;background:radial-gradient(circle,#0000 60%,#000 100%);width:100%;height:100%;position:absolute;top:0;left:0}.style-module__centerVignette___n9uVG{pointer-events:none;background:radial-gradient(circle,#000c 0%,#0000 60%);width:100%;height:100%;position:absolute;top:0;left:0}.style-module__container___Hh3-c{width:100%;height:100%;position:relative;overflow:hidden}.styles-module__button___RbliA{cursor:pointer;border:1px solid #0000;border-radius:.5rem;outline:none;justify-content:center;align-items:center;gap:.5rem;font-family:inherit;font-weight:500;transition:all .2s;display:inline-flex;position:relative}.styles-module__button___RbliA:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.styles-module__button___RbliA:disabled{cursor:not-allowed;opacity:.6}.styles-module__button___RbliA.styles-module__small___yK0Yp{min-height:2rem;padding:.5rem 1rem;font-size:.8125rem}.styles-module__button___RbliA.styles-module__medium___eBTch{min-height:2.5rem;padding:.75rem 1.5rem;font-size:.875rem}.styles-module__button___RbliA.styles-module__large___pIZkl{min-height:3rem;padding:1rem 2rem;font-size:1rem}.styles-module__button___RbliA.styles-module__primary___qsZpA{background:var(--color-primary);border-color:var(--color-primary);color:var(--color-primary-fg,#fff)}.styles-module__button___RbliA.styles-module__primary___qsZpA:hover:not(:disabled){background:var(--color-primary-light);border-color:var(--color-primary-light);transform:translateY(-1px)}.styles-module__button___RbliA.styles-module__primary___qsZpA:active:not(:disabled){transform:translateY(0)}.styles-module__button___RbliA.styles-module__secondary___SCpPv{background:var(--color-bg-2);border-color:var(--color-border-4);color:var(--color-fg-text)}.styles-module__button___RbliA.styles-module__secondary___SCpPv:hover:not(:disabled){background:var(--color-bg-3);border-color:var(--color-primary)}.styles-module__button___RbliA.styles-module__outline___rrlk9{border-color:var(--color-border-4);color:var(--color-fg-text);background:0 0}.styles-module__button___RbliA.styles-module__outline___rrlk9:hover:not(:disabled){background:var(--color-bg-2);border-color:var(--color-primary)}.styles-module__button___RbliA.styles-module__ghost___QMoiH{color:var(--color-fg-text);background:0 0;border-color:#0000}.styles-module__button___RbliA.styles-module__ghost___QMoiH:hover:not(:disabled){background:var(--color-bg-2)}.styles-module__button___RbliA.styles-module__danger___MW-pg{background:var(--color-danger);border-color:var(--color-danger);color:#fff}.styles-module__button___RbliA.styles-module__danger___MW-pg:hover:not(:disabled){background:var(--color-danger-light);border-color:var(--color-danger-light);transform:translateY(-1px)}.styles-module__button___RbliA.styles-module__danger___MW-pg:active:not(:disabled){transform:translateY(0)}.styles-module__button___RbliA.styles-module__fullWidth___-dXBR{width:100%}.styles-module__button___RbliA.styles-module__loading___UWw6V{pointer-events:none}.styles-module__spinner___KpJ-L{border:2px solid;border-top-color:#0000;border-radius:50%;flex-shrink:0;width:1rem;height:1rem;animation:.6s linear infinite styles-module__spin___ntZKM}@keyframes styles-module__spin___ntZKM{to{transform:rotate(360deg)}}.styles-module__button___RbliA.styles-module__small___yK0Yp .styles-module__spinner___KpJ-L{border-width:1.5px;width:.875rem;height:.875rem}.styles-module__button___RbliA.styles-module__large___pIZkl .styles-module__spinner___KpJ-L{border-width:2.5px;width:1.25rem;height:1.25rem}.styles-module__content___oyZRO{align-items:center;display:flex}.styles-module__leftIcon___cDktv,.styles-module__rightIcon___1mpk0{flex-shrink:0;align-items:center;display:flex}.styles-module__leftIcon___cDktv{margin-right:-.25rem}.styles-module__rightIcon___1mpk0{margin-left:-.25rem}.styles-module__button___RbliA.styles-module__iconOnly___iOv-U{aspect-ratio:1;min-width:2.5rem;min-height:2.5rem;padding:0}.styles-module__button___RbliA.styles-module__iconOnly___iOv-U.styles-module__small___yK0Yp{min-width:2rem;min-height:2rem}.styles-module__button___RbliA.styles-module__iconOnly___iOv-U.styles-module__large___pIZkl{min-width:3rem;min-height:3rem}.styles-module__iconContainer___bwvE3{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.styles-module__layout___WaGy9{flex-direction:column;justify-content:center;align-items:center;gap:.25rem;width:100%;display:flex}.styles-module__horizontal___lKpGq{justify-content:center;align-items:center;gap:.5rem;width:100%;display:flex}.styles-module__topIcon___bzw6s,.styles-module__bottomIcon___suPfa{flex-shrink:0;justify-content:center;align-items:center;display:flex}.styles-module__iconOnly___iOv-U .styles-module__iconContainer___bwvE3 .styles-module__leftIcon___cDktv,.styles-module__iconOnly___iOv-U .styles-module__iconContainer___bwvE3 .styles-module__rightIcon___1mpk0{margin:0}.Dropdown-module__dropdown___c9wIp{width:100%;display:inline-block;position:relative}.Dropdown-module__dropdownButton___suNh-{border:1px solid var(--color-separator);cursor:pointer;text-align:left;background:var(--color-bg-2);width:100%;color:var(--color-fg-text);border-radius:8px;outline:none;justify-content:space-between;align-items:center;padding:.75rem 2.5rem .75rem 1rem;font-family:inherit;font-size:1rem;font-weight:400;line-height:1.5rem;transition:all .2s ease-in-out;display:flex;position:relative}.Dropdown-module__dropdownButton___suNh-:hover:not(:disabled){border-color:var(--color-primary);background:var(--color-bg-1)}.Dropdown-module__dropdownButton___suNh-:focus{border-color:var(--color-primary);background:var(--color-bg-1);box-shadow:0 0 0 2px var(--color-primary-transparent)}.Dropdown-module__dropdownButton___suNh-.Dropdown-module__disabled___Rz0pX{cursor:not-allowed;opacity:.6;background:var(--color-bg-3)}.Dropdown-module__dropdownButton___suNh-.Dropdown-module__error___F7dDu{border-color:#ef4444}.Dropdown-module__buttonText___D2zxn{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.Dropdown-module__chevronIcon___uyawp{color:var(--color-fg-highlight);flex-shrink:0;transition:transform .15s;position:absolute;right:1rem}.Dropdown-module__chevronIcon___uyawp.Dropdown-module__open___APoXd{transform:rotate(180deg)}.Dropdown-module__dropdownMenu___WJ-QO{background:var(--color-bg);border:1px solid var(--color-border-4);z-index:1000;border-radius:8px;min-width:100%;animation:.15s ease-out Dropdown-module__slideDown___sRCmO;position:absolute;top:calc(100% + .5rem);left:0;right:0;overflow:hidden;box-shadow:0 .5rem 1rem #0000002d}@keyframes Dropdown-module__slideDown___sRCmO{0%{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:translateY(0)}}.Dropdown-module__optionsList___Be6RN{margin:0;padding:.5rem 0;list-style:none}.Dropdown-module__option___q-NgT{cursor:pointer;color:var(--color-fg-text);align-items:center;padding:.75rem 1rem;font-size:.875rem;transition:all .15s;display:flex}.Dropdown-module__option___q-NgT:hover{background-color:var(--color-bg-2)}.Dropdown-module__option___q-NgT.Dropdown-module__selected___-OTW-{background-color:var(--color-bg-3);color:var(--color-fg-highlight);font-weight:600}@media (width<=768px){.Dropdown-module__dropdownButton___suNh-{padding:.625rem 2.25rem .625rem .875rem;font-size:.875rem}.Dropdown-module__chevronIcon___uyawp{right:.875rem}.Dropdown-module__option___q-NgT{padding:.625rem .875rem;font-size:.8125rem}}.styles-module__wrapper___COeGm{flex-direction:column;gap:.5rem;display:flex}.styles-module__wrapper___COeGm.styles-module__fullWidth___lVU49{width:100%}.styles-module__label___gfOA7{color:var(--color-fg-heading);align-items:center;gap:.25rem;font-size:.875rem;font-weight:500;display:flex}.styles-module__required___-zOy5{color:var(--color-danger)}.styles-module__inputContainer___wXY53{align-items:center;width:100%;display:flex;position:relative}.styles-module__input___IZDc3{border:1px solid var(--color-border-4);background:var(--color-bg);width:100%;color:var(--color-fg-text);border-radius:.5rem;outline:none;font-family:inherit;font-size:.875rem;transition:all .2s}.styles-module__input___IZDc3[type=password]::-webkit-credentials-auto-fill-button{visibility:hidden!important;opacity:0!important;pointer-events:none!important;appearance:none!important;display:none!important;position:absolute!important;left:-9999px!important}.styles-module__input___IZDc3[type=password]::-webkit-strong-password-toggle-button{visibility:hidden!important;opacity:0!important;pointer-events:none!important;appearance:none!important;width:0!important;height:0!important;margin:0!important;padding:0!important;display:none!important;position:absolute!important;left:-9999px!important}.styles-module__input___IZDc3[type=password]::-ms-reveal{visibility:hidden!important;opacity:0!important;pointer-events:none!important;width:0!important;height:0!important;display:none!important;position:absolute!important;left:-9999px!important}.styles-module__input___IZDc3[type=password]::-ms-clear{visibility:hidden!important;opacity:0!important;pointer-events:none!important;width:0!important;height:0!important;display:none!important;position:absolute!important;left:-9999px!important}.styles-module__input___IZDc3:focus{border-color:var(--color-primary);box-shadow:0 0 0 3px rgba(var(--color-primary-rgb,102, 126, 234), .1)}.styles-module__input___IZDc3::placeholder{color:var(--color-fg-muted,var(--color-fg-text));opacity:.5}.styles-module__input___IZDc3.styles-module__small___cuGyE{padding:.5rem .75rem;font-size:.8125rem}.styles-module__input___IZDc3.styles-module__medium___JdDPu{padding:.75rem;font-size:.875rem}.styles-module__input___IZDc3.styles-module__large___fMmiG{padding:1rem;font-size:1rem}.styles-module__input___IZDc3.styles-module__default___-eZTG{background:var(--color-bg);border-color:var(--color-border-4)}.styles-module__input___IZDc3.styles-module__filled___EQ5PQ{background:var(--color-bg-2);border-color:var(--color-border-3)}.styles-module__inputContainer___wXY53.styles-module__withLeftIcon___NFn6- .styles-module__input___IZDc3{padding-left:2.5rem}.styles-module__inputContainer___wXY53.styles-module__withRightIcon___mz-hn .styles-module__input___IZDc3{padding-right:2.5rem}.styles-module__inputContainer___wXY53.styles-module__withLeftIcon___NFn6- .styles-module__input___IZDc3.styles-module__small___cuGyE{padding-left:2rem}.styles-module__inputContainer___wXY53.styles-module__withRightIcon___mz-hn .styles-module__input___IZDc3.styles-module__small___cuGyE{padding-right:2rem}.styles-module__inputContainer___wXY53.styles-module__withLeftIcon___NFn6- .styles-module__input___IZDc3.styles-module__large___fMmiG{padding-left:3rem}.styles-module__inputContainer___wXY53.styles-module__withRightIcon___mz-hn .styles-module__input___IZDc3.styles-module__large___fMmiG{padding-right:3rem}.styles-module__leftIcon___jEW5H,.styles-module__rightIcon___bA3Eo{color:var(--color-fg-muted,var(--color-fg-text));pointer-events:none;z-index:1;justify-content:center;align-items:center;display:flex;position:absolute}.styles-module__leftIcon___jEW5H{left:.75rem}.styles-module__rightIcon___bA3Eo{right:.75rem}.styles-module__rightIcon___bA3Eo.styles-module__rightIconInteractive___ccypw{pointer-events:auto}.styles-module__inputContainer___wXY53.styles-module__containerSmall___20ICq .styles-module__leftIcon___jEW5H{left:.5rem}.styles-module__inputContainer___wXY53.styles-module__containerSmall___20ICq .styles-module__rightIcon___bA3Eo{right:.5rem}.styles-module__inputContainer___wXY53.styles-module__containerLarge___IztuN .styles-module__leftIcon___jEW5H{left:1rem}.styles-module__inputContainer___wXY53.styles-module__containerLarge___IztuN .styles-module__rightIcon___bA3Eo{right:1rem}.styles-module__input___IZDc3.styles-module__error___946qV{border-color:var(--color-danger)}.styles-module__input___IZDc3.styles-module__error___946qV:focus{border-color:var(--color-danger);box-shadow:0 0 0 3px rgba(var(--color-danger-rgb,244, 67, 54), .1)}.styles-module__input___IZDc3.styles-module__disabled___sJvLd{background:var(--color-bg-3);border-color:var(--color-border-5);color:var(--color-fg-muted);cursor:not-allowed;opacity:.6}.styles-module__errorMessage___5Mn22{color:var(--color-danger);margin:0;font-size:.75rem}.styles-module__helperText___T2eui{color:var(--color-fg-muted);margin:0;font-size:.75rem}.styles-module__container___xeg8O{flex-direction:column;gap:1rem;display:flex}.styles-module__label___qhbKe{color:var(--color-fg-text);font-size:.875rem;font-weight:500}.styles-module__error___O-7AY{color:var(--color-error);font-size:.875rem}.styles-module__pairs___owGV3{flex-direction:column;gap:.75rem;display:flex}.styles-module__pair___G4WFY{grid-template-columns:1fr 2fr auto;align-items:start;gap:.75rem;display:grid}.styles-module__keyInput___wl1M1,.styles-module__valueInput___HiwJ5{flex:1}.styles-module__removeButton___4-X0b{min-width:auto;color:var(--color-error);padding:.5rem}.styles-module__removeButton___4-X0b:hover{background-color:var(--color-error);color:#fff}.styles-module__addButton___QFljt{align-self:flex-start}@media (width<=768px){.styles-module__pair___G4WFY{grid-template-columns:1fr}.styles-module__removeButton___4-X0b{align-self:flex-end}}.styles-module__searchContainer___86TGN{width:100%;max-width:400px;position:relative}.styles-module__searchIcon___ZInry{color:var(--color-fg-muted);pointer-events:none;position:absolute;top:50%;left:1rem;transform:translateY(-50%)}.styles-module__searchInput___SqZXQ{border:1px solid var(--color-border);width:100%;color:var(--color-fg-text);background:var(--color-bg-2);border-radius:.5rem;padding:.75rem 3rem;font-size:1rem;transition:all .2s}.styles-module__searchInput___SqZXQ:focus{border-color:var(--color-primary);box-shadow:0 0 0 3px var(--color-primary-bg);outline:none}.styles-module__searchInput___SqZXQ::placeholder{color:var(--color-fg-muted)}.styles-module__clearBtn___7jExr{width:1.5rem;height:1.5rem;color:var(--color-fg-muted);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;padding:0;transition:all .2s;display:flex;position:absolute;top:50%;right:.75rem;transform:translateY(-50%)}.styles-module__clearBtn___7jExr:hover{color:var(--color-fg-text)}@media (width<=768px){.styles-module__searchContainer___86TGN{max-width:100%}}.styles-module__container___nGxdM{flex-direction:column;gap:.75rem;display:flex}.styles-module__toggleContainer___VrsKI{align-items:center;display:flex}.styles-module__toggleButton___IzD6Z{border:1px solid var(--color-border-4);background:var(--color-bg);color:var(--color-fg-muted);cursor:pointer;border-radius:.5rem;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.875rem;transition:all .2s;display:flex}.styles-module__toggleButton___IzD6Z:hover{background:var(--color-bg-2);border-color:var(--color-border-3)}.styles-module__toggleButton___IzD6Z.styles-module__enabled___cao0G{background:var(--color-primary);color:#fff;border-color:var(--color-primary)}.styles-module__toggleButton___IzD6Z.styles-module__enabled___cao0G:hover{background:var(--color-primary-hover);border-color:var(--color-primary-hover)}.styles-module__optionsContainer___LOzlO{background:var(--color-bg-2);border:1px solid var(--color-border-4);border-radius:.5rem;gap:.5rem;padding:.5rem;display:flex}.styles-module__option___abhnC{border:1px solid var(--color-border-4);background:var(--color-bg);color:var(--color-fg);cursor:pointer;border-radius:.375rem;flex:1;justify-content:center;align-items:center;gap:.375rem;padding:.5rem .875rem;font-size:.875rem;font-weight:500;transition:all .2s;display:flex}.styles-module__option___abhnC:hover{background:var(--color-bg-3);border-color:var(--color-border-3)}.styles-module__option___abhnC.styles-module__active___pqmSi{background:var(--color-primary);color:#fff;border-color:var(--color-primary)}.styles-module__option___abhnC.styles-module__active___pqmSi:hover{background:var(--color-primary-hover);border-color:var(--color-primary-hover)}.styles-module__nbSelect___KjxSc{font-family:inherit;font-size:.9375rem;font-weight:600;line-height:1.5rem;display:inline-block;position:relative}.styles-module__selectButton___AKZe4{cursor:pointer;text-align:left;width:100%;min-width:8rem;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;appearance:none;border:1px solid;border-radius:.25rem;outline:none;justify-content:space-between;align-items:center;padding:.4375rem 2.2rem .4375rem 1.125rem;transition:all .15s ease-in-out;display:flex;position:relative}.styles-module__selectButton___AKZe4.styles-module__primary___HU36a{background-color:var(--color-primary);border-color:var(--color-primary);color:var(--color-primary-fg)}.styles-module__selectButton___AKZe4.styles-module__primary___HU36a:hover:not(:disabled){background-color:var(--color-primary-light);border-color:var(--color-primary-light)}.styles-module__selectButton___AKZe4.styles-module__primary___HU36a:focus,.styles-module__selectButton___AKZe4.styles-module__primary___HU36a.styles-module__open___9AKMb{background-color:var(--color-primary-light);border-color:var(--color-primary-light);box-shadow:0 0 0 .125rem #8f9bb340}.styles-module__selectButton___AKZe4.styles-module__default___LedYP{background-color:var(--color-bg);border-color:var(--color-border-4);color:var(--color-fg-text)}.styles-module__selectButton___AKZe4.styles-module__default___LedYP:hover:not(:disabled){background-color:var(--color-bg-2);border-color:var(--color-primary)}.styles-module__selectButton___AKZe4.styles-module__default___LedYP:focus,.styles-module__selectButton___AKZe4.styles-module__default___LedYP.styles-module__open___9AKMb{background-color:var(--color-bg-2);border-color:var(--color-primary);box-shadow:0 0 0 .125rem #8f9bb340}.styles-module__selectButton___AKZe4:disabled{cursor:not-allowed;opacity:.6}.styles-module__buttonText___QSLO1{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.styles-module__chevronIcon___qAHaD{flex-shrink:0;width:1.5rem;height:1.5rem;transition:transform .15s;position:absolute;right:.41rem}.styles-module__selectButton___AKZe4.styles-module__primary___HU36a .styles-module__chevronIcon___qAHaD{color:var(--color-primary-fg)}.styles-module__selectButton___AKZe4.styles-module__default___LedYP .styles-module__chevronIcon___qAHaD{color:var(--color-fg)}.styles-module__chevronIcon___qAHaD.styles-module__open___9AKMb{transform:rotate(180deg)}.styles-module__optionsPanel___NWAp3{background-color:var(--color-bg);border:1px solid var(--color-border-4);z-index:1000;transform-origin:top;visibility:hidden;pointer-events:none;border-radius:.25rem;min-width:100%;position:absolute;top:calc(100% + .5rem);left:0;right:0;overflow:hidden;box-shadow:0 .5rem 1rem #00000026}.styles-module__optionsPanel___NWAp3.styles-module__open___9AKMb{visibility:visible;pointer-events:auto;animation:.25s ease-out styles-module__expandDown___eD4lh}.styles-module__optionsPanel___NWAp3.styles-module__closed___bez-q{visibility:hidden;pointer-events:none;animation:.25s ease-out styles-module__collapseUp___dt1E7}@keyframes styles-module__expandDown___eD4lh{0%{opacity:0;transform:scaleY(0)}to{opacity:1;transform:scaleY(1)}}@keyframes styles-module__collapseUp___dt1E7{0%{opacity:1;transform:scaleY(1)}to{opacity:0;transform:scaleY(0)}}.styles-module__optionsPanel___NWAp3.styles-module__primary___HU36a{border-color:var(--color-primary)}.styles-module__optionsPanel___NWAp3.styles-module__default___LedYP{border-color:var(--color-border-4)}.styles-module__optionsList___AxhVp{margin:0;padding:.5rem 0;list-style:none}.styles-module__option___t1SSw{cursor:pointer;color:var(--color-fg-text);justify-content:space-between;align-items:center;padding:.75rem 1.125rem;transition:all .15s;display:flex}.styles-module__option___t1SSw:hover{background-color:var(--color-bg-2)}.styles-module__option___t1SSw.styles-module__selected___azD4A{background-color:var(--color-primary);color:var(--color-primary-fg);font-weight:700}@media (prefers-color-scheme:dark){.styles-module__optionsPanel___NWAp3{box-shadow:0 .5rem 1rem #0000004d}}.styles-module__sliderContainer___lgpaD{flex-direction:column;gap:.5rem;display:flex}.styles-module__sliderContainer___lgpaD.styles-module__fullWidth___ZS8W5{width:100%}.styles-module__labelRow___dkVVM{justify-content:space-between;align-items:center;min-height:1.5rem;margin-bottom:.5rem;display:flex}.styles-module__label___bXGZs{color:var(--color-fg-text);font-size:.875rem;font-weight:500}.styles-module__required___FuyfE{color:var(--color-danger);margin-left:.25rem}.styles-module__sliderWrapper___1Wdti{touch-action:none;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;gap:.75rem;width:100%;display:flex}.styles-module__sliderRoot___yzOjR{cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none;flex-grow:1;align-items:center;width:100%;padding:.75rem 0;display:flex;position:relative}.styles-module__sliderRoot___yzOjR:active{cursor:grabbing}.styles-module__sliderTrackWrapper___N72WQ{flex-grow:1;display:flex;position:relative}.styles-module__sliderTrack___AltcD{background-color:var(--color-bg-3);border-radius:9999px;width:100%;height:.375rem;position:relative;overflow:hidden}.styles-module__sliderRange___U3g0-{background-color:var(--color-primary);border-radius:9999px;height:100%;position:absolute}.styles-module__valueIndicator___aLf0I{color:var(--color-primary);text-align:center;flex-shrink:0;min-width:2rem;font-size:.875rem;font-weight:600;line-height:1}.styles-module__iconWrapper___wL-b8{flex-shrink:0;justify-content:center;align-items:center;display:flex}.styles-module__icon___vHsID{width:20px;height:20px;color:var(--color-fg-muted)}.styles-module__errorMessage___qFgGe{color:var(--color-danger);margin:0;font-size:.75rem}.styles-module__helperText___tgBGl{color:var(--color-fg-muted);margin:0;font-size:.75rem}.styles-module__loadingContainer___OMgwS{flex-direction:column;justify-content:center;align-items:center;gap:1.5rem;min-height:60vh;display:flex}.styles-module__loadingText___KRZqR{color:var(--color-fg-muted);font-size:1rem}.styles-module__errorContainer___qhAg2{text-align:center;min-height:60vh;color:var(--color-fg-text);flex-direction:column;justify-content:center;align-items:center;gap:2rem;padding:3rem 2rem;display:flex}.styles-module__errorIconWrapper___IHZrN{background:linear-gradient(135deg, rgba(var(--color-error-rgb,239, 68, 68), .1), rgba(var(--color-error-rgb,239, 68, 68), .05));border:2px solid rgba(var(--color-error-rgb,239, 68, 68), .2);border-radius:50%;justify-content:center;align-items:center;width:120px;height:120px;animation:2s ease-in-out infinite styles-module__pulse___Lju-z;display:flex}@keyframes styles-module__pulse___Lju-z{0%,to{opacity:1;transform:scale(1)}50%{opacity:.9;transform:scale(1.05)}}.styles-module__errorIcon___oGDIP{color:var(--color-error,#ef4444);stroke-width:1.5px}.styles-module__errorContent___F55rQ{flex-direction:column;align-items:center;gap:1rem;width:100%;max-width:600px;display:flex}.styles-module__errorTitle___hC8D-{color:var(--color-fg-heading);letter-spacing:-.02em;margin:0;font-size:1.75rem;font-weight:700;line-height:1.2}.styles-module__errorDescription___hZtuP{color:var(--color-fg-muted);max-width:480px;margin:0;font-size:1rem;line-height:1.6}.styles-module__errorDetailsWrapper___-sp8b{width:100%;max-width:600px;margin-top:.5rem}.styles-module__errorDetailsContainer___eywMo{text-align:left;border:1px solid var(--color-border,#0000001a);background:var(--color-bg-2,#00000005);border-radius:.75rem;width:100%;transition:all .2s;overflow:hidden}.styles-module__errorDetailsContainer___eywMo:hover{border-color:var(--color-border-hover,#00000026);background:var(--color-bg-3,#00000008)}.styles-module__errorDetailsSummary___hGEoD{cursor:pointer;color:var(--color-fg-muted);-webkit-user-select:none;user-select:none;padding:.875rem 1.25rem;font-size:.875rem;font-weight:500;list-style:none;transition:color .2s}.styles-module__errorDetailsSummary___hGEoD:hover{color:var(--color-fg-text)}.styles-module__errorDetailsSummary___hGEoD::-webkit-details-marker{display:none}.styles-module__errorDetailsSummary___hGEoD:before{content:"▶";margin-right:.5rem;font-size:.75rem;transition:transform .2s;display:inline-block}.styles-module__errorDetailsContainer___eywMo[open] .styles-module__errorDetailsSummary___hGEoD:before{transform:rotate(90deg)}.styles-module__errorDetails___tzCT-{background:var(--color-bg-3,#00000008);border-top:1px solid var(--color-border,#0000001a);max-width:100%;color:var(--color-fg-muted);white-space:pre-wrap;word-break:break-word;margin:0;padding:1rem 1.25rem;font-family:Monaco,Menlo,Ubuntu Mono,Consolas,source-code-pro,monospace;font-size:.8125rem;line-height:1.6;overflow-x:auto}.styles-module__errorActions___gtqYw{flex-wrap:wrap;justify-content:center;align-items:center;gap:.75rem;margin-top:1rem;display:flex}.styles-module__retryButton___TA4jm{background:var(--color-primary);color:var(--color-primary-fg);cursor:pointer;border:none;border-radius:.5rem;justify-content:center;align-items:center;gap:.5rem;padding:.75rem 2rem;font-size:.9375rem;font-weight:500;transition:all .2s;display:inline-flex;box-shadow:0 2px 8px #00000014}.styles-module__retryButton___TA4jm:hover{background:var(--color-primary-hover,var(--color-primary));transform:translateY(-2px);box-shadow:0 4px 16px #0000001f}.styles-module__retryButton___TA4jm:active{transform:translateY(0);box-shadow:0 2px 8px #00000014}.styles-module__retryButtonIcon___vzfp-{font-size:1.125rem;line-height:1;transition:transform .3s;display:inline-block}.styles-module__retryButton___TA4jm:hover .styles-module__retryButtonIcon___vzfp-{transform:rotate(180deg)}.styles-module__clearLocalDataButton___T3B-K{color:var(--color-fg-muted);border:1px solid var(--color-border-4);cursor:pointer;background:0 0;border-radius:.5rem;justify-content:center;align-items:center;padding:.75rem 1.5rem;font-size:.9375rem;font-weight:500;transition:all .2s;display:inline-flex}.styles-module__clearLocalDataButton___T3B-K:hover{color:var(--color-fg-text);border-color:var(--color-border-3);background:var(--color-bg-secondary)}.styles-module__wrapper___jXPV3{flex-direction:column;gap:.5rem;display:flex}.styles-module__wrapper___jXPV3.styles-module__fullWidth___eKyGB{width:100%}.styles-module__label___MyTeo{color:var(--color-fg-heading);align-items:center;gap:.25rem;font-size:.875rem;font-weight:500;display:flex}.styles-module__required___TV-m8{color:var(--color-danger)}.styles-module__inputContainer___VvGBl{align-items:flex-start;width:100%;display:flex;position:relative}.styles-module__textarea___AjX9N{border:1px solid var(--color-border-4);background:var(--color-bg);width:100%;color:var(--color-fg-text);resize:vertical;border-radius:.5rem;outline:none;min-height:4rem;font-family:inherit;font-size:.875rem;transition:all .2s}.styles-module__textarea___AjX9N:focus{border-color:var(--color-primary);box-shadow:0 0 0 3px rgba(var(--color-primary-rgb,102, 126, 234), .1)}.styles-module__textarea___AjX9N::placeholder{color:var(--color-fg-muted,var(--color-fg-text));opacity:.5}.styles-module__textarea___AjX9N.styles-module__small___zMx0G{min-height:3rem;padding:.5rem .75rem;font-size:.8125rem}.styles-module__textarea___AjX9N.styles-module__medium___tO2Lb{min-height:4rem;padding:.75rem;font-size:.875rem}.styles-module__textarea___AjX9N.styles-module__large___3eU2g{min-height:5rem;padding:1rem;font-size:1rem}.styles-module__textarea___AjX9N.styles-module__default___vsSxX{background:var(--color-bg);border-color:var(--color-border-4)}.styles-module__textarea___AjX9N.styles-module__filled___TPQgI{background:var(--color-bg-2);border-color:var(--color-border-3)}.styles-module__inputContainer___VvGBl .styles-module__leftIcon___FHp2R{color:var(--color-fg-muted,var(--color-fg-text));pointer-events:none;z-index:1;justify-content:center;align-items:center;display:flex;position:absolute;top:.75rem;left:.75rem}.styles-module__inputContainer___VvGBl .styles-module__rightIcon___dkyvP{color:var(--color-fg-muted,var(--color-fg-text));pointer-events:none;z-index:1;justify-content:center;align-items:center;display:flex;position:absolute;top:.75rem;right:.75rem}.styles-module__inputContainer___VvGBl .styles-module__textarea___AjX9N.styles-module__small___zMx0G+.styles-module__leftIcon___FHp2R,.styles-module__inputContainer___VvGBl .styles-module__textarea___AjX9N.styles-module__small___zMx0G+.styles-module__rightIcon___dkyvP{top:.5rem}.styles-module__inputContainer___VvGBl .styles-module__textarea___AjX9N.styles-module__large___3eU2g+.styles-module__leftIcon___FHp2R,.styles-module__inputContainer___VvGBl .styles-module__textarea___AjX9N.styles-module__large___3eU2g+.styles-module__rightIcon___dkyvP{top:1rem}.styles-module__textarea___AjX9N.styles-module__error___d8gLK{border-color:var(--color-danger)}.styles-module__textarea___AjX9N.styles-module__error___d8gLK:focus{border-color:var(--color-danger);box-shadow:0 0 0 3px rgba(var(--color-danger-rgb,244, 67, 54), .1)}.styles-module__textarea___AjX9N.styles-module__disabled___IzbfE{background:var(--color-bg-3);border-color:var(--color-border-5);color:var(--color-fg-muted);cursor:not-allowed;opacity:.6}.styles-module__errorText___Nom7x{color:var(--color-danger);margin:0;font-size:.75rem}.styles-module__helperText___97Def{color:var(--color-fg-muted);margin:0;font-size:.75rem}.styles-module__virtualList___pM6rN{contain:strict;width:100%;padding-bottom:300px;position:relative;overflow:auto}.styles-module__emptyContainer___rm938{height:100%;color:var(--color-fg-muted);justify-content:center;align-items:center;display:flex}.styles-module__virtualListInner___HxRzc{width:100%;position:relative}.styles-module__virtualListItems___p19-a{width:100%;position:absolute;top:0;left:0}.styles-module__loadingMore___zAdLM{color:var(--color-fg-muted);justify-content:center;align-items:center;gap:.75rem;padding:2rem 0;font-size:.875rem;display:flex}.styles-module__endOfList___5cYFh{color:var(--color-fg-muted);border-top:1px solid var(--color-border-3);justify-content:center;margin-top:1rem;padding:2rem 0;font-size:.875rem;display:flex}.styles-module__endOfList___5cYFh span{background-color:var(--color-bg-2);border-radius:.25rem;padding:.5rem 1rem}.styles-module__virtualList___xmj2v{width:100%;padding-bottom:300px;position:relative;overflow:visible}.styles-module__virtualListInner___quD74{width:100%;position:relative}.styles-module__virtualListItems___-Muml{width:100%;position:absolute;top:0;left:0}.styles-module__virtualListRow___h3pzX{width:100%}.styles-module__emptyContainer___LIy8r{color:var(--color-fg-muted);justify-content:center;align-items:center;padding:2rem 0;display:flex}.styles-module__loadingMore___Mzf-p{color:var(--color-fg-muted);justify-content:center;align-items:center;padding:1.5rem 0;display:flex}.styles-module__endOfList___g5G--{color:var(--color-fg-muted);border-top:1px solid var(--color-border-3);justify-content:center;padding:1.5rem 0;display:flex}.styles-module__sidebar___BMt0j{flex-direction:column;height:100%;min-height:0;display:flex;overflow:hidden}.styles-module__sidebarContent___iAwiw{flex-direction:column;height:100%;min-height:0;padding-top:1rem;display:flex;overflow:hidden}.styles-module__menuWrapper___DKuEv{flex:1;min-height:0;overflow:hidden auto}.styles-module__sidebarContent___iAwiw::-webkit-scrollbar{width:0}.styles-module__sidebarContent___iAwiw::-webkit-scrollbar-track{background:0 0}.styles-module__sidebarContent___iAwiw::-webkit-scrollbar-thumb{background:0 0}.styles-module__sidebarContent___iAwiw::-webkit-scrollbar-thumb:hover{background:0 0}.styles-module__sidebar___BMt0j a{margin-left:0}.styles-module__sidebar___BMt0j .ps-sidebar-root{background-color:var(--color-bg-2)!important;border-right:1px solid var(--color-separator)!important;flex-direction:column!important;height:100%!important;min-height:0!important;display:flex!important;overflow:hidden!important}.styles-module__sidebar___BMt0j .ps-sidebar-container{background-color:var(--color-bg-2)!important;height:100%!important;min-height:0!important;color:var(--color-fg-text)!important;flex-direction:column!important;flex:1!important;display:flex!important;overflow:hidden!important}.styles-module__sidebar___BMt0j .ps-menu-button{color:var(--color-fg-text)!important;border-radius:.375rem!important;margin:.125rem .5rem!important;padding:.5rem .75rem!important;font-size:.875rem!important;transition:all .2s!important}.styles-module__sidebar___BMt0j .ps-menu-button:hover{background-color:var(--color-bg-3)!important;color:var(--color-fg-text)!important}.styles-module__sidebar___BMt0j .ps-menu-button.ps-active{background-color:var(--color-primary)!important;color:#fff!important}.styles-module__sidebar___BMt0j .ps-menu-button.ps-active *,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active .ps-menu-icon,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active .ps-menu-label{color:#fff!important}.styles-module__sidebar___BMt0j .ps-menu-icon{width:1.25rem!important;height:1.25rem!important;color:var(--color-fg-text)!important;margin-right:.5rem!important}.styles-module__sidebar___BMt0j .ps-submenu-content{background-color:var(--color-bg-3)!important;padding-left:.5rem!important;overflow:hidden!important}.styles-module__sidebar___BMt0j .ps-submenu-content .ps-menu-button{margin:.125rem .25rem!important;padding:.375rem .5rem!important;font-size:.8125rem!important;transition:all .2s!important}.styles-module__sidebar___BMt0j .ps-menu-label{color:var(--color-fg-text)!important;font-weight:500!important}.styles-module__sidebar___BMt0j .ps-menu-button.ps-active,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active span,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active div,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active .ps-menu-icon,.styles-module__sidebar___BMt0j .ps-menu-button.ps-active .ps-menu-label{color:#fff!important}.styles-module__logoutContainer___7NwBL{border-top:1px solid var(--color-separator);writing-mode:horizontal-tb;text-orientation:mixed;flex-shrink:0;margin-top:auto;padding:.5rem}.styles-module__logoutButton___rfD6u{width:100%;color:var(--color-fg-text);cursor:pointer;white-space:nowrap;writing-mode:horizontal-tb;text-orientation:mixed;direction:ltr;background:0 0;border:none;border-radius:.375rem;justify-content:flex-start;align-items:center;gap:.5rem;padding:.5rem .75rem;font-size:.875rem;transition:background-color .2s,color .2s;display:flex;overflow:hidden}.styles-module__logoutButton___rfD6u span{opacity:1;max-width:200px;transition:opacity .3s,max-width .3s;display:inline-block;writing-mode:horizontal-tb!important;text-orientation:mixed!important;direction:ltr!important;transform:none!important}.styles-module__logoutButton___rfD6u .styles-module__hiddenText___z183T{opacity:0;width:0;max-width:0;overflow:hidden}.styles-module__logoutButton___rfD6u .styles-module__visibleText___lfsv-{opacity:1;width:auto;max-width:200px}.styles-module__logoutButton___rfD6u:hover{background-color:var(--color-bg-3)}.styles-module__logoutButton___rfD6u:active{transform:scale(.98)}.styles-module__logoutButton___rfD6u svg{color:inherit;flex-shrink:0}.styles-module__footer___g-hY7{background:var(--color-bg-2);width:100%;padding:0 2rem}.styles-module__footerContent___Oen5n{justify-content:space-between;align-items:center;max-width:100%;margin:0 auto;display:flex}.styles-module__copyright___1R2o3{color:var(--color-fg-text);font-size:.875rem}.styles-module__links___dQyvB{gap:1.5rem;display:flex}.styles-module__link___UWfyK{color:var(--color-fg-text);font-size:.875rem;text-decoration:none;transition:color .3s}.styles-module__link___UWfyK:hover{color:var(--color-primary)}@media (width<=768px){.styles-module__footerContent___Oen5n{flex-direction:column;gap:1rem}.styles-module__links___dQyvB{gap:1rem}}.styles-module__header___4Uc8h{width:100%;padding:.5rem 2rem;display:flex}.styles-module__header___4Uc8h>:first-child{flex:1;justify-content:flex-start;align-items:center;display:flex}.styles-module__header___4Uc8h>:last-child{flex:1;justify-content:flex-end;align-items:center;display:flex}.styles-module__layout___ZQKU7{background:var(--color-bg);flex-direction:column;width:100%;height:100vh;display:flex;position:relative}.styles-module__header___XIaFb{z-index:100;background:var(--color-bg);width:100%;position:fixed;top:0;box-shadow:0 .125rem .25rem #2c33491a}.styles-module__footer___r8ASO{z-index:100;width:100%;position:fixed;bottom:0}.styles-module__mainWrapper___i4tEI{flex:1;display:flex;position:relative}.styles-module__sidebar___ij-8-{position:fixed;top:0}.styles-module__content___mTgUr{background:var(--color-bg);flex:1;min-height:calc(100vh - 10rem);margin:0;padding-top:0;padding-bottom:0;overflow:hidden auto}@media (width<=768px){.styles-module__content___mTgUr{width:100%}.styles-module__sidebar___ij-8-{z-index:999;height:100vh;position:fixed;top:0;left:0}}.styles-module__mainWrapper___AiTAw{flex-direction:row;flex:1;display:flex;position:relative}.styles-module__sidebarContainer___X4yj8{z-index:99;flex-direction:column;display:flex;position:fixed;left:0;overflow:hidden}.styles-module__sidebar___VQTlH{flex-shrink:0;top:0;left:0}.styles-module__content___htJlH{background:var(--color-bg);flex:1;margin:0;padding-top:0;padding-bottom:0;overflow:hidden auto}@media (width<=1024px){.styles-module__content___htJlH{padding:1.5rem}}@media (width<=768px){.styles-module__content___htJlH{width:100%}.styles-module__sidebar___VQTlH{z-index:999;height:100vh;position:fixed;top:0;left:0}}.styles-module__wavesWrapper___TK7DI{pointer-events:none;z-index:0;width:100vw;height:100vh;position:fixed;inset:0;overflow:hidden}.styles-module__wavesWrapper___TK7DI>*{pointer-events:auto}.styles-module__squaresWrapper___P25uF{pointer-events:none;z-index:0;width:100vw;height:100vh;position:fixed;inset:0;overflow:hidden}.styles-module__squaresWrapper___P25uF>*{pointer-events:auto}.styles-module__letterGlitchWrapper___KWtWU{pointer-events:none;z-index:0;width:100vw;height:100vh;position:fixed;inset:0;overflow:hidden}.styles-module__letterGlitchWrapper___KWtWU>*{pointer-events:auto}.styles-module__pixelBlastWrapper___YptHh{pointer-events:none;z-index:0;width:100vw;height:100vh;position:fixed;inset:0;overflow:hidden}.styles-module__pixelBlastWrapper___YptHh>*{pointer-events:auto}
|
|
2
|
+
/*$vite$:1*/`)),document.head.appendChild(e)}}catch(o){console.error("vite-plugin-css-injected-by-js",o)}})();
|
|
3
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b=require("./chunk-chunk-BFrxaqQT.cjs");let m=require("react"),f=require("@tanstack/react-query");function k(i,c=20,n){return async(a=0,u)=>{const{items:e,total:r}=await i({...u,offset:a*c,limit:c});return e?.length&&n?.(e),{items:e,total:r}}}function h(i,c=20,n){return async(a="",u)=>{const{items:e,nextCursor:r}=await i({...u,offset:a,limit:c});return e?.length&&n?.(e),{items:e,nextCursor:r}}}var l="normal",C="suspense";function N(i,c=l,n=20,a){const u=k(i,n,a);return c==="suspense"?(e,r,t)=>E(e,u,r,t,n):(e,r,t)=>O(e,u,r,t,n)}function F(i,c,n,a,u){return{queryKey:n!==void 0?[...i,n]:i,queryFn:({pageParam:e})=>c(e,n||{}),initialPageParam:0,getNextPageParam:(e,r)=>u!=null&&r.length*u<e.total?r.length:void 0,select:e=>e.pages.flatMap(r=>r.items),retry:(e,r)=>{const t=r?.status&&r.status>=500||r?.code==="NETWORK_ERROR",s=typeof a?.retry=="number"?a.retry:3;return t&&e<s},...a}}function O(i,c,n,a,u){return(0,f.useInfiniteQuery)((0,m.useMemo)(()=>F(i,c,n,a,u),[i,c,n,a,u]))}function E(i,c,n,a,u){return(0,f.useSuspenseInfiniteQuery)((0,m.useMemo)(()=>F(i,c,n,a,u),[i,c,n,a,u]))}function S(i,c=l,n){const a=async t=>{const s=await i(t);return n?.(s),s},u=(t,s,o)=>({queryKey:s!==void 0?[...t,s]:t,queryFn:()=>a(s||{}),select:y=>y,retry:(y,d)=>{const Q=d?.status??d?.response?.status,M=typeof Q=="number"&&Q>=500||d?.code==="NETWORK_ERROR",R=typeof o?.retry=="number"?o.retry:3;return M&&y<R},...o});function e(t,s,o){return(0,f.useQuery)((0,m.useMemo)(()=>u(t,s,o),[t,s,o]))}function r(t,s,o){return(0,f.useSuspenseQuery)((0,m.useMemo)(()=>u(t,s,o),[t,s,o]))}return c==="suspense"?(t,s,o)=>r(t,s,o):(t,s,o)=>e(t,s,o)}exports.NORMAL=l;exports.SUSPENSE=C;exports.makeCursorFetchFunction=k;exports.makeStringCursorFetchFunction=h;exports.makeUnifiedInfiniteQuery=N;exports.makeUnifiedQuery=S;
|
|
4
|
+
|
|
5
|
+
//# sourceMappingURL=hooks.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.cjs","names":[],"sources":["../src/hooks/makeCursorFetchFunction.tsx","../src/hooks/type.ts","../src/hooks/makeUnifiedInfiniteQuery.tsx","../src/hooks/makeUnifiedQuery.tsx"],"sourcesContent":["import type { ListDTOWithNextCursor, ListDTOWithTotalNumber } from \"@/types/api\";\nimport type { FetchNumberListParams, FetchStringListParams } from \"./type\";\n\n/**\n * 创建基于游标(Cursor)的分页获取函数\n *\n * 将标准的分页 API(基于 offset/limit)转换为游标分页函数,用于无限查询。\n * 自动计算下一页游标,并支持数据后处理。\n *\n * @template T - 数据项类型\n * @template F - 过滤器对象类型,必须是对象类型,默认为 Record<string, unknown>\n *\n * @param {Function} fetchFunc - 远程数据获取函数,接收 FetchListParams 参数,返回包含 items 和 total 的结果\n * @param {number} [pageSize=20] - 每页数据条数,默认 20\n * @param {Function} [postProcess] - 可选的数据后处理函数,在每次数据获取后调用\n *\n * @returns {Function} 返回一个游标分页函数,接收 pageParam(页码)和 filter(过滤器)参数\n *\n * @example\n * ```tsx\n * * 定义标准的分页 API\n * const fetchProductsAPI = async (params: { offset: number; limit: number; category?: string }) => {\n * const response = await fetch('/api/products?' + new URLSearchParams(params));\n * const { items, total } = await response.json();\n * return { items, total };\n * };\n *\n * * 创建游标分页函数\n * const fetchProducts = makeCursorFetchFunction(\n * fetchProductsAPI,\n * 20,\n * (data) => {\n * * 数据后处理:为每个商品添加缓存\n * data.forEach(product => cache.set(product.id, product));\n * }\n * );\n *\n * * 使用游标函数\n * const firstPage = await fetchProducts(0, { category: \"electronics\" });\n * * 返回: ListDTOWithTotalNumber<Product> = { items, total }\n * * getNextPageParam 由 makeUnifiedInfiniteQuery 根据 total 与 pageSize 计算\n * ```\n *\n * @remarks\n * **为什么需要游标转换?**\n * - React Query 的无限查询使用 pageParam(游标)来跟踪分页位置\n * - 后端 API 通常使用 offset/limit 分页,两者需要转换才能配合使用\n * - 游标模式更适合无限滚动,避免在组件中手动计算 offset\n *\n * **游标计算逻辑:**\n * - **offset 计算**:`offset = pageParam × pageSize`\n * - 示例:pageParam=0 → offset=0(第一页)\n * - 示例:pageParam=2, pageSize=20 → offset=40(第三页,跳过前 40 条)\n * - **nextCursor 判断**:`(pageParam + 1) × pageSize < total ? pageParam + 1 : undefined`\n * - 如果下一页的起始位置小于总数,返回下一页页码\n * - 否则返回 undefined,告知 React Query 没有更多数据\n *\n * **为什么 pageParam 从 0 开始?**\n * - 符合数组索引习惯,第 0 页、第 1 页...\n * - 计算 offset 时公式更简洁:`offset = pageParam × pageSize`\n * - 避免使用 1-based 索引时需要额外的 -1 运算\n *\n * **postProcess 的作用:**\n * - 在数据返回后、缓存前执行,适合进行副作用操作\n * - 常见用途:更新单项缓存、触发分析事件、数据预处理\n * - 不影响返回值,保持数据流的纯净性\n */\nfunction makeCursorFetchFunction<T, F extends object = Record<string, unknown>>(\n fetchFunc: (params: FetchNumberListParams<F>) => Promise<ListDTOWithTotalNumber<T>>,\n pageSize: number = 20,\n postProcess?: (data: T[]) => void,\n) {\n return async (pageParam: number = 0, filter?: F): Promise<ListDTOWithTotalNumber<T>> => {\n const payload = {\n ...filter,\n offset: pageParam * pageSize,\n limit: pageSize,\n } as FetchNumberListParams<F>;\n const { items, total } = await fetchFunc(payload);\n if (items?.length) postProcess?.(items);\n return { items, total };\n };\n}\n\n/**\n * 创建基于字符串游标的分页获取函数(用于 nextCursor 为 string 的 API)。\n * Creates cursor-based fetch function for string cursor (API returns nextCursor: string).\n *\n * @param fetchFunc - 远程获取函数,参数含 offset: string, limit,返回 { items, nextCursor }。Fetch (params: FetchStringListParams<F>) => Promise<ListDTOWithNextCursor<T>>.\n * @param pageSize - 每页条数,默认 20。Page size.\n * @param postProcess - 可选,数据返回后调用。Optional post-process (data: T[]) => void.\n * @returns 返回 (pageParam: string, filter?: F) => Promise<ListDTOWithNextCursor<T>>。Returns async cursor fetcher.\n * @example\n * ```ts\n * const fetch = makeStringCursorFetchFunction(fetchByToken, 20);\n * const page = await fetch(\"\", { q: \"x\" });\n * if (page.nextCursor) await fetch(page.nextCursor, { q: \"x\" });\n * ```\n */\nfunction makeStringCursorFetchFunction<T, F extends object = Record<string, unknown>>(\n fetchFunc: (params: FetchStringListParams<F>) => Promise<ListDTOWithNextCursor<T>>,\n pageSize: number = 20,\n postProcess?: (data: T[]) => void,\n) {\n return async (pageParam: string = \"\", filter?: F): Promise<ListDTOWithNextCursor<T>> => {\n const payload = {\n ...filter,\n offset: pageParam,\n limit: pageSize,\n } as FetchStringListParams<F>;\n const { items, nextCursor } = await fetchFunc(payload);\n if (items?.length) postProcess?.(items);\n return { items, nextCursor };\n };\n}\n\nexport { makeCursorFetchFunction, makeStringCursorFetchFunction };\n","/**\n * Hooks 模块类型:分页 payload、列表参数、React Query options 等。\n * Types for hooks: page payloads, list params, React Query options.\n */\nimport type { UseInfiniteQueryOptions, UseQueryOptions, UseSuspenseInfiniteQueryOptions, UseSuspenseQueryOptions } from \"@tanstack/react-query\";\nimport type { AxiosError } from \"axios\";\nimport type { ListDTOWithNextCursor, ListDTOWithTotalNumber, OffsetLimitNumber, OffsetLimitString } from \"@/types/api\";\n\n//! ================ Query Mode Constants ================\n\n/** 普通模式(useQuery),可配合 enabled 等。Normal mode (useQuery); supports enabled etc. */\nconst NORMAL = \"normal\" as const;\n\n/** Suspense 模式(useSuspenseQuery),由 React 挂起。Suspense mode (useSuspenseQuery); suspended by React. */\nconst SUSPENSE = \"suspense\" as const;\n\n/** 仅允许 \"normal\" | \"suspense\",请使用 NORMAL / SUSPENSE 避免拼写错误。Only \"normal\" | \"suspense\"; use NORMAL / SUSPENSE to avoid typos. */\ntype QueryMode = typeof NORMAL | typeof SUSPENSE;\n\n//! ================ Base Type ================\n// 列表/分页形状与 offset/limit 参数均来自 @/types/api。\n\n/** F & OffsetLimitNumber,数字分页列表请求参数。Params for number-offset list fetch. */\ntype FetchNumberListParams<F extends object = Record<string, unknown>> = F & OffsetLimitNumber;\n\n/** F & OffsetLimitString,字符串游标列表请求参数。Params for string-cursor list fetch. */\ntype FetchStringListParams<F extends object = Record<string, unknown>> = F & OffsetLimitString;\n\n/** 变更上下文(如 prev)。Mutation context (e.g. prev). */\ntype MutationCtx = {\n prev?: unknown;\n};\n\n//! ================ High Order Type ================\n\n/** 无限查询 options(不含 queryKey/queryFn/getNextPageParam/initialPageParam)。Infinite query options (excludes queryKey, queryFn, getNextPageParam, initialPageParam). */\ntype InfiniteQueryOptions<T> = Omit<\n UseInfiniteQueryOptions<ListDTOWithTotalNumber<T>, AxiosError, T[]>,\n \"queryKey\" | \"queryFn\" | \"getNextPageParam\" | \"initialPageParam\"\n>;\n\n/** 字符串游标无限查询 options。String-cursor infinite query options. */\ntype StringInfiniteQueryOptions<T> = Omit<\n UseInfiniteQueryOptions<ListDTOWithNextCursor<T>, AxiosError, T[]>,\n \"queryKey\" | \"queryFn\" | \"getNextPageParam\" | \"initialPageParam\"\n>;\n\n/** Suspense 无限查询 options。Suspense infinite query options. */\ntype SuspenseInfiniteQueryOptions<T> = Omit<\n UseSuspenseInfiniteQueryOptions<ListDTOWithTotalNumber<T>, AxiosError, T[]>,\n \"queryKey\" | \"queryFn\" | \"getNextPageParam\" | \"initialPageParam\"\n>;\n\n/** InfiniteQueryOptions | SuspenseInfiniteQueryOptions。Union of normal and suspense infinite query options. */\ntype InfiniteQueryOptionsUnion<T> = InfiniteQueryOptions<T> | SuspenseInfiniteQueryOptions<T>;\n\n/** 单条查询 Suspense options。Single-item suspense query options. */\ntype SuspenseUnifiedQueryOptions<T> = Omit<UseSuspenseQueryOptions<T, AxiosError, T>, \"queryKey\" | \"queryFn\">;\n\n/** 普通单条查询 options(含 enabled)。Normal single-item query options (includes enabled). */\ntype NormalUnifiedQueryOptions<T> = Omit<UseQueryOptions<T, AxiosError, T>, \"queryKey\" | \"queryFn\">;\n\n/** 单条查询参数(options、postProcess + 业务参数)。Single-item query params (options, postProcess, and business params). */\ntype UnifiedQueryParams<T> = {\n options?: SuspenseUnifiedQueryOptions<T>;\n postProcess?: (data: T) => void;\n} & Record<string, unknown>;\n\nexport { NORMAL, SUSPENSE };\nexport type {\n FetchNumberListParams,\n FetchStringListParams,\n InfiniteQueryOptions,\n InfiniteQueryOptionsUnion,\n MutationCtx,\n NormalUnifiedQueryOptions,\n QueryMode,\n StringInfiniteQueryOptions,\n SuspenseInfiniteQueryOptions,\n SuspenseUnifiedQueryOptions,\n UnifiedQueryParams,\n};\n","import type { InfiniteData, QueryKey, UseInfiniteQueryResult, UseSuspenseInfiniteQueryResult } from \"@tanstack/react-query\";\nimport type { AxiosError } from \"axios\";\nimport type { ListDTOWithTotalNumber } from \"@/types/api\";\nimport type { FetchNumberListParams, InfiniteQueryOptions, InfiniteQueryOptionsUnion, QueryMode, SuspenseInfiniteQueryOptions } from \"./type\";\n\nimport { useMemo } from \"react\";\nimport { useInfiniteQuery, useSuspenseInfiniteQuery } from \"@tanstack/react-query\";\n\nimport { makeCursorFetchFunction } from \"./makeCursorFetchFunction\";\nimport { NORMAL, SUSPENSE } from \"./type\";\n\n//! ================ Function overloads ================\n\n/**\n * 创建统一的无限查询 Hook(Suspense 模式)\n *\n * 这是一个高阶函数工厂,用于创建支持无限滚动的数据查询 Hook。\n * 它自动处理分页、缓存、错误重试等常见场景,并支持 Suspense 模式。\n *\n * @template T - 数据项类型\n * @template F - 过滤器对象类型,必须是对象类型,默认为 Record<string, unknown>\n *\n * @param {Function} fetchRemote - 远程数据获取函数,接收分页参数和过滤器,返回 Promise\n * @param {string} mode - 查询模式,设置为 \"suspense\" 启用 React Suspense 支持\n * @param {number} [pageSize=20] - 每页数据条数,默认 20\n * @param {Function} [postProcess] - 可选的数据后处理函数,在数据返回后调用\n *\n * @returns {Function} 返回一个 Hook 函数,接收 queryKey、filter 和 options 参数\n *\n * @example\n * ```tsx\n * * 定义 API 获取函数\n * const fetchProducts = async (params: FetchListParams<ProductFilter>) => {\n * const { items, total } = await api.getProducts(params);\n * return { items, total };\n * };\n *\n * * 创建 Hook(Suspense 模式)\n * const useProductList = makeUnifiedInfiniteQuery(\n * fetchProducts,\n * \"suspense\",\n * 20,\n * (data) => console.warn('数据已加载:', data.length)\n * );\n *\n * * 在组件中使用\n * function ProductList() {\n * const { data, fetchNextPage, hasNextPage } = useProductList(\n * [\"products\"],\n * { category: \"electronics\" },\n * { staleTime: 60000 }\n * );\n *\n * return (\n * <div>\n * {data.map(product => <ProductCard key={product.id} {...product} />)}\n * {hasNextPage && <button onClick={() => fetchNextPage()}>加载更多</button>}\n * </div>\n * );\n * }\n * ```\n *\n * @remarks\n * **为什么需要这个函数?**\n * - React Query 的无限查询 API 较为底层,需要手动配置 queryFn、initialPageParam、getNextPageParam 等\n * - 大多数列表查询都有相似的分页逻辑(offset/limit),重复编写这些配置容易出错\n * - 通过工厂函数统一封装,确保分页逻辑的一致性,减少样板代码\n *\n * **为什么区分 Suspense 和普通模式?**\n * - Suspense 模式:数据未就绪时会挂起组件渲染,适合配合 React Suspense 边界使用\n * - 普通模式:提供 isLoading 状态,需要手动处理加载状态,更灵活\n * - 两种模式的 Hook 返回类型不同,TypeScript 需要通过函数重载区分\n *\n * **内部实现原理:**\n * 1. **游标转换**:使用 makeCursorFetchFunction 将 offset/limit 转换为页码游标\n * 2. **查询键构造**:自动将 filter 合并到 queryKey 中,确保不同过滤条件有独立缓存\n * 3. **数据扁平化**:通过 select 将分页数据 pages 扁平化为单一数组,简化组件使用\n * 4. **智能重试**:仅对 5xx 服务器错误和网络错误重试,避免对 4xx 客户端错误无意义重试\n * 5. **选项合并**:使用 spread 运算符允许外部覆盖默认配置(如 staleTime、retry)\n */\nfunction makeUnifiedInfiniteQuery<T, F extends object = Record<string, unknown>>(\n fetchRemote: (params: FetchNumberListParams<F>) => Promise<ListDTOWithTotalNumber<T>>,\n mode: \"suspense\",\n pageSize?: number,\n postProcess?: (data: T[]) => void,\n): (queryKey: QueryKey, filter?: F, options?: SuspenseInfiniteQueryOptions<T>) => UseSuspenseInfiniteQueryResult<T[], AxiosError>;\n\n/**\n * 创建统一的无限查询 Hook(普通模式)\n *\n * 这是一个高阶函数工厂,用于创建支持无限滚动的数据查询 Hook。\n * 它自动处理分页、缓存、错误重试等常见场景,普通模式不使用 Suspense。\n *\n * @template T - 数据项类型\n * @template F - 过滤器对象类型,必须是对象类型,默认为 Record<string, unknown>\n *\n * @param {Function} fetchRemote - 远程数据获取函数,接收分页参数和过滤器,返回 Promise\n * @param {string} [mode=\"normal\"] - 查询模式,设置为 \"normal\" 或省略使用普通模式\n * @param {number} [pageSize=20] - 每页数据条数,默认 20\n * @param {Function} [postProcess] - 可选的数据后处理函数,在数据返回后调用\n *\n * @returns {Function} 返回一个 Hook 函数,接收 queryKey、filter 和 options 参数\n *\n * @example\n * ```tsx\n * * 定义 API 获取函数\n * const fetchProducts = async (params: FetchListParams<ProductFilter>) => {\n * const { items, total } = await api.getProducts(params);\n * return { items, total };\n * };\n *\n * * 创建 Hook(普通模式)\n * const useProductList = makeUnifiedInfiniteQuery(\n * fetchProducts,\n * \"normal\", * 或省略此参数\n * 20\n * );\n *\n * * 在组件中使用\n * function ProductList() {\n * const { data, fetchNextPage, hasNextPage, isLoading } = useProductList(\n * [\"products\"],\n * { category: \"electronics\" },\n * { staleTime: 60000 }\n * );\n *\n * if (isLoading) return <Loading />;\n *\n * return (\n * <div>\n * {data?.map(product => <ProductCard key={product.id} {...product} />)}\n * {hasNextPage && <button onClick={() => fetchNextPage()}>加载更多</button>}\n * </div>\n * );\n * }\n * ```\n */\nfunction makeUnifiedInfiniteQuery<T, F extends object = Record<string, unknown>>(\n fetchRemote: (params: FetchNumberListParams<F>) => Promise<ListDTOWithTotalNumber<T>>,\n mode?: \"normal\",\n pageSize?: number,\n postProcess?: (data: T[]) => void,\n): (queryKey: QueryKey, filter?: F, options?: InfiniteQueryOptions<T>) => UseInfiniteQueryResult<T[], AxiosError>;\n\n//! ================ Function implementation ================\nfunction makeUnifiedInfiniteQuery<T, F extends object = Record<string, unknown>>(\n fetchRemote: (params: FetchNumberListParams<F>) => Promise<ListDTOWithTotalNumber<T>>,\n mode: QueryMode = NORMAL,\n pageSize: number = 20,\n postProcess?: (data: T[]) => void,\n) {\n const fetchFunction = makeCursorFetchFunction(fetchRemote, pageSize, postProcess);\n if (mode === SUSPENSE) {\n return (queryKey: QueryKey, filter?: F, options?: SuspenseInfiniteQueryOptions<T>) =>\n useCreateSuspenseInfiniteQuery(queryKey, fetchFunction, filter, options, pageSize);\n }\n return (queryKey: QueryKey, filter?: F, options?: InfiniteQueryOptions<T>) =>\n useCreateNormalInfiniteQuery(queryKey, fetchFunction, filter, options, pageSize);\n}\n\nexport { makeUnifiedInfiniteQuery };\n\n//! ================ Private Function ================\n\nfunction buildCommonOptions<T, F extends object = Record<string, unknown>>(\n queryKey: QueryKey,\n fetchFunction: (pageParam: number, filter?: F) => Promise<ListDTOWithTotalNumber<T>>,\n filter?: F,\n options?: InfiniteQueryOptionsUnion<T>,\n pageSize?: number,\n) {\n return {\n // eslint-disable-next-line @tanstack/query/exhaustive-deps\n queryKey: filter !== undefined ? [...queryKey, filter] : queryKey,\n queryFn: ({ pageParam }: { pageParam: number }) => fetchFunction(pageParam, filter || ({} as F)),\n initialPageParam: 0,\n getNextPageParam: (lastPage: ListDTOWithTotalNumber<T>, allPages: ListDTOWithTotalNumber<T>[]) =>\n pageSize != null && allPages.length * pageSize < lastPage.total ? allPages.length : undefined,\n select: (d: InfiniteData<ListDTOWithTotalNumber<T>>) => d.pages.flatMap((p) => p.items),\n retry: (failureCount: number, error: AxiosError) => {\n const transient = (error?.status && error.status >= 500) || error?.code === \"NETWORK_ERROR\";\n const retryMax = typeof options?.retry === \"number\" ? options.retry : 3;\n return transient && failureCount < retryMax;\n },\n ...(options as Partial<ReturnType<typeof useInfiniteQuery>>),\n };\n}\n\nfunction useCreateNormalInfiniteQuery<T, F extends object = Record<string, unknown>>(\n queryKey: QueryKey,\n fetchFunction: (pageParam: number, filter?: F) => Promise<ListDTOWithTotalNumber<T>>,\n filter?: F,\n options?: InfiniteQueryOptions<T>,\n pageSize?: number,\n) {\n const common = useMemo(() => buildCommonOptions(queryKey, fetchFunction, filter, options, pageSize), [queryKey, fetchFunction, filter, options, pageSize]);\n return useInfiniteQuery(common);\n}\n\nfunction useCreateSuspenseInfiniteQuery<T, F extends object = Record<string, unknown>>(\n queryKey: QueryKey,\n fetchFunction: (pageParam: number, filter?: F) => Promise<ListDTOWithTotalNumber<T>>,\n filter?: F,\n options?: SuspenseInfiniteQueryOptions<T>,\n pageSize?: number,\n) {\n const common = useMemo(() => buildCommonOptions(queryKey, fetchFunction, filter, options, pageSize), [queryKey, fetchFunction, filter, options, pageSize]);\n return useSuspenseInfiniteQuery(common);\n}\n","import type { QueryKey, UseQueryOptions, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult } from \"@tanstack/react-query\";\nimport type { AxiosError } from \"axios\";\nimport type { QueryMode } from \"./type\";\n\nimport { useMemo } from \"react\";\nimport { useQuery, useSuspenseQuery } from \"@tanstack/react-query\";\n\nimport { NORMAL } from \"./type\";\n\ntype QueryOptions<T> = Omit<UseQueryOptions<T, AxiosError, T>, \"queryKey\" | \"queryFn\">;\ntype SuspenseQueryOptions<T> = Omit<UseSuspenseQueryOptions<T, AxiosError, T>, \"queryKey\" | \"queryFn\">;\n\n/**\n * 创建统一的单条查询 Hook 工厂(支持 normal / suspense 模式)。\n * Creates a unified single-item query Hook factory (normal or suspense mode).\n *\n * @param fetchRemote - 拉取函数,接收 filter 返回 Promise<T>。Fetch function (params: F) => Promise<T>.\n * @param mode - \"suspense\" 或 \"normal\"(默认)。Query mode.\n * @param postProcess - 可选,数据返回后调用。Optional post-process (data: T) => void.\n * @returns 返回一个 Hook:(queryKey, filter?, options?) => UseQueryResult 或 UseSuspenseQueryResult。Returns a Hook.\n * @example\n * ```ts\n * const useProfile = makeUnifiedQuery(fetchProfile, \"normal\");\n * const { data } = useProfile(profileKey, { id }, { enabled: !!id });\n * ```\n */\n// ------------------ Overload Signatures ------------------\nfunction makeUnifiedQuery<T, F extends object = Record<string, unknown>>(\n fetchRemote: (params: F) => Promise<T>,\n mode: \"suspense\",\n postProcess?: (data: T) => void,\n): (queryKey: QueryKey, filter?: F, options?: Omit<UseSuspenseQueryOptions<T, AxiosError, T>, \"queryKey\" | \"queryFn\">) => UseSuspenseQueryResult<T, AxiosError>;\n\nfunction makeUnifiedQuery<T, F extends object = Record<string, unknown>>(\n fetchRemote: (params: F) => Promise<T>,\n mode?: \"normal\",\n postProcess?: (data: T) => void,\n): (queryKey: QueryKey, filter?: F, options?: Omit<UseQueryOptions<T, AxiosError, T>, \"queryKey\" | \"queryFn\">) => UseQueryResult<T, AxiosError>;\n\n// ------------------ Implementation ------------------\nfunction makeUnifiedQuery<T, F extends object = Record<string, unknown>>(\n fetchRemote: (params: F) => Promise<T>,\n mode: QueryMode = NORMAL,\n postProcess?: (data: T) => void,\n) {\n const fetchFunction = async (filter: F): Promise<T> => {\n const data = await fetchRemote(filter);\n postProcess?.(data);\n return data;\n };\n\n const buildCommonOptions = (queryKey: QueryKey, filter?: F, options?: QueryOptions<T> | SuspenseQueryOptions<T>) => {\n return {\n queryKey: filter !== undefined ? [...queryKey, filter] : queryKey,\n queryFn: () => fetchFunction(filter || ({} as F)),\n select: (data: T) => data,\n retry: (failureCount: number, error: AxiosError) => {\n const status = error?.status ?? error?.response?.status;\n const transient = (typeof status === \"number\" && status >= 500) || error?.code === \"NETWORK_ERROR\";\n const retryMax = typeof options?.retry === \"number\" ? options.retry : 3;\n return transient && failureCount < retryMax;\n },\n ...(options as object),\n };\n };\n\n // Normal Query\n function useQueryNormal(queryKey: QueryKey, filter?: F, options?: QueryOptions<T>): UseQueryResult<T, AxiosError> {\n const common = useMemo(() => buildCommonOptions(queryKey, filter, options), [queryKey, filter, options]);\n return useQuery(common);\n }\n\n // Suspense Query\n function useQuerySuspense(queryKey: QueryKey, filter?: F, options?: SuspenseQueryOptions<T>): UseSuspenseQueryResult<T, AxiosError> {\n const common = useMemo(() => buildCommonOptions(queryKey, filter, options), [queryKey, filter, options]);\n return useSuspenseQuery(common);\n }\n\n if (mode === \"suspense\") {\n return (queryKey: QueryKey, filter?: F, options?: SuspenseQueryOptions<T>) => useQuerySuspense(queryKey, filter, options);\n }\n return (queryKey: QueryKey, filter?: F, options?: QueryOptions<T>) => useQueryNormal(queryKey, filter, options);\n}\n\nexport { makeUnifiedQuery };\n"],"mappings":"2KAmEA,SAAS,EACP,EACA,EAAmB,GACnB,EACA,CACA,MAAO,OAAO,EAAoB,EAAG,IAAmD,CAMtF,KAAM,CAAE,MAAA,EAAO,MAAA,CAAA,EAAU,MAAM,EALf,CACd,GAAG,EACH,OAAQ,EAAY,EACpB,MAAO,EACR,EAED,OAAI,GAAO,QAAQ,IAAc,CAAA,EAC1B,CAAE,MAAA,EAAO,MAAA,IAmBpB,SAAS,EACP,EACA,EAAmB,GACnB,EACA,CACA,MAAO,OAAO,EAAoB,GAAI,IAAkD,CAMtF,KAAM,CAAE,MAAA,EAAO,WAAA,CAAA,EAAe,MAAM,EALpB,CACd,GAAG,EACH,OAAQ,EACR,MAAO,EACR,EAED,OAAI,GAAO,QAAQ,IAAc,CAAA,EAC1B,CAAE,MAAA,EAAO,WAAA,ICrGpB,IAAM,EAAS,SAGT,EAAW,WCmIjB,SAAS,EACP,EACA,EAAkB,EAClB,EAAmB,GACnB,EACA,CACA,MAAM,EAAgB,EAAwB,EAAa,EAAU,CAAA,EACrE,OAAI,IAAA,WACF,CAAQ,EAAoB,EAAY,IACtC,EAA+B,EAAU,EAAe,EAAQ,EAAS,CAAA,EAE7E,CAAQ,EAAoB,EAAY,IACtC,EAA6B,EAAU,EAAe,EAAQ,EAAS,CAAA,EAO3E,SAAS,EACP,EACA,EACA,EACA,EACA,EACA,CACA,MAAO,CAEL,SAAU,IAAW,OAAY,CAAC,GAAG,EAAU,CAAA,EAAU,EACzD,QAAA,CAAU,CAAE,UAAA,CAAA,IAAuC,EAAc,EAAW,GAAW,CAAA,CAAE,EACzF,iBAAkB,EAClB,iBAAA,CAAmB,EAAqC,IACtD,GAAY,MAAQ,EAAS,OAAS,EAAW,EAAS,MAAQ,EAAS,OAAS,OACtF,OAAS,GAA+C,EAAE,MAAM,QAAS,GAAM,EAAE,KAAA,EACjF,MAAA,CAAQ,EAAsB,IAAsB,CAClD,MAAM,EAAa,GAAO,QAAU,EAAM,QAAU,KAAQ,GAAO,OAAS,gBACtE,EAAW,OAAO,GAAS,OAAU,SAAW,EAAQ,MAAQ,EACtE,OAAO,GAAa,EAAe,GAErC,GAAI,GAIR,SAAS,EACP,EACA,EACA,EACA,EACA,EACA,CAEA,SAAA,EAAA,qBAAA,EAAA,SAAA,IAD6B,EAAmB,EAAU,EAAe,EAAQ,EAAS,CAAA,EAAW,CAAC,EAAU,EAAe,EAAQ,EAAS,EAAS,CAAC,EAI5J,SAAS,EACP,EACA,EACA,EACA,EACA,EACA,CAEA,SAAA,EAAA,6BAAA,EAAA,SAAA,IAD6B,EAAmB,EAAU,EAAe,EAAQ,EAAS,CAAA,EAAW,CAAC,EAAU,EAAe,EAAQ,EAAS,EAAS,CAAC,ECtK5J,SAAS,EACP,EACA,EAAkB,EAClB,EACA,CACA,MAAM,EAAgB,MAAO,GAA0B,CACrD,MAAM,EAAO,MAAM,EAAY,CAAA,EAC/B,OAAA,IAAc,CAAA,EACP,GAGH,EAAA,CAAsB,EAAoB,EAAY,KACnD,CACL,SAAU,IAAW,OAAY,CAAC,GAAG,EAAU,CAAA,EAAU,EACzD,QAAA,IAAe,EAAc,GAAW,CAAA,CAAE,EAC1C,OAAS,GAAY,EACrB,MAAA,CAAQ,EAAsB,IAAsB,CAClD,MAAM,EAAS,GAAO,QAAU,GAAO,UAAU,OAC3C,EAAa,OAAO,GAAW,UAAY,GAAU,KAAQ,GAAO,OAAS,gBAC7E,EAAW,OAAO,GAAS,OAAU,SAAW,EAAQ,MAAQ,EACtE,OAAO,GAAa,EAAe,GAErC,GAAI,IAKR,SAAS,EAAe,EAAoB,EAAY,EAA0D,CAEhH,SAAA,EAAA,aAAA,EAAA,SAAA,IAD6B,EAAmB,EAAU,EAAQ,CAAA,EAAU,CAAC,EAAU,EAAQ,EAAQ,CAAC,EAK1G,SAAS,EAAiB,EAAoB,EAAY,EAA0E,CAElI,SAAA,EAAA,qBAAA,EAAA,SAAA,IAD6B,EAAmB,EAAU,EAAQ,CAAA,EAAU,CAAC,EAAU,EAAQ,EAAQ,CAAC,EAI1G,OAAI,IAAS,WACX,CAAQ,EAAoB,EAAY,IAAsC,EAAiB,EAAU,EAAQ,CAAA,EAEnH,CAAQ,EAAoB,EAAY,IAA8B,EAAe,EAAU,EAAQ,CAAA"}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { AxiosError } from 'axios';
|
|
2
|
+
import { QueryKey } from '@tanstack/react-query';
|
|
3
|
+
import { UseInfiniteQueryOptions } from '@tanstack/react-query';
|
|
4
|
+
import { UseInfiniteQueryResult } from '@tanstack/react-query';
|
|
5
|
+
import { UseQueryOptions } from '@tanstack/react-query';
|
|
6
|
+
import { UseQueryResult } from '@tanstack/react-query';
|
|
7
|
+
import { UseSuspenseInfiniteQueryOptions } from '@tanstack/react-query';
|
|
8
|
+
import { UseSuspenseInfiniteQueryResult } from '@tanstack/react-query';
|
|
9
|
+
import { UseSuspenseQueryOptions } from '@tanstack/react-query';
|
|
10
|
+
import { UseSuspenseQueryResult } from '@tanstack/react-query';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 数组类型。Array type.
|
|
14
|
+
* @example Array<string> => string[]
|
|
15
|
+
*/
|
|
16
|
+
declare type Array_2<T> = T[];
|
|
17
|
+
|
|
18
|
+
/** F & OffsetLimitNumber,数字分页列表请求参数。Params for number-offset list fetch. */
|
|
19
|
+
export declare type FetchNumberListParams<F extends object = Record<string, unknown>> = F & OffsetLimitNumber;
|
|
20
|
+
|
|
21
|
+
/** F & OffsetLimitString,字符串游标列表请求参数。Params for string-cursor list fetch. */
|
|
22
|
+
export declare type FetchStringListParams<F extends object = Record<string, unknown>> = F & OffsetLimitString;
|
|
23
|
+
|
|
24
|
+
/** 无限查询 options(不含 queryKey/queryFn/getNextPageParam/initialPageParam)。Infinite query options (excludes queryKey, queryFn, getNextPageParam, initialPageParam). */
|
|
25
|
+
export declare type InfiniteQueryOptions<T> = Omit<UseInfiniteQueryOptions<ListDTOWithTotalNumber<T>, AxiosError, T[]>, "queryKey" | "queryFn" | "getNextPageParam" | "initialPageParam">;
|
|
26
|
+
|
|
27
|
+
/** InfiniteQueryOptions | SuspenseInfiniteQueryOptions。Union of normal and suspense infinite query options. */
|
|
28
|
+
export declare type InfiniteQueryOptionsUnion<T> = InfiniteQueryOptions<T> | SuspenseInfiniteQueryOptions<T>;
|
|
29
|
+
|
|
30
|
+
/** 字符串游标列表:items + nextCursor(用于 nextCursor 为 string 的 API)。List with string nextCursor. */
|
|
31
|
+
declare interface ListDTOWithNextCursor<T> {
|
|
32
|
+
/** 列表项。Items. */
|
|
33
|
+
items: Array_2<T>;
|
|
34
|
+
/** 下一页游标。Next cursor. */
|
|
35
|
+
nextCursor: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** 列表 + 总数:items + total(用于 offset/limit 分页的返回)。List with total count; used as offset/limit response. */
|
|
39
|
+
declare interface ListDTOWithTotalNumber<T> {
|
|
40
|
+
/** 列表项。Items. */
|
|
41
|
+
items: Array_2<T>;
|
|
42
|
+
/** 总数。Total count. */
|
|
43
|
+
total: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 创建基于游标(Cursor)的分页获取函数
|
|
48
|
+
*
|
|
49
|
+
* 将标准的分页 API(基于 offset/limit)转换为游标分页函数,用于无限查询。
|
|
50
|
+
* 自动计算下一页游标,并支持数据后处理。
|
|
51
|
+
*
|
|
52
|
+
* @template T - 数据项类型
|
|
53
|
+
* @template F - 过滤器对象类型,必须是对象类型,默认为 Record<string, unknown>
|
|
54
|
+
*
|
|
55
|
+
* @param {Function} fetchFunc - 远程数据获取函数,接收 FetchListParams 参数,返回包含 items 和 total 的结果
|
|
56
|
+
* @param {number} [pageSize=20] - 每页数据条数,默认 20
|
|
57
|
+
* @param {Function} [postProcess] - 可选的数据后处理函数,在每次数据获取后调用
|
|
58
|
+
*
|
|
59
|
+
* @returns {Function} 返回一个游标分页函数,接收 pageParam(页码)和 filter(过滤器)参数
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```tsx
|
|
63
|
+
* * 定义标准的分页 API
|
|
64
|
+
* const fetchProductsAPI = async (params: { offset: number; limit: number; category?: string }) => {
|
|
65
|
+
* const response = await fetch('/api/products?' + new URLSearchParams(params));
|
|
66
|
+
* const { items, total } = await response.json();
|
|
67
|
+
* return { items, total };
|
|
68
|
+
* };
|
|
69
|
+
*
|
|
70
|
+
* * 创建游标分页函数
|
|
71
|
+
* const fetchProducts = makeCursorFetchFunction(
|
|
72
|
+
* fetchProductsAPI,
|
|
73
|
+
* 20,
|
|
74
|
+
* (data) => {
|
|
75
|
+
* * 数据后处理:为每个商品添加缓存
|
|
76
|
+
* data.forEach(product => cache.set(product.id, product));
|
|
77
|
+
* }
|
|
78
|
+
* );
|
|
79
|
+
*
|
|
80
|
+
* * 使用游标函数
|
|
81
|
+
* const firstPage = await fetchProducts(0, { category: "electronics" });
|
|
82
|
+
* * 返回: ListDTOWithTotalNumber<Product> = { items, total }
|
|
83
|
+
* * getNextPageParam 由 makeUnifiedInfiniteQuery 根据 total 与 pageSize 计算
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @remarks
|
|
87
|
+
* **为什么需要游标转换?**
|
|
88
|
+
* - React Query 的无限查询使用 pageParam(游标)来跟踪分页位置
|
|
89
|
+
* - 后端 API 通常使用 offset/limit 分页,两者需要转换才能配合使用
|
|
90
|
+
* - 游标模式更适合无限滚动,避免在组件中手动计算 offset
|
|
91
|
+
*
|
|
92
|
+
* **游标计算逻辑:**
|
|
93
|
+
* - **offset 计算**:`offset = pageParam × pageSize`
|
|
94
|
+
* - 示例:pageParam=0 → offset=0(第一页)
|
|
95
|
+
* - 示例:pageParam=2, pageSize=20 → offset=40(第三页,跳过前 40 条)
|
|
96
|
+
* - **nextCursor 判断**:`(pageParam + 1) × pageSize < total ? pageParam + 1 : undefined`
|
|
97
|
+
* - 如果下一页的起始位置小于总数,返回下一页页码
|
|
98
|
+
* - 否则返回 undefined,告知 React Query 没有更多数据
|
|
99
|
+
*
|
|
100
|
+
* **为什么 pageParam 从 0 开始?**
|
|
101
|
+
* - 符合数组索引习惯,第 0 页、第 1 页...
|
|
102
|
+
* - 计算 offset 时公式更简洁:`offset = pageParam × pageSize`
|
|
103
|
+
* - 避免使用 1-based 索引时需要额外的 -1 运算
|
|
104
|
+
*
|
|
105
|
+
* **postProcess 的作用:**
|
|
106
|
+
* - 在数据返回后、缓存前执行,适合进行副作用操作
|
|
107
|
+
* - 常见用途:更新单项缓存、触发分析事件、数据预处理
|
|
108
|
+
* - 不影响返回值,保持数据流的纯净性
|
|
109
|
+
*/
|
|
110
|
+
export declare function makeCursorFetchFunction<T, F extends object = Record<string, unknown>>(fetchFunc: (params: FetchNumberListParams<F>) => Promise<ListDTOWithTotalNumber<T>>, pageSize?: number, postProcess?: (data: T[]) => void): (pageParam?: number, filter?: F) => Promise<ListDTOWithTotalNumber<T>>;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 创建基于字符串游标的分页获取函数(用于 nextCursor 为 string 的 API)。
|
|
114
|
+
* Creates cursor-based fetch function for string cursor (API returns nextCursor: string).
|
|
115
|
+
*
|
|
116
|
+
* @param fetchFunc - 远程获取函数,参数含 offset: string, limit,返回 { items, nextCursor }。Fetch (params: FetchStringListParams<F>) => Promise<ListDTOWithNextCursor<T>>.
|
|
117
|
+
* @param pageSize - 每页条数,默认 20。Page size.
|
|
118
|
+
* @param postProcess - 可选,数据返回后调用。Optional post-process (data: T[]) => void.
|
|
119
|
+
* @returns 返回 (pageParam: string, filter?: F) => Promise<ListDTOWithNextCursor<T>>。Returns async cursor fetcher.
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* const fetch = makeStringCursorFetchFunction(fetchByToken, 20);
|
|
123
|
+
* const page = await fetch("", { q: "x" });
|
|
124
|
+
* if (page.nextCursor) await fetch(page.nextCursor, { q: "x" });
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export declare function makeStringCursorFetchFunction<T, F extends object = Record<string, unknown>>(fetchFunc: (params: FetchStringListParams<F>) => Promise<ListDTOWithNextCursor<T>>, pageSize?: number, postProcess?: (data: T[]) => void): (pageParam?: string, filter?: F) => Promise<ListDTOWithNextCursor<T>>;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 创建统一的无限查询 Hook(Suspense 模式)
|
|
131
|
+
*
|
|
132
|
+
* 这是一个高阶函数工厂,用于创建支持无限滚动的数据查询 Hook。
|
|
133
|
+
* 它自动处理分页、缓存、错误重试等常见场景,并支持 Suspense 模式。
|
|
134
|
+
*
|
|
135
|
+
* @template T - 数据项类型
|
|
136
|
+
* @template F - 过滤器对象类型,必须是对象类型,默认为 Record<string, unknown>
|
|
137
|
+
*
|
|
138
|
+
* @param {Function} fetchRemote - 远程数据获取函数,接收分页参数和过滤器,返回 Promise
|
|
139
|
+
* @param {string} mode - 查询模式,设置为 "suspense" 启用 React Suspense 支持
|
|
140
|
+
* @param {number} [pageSize=20] - 每页数据条数,默认 20
|
|
141
|
+
* @param {Function} [postProcess] - 可选的数据后处理函数,在数据返回后调用
|
|
142
|
+
*
|
|
143
|
+
* @returns {Function} 返回一个 Hook 函数,接收 queryKey、filter 和 options 参数
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```tsx
|
|
147
|
+
* * 定义 API 获取函数
|
|
148
|
+
* const fetchProducts = async (params: FetchListParams<ProductFilter>) => {
|
|
149
|
+
* const { items, total } = await api.getProducts(params);
|
|
150
|
+
* return { items, total };
|
|
151
|
+
* };
|
|
152
|
+
*
|
|
153
|
+
* * 创建 Hook(Suspense 模式)
|
|
154
|
+
* const useProductList = makeUnifiedInfiniteQuery(
|
|
155
|
+
* fetchProducts,
|
|
156
|
+
* "suspense",
|
|
157
|
+
* 20,
|
|
158
|
+
* (data) => console.warn('数据已加载:', data.length)
|
|
159
|
+
* );
|
|
160
|
+
*
|
|
161
|
+
* * 在组件中使用
|
|
162
|
+
* function ProductList() {
|
|
163
|
+
* const { data, fetchNextPage, hasNextPage } = useProductList(
|
|
164
|
+
* ["products"],
|
|
165
|
+
* { category: "electronics" },
|
|
166
|
+
* { staleTime: 60000 }
|
|
167
|
+
* );
|
|
168
|
+
*
|
|
169
|
+
* return (
|
|
170
|
+
* <div>
|
|
171
|
+
* {data.map(product => <ProductCard key={product.id} {...product} />)}
|
|
172
|
+
* {hasNextPage && <button onClick={() => fetchNextPage()}>加载更多</button>}
|
|
173
|
+
* </div>
|
|
174
|
+
* );
|
|
175
|
+
* }
|
|
176
|
+
* ```
|
|
177
|
+
*
|
|
178
|
+
* @remarks
|
|
179
|
+
* **为什么需要这个函数?**
|
|
180
|
+
* - React Query 的无限查询 API 较为底层,需要手动配置 queryFn、initialPageParam、getNextPageParam 等
|
|
181
|
+
* - 大多数列表查询都有相似的分页逻辑(offset/limit),重复编写这些配置容易出错
|
|
182
|
+
* - 通过工厂函数统一封装,确保分页逻辑的一致性,减少样板代码
|
|
183
|
+
*
|
|
184
|
+
* **为什么区分 Suspense 和普通模式?**
|
|
185
|
+
* - Suspense 模式:数据未就绪时会挂起组件渲染,适合配合 React Suspense 边界使用
|
|
186
|
+
* - 普通模式:提供 isLoading 状态,需要手动处理加载状态,更灵活
|
|
187
|
+
* - 两种模式的 Hook 返回类型不同,TypeScript 需要通过函数重载区分
|
|
188
|
+
*
|
|
189
|
+
* **内部实现原理:**
|
|
190
|
+
* 1. **游标转换**:使用 makeCursorFetchFunction 将 offset/limit 转换为页码游标
|
|
191
|
+
* 2. **查询键构造**:自动将 filter 合并到 queryKey 中,确保不同过滤条件有独立缓存
|
|
192
|
+
* 3. **数据扁平化**:通过 select 将分页数据 pages 扁平化为单一数组,简化组件使用
|
|
193
|
+
* 4. **智能重试**:仅对 5xx 服务器错误和网络错误重试,避免对 4xx 客户端错误无意义重试
|
|
194
|
+
* 5. **选项合并**:使用 spread 运算符允许外部覆盖默认配置(如 staleTime、retry)
|
|
195
|
+
*/
|
|
196
|
+
export declare function makeUnifiedInfiniteQuery<T, F extends object = Record<string, unknown>>(fetchRemote: (params: FetchNumberListParams<F>) => Promise<ListDTOWithTotalNumber<T>>, mode: "suspense", pageSize?: number, postProcess?: (data: T[]) => void): (queryKey: QueryKey, filter?: F, options?: SuspenseInfiniteQueryOptions<T>) => UseSuspenseInfiniteQueryResult<T[], AxiosError>;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 创建统一的无限查询 Hook(普通模式)
|
|
200
|
+
*
|
|
201
|
+
* 这是一个高阶函数工厂,用于创建支持无限滚动的数据查询 Hook。
|
|
202
|
+
* 它自动处理分页、缓存、错误重试等常见场景,普通模式不使用 Suspense。
|
|
203
|
+
*
|
|
204
|
+
* @template T - 数据项类型
|
|
205
|
+
* @template F - 过滤器对象类型,必须是对象类型,默认为 Record<string, unknown>
|
|
206
|
+
*
|
|
207
|
+
* @param {Function} fetchRemote - 远程数据获取函数,接收分页参数和过滤器,返回 Promise
|
|
208
|
+
* @param {string} [mode="normal"] - 查询模式,设置为 "normal" 或省略使用普通模式
|
|
209
|
+
* @param {number} [pageSize=20] - 每页数据条数,默认 20
|
|
210
|
+
* @param {Function} [postProcess] - 可选的数据后处理函数,在数据返回后调用
|
|
211
|
+
*
|
|
212
|
+
* @returns {Function} 返回一个 Hook 函数,接收 queryKey、filter 和 options 参数
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```tsx
|
|
216
|
+
* * 定义 API 获取函数
|
|
217
|
+
* const fetchProducts = async (params: FetchListParams<ProductFilter>) => {
|
|
218
|
+
* const { items, total } = await api.getProducts(params);
|
|
219
|
+
* return { items, total };
|
|
220
|
+
* };
|
|
221
|
+
*
|
|
222
|
+
* * 创建 Hook(普通模式)
|
|
223
|
+
* const useProductList = makeUnifiedInfiniteQuery(
|
|
224
|
+
* fetchProducts,
|
|
225
|
+
* "normal", * 或省略此参数
|
|
226
|
+
* 20
|
|
227
|
+
* );
|
|
228
|
+
*
|
|
229
|
+
* * 在组件中使用
|
|
230
|
+
* function ProductList() {
|
|
231
|
+
* const { data, fetchNextPage, hasNextPage, isLoading } = useProductList(
|
|
232
|
+
* ["products"],
|
|
233
|
+
* { category: "electronics" },
|
|
234
|
+
* { staleTime: 60000 }
|
|
235
|
+
* );
|
|
236
|
+
*
|
|
237
|
+
* if (isLoading) return <Loading />;
|
|
238
|
+
*
|
|
239
|
+
* return (
|
|
240
|
+
* <div>
|
|
241
|
+
* {data?.map(product => <ProductCard key={product.id} {...product} />)}
|
|
242
|
+
* {hasNextPage && <button onClick={() => fetchNextPage()}>加载更多</button>}
|
|
243
|
+
* </div>
|
|
244
|
+
* );
|
|
245
|
+
* }
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
export declare function makeUnifiedInfiniteQuery<T, F extends object = Record<string, unknown>>(fetchRemote: (params: FetchNumberListParams<F>) => Promise<ListDTOWithTotalNumber<T>>, mode?: "normal", pageSize?: number, postProcess?: (data: T[]) => void): (queryKey: QueryKey, filter?: F, options?: InfiniteQueryOptions<T>) => UseInfiniteQueryResult<T[], AxiosError>;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* 创建统一的单条查询 Hook 工厂(支持 normal / suspense 模式)。
|
|
252
|
+
* Creates a unified single-item query Hook factory (normal or suspense mode).
|
|
253
|
+
*
|
|
254
|
+
* @param fetchRemote - 拉取函数,接收 filter 返回 Promise<T>。Fetch function (params: F) => Promise<T>.
|
|
255
|
+
* @param mode - "suspense" 或 "normal"(默认)。Query mode.
|
|
256
|
+
* @param postProcess - 可选,数据返回后调用。Optional post-process (data: T) => void.
|
|
257
|
+
* @returns 返回一个 Hook:(queryKey, filter?, options?) => UseQueryResult 或 UseSuspenseQueryResult。Returns a Hook.
|
|
258
|
+
* @example
|
|
259
|
+
* ```ts
|
|
260
|
+
* const useProfile = makeUnifiedQuery(fetchProfile, "normal");
|
|
261
|
+
* const { data } = useProfile(profileKey, { id }, { enabled: !!id });
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
export declare function makeUnifiedQuery<T, F extends object = Record<string, unknown>>(fetchRemote: (params: F) => Promise<T>, mode: "suspense", postProcess?: (data: T) => void): (queryKey: QueryKey, filter?: F, options?: Omit<UseSuspenseQueryOptions<T, AxiosError, T>, "queryKey" | "queryFn">) => UseSuspenseQueryResult<T, AxiosError>;
|
|
265
|
+
|
|
266
|
+
export declare function makeUnifiedQuery<T, F extends object = Record<string, unknown>>(fetchRemote: (params: F) => Promise<T>, mode?: "normal", postProcess?: (data: T) => void): (queryKey: QueryKey, filter?: F, options?: Omit<UseQueryOptions<T, AxiosError, T>, "queryKey" | "queryFn">) => UseQueryResult<T, AxiosError>;
|
|
267
|
+
|
|
268
|
+
/** 变更上下文(如 prev)。Mutation context (e.g. prev). */
|
|
269
|
+
export declare type MutationCtx = {
|
|
270
|
+
prev?: unknown;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
/** 普通模式(useQuery),可配合 enabled 等。Normal mode (useQuery); supports enabled etc. */
|
|
274
|
+
export declare const NORMAL: "normal";
|
|
275
|
+
|
|
276
|
+
/** 普通单条查询 options(含 enabled)。Normal single-item query options (includes enabled). */
|
|
277
|
+
export declare type NormalUnifiedQueryOptions<T> = Omit<UseQueryOptions<T, AxiosError, T>, "queryKey" | "queryFn">;
|
|
278
|
+
|
|
279
|
+
/** 数字 offset 分页参数(用于 makeCursorFetchFunction 等)。Number offset pagination params; used by makeCursorFetchFunction etc. */
|
|
280
|
+
declare interface OffsetLimitNumber {
|
|
281
|
+
/** 偏移量。Offset. */
|
|
282
|
+
offset: number;
|
|
283
|
+
/** 每页条数。Limit. */
|
|
284
|
+
limit: number;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** 字符串游标分页参数(用于 makeStringCursorFetchFunction 等)。String cursor pagination params; used by makeStringCursorFetchFunction etc. */
|
|
288
|
+
declare interface OffsetLimitString {
|
|
289
|
+
/** 游标(字符串)。Cursor (string). */
|
|
290
|
+
offset: string;
|
|
291
|
+
/** 每页条数。Limit. */
|
|
292
|
+
limit: number;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** 仅允许 "normal" | "suspense",请使用 NORMAL / SUSPENSE 避免拼写错误。Only "normal" | "suspense"; use NORMAL / SUSPENSE to avoid typos. */
|
|
296
|
+
export declare type QueryMode = typeof NORMAL | typeof SUSPENSE;
|
|
297
|
+
|
|
298
|
+
/** 字符串游标无限查询 options。String-cursor infinite query options. */
|
|
299
|
+
export declare type StringInfiniteQueryOptions<T> = Omit<UseInfiniteQueryOptions<ListDTOWithNextCursor<T>, AxiosError, T[]>, "queryKey" | "queryFn" | "getNextPageParam" | "initialPageParam">;
|
|
300
|
+
|
|
301
|
+
/** Suspense 模式(useSuspenseQuery),由 React 挂起。Suspense mode (useSuspenseQuery); suspended by React. */
|
|
302
|
+
export declare const SUSPENSE: "suspense";
|
|
303
|
+
|
|
304
|
+
/** Suspense 无限查询 options。Suspense infinite query options. */
|
|
305
|
+
export declare type SuspenseInfiniteQueryOptions<T> = Omit<UseSuspenseInfiniteQueryOptions<ListDTOWithTotalNumber<T>, AxiosError, T[]>, "queryKey" | "queryFn" | "getNextPageParam" | "initialPageParam">;
|
|
306
|
+
|
|
307
|
+
/** 单条查询 Suspense options。Single-item suspense query options. */
|
|
308
|
+
export declare type SuspenseUnifiedQueryOptions<T> = Omit<UseSuspenseQueryOptions<T, AxiosError, T>, "queryKey" | "queryFn">;
|
|
309
|
+
|
|
310
|
+
/** 单条查询参数(options、postProcess + 业务参数)。Single-item query params (options, postProcess, and business params). */
|
|
311
|
+
export declare type UnifiedQueryParams<T> = {
|
|
312
|
+
options?: SuspenseUnifiedQueryOptions<T>;
|
|
313
|
+
postProcess?: (data: T) => void;
|
|
314
|
+
} & Record<string, unknown>;
|
|
315
|
+
|
|
316
|
+
export { }
|