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/utils.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 A=require("./chunk-chunk-BFrxaqQT.cjs"),m=require("./chunk-lstorage-BnxLXHgH.cjs");require("./chunk-types-BE3JCLff.cjs");const D=require("./chunk-i18n-_7W7guSV.cjs");let M=require("google-libphonenumber"),d=require("async-retry");d=A.__toESM(d);function N(t){return t.trim().replace(/\s+/g," ")}function h(t){const e=t?.response?.data;return!e||typeof e!="object"?null:{status:e.status,errCode:e.errCode,message:e.message,details:e.details,traceId:e.traceId}}function T(t,e){const r=h(t);if(r?.errCode){const o=D.i18n_default.t(`errors:${r.errCode}`);if(o&&o!==`errors:${r.errCode}`)return o}return r?.message?r.message:e}function R(t,e,r,o,n){if(e.length===0)return t;switch(n){case"insert":return C(t,e,r,o);case"upsert":return E(t,e,r,o)}}function C(t,e,r,o){const n=new Set(t.map(r)),s=e.filter(i=>{const a=r(i);return n.has(a)?!1:(n.add(a),!0)});return s.length===0?t:o==="prepend"?[...s,...t]:[...t,...s]}function E(t,e,r,o){const n=new Map;t.forEach((u,c)=>n.set(r(u),c));let s=!1;const i=t.slice();for(const u of e){const c=r(u),f=n.get(c);f!==void 0&&i[f]!==u&&(i[f]=u,s=!0)}const a=[];for(const u of e){const c=r(u);n.has(c)||a.push(u)}return a.length>0?(s=!0,o==="prepend"?[...a,...i]:[...i,...a]):s?i:t}function P(t,e,r){let o=!1;const n=t.filter(s=>{const i=!e.has(r(s));return i||(o=!0),i});return o?n:t}const k=(t,e)=>{const r=t.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/);if(r){const[,o,n,s]=r;return`rgba(${o}, ${n}, ${s}, ${e})`}return $(t,e)},q=(t,e)=>{if(t.startsWith("rgba"))return t;const r=t.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);if(r){const[,o,n,s]=r;return`rgba(${o}, ${n}, ${s}, ${e})`}return console.warn("Invalid RGB color format:",t),t},$=(t,e)=>{if(t.indexOf("rgb")!==-1)return t;let r=0,o=0,n=0;return t.startsWith("#")&&(t=t.slice(1)),t.length===3?(r=parseInt(t[0]+t[0],16),o=parseInt(t[1]+t[1],16),n=parseInt(t[2]+t[2],16)):t.length===6?(r=parseInt(t.slice(0,2),16),o=parseInt(t.slice(2,4),16),n=parseInt(t.slice(4,6),16)):console.warn("Unsupported HEX color format"),`rgba(${r}, ${o}, ${n}, ${e})`},B=(t,e,r)=>{const o=f=>{const l=f.match(/^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i);if(l)return[parseInt(l[1],16),parseInt(l[2],16),parseInt(l[3],16)];const g=f.match(/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/i);return g?[parseInt(g[1]),parseInt(g[2]),parseInt(g[3])]:[0,0,0]},[n,s,i]=o(t),[a,u,c]=o(e);return`rgb(${Math.round(n+(a-n)*r)}, ${Math.round(s+(u-s)*r)}, ${Math.round(i+(c-i)*r)})`},_=t=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t);function j(t){return typeof t=="string"?t:t==null?"":typeof t=="number"||typeof t=="boolean"?String(t):Array.isArray(t)?t.map(e=>String(e)).join(", "):typeof t=="object"?JSON.stringify(t):String(t)}function V(t){return t==null?"":typeof t=="number"?Number.isFinite(t)?String(t):"":typeof t=="string"?t:typeof t=="boolean"?t?"1":"0":Array.isArray(t)&&t.length>0?String(t[0]):""}function F(t,e,...r){const o={},n=Array.isArray(e)?e:[e,...r],s=new Set(n);for(const i of Object.keys(t))s.has(i)||(o[i]=t[i]);return o}var p=M.PhoneNumberUtil.getInstance();const U=t=>p.parseAndKeepRawInput(t).getCountryCode(),H=t=>{if(!t||!t.replace(/\D/g,"").length)return!1;try{const e=p.parseAndKeepRawInput(t);return p.isValidNumber(e)}catch{return!1}},b=t=>[t,null],I=t=>[null,t instanceof Error?t:new Error(String(t))];async function w(t,e){try{return b(await(0,d.default)(async(r,o)=>{try{return await t(r,o)}catch(n){throw e?.isNonRetryable?.(n)&&r(n),n}},e))}catch(r){return I(r)}}async function K(t,e,r){return w(async(o,n)=>{const s=await t();if(!e(s))throw new Error("Condition not satisfied");return s},r)}function O(t){return Math.round(Number(t)*100)}function S(t){return(Number(t)/100).toFixed(2)}function W(t){return Number(S(t))}function Y(t){return t<1e3?t.toString():t<1e6?`${(t/1e3).toFixed(1).replace(/\.0$/,"")}k+`:t<1e9?`${(t/1e6).toFixed(1).replace(/\.0$/,"")}M+`:`${(t/1e9).toFixed(1).replace(/\.0$/,"")}B+`}function G(t){let e=null;return async(...r)=>e||(e=t(...r).finally(()=>e=null),e)}function z(t,e){const r=new Map;return async(...o)=>{const n=e(...o),s=r.get(n);if(s)return s;const i=t(...o).finally(()=>r.delete(n));return r.set(n,i),i}}function y(t,e){if(Object.is(t,e))return!0;if(typeof t!=typeof e)return!1;if(t===null||e===null||typeof t!="object"||typeof e!="object")return t===e;const r=Array.isArray(t),o=Array.isArray(e);if(r!==o)return!1;if(r&&o)return t.length!==e.length?!1:t.every((i,a)=>y(i,e[a]));const n=Object.keys(t).sort(),s=Object.keys(e).sort();return n.length!==s.length||!n.every((i,a)=>i===s[a])?!1:n.every(i=>y(t[i],e[i]))}const J=t=>{let e,r=[];return new Proxy(t,{construct(o,n){if(e||(e=new t(...n),r=n),!y(n,r))throw new Error("Cannot create multiple instances with different parameters");return e}})};function x(t,e=100){if(t==null)throw new Promise(r=>setTimeout(r,e));return t}const L=t=>{if(!t)return"";const e=new Date(t);return isNaN(e.getTime())?"":`${e.getFullYear()}/${(e.getMonth()+1).toString().padStart(2,"0")}/${e.getDate().toString().padStart(2,"0")}`},X=t=>{if(!t)return"Unknown";const e=new Date(t);if(isNaN(e.getTime()))return"Invalid date";const r=new Date().getTime()-e.getTime(),o=Math.floor(r/1e3),n=Math.floor(o/60),s=Math.floor(n/60),i=Math.floor(s/24),a=Math.floor(i/30),u=Math.floor(i/365);return u>0?`${u} year${u>1?"s":""} ago`:a>0?`${a} month${a>1?"s":""} ago`:i>0?`${i} day${i>1?"s":""} ago`:s>0?`${s} hour${s>1?"s":""} ago`:n>0?`${n} minute${n>1?"s":""} ago`:"Just now"};function Q(t){try{return new Date(t).toLocaleDateString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return t}}const Z=t=>{try{const e=new Date(t);return isNaN(e.getTime())?t:`${e.getFullYear()}/${String(e.getMonth()+1).padStart(2,"0")}/${String(e.getDate()).padStart(2,"0")} ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}catch{return t}},v=t=>{try{const e=new Date(t);return isNaN(e.getTime())?t:`${String(e.getMonth()+1).padStart(2,"0")}/${String(e.getDate()).padStart(2,"0")} ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}catch{return t}},tt=t=>{try{const e=new Date(t);return isNaN(e.getTime())?t:`${e.getFullYear()}/${String(e.getMonth()+1).padStart(2,"0")}/${String(e.getDate()).padStart(2,"0")}`}catch{return t}},et=t=>{try{const e=new Date(t);return isNaN(e.getTime())?t:`${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`}catch{return t}};function rt(t,e){return t.reduce((r,o,n)=>(r[o]=e?e(o,n):o,r),{})}exports.createMap=rt;exports.err=I;exports.formatDate=tt;exports.formatDateTime=Z;exports.formatDisplayDate=L;exports.formatMonthDayTime=v;exports.formatNumberAbbreviated=Y;exports.formatRelativeTime=X;exports.formatTickDate=Q;exports.formatTime=et;exports.getApiError=h;exports.getApiErrorMessage=T;exports.getCountryCode=U;exports.getItem=m.getItem;exports.hexToRGBA=$;exports.interpolateColor=B;exports.isValidEmail=_;exports.isValidPhoneNumber=H;exports.mergeById=R;exports.normalizeAddress=N;exports.ok=b;exports.omit=F;exports.onceAsync=G;exports.onceAsyncByKey=z;exports.pollUntil=K;exports.pruneArray=P;exports.removeItem=m.removeItem;exports.rgbToRgba=q;exports.setItem=m.setItem;exports.singleton=J;exports.suspenseIfNull=x;exports.toDatabasePrice=O;exports.toDisplayPrice=S;exports.toDisplayPriceNumber=W;exports.toNumberInputValue=V;exports.toRgbaWithAlpha=k;exports.toTextInputValue=j;exports.withRetryResult=w;
|
|
4
|
+
|
|
5
|
+
//# sourceMappingURL=utils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.cjs","names":[],"sources":["../src/utils/address.ts","../src/utils/apiError.ts","../src/utils/array.ts","../src/utils/colors.ts","../src/utils/email.ts","../src/utils/form.ts","../src/utils/object.ts","../src/utils/phone.ts","../src/utils/result.ts","../src/utils/retry.ts","../src/utils/polling.ts","../src/utils/price.ts","../src/utils/promise.ts","../src/utils/singleton.ts","../src/utils/suspense.ts","../src/utils/time.ts","../src/utils/types.ts"],"sourcesContent":["/**\n * 规范化地址字符串:去除首尾空白并将连续空白合并为单个空格\n * Normalize address string: trim and collapse consecutive spaces to one.\n * @param address - 原始地址字符串\n * @returns 规范化后的地址\n */\nexport function normalizeAddress(address: string): string {\n return address.trim().replace(/\\s+/g, \" \");\n}\n","/**\n * 与约定一致:HTTP 错误经 fiberx.Error/ErrorFromErrx → httpx.BuildErrorResp,\n * 响应体固定为 { status, err_code, message, details?, trace_id? }(axios 转 camelCase)。\n * 前端只认「有 response.data」= 后端错误体;UI 展示与 NFX 一致:先 errors 命名空间(后端拉取),再 message,再 fallback。\n */\n\nimport type { AxiosError } from \"axios\";\nimport type { ApiErrorBody } from \"@/types/api\";\n\nimport i18n from \"@/languages/languages/i18n\";\n\n/**\n * 仅当为后端错误(有 response.data)时解析为 ApiErrorBody,否则返回 null\n * Parse to ApiErrorBody only when response.data exists; otherwise null.\n * @param error - 通常为 Axios 错误或 unknown\n * @returns ApiErrorBody 或 null\n */\nexport function getApiError(error: unknown): ApiErrorBody | null {\n const d = (error as AxiosError<ApiErrorBody>)?.response?.data;\n if (!d || typeof d !== \"object\") return null;\n return {\n status: d.status,\n errCode: d.errCode,\n message: d.message,\n details: d.details,\n traceId: d.traceId,\n };\n}\n\n/**\n * UI 展示用错误文案:优先 i18n errors 命名空间(errCode),其次 api.message,最后 fallback\n * Get display message: i18n errors namespace (by errCode) → api.message → fallback.\n * @param error - 通常为 Axios 错误\n * @param fallback - 无法解析时的默认文案\n * @returns 展示用字符串\n */\nexport function getApiErrorMessage(error: unknown, fallback: string): string {\n const api = getApiError(error);\n if (api?.errCode) {\n const out = i18n.t(`errors:${api.errCode}`);\n if (out && out !== `errors:${api.errCode}`) return out;\n }\n if (api?.message) return api.message;\n return fallback;\n}\n","/**\n * 按 id 将 items 合并进数组:insert 仅插入新 id,upsert 覆盖同 id 并插入新 id;可 prepend 或 append\n * Merge items into array by id: insert = only new ids, upsert = overwrite same id + insert new; place = prepend | append.\n * @param arr - 原数组\n * @param items - 待合并项\n * @param idOf - 取 id 的函数\n * @param place - 新项插入位置\n * @param mode - insert 不覆盖已有 id;upsert 覆盖同 id\n * @returns 合并后的新数组\n */\nexport function mergeById<T>(arr: T[], items: T[], idOf: (x: T) => string, place: \"prepend\" | \"append\", mode: \"insert\" | \"upsert\") {\n if (items.length === 0) return arr;\n\n switch (mode) {\n case \"insert\":\n return insertUnique(arr, items, idOf, place);\n case \"upsert\":\n return upsertArray(arr, items, idOf, place);\n }\n}\n\nfunction insertUnique<T>(arr: T[], items: T[], idOf: (x: T) => string, place: \"prepend\" | \"append\") {\n const seen = new Set(arr.map(idOf));\n\n const toInsert = items.filter((x) => {\n const id = idOf(x);\n if (seen.has(id)) return false;\n seen.add(id);\n return true;\n });\n if (toInsert.length === 0) return arr;\n\n return place === \"prepend\" ? [...toInsert, ...arr] : [...arr, ...toInsert];\n}\n\nfunction upsertArray<T>(arr: T[], items: T[], idOf: (x: T) => string, place: \"prepend\" | \"append\") {\n const idxById = new Map<string, number>();\n arr.forEach((x, i) => idxById.set(idOf(x), i));\n\n let changed = false;\n const next = arr.slice();\n\n // Overwrite: elements with the same id are replaced with the real items\n for (const it of items) {\n const id = idOf(it);\n const idx = idxById.get(id);\n if (idx !== undefined) {\n if (next[idx] !== it) {\n next[idx] = it;\n changed = true;\n }\n }\n }\n\n // Insert: elements with the same id are replaced with the real items\n const toInsert: T[] = [];\n for (const it of items) {\n const id = idOf(it);\n if (!idxById.has(id)) toInsert.push(it);\n }\n if (toInsert.length > 0) {\n changed = true;\n return place === \"prepend\" ? [...toInsert, ...next] : [...next, ...toInsert];\n }\n\n return changed ? next : arr;\n}\n\n/**\n * 从数组中移除 id 在集合 ids 中的项,返回新数组\n * Remove elements whose id is in the given set; return new array.\n * @param arr - 原数组\n * @param ids - 要移除的 id 集合\n * @param idOf - 取 id 的函数\n * @returns 若无变化返回原数组,否则返回新数组\n */\nexport function pruneArray<T>(arr: T[], ids: ReadonlySet<string>, idOf: (x: T) => string) {\n let changed = false;\n const next = arr.filter((v) => {\n const keep = !ids.has(idOf(v));\n if (!keep) changed = true;\n return keep;\n });\n return changed ? next : arr;\n}\n","/**\n * 将任意颜色统一为指定透明度的 RGBA(rgb/rgba/hex 均用新 alpha 覆盖)\n * Convert any color to RGBA with given alpha (overwrites existing alpha).\n * @param color - rgb / rgba / hex 字符串\n * @param alpha - 透明度 0–1\n * @returns rgba(r, g, b, alpha) 字符串\n */\nexport const toRgbaWithAlpha = (color: string, alpha: number): string => {\n const rgbaMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*[\\d.]+)?\\)/);\n if (rgbaMatch) {\n const [, r, g, b] = rgbaMatch;\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n }\n return hexToRGBA(color, alpha);\n};\n\n/**\n * 将 RGB 颜色转换为 RGBA\n * @param rgb - RGB 颜色字符串,格式: \"rgb(r, g, b)\"\n * @param alpha - 透明度,范围 0-1\n * @returns RGBA 颜色字符串,格式: \"rgba(r, g, b, alpha)\"\n *\n * @example\n * rgbToRgba(\"rgb(250, 30, 22)\", 0.3) // \"rgba(250, 30, 22, 0.3)\"\n */\nexport const rgbToRgba = (rgb: string, alpha: number): string => {\n if (rgb.startsWith(\"rgba\")) return rgb;\n const match = rgb.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);\n if (match) {\n const [, r, g, b] = match;\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n }\n console.warn(\"Invalid RGB color format:\", rgb);\n return rgb;\n};\n\n/**\n * 将 HEX 颜色转换为 RGBA\n * @param hex - HEX 颜色字符串,格式: \"#RRGGBB\" 或 \"#RGB\"\n * @param alpha - 透明度,范围 0-1\n * @returns RGBA 颜色字符串,格式: \"rgba(r, g, b, alpha)\"\n *\n * @example\n * hexToRGBA(\"#FA1E16\", 0.3) // \"rgba(250, 30, 22, 0.3)\"\n */\nexport const hexToRGBA = (hex: string, alpha: number): string => {\n // 如果传入是 rgb 或者 rgba 直接返回\n if (hex.indexOf(\"rgb\") !== -1) return hex;\n\n let r = 0,\n g = 0,\n b = 0;\n\n // 去除开头的 '#' 符号\n if (hex.startsWith(\"#\")) {\n hex = hex.slice(1);\n }\n\n // 处理 3 位或 6 位十六进制颜色\n if (hex.length === 3) {\n r = parseInt(hex[0] + hex[0], 16);\n g = parseInt(hex[1] + hex[1], 16);\n b = parseInt(hex[2] + hex[2], 16);\n } else if (hex.length === 6) {\n r = parseInt(hex.slice(0, 2), 16);\n g = parseInt(hex.slice(2, 4), 16);\n b = parseInt(hex.slice(4, 6), 16);\n } else {\n console.warn(\"Unsupported HEX color format\");\n }\n\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n};\n\n/**\n * 在两色之间按 factor 线性插值(支持 hex / rgb)\n * Linear color interpolation between start and end by factor (0–1); supports hex and rgb.\n * @param start - 起始颜色\n * @param end - 结束颜色\n * @param factor - 插值系数 0–1\n * @returns rgb(r, g, b) 字符串\n */\nexport const interpolateColor = (start: string, end: string, factor: number): string => {\n const parse = (color: string): [number, number, number] => {\n const hex = color.match(/^#?([\\da-f]{2})([\\da-f]{2})([\\da-f]{2})$/i);\n if (hex) return [parseInt(hex[1], 16), parseInt(hex[2], 16), parseInt(hex[3], 16)];\n const rgb = color.match(/^rgb\\((\\d{1,3}),\\s*(\\d{1,3}),\\s*(\\d{1,3})\\)$/i);\n if (rgb) return [parseInt(rgb[1]), parseInt(rgb[2]), parseInt(rgb[3])];\n return [0, 0, 0];\n };\n const [r1, g1, b1] = parse(start);\n const [r2, g2, b2] = parse(end);\n const r = Math.round(r1 + (r2 - r1) * factor);\n const g = Math.round(g1 + (g2 - g1) * factor);\n const b = Math.round(b1 + (b2 - b1) * factor);\n return `rgb(${r}, ${g}, ${b})`;\n};\n","/**\n * 校验邮箱格式是否有效(简单正则:含 @ 与点)\n * Check if email format is valid (simple regex: contains @ and dot).\n * @param email - 待校验的邮箱字符串\n * @returns 是否有效\n */\nexport const isValidEmail = (email: string): boolean => {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n};\n","/**\n * 将任意值转为文本输入框可用的字符串(用于表单回显)\n * Convert any value to a string suitable for text input (e.g. form display).\n * @param value - 任意值\n * @returns 字符串;null/undefined → \"\";数组 → 逗号拼接;对象 → JSON 字符串\n */\nexport function toTextInputValue(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n if (Array.isArray(value)) return value.map((item) => String(item)).join(\", \");\n if (typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n}\n\n/**\n * 将任意值转为数字输入框可用的字符串(用于表单回显)\n * Convert any value to a string suitable for number input (e.g. form display).\n * @param value - 任意值\n * @returns 字符串;null/undefined → \"\";非有限数字 → \"\";数组取首项\n */\nexport function toNumberInputValue(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\") return Number.isFinite(value) ? String(value) : \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"boolean\") return value ? \"1\" : \"0\";\n if (Array.isArray(value) && value.length > 0) return String(value[0]);\n return \"\";\n}\n","/**\n * 从对象中剔除指定键,返回新对象(不修改原对象)\n * Omit specified keys from object and return a new object.\n * @param obj - 源对象\n * @param keys - 要剔除的键(数组或单个键,可再接多个键)\n * @returns 剔除后的新对象\n * @example omit({ a: 1, b: 2, c: 3 }, ['a', 'c']) // { b: 2 }\n * @example omit({ a: 1, b: 2, c: 3 }, 'a', 'b') // { c: 3 }\n */\nexport function omit<Obj extends object, Key extends keyof Obj>(obj: Obj, keys: Key[] | Key, ...restKeys: Key[]): Omit<Obj, Key> {\n const result = {} as Omit<Obj, Key>;\n\n const removeKeys = Array.isArray(keys) ? keys : [keys, ...restKeys];\n const removeSet = new Set(removeKeys);\n\n for (const key of Object.keys(obj) as Key[]) {\n if (!removeSet.has(key)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (result as any)[key] = obj[key];\n }\n }\n\n return result;\n}\n","import { PhoneNumberUtil } from \"google-libphonenumber\";\n\nconst phoneUtil = PhoneNumberUtil.getInstance();\n\n/**\n * 从电话号码解析国家/地区码(基于 google-libphonenumber)\n * Get country code from phone number (google-libphonenumber).\n * @param phoneNumber - 电话号码字符串\n * @returns 国家码数字\n */\nexport const getCountryCode = (phoneNumber: string) => {\n const phoneNumberObject = phoneUtil.parseAndKeepRawInput(phoneNumber);\n return phoneNumberObject.getCountryCode();\n};\n\n/**\n * 校验电话号码是否有效(基于 google-libphonenumber)\n * Check if phone number is valid (google-libphonenumber).\n * @param phoneNumber - 电话号码字符串\n * @returns 是否有效\n */\nexport const isValidPhoneNumber = (phoneNumber: string): boolean => {\n if (!phoneNumber || !phoneNumber.replace(/\\D/g, \"\").length) return false;\n try {\n const phoneNumberObject = phoneUtil.parseAndKeepRawInput(phoneNumber);\n return phoneUtil.isValidNumber(phoneNumberObject);\n } catch {\n return false;\n }\n};\n","/**\n * 结果类型:成功为 [T, null],失败为 [null, Error]。\n * Result type: success [T, null], failure [null, Error].\n * @template T - 成功时的值类型。Value type on success.\n * @example const [data, err] = await withRetryResult(() => fetchData()); if (err) return; use(data);\n */\nexport type Result<T> = [T, null] | [null, Error];\n\n/**\n * 构造成功结果。Create a successful result.\n * @param v - 结果值。Result value.\n * @returns [v, null]\n * @example ok(42) // [42, null]\n */\nexport const ok = <T>(v: T): Result<T> => [v, null];\n\n/**\n * 构造失败结果(非 Error 会包装为 Error)。Create a failed result; non-Error wrapped in Error.\n * @param e - 错误或任意值。Error or any value.\n * @returns [null, Error]\n * @example err(new Error(\"fail\")) // [null, Error]\n */\nexport const err = (e: unknown): Result<never> => [null, e instanceof Error ? e : new Error(String(e))];\n","import retry from \"async-retry\";\nimport type { Options as RetryOptions } from \"async-retry\";\n\nimport { err, ok } from \"./result\";\nimport type { Result } from \"./result\";\n\nexport type WithRetryOptions = RetryOptions & {\n /** 若返回 true 则不再重试,直接 bail。If true, do not retry and bail. */\n isNonRetryable?: (e: Error) => boolean;\n};\n\n/**\n * 带重试执行异步函数,成功返回 ok(value),失败返回 err(error)。\n * Retry async function until success or max attempts; returns Result.\n * @param fn - 可接收 bail 与 attempt 的异步函数。Async function receiving bail and attempt.\n * @param opts - async-retry 选项及 isNonRetryable。async-retry options and isNonRetryable.\n * @returns Promise<Result<T>>\n * @example const [data, err] = await withRetryResult(() => fetchData(), { retries: 3 });\n */\nexport async function withRetryResult<T>(fn: (bail: (e: Error) => void, attempt: number) => Promise<T>, opts?: WithRetryOptions): Promise<Result<T>> {\n try {\n const value = await retry(async (bail: (e: Error) => void, attempt: number) => {\n try {\n return await fn(bail, attempt);\n } catch (e) {\n if (opts?.isNonRetryable?.(e as Error)) bail(e as Error);\n throw e;\n }\n }, opts);\n return ok(value);\n } catch (e) {\n return err(e);\n }\n}\n","import type { Result } from \"./result\";\nimport type { WithRetryOptions } from \"./retry\";\n\nimport { withRetryResult } from \"./retry\";\n\n/**\n * 轮询直到 isOK(data) 为 true(内部用 withRetryResult 重试)。\n * Poll until fetcher returns data that satisfies isOK; uses withRetryResult.\n * @param fetcher - 拉取数据的函数。Function that fetches data.\n * @param isOK - 判断数据是否满足条件。Predicate to check if data is OK.\n * @param opts - 重试选项。Retry options.\n * @returns Promise<Result<T>>\n * @example const [job] = await pollUntil(() => getJob(id), (j) => j.status === \"done\", { retries: 10 });\n */\nexport async function pollUntil<T>(fetcher: () => Promise<T>, isOK: (data: T) => boolean, opts?: WithRetryOptions): Promise<Result<T>> {\n return withRetryResult<T>(async (_bail, _attempt) => {\n const data = await fetcher();\n if (!isOK(data)) {\n throw new Error(\"Condition not satisfied\");\n }\n return data;\n }, opts);\n}\n","/**\n * 显示价格 → 数据库价格(分)。用于提交到后端、保存草稿等\n * Display price to database price (cents). For submit/save.\n * @param displayPrice - 展示用价格(元)\n * @returns 数据库存储价格(分)\n */\nexport function toDatabasePrice(displayPrice: number): number {\n return Math.round(Number(displayPrice) * 100);\n}\n\n/**\n * 数据库价格(分)→ 显示价格字符串(两位小数)\n * Database price (cents) to display string (2 decimal places).\n * @param databasePrice - 数据库价格(分)\n * @returns 如 \"12.34\"\n */\nexport function toDisplayPrice(databasePrice: number): string {\n return (Number(databasePrice) / 100).toFixed(2);\n}\n\n/**\n * 数据库价格(分)→ 显示价格数字。用于表单、计算等\n * Database price (cents) to display number.\n * @param databasePrice - 数据库价格(分)\n * @returns 数字(元)\n */\nexport function toDisplayPriceNumber(databasePrice: number): number {\n return Number(toDisplayPrice(databasePrice));\n}\n\n/**\n * 数字缩写显示(如 1.2k+、3.5M+、1.1B+)\n * Format number to abbreviated string (e.g. 1.2k+, 3.5M+, 1.1B+).\n * @param num - 数字\n * @returns 缩写字符串\n */\nexport function formatNumberAbbreviated(num: number): string {\n if (num < 1_000) {\n return num.toString();\n }\n\n if (num < 1_000_000) {\n return `${(num / 1_000).toFixed(1).replace(/\\.0$/, \"\")}k+`;\n }\n\n if (num < 1_000_000_000) {\n return `${(num / 1_000_000).toFixed(1).replace(/\\.0$/, \"\")}M+`;\n }\n\n return `${(num / 1_000_000_000).toFixed(1).replace(/\\.0$/, \"\")}B+`;\n}\n","/**\n * 包装为「仅执行一次」的异步函数(重复调用返回同一 Promise)。\n * Wrap async function so it runs only once; repeated calls return the same promise.\n * @param fn - 要执行的异步函数。Async function to run once.\n * @returns 包装后的函数,多次调用只执行一次。Wrapped function; only first call runs.\n * @example const loadOnce = onceAsync(() => fetch(\"/api/config\")); loadOnce(); loadOnce(); // 只请求一次\n */\nexport function onceAsync<T, Args extends unknown[]>(fn: (...args: Args) => Promise<T>) {\n let promise: Promise<T> | null = null;\n\n return async (...args: Args) => {\n if (promise) return promise;\n promise = fn(...args).finally(() => (promise = null));\n return promise;\n };\n}\n\n/**\n * 按 key 仅执行一次的异步函数(同一 key 重复调用返回同一 Promise)。\n * Async function that runs only once per key; same key returns same promise.\n * @param fn - 要执行的异步函数。Async function to run.\n * @param keyExtractor - 从参数中提取 key 的函数。Function to extract key from args.\n * @returns 包装后的函数。Wrapped function.\n * @example const fetchUser = onceAsyncByKey((id: string) => api.getUser(id), (id) => id); fetchUser(\"1\"); fetchUser(\"1\"); // 同 id 只请求一次\n */\nexport function onceAsyncByKey<T, Args extends unknown[]>(fn: (...args: Args) => Promise<T>, keyExtractor: (...args: Args) => string) {\n const promises = new Map<string, Promise<T>>();\n\n return async (...args: Args) => {\n const key = keyExtractor(...args);\n const existingPromise = promises.get(key);\n if (existingPromise) return existingPromise;\n\n const promise = fn(...args).finally(() => promises.delete(key));\n promises.set(key, promise);\n return promise;\n };\n}\n","/** 可实例化的构造函数类型。Instantiable constructor type. */\ntype Constructor<T extends object = object> = new (...args: unknown[]) => T;\n\n/** 深度比较两个值是否相等(支持 primitives、数组、plain objects)。Deep equal for primitives, arrays, plain objects. */\nfunction isEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (typeof a !== typeof b) return false;\n if (a === null || b === null) return a === b;\n if (typeof a !== \"object\" || typeof b !== \"object\") return a === b;\n\n const arrA = Array.isArray(a);\n const arrB = Array.isArray(b);\n if (arrA !== arrB) return false;\n if (arrA && arrB) {\n if (a.length !== b.length) return false;\n return a.every((v, i) => isEqual(v, (b as unknown[])[i]));\n }\n\n const keysA = Object.keys(a as object).sort();\n const keysB = Object.keys(b as object).sort();\n if (keysA.length !== keysB.length) return false;\n if (!keysA.every((k, i) => k === keysB[i])) return false;\n return keysA.every((k) => isEqual((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]));\n}\n\n/**\n * 单例工厂:将传入的构造函数包装为单例模式;Proxy 拦截 construct,多次 new 返回同一实例。\n * Singleton factory: wrap constructor so that multiple new calls return the same instance.\n *\n * @template T - 实例类型(需为 object)。Instance type (must be object).\n * @param className - 被包装的构造函数(class)。Constructor (class) to wrap.\n * @returns 代理后的构造函数,调用时始终返回同一实例。Proxied constructor returning same instance.\n *\n * @example\n * ```ts\n * class MyService { ... }\n * const SingletonService = singleton(MyService);\n * const a = new SingletonService();\n * const b = new SingletonService();\n * console.log(a === b); // true\n * ```\n */\nexport const singleton = <T extends object>(className: Constructor<T>): Constructor<T> => {\n let instance: T | undefined;\n let parameters: unknown[] = [];\n return new Proxy(className, {\n construct(_target: Constructor<T>, args: unknown[]): T {\n if (!instance) {\n instance = new className(...args);\n parameters = args;\n }\n if (!isEqual(args, parameters)) {\n throw new Error(\"Cannot create multiple instances with different parameters\");\n }\n return instance;\n },\n }) as Constructor<T>;\n};\n","import type { Nilable } from \"@/types\";\n\n/**\n * 若值为 null/undefined 则抛出 Promise 使 React Suspense 挂起,否则返回该值。\n * If value is null/undefined, throw a promise to suspend (React Suspense); otherwise return value.\n * @param value - 待检查的值。Value to check.\n * @param delay - 重试前的延迟(毫秒)。Delay in ms before retry.\n * @returns 非空时的 value。Value when non-null.\n * @example const data = suspenseIfNull(resource); // 在 Suspense 边界内,data 非空时才渲染\n */\nexport function suspenseIfNull<T>(value: Nilable<T>, delay = 100): T {\n if (value == null) {\n throw new Promise<void>((resolve) => setTimeout(resolve, delay));\n }\n return value;\n}\n","/**\n * 格式化日期为 YYYY/MM/DD(空或无效返回 \"\")\n * Format date as YYYY/MM/DD; empty or invalid returns \"\".\n * @param dateString - 日期字符串\n * @returns 格式化后的日期字符串,无效则 \"\"\n */\nexport const formatDisplayDate = (dateString: string | undefined | null): string => {\n if (!dateString) return \"\";\n const date = new Date(dateString);\n if (isNaN(date.getTime())) return \"\";\n const year = date.getFullYear();\n const month = (date.getMonth() + 1).toString().padStart(2, \"0\");\n const day = date.getDate().toString().padStart(2, \"0\");\n return `${year}/${month}/${day}`;\n};\n\n/**\n * 格式化为相对时间(如 2 days ago, 3 months ago)\n * Format as relative time (e.g. 2 days ago, 3 months ago).\n * @param dateString - 日期字符串\n * @returns 相对时间字符串,无效为 \"Invalid date\",空为 \"Unknown\"\n */\nexport const formatRelativeTime = (dateString: string | undefined | null): string => {\n if (!dateString) return \"Unknown\";\n const date = new Date(dateString);\n if (isNaN(date.getTime())) return \"Invalid date\";\n\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n const diffMonths = Math.floor(diffDays / 30);\n const diffYears = Math.floor(diffDays / 365);\n\n if (diffYears > 0) return `${diffYears} year${diffYears > 1 ? \"s\" : \"\"} ago`;\n if (diffMonths > 0) return `${diffMonths} month${diffMonths > 1 ? \"s\" : \"\"} ago`;\n if (diffDays > 0) return `${diffDays} day${diffDays > 1 ? \"s\" : \"\"} ago`;\n if (diffHours > 0) return `${diffHours} hour${diffHours > 1 ? \"s\" : \"\"} ago`;\n if (diffMinutes > 0) return `${diffMinutes} minute${diffMinutes > 1 ? \"s\" : \"\"} ago`;\n return \"Just now\";\n};\n\n/**\n * 格式化 ISO 日期为图表轴/提示用短格式(如:Jan 4, 02:30 PM)\n * Format ISO date for chart axis/tooltip (e.g. Jan 4, 02:30 PM).\n * @param iso - ISO 日期字符串\n * @returns 格式化字符串,解析失败则返回原串\n */\nexport function formatTickDate(iso: string): string {\n try {\n const d = new Date(iso);\n return d.toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n } catch {\n return iso;\n }\n}\n\n/**\n * 格式化时间显示年月日时分 (YYYY/MM/DD HH:mm)\n * Format date-time as year/month/day hour:minute.\n * @param dateString - 时间字符串\n * @returns 格式化后的时间字符串,无效则返回原串\n */\nexport const formatDateTime = (dateString: string): string => {\n try {\n const date = new Date(dateString);\n if (isNaN(date.getTime())) return dateString;\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hour = String(date.getHours()).padStart(2, \"0\");\n const minute = String(date.getMinutes()).padStart(2, \"0\");\n return `${year}/${month}/${day} ${hour}:${minute}`;\n } catch {\n return dateString;\n }\n};\n\n/**\n * 格式化时间显示月日时分 (MM/DD HH:mm)\n * Format date-time as month/day hour:minute.\n * @param dateString - 时间字符串\n * @returns 格式化后的时间字符串,无效则返回原串\n */\nexport const formatMonthDayTime = (dateString: string): string => {\n try {\n const date = new Date(dateString);\n if (isNaN(date.getTime())) return dateString;\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hour = String(date.getHours()).padStart(2, \"0\");\n const minute = String(date.getMinutes()).padStart(2, \"0\");\n return `${month}/${day} ${hour}:${minute}`;\n } catch {\n return dateString;\n }\n};\n\n/**\n * 格式化日期仅年月日 (YYYY/MM/DD),用于生日等\n * Format date as year/month/day only.\n * @param dateString - 日期字符串,如 \"2000-01-15\" 或 ISO\n * @returns 格式化后的日期字符串,无效则返回原串\n */\nexport const formatDate = (dateString: string): string => {\n try {\n const date = new Date(dateString);\n if (isNaN(date.getTime())) return dateString;\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n return `${year}/${month}/${day}`;\n } catch {\n return dateString;\n }\n};\n\n/**\n * 格式化时间显示时分 (HH:mm)\n * Format time as hour:minute.\n * @param dateString - 时间字符串\n * @returns 格式化后的时间字符串,无效则返回原串\n */\nexport const formatTime = (dateString: string): string => {\n try {\n const date = new Date(dateString);\n if (isNaN(date.getTime())) return dateString;\n const hour = String(date.getHours()).padStart(2, \"0\");\n const minute = String(date.getMinutes()).padStart(2, \"0\");\n return `${hour}:${minute}`;\n } catch {\n return dateString;\n }\n};\n","/**\n * 从字符串列表创建键值映射对象;可选 valueMapper 指定值\n * Create record from string list; optional valueMapper for values.\n * @param list - 字符串数组(作为键)\n * @param valueMapper - 可选,(item, index) => value,缺省时值为键本身\n * @returns Record<list[number], V>\n * @example createMap([\"a\",\"b\",\"c\"]) // { a: \"a\", b: \"b\", c: \"c\" }\n * @example createMap([\"a\",\"b\",\"c\"], (_, i) => i) // { a: 0, b: 1, c: 2 }\n */\nexport function createMap<T extends string, V = T>(list: ReadonlyArray<T>, valueMapper?: (item: T, index: number) => V): Record<T, V> {\n return list.reduce(\n (acc, item, index) => {\n acc[item] = valueMapper ? valueMapper(item, index) : (item as unknown as V);\n return acc;\n },\n {} as Record<T, V>,\n );\n}\n"],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { Options } from 'async-retry';
|
|
2
|
+
|
|
3
|
+
/** 错误响应。Error response. */
|
|
4
|
+
declare interface ApiErrorBody {
|
|
5
|
+
/** 状态码。Status code. */
|
|
6
|
+
status?: number;
|
|
7
|
+
/** 错误码。Error code. */
|
|
8
|
+
errCode?: string;
|
|
9
|
+
/** 消息。Message. */
|
|
10
|
+
message?: string;
|
|
11
|
+
/** 详情。Details. */
|
|
12
|
+
details?: unknown;
|
|
13
|
+
/** 追踪 ID。Trace ID. */
|
|
14
|
+
traceId?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** 可实例化的构造函数类型。Instantiable constructor type. */
|
|
18
|
+
declare type Constructor<T extends object = object> = new (...args: unknown[]) => T;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 从字符串列表创建键值映射对象;可选 valueMapper 指定值
|
|
22
|
+
* Create record from string list; optional valueMapper for values.
|
|
23
|
+
* @param list - 字符串数组(作为键)
|
|
24
|
+
* @param valueMapper - 可选,(item, index) => value,缺省时值为键本身
|
|
25
|
+
* @returns Record<list[number], V>
|
|
26
|
+
* @example createMap(["a","b","c"]) // { a: "a", b: "b", c: "c" }
|
|
27
|
+
* @example createMap(["a","b","c"], (_, i) => i) // { a: 0, b: 1, c: 2 }
|
|
28
|
+
*/
|
|
29
|
+
export declare function createMap<T extends string, V = T>(list: ReadonlyArray<T>, valueMapper?: (item: T, index: number) => V): Record<T, V>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 构造失败结果(非 Error 会包装为 Error)。Create a failed result; non-Error wrapped in Error.
|
|
33
|
+
* @param e - 错误或任意值。Error or any value.
|
|
34
|
+
* @returns [null, Error]
|
|
35
|
+
* @example err(new Error("fail")) // [null, Error]
|
|
36
|
+
*/
|
|
37
|
+
export declare const err: (e: unknown) => Result<never>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 格式化日期仅年月日 (YYYY/MM/DD),用于生日等
|
|
41
|
+
* Format date as year/month/day only.
|
|
42
|
+
* @param dateString - 日期字符串,如 "2000-01-15" 或 ISO
|
|
43
|
+
* @returns 格式化后的日期字符串,无效则返回原串
|
|
44
|
+
*/
|
|
45
|
+
export declare const formatDate: (dateString: string) => string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 格式化时间显示年月日时分 (YYYY/MM/DD HH:mm)
|
|
49
|
+
* Format date-time as year/month/day hour:minute.
|
|
50
|
+
* @param dateString - 时间字符串
|
|
51
|
+
* @returns 格式化后的时间字符串,无效则返回原串
|
|
52
|
+
*/
|
|
53
|
+
export declare const formatDateTime: (dateString: string) => string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 格式化日期为 YYYY/MM/DD(空或无效返回 "")
|
|
57
|
+
* Format date as YYYY/MM/DD; empty or invalid returns "".
|
|
58
|
+
* @param dateString - 日期字符串
|
|
59
|
+
* @returns 格式化后的日期字符串,无效则 ""
|
|
60
|
+
*/
|
|
61
|
+
export declare const formatDisplayDate: (dateString: string | undefined | null) => string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 格式化时间显示月日时分 (MM/DD HH:mm)
|
|
65
|
+
* Format date-time as month/day hour:minute.
|
|
66
|
+
* @param dateString - 时间字符串
|
|
67
|
+
* @returns 格式化后的时间字符串,无效则返回原串
|
|
68
|
+
*/
|
|
69
|
+
export declare const formatMonthDayTime: (dateString: string) => string;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 数字缩写显示(如 1.2k+、3.5M+、1.1B+)
|
|
73
|
+
* Format number to abbreviated string (e.g. 1.2k+, 3.5M+, 1.1B+).
|
|
74
|
+
* @param num - 数字
|
|
75
|
+
* @returns 缩写字符串
|
|
76
|
+
*/
|
|
77
|
+
export declare function formatNumberAbbreviated(num: number): string;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 格式化为相对时间(如 2 days ago, 3 months ago)
|
|
81
|
+
* Format as relative time (e.g. 2 days ago, 3 months ago).
|
|
82
|
+
* @param dateString - 日期字符串
|
|
83
|
+
* @returns 相对时间字符串,无效为 "Invalid date",空为 "Unknown"
|
|
84
|
+
*/
|
|
85
|
+
export declare const formatRelativeTime: (dateString: string | undefined | null) => string;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 格式化 ISO 日期为图表轴/提示用短格式(如:Jan 4, 02:30 PM)
|
|
89
|
+
* Format ISO date for chart axis/tooltip (e.g. Jan 4, 02:30 PM).
|
|
90
|
+
* @param iso - ISO 日期字符串
|
|
91
|
+
* @returns 格式化字符串,解析失败则返回原串
|
|
92
|
+
*/
|
|
93
|
+
export declare function formatTickDate(iso: string): string;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 格式化时间显示时分 (HH:mm)
|
|
97
|
+
* Format time as hour:minute.
|
|
98
|
+
* @param dateString - 时间字符串
|
|
99
|
+
* @returns 格式化后的时间字符串,无效则返回原串
|
|
100
|
+
*/
|
|
101
|
+
export declare const formatTime: (dateString: string) => string;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 仅当为后端错误(有 response.data)时解析为 ApiErrorBody,否则返回 null
|
|
105
|
+
* Parse to ApiErrorBody only when response.data exists; otherwise null.
|
|
106
|
+
* @param error - 通常为 Axios 错误或 unknown
|
|
107
|
+
* @returns ApiErrorBody 或 null
|
|
108
|
+
*/
|
|
109
|
+
export declare function getApiError(error: unknown): ApiErrorBody | null;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* UI 展示用错误文案:优先 i18n errors 命名空间(errCode),其次 api.message,最后 fallback
|
|
113
|
+
* Get display message: i18n errors namespace (by errCode) → api.message → fallback.
|
|
114
|
+
* @param error - 通常为 Axios 错误
|
|
115
|
+
* @param fallback - 无法解析时的默认文案
|
|
116
|
+
* @returns 展示用字符串
|
|
117
|
+
*/
|
|
118
|
+
export declare function getApiErrorMessage(error: unknown, fallback: string): string;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 从电话号码解析国家/地区码(基于 google-libphonenumber)
|
|
122
|
+
* Get country code from phone number (google-libphonenumber).
|
|
123
|
+
* @param phoneNumber - 电话号码字符串
|
|
124
|
+
* @returns 国家码数字
|
|
125
|
+
*/
|
|
126
|
+
export declare const getCountryCode: (phoneNumber: string) => number;
|
|
127
|
+
|
|
128
|
+
export declare function getItem(key: string): Nilable<string>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 将 HEX 颜色转换为 RGBA
|
|
132
|
+
* @param hex - HEX 颜色字符串,格式: "#RRGGBB" 或 "#RGB"
|
|
133
|
+
* @param alpha - 透明度,范围 0-1
|
|
134
|
+
* @returns RGBA 颜色字符串,格式: "rgba(r, g, b, alpha)"
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* hexToRGBA("#FA1E16", 0.3) // "rgba(250, 30, 22, 0.3)"
|
|
138
|
+
*/
|
|
139
|
+
export declare const hexToRGBA: (hex: string, alpha: number) => string;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 在两色之间按 factor 线性插值(支持 hex / rgb)
|
|
143
|
+
* Linear color interpolation between start and end by factor (0–1); supports hex and rgb.
|
|
144
|
+
* @param start - 起始颜色
|
|
145
|
+
* @param end - 结束颜色
|
|
146
|
+
* @param factor - 插值系数 0–1
|
|
147
|
+
* @returns rgb(r, g, b) 字符串
|
|
148
|
+
*/
|
|
149
|
+
export declare const interpolateColor: (start: string, end: string, factor: number) => string;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 校验邮箱格式是否有效(简单正则:含 @ 与点)
|
|
153
|
+
* Check if email format is valid (simple regex: contains @ and dot).
|
|
154
|
+
* @param email - 待校验的邮箱字符串
|
|
155
|
+
* @returns 是否有效
|
|
156
|
+
*/
|
|
157
|
+
export declare const isValidEmail: (email: string) => boolean;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 校验电话号码是否有效(基于 google-libphonenumber)
|
|
161
|
+
* Check if phone number is valid (google-libphonenumber).
|
|
162
|
+
* @param phoneNumber - 电话号码字符串
|
|
163
|
+
* @returns 是否有效
|
|
164
|
+
*/
|
|
165
|
+
export declare const isValidPhoneNumber: (phoneNumber: string) => boolean;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 按 id 将 items 合并进数组:insert 仅插入新 id,upsert 覆盖同 id 并插入新 id;可 prepend 或 append
|
|
169
|
+
* Merge items into array by id: insert = only new ids, upsert = overwrite same id + insert new; place = prepend | append.
|
|
170
|
+
* @param arr - 原数组
|
|
171
|
+
* @param items - 待合并项
|
|
172
|
+
* @param idOf - 取 id 的函数
|
|
173
|
+
* @param place - 新项插入位置
|
|
174
|
+
* @param mode - insert 不覆盖已有 id;upsert 覆盖同 id
|
|
175
|
+
* @returns 合并后的新数组
|
|
176
|
+
*/
|
|
177
|
+
export declare function mergeById<T>(arr: T[], items: T[], idOf: (x: T) => string, place: "prepend" | "append", mode: "insert" | "upsert"): T[];
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 可为 null 或 undefined。T | null | undefined.
|
|
181
|
+
* @example Nilable<boolean> => boolean | null | undefined
|
|
182
|
+
*/
|
|
183
|
+
declare type Nilable<T> = T | null | undefined;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* 可为 null 或 undefined。T | null | undefined.
|
|
187
|
+
* @example Nilable<boolean> => boolean | null | undefined
|
|
188
|
+
*/
|
|
189
|
+
declare type Nilable_2<T> = T | null | undefined;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 规范化地址字符串:去除首尾空白并将连续空白合并为单个空格
|
|
193
|
+
* Normalize address string: trim and collapse consecutive spaces to one.
|
|
194
|
+
* @param address - 原始地址字符串
|
|
195
|
+
* @returns 规范化后的地址
|
|
196
|
+
*/
|
|
197
|
+
export declare function normalizeAddress(address: string): string;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 构造成功结果。Create a successful result.
|
|
201
|
+
* @param v - 结果值。Result value.
|
|
202
|
+
* @returns [v, null]
|
|
203
|
+
* @example ok(42) // [42, null]
|
|
204
|
+
*/
|
|
205
|
+
export declare const ok: <T>(v: T) => Result<T>;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* 从对象中剔除指定键,返回新对象(不修改原对象)
|
|
209
|
+
* Omit specified keys from object and return a new object.
|
|
210
|
+
* @param obj - 源对象
|
|
211
|
+
* @param keys - 要剔除的键(数组或单个键,可再接多个键)
|
|
212
|
+
* @returns 剔除后的新对象
|
|
213
|
+
* @example omit({ a: 1, b: 2, c: 3 }, ['a', 'c']) // { b: 2 }
|
|
214
|
+
* @example omit({ a: 1, b: 2, c: 3 }, 'a', 'b') // { c: 3 }
|
|
215
|
+
*/
|
|
216
|
+
export declare function omit<Obj extends object, Key extends keyof Obj>(obj: Obj, keys: Key[] | Key, ...restKeys: Key[]): Omit<Obj, Key>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* 包装为「仅执行一次」的异步函数(重复调用返回同一 Promise)。
|
|
220
|
+
* Wrap async function so it runs only once; repeated calls return the same promise.
|
|
221
|
+
* @param fn - 要执行的异步函数。Async function to run once.
|
|
222
|
+
* @returns 包装后的函数,多次调用只执行一次。Wrapped function; only first call runs.
|
|
223
|
+
* @example const loadOnce = onceAsync(() => fetch("/api/config")); loadOnce(); loadOnce(); // 只请求一次
|
|
224
|
+
*/
|
|
225
|
+
export declare function onceAsync<T, Args extends unknown[]>(fn: (...args: Args) => Promise<T>): (...args: Args) => Promise<T>;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* 按 key 仅执行一次的异步函数(同一 key 重复调用返回同一 Promise)。
|
|
229
|
+
* Async function that runs only once per key; same key returns same promise.
|
|
230
|
+
* @param fn - 要执行的异步函数。Async function to run.
|
|
231
|
+
* @param keyExtractor - 从参数中提取 key 的函数。Function to extract key from args.
|
|
232
|
+
* @returns 包装后的函数。Wrapped function.
|
|
233
|
+
* @example const fetchUser = onceAsyncByKey((id: string) => api.getUser(id), (id) => id); fetchUser("1"); fetchUser("1"); // 同 id 只请求一次
|
|
234
|
+
*/
|
|
235
|
+
export declare function onceAsyncByKey<T, Args extends unknown[]>(fn: (...args: Args) => Promise<T>, keyExtractor: (...args: Args) => string): (...args: Args) => Promise<T>;
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* 轮询直到 isOK(data) 为 true(内部用 withRetryResult 重试)。
|
|
239
|
+
* Poll until fetcher returns data that satisfies isOK; uses withRetryResult.
|
|
240
|
+
* @param fetcher - 拉取数据的函数。Function that fetches data.
|
|
241
|
+
* @param isOK - 判断数据是否满足条件。Predicate to check if data is OK.
|
|
242
|
+
* @param opts - 重试选项。Retry options.
|
|
243
|
+
* @returns Promise<Result<T>>
|
|
244
|
+
* @example const [job] = await pollUntil(() => getJob(id), (j) => j.status === "done", { retries: 10 });
|
|
245
|
+
*/
|
|
246
|
+
export declare function pollUntil<T>(fetcher: () => Promise<T>, isOK: (data: T) => boolean, opts?: WithRetryOptions): Promise<Result<T>>;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 从数组中移除 id 在集合 ids 中的项,返回新数组
|
|
250
|
+
* Remove elements whose id is in the given set; return new array.
|
|
251
|
+
* @param arr - 原数组
|
|
252
|
+
* @param ids - 要移除的 id 集合
|
|
253
|
+
* @param idOf - 取 id 的函数
|
|
254
|
+
* @returns 若无变化返回原数组,否则返回新数组
|
|
255
|
+
*/
|
|
256
|
+
export declare function pruneArray<T>(arr: T[], ids: ReadonlySet<string>, idOf: (x: T) => string): T[];
|
|
257
|
+
|
|
258
|
+
export declare function removeItem(key: string): void;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* 结果类型:成功为 [T, null],失败为 [null, Error]。
|
|
262
|
+
* Result type: success [T, null], failure [null, Error].
|
|
263
|
+
* @template T - 成功时的值类型。Value type on success.
|
|
264
|
+
* @example const [data, err] = await withRetryResult(() => fetchData()); if (err) return; use(data);
|
|
265
|
+
*/
|
|
266
|
+
export declare type Result<T> = [T, null] | [null, Error];
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* 将 RGB 颜色转换为 RGBA
|
|
270
|
+
* @param rgb - RGB 颜色字符串,格式: "rgb(r, g, b)"
|
|
271
|
+
* @param alpha - 透明度,范围 0-1
|
|
272
|
+
* @returns RGBA 颜色字符串,格式: "rgba(r, g, b, alpha)"
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* rgbToRgba("rgb(250, 30, 22)", 0.3) // "rgba(250, 30, 22, 0.3)"
|
|
276
|
+
*/
|
|
277
|
+
export declare const rgbToRgba: (rgb: string, alpha: number) => string;
|
|
278
|
+
|
|
279
|
+
export declare function setItem(key: string, value: string): void;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* 单例工厂:将传入的构造函数包装为单例模式;Proxy 拦截 construct,多次 new 返回同一实例。
|
|
283
|
+
* Singleton factory: wrap constructor so that multiple new calls return the same instance.
|
|
284
|
+
*
|
|
285
|
+
* @template T - 实例类型(需为 object)。Instance type (must be object).
|
|
286
|
+
* @param className - 被包装的构造函数(class)。Constructor (class) to wrap.
|
|
287
|
+
* @returns 代理后的构造函数,调用时始终返回同一实例。Proxied constructor returning same instance.
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* class MyService { ... }
|
|
292
|
+
* const SingletonService = singleton(MyService);
|
|
293
|
+
* const a = new SingletonService();
|
|
294
|
+
* const b = new SingletonService();
|
|
295
|
+
* console.log(a === b); // true
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
export declare const singleton: <T extends object>(className: Constructor<T>) => Constructor<T>;
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* 若值为 null/undefined 则抛出 Promise 使 React Suspense 挂起,否则返回该值。
|
|
302
|
+
* If value is null/undefined, throw a promise to suspend (React Suspense); otherwise return value.
|
|
303
|
+
* @param value - 待检查的值。Value to check.
|
|
304
|
+
* @param delay - 重试前的延迟(毫秒)。Delay in ms before retry.
|
|
305
|
+
* @returns 非空时的 value。Value when non-null.
|
|
306
|
+
* @example const data = suspenseIfNull(resource); // 在 Suspense 边界内,data 非空时才渲染
|
|
307
|
+
*/
|
|
308
|
+
export declare function suspenseIfNull<T>(value: Nilable_2<T>, delay?: number): T;
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* 显示价格 → 数据库价格(分)。用于提交到后端、保存草稿等
|
|
312
|
+
* Display price to database price (cents). For submit/save.
|
|
313
|
+
* @param displayPrice - 展示用价格(元)
|
|
314
|
+
* @returns 数据库存储价格(分)
|
|
315
|
+
*/
|
|
316
|
+
export declare function toDatabasePrice(displayPrice: number): number;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* 数据库价格(分)→ 显示价格字符串(两位小数)
|
|
320
|
+
* Database price (cents) to display string (2 decimal places).
|
|
321
|
+
* @param databasePrice - 数据库价格(分)
|
|
322
|
+
* @returns 如 "12.34"
|
|
323
|
+
*/
|
|
324
|
+
export declare function toDisplayPrice(databasePrice: number): string;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* 数据库价格(分)→ 显示价格数字。用于表单、计算等
|
|
328
|
+
* Database price (cents) to display number.
|
|
329
|
+
* @param databasePrice - 数据库价格(分)
|
|
330
|
+
* @returns 数字(元)
|
|
331
|
+
*/
|
|
332
|
+
export declare function toDisplayPriceNumber(databasePrice: number): number;
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* 将任意值转为数字输入框可用的字符串(用于表单回显)
|
|
336
|
+
* Convert any value to a string suitable for number input (e.g. form display).
|
|
337
|
+
* @param value - 任意值
|
|
338
|
+
* @returns 字符串;null/undefined → "";非有限数字 → "";数组取首项
|
|
339
|
+
*/
|
|
340
|
+
export declare function toNumberInputValue(value: unknown): string;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* 将任意颜色统一为指定透明度的 RGBA(rgb/rgba/hex 均用新 alpha 覆盖)
|
|
344
|
+
* Convert any color to RGBA with given alpha (overwrites existing alpha).
|
|
345
|
+
* @param color - rgb / rgba / hex 字符串
|
|
346
|
+
* @param alpha - 透明度 0–1
|
|
347
|
+
* @returns rgba(r, g, b, alpha) 字符串
|
|
348
|
+
*/
|
|
349
|
+
export declare const toRgbaWithAlpha: (color: string, alpha: number) => string;
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* 将任意值转为文本输入框可用的字符串(用于表单回显)
|
|
353
|
+
* Convert any value to a string suitable for text input (e.g. form display).
|
|
354
|
+
* @param value - 任意值
|
|
355
|
+
* @returns 字符串;null/undefined → "";数组 → 逗号拼接;对象 → JSON 字符串
|
|
356
|
+
*/
|
|
357
|
+
export declare function toTextInputValue(value: unknown): string;
|
|
358
|
+
|
|
359
|
+
export declare type WithRetryOptions = Options & {
|
|
360
|
+
/** 若返回 true 则不再重试,直接 bail。If true, do not retry and bail. */
|
|
361
|
+
isNonRetryable?: (e: Error) => boolean;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* 带重试执行异步函数,成功返回 ok(value),失败返回 err(error)。
|
|
366
|
+
* Retry async function until success or max attempts; returns Result.
|
|
367
|
+
* @param fn - 可接收 bail 与 attempt 的异步函数。Async function receiving bail and attempt.
|
|
368
|
+
* @param opts - async-retry 选项及 isNonRetryable。async-retry options and isNonRetryable.
|
|
369
|
+
* @returns Promise<Result<T>>
|
|
370
|
+
* @example const [data, err] = await withRetryResult(() => fetchData(), { retries: 3 });
|
|
371
|
+
*/
|
|
372
|
+
export declare function withRetryResult<T>(fn: (bail: (e: Error) => void, attempt: number) => Promise<T>, opts?: WithRetryOptions): Promise<Result<T>>;
|
|
373
|
+
|
|
374
|
+
export { }
|